blackhack-logic

Game logic, physics hooks and update extensions for blackhack

このスクリプトは単体で利用できません。右のようなメタデータを含むスクリプトから、ライブラリとして読み込まれます: // @require https://update.greasyfork.org/scripts/573606/1796986/blackhack-logic.js

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

You will need to install an extension such as Tampermonkey to install this script.

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name           blackhack-logic
// @namespace      brofist.io 1st-cheat (FOR ALL MODES)
// @version        1.0
// @description    Game logic, physics hooks and update extensions for blackhack
// @author         CiNoP
// @license        GPL-3.0-only
// ==/UserScript==

/* blackhack-logic.js */
(function () {
	'use strict';
	const BH = window.BH = window.BH || {};
	BH.logicVer = 1.0;

	// ─── Bind Hack (Runs immediately) ───
	const _bind = Function.prototype.bind;
	const pathname = location.pathname.toLowerCase();
	const isTwoPlayer = pathname.includes("twoplayer");
	const bm = { processOthers: false, movement: false, _allFound: false, _origPO: null, _origMV: null };

	Function.prototype.bind = function (ctx, ...args) {
		const b = _bind.apply(this, [ctx, ...args]);
		if (!bm._allFound) {
			try {
				const s = this.toString();
				if (!bm.processOthers && s.includes('othersPlayerNetworkData') && s.includes('oldPlayersIndex')) {
					b.__hk_processOthers = true; bm.processOthers = true; bm._origPO = this;
				}
				if (!bm.movement && s.includes('moveLeft') && (s.includes('raycast') || s.includes('velocity[1]'))) {
					b.__hk_movement = true; bm.movement = true; bm._origMV = this;
				}
				if (bm.processOthers && bm.movement) bm._allFound = true;
			} catch (_) {}
		} else {
			if (this === bm._origPO) b.__hk_processOthers = true;
			if (this === bm._origMV) b.__hk_movement = true;
		}
		if (isTwoPlayer && window.hack && !window.hack.mode && ctx && ctx.playerData && ctx.twoPlayerController) {
			window.hack.mode = ctx; window.hack.modeController = ctx.twoPlayerController;
			window.hack.gp = ctx.gp; window.hack.networkHandler = ctx.networkHandler;
			window.hack.client = ctx.client;
		}
		return b;
	};

	BH.Logic = {
		diff: (a, b) => a.filter(x => !b.includes(x)),

		getIdxByName: (hack, n) => {
			const r =[], o = hack.mode.otherPlayers;
			for (let i = 0; i < o.length; i++) if (o[i]?.myName === n) r.push(i);
			return r;
		},

		processBL: (hack) => {
			const bl = hack.vars.blacklisted;
			for (const n of bl.names) {
				for (const i of BH.Logic.getIdxByName(hack, n)) {
					if (!bl.data.some(e => e?.[0] === i && e?.[1] === n)) bl.data.push([i, n]);
				}
			}
			if (bl.data.length) bl.data = bl.data.filter(e => e?.[1] && bl.names.includes(e[1]));
		},

		isIdxBL: (hack, i) => hack.vars.blacklisted.data.some(e => e?.[0] === i),

		enforceBL: (hack) => {
			const bl = hack.vars.blacklisted; if (!bl.data.length) return;
			const o = hack.mode.otherPlayers;
			for (const [i] of bl.data) {
				const p = o[i]; if (!p?.gpData) continue;
				p.gpData.g.visible = false;
				if (p.gpData.p) p.gpData.p.collisionResponse = false;
			}
			const msgs = hack.mode.othersPlayerMsgNetworkData;
			if (msgs) {
				const s = new Set(bl.data.map(e => e[0]));
				for (let i = 0; i < msgs.length; i++) msgs[i] = msgs[i].filter(m => !s.has(m[0]));
			}
		},

		getEV: (hack) => {
			const u = hack.keyBinds.ARROW_UP, d = hack.keyBinds.ARROW_DOWN;
			if (u && d) {
				if (hack.vars.arrowFirstPressed === 'up') return 'down';
				if (hack.vars.arrowFirstPressed === 'down') return 'up';
				return null;
			}
			return u ? 'up' : d ? 'down' : null;
		},

		initHooks: (hack, is2pa) => {
			const customPO = function () {
				const mode = hack.mode, gp = hack.gp, nh = hack.networkHandler;
				BH.Logic.processBL(hack);
				if (!mode.othersPlayerNetworkData.length) return;
				var cur =[];
				for (var x = 0; x < mode.othersPlayerNetworkData.length; x++) {
					for (var y = 0; y < mode.othersPlayerNetworkData[x].length; y++) {
						var d = mode.othersPlayerNetworkData[x][y], idx = d[0], xV = d[1], yV = d[2], xA = d[3], yA = d[4];
						if (BH.Logic.isIdxBL(hack, idx)) continue;
						if (mode.otherPlayers[idx] == null) {
							mode.oldPlayersIndex.push(idx);
							var p = {}; p.myName = ""; p.mySkin = 0; p.reset = Infinity;
							p.gpData = is2pa ? mode.basePlayer.createPlayer(mode.playerData) : mode.createPlayer();
							p.gpData.g.myIndex = idx; mode.otherPlayers[idx] = p;
							if (nh?.gsSocket) nh.gsSocket.emit("rBio", idx);
							gp.gWorld.removeChild(p.gpData.g); gp.gWorld.mid.addChild(p.gpData.g);
						}
						if (10 < mode.otherPlayers[idx].reset) { mode.otherPlayers[idx].gpData.setX(xA); mode.otherPlayers[idx].gpData.setY(yA); mode.otherPlayers[idx].reset = 0; }
						mode.otherPlayers[idx].reset++;
						mode.otherPlayers[idx].gpData.p.velocity[0] = xV;
						mode.otherPlayers[idx].gpData.p.velocity[1] = yV;
						cur.push(idx);
					}
				}
				var r = BH.Logic.diff(mode.oldPlayersIndex, cur);
				for (var i = 0; i < r.length; i++) {
					var p2 = mode.otherPlayers[r[i]];
					if (p2 != null) {
						gp.gWorld.mid.removeChild(p2.gpData.g); gp.pWorld.removeBody(p2.gpData.p);
						gp.list[gp.list.indexOf(p2.gpData)] = null; gp.deleteCounter++; mode.otherPlayers[r[i]] = null;
					}
				}
				mode.oldPlayersIndex = cur; mode.othersPlayerNetworkData =[];
			};

			const customMV = function () {
				const ctrl = hack.modeController, p = hack.getLP();
				const mult = hack.vars.mult.value, jh = hack.vars.jumpHeight, gs = hack.vars.gravNoclipGravScale;
				if (!p || !ctrl) return;

				if (hack.vars.noclip) {
					p.p.velocity[0] = ctrl.moveRight ? 3 * mult : ctrl.moveLeft ? -3 * mult : 0;
					p.p.velocity[1] = ctrl.moveUp ? 3 * mult : ctrl.moveDown ? -3 * mult : 0;
					return;
				}

				if (hack.vars.gravNoclip) {
					p.p.velocity[0] = ctrl.moveRight ? 3 * mult : ctrl.moveLeft ? -3 * mult : 0;
					const v = BH.Logic.getEV(hack);
					if (v === 'up') { p.p.gravityScale = -gs; p.setAngle(180); }
					else if (v === 'down') { p.p.gravityScale = gs; p.setAngle(0); }
					else p.p.gravityScale = 0;
					const gd = p.p.gravityScale;
					let sj = false, jd = 0, rsY, reY;
					const ex = p.getX(), ty = p.getY(), hH = 50, rL = 50, n = ex - 15, r = 30 / 11;
					if (gd > 0 && ctrl.moveUp) { sj = true; jd = jh; rsY = ty + (hH - 1); reY = rsY + rL; }
					else if (gd < 0 && ctrl.moveDown) { sj = true; jd = -jh; rsY = ty - (hH - 1); reY = rsY - rL; }
					if (sj) {
						const ph = is2pa ? ctrl.physics : hack.gp;
						for (let i = 0; i < 12; i++) {
							const ox = n + i * r;
							p.ray.from = [ph.xAxis(ox, 0), ph.yAxis(rsY, 0)]; p.ray.to =[ph.xAxis(ox, 0), ph.yAxis(reY, 0)];
							p.ray.update(); p.ray.result.reset(); p.ray.hitPoint = [Infinity, Infinity];
							if (hack.gp.pWorld.raycast(p.ray.result, p.ray))
								if (p.ray.result.shape.ref.getCollision() && p.ray.result.getHitDistance(p.ray) < 0.15) { p.p.velocity[1] = jd; break; }
						}
					}
					return;
				}

				if (ctrl.moveRight) p.p.velocity[0] = 3;
				if (ctrl.moveLeft) p.p.velocity[0] = -3;
				if (!ctrl.moveUp) return;
				const ex = p.getX(), ty = p.getY(), n = ex - 15, r = 30 / 11;
				const ph = is2pa ? ctrl.physics : hack.gp;
				for (let i = 0; i < 12; i++) {
					const ox = n + i * r, oy1 = ty + 49, oy2 = oy1 + 50;
					p.ray.from =[ph.xAxis(ox, 0), ph.yAxis(oy1, 0)]; p.ray.to =[ph.xAxis(ox, 0), ph.yAxis(oy2, 0)];
					p.ray.update(); p.ray.result.reset(); p.ray.hitPoint = [Infinity, Infinity];
					if (hack.gp.pWorld.raycast(p.ray.result, p.ray))
						if (p.ray.result.shape.ref.getCollision() && p.ray.result.getHitDistance(p.ray) < 0.05) { p.p.velocity[1] = jh; break; }
				}
			};

			let poI = false, mvI = false;
			function cih() {
				const lf = hack.client.loopFunctions;
				if (!poI) { const i = lf.findIndex(e => e?.fun?.__hk_processOthers || (e?.fun?.toString().includes('othersPlayerNetworkData') && e.fun.toString().includes('oldPlayersIndex'))); if (i !== -1) { lf[i].fun = customPO; poI = true; } }
				if (!mvI) { const i = lf.findIndex(e => e?.fun?.__hk_movement || (e?.fun?.toString().includes('moveLeft') && (e.fun.toString().includes('raycast') || e.fun.toString().includes('velocity[1]')))); if (i !== -1) { lf[i].fun = customMV; mvI = true; } else if (is2pa && lf.length > 7) { lf[7].fun = customMV; mvI = true; } }
				if (!poI || !mvI) requestAnimationFrame(cih);
			}
			cih();

			const oal = hack.client.addLoopFunction;
			hack.client.addLoopFunction = function (f, p, t, e) {
				if (f) {
					if (f.__hk_processOthers || (f.toString().includes('othersPlayerNetworkData') && f.toString().includes('oldPlayersIndex'))) return oal.call(this, customPO, p, t, e);
					if (f.__hk_movement || (f.toString().includes('moveLeft') && (f.toString().includes('raycast') || f.toString().includes('velocity[1]')))) return oal.call(this, customMV, p, t, e);
				}
				return oal.call(this, f, p, t, e);
			};
		},

		updateTP: (hack) => {
			const v = hack.vars;
			if (v.tpToPlayerEnabled && v.tpTargetName !== "Никто") {
				let target = hack.mode.otherPlayers[v.tpTargetIndex];
				if (!target || target.myName !== v.tpTargetName) {
					let foundNewIndex = -1;
					const oPlayers = hack.mode.otherPlayers;
					for (let i = 0; i < oPlayers.length; i++) {
						if (oPlayers[i] && oPlayers[i].myName === v.tpTargetName) { foundNewIndex = i; break; }
					}
					if (foundNewIndex !== -1) {
						v.tpTargetIndex = foundNewIndex;
						target = oPlayers[foundNewIndex];
					}
				}
				if (target && target.gpData && target.reset <= 10) {
					const lp = hack.getLP();
					if (lp) {
						lp.setX(target.gpData.getX());
						lp.setY(target.gpData.getY());
						if (lp.p) { lp.p.velocity[0] = 0; lp.p.velocity[1] = 0; }
					}
				}
			}
		},

		updateXray: (hack) => {
			const v = hack.vars;
			if (v.layoutMode) {
				if (v.xrayGates.length === 0 && hack.gp && hack.gp.list) {
					const pixi = window.pixi || window.PIXI;
					if (pixi && pixi.Graphics) {
						hack.gp.list.forEach(obj => {
							if (obj && obj.id && obj.id.toLowerCase().startsWith('gate')) {
								const parts = obj.id.split(':');
								const action = parts[parts.length - 1];
								obj.shapes.forEach((shape, idx) => {
									if (shape && shape.make !== 3 && shape.g && shape.g.parent) {
										const gfx = new pixi.Graphics();
										const color = action === "1" ? 0xFF00FF : 0x00FFFF;
										let baseW = 50, baseH = 50, baseR = 25;
										if (shape.p) {
											if (shape.p.width) baseW = shape.p.width * 100;
											if (shape.p.height) baseH = shape.p.height * 100;
											if (shape.p.radius) baseR = shape.p.radius * 100;
										} else if (shape.g) {
											const sx = shape.g.scale ? Math.abs(shape.g.scale.x) : 1;
											const sy = shape.g.scale ? Math.abs(shape.g.scale.y) : 1;
											if (shape.g.width) baseW = shape.g.width / sx;
											if (shape.g.height) baseH = shape.g.height / sy;
											baseR = baseW / 2;
										}
										const type = typeof shape.getType === 'function' ? shape.getType() : shape.type;
										if (type === 2) { gfx.circle(0, 0, baseR); }
										else if (type === 5) {
											const triH = baseW * Math.sqrt(3) / 2;
											const rOff = triH / 6;
											gfx.moveTo(-baseW / 2, triH / 2 - rOff); gfx.lineTo(baseW / 2, triH / 2 - rOff); gfx.lineTo(0, -triH / 2 - rOff); gfx.closePath();
										} else { gfx.rect(-baseW / 2, -baseH / 2, baseW, baseH); }

										gfx.fill({ color: color, alpha: 0.15 });
										gfx.stroke({ width: 3, color: color, alpha: 1 });
										if (hack.gp.gWorld && hack.gp.gWorld.mid) hack.gp.gWorld.mid.addChild(gfx);

										let textObj = null;
										if (idx === 0) {
											textObj = new pixi.Text(obj.id, { fontFamily: 'monospace', fontSize: 14, fill: color, stroke: 0x000000, strokeThickness: 3, fontWeight: 'bold' });
											textObj.anchor.set(0.5, 1);
											hack.gp.gWorld.mid.addChild(textObj);
										}
										v.xrayGates.push({ gfx: gfx, src: shape, text: textObj, baseH: baseH, baseR: baseR, type: type });
									}
								});
							}
						});
					}
				}
				v.xrayGates.forEach(item => {
					const { src, gfx, text, baseH, baseR, type } = item;
					if (src && gfx) {
						if (!src.g || !src.g.parent) { gfx.visible = false; if (text) text.visible = false; return; }
						gfx.visible = true; gfx.scale.set(1);
						if (typeof src.getGlobalPosition === 'function') {
							const pos = src.getGlobalPosition(); gfx.x = pos.x * 100; gfx.y = pos.y * -100; gfx.rotation = -pos.angle;
						} else { gfx.x = src.g.x; gfx.y = src.g.y; gfx.rotation = src.g.rotation || 0; }
						const hasCollision = typeof src.getCollision === 'function' ? src.getCollision() : src.collision;
						if (!hasCollision) { gfx.alpha = 1.0; if (text) text.alpha = 1.0; } else { gfx.alpha = 0.15; if (text) text.alpha = 0.5; }
						if (text) {
							text.visible = true; text.x = gfx.x;
							const objHeight = type === 2 ? baseR * 2 : baseH;
							text.y = gfx.y - (objHeight / 2) - 5; text.scale.set(1);
						}
					}
				});
			} else if (v.xrayGates.length > 0) {
				v.xrayGates.forEach(item => {
					if (item.gfx && item.gfx.parent) item.gfx.parent.removeChild(item.gfx);
					if (item.gfx && typeof item.gfx.destroy === 'function') item.gfx.destroy();
					if (item.text && item.text.parent) item.text.parent.removeChild(item.text);
					if (item.text && typeof item.text.destroy === 'function') item.text.destroy();
				});
				v.xrayGates =[];
			}
		}
	};
})();