Utility functions for blackhack
بۇ قوليازمىنى بىۋاسىتە قاچىلاشقا بولمايدۇ. بۇ باشقا قوليازمىلارنىڭ ئىشلىتىشى ئۈچۈن تەمىنلەنگەن ئامبار بولۇپ، ئىشلىتىش ئۈچۈن مېتا كۆرسەتمىسىگە قىستۇرىدىغان كود: // @require https://update.greasyfork.org/scripts/571913/1787411/blackhack-utils.js
// ==UserScript==
// @name blackhack-utils
// @namespace brofist.io 1st-cheat (FOR ALL MODES)
// @version 1.5
// @description Utility functions for blackhack
// @author CiNoP
// @license GPL-3.0-only
// @grant none
// ==/UserScript==
(function () {
'use strict';
const DEBUG = true;
const dbg = (...a) => { if (DEBUG) console.log('%c[BH]', 'color:#0af;font-weight:bold', ...a); };
const wrn = (...a) => console.warn('[BH]', ...a);
dbg('========== blackhack-utils v1.5 ==========');
const BH = window.BH = window.BH || {};
BH.utilsVer = 1.5;
BH.clamp = (v, min, max) => Math.max(min, Math.min(max, v));
BH.round3 = v => Math.round(v * 1000) / 1000;
const _c = document.createElement('canvas'), _x = _c.getContext('2d');
BH.measureTextWidth = (fs, t) => {
_x.font = fs + 'px Arial';
return Math.round(_x.measureText(t).width);
};
BH.STORAGE_KEY = 'blackhack_settings';
BH.DEFAULTS = {
mult: 3, gravScale: 2, jumpHeight: 8,
mass: 1, damping: 0.9,
alphaCollision: 1, alphaPoison: 1, alphaFunctional: 1
};
BH.saveSettings = () => {
try {
const v = window.hack.vars;
localStorage.setItem(BH.STORAGE_KEY, JSON.stringify({
mult: v.mult.uiValue, gravScale: v.gravNoclipGravScale,
jumpHeight: v.jumpHeight, mass: v.playerMass, damping: v.playerDamping,
alphaCollision: v.layoutAlpha.collision, alphaPoison: v.layoutAlpha.poison,
alphaFunctional: v.layoutAlpha.functional
}));
} catch (_) {}
};
BH.loadSettings = () => {
try {
const raw = localStorage.getItem(BH.STORAGE_KEY);
if (raw) return { ...BH.DEFAULTS, ...JSON.parse(raw) };
} catch (_) {}
return { ...BH.DEFAULTS };
};
/* ═══════════════════ LZMA ═══════════════════
*
* lzma_worker-min.js кеширует setTimeout в локальную переменную
* при первом выполнении: var _st = setTimeout;
*
* Поэтому нужно подменить window.setTimeout ДО загрузки кода,
* чтобы библиотека закешировала наш прокси, а не оригинал.
*
* Прокси работает в двух режимах:
* _syncQ === null → passthrough (прозрачно, как настоящий setTimeout)
* _syncQ === [] → sync mode (колбэки складываются в очередь)
*
* ═══════════════════════════════════════════ */
const CDN = 'https://cdn.jsdelivr.net/npm/[email protected]/src/lzma_worker-min.js';
const _realST = window.setTimeout;
let _syncQ = null;
// Прокси — библиотека закеширует ЭТУ функцию
const _stProxy = function () {
if (_syncQ !== null && typeof arguments[0] === 'function') {
_syncQ.push(arguments[0]);
return -1;
}
return _realST.apply(window, arguments);
};
/* ─── Шаг 1: Fetch ─── */
dbg('Step 1: Fetching LZMA…');
let lzmaSrc = null;
try {
const xhr = new XMLHttpRequest();
xhr.open('GET', CDN, false);
xhr.send();
dbg(' XHR status:', xhr.status, '| length:', xhr.responseText?.length);
if (xhr.status === 200 && xhr.responseText) lzmaSrc = xhr.responseText;
} catch (e) { wrn(' XHR error:', e.message); }
if (!lzmaSrc) {
wrn('❌ LZMA source not available');
} else {
/* ─── Шаг 2: Прокси ПЕРЕД инъекцией ─── */
dbg('Step 2: Proxy + inject');
const savedOM = window.onmessage;
// ★ КЛЮЧЕВОЙ МОМЕНТ: ставим прокси ДО выполнения кода библиотеки
window.setTimeout = _stProxy;
dbg(' setTimeout proxy installed BEFORE injection');
let injected = false;
try {
const el = document.createElement('script');
el.textContent = lzmaSrc;
(document.head || document.documentElement).appendChild(el);
el.remove();
injected = true;
dbg(' ✓ inline <script>');
} catch (e1) {
dbg(' inline <script> fail:', e1.message);
try { (0, eval)(lzmaSrc); injected = true; dbg(' ✓ eval'); }
catch (e2) { dbg(' eval fail:', e2.message); }
}
window.onmessage = savedOM;
// НЕ восстанавливаем setTimeout — прокси остаётся!
// Он прозрачен когда _syncQ === null
if (!injected) {
window.setTimeout = _realST;
wrn('❌ LZMA injection failed');
} else {
/* ─── Шаг 3: Найти API ─── */
dbg('Step 3: Finding API');
dbg(' window.LZMA:', window.LZMA);
dbg(' window.LZMA_WORKER:', window.LZMA_WORKER);
let api = null;
if (window.LZMA_WORKER && typeof window.LZMA_WORKER.compress === 'function') {
api = window.LZMA_WORKER;
dbg(' → LZMA_WORKER');
} else if (window.LZMA && window.LZMA.LZMA_WORKER &&
typeof window.LZMA.LZMA_WORKER.compress === 'function') {
api = window.LZMA.LZMA_WORKER;
dbg(' → LZMA.LZMA_WORKER');
} else if (window.LZMA && typeof window.LZMA.compress === 'function') {
api = window.LZMA;
dbg(' → LZMA direct');
}
if (!api) {
wrn('❌ LZMA API not found');
} else {
/* ─── Шаг 4: Sync bridge ─── */
dbg('Step 4: Sync bridge');
const cC = api.compress.bind(api);
const cD = api.decompress.bind(api);
function syncCall(fn, args) {
_syncQ = []; // ← sync mode ON
let result = null, error = null;
args.push(function (res, err) {
if (err) error = err; else result = res;
});
fn.apply(null, args);
let s = 0;
while (_syncQ.length && s++ < 200000) _syncQ.shift()();
_syncQ = null; // ← sync mode OFF
if (DEBUG) dbg(' syncCall: drained', s, 'items');
if (error) throw new Error(String(error));
return result;
}
window.LZMA = {
compress: (input, level) => syncCall(cC, [input, level]),
decompress: (bytes) => syncCall(cD, [bytes])
};
dbg(' ✓ window.LZMA ready');
/* ─── Шаг 5: Тест ─── */
dbg('Step 5: Self-test');
try {
const comp = window.LZMA.compress('blackhack', 1);
dbg(' compressed:', comp ? (comp.length + ' bytes') : '❌ NULL');
if (comp) {
const back = window.LZMA.decompress(comp);
const ok = back === 'blackhack';
dbg(' decompressed:', JSON.stringify(back));
dbg(ok ? ' ✅ PASS' : ' ❌ FAIL');
}
} catch (e) { dbg(' ❌', e.message); }
}
}
}
dbg('========== init complete ==========');
})();