Utility functions for blackhack
נכון ליום
אין להתקין סקריפט זה ישירות. זוהי ספריה עבור סקריפטים אחרים // @require https://update.greatest.deepsurf.us/scripts/571913/1787095/blackhack-utils.js
// ==UserScript== // @name blackhack-utils // @namespace brofist.io 1st-cheat (FOR ALL MODES) // @version 1.2 // @description Utility functions for blackhack // @author CiNoP // @license GPL-3.0-only // @grant GM_getResourceText // @resource lzmaWorker https://cdn.jsdelivr.net/npm/[email protected]/src/lzma_worker-min.js // ==/UserScript== (function () { 'use strict'; const BH = window.BH = window.BH || {}; BH.utilsVer = 1.2 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: @resource → inline <script> в контексте страницы ──────── // // Зачем inline <script>? // • @require кладёт код в sandbox скриптменеджера — var LZMA_WORKER // не попадает на window страницы, и blackhack-map его не видит. // • <script src="..."> — асинхронный, LZMA может быть не готов // к моменту первого parseMapToLayout. // • Inline <script> с textContent выполняется СИНХРОННО в контексте // страницы при appendChild → window.LZMA доступен сразу. // // GM_getResourceText отдаёт кешированный текст ресурса синхронно. // jsdelivr — одобренный CDN на Greasyfork. if (!window.LZMA || typeof window.LZMA.decompress !== 'function') { try { const lzmaSrc = GM_getResourceText('lzmaWorker'); if (lzmaSrc) { // Мост: после выполнения lzma_worker-min.js находим API, // восстанавливаем onmessage и оборачиваем в синхронные вызовы. const bridge = [ ';(function(){', 'window.onmessage=window.__bh_om;delete window.__bh_om;', 'var r=window.LZMA_WORKER||(window.LZMA&&window.LZMA.LZMA_WORKER)||window.LZMA;', 'if(!r||typeof r.compress!=="function"){console.warn("[BH] LZMA API not found");return}', 'var cC=r.compress.bind(r),cD=r.decompress.bind(r);', 'function S(fn,a){', ' var res=null,er=null,rST=window.setTimeout,q=[];', ' window.setTimeout=function(f,d){', ' if(typeof f==="function"&&d===0){q.push(f);return -1}', ' return rST.apply(window,arguments)};', ' a.push(function(v,e){if(e)er=e;else res=v});', ' fn.apply(null,a);', ' var s=0;while(q.length&&s++<200000)q.shift()();', ' window.setTimeout=rST;', ' if(er)throw new Error(er);return res}', 'window.LZMA={', ' compress:function(i,l){return S(cC,[i,l])},', ' decompress:function(b){return S(cD,[b])}};', 'console.log("[BH] LZMA sync bridge OK")', '})();' ].join('\n'); const el = document.createElement('script'); // 1) сохраняем onmessage ДО lzma (он его перезапишет) // 2) код библиотеки // 3) мост: восстановление + синхронные обёртки el.textContent = 'window.__bh_om=window.onmessage;\n' + lzmaSrc + '\n' + bridge; (document.head || document.documentElement).appendChild(el); el.remove(); // чистим DOM, код уже исполнен } } catch (e) { console.warn('[BH] LZMA load failed:', e); } } })();