Greasy Fork is available in English.
made with much love
当前为
// ==UserScript==
// @name DiepBox by Cazka
// @description made with much love
// @version 0.1.2
// @author Cazka#1820
// @match *://diep.io/*
// @grant GM_addStyle
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_addValueChangeListener
// @grant GM_removeValueChangeListener
// @namespace http://greasyfork.icu/users/541070
// ==/UserScript==
'use strict';
/*
* Feel free to use some of my code for your own multiboxing script. make sure to give credits!
*/
/*
* C L A S S E S
*/
class Gui {
constructor(title) {
this._colors = ['#E8B18A', '#E666EA', '#9566EA', '#6690EA', '#E7D063', '#EA6666', '#92EA66', '#66EAE6'];
this._buttons = [];
this._notifications = [];
this._title = title;
this._gui;
this._guiHead;
this._guiBody;
this._init();
this._enableShortcuts();
}
_init() {
const nonce = `a${Math.floor(Math.random() * 1e5)}`;;
GM_addStyle(`.${nonce} button{display:block;font-family:Ubuntu;color:#fff;text-shadow:-.1em -.1em 0 #000,0 -.1em 0 #000,.1em -.1em 0 #000,.1em 0 0 #000,.1em .1em 0 #000,0 .1em 0 #000,-.1em .1em 0 #000,-.1em 0 0 #000;opacity:.8;border:0;padding:.3em .5em;width:100%;transition:all .15s}.${nonce}{top:0;left:0;position:absolute}.${nonce} button:active:not([disabled]){filter:brightness(.9)}.${nonce} button:hover:not([disabled]):not(:active){filter:brightness(1.1)}`);
this._gui = document.createElement('div');
this._guiHead = document.createElement('div');
this._guiBody = document.createElement('div');
this._gui.className = `${nonce}`;
this._guiBody.style.display = 'block';
document.body.appendChild(this._gui);
this._gui.appendChild(this._guiHead);
this._gui.appendChild(this._guiBody);
this._addButton(this._guiHead, this._title, () => {
if (this._guiBody.style.display === 'block') {
this._guiBody.style.display = 'none';
} else {
this._guiBody.style.display = 'block';
}
});
}
addButton(text, onclick, keyCode) {
return this._addButton(this._guiBody, text, onclick, keyCode);
}
removeButton(button) {
const index = this._buttons.findIndex((x) => x === button);
if (index == -1) return;
this._buttons.splice(index, 1);
button.remove();
button.active = false;
}
reset() {
const head = this._buttons[0];
this._buttons.forEach((x, i) => {
if (i === 0) return;
this.removeButton(x);
});
this._buttons = [head];
}
_addButton(parent, text, onclick, keyCode) {
const button = document.createElement('button');
button.innerHTML = text;
button.keyCode = keyCode;
button.onclick = onclick;
button.style['background-color'] = this._colors[this._buttons.length % this._colors.length];
parent.appendChild(button);
this._buttons.push(button);
return button;
}
_enableShortcuts() {
document.addEventListener('keydown', (event) => {
if (document.getElementById('textInputContainer').style.display === 'block') return;
this._buttons.forEach((button) => {
if (button.keyCode === event.code) button.onclick();
});
});
}
}
class Minimap {
constructor() {
this._minimapWidth;
this._minimapHeight;
this._x00;
this._y00;
this._pointX;
this._pointY;
this._pointX_previous;
this._pointY_previous;
this._viewportWidth;
this._viewportHeight;
this._minimapHook();
this._arrowHook();
this._viewportHook();
}
get x() {
return +((this._pointX - this._x00) / this._minimapWidth).toFixed(6);
}
get y() {
return +((this._pointY - this._y00) / this._minimapHeight).toFixed(6);
}
get x_previous() {
return +((this._pointX_previous - this._x00) / this._minimapWidth).toFixed(6);
}
get y_previous() {
return +((this._pointY_previous - this._y00) / this._minimapHeight).toFixed(6);
}
get scale() {
return {
x: this._viewportWidth / this._minimapWidth,
y: this._viewportHeight / this._minimapHeight,
};
}
_minimapHook() {
let setTransformArgs;
const onsetTransform = (args) => {
if (args[0] === args[3]) setTransformArgs = args;
};
const onstrokeRect = () => {
if (setTransformArgs) {
this._minimapWidth = setTransformArgs[0];
this._minimapHeight = setTransformArgs[3];
this._x00 = setTransformArgs[4];
this._y00 = setTransformArgs[5];
setTransformArgs = undefined;
}
};
this._ctxHook('setTransform', onsetTransform);
this._ctxHook('strokeRect', onstrokeRect);
}
_arrowHook() {
let index = 0;
const stack = Array(4);
let pointA;
let pointB;
let pointC;
const calculatePos = () => {
const side1 = Math.floor(Math.sqrt(Math.pow(pointA[0] - pointB[0], 2) + Math.pow(pointA[1] - pointB[1], 2)));
const side2 = Math.floor(Math.sqrt(Math.pow(pointA[0] - pointC[0], 2) + Math.pow(pointA[1] - pointC[1], 2)));
const side3 = Math.floor(Math.sqrt(Math.pow(pointB[0] - pointC[0], 2) + Math.pow(pointB[1] - pointC[1], 2)));
if (side1 == side2 && side2 == side3) return;
this._pointX_previous = this._pointX;
this._pointY_previous = this._pointY;
this._pointX = (pointA[0] + pointB[0] + pointC[0]) / 3;
this._pointY = (pointA[1] + pointB[1] + pointC[1]) / 3;
};
const onbeginPath = () => {
index = 0;
stack[index++] = 0;
};
const onmoveTo = (args) => {
if (index === 1 && stack[index - 1] === 0) {
stack[index++] = 1;
pointA = args;
return;
}
index = 0;
};
const onlineTo = (args) => {
if (index === 2 && stack[index - 1] === 1) {
stack[index++] = 2;
pointB = args;
return;
}
if (index === 3 && stack[index - 1] === 2) {
stack[index++] = 2;
pointC = args;
return;
}
index = 0;
};
const onfill = () => {
if (index === 4 && stack[index - 1] === 2) {
calculatePos();
return;
}
index = 0;
};
this._ctxHook('beginPath', onbeginPath);
this._ctxHook('moveTo', onmoveTo);
this._ctxHook('lineTo', onlineTo);
this._ctxHook('fill', onfill);
}
_viewportHook() {
let setTransformArgs;
const onsetTransform = (args) => {
if ((args[0] / args[3]).toFixed(4) !== (unsafeWindow.innerWidth / unsafeWindow.innerHeight).toFixed(4)) return;
if (args[0] >= unsafeWindow.innerWidth && args[3] >= unsafeWindow.innerHeight) return;
setTransformArgs = args;
};
const onfillRect = () => {
if (setTransformArgs) {
unsafeWindow.input.execute('ren_minimap_viewport false');
this._viewportWidth = setTransformArgs[0];
this._viewportHeight = setTransformArgs[3];
setTransformArgs = undefined;
}
};
this._ctxHook('setTransform', onsetTransform);
this._ctxHook('fillRect', onfillRect);
setTimeout(() => unsafeWindow.input.execute('ren_minimap_viewport true'), 1000);
setInterval(() => {
unsafeWindow.input.execute('ren_minimap_viewport true');
}, 10000);
}
_ctxHook(method, callback) {
const target = window.CanvasRenderingContext2D.prototype;
target[method] = new Proxy(target[method], {
apply(target, thisArg, args) {
callback(args);
return target.apply(thisArg, args);
},
});
}
}
class DiepGamepad {
constructor() {
this._axes = [0, 0, 0, 0];
this._buttons = [...Array(17)].map((x) => {
return { pressed: false };
});
}
set x(value) {
this._axes[0] = value;
}
set y(value) {
this._axes[1] = value;
}
set mx(value) {
this._axes[2] = value;
}
set my(value) {
this._axes[3] = value;
}
set leftMouse(value) {
this._buttons[7].pressed = value;
}
set rightMouse(value) {
this._buttons[5].pressed = value;
}
set connected(value) {
unsafeWindow.navigator.getGamepads = () => [value ? this.toGamepad() : undefined];
}
get x() {
return this._axes[0];
}
get y() {
return this._axes[1];
}
get mx() {
return this._axes[2];
}
get my() {
return this._axes[3];
}
get leftMouse() {
return this._buttons[7].pressed;
}
get rightMouse() {
return this._buttons[5].pressed;
}
get connected() {
return unsafeWindow.navigator.getGamepads()[0] ? true : false;
}
toGamepad() {
return {
axes: this._axes,
buttons: this._buttons,
mapping: 'standard',
};
}
}
class Vector {
static length({ x, y }) {
return Math.sqrt(x ** 2 + y ** 2);
}
}
class Player {
constructor() {
this._minimap = new Minimap();
this._gamepad = new DiepGamepad();
this._mouse = {
x: 0,
y: 0,
};
unsafeWindow.addEventListener('mousemove', (e) => this._onmousemove(e));
unsafeWindow.addEventListener('mousedown', (e) => this._onmousedown(e));
unsafeWindow.addEventListener('mouseup', (e) => this._onmouseup(e));
unsafeWindow.addEventListener('keydown', (e) => this._onkeydown(e));
unsafeWindow.addEventListener('keyup', (e) => this._onkeyup(e));
}
set useGamepad(value) {
this._gamepad.connected = value;
}
get position() {
return {
x: this._minimap.x,
y: this._minimap.y,
x_previous: this._minimap.x_previous,
y_previous: this._minimap.y_previous,
}
}
get mouse() {
return this.toArenaPos(this._mouse.x, this._mouse.y);
}
toScreenPos(x, y) {
const position = this.position;
const scale = this._minimap.scale;
x -= position.x;
x /= scale.x;
x += 0.5;
x *= unsafeWindow.innerWidth;
y -= position.y;
y /= scale.y;
y += 0.5;
y *= unsafeWindow.innerHeight;
return { x, y };
}
toArenaPos(x, y) {
const position = this.position;
const scale = this._minimap.scale;
x /= unsafeWindow.innerWidth;
x -= 0.5;
x *= scale.x;
x += position.x;
y /= unsafeWindow.innerHeight;
y -= 0.5;
y *= scale.y;
y += position.y;
return { x, y }
}
moveTo(x, y) {
const position = this.position;
if (!position.x || !position.y) return;
const deltaX = x - position.x;
const deltaY = y - position.y;
const length = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
if (length === 0) {
this._gamepad.x = 0;
this._gamepad.y = 0;
return;
}
x = deltaX / length;
y = deltaY / length;
this._gamepad.x = x;
this._gamepad.y = y;
}
lookAt(x, y) {
const position = this.position;
if (!position.x || !position.y) return;
const deltaX = x - position.x;
const deltaY = y - position.y;
const length = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
x = deltaX * 1.05;
y = deltaY * 1.05;
if (length < 0.1) {
x /= length * 9;
y /= length * 9;
}
this._gamepad.mx = x;
this._gamepad.my = y;
}
findBestPos(targetPosition) {
const TOLERANCE = 0.009;
//Strategies:
//(1) Dont move to target if to close
//(2) copy movement vector if to close
//(3) predict future position
//(4) make way when target moves to my direction?
const me = this.position;
const target = {
x: targetPosition.x,
y: targetPosition.y,
x_previous: targetPosition.x_previous,
y_previous: targetPosition.y_previous,
}
const meVector = {
x: me.x - me.x_previous,
y: me.y - me.y_previous
}
const targetVector = {
x: target.x - target.x_previous,
y: target.y - target.y_previous
}
const directionVector = {
x: target.x - me.x,
y: target.y - me.y
}
if (Vector.length(directionVector) < TOLERANCE) {
// (2)
me.x += targetVector.x;
me.y += targetVector.y;
return me;
}
// (3)
target.x += targetVector.x * 25;
target.y += targetVector.y * 25;
return target;
}
_onmousemove(e) {
this._mouse.x = e.clientX;
this._mouse.y = e.clientY;
}
_onmousedown(e) {
this.onkeyDown && this.onkeyDown(e.which);
}
_onmouseup(e) {
this.onkeyUp && this.onkeyUp(e.which);
}
_onkeydown(e) {
this.onkeyDown && this.onkeyDown(e.keyCode);
}
_onkeyup(e) {
this.onkeyUp && this.onkeyUp(e.keyCode);
}
}
class MultiboxStorage {
/*
* items in storage:
* position: [x,y,x_previous, y_previous]
* mouse: [x,y]
* mutex: boolean
* multibox: boolean
* keyDown: Number
' keyUp: Number
*/
constructor() {
//if the user launches this script for the first time
try {
this.mutex;
} catch (err) {
this.reset();
}
}
set position(position) {
GM_setValue('position', [
position.x,
position.y,
position.x_previous,
position.y_previous
]);
}
set mouse(mouse) {
GM_setValue('mouse', [mouse.x, mouse.y]);
}
set mutex(mutex) {
GM_setValue('mutex', mutex ? 1 : 0);
}
set multibox(multibox) {
GM_setValue('multibox', multibox ? 1 : 0);
}
set keyDown(key) {
GM_setValue('keyDown', key);
}
set keyUp(key) {
GM_setValue('keyUp', key);
}
get position() {
const position = GM_getValue('position');
return {
x: position[0],
y: position[1],
x_previous: position[2],
y_previous: position[3],
}
}
get mouse() {
const mouse = GM_getValue('mouse');
return {
x: mouse[0],
y: mouse[1],
}
}
get mutex() {
const mutex = GM_getValue('mutex');
return mutex === 1 ? true : false;
}
get multibox() {
const multibox = GM_getValue('multibox');
return multibox === 1 ? true : false;
}
get keyDown() {
return GM_getValue('keyDown');
}
get keyUp() {
return GM_getValue('keyUp');
}
reset() {
this.position = { x: 0, y: 0, x_previous: 0, y_previous: 0 };
this.mouse = { x: 0, y: 0 };
this.mutex = false;
this.multibox = false;
this.keyDown = -1;
this.keyUp = -1;
}
on(name, cb) {
return GM_addValueChangeListener(name, cb);
}
once(name, cb) {
const id = GM_addValueChangeListener(name, (...args) => {
cb(...args);
this.off(id);
});
}
off(id) {
GM_removeValueChangeListener(id);
}
}
/*
* D E B U G G E R
*/
const DEBUG = false;
const debugger_mouse = document.body.appendChild(document.createElement('div'));
function DEBUG_MousePosition(x, y) {
if (!DEBUG) return;
debugger_mouse.style.pointerEvents = 'none';
debugger_mouse.style.position = 'absolute';
debugger_mouse.style.zIndex = '99999';
debugger_mouse.style.left = `${x - 5}px`;
debugger_mouse.style.top = `${y - 2}px`;
debugger_mouse.innerText = '👆';
}
const debugger_pos = document.body.appendChild(document.createElement('div'));
const debugger_pos_prediction = document.body.appendChild(document.createElement('div'));
function DEBUG_PlayerPosition(x = -100, y = -100, x_prediction = -100, y_prediction = -100) {
if (!DEBUG) return;
debugger_pos.style.pointerEvents = 'none';
debugger_pos.style.position = 'absolute';
debugger_pos.style.zIndex = '99999';
debugger_pos.style.left = `${x - 11}px`;
debugger_pos.style.top = `${y - 12}px`;
debugger_pos.innerText = '🟢';
debugger_pos_prediction.style.pointerEvents = 'none';
debugger_pos_prediction.style.position = 'absolute';
debugger_pos_prediction.style.zIndex = '99999';
debugger_pos_prediction.style.left = `${x_prediction - 11}px`;
debugger_pos_prediction.style.top = `${y_prediction - 12}px`;
debugger_pos_prediction.innerText = '🔵';
}
/*
* H E L P E R F U N C T I O N S
*/
function onbtnMultibox() {
this.active = !this.active;
if (this.active) {
storage.multibox = true;
this.innerHTML = 'Multiboxing: ON';
} else {
storage.multibox = false;
this.innerHTML = 'Multiboxing: OFF';
}
}
function smallBoi() {
player.isMaster = false;
player.useGamepad = storage.multibox;
const multiboxListener = storage.on('multibox', (name, old_value, new_value, remote) => {
player.useGamepad = new_value;
});
const keyDownListener = storage.on('keyDown', (name, old_value, new_value, remote) => {
if ([-1, 87, 65, 83, 68].includes(new_value)) return;
if (DEBUG) console.log('master keyDown', new_value);
if (storage.multibox) {
if (new_value === 1) player._gamepad.leftMouse = true;
else if (new_value === 3) player._gamepad.rightMouse = true;
unsafeWindow.input.keyDown(new_value);
}
});
const keyUpListener = storage.on('keyUp', (name, old_value, new_value, remote) => {
if ([-1, 87, 65, 83, 68].includes(new_value)) return;
if (DEBUG) console.log('master keyUp', new_value);
if (storage.multibox) {
if (new_value === 1) player._gamepad.leftMouse = false;
else if (new_value === 3) player._gamepad.rightMouse = false;
unsafeWindow.input.keyUp(new_value);
}
});
btnForceMaster = gui.addButton('Unlock this tab', () => {
storage.reset();
storage.off(multiboxListener);
storage.off(keyDownListener);
storage.off(keyUpListener);
gui.reset();
bigBoi();
});
}
function bigBoi() {
player.isMaster = true;
storage.mutex = true;
storage.once('mutex', (name, old_value, new_value, remote) => {
if (!new_value) {
gui.reset();
smallBoi();
}
});
btnMultibox = gui.addButton('Multiboxing: OFF', onbtnMultibox, 'KeyF');
}
function mainLoop() {
if (!unsafeWindow.input) return;
if (player.isMaster) {
storage.position = player.position;
storage.mouse = player.mouse;
} else {
const position = storage.position;
const bestPosition = player.findBestPos(position);
const mouse = storage.mouse;
if (storage.multibox) {
player.moveTo(bestPosition.x, bestPosition.y);
player.lookAt(mouse.x, mouse.y);
}
//Debugging
const mouseScreen = player.toScreenPos(mouse.x, mouse.y);
DEBUG_MousePosition(mouseScreen.x, mouseScreen.y);
const playerScreen = player.toScreenPos(position.x, position.y);
const bestPositionScreen = player.toScreenPos(bestPosition.x, bestPosition.y);
DEBUG_PlayerPosition(playerScreen.x, playerScreen.y, bestPositionScreen.x, bestPositionScreen.y);
}
}
/*
* M A I N
*/
const gui = new Gui('DiepBox by Cazka');
const player = new Player();
const storage = new MultiboxStorage();
let btnForceMaster;
let btnMultibox;
if (storage.mutex) smallBoi();
else bigBoi();
unsafeWindow.addEventListener('unload', () => {
if (player.isMaster) {
storage.reset();
}
});
player.onkeyDown = key => {
if (player.isMaster) {
storage.keyDown = key;
storage.keyDown = -1;
}
}
player.onkeyUp = key => {
if (player.isMaster) {
storage.keyUp = key;
storage.keyUp = -1;
}
}
// run main Loop
unsafeWindow.requestAnimationFrame = new Proxy(unsafeWindow.requestAnimationFrame, {
apply: function (target, thisArg, args) {
mainLoop();
return target.apply(thisArg, args);
},
});