// ==UserScript==
// @name Kb+ - cuberealm.io
// @namespace https://github.com/Thibb1
// @match https://cuberealm.io/*
// @match https://www.cuberealm.io/*
// @run-at document-start
// @grant none
// @version 1.2.1
// @author Thibb1
// @description Cuberealm extender Kb+, adds helpful features like Zoom and friend/enemy list
// @license GPL
// ==/UserScript==
let loaded = false;
console.log("Kb+ started, waiting to load...");
Object.defineProperty(Object.prototype, "_eventEmitter", {
get() { return this.__eventEmitter },
set(v) {
if (!loaded) {
loaded = true;
console.log("Kb+ loaded");
}
this.__eventEmitter = v;
window.__eventEmitter = v;
this.__eventEmitter.emit = new Proxy(this.__eventEmitter.emit, {
apply(target, thisArg, args) {
try {
const type = Number(args[0]);
switch (type) {
case Event.Tick:
break;
case Events.InitPlayer:
if (!settings.welcomeText) break;
sendMessage("Kb+ loaded <3 Made by Thibb1", Colors.MAGENTA);
sendMessage(
Colors.ORANGE.convert() + "Send '" +
Colors.CYAN.convert() + settings.commandPrefix + "help" +
Colors.ORANGE.convert() + "' in chat to see available commands"
);
sendMessage(
Colors.ORANGE.convert() + "Press '" +
Colors.CYAN.convert() + settings.zoomKey +
Colors.ORANGE.convert() + "' to zoom"
);
break;
case Events.Message:
args[1] = handleMessage(args[1]);
if (args[1] == "") args[0] = Events.Disable;
break;
case Events.SendMessage:
const send = args[1];
if (settings.keepHistory) saveHistory(send);
if (send.startsWith(settings.commandPrefix)) {
handleCommand(send.slice(settings.commandPrefix.length));
args[0] = Events.Disable;
}
break;
case Events.TabValues:
handleTabValues(args[1]);
break;
default:
if (settings.debug) console.log(`Event ${type} emitted with args:`, args.slice(1));
break;
}
} catch (error) {
console.error('Error in event emitter:', error);
} finally {
return target.apply(thisArg, args);
}
}
});
}
})
const Events = {
Tick: 0,
JoinRoom: 1,
InitPlayer: 2,
Disconnect: 4,
Keyboard: 9,
ChunkData: 10,
// 11 load/unload chunk ?
UnlockMouse: 15,
LockMouse: 16,
// 20 remove player/entity?
ChangeSlot: 24,
HoldingItem: 32,
Message: 33,
SendMessage: 34,
TabValues: 44,
Disable: 99999
}
const createColor = (code) => ({
code,
convert() { return "∁" + this.code.slice(1); }
});
const Colors = {
DARK_RED: createColor("#c43535"),
RED: createColor("#ff5050"),
PINK: createColor("#ff89e9"),
BROWN: createColor("#de660f"),
ORANGE: createColor("#ffa540"),
GOLD: createColor("#ffd700"),
YELLOW: createColor("#ffff40"),
DARK_GREEN: createColor("#40aa40"),
GREEN: createColor("#40ff40"),
DARK_CYAN: createColor("#40a5a5"),
CYAN: createColor("#40ffff"),
DARK_BLUE: createColor("#1b7dff"),
BLUE: createColor("#6ab4ff"),
DARK_PURPLE: createColor("#c04eff"),
PURPLE: createColor("#c28fff"),
MAGENTA: createColor("#ff40ff"),
WHITE: createColor("#ffffff"),
GRAY: createColor("#a9a9a9"),
DARK_GRAY: createColor("#808080"),
BLACK: createColor("#565656")
}
Colors.ENEMY = Colors.RED;
Colors.FRIEND = Colors.GREEN;
const Modes = ["survival", "creative", "peaceful", "custom"];
function getData(key, defaultValue = {}) {
const raw = localStorage.getItem(key);
if (raw) {
const data = JSON.parse(raw);
if (data.version && data.version !== defaultValue.version) {
const mergedSettings = { ...defaultValue, ...data };
mergedSettings.version = defaultValue.version;
setData(key, mergedSettings);
return mergedSettings;
}
return data;
}
return defaultValue;
}
function setData(key, data) {
localStorage.setItem(key, JSON.stringify(data));
}
const defaultSettings = {
version: "1.2",
commandPrefix: '?',
zoomKey: 'x',
welcomeText: true,
keepHistory: true,
disableTips: true,
disableCantBreak: true,
disableChunkInChat: true,
disableAds: true,
debug: false,
gameVersion: 23
}
const settings = getData('Kb+', defaultSettings);
const tabList = [];
function saveSettings() {
setData('Kb+', settings);
}
const friends = getData('Kb+_friends', []);
const enemies = getData('Kb+_enemies', []);
const marked = getData('Kb+_marked', {});
const history = getData("Kb+_hst", []);
let historyIndex = -1;
const MAX_HISTORY = 50;
function saveHistory(message) {
history.push(message);
if (history.length > MAX_HISTORY) {
history.shift();
}
setData('Kb+_hst', history);
historyIndex = history.length - 1;
}
CanvasRenderingContext2D.prototype.fillText = new Proxy(CanvasRenderingContext2D.prototype.fillText, {
apply(target, thisArg, args) {
try {
const text = args[0];
if (friends.includes(text)) {
thisArg.fillStyle = Colors.GREEN.code;
} else if (enemies.includes(text)) {
thisArg.fillStyle = Colors.RED.code;
} else if (marked[text]) {
thisArg.fillStyle = Colors[marked[text]].code;
}
} catch (error) {
console.error('Error in fillText proxy:', error);
} finally {
return target.apply(thisArg, args);
}
}
});
Object.defineProperty(Object.prototype, "generalFOV", {
get() { return this._generalFOV; },
set(v) {
this._generalFOV = v;
window.__cbSettings = this;
setTimeout(() => {
for (const key of Object.keys(this)) {
if (typeof this[key] === 'function' && this[key].toString().includes('generalFOV')) {
this.setGeneralFOV = this[key];
break;
}
}
}, 0)
}
});
if (settings.disableAds) {
// needs refining
Object.defineProperty(Object.prototype, "adplayer", {
get() {
if (window.adsLoadedPromiseResolve) window.adsLoadedPromiseResolve();
return null;
},
set(v) {}
});
Object.defineProperty(Object.prototype, "requestAds", {
get() {
if (window.adsLoadedPromiseResolve) window.adsLoadedPromiseResolve();
return () => {};
},
set(v) {}
});
}
let previousFOV = 100;
let zoomOn = false;
document.addEventListener('keydown', (event) => {
if (event.key.toLowerCase() === settings.zoomKey.toLowerCase() && window.__cbSettings && !zoomOn) {
zoomOn = true;
const CBsettings = JSON.parse(localStorage.getItem("settings"));
previousFOV = CBsettings.state._generalFOV ?? CBsettings.state.generalFOV ?? previousFOV;
window.__cbSettings?.setGeneralFOV(40);
}
});
document.addEventListener('keyup', (event) => {
if (event.key.toLowerCase() === settings.zoomKey.toLowerCase() && window.__cbSettings && zoomOn) {
zoomOn = false;
window.__cbSettings?.setGeneralFOV(previousFOV);
}
});
function sendMessage(message, color) {
const text = (color ? color.convert() : "") + message;
window.__eventEmitter.emit(Events.Message, text);
}
const commands = {
"help": {
description: "[command] - Shows help menu or details about a command"
},
"friends": {
description: "- Prints your friend list"
},
"addfriend": {
description: "[name] - Add a friend to your friend list"
},
"delfriend": {
description: "[name] - Remove a friend from your friend list"
},
"enemies": {
description: "- Prints your enemy list"
},
"addenemy": {
description: "[name] - Add an enemy to your enemy list"
},
"delenemy": {
description: "[name] - Remove an enemy from your enemy list"
},
"addmark": {
description: "[color] [name] - Mark a player with a specific color",
},
"delmark": {
description: "[name] - Remove a mark from a player"
},
"marks":{
description: "- Prints your marked player list"
},
"toggle": {
description: "[setting] - Toggle a setting on or off",
settings: ["welcomeText", "keepHistory", "disableTips", "disableCantBreak", "disableChunkInChat", "disableAds", "debug"]
},
"toggles": {
description: "- List available toggle settings"
},
"join": {
description: "[type] [region] - Join a specific region (e.g., 'join survival eu-1' or 'join custom ws://<ip-address>:<port>')"
},
"leave": {
description: "- Leave the current game"
}
}
function handleCommand(cmd) {
const parts = cmd.split(" ").filter(Boolean);
const partsLen = parts.length;
if (partsLen === 0) {
sendMessage("Please enter a command.", Colors.RED);
return;
}
switch (parts[0]) {
case "help":
case "?":
if (partsLen == 2) {
const command = parts[1];
if (commands[command]) {
sendMessage(`${settings.commandPrefix}${command} ${commands[command].description}`, Colors.ORANGE);
if (commands[command].settings) {
sendMessage("Available settings: " + commands[command].settings.join(", "), Colors.ORANGE);
}
} else {
sendMessage("Command not found: " + command, Colors.RED);
}
break;
}
sendMessage("=".repeat(20) + "Help Menu" + "=".repeat(20), Colors.CYAN);
sendMessage(settings.commandPrefix + "help [<command>] - Help menu or details on a command", Colors.ORANGE);
const friendsHelp = ["friends", "addfriend [name]", "delfriend [name]"].map(cmd => settings.commandPrefix + cmd).join(" ");
sendMessage(friendsHelp + " - Manage friends", Colors.ORANGE);
const enemiesHelp = ["enemies", "addenemy [name]", "delenemy [name]"].map(cmd => settings.commandPrefix + cmd).join(" ");
sendMessage(enemiesHelp + " - Manage enemies", Colors.ORANGE);
const markHelp = ["marks", "addmark [color] [name]", "delmark [name]"].map(cmd => settings.commandPrefix + cmd).join(" ");
sendMessage(markHelp + " - Manage marked players", Colors.ORANGE);
const toggleHelp = ["toggle [setting]", "toggles"].map(cmd => settings.commandPrefix + cmd).join(" ");
sendMessage(toggleHelp + " - Manage Kb+ toggles", Colors.ORANGE);
sendMessage(settings.commandPrefix + "join <mode> <region> - Join a specific region", Colors.ORANGE);
sendMessage(settings.commandPrefix + "leave - Leave the current game", Colors.ORANGE);
sendMessage("=".repeat(49), Colors.CYAN);
break;
case "friends":
sendMessage("Friends: " + friends.join(", "), Colors.BLUE);
break;
case "addfriend":
if (partsLen == 2) {
addFriend(parts[1]);
} else {
sendMessage("Invalid usage: " + settings.commandPrefix + "addfriend <name>", Colors.RED);
}
break;
case "delfriend":
if (partsLen == 2) {
delFriend(parts[1]);
} else {
sendMessage("Invalid usage: " + settings.commandPrefix + "delfriend <name>", Colors.RED);
}
break;
case "enemies":
sendMessage("Enemies: " + enemies.join(", "), Colors.BLUE);
break;
case "addenemy":
if (partsLen == 2) {
addEnemy(parts[1]);
} else {
sendMessage("Invalid usage: " + settings.commandPrefix + "addenemy <name>", Colors.RED);
}
break;
case "delenemy":
if (partsLen == 2) {
delEnemy(parts[1]);
} else {
sendMessage("Invalid usage: " + settings.commandPrefix + "delenemy <name>", Colors.RED);
}
break;
case "marks":
let markedPlayers = Colors.BLUE.convert() + "Marked players:";
for (const name in marked) {
markedPlayers += ` ${Colors[marked[name]].convert()}${name}`;
}
sendMessage(markedPlayers, Colors.BLUE);
break;
case "addmark":
if (partsLen >= 3) {
const color = parts[1].toUpperCase();
const name = parts.slice(2).join(" ");
addMark(color, name);
} else {
sendMessage("[Help] " + settings.commandPrefix + "addmark <color> <name>", Colors.RED);
sendMessage("Available colors: " + Object.keys(Colors).map(color => Colors[color].convert() + color).join(", "), Colors.RED);
}
break;
case "delmark":
if (partsLen == 2){
const name = parts[1];
delMark(name);
} else {
sendMessage("[Help] " + settings.commandPrefix + "delmark <name>", Colors.RED);
}
break;
case "toggle":
if (partsLen == 2) {
const setting = parts[1];
if (commands.toggle.settings.includes(setting)) {
settings[setting] = !settings[setting];
saveSettings();
sendMessage(`Toggled ${setting} to ${settings[setting]}`, Colors.GREEN);
} else {
sendMessage("Unknown setting: " + setting, Colors.RED);
}
} else {
sendMessage("[Help] " + settings.commandPrefix + "toggle <setting>", Colors.RED);
}
break;
case "toggles":
sendMessage("Available toggles: " + commands.toggle.settings.join(", "), Colors.YELLOW);
break;
case "join":
if (partsLen == 3) {
const mode = parts[1];
const region = parts[2];
joinGame(mode, region);
} else {
sendMessage("[Help] " + settings.commandPrefix + "join <mode> <region>")
}
break;
case "leave":
sendMessage("Leaving game...", Colors.YELLOW);
leave();
break;
default:
sendMessage("Unknown command: " + parts[0], Colors.RED);
break;
}
}
function leave() {
__eventEmitter.emit(Events.Disconnect);
}
function joinGame(mode, region) {
if (!Modes.includes(mode)) {
sendMessage("Invalid mode: " + mode + ". Available modes: " + Modes.join(", "), Colors.RED);
return;
}
if (mode == "custom") {
sendMessage(`Attempting to join ${region}...`, Colors.YELLOW);
const secure = region.startsWith("wss://") ? true : false;
region = region.slice(secure ? 6 : 5); // ws or wss
const parts = region.split(":");
const hostname = parts[0];
const port = parts[1];
leave();
setTimeout(() => {__eventEmitter.emit(Events.JoinRoom, hostname, port, secure, "battle", "custom");}, 1000);
return;
}
sendMessage(`Attempting to join ${mode}-${region}...`, Colors.YELLOW);
fetch("https://cuberealm.io/v1/matchmake", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({ mode: mode, room: `${mode}-${region}`, version: String(settings.gameVersion) })
}).then(response => response.json()).then(data => {
if (settings.debug) console.log("Matchmake response:", data);
if (data.hostname && data.port) {
leave();
__eventEmitter.emit(Events.JoinRoom, data.hostname, data.port, data.isSecure, mode, data.room);
} else {
sendMessage(`Failed to join ${mode}-${region}. ${data.message || ''}`, Colors.RED);
}
}).catch(error => {
console.error("Matchmake error:", error);
sendMessage(`Error joining ${mode}-${region}: ${error.message}`, Colors.RED);
});
}
function checkList(list, name) {
if (!list.includes(name)) {
const matchingPlayers = list.filter(player => player.startsWith(name));
if (matchingPlayers.length > 0) {
return matchingPlayers[0];
}
sendMessage("Player not found: " + name, Colors.RED);
return "";
}
return name;
}
function addFriend(name) {
name = checkList(tabList, name);
if (name === "") return;
if (!friends.includes(name)) {
friends.push(name);
if (enemies.includes(name)) delEnemy(name);
if (marked[name]) delMark(name);
setData("Kb+_friends", friends);
sendMessage(`Added ${name} to friends list`, Colors.GREEN);
} else {
sendMessage(`${name} is already in your friends list`, Colors.YELLOW);
}
}
function delFriend(name) {
name = checkList(friends, name);
if (name === "") return;
const index = friends.indexOf(name);
if (index > -1) {
friends.splice(index, 1);
setData("Kb+_friends", enemies);
sendMessage(`Removed ${name} from friends list`, Colors.GREEN);
} else {
sendMessage(`${name} is not in your friends list`, Colors.YELLOW);
}
}
function addEnemy(name) {
name = checkList(tabList, name);
if (name === "") return;
if (!enemies.includes(name)) {
enemies.push(name);
if (friends.includes(name)) delFriend(name);
if (marked[name]) delMark(name);
setData("Kb+_enemies", enemies);
sendMessage(`Added ${name} to enemies list`, Colors.GREEN);
} else {
sendMessage(`${name} is already in your enemies list`, Colors.YELLOW);
}
}
function delEnemy(name) {
name = checkList(enemies, name);
if (name === "") return;
const index = enemies.indexOf(name);
if (index > -1) {
enemies.splice(index, 1);
setData("Kb+_enemies", friends);
sendMessage(`Removed ${name} from enemies list`, Colors.GREEN);
} else {
sendMessage(`${name} is not in your enemies list`, Colors.YELLOW);
}
}
function addMark(color, name) {
if (Colors[color]) {
const playerName = checkList(tabList, name);
if (playerName === "") return;
if (friends.includes(name)) delFriend(name);
if (enemies.includes(name)) delEnemy(name);
marked[playerName] = color;
setData("Kb+_marked", marked);
sendMessage(`Marked ${playerName} with color ${Colors[color].convert()}${color}`, Colors.GREEN);
} else {
sendMessage("Invalid color: " + color + ". Available colors: " + Object.keys(Colors).map(color => Colors[color].convert() + color).join(", "), Colors.RED);
}
}
function delMark(name) {
if (marked[name]) {
delete marked[name];
setData("Kb+_marked", marked);
sendMessage(`Removed mark from ${name}`, Colors.GREEN);
} else {
sendMessage(`${name} is not marked`, Colors.YELLOW);
}
}
function handleMessage(message) {
if (message.startsWith("∁6ab4ff[∁ffd700Tip")) {
if (settings.disableTips) return "";
}
if (message.startsWith(Colors.RED.convert())) {
const error = message.slice(7);
if (error.startsWith("You can't build") && settings.disableCantBreak) return "";
}
if (message.startsWith(Colors.GREEN.convert())) {
const success = message.slice(7);
if (success.startsWith("Entering") && settings.disableChunkInChat) return "";
if (success.startsWith("Leaving") && settings.disableChunkInChat) return "";
}
if (message.startsWith(Colors.GOLD.convert())) {
const parts = message.slice(7).split(" ");
const name = parts[0];
const text = " " + Colors.GOLD.convert() + parts.slice(1).join(" ");
if (friends.includes(name)) {
return Colors.GREEN.convert() + name + text;
} else if (enemies.includes(name)) {
return Colors.RED.convert() + name + text;
} else if (marked[name]) {
return Colors[marked[name]].convert() + name + text;
}
return message;
}
if (!message.includes("∁") && message.includes(":")) {
const parts = message.split(":");
const name = parts[0];
const text = parts.slice(1).join(":");
if (friends.includes(name)) {
return Colors.GREEN.convert() + name + Colors.WHITE.convert() + ":" + text;
} else if (enemies.includes(name)) {
return Colors.RED.convert() + name + Colors.WHITE.convert() + ":" + text;
} else if (marked[name]) {
return Colors[marked[name]].convert() + name + Colors.WHITE.convert() + ":" + text;
}
}
return message;
}
function setInputValue(input, newValue) {
// You need to use this to update react state or it wont register the change
const nativeInputValueSetter = Object.getOwnPropertyDescriptor(
window.HTMLInputElement.prototype,
'value').set;
nativeInputValueSetter.call(input, newValue);
const event = new Event('input', { bubbles: true });
input.dispatchEvent(event);
}
function handleKeydownInput(event, input) {
if (event.key === 'Tab' && input.value.startsWith(settings.commandPrefix)) {
event.preventDefault();
const currentValue = input.value;
const commandPrefix = settings.commandPrefix;
const command = currentValue.slice(commandPrefix.length);
const autocomplete = (baseCommand, list, commandPrefix = settings.commandPrefix) => {
if (!currentValue.startsWith(commandPrefix + baseCommand + " ")) return;
const settingVar = currentValue.slice(commandPrefix.length + baseCommand.length + 1).toLowerCase();
const matchs = list.filter(el => el.toLowerCase().startsWith(settingVar));
if (matchs.length > 0) {
setInputValue(input, commandPrefix + baseCommand + " " + matchs[0]);
}
};
const availableCommands = Object.keys(commands);
const matchingCommands = availableCommands.filter(cmd => cmd.startsWith(command));
if (matchingCommands.length > 0) {
setInputValue(input, commandPrefix + matchingCommands[0]);
} else {
autocomplete("help", Object.keys(commands));
autocomplete("addfriend", tabList);
autocomplete("delfriend", friends);
autocomplete("addenemy", tabList);
autocomplete("delenemy", enemies);
autocomplete("toggle", commands.toggle.settings);
const joinParts = currentValue.slice(commandPrefix.length + "join ".length).split(" ");
if (joinParts.length === 1) autocomplete("join", Modes);
autocomplete("delmark", Object.keys(marked));
const markParts = currentValue.slice(commandPrefix.length + "addmark ".length).split(" ");
if (markParts.length === 1) {
autocomplete("addmark", Object.keys(Colors));
} else if (markParts.length === 2) {
autocomplete("addmark " + markParts[0], tabList);
}
}
} else if (event.key === 'ArrowUp') {
event.preventDefault();
if (historyIndex >= 0) {
setInputValue(input, history[historyIndex]);
historyIndex = Math.max(historyIndex - 1, 0);
}
} else if (event.key === 'ArrowDown') {
event.preventDefault();
if (historyIndex < history.length - 1) {
historyIndex++;
setInputValue(input, history[historyIndex]);
} else {
setInputValue(input, "");
historyIndex = history.length - 1;
}
}
}
function findStringInObject(obj) {
for (const key in obj) {
if (typeof obj[key] === 'string') {
return obj[key];
} else if (Array.isArray(obj[key])) {
for (const item of obj[key]) {
if (typeof item === 'object') {
const result = findStringInObject(item);
if (result) return result;
}
}
} else if (typeof obj[key] === 'object' && obj[key] !== null) {
const result = findStringInObject(obj[key]);
if (result) return result;
}
}
return null;
}
function handleTabValues(object) {
const playerName = findStringInObject(object);
if (playerName) {
if (!tabList.includes(playerName)) {
tabList.push(playerName);
}
}
}
document.addEventListener("DOMContentLoaded", () => {
if (settings.disableAds) window.adSDKType = '';
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.addedNodes.length > 0) {
mutation.addedNodes.forEach((addedNode) => {
if (addedNode.tagName === 'INPUT' && addedNode.getAttribute('maxlength') === '100') {
historyIndex = history.length - 1;
addedNode.addEventListener('keydown', (event) => handleKeydownInput(event, addedNode));
}
if (!addedNode.querySelectorAll) return;
addedNode.querySelectorAll('span').forEach(span => {
const player = span.innerText;
if (friends.includes(player)) {
span.style.color = Colors.GREEN.code;
} else if (enemies.includes(player)) {
span.style.color = Colors.RED.code;
} else if (marked[player]) {
span.style.color = Colors[marked[player]].code;
}
});
});
}
});
});
try {
observer.observe(document.body, { childList: true, subtree: true });
setTimeout(() => {
const appUI = document.querySelector('#app > div > div');
observer.observe(appUI, { childList: true, subtree: true });
}, 10000)
} catch (error) {
console.error("Couldn't hook input / document body, features like tab autocomplete and name coloring won't work. Try reloading the page.");
}
});