Numerical Storage
概述
Numerical Storage 让你为每位玩家创建具名的数值存储:银行账户、法力池、代币钱包,或任意资源的储备。你只需在一个 definition 中描述一次存储,扩展就会为每位玩家保存一个余额和一个等级。
存储可以拥有等级,每个等级都有最大容量。玩家通过一个使用 GUI 扩展构建的物品栏菜单向其中存入和取出。资金可以通过 Vault 来自你的经济插件,也可以来自你选择的任意占位符和控制台命令。利息可以按计划增加,存储还可以通过命令重置、编辑或打开。
余额保存在 TypeWriter artifact 中并异步写入,因此存款永远不会阻塞服务器主线程。余额、等级和容量会以 PlaceholderAPI 占位符的形式提供,可用于计分板、全息图和菜单。
功能
- 多个存储 — 你需要多少个 definition 就能创建多少个,每个都有自己的名称、前缀、等级和菜单。
- 等级与容量 — 每个等级都有最大余额;玩家通过升级来提高它。
- 等级要求 — 通过占位符或 fact 的比较来解锁某个等级,还可以选择扣除费用。
- 利息 — 支持 cron 计划、全局利率、按等级的利率以及按权限的利率,并带有每个周期的上限。
- Vault 或命令 — 存款和取款可通过 Vault 进行,也可通过占位符加控制台命令进行。
- 转账 — 在两个存储之间以原子方式转移余额。
- 菜单按钮 — 固定金额、百分比、全部、自定义金额(对话框)、子菜单、升级和关闭。
- 安全的持久化 — 异步保存、每个 artifact 一把锁,以及对旧文件的自动迁移。
- 档案模式 — 通过 MMOProfiles 实现的可选按档案余额。
- 占位符和命令 — 可在任何地方读取数值,并通过控制台进行编辑。
安装
- 安装 GUI 扩展:Numerical Storage 的菜单需要它。GUI 扩展以
GuiAndDialogs的名称发布。 - 如果你想使用
%typewriter_ns_...%占位符,请安装 PlaceholderAPI。 - 可选:安装 Vault(扩展基于 VaultUnlocked 构建)和一个经济插件,以使用
VAULT交易模式。 - 可选:安装 MMOProfiles 以使用
profileMode。 - 将 Numerical Storage 的 JAR 放入
plugins/Typewriter/extensions/,然后重启服务器。
自定义金额窗口使用 Paper 对话框,因此需要使用支持它们的 Paper 版本(Minecraft 1.21.6 或更高)。
自 0.9 版本起,新的 artifact 使用技术标识符和 JSON schema 版本 2。旧文件在第一次被读取时,会被复制到新路径,保存到 backups/numericalstorage/ 下,并被删除。更新前请保留一份 TypeWriter assets/ 文件夹的副本。
快速上手
创建一个使用你的 Vault 经济支付的银行:
- 在 TypeWriter 网页面板中,打开一个 manifest 页面,添加一个 Player Numerical Storage artifact。让
artifactId保持为空:TypeWriter 会自动生成。 - 添加一个 Numerical Storage Definition。设置
displayName(例如Bank)、prefix,并在artifact中链接该 artifact。 - 在
levels中添加第一个等级,limit为1000,再添加第二个等级,上限为5000。如果想要自定义文本,请填写depositMessage和levelUpMessage。 - 在
transaction中,将transactionMode设为VAULT。 - 在
menu.transactionButtons中添加一个类型为DEPOSIT的按钮,amountType为FIXED,amount为100,并设置要显示的物品。再添加第二个类型为WITHDRAW的按钮。 - 添加一个 Open Numerical Storage Menu 动作。链接
definition。 - 在其
layoutPool中,添加一个id为main的simple布局,并将mainLayoutId设为main。在布局中添加一个物品,将buttonPrefix设为numericalstorage_button:,buttonType设为DEPOSIT_FIXED:100。对WITHDRAW_FIXED:100、UPGRADE_LEVEL和NAV_CLOSE也这样操作。 - 将该动作链接到某个 NPC 对话或命令事件,发布,然后在游戏中打开银行。你也可以运行
/typewriter ns open <definition>。
每次交易之后,菜单都会重新打开以显示新的余额。扩展会查找链接到同一 definition 的 Open Numerical Storage Menu 条目。如果没有,菜单会直接关闭。
工作原理
菜单
菜单是一个普通的 GUI 布局。Open Menu 动作会使用 definition 中的标题和行数(menu.title、menu.rows,1 到 6)打开它,而你的 layoutPool 决定每个物品放在哪里。当物品的 buttonPrefix 设为 numericalstorage_button:,并且 buttonType 取自下面的列表时,扩展会把该物品变成一个可用的按钮:
buttonType | 按钮的作用 |
|---|---|
DEPOSIT_FIXED | 存入固定金额。在冒号后添加金额,例如 DEPOSIT_FIXED:100。 |
DEPOSIT_PERCENT | 存入来源余额的某个百分比,例如 DEPOSIT_PERCENT:50。 |
DEPOSIT_CUSTOM | 关闭菜单,并通过对话框询问金额。 |
DEPOSIT_ALL | 存入来源余额,上限为剩余容量。这需要 amountPlaceholder:在 VAULT 模式下,该按钮会尝试存入全部剩余容量,如果经济余额更低则会失败。 |
DEPOSIT_SUBMENU | 打开一个存款按钮的子菜单。子菜单 id 跟在冒号之后。 |
WITHDRAW_FIXED, WITHDRAW_PERCENT, WITHDRAW_CUSTOM, WITHDRAW_ALL, WITHDRAW_SUBMENU | 与上面相同,但用于取款。百分比取自已存储的余额。 |
TRANSFER_FIXED, TRANSFER_PERCENT, TRANSFER_ALL | 将余额转移到另一个 definition。该按钮来自 transactionButtons 中类型为 TRANSFER、并带有 transferTarget 的条目。 |
SUB_MENU | 打开 id 跟在冒号之后的子菜单,例如 SUB_MENU:deposit_options。 |
UPGRADE_LEVEL | 升级到下一等级,或显示最高等级的物品。 |
NAV_CLOSE | 关闭菜单。 |
当 buttonType 带有金额(DEPOSIT_FIXED:100)时,扩展会在 menu.transactionButtons 中选取类型、金额类型和金额都相同的条目,并使用它的 template 作为物品。没有金额时,则使用第一个匹配的条目。如果没有任何匹配,则会显示一个带有默认标签的普通染料物品。
子菜单在 menu.subMenus 中定义,它是从 id 到标题、行数、放置在 slots 中的交易按钮、返回按钮和关闭按钮的映射。
转账按钮需要另一个 definition 的 transferTarget(其条目 id),并且玩家在目标存储中必须还有空间。
命令
所有命令都是 /typewriter(别名 /tw)的子命令。<definition> 是一个 definition 条目。可选的 [target] 用于选择另一位玩家;不填时命令作用于发送者。
| 命令 | 权限 | 说明 |
|---|---|---|
/typewriter ns open <definition> [target] | typewriter.ns.open | 通过其 Open Menu 条目打开该存储的菜单。 |
/typewriter ns add <definition> <amount> [target] | typewriter.ns.add | 增加余额。不检查容量。 |
/typewriter ns remove <definition> <amount> [target] | typewriter.ns.remove | 减少余额,最低减至 0。 |
/typewriter ns level <definition> <level> [target] | typewriter.ns.level | 设置等级,并将余额重置为 0。 |
/typewriter ns reset <definition> [target] | typewriter.ns.reset | 将等级重置为 1,并将余额重置为 0。 |
命令 /typewriter numstorage tx ...、upgrade 和 back_main 由菜单按钮在内部使用。对于没有打开菜单的玩家,它们不会有任何效果。
启用 profileMode 时,add、remove、level 和 reset 会像菜单一样更改目标档案的余额和等级。
命令回复
add、remove、level、reset 和 open 的回复,以及下面的错误回复,都是定义上 adminMessages 的字段,使用 MiniMessage。每条都可以使用 <player>、<storage>(定义的 id)和 <prefix>。
| 字段 | 额外占位符 | 默认值 |
|---|---|---|
resetMessage | 无 | Numerical storage reset for <player>. |
levelSetMessage | <level> | Set numerical storage level to <level> for <player>. |
addMessage | <amount> | Added <amount> to <player>. |
removeMessage | <amount> | Removed <amount> from <player>. |
noMenuMessage | 无 | 存储没有 Open Menu 条目时显示的消息。 |
invalidAmountMessage | <amount>(输入的值) | Invalid amount '<amount>'. Use a positive number. 当数额不是正数时,由 add 和 remove 显示。 |
noArtifactMessage | 无 | 定义没有关联 artifact 时,add、remove、level 和 reset 显示的消息。 |
noActiveProfileMessage | 无 | <player> has no active profile. 当 profileMode 开启且玩家没有活动的 MMOProfiles 档案时,由 add、remove、level 和 reset 显示,也会显示给点击菜单操作的玩家。不会写入任何内容。 |
默认值以 Typewriter 前缀开头。有三条文本不属于任何定义,因此改为 snippets.yml 中的 snippet:numericalstorage.command.player_only(由非玩家执行的菜单按钮命令),以及占位符文本 numericalstorage.placeholder.interest_disabled(Disabled)、numericalstorage.placeholder.interest_error(Error)和 numericalstorage.placeholder.capacity_unlimited(无穷符号)。interest_cooldown 的时间单位是 snippet numericalstorage.duration.days、hours、minutes、seconds(每个都是带 {value} 的模板,默认为 {value}j)和 numericalstorage.duration.separator。
权限
| 权限 | 授予 |
|---|---|
typewriter.ns.open | /typewriter ns open。 |
typewriter.ns.add | /typewriter ns add。 |
typewriter.ns.remove | /typewriter ns remove。 |
typewriter.ns.level | /typewriter ns level。 |
typewriter.ns.reset | /typewriter ns reset。 |
interestRates 中的权限 | 为玩家指定特定的利率。使用列表中玩家拥有的第一个权限。 |
占位符
将 <id> 替换为 definition 的条目 id。它们需要 PlaceholderAPI,并且从缓存中读取,因此可以安全地用于计分板。启用 profileMode 时,balance、level、capacity 和 interest 会像菜单一样,跟随玩家当前使用的档案。
| 占位符 | 返回值 |
|---|---|
%typewriter_ns_balance_<id>% | 当前余额。 |
%typewriter_ns_level_<id>% | 当前等级,从 1 开始。 |
%typewriter_ns_capacity_<id>% | 当前等级的容量;如果没有定义等级,则返回无穷符号。 |
%typewriter_ns_interest_<id>% | 适用于该玩家的利率,以百分比表示。 |
%typewriter_ns_interest_cooldown_<id>% | 距离下一个计划利息周期的时间,或 Disabled。 |
%typewriter_ns_name_<id>% | definition 的 displayName。 |
%typewriter_ns_prefix_<id>% | definition 的 prefix。 |
条目
4 个条目,由扩展源码生成。
动作2
- Numericalstorage MenuOpens a Numerical Storage menu
- Numericalstorage Open MenuOpens a Numerical Storage menu (triggerable)
构件1
- Player Numericalstorage ArtifactStores the numericalstorage amount per player
清单1
- Numericalstorage DefinitionDefines a configurable numerical storage
故障排查
菜单打开后是空的,或按钮没有反应。 请检查每个物品的 buttonPrefix 是否严格设为 numericalstorage_button:,并且 buttonType 有效。如果前缀有误,该物品只会是一个没有任何动作的普通物品。同时检查 mainLayoutId 是否与 layoutPool 中某个布局的 id 匹配。
每次存款之后菜单都会关闭。 菜单是通过链接到同一 definition 的 Open Numerical Storage Menu 条目重新打开的。请添加一个,即使你是用其他条目来打开菜单的。
“Cannot add ... Would exceed limit”。 该存储已达到玩家当前等级的容量(levels[].limit)。请升级等级或提高上限。如果没有定义等级,则没有上限。
INTERNAL 模式下存款失败。 玩家的来源余额是通过 amountPlaceholder 读取的,必须返回一个纯数字。addCommand 会在存款之前由控制台运行,并且必须成功。请在命令中使用 {player} 和 {amount}。
“Economy system is not available.” transactionMode 为 VAULT,但缺少 Vault 或经济提供者。请两者都安装,然后重启。
利息没有发放。 利息会在玩家加入时结算,针对自其上次领取以来所经过的 cron 周期(最多 100 个周期)。必须开启 interestEnabled 并填写 interestCron。首次加入只会记录起始时间。余额已达到其等级容量时不会产生收益。
升级要求的费用是容量。 当下一等级没有 criteria 时,升级的费用是当前等级的 limit,从已存储的余额中扣除。请在下一等级上添加 criteria 来定义不同的要求。
占位符显示的是另一个档案的余额。 开启 profileMode 时,占位符和升级按钮读取玩家所选档案的余额和等级。没有 MMOProfiles 时,读取玩家自己的余额。有 MMOProfiles 但没有活动档案时(选择界面,或 /mmoprofiles quit 之后),显示 0,因为玩家的 UUID 是其 Main 档案的 id,不能显示或增加它的余额。写入会被 noActiveProfileMessage 拒绝,档案的利息在选择该档案时结算。
重启后占位符立刻显示为空。 存储在加入时于后台加载:第一次读取可能早于加载完成;下一次读取会显示已保存的值。
占位符为空。 占位符中的 id 必须是 definition 的条目 id,而不是它的名称。运行 /papi parse me %typewriter_ns_balance_<id>% 进行测试。
相关扩展
- GUI — 用于布局和按钮的菜单引擎。
- MMOProfiles — 可选,供
profileMode使用。