跳到主要内容

Vote System

游戏内投票,支持选项、截止日期、每位玩家一票和实时占位符。

免费v0.9社交
依赖TypeWriter0.9PlaceholderAPI可选

概览​

Vote System 为你的服务器添加投票功能。一个投票就是一个投票定义:包含标题、选项列表、可选的结束日期,以及投票关闭后显示的消息。每位玩家在每个投票中只能投一次票,可通过 TypeWriter 动作(对话选项、NPC、菜单点击)或命令投票。投票数据存储在 TypeWriter 构件中。

结果以 PlaceholderAPI 占位符的形式提供,因此你可以将其显示在计分板、全息图或菜单中,管理员还可以通过命令查看。这是玩家之间的投票,而不是服务器列表投票网站的链接。

功能​

  • 多选项投票 — 每个选项都有自己的文本,可包含占位符和颜色。
  • 每位玩家一票 — 对同一投票的第二次投票会被拒绝,除非你在 Vote Config 中设置了用于再次投票的 cooldownSeconds。
  • 结束日期 — 在指定的日期和时间自动关闭投票。
  • 关闭和阻止消息 — 告诉迟到的投票者投票已结束,告诉过早再次投票的玩家需要等待。两者都是 MiniMessage。
  • 投票动作 — 为触发的玩家投出一票,并且仅在投票被记录时才继续你的序列。
  • 状态消息 — 根据玩家是否已投票发送不同的消息。
  • 实时结果 — 总票数、各选项票数以及玩家所选的选项,均以占位符提供。
  • 管理员命令 — 代玩家投票、读取结果以及重置投票。

安装​

  1. 如果你想用占位符显示结果,请安装 PlaceholderAPI。
  2. 将 Vote System 的 JAR 放入 plugins/Typewriter/extensions/ 并重启服务器。

快速上手​

举办一场关于下一个地图主题的投票:

  1. 在 TypeWriter 网页面板中,打开一个**清单(manifest)**页面,添加一个 Vote Data 构件。保留默认的 artifactId(vote_storage)。
  2. 添加一个 Vote Definition。将 displayName 设为 Next map theme,在 options 中添加三项(例如 Desert、Snow、Jungle),并在 data 中链接该构件。
  3. 将 endDate 设为 UTC 日期和时间,例如 2026-12-31T23:00:00Z,并将 closedMessage 设为一段简短的文本。若投票没有结束时间,请将 endDate 留空。
  4. 打开一个**序列(sequence)**页面。为每个选项添加一个 Vote Action:链接 definition,并将 optionIndex 设为 0、1 或 2。选项索引从 0 开始。
  5. 将每个动作连接到某个对话选项、NPC 交互或菜单按钮,并把你的感谢消息或奖励放入该动作的 triggers 中。它们只会在投票被记录时运行。
  6. 可选:在选项之前添加一个 Vote Message,用来提醒已经投过票的玩家。
  7. 发布。在计分板上使用 %typewriter_vote_total_<definition id>% 即可显示票数。
保留定义 id

投票的数据存储在由其投票定义的条目 id 派生出的键下。如果你删除该条目或更改其 id,就再也找不到已存储的投票。

命令​

所有命令都是 /typewriter(别名 /tw)的子命令。<definition> 是投票定义的 id 或名称。

命令权限说明
/typewriter vote <definition> <option> [target]typewriter.vote.cast为某个选项投票。选项从 1 开始。指定 target 时,为所选玩家投票。
/typewriter vote stats [definition]typewriter.vote.stats显示某个投票或全部投票中各选项的票数和总数。
/typewriter vote reset <definition>typewriter.vote.reset删除某个投票的全部票数。

它们同时都需要 typewriter.vote。

可编辑文本​

游戏中显示的文本没有任何一条固定在代码里。一次投票的消息是其条目的字段:Vote Definition 的 closedMessage,以及 Vote Message 的两条消息。/typewriter vote 命令的回复是 TypeWriter 的 snippet,因此无需重新构建即可改写、翻译或重新着色。打开 plugins/Typewriter/snippets.yml,找到 content.vote 下的键,修改值并运行 /tw reload。扩展在启动时会以默认文本注册其所有 snippet,因此首次启动后它们会出现在该文件中。保持默认值则不会有任何变化。

命令回复使用 MiniMessage。发送时带有 Typewriter 回复前缀(Typewriter »),该前缀来自引擎,不属于这些 snippet。文本中的 {name} 会被表中所列的值替换;不存在的占位符会原样保留,值中不会再次查找占位符。服务器控制台日志保持英文。

