From e98fd48082663c89f187fb3a0cad6a162dc03365 Mon Sep 17 00:00:00 2001 From: TuNombre Date: Fri, 3 Jul 2026 15:06:58 -0500 Subject: [PATCH 1/4] Initial commit --- packages/junon-io/client/main.ejs | 24 +++ .../junon-io/client/src/menus/chat_menu.js | 11 +- .../junon-io/client/src/menus/team_menu.js | 40 ++++- .../junon-io/server/commands/chatprefix.js | 65 ++++++++ packages/junon-io/server/commands/fly.js | 13 +- packages/junon-io/server/commands/god.js | 31 +++- packages/junon-io/server/commands/index.js | 1 + packages/junon-io/server/commands/spectate.js | 3 + .../junon-io/server/entities/event_handler.js | 141 ++++++++++++++++-- packages/junon-io/server/entities/player.js | 43 +++--- packages/junon-io/server/entities/sector.js | 19 ++- 11 files changed, 341 insertions(+), 50 deletions(-) create mode 100644 packages/junon-io/server/commands/chatprefix.js diff --git a/packages/junon-io/client/main.ejs b/packages/junon-io/client/main.ejs index 7d696fbf..9e4b4ab4 100644 --- a/packages/junon-io/client/main.ejs +++ b/packages/junon-io/client/main.ejs @@ -916,6 +916,11 @@ value1, value2, ... , valueN Sums all given values. Ex. $add(2,5,8) = 15 + + $if + condition, then, else + Returns the value given the condition. + $subtract value1, value2, ... , valueN @@ -1041,6 +1046,16 @@ $itemId Returns the usage capacity of an item + + $getNthLetter + index, word + Returns the Nth letter of a word + + + $getNthWord + index, string + Returns the Nth word of a string +
@@ -1922,6 +1937,15 @@
+
+ +
+ + + + +
+
diff --git a/packages/junon-io/client/src/menus/chat_menu.js b/packages/junon-io/client/src/menus/chat_menu.js index 21e75233..0415a3f6 100644 --- a/packages/junon-io/client/src/menus/chat_menu.js +++ b/packages/junon-io/client/src/menus/chat_menu.js @@ -219,8 +219,7 @@ class ChatMenu extends BaseMenu { tooltip.style.top = top + "px" } - - createChatEntry(chatGroup, messageObj) { + createChatEntry(chatGroup, messageObj,prefixList) { let chatMessage = document.createElement("div") chatMessage.className = "chat_message" chatMessage.dataset.username = messageObj.username @@ -229,7 +228,11 @@ class ChatMenu extends BaseMenu { let chatUsername = document.createElement("span") chatUsername.className = "chat_user" if (messageObj.username) { - chatUsername.innerText = "[" + messageObj.username + "]" + if (prefixList && prefixList[messageObj.username]) { + chatUsername.innerHTML = ""+ prefixList[messageObj.username].styleA + prefixList[messageObj.username].prefix.slice(0, 16) + prefixList[messageObj.username].styleB + " [" + messageObj.username + "]" + } else { + chatUsername.innerText = "[" + messageObj.username + "]" + } if (messageObj.uid) { chatUsername.dataset.uid = messageObj.uid } @@ -261,6 +264,8 @@ class ChatMenu extends BaseMenu { } } + + setOpenDisplay() { this.el.style.display = 'inline-block' } diff --git a/packages/junon-io/client/src/menus/team_menu.js b/packages/junon-io/client/src/menus/team_menu.js index 001ce567..01232b79 100644 --- a/packages/junon-io/client/src/menus/team_menu.js +++ b/packages/junon-io/client/src/menus/team_menu.js @@ -48,6 +48,9 @@ class TeamMenu extends BaseMenu { this.el.querySelector("#enable_fov").addEventListener("click", this.onEnableFovClick.bind(this), true) this.el.querySelector("#disable_fov").addEventListener("click", this.onDisableFovClick.bind(this), true) + this.el.querySelector("#enable_spectate").addEventListener("click", this.onAllowSpectateClick.bind(this), true) + this.el.querySelector("#disable_spectate").addEventListener("click", this.onDenySpectateClick.bind(this), true) + this.el.querySelector("#enable_minimap").addEventListener("click", this.onEnableMinimapClick.bind(this), true) this.el.querySelector("#disable_minimap").addEventListener("click", this.onDisableMinimapClick.bind(this), true) @@ -143,6 +146,15 @@ class TeamMenu extends BaseMenu { this.el.querySelector("#disable_fov").checked = true } } + + if (name === 'isSpectateAllowed') { + let value = settings[name] + if (value) { + this.el.querySelector("#enable_spectate").checked = true + } else { + this.el.querySelector("#disable_spectate").checked = true + } + } if (name === 'showMiniMap') { let value = settings[name] @@ -405,7 +417,6 @@ class TeamMenu extends BaseMenu { }) } } - onDisableFovClick(e) { e.preventDefault() @@ -420,6 +431,33 @@ class TeamMenu extends BaseMenu { } } + onAllowSpectateClick(e) { + e.preventDefault() + + let value = e.target.value + if (value === 'yes') { + SocketUtil.emit("SectorAction", { + action: 'editSetting', + sectorId: this.game.sector.uid, + key: 'isSpectateAllowed', + value: 'true' + }) + } + } + onDenySpectateClick(e) { + e.preventDefault() + + let value = e.target.value + if (value === 'no') { + SocketUtil.emit("SectorAction", { + action: 'editSetting', + sectorId: this.game.sector.uid, + key: 'isSpectateAllowed', + value: 'false' + }) + } + } + onEnableFloorAutodirtClick(e) { e.preventDefault() diff --git a/packages/junon-io/server/commands/chatprefix.js b/packages/junon-io/server/commands/chatprefix.js new file mode 100644 index 00000000..2c5f6f20 --- /dev/null +++ b/packages/junon-io/server/commands/chatprefix.js @@ -0,0 +1,65 @@ +const BaseCommand = require("./base_command") +const Constants = require("../../common/constants") + +class ChatPrefix extends BaseCommand { + + getUsage() { + return [ + "/chatprefix set [player] [prefix] [color] [style]", + "/chatprefix clear [player]", + "Styles:", + "1: [Test], 2: (Test), 3: {Test}", + ] + } + + allowOwnerOnly() { + return true + } + + perform(caller, args) { + if (!this.game.playerChatPrefixes) {this.game.playerChatPrefixes = {}} + let selectedPlayers = this.getPlayersBySelector(args[1]) + if (selectedPlayers.length === 0) { + caller.showChatError("No such player") + return + } + + let subcommand = args[0] + let style = args[4] + if (style) { + if (style==1) { + style = "[]" + } else if (style==2) { + style = "()" + } else { + style = "{}" + } + } else {style="[]"} + + switch(subcommand) { + case "set": + if (!args[2]) { + caller.showChatError("No prefix") + return + } + selectedPlayers.forEach(ply => { + console.log(ply.name) + this.game.playerChatPrefixes[ply.name] = { + prefix:args[2].slice(0, 8), + color:args[3] || "#ffffff", + styleA:style[0], + styleB:style[1] + } + }); + break + case "clear": + selectedPlayers.forEach(ply => { + delete this.game.playerChatPrefixes[ply.name] + }) + break + } + } + +} + +module.exports = ChatPrefix \ No newline at end of file diff --git a/packages/junon-io/server/commands/fly.js b/packages/junon-io/server/commands/fly.js index fee8f1cf..7f8fad43 100644 --- a/packages/junon-io/server/commands/fly.js +++ b/packages/junon-io/server/commands/fly.js @@ -5,8 +5,10 @@ class Fly extends BaseCommand { getUsage() { return [ + "Enables or disables fly state for players.", "/fly", - "/fly [player]" + "/fly [player]", + "/fly [player] [true/false]" ] } @@ -20,17 +22,22 @@ class Fly extends BaseCommand { perform(player, args) { const username = args[0] + let nextState = args[1] + + if ((nextState !== "true") && (nextState !== "false") && (nextState !== null)) { + nextState = null + } let targetPlayers = this.getPlayersBySelector(username) if (targetPlayers.length === 0) { if (player.isPlayer()) { - player.toggleFly() + player.toggleFly(nextState) } return } targetPlayers.forEach((targetPlayer) => { - targetPlayer.toggleFly() + targetPlayer.toggleFly(nextState) }) } diff --git a/packages/junon-io/server/commands/god.js b/packages/junon-io/server/commands/god.js index 58c69eee..366762d7 100644 --- a/packages/junon-io/server/commands/god.js +++ b/packages/junon-io/server/commands/god.js @@ -5,8 +5,10 @@ const Protocol = require('../../common/util/protocol') class God extends BaseCommand { getUsage() { return [ + "Enables or disables god state for players.", "/god", - "/god [player]" + "/god [player]", + "/god [player] [true/false]" ] } @@ -21,6 +23,12 @@ class God extends BaseCommand { perform(caller, args) { const selector = args[0] + let godPar = args[1] + + if ((godPar !== "false") && (godPar !== "true") && (godPar !== null)) { + godPar = null + } + if (selector) { if (!caller.isSectorOwner()) { caller.showChatError("permission denied") @@ -34,21 +42,30 @@ class God extends BaseCommand { } targetPlayers.forEach((player) => { - this.toggleGod(player) + this.toggleGod(player,godPar) }) } else { - if (caller.isPlayer()) { - this.toggleGod(caller) + if (caller.isPlayer()) { + this.toggleGod(caller,godPar) } } } - toggleGod(player) { - player.godMode = !player.godMode + toggleGod(player,tostate) { + + if (tostate) { + if (tostate == "true") { + player.godMode = true + } else { + player.godMode = false + } + } else { + player.godMode = !player.godMode + } + if (player.godMode) { player.setHealth(player.getMaxHealth()) } - player.showChatSuccess("god mode: " + (player.godMode ? "ON" : "OFF" )) } } diff --git a/packages/junon-io/server/commands/index.js b/packages/junon-io/server/commands/index.js index 40964ca0..e0d560c3 100644 --- a/packages/junon-io/server/commands/index.js +++ b/packages/junon-io/server/commands/index.js @@ -71,6 +71,7 @@ Commands.dirt = require('./dirt') Commands.blood = require('./blood') Commands.setstatus = require('./set_status') Commands.menu = require('./menu') +Commands.chatprefix = require('./chatprefix') Commands.accept_rules = require("./accept_rules") diff --git a/packages/junon-io/server/commands/spectate.js b/packages/junon-io/server/commands/spectate.js index 38ad31a0..cd6d8f6c 100644 --- a/packages/junon-io/server/commands/spectate.js +++ b/packages/junon-io/server/commands/spectate.js @@ -1,6 +1,7 @@ const BaseCommand = require("./base_command") const Constants = require("../../common/constants") const Protocol = require('../../common/util/protocol') +const { setting } = require(".") class Spectate extends BaseCommand { getUsage() { @@ -36,10 +37,12 @@ class Spectate extends BaseCommand { this.toggleSpectate(player) }) } else { + if (this.game.sector.settings.isSpectateAllowed) { if (caller.isPlayer()) { this.toggleSpectate(caller) } } + } } diff --git a/packages/junon-io/server/entities/event_handler.js b/packages/junon-io/server/entities/event_handler.js index f7a0b468..68d2e819 100644 --- a/packages/junon-io/server/entities/event_handler.js +++ b/packages/junon-io/server/entities/event_handler.js @@ -467,6 +467,82 @@ class EventHandler { return this.scoreIndexByPlayer[playerId] } + if(...vals) { + let condition = vals[1] + let val1 = vals[0] + let val2 = vals[2] + + switch(condition) { + case "=": { + if (val1 === val2) { + return vals[3] + } else {return vals[4]} + } + case "<": { + if (val1 < val2) { + return vals[3] + } else {return vals[4]} + } + case ">": { + if (val1 > val2) { + return vals[3] + } else {return vals[4]} + } + case "<=": { + if (val1 <= val2) { + return vals[3] + } else {return vals[4]} + } + case ">=": { + if (val1 >= val2) { + return vals[3] + } else {return vals[4]} + } + case "!=": { + if (!(val1 === val2)) { + return vals[3] + } else {return vals[4]} + } + } + } + + getNthWord(...values) { + if (values.length < 2) return "" + let index = parseInt(values[0]) + let word = values.slice(1).join(" ") + let stringArray = word.split(" ") + + if (isNaN(index) || index < 1) { + return "" + } + if (!word || typeof word !== "string") { + return "" + } + if(index > stringArray.length+1) { + return "" + } + + let letter = stringArray[index - 1] + return letter + } + + getNthLetter(...values) { + if (values.length === 0) return "" + let index = parseInt(values[0]) + let word = values[1]; + if (isNaN(index)) { + return "" + } + if (!word || typeof word !== "string") { + return "" + } + if (index < 1 || index > word.length) { + return "" + } + let letter = word[index - 1]; + return letter + } + setScoreIndex(playerId, index) { this.scoreIndexByPlayer[playerId] = index } @@ -1218,6 +1294,7 @@ class EventHandler { "$getInventoryItemCount": true, "$getArmorEquip": true, "$add": true, + "$if": true, "$subtract": true, "$multiply": true, "$divide": true, @@ -1243,7 +1320,9 @@ class EventHandler { "$getTotalMobCount": true, "$getAngle": true, "$getUsage": true, - "$getCapacity": true + "$getCapacity": true, + "$getNthLetter": true, + "$getNthWord": true, } } @@ -1270,14 +1349,20 @@ class EventHandler { return this.getFunctionTable()[funcName] } - interpolateFunctions(result) { + interpolateFunctions(result) { + result = result.replace(/[\r\n]+/g, " ").trim(); let chars = result.split("") let functionBuffer = "" let resultBuffer = "" + let padepth = 0 for (var i = 0; i < chars.length; i++) { let char = chars[i] let isEndOfString = i === chars.length - 1 + + if (char === '(') padepth++ + if (char === ')') padepth-- + if (isEndOfString) { if (functionBuffer.length > 0) { functionBuffer += char @@ -1288,11 +1373,13 @@ class EventHandler { resultBuffer += char } } else if (char === " ") { - if (functionBuffer.length > 0) { + if (functionBuffer.length > 0 && padepth === 0) { let result = this.parseAndEvalExpression(functionBuffer) functionBuffer = "" resultBuffer += result resultBuffer += char + } else if (functionBuffer.length > 0 && padepth > 0) { + functionBuffer += char } else { resultBuffer += char } @@ -1305,27 +1392,44 @@ class EventHandler { return resultBuffer } - parseAndEvalExpression(expression) { let stack = [] let characters = expression.split("") let keyword = "" + let parenthesisDepth = 0 for (var i = 0; i < characters.length; i++) { let character = characters[i] + if (character === '(') { - stack.push(keyword) + parenthesisDepth++ + if (keyword.trim()) { + stack.push(keyword.trim()) + } stack.push("(") keyword = "" - // end functionName + } else if (character === " ") { + if (parenthesisDepth > 0) { + if (keyword.trim()) { + stack.push(keyword.trim()) + keyword = "" + } + } else { + if (keyword) { + stack.push(keyword) + keyword = "" + } + stack.push(" ") + } } else if (character === ",") { - if (keyword) { - stack.push(keyword) + if (keyword.trim()) { + stack.push(keyword.trim()) keyword = "" } } else if (character === ")") { - if (keyword) { - stack.push(keyword) + parenthesisDepth-- + if (keyword.trim()) { + stack.push(keyword.trim()) keyword = "" } @@ -1337,30 +1441,35 @@ class EventHandler { if (arg === "(") { isFuncFound = true - arg = stack.pop() // func name + arg = stack.pop() args.unshift(arg) } else { - args.unshift(arg) + if (arg !== "" && arg !== " ") { + args.unshift(arg) + } } - } if (isFuncFound) { let funcName = args.shift() if (this.hasFunction(funcName)) { let result = this.runFunction(funcName, args) - stack.push(result) + stack.push(typeof result === 'object' ? JSON.stringify(result) : String(result)) } else { this.queueLog({ type: 'error', message: "Does not have function named: " + funcName }) } - } else { } } else { keyword += character } } - return stack[0] + if (keyword) { + stack.push(keyword) + } + + let finalResult = stack.map(item => typeof item === 'string' ? item : String(item)).join("") + return finalResult.trim() } interpolate(value, params, options = {}) { diff --git a/packages/junon-io/server/entities/player.js b/packages/junon-io/server/entities/player.js index ec0f5b15..4ed2ee5d 100644 --- a/packages/junon-io/server/entities/player.js +++ b/packages/junon-io/server/entities/player.js @@ -712,11 +712,27 @@ class Player extends BaseEntity { }) } - toggleFly() { - this.isFlying = !this.isFlying - let message = this.isFlying ? "Flying mode enabled" : "Flying mode disabled" + toggleFly(currState) { + + let nextState = currState + let prevState = this.isFlying - this.showError(message, { isSuccess: true, fontSize: 36 }) + if (nextState == null) { + nextState = !this.isFlying + } else { + if (nextState == "true") { + nextState = true + } else { + nextState = false + } + } + + if (prevState !== nextState) { + this.isFlying = nextState + let message = this.isFlying ? "Flying mode enabled" : "Flying mode disabled" + + this.showError(message, { isSuccess: true, fontSize: 36 }) + } } onRoleAssigned() { @@ -1995,11 +2011,6 @@ class Player extends BaseEntity { return } - if(Protocol.definition().TerrainType[item.type] && !this.game.isPeaceful() && !this.game.isAdminMode){ - // can't craft terrains outside of peaceful mode - return - } - const isSuccess = storage.craft(item, this.inventory.storage) if (!isSuccess) return @@ -3857,7 +3868,7 @@ class Player extends BaseEntity { setUserOxygen(oxygen) { const armor = this.getArmorEquip() - if (armor && armor.hasOxygen()) { + if (armor) { armor.setOxygen(oxygen, this) } else { this.setOxygen(oxygen) @@ -4410,7 +4421,7 @@ class Player extends BaseEntity { message = i18n.t(this.locale, message) options.message = message this.getSocketUtil().emit(this.getSocket(), "ErrorMessage", options) - } + } showChatError(message) { this.getSocketUtil().emit(this.getSocket(), "ServerChat", { message: "%error%" + message }) @@ -5529,14 +5540,15 @@ class Player extends BaseEntity { if (data.isGlobal) { LOG.info("globalchat> " + this.name + ": " + message) - let data = { username: this.name, message: message } + let data = { username: this.name, message: message, prefixesList:JSON.stringify(this.game.playerChatPrefixes||{})} if (this.isLoggedIn()) { data.uid = this.getUid() } this.game.sendToMatchmaker({ event: "GlobalClientChat", data: data }) } else { LOG.info("[" + this.game.getSectorUid() + "] chat> " + this.name + ": " + message) - let data = { playerId: this.id, message: message, username: this.name, isTeam: isTeamChat } + console.log(this.game.playerChatPrefixes) + let data = { playerId: this.id, message: message, username: this.name, isTeam: isTeamChat,prefixesList:JSON.stringify(this.game.playerChatPrefixes||{})} if (this.isLoggedIn()) { data.uid = this.getUid() } @@ -5995,11 +6007,6 @@ Object.assign(Player.prototype, Destroyable.prototype, { this.releaseDragTarget() } - if (this.hasPendingItem()) - { - this.removePendingItem() - } - this.getSocketUtil().broadcast(this.game.getSocketIds(), "PlayerDestroyed", { id: this.id, canRespawn: this.canRespawn(), restartCooldown: this.getRespawnCooldown() }) EventBus.dispatch(`${this.game.getId()}:entity:died:${this.getId()}`, this) diff --git a/packages/junon-io/server/entities/sector.js b/packages/junon-io/server/entities/sector.js index eff969e3..ce9b83e0 100644 --- a/packages/junon-io/server/entities/sector.js +++ b/packages/junon-io/server/entities/sector.js @@ -398,6 +398,7 @@ class Sector { isMutantEnabled: true, isGravityEnabled: false, isFireSpreadEnabled: firespread, + isSpectateAllowed: true, } if (!entities) return @@ -803,13 +804,23 @@ class Sector { this.getSocketUtil().broadcast(this.game.getSocketIds(), "SectorUpdated", { settings: this.settings }) + + if (key === "isSpectateAllowed") { + if (value === false) { + this.game.forEachPlayer((player) => { + if (player.ghost) { + player.possess(player) + } + }) + } + } } } canEditSetting(key) { if(this.gameMode === 'hardcore' || !this.gameMode) return false; if(this.gameMode === 'survival') { - let allowedSettingChanges = ['isPvPAllowed',"isFovMode", "isZoomAllowed", "showMiniMap", "showPlayerList", "isFloorAutodirt", "isChatEnabled", "isShadowsEnabled", "isPlayerSavingEnabled", "isBloodEnabled", "isGravityEnabled"] + let allowedSettingChanges = ['isPvPAllowed',"isFovMode", "isZoomAllowed", "showMiniMap", "showPlayerList", "isFloorAutodirt", "isChatEnabled", "isShadowsEnabled", "isPlayerSavingEnabled", "isBloodEnabled", "isGravityEnabled","isSpectateAllowed"] if(allowedSettingChanges.indexOf(key) === -1) return false; } @@ -1209,7 +1220,7 @@ class Sector { } } } - + addClaim(entity, claimer) { new Claim(this, entity, claimer, this.game.timestamp) @@ -1496,6 +1507,10 @@ class Sector { return this.settings.isFovMode } + isSpectateAllowed() { + return this.settings.isSpectateAllowed + } + isZoomAllowed() { if (this.game.isPvP()) return false return this.settings.isZoomAllowed From b088bee52fe9d59cdb150d7cfd83d870ab0f46be Mon Sep 17 00:00:00 2001 From: TuNombre Date: Fri, 3 Jul 2026 16:16:22 -0500 Subject: [PATCH 2/4] Initial commit --- packages/junon-common/protocol/base.proto | 1 + packages/junon-io/client/main.ejs | 2 +- packages/junon-io/client/src/menus/chat_menu.js | 4 ++-- packages/junon-io/server/entities/event_handler.js | 8 ++++++++ 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/junon-common/protocol/base.proto b/packages/junon-common/protocol/base.proto index 11a06c97..b17f6fc2 100644 --- a/packages/junon-common/protocol/base.proto +++ b/packages/junon-common/protocol/base.proto @@ -798,6 +798,7 @@ message ServerChat { string username = 3; string uid = 4; bool isTeam = 5; + string prefixesList = 6; } message Chunk { diff --git a/packages/junon-io/client/main.ejs b/packages/junon-io/client/main.ejs index 9e4b4ab4..69ca7946 100644 --- a/packages/junon-io/client/main.ejs +++ b/packages/junon-io/client/main.ejs @@ -918,7 +918,7 @@ $if - condition, then, else + value1, operator, value2, then, else Returns the value given the condition. diff --git a/packages/junon-io/client/src/menus/chat_menu.js b/packages/junon-io/client/src/menus/chat_menu.js index 0415a3f6..a1d0e52b 100644 --- a/packages/junon-io/client/src/menus/chat_menu.js +++ b/packages/junon-io/client/src/menus/chat_menu.js @@ -280,7 +280,7 @@ class ChatMenu extends BaseMenu { const playerId = data.playerId const username = data.username const message = data.message - + const prefixList = JSON.parse(data.prefixesList||"{}") const chatUser = this.game.sector.players[playerId] let messageObj = this.parseServerChat(message) @@ -290,7 +290,7 @@ class ChatMenu extends BaseMenu { let chatGroup = data.isTeam ? "team" : "local" if (!this.isMuted(username)) { - this.createChatEntry(chatGroup, messageObj) + this.createChatEntry(chatGroup, messageObj, prefixList) } if (chatUser && !this.isMuted(chatUser.name)) { diff --git a/packages/junon-io/server/entities/event_handler.js b/packages/junon-io/server/entities/event_handler.js index 68d2e819..c81fdece 100644 --- a/packages/junon-io/server/entities/event_handler.js +++ b/packages/junon-io/server/entities/event_handler.js @@ -503,6 +503,14 @@ class EventHandler { return vals[3] } else {return vals[4]} } + case "=~": { + if (val1.includes(val2)) { + return vals[3] + } else {return vals[4]} + } + default: { + return "undefined" + } } } From b9893de68054905338ead95fe5ca447adbafe0b6 Mon Sep 17 00:00:00 2001 From: TuNombre Date: Fri, 3 Jul 2026 17:47:47 -0500 Subject: [PATCH 3/4] QOL Update #1 --- packages/junon-io/server/entities/player.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/junon-io/server/entities/player.js b/packages/junon-io/server/entities/player.js index 4ed2ee5d..4f5a75fc 100644 --- a/packages/junon-io/server/entities/player.js +++ b/packages/junon-io/server/entities/player.js @@ -2011,6 +2011,12 @@ class Player extends BaseEntity { return } + if(Protocol.definition().TerrainType[item.type] && !this.game.isPeaceful() && !this.game.isAdminMode){ + // can't craft terrains outside of peaceful mode + return + } + + const isSuccess = storage.craft(item, this.inventory.storage) if (!isSuccess) return @@ -3868,7 +3874,7 @@ class Player extends BaseEntity { setUserOxygen(oxygen) { const armor = this.getArmorEquip() - if (armor) { + if (armor && armor.hasOxygen()) { armor.setOxygen(oxygen, this) } else { this.setOxygen(oxygen) @@ -6007,6 +6013,11 @@ Object.assign(Player.prototype, Destroyable.prototype, { this.releaseDragTarget() } + if (this.hasPendingItem()) + { + this.removePendingItem() + } + this.getSocketUtil().broadcast(this.game.getSocketIds(), "PlayerDestroyed", { id: this.id, canRespawn: this.canRespawn(), restartCooldown: this.getRespawnCooldown() }) EventBus.dispatch(`${this.game.getId()}:entity:died:${this.getId()}`, this) From e85e441526aa9672c3ac40868739c8ab99d222af Mon Sep 17 00:00:00 2001 From: TuNombre Date: Fri, 3 Jul 2026 19:07:54 -0500 Subject: [PATCH 4/4] QOL Update #1 --- packages/junon-io/server/commands/chatprefix.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/junon-io/server/commands/chatprefix.js b/packages/junon-io/server/commands/chatprefix.js index 2c5f6f20..61bb021d 100644 --- a/packages/junon-io/server/commands/chatprefix.js +++ b/packages/junon-io/server/commands/chatprefix.js @@ -45,7 +45,7 @@ class ChatPrefix extends BaseCommand { selectedPlayers.forEach(ply => { console.log(ply.name) this.game.playerChatPrefixes[ply.name] = { - prefix:args[2].slice(0, 8), + prefix:args[2].replace(/[^a-zA-Z]/g, '').slice(0, 8), color:args[3] || "#ffffff", styleA:style[0], styleB:style[1]