From 56fef3a84acbba9b3079ead4de0ef987486740cf Mon Sep 17 00:00:00 2001 From: LJM12914 Date: Tue, 13 Aug 2024 13:33:14 +0800 Subject: [PATCH] 1.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 完成留言系统。 --- scripts/commandBase.js | 74 ++++++++++++------- scripts/day.js | 5 +- scripts/deathCoords.js | 23 ++++++ scripts/debug.js | 149 ++++++++++++++++++++++++++++++++++---- scripts/fst.js | 52 ++++++++++++-- scripts/fst_old.js | 107 ---------------------------- scripts/loopCommands.js | 2 +- scripts/main.js | 3 + scripts/message.js | 154 ++++++++++++++++++++++++++++++---------- scripts/welcome.js | 5 +- 10 files changed, 372 insertions(+), 202 deletions(-) create mode 100644 scripts/deathCoords.js delete mode 100644 scripts/fst_old.js diff --git a/scripts/commandBase.js b/scripts/commandBase.js index 71dc57d..c3b6e4e 100644 --- a/scripts/commandBase.js +++ b/scripts/commandBase.js @@ -17,7 +17,7 @@ let prefix = "."; * args :argumentDef[]; * description :string; * callback :(usedName :string, player :Player, args :Record)=>boolean; - * tagRequired? :string[]; + * tagsRequired? :string[]; * hidden? :boolean; * }} Command * @type {Command[]} @@ -27,16 +27,28 @@ const commands = []; //#region 命令注册 /**注册命令,可选参数必须排在必选参数后面 * @param {Command} args 函数参数 + * @returns {boolean} 是否成功注册命令。 */ export function registerCommand(args){ + if(args.names.length === 0){ + world.sendMessage("§c内部错误。请报告管理员。"); + console.error(`Found command with no names!`); + return false; + } + for(let i = 0; i < commands.length; i++) for(let j = 0; j < commands[i].names.length; j++) for(let k = 0; k < args.names.length; k++) if(commands[i].names[j] === args.names[k]){ + world.sendMessage("§c内部错误。请报告管理员。"); + console.error(`Duplicate name on [${commands[i].names.join(", ")}] and new [${args.names.join(", ")}]`); + return false; + } commands.push({ names: args.names, args: args.args, description: args.description, - tagRequired: args.tagRequired, + tagsRequired: args.tagsRequired, hidden: args.hidden, callback: args.callback }); + return true; } //#endregion @@ -50,7 +62,7 @@ world.beforeEvents.chatSend.subscribe(data=>{ raw = message.substring(1, message.length).split(" "), name = raw.shift(); let firedCommand = false; - for(let i = 0; i < commands.length; i++) for(let j = 0; j < commands[i].names.length; j++) if(commands[i].names[j] === name){ + for(let i = 0; i < commands.length; i++) for(let j = 0; j < commands[i].names.length; j++) if(commands[i].names[j] === name && checkTags(commands[i].tagsRequired, data.sender)){ const argDefs = commands[i].args, /**@type {Record}*/ @@ -70,8 +82,8 @@ world.beforeEvents.chatSend.subscribe(data=>{ else if(raw[k] !== undefined || !foundOptional) hasError = true; break; case "string": - if(raw[k] !== "") argsToSend[argDefs[k].name] = raw[k]; - else if(raw[k] !== undefined || !foundOptional) hasError = true; + if(raw[k] !== undefined && raw[k] !== "") argsToSend[argDefs[k].name] = raw[k]; + else if(!foundOptional) hasError = true; break; default: console.error(`Illegal argument type in command ${name}: ${argDefs[k].name} is ${argDefs[k].type}`); @@ -79,7 +91,7 @@ world.beforeEvents.chatSend.subscribe(data=>{ return; } if(hasError){ - errorString = `§c.${name}语法错误:意外的“${raw[k]}”出现在参数“${argDefs[k].name}”,应为${argDefs[k].type}类型`; + errorString = `§c.${name}错误:意外的“${raw[k]}”出现在参数“${argDefs[k].name}”,应为${argDefs[k].type}类型`; break; } } @@ -88,7 +100,7 @@ world.beforeEvents.chatSend.subscribe(data=>{ firedCommand = true; } else{ - console.warn(`Player ${data.sender.name} executed command .${name} and occured an error: ${errorString}`); + console.warn(`${data.sender.name} executed .${name} occured error: ${errorString}`); data.sender.sendMessage(errorString); } return; @@ -96,31 +108,39 @@ world.beforeEvents.chatSend.subscribe(data=>{ if(!firedCommand) data.sender.sendMessage(`§c命令不存在或执行权限不足:${name}。输入.help获取命令帮助。`); return; } - if(data.message[0] != prefix) console.log(`<${data.sender.name}>${data.message}`); + if(data.message[0] !== prefix) console.log(`<${data.sender.name}>${data.message}`); }); registerCommand({ names: ["h", "bz", "help"], description: "显示命令帮助。", - args: [], - callback: (_name, player)=>{ - let validCommands = 0; - for(let i = 0; i < commands.length; i++) if(!commands[i].hidden && checkTags(commands[i].tagRequired, player)){ - validCommands++; - let argString = ""; - for(let j = 0; j < commands[i].args.length; j++){ - if(!j) argString += " "; - const arg = commands[i].args[j]; - argString += `${arg.optional ? "[" : "<"}${arg.name} :${arg.type}${arg.optional ? "]" : ">"}`; - if(j < commands[i].args.length - 1) argString += " "; + args: [{ + name: "wantsMore", + optional: true, + type: "boolean" + }], + callback: (_name, player, args)=>{ + if(args.wantsMore === true){ + player.sendMessage("§e§l——基岩服自定义命令使用手册——\nnouino"); + } + else{ + let validCommands = 0; + for(let i = 0; i < commands.length; i++) if(!commands[i].hidden && checkTags(commands[i].tagsRequired, player)){ + validCommands++; + let argString = ""; + for(let j = 0; j < commands[i].args.length; j++){ + if(!j) argString += " "; + const arg = commands[i].args[j]; + argString += `${arg.optional ? "[" : "<"}${arg.name} :${arg.type}${arg.optional ? "]" : ">"}`; + if(j < commands[i].args.length - 1) argString += " "; + } + player.sendMessage(`${prefix}${commands[i].names.length - 1 ? "<" : ""}${commands[i].names.join(" | ")}${commands[i].names.length - 1 ? ">" : ""}${argString} —— ${commands[i].description}`); } - player.sendMessage(`${prefix}<${commands[i].names.join(" | ")}>${argString} —— ${commands[i].description}`); + player.sendMessage(`§e列出完毕,共有 ${validCommands} 条命令。\n§7<>内为必选项;[]内为可选项;|分隔的为多选一;:前为参数名,后为参数类型。输入.h true获取更详细的帮助手册。`); } - player.sendMessage(`§e列出完毕,共有 ${validCommands} 条命令。`); - player.sendMessage("§7<>内为必选项;[]内为可选项;|分隔的为多选一;:前为参数名,后为参数类型。"); return true; - }} -); + } +}); /**检查玩家是否有权限看到并执行某个命令。 * @param {string[] | undefined} tags 需要检查的标签集合,以或门连接。 @@ -137,13 +157,13 @@ const confirmStagePlayers = []; registerCommand({ names: ["reset_all", "reset_all_confirm", "nope"], - description: "【仅限出现故障时使用】清除所有玩家关联的命令数据,如常用语等。", + description: "【仅限出现故障时使用】清除所有你关联的命令数据,如常用语等。", args: [], callback: (name, player)=>{ if(name == "reset_all"){ - if(confirmStagePlayers.includes(player.name)) player.sendMessage("§c错误:你已经在清除确认阶段了!请先输入.nope取消清除。"); + if(confirmStagePlayers.includes(player.name)) player.sendMessage("§c你已经在清除确认阶段了!请先输入.nope取消清除。"); else{ - player.sendMessage(`§c§l你确定要清除所有你关联的数据吗?这可能会导致信息丢失或产生bug!确保你得到了可信的指导再这样做!如果你确认,请输入指令.reset_all_confirm;否则请输入.nope取消清除。`); + player.sendMessage(`§c§l你确定要清除所有你关联的数据吗?这可能会导致信息丢失或产生bug!确保你得到了可信的指导再这样做!如果你确认,请输入.reset_all_confirm;否则请输入.nope取消清除。`); confirmStagePlayers.push(player.name); } } diff --git a/scripts/day.js b/scripts/day.js index 4c59cbe..701cd19 100644 --- a/scripts/day.js +++ b/scripts/day.js @@ -9,10 +9,7 @@ registerCommand({ description: "显示时间量。", args: [], callback: (_name, player)=>{ - system.runTimeout(()=>{ - player.sendMessage(getTimeString(world.getAbsoluteTime(), "世界")); - player.sendMessage(getTimeString(system.currentTick, "服务器")); - }, Math.random() * 3); + system.runTimeout(()=>{player.sendMessage(`${getTimeString(world.getAbsoluteTime(), "世界")}\n${getTimeString(system.currentTick, "服务器")}`)}, Math.random() * 3); return true; } }); diff --git a/scripts/deathCoords.js b/scripts/deathCoords.js new file mode 100644 index 0000000..402f6e9 --- /dev/null +++ b/scripts/deathCoords.js @@ -0,0 +1,23 @@ +//@ts-check +import { Player, world } from "@minecraft/server"; + +export function deathCoordsInit(){} + +/**@type {Map}*/ +const deadPlayerLocations = new Map(); + +world.afterEvents.entityDie.subscribe(data=>{ + if(data.deadEntity.typeId === "minecraft:player"){ + deadPlayerLocations.set(/**@type {Player}*/ (data.deadEntity).name, data.deadEntity.location); + console.log(`${/**@type {Player}*/ (data.deadEntity).name} died at (${data.deadEntity.location.x.toFixed(0)}, ${data.deadEntity.location.y.toFixed(0)}, ${data.deadEntity.location.z.toFixed(0)}) from ${data.damageSource.cause}, ${data.damageSource.damagingEntity?.typeId}, ${data.damageSource.damagingProjectile?.typeId}`); + } +}); + +world.afterEvents.playerSpawn.subscribe(data=>{ + if(!data.initialSpawn){ + const location = deadPlayerLocations.get(data.player.name); + deadPlayerLocations.delete(data.player.name); + if(location) data.player.sendMessage(`§4§l您死在了(${location.x.toFixed(0)}, ${location.y.toFixed(0)}, ${location.z.toFixed(0)})。`); + else data.player.sendMessage("§e§l您死在了没有坐标的地方!"); + } +}); \ No newline at end of file diff --git a/scripts/debug.js b/scripts/debug.js index bf09270..3215538 100644 --- a/scripts/debug.js +++ b/scripts/debug.js @@ -1,13 +1,13 @@ //@ts-check -import { system, Player, world } from "@minecraft/server"; +import { world } from "@minecraft/server"; import { registerCommand } from "./commandBase"; export function debugInit(){} registerCommand({ - names: ["getpp"], + names: ["gpp"], description: "获取玩家的附加属性。", - tagRequired: ["dev"], + tagsRequired: ["dev"], args: [ { name: "player", @@ -28,18 +28,16 @@ registerCommand({ switch(typeof content){ case "string": case "number": - player.sendMessage(`${content}`); + player.sendMessage(`${args.property}: ${content}`); break; case "boolean": - player.sendMessage(content ? "true" : "false"); + player.sendMessage(`${args.property}: ${content ? "true" : "false"}`); break; case "undefined": - player.sendMessage("undefined"); - player.sendMessage("real undefined!"); + player.sendMessage(`${args.property}: undefined\nreal undefined!`); break; case "object": - player.sendMessage(`${content.x}, ${content.y}, ${content.z}`); - player.sendMessage("real Vector3!"); + player.sendMessage(`${args.property}: ${content.x}, ${content.y}, ${content.z}\nreal Vector3!`); break; } } @@ -48,9 +46,9 @@ registerCommand({ }); registerCommand({ - names: ["setpp"], + names: ["spp"], description: "设置玩家的附加属性,undefined6,true6,false6,不支持坐标。", - tagRequired: ["dev"], + tagsRequired: ["dev"], args: [ { name: "player", @@ -72,11 +70,132 @@ registerCommand({ const target = world.getPlayers({name: /**@type {string}*/ (args.player)}); if(target.length === 0) player.sendMessage("§c玩家不在线"); else{ - if(args.value === "undefined6") player.setDynamicProperty(/**@type {string}*/ (args.property), undefined); - else if(args.value === "true6") player.setDynamicProperty(/**@type {string}*/ (args.property), true); - else if(args.value === "false6") player.setDynamicProperty(/**@type {string}*/ (args.property), false); - else player.setDynamicProperty(/**@type {string}*/ (args.property), args.value); + if(args.value === "undefined6") target[0].setDynamicProperty(/**@type {string}*/ (args.property), undefined); + else if(args.value === "true6") target[0].setDynamicProperty(/**@type {string}*/ (args.property), true); + else if(args.value === "false6") target[0].setDynamicProperty(/**@type {string}*/ (args.property), false); + else target[0].setDynamicProperty(/**@type {string}*/ (args.property), args.value); + player.sendMessage(`成功设置${target[0].name}的附加属性${args.property}为${args.value}。`); } return true; } +}); + +registerCommand({ + names: ["cpp"], + description: "清除玩家的附加属性。", + tagsRequired: ["dev"], + args: [{ + name: "player", + optional: false, + type: "string" + }], + callback: (_name, player, args)=>{ + const target = world.getPlayers({name: /**@type {string}*/ (args.player)}); + if(target.length === 0) player.sendMessage("§c玩家不在线"); + else{ + target[0].clearDynamicProperties(); + player.sendMessage(`成功清除${target[0].name}的附加属性。`); + } + return true; + } +}); + +registerCommand({ + names: ["qpp"], + description: "查询玩家的附加属性信息。", + tagsRequired: ["dev"], + args: [{ + name: "player", + optional: false, + type: "string" + }], + callback: (_name, player, args)=>{ + const target = world.getPlayers({name: /**@type {string}*/ (args.player)}); + if(target.length === 0) player.sendMessage("§c玩家不在线"); + else{ + player.sendMessage(`所有ID:${[target[0].getDynamicPropertyIds().join(",")]}`); + player.sendMessage(`占用大小:${target[0].getDynamicPropertyTotalByteCount()}`); + } + return true; + } +}); + +registerCommand({ + names: ["gwp"], + description: "获取世界的附加属性。", + tagsRequired: ["dev"], + args: [{ + name: "property", + optional: false, + type: "string" + }], + callback: (_name, player, args)=>{ + const content = world.getDynamicProperty(/**@type {string}*/ (args.property)); + switch(typeof content){ + case "string": + case "number": + player.sendMessage(`${args.property}: ${content}`); + break; + case "boolean": + player.sendMessage(`${args.property}: ${content ? "true" : "false"}`); + break; + case "undefined": + player.sendMessage(`${args.property}: undefined\nreal undefined!`); + break; + case "object": + player.sendMessage(`${args.property}: ${content.x}, ${content.y}, ${content.z}\nreal Vector3!`); + break; + } + return true; + } +}); + +registerCommand({ + names: ["swp"], + description: "设置世界的附加属性,undefined6,true6,false6,不支持坐标。", + tagsRequired: ["dev"], + args: [ + { + name: "property", + optional: false, + type: "string" + }, + { + name: "value", + optional: false, + type: "string" + } + ], + callback: (_name, player, args)=>{ + if(args.value === "undefined6") world.setDynamicProperty(/**@type {string}*/ (args.property), undefined); + else if(args.value === "true6") world.setDynamicProperty(/**@type {string}*/ (args.property), true); + else if(args.value === "false6") world.setDynamicProperty(/**@type {string}*/ (args.property), false); + else world.setDynamicProperty(/**@type {string}*/ (args.property), args.value); + player.sendMessage(`成功设置世界附加属性${args.property}为${args.value}。`); + return true; + } +}); + +registerCommand({ + names: ["cwp"], + description: "清除世界的附加属性。", + tagsRequired: ["dev"], + args: [], + callback: (_name, player)=>{ + world.clearDynamicProperties(); + player.sendMessage("成功清除世界附加属性。"); + return true; + } +}); + +registerCommand({ + names: ["qwp"], + description: "查询世界的附加属性信息。", + tagsRequired: ["dev"], + args: [], + callback: (_name, player)=>{ + player.sendMessage(`所有ID:${[world.getDynamicPropertyIds().join(" ")]}`); + player.sendMessage(`占用大小:${world.getDynamicPropertyTotalByteCount()}`); + return true; + } }); \ No newline at end of file diff --git a/scripts/fst.js b/scripts/fst.js index 7118ef3..5fcf373 100644 --- a/scripts/fst.js +++ b/scripts/fst.js @@ -1,18 +1,18 @@ //@ts-check import { Player, system, world } from "@minecraft/server"; import { registerCommand } from "./commandBase"; -import { ActionFormData, FormCancelationReason } from "@minecraft/server-ui"; +import { ActionFormData, FormCancelationReason, MessageFormData, ModalFormData } from "@minecraft/server-ui"; export function fstInit(){} -const maxFsts = 6; +const maxFsts = 6, maxLength = 20; registerCommand({ - names: ["s", "cyy", "set", "szcyy", "setfst"], + names: ["s", "cyy", "fst", "set", "szcyy", "setfst"], description: "打开常用语管理窗口。", args: [], callback: (_name, player)=>{ - player.sendMessage("窗口已打开,请关闭聊天栏查看。"); + player.sendMessage("常用语管理窗口已打开,请关闭聊天栏查看。"); system.run(()=>showMain(player)); return true; } @@ -28,11 +28,51 @@ function showMain(player){ if(data !== undefined) mainForm.button(`${i}:${data}`); else mainForm.button(`${i}<未设置>`); } - mainForm.button("§6§l删除所有常用语", "textures/ui/icon_trash.png"); + mainForm.button("§4§l删除所有常用语", "textures/ui/icon_trash.png").button("关闭", "textures/ui/crossout"); mainForm.show(player).then(response=>{ if(response.cancelationReason === FormCancelationReason.UserBusy) system.run(()=>showMain(player)); - else{ + else if(response.selection !== undefined){ + if(response.selection < maxFsts){ + const selection = response.selection + 1; + showFstOp(player, selection); + } + else if(response.selection === maxFsts){ + const removeAllForm = new MessageFormData().title("确认操作").body("确认删除所有常用语?此操作不可恢复!").button1("§4确认").button2("取消"); + removeAllForm.show(player).then(response=>{ + if(response.selection === 0) for(let i = 1; i <= maxFsts; i++) player.setDynamicProperty(`cyy${i}`, undefined); + showMain(player); + }); + } + } + }); +} +/**进入常用语分条管理窗口。 + * @param {Player} player + * @param {number} index + */ +function showFstOp(player, index){ + const + fst = /**@type {string | undefined}*/ (player.getDynamicProperty(`cyy${index}`)), + fstOpForm = new ModalFormData().title(`常用语${index}:${fst ?? "<未设置>"}`).textField("修改内容", "(不修改)").toggle("删除该常用语(优先级大于修改内容)", false); + fstOpForm.show(player).then(response=>{ + if(response.cancelationReason == FormCancelationReason.UserBusy) system.run(()=>showFstOp(player, index)); + else if(response.formValues){ + if(response.formValues[1] === true){ + player.setDynamicProperty(`cyy${index}`, undefined); + showMain(player); + } + else if(response.formValues[0] !== ""){ + if(/**@type {string}*/ (response.formValues[0]).length <= maxLength){ + player.setDynamicProperty(`cyy${index}`, response.formValues[0]); + showMain(player); + } + else{ + const errorForm = new MessageFormData().title("修改失败").body(`常用语过长,不能超过${maxLength}个字符!`).button1("确定").button2("取消"); + errorForm.show(player).then(()=>showMain(player)); + } + } + else if(!response.canceled) showMain(player); } }); } diff --git a/scripts/fst_old.js b/scripts/fst_old.js deleted file mode 100644 index 9fc14c4..0000000 --- a/scripts/fst_old.js +++ /dev/null @@ -1,107 +0,0 @@ -//@ts-check -import { world } from "@minecraft/server"; -import { registerCommand } from "./commandBase"; - -export function fstInit(){} - -const max = 6; - -registerCommand({ - names: ["s", "cyy", "set", "szcyy", "setfst"], - description: "管理常用语。使用.s add添加或替换,.s list列出,.s remove删除,.s remove_all删除全部。", - args: [ - { - name: "operation", - optional: false, - type: "string" - }, - { - name: "number", - optional: true, - type: "number" - }, - { - name: "text", - optional: true, - type: "string" - } - ], - callback: (_name, player, args)=>{ - /**@type {number}*/ - let index; - switch(args.operation){ - case "add": - if(args.number === undefined) player.sendMessage(`§c错误:未指定常用语。`); - else if(args.text == undefined) player.sendMessage(`§c错误:未输入常用语。`); - else{ - index = Math.floor(/**@type {number}*/ (args.number)); - if(index > max) player.sendMessage(`您最多设置${max}条常用语!`); - else if(index <= 0) player.sendMessage(`§c错误:${index}不是有效的正整数。`); - else{ - const last = player.getDynamicProperty(`cyy${index}`); - if(last !== undefined) player.sendMessage(`已替代第${index}条常用语(${last})。`); - else player.sendMessage(`已创建第${index}条常用语:${args.text}。`); - player.setDynamicProperty(`cyy${index}`, args.text); - } - } - break; - case "remove": - if(args.number === undefined) player.sendMessage(`§c错误:未指定常用语。`); - else{ - index = Math.floor(/**@type {number}*/ (args.number)); - if(index > max) player.sendMessage(`您最多设置${max}条常用语!`); - else if(index <= 0) player.sendMessage(`§c错误:${index}不是有效的正整数。`); - else{ - const fst = player.getDynamicProperty(`cyy${index}`); - if(fst !== undefined){ - player.setDynamicProperty(`cyy${index}`, undefined); - player.sendMessage(`已删除第${index}条常用语(${fst})`) - } - else player.sendMessage(`§c错误:未设置第${index}条常用语。`); - } - } - break; - case "remove_all": - for(let i = 0; i < max; i++) player.setDynamicProperty(`cyy${i}`, undefined); - player.sendMessage("成功删除所有常用语。"); - break; - case "list": - player.sendMessage("§e设置的常用语:"); - for(let i = 1; i <= max; i++){ - const fst = /**@type {string | undefined}*/ (player.getDynamicProperty(`cyy${i}`)); - if(fst !== undefined) player.sendMessage(`第${i}条:${fst}`); - else player.sendMessage(`第${i}条:§7<未设置>`); - } - break; - default: - player.sendMessage(`§c未知操作:${args.operation}。请使用.s add添加或替换常用语,.s list列出常用语,.s remove删除常用语,.s remove_all删除所有常用语。`); - break; - } - return true; - } -}); - -registerCommand({ - names: ["a", "aaa", "send", "fscyy", "sendfst"], - description: "发送常用语。", - args: [{ - name: "number", - optional: false, - type: "number" - }], - callback: (_name, player, args)=>{ - const index = Math.floor(/**@type {number}*/ (args.number)); - if(index > max) player.sendMessage(`您最多有${max}条常用语!`); - else if(index <= 0) player.sendMessage(`§c错误:${index}不是有效的正整数。`); - else{ - const fst = player.getDynamicProperty(`cyy${index}`); - if(fst !== undefined && fst !== ""){ - const str = `<${player.name}> ${fst}`; - world.sendMessage(str); - console.log(str); - } - else player.sendMessage(`§c未设置第${index}条常用语。`); - } - return true; - } -}); \ No newline at end of file diff --git a/scripts/loopCommands.js b/scripts/loopCommands.js index 943f279..7aabb3e 100644 --- a/scripts/loopCommands.js +++ b/scripts/loopCommands.js @@ -61,7 +61,7 @@ function removeSurvival(ids, warn){ const item = container.getItem(j); if(item && item.typeId.includes(ids[k])){ container.setItem(j); - console.error(`Illegal item ${item.typeId} x${item.amount} found in player ${players[i].name} at (${players[i].location.x.toFixed(1)},${players[i].location.y.toFixed(1)},${players[i].location.z.toFixed(1)})`); + console.error(`Illegal item ${item.typeId} x${item.amount} found in ${players[i].name} at (${players[i].location.x.toFixed(1)},${players[i].location.y.toFixed(1)},${players[i].location.z.toFixed(1)})`); if(warn) players[i].sendMessage(`§c§l检测到违禁物品:${item.typeId.replace("minecraft:", "")},已清除并上报!`); } } diff --git a/scripts/main.js b/scripts/main.js index 3faa310..63538ca 100644 --- a/scripts/main.js +++ b/scripts/main.js @@ -8,6 +8,7 @@ import { tridentInit } from "./trident"; import { welcomeInit } from "./welcome"; import { fstInit } from "./fst"; import { debugInit } from "./debug"; +import { deathCoordsInit } from "./deathCoords"; commandInit(); welcomeInit(); @@ -18,4 +19,6 @@ dayInit(); tridentInit(); debugInit(); +deathCoordsInit(); + loopCommandsInit(); \ No newline at end of file diff --git a/scripts/message.js b/scripts/message.js index 4570951..fc73ad6 100644 --- a/scripts/message.js +++ b/scripts/message.js @@ -5,7 +5,7 @@ import { registerCommand } from "./commandBase"; export function messageInit(){} -const players = [ +const absPlayerNames = [ "LJM12914", "DK6666Orange", "TJJ456", @@ -16,61 +16,139 @@ const players = [ "Cr3st_39" ]; -const maxMessages = 20; +const maxMessages = 2; registerCommand({ names: ["m", "msg", "message"], description: "打开留言窗口。", args: [], callback: (_name, player)=>{ - player.sendMessage("窗口已打开,请关闭聊天栏查看。"); + player.sendMessage("留言窗口已打开,请关闭聊天栏查看。"); system.run(()=>showMain(player)); return true; } }); -/**进入留言窗口。 +/**进入留言主窗口。 * @param {Player} player */ function showMain(player){ - const mainForm = new ActionFormData().title("留言").button("给玩家留言", "textures/ui/newOffersIcon").button(`您的未读留言(2条)`, "textures/ui/mute_off").button("关闭", "textures/ui/crossout"); + const + info = getUnreadInfo(player), + mainForm = new ActionFormData().title("留言").button("发送留言", "textures/ui/newOffersIcon").button(`您的未读留言§l(${info.length}条)`, "textures/ui/FriendsDiversity").button("已发送的未读留言", "textures/ui/mute_off").button("关闭", "textures/ui/crossout"); mainForm.show(player).then(response=>{ if(response.cancelationReason === FormCancelationReason.UserBusy) system.run(()=>showMain(player)); - else if(response.selection === 0){ - const - filteredPlayers = ["§7<未选择>", ...players.filter(value=>!world.getPlayers({name: value}).length)], - selectForm = new ModalFormData().title("选择玩家").dropdown("选择接收玩家:", filteredPlayers); - selectForm.show(player).then(selectResponse=>{ - if(!selectResponse.canceled && selectResponse.formValues){ - const target = filteredPlayers[/**@type {number}*/(selectResponse.formValues[0])]; - if(target === "§7<未选择>") player.sendMessage("§c错误:未选择要发送留言的玩家!"); - else{ - let foundEmpty = false; - for(let i = 1; i <= maxMessages; i++) if(world.getDynamicProperty(`${target}#${i}`) === undefined){ - foundEmpty = true; - const sendForm = new ModalFormData().title("编辑内容").textField(`发送给${target}:`, "输入留言内容"); - sendForm.show(player).then(sendResponse=>{ - const formValues = sendResponse.formValues; - if(!sendResponse.canceled && formValues){ - if(formValues[0] === "") player.sendMessage("§c错误:不能发送空白留言!"); - else{ - world.setDynamicProperty(`${target}#${i}`, ""); - } - } - }); - break; - } - if(foundEmpty) player.sendMessage(`§e已经成功发送留言给${target}。在其上线前,你仍能在“已发送留言”处查看发送的内容。`); - else player.sendMessage(`§c错误:${target}拥有太多的未读留言,已经无法给其留言!`); - } - //else player.sendMessage("§c错误:未选择玩家。"); - } - }); - } + else if(response.selection === 0) showSendSelect(player); else if(response.selection === 1){ - const infoForm = new ActionFormData(); - player.sendMessage("b"); + if(info.length) showReadMain(player, 0); + else world.sendMessage("无未读留言。"); + } + else if(response.selection === 2) showSent(player); + }); +} + +/**进入选择留言对象窗口。 + * @param {Player} player + */ +function showSendSelect(player){ + const + filteredPlayers = ["§7", ...absPlayerNames.filter(value=>!world.getPlayers({name: value}).length)], + selectForm = new ModalFormData().title("选择玩家").dropdown("选择接收玩家:", filteredPlayers); + selectForm.show(player).then(selectResponse=>{ + if(!selectResponse.canceled && selectResponse.formValues){ + const target = filteredPlayers[/**@type {number}*/(selectResponse.formValues[0])]; + if(target !== "§7") showSendEdit(player, target); + else showSendSelect(player); } }); +} + +/**进入输入留言内容窗口。 + * @param {Player} player 发送者。 + * @param {string} target 接收者的名称。 + */ +function showSendEdit(player, target){ + let foundEmpty = false; + for(let i = 1; i <= maxMessages; i++) if(world.getDynamicProperty(`${target}#${player.name}#${i}`) === undefined){ + foundEmpty = true; + const sendForm = new ModalFormData().title("编辑内容").textField(`发送给${target}:`, "输入留言内容"); + sendForm.show(player).then(sendResponse=>{ + const formValues = sendResponse.formValues; + if(!sendResponse.canceled && formValues){ + if(formValues[0] === "") showSendEdit(player, target); + else{ + world.setDynamicProperty(`${target}#${player.name}#${i}`, `${formValues[0]}`); + player.sendMessage(`§e已经成功发送留言给${target}。在其上线并查看留言前,你仍能在“已发送的未读留言”处查看发送的内容。`); + } + } + }); + break; + } + if(!foundEmpty) player.sendMessage(`§c${target}拥有太多的未读留言,无法再给其发送留言!`); +} + +/**进入阅读未读留言主窗口。 + * @param {Player} player + * @param {number} index + */ +function showReadMain(player, index){ + const + info = getUnreadInfo(player), + infoForm = new ActionFormData().body(`第${index + 1}条,共${info.length}条\n发送者:${info[index].sender}\n${info[index].content}\n\n留言序号:${info[index].innerIndex}\n\n\n§c离开此页面后本留言将被删除!\n若需要保存信息,请使用截图等方式`); + if(index !== info.length - 1) infoForm.button("下一条", "textures/ui/arrow_right_white"); + infoForm.button("关闭", "textures/ui/crossout"); + infoForm.show(player).then(response=>{ + if(response.selection === 0 && index !== info.length - 1) showReadMain(player, index + 1); + world.setDynamicProperty(`${player.name}#${info[index].sender}#${info[index].innerIndex}`, undefined); + }); +} + +/**进入已发送未读留言窗口。 + * @param {Player} player + */ +function showSent(player){ + const + wps = world.getDynamicPropertyIds(), + /**@type {string[]}*/ + sents = [], + sentForm = new ActionFormData().title("已发送的未读留言"); + for(let i = 0; i < wps.length; i++) if(wps[i].includes("#")){ + const raw = wps[i].split("#"); + if(raw.length === 3 && raw[1] === player.name) sents.push(`给${raw[0]}的${raw[2]}号留言:${world.getDynamicProperty(wps[i])}`); + } + sentForm.body(`————共${sents.length}条————\n\n${sents.join("\n\n")}\n\n`).button("关闭", "textures/ui/crossout"); + sentForm.show(player); +} + +world.afterEvents.playerSpawn.subscribe(data=>{ + if(data.initialSpawn) system.runTimeout(()=>{ + const info = getUnreadInfo(data.player); + if(info.length) data.player.sendMessage(`§e§l您有${info.length}条未读留言,输入.m查看。`); + }, 81); +}); + +/**获取玩家的未读消息。 + * @param {Player} player + * @typedef {{ + * sender :string; + * innerIndex :number; + * content :string; + * }[]} messageInfos + * @returns {messageInfos} + */ +function getUnreadInfo(player){ + const + wps = world.getDynamicPropertyIds(), + /**@type {messageInfos}*/ + result = []; + for(let i = 0; i < wps.length; i++) if(wps[i].includes("#")){ + const raw = wps[i].split("#"); + if(raw.length === 3 && raw[0] === player.name) result.push({ + sender: raw[1], + innerIndex: parseInt(raw[2]), + content: /**@type {string}*/ (world.getDynamicProperty(wps[i])) + }); + } + return result; } \ No newline at end of file diff --git a/scripts/welcome.js b/scripts/welcome.js index ae5b10b..e0bfd48 100644 --- a/scripts/welcome.js +++ b/scripts/welcome.js @@ -22,9 +22,6 @@ registerCommand({ world.afterEvents.playerSpawn.subscribe(data=>{ if(data.initialSpawn) system.runTimeout(()=>{ const player = world.getPlayers({name: data.player.name})[0]; - if(player.getDynamicProperty("disableWelcome") != true){ - player.sendMessage(`§6§l基岩之上服务器第八季`); - player.sendMessage(`§b欢迎玩家${player.name},输入.h查看命令帮助,输入.j false关闭进服提示。`); - } + if(player.getDynamicProperty("disableWelcome") != true) player.sendMessage(`§6§l基岩之上服务器第八季\n§b欢迎玩家${player.name},输入.h查看命令帮助,输入.j false关闭进服提示。`); }, 80); }); \ No newline at end of file