Snippet(位于 content.vote. 下)默认值占位符
usage<gray>Usage: /tw vote <definition> <option> [target]</gray>无
option_unavailable<red>Option {option} is not available for {definition}.</red>{option} (输入的编号), {definition} (投票的 id)
already_voted<red>{player} cannot vote in {definition} yet.</red>{player}, {definition}
cast_option_fallbackoption {number}{number} (选项的位置,从 1 开始)
recorded_for_voterYour vote for <blue>{definition}</blue> has been recorded as <green>{option}</green>.{definition}, {option} (选项的文本)
recorded_by_otherRecorded vote for <blue>{player}</blue> in {definition}: {option}.{player}, {definition}, {option}
recorded_for_selfVote registered for {definition}: {option}.{definition}, {option}
cast_failed<red>Unable to register the vote for {player} in {definition}.</red>{player}, {definition}
reset_done<green>Votes reset for {definition}.</green>{definition}
no_definitionsThere are no active vote definitions.无
stats_lineStats for {name} [{definition}]: {options} | total: {total}{name} (displayName,为空时为条目名称), {definition}, {options}, {total}
stats_option{number}: {votes} ({label}){number}, {votes}, {label} (选项的文本)
stats_option_fallbackOption {number}{number}
stats_separator, 无
entry_not_foundCould not find entry {entry}{entry} (输入的内容)
entry_rejectedEntry did not pass filter无

stats_option 会为每个选项重复一次,结果用 stats_separator 连接,组成 stats_line 的 {options}。stats_option_fallback 是没有文本的选项的 {label},cast_option_fallback 是此类选项在记录投票时所发消息中的名称。最后两个 snippet 是命令错误,由游戏以红色显示:它们是纯文本,不使用 MiniMessage。

投票关闭时,/tw vote 会向工作人员显示该投票的 closedMessage(只有该消息为空时才使用 cast_failed)。cast_failed 也用于缺少数据条目或选项超出范围的情况。

权限​

权限授予
typewriter.vote访问 /typewriter vote 命令。
typewriter.vote.cast通过命令投票。
typewriter.vote.stats通过命令读取结果。
typewriter.vote.reset重置投票。

投票动作不会检查这些权限:它只需要该条目被执行。

占位符​

将 <id> 替换为投票定义的条目 id。它们需要 PlaceholderAPI。

占位符返回
%typewriter_vote_display_<id>%投票的 displayName。
%typewriter_vote_option_<id>_<n>%第 n 个选项的文本,从 1 开始。
%typewriter_vote_total_<id>%总票数。
%typewriter_vote_stats_<id>%每个选项的票数,以逗号分隔。
%typewriter_vote_stats_<id>_<n>%第 n 个选项的票数,从 1 开始。
%typewriter_vote_player_<id>%玩家所投选项的文本;如果没有投票则为空。
%typewriter_vote_has_voted_<id>%玩家暂时无法再次投票(已投票且冷却未结束)时为 1,否则为 0。
%typewriter_vote_closed_<id>%结束日期已过时为 1,否则为 0。
%typewriter_vote_remaining_<id>%距结束日期的整秒数;没有结束日期或已过期时为 0。

vote_votes_<id> 的作用与 vote_stats_<id> 相同。

条目​

7 个条目,由扩展源码生成。

动作2
事件1
事实1
构件1
清单2
当前版本未使用的条目

Vote Cast Event 和 Vote Fact 虽然存在,但目前没有任何功能读取它们:该事件从不触发,事实也不会由投票填充。Vote Config 会被读取:它设置再次投票的冷却时间和调试日志。

故障排查​

投票没有被记录。 当缺少某些内容时,动作和命令会静默失败:投票定义必须已链接 data 构件,选项必须存在,玩家不能已经投过票(或其冷却必须已结束,见 Vote Config),并且投票不能已过 endDate。当投票已关闭时,closedMessage 会发送给玩家。玩家仍需等待时,会发送 blockedMessage。在 Vote Config 中开启 debug,可记录每次拒绝的原因。

票投给了错误的选项。 投票动作的选项从 0 开始计数,而命令和占位符从 1 开始计数。

投票始终不会关闭。 endDate 必须是以 UTC 表示、以 Z 结尾的 ISO-8601 时刻,例如 2026-12-31T23:00:00Z。其他格式的值会被忽略,投票将保持开放。

重命名条目后结果为空。 票数与定义的条目 id 绑定。请恢复旧 id,或重置投票后重新开始。

占位符原样显示。 请检查是否已安装 PlaceholderAPI,以及 id 是否为该定义的条目 id。在第一次投票之前请求占位符时,扩展同样能找到对应的定义。

消息中的颜色看起来不对。 Vote Message 的状态消息、closedMessage 和 blockedMessage 会在解析占位符后按 MiniMessage 读取:请写 <red>文本</red>,不要使用 &c 代码。

玩家可以投两次票。 如果 Vote Config 中的 cooldownSeconds 大于 0,冷却结束后这是预期行为。否则,检查按玩家和按投票进行。使用多个选项相同的投票定义会创建彼此独立的投票。