跳到主要内容

Puzzle

九种谜题类型,包含客户端棋盘、计时器、尝试次数、链式关联和事实。

免费v0.6任务与剧情
依赖TypeWriter0.9Basic (TypeWriter extension)

概览​

Puzzle 可以把世界中的某个地点变成一个可解的谜题。你可以从九种机制中选择:把方块推入洞中、重复一个序列、按顺序拨动拉杆、重定向激光束等等。每个谜题都是你在网页面板中放置的一个受众条目。它通过触发器(onStart、onComplete、onFail、onTimeout、onLifespanExpire)和一个可选的事实,将结果报告给 TypeWriter 的其余部分。

棋盘的大部分内容都是在客户端绘制的:方块、高亮、预览和激光粒子都是发送给解谜玩家的数据包,因此两位玩家可以在同一块棋盘上解谜,而看不到彼此的进度。少数机制确实会触及世界:物品展示框谜题会旋转真实的物品展示框,而图案谜题会放置真实的方块,除非开启了 ghostBlocks。

谜题属于你搭建它的地点。它只会为站在其位置所在世界、且距其中某个位置在 activationRadius 格以内的玩家运行。到达棋盘会开始一个会话;走开则结束会话并清除客户端棋盘。

功能​

  • 九种谜题类型 — 推方块、记忆序列、激光网格、拉杆顺序、图案摆放、合作压力板、物品展示框、密码锁和基座献祭。
  • 共享的生命周期 — 每个谜题都有时间限制、最大错误尝试次数、失败冷却、存续时间、提示和完成消息。
  • 处处都有触发器 — 开始、完成、失败、超时和存续到期都可以启动一个 TypeWriter 条目。
  • 事实奖励 — 谜题解开时,某个事实会增加 amount。
  • 谜题链 — 按顺序运行多个谜题,并对整条链作出反应。
  • 空间限制 — 世界检查和激活半径可防止棋盘出现在其他维度或很远的地方。
  • 统计数据 — 每位玩家的尝试次数、解开次数和最佳时间,并提供排行榜命令。
  • 状态事实 — 读取某个谜题对某位玩家是已解开还是处于激活状态。
  • 兼容 Folia — 对世界的访问在拥有该谜题的区域上运行。

安装​

  1. 安装 TypeWriter 官方的 Basic 扩展,它提供了谜题所使用的共享类型(音效、物品、变量)。
  2. 将 Puzzle 的 JAR 放入 plugins/Typewriter/extensions/ 并重启服务器。
  3. 可选:如果你希望保存尝试次数、解开次数和最佳时间,请在页面中添加一个 Puzzle Artifact 条目(参见“配置”中的警告)。

快速上手​

构建一个三拉杆的门谜题:

  1. 在 TypeWriter 网页面板中,打开一个**清单(manifest)**页面,添加一个 Lever Order 条目。
  2. 在 levers 中添加三个拉杆。对每个拉杆,在游戏中捕获一个拉杆方块的 position,并将 orderIndex 依次设为 0、1 和 2,即玩家必须拨动它们的顺序。
  3. 将 amount 设为 3,使提示显示为 1/3、2/3、3/3。开启 resetOnWrong,如果你希望出错后有一段暂停,则将 cooldownOnFail 设为 5。
  4. 将 onComplete 链接到一个打开门的序列,并将 fact 链接到一个存储奖励的可缓存事实。这个事实也是记住谜题已被解开的可靠方式。
  5. 可选:把谜题放在某个受众筛选器之下,例如任务受众,使其只对合适的玩家运行。
  6. 发布,重启或重载扩展,然后走近拉杆。按正确顺序拨动它们即可解开谜题。拨错拉杆会重置拉杆状态并触发 onFail。
新谜题

谜题条目会在扩展加载时注册。添加谜题后,请先重载 TypeWriter 或重启,再使用 /typewriter puzzle start。

工作原理​

会话。 玩家进入半径范围时会话开始。它会清除进度、错误尝试次数和失败冷却,启动 timeLimit 和 lifespan,并触发 onStart。因此 maxAttempts 是每个会话的额度:用完额度的玩家可以走开再回来。玩家已经解开的谜题不会再次为其重新开启。

已解开的谜题会变为惰性。 玩家解开 Block Push、Combination Lock、Lever Order 或 Laser Grid 后,它不再为该玩家绘制面板,也不再取消其交互,即使玩家重新回到它的受众中(过滤器闪烁、重新加入)。已解开谜题的拉杆和按钮会像普通方块一样工作,已解开的 Pedestal 也不再吞掉物品的拾取。

被取消的点击。 服务器会用被点击方块的真实状态回应被取消的点击,这会擦除客户端绘制的方块。因此,每次点击被取消后一个 tick,面板都会重新绘制(Memory 按钮、Pattern 网格、被拒绝的放置、被拒绝的推动),玩家左键击打已绘制的镜子或拉杆时也是如此。

完成只会触发一次。 事实写入、完成消息、onComplete 以及链的进度都来自同一个被接受的结果,因此重复点击不会让它们触发两次。

进度。 每个正确的步骤会使进度加一,最多到 amount。hintMessage 中的 {progress} 和 {total} 显示进度和 amount。谜题不会根据自身大小设置 amount,因此请自行填入真实的步骤数。

共享选项​

每个谜题都有这些字段。

字段含义
fact谜题解开时增加 amount 的可缓存事实。
amount最大进度,以及加到事实上的奖励。
timeLimit谜题超时前的秒数。0 表示禁用。
cooldownOnFail失败后玩家必须等待的秒数。
maxAttempts每个会话允许的错误尝试次数。0 表示不设限制。
resetOnWrong错误的步骤是否清除进度。
showHints、hintMessage每一步之后的聊天提示,可使用 {progress} 和 {total}。 留空则不发送任何内容。
completionMessage解开时发送一次。留空则关闭。默认值为 <green>Puzzle completed!。
onStart、onComplete、onFail、onTimeout、onLifespanExpire为该玩家触发的条目。
lifespan无论玩家做什么,谜题对该玩家过期前的秒数。0 表示禁用。
activationRadius谜题位置周围的格数。0 会取消距离检查,但世界检查始终适用。默认值为 16。
criteria玩家要参与该谜题必须满足的条件。

共享谜题​

当 isShared 开启且谜题的 fact 带有群组(队伍、团队)时,该群组共同进行同一个谜题:一名玩家的每一步、每次失误和冷却都会复制给该群组的在线玩家。第一个解开它的成员即为整个群组解开:fact 只增加一次 amount,每名成员各获得一次完成消息、onComplete 和链步骤。不在线的成员会在回来时获得它们。一名玩家对同一谜题最多获得一次完成,即使更换群组也是如此;只有涉及该玩家的管理员重置,才能让他再次获得。

  • 解开的记录按群组保存。死亡或重新连接不会重置它,也不会再次给予任何奖励,这与单人谜题不同,后者在死亡或断开连接后可以重玩。
  • 统计数据和每名玩家的棋盘仍然是个人的。如果 fact 没有群组,或玩家不属于任何群组,则不共享任何内容。Coop Pressure 会忽略 isShared:它本来就会为每名参与者完成谜题。
  • 要再次游玩,请使用 /typewriter puzzle admin reset <player> <id>,它会为该玩家的整个群组重新开启该谜题。
必须使用 Puzzle Artifact

群组的解开记录保存在 Puzzle Artifact 中。没有它,记录只存在于内存中:服务器重启后,群组可以再次解开谜题并再次获得奖励。使用 isShared 之前请先添加该 artifact。回退到扩展的旧版本同样会丢失共享记录,因为该版本保存 artifact 时不含此记录,奖励会被再次发放。解开记录会在下一次保存时写入(每 30 秒一次):在此期间发生崩溃可能会丢失它。

谜题类型​

条目玩家的操作主要字段
Block Push左键或右键点击方块,将其朝玩家面对的方向推一格,直到每个目标洞都被填满。pushBlocks、targetHoles(含 acceptedMaterial)、blockMaterial、holeMaterial。方块数量必须等于洞的数量。 allowPull 没有效果(拉动尚未实现)。
Memory Sequence观看按钮依次亮起,然后按相同顺序点击它们。每个会话的序列都是随机的。buttons(至少 2 个)、sequenceLength、highlightDuration、stepGap、inputDelay(tick)、highlightMaterial。
Laser Grid右键点击镜子使其旋转,直到每个接收器都被其对应颜色的光束击中。emitters(颜色、方向)、mirrors(rotatable、initialDirection)、receivers(requiredColor)、maxReflections、maxBeamLength、beamDensity。
Lever Order按 orderIndex 的顺序右键点击拉杆。拨错拉杆会重置所有拉杆。levers(position、orderIndex)。
Pattern Placement在网格上放置方块以复现一个图案。pattern、gridOrigin、columns、previewOffsetY、ghostBlocks、tolerance。
Coop Pressure多名玩家站在不同的压力板上并坚持几秒钟。plates、requiredPlayers、holdDuration(秒)。
Item Frame把物品放入已有的物品展示框,然后将其旋转到目标角度。frameTargets(correctRotation 0 到 7、requiredItem)、checkItem。
Combination Lock按密码的顺序点击数字方块。digits(位置),code(数字索引,从 0 开始计数)。
Pedestal手持物品右键点击基座方块,或在其附近丢下或拾起该物品。targetPosition、requiredItem、consumeItem、pickupRadius、consumeDroppedItem。

各类型的详细说明:

  • Laser Grid。 光束从发射器旁一格处开始,并沿直线前进。镜子会把它导向镜子所朝的方向。右键点击镜子会把它的方向设为与你点击的那一面相反的方向;如果点击的是它的顶面或底面,则顺时针旋转。实心方块会挡住光束。当每个接收器都被其 requiredColor 颜色的光束击中时,谜题即告解开。光束以粒子显示。 右键点击镜子时它不会消失:点击后面板会重新绘制。光束从方块中心穿过,并恰好在每面镜子上转向;beamDensity 是每个方块的粒子数。光束最长为 maxBeamLength 格(默认 64;0 或更小等于 64,绝不无限),并且从不加载区块:它会在已加载世界的边缘停止。光束更长的棋盘必须调高 maxBeamLength。
  • Block Push。 每次推动会让方块朝玩家面对的方向移动一格。被推回起始格的方块总会在那里被接受,方块被推过目标洞并离开后,该目标洞会重新绘制。请让世界中的起始格保持为空(空气)。 那里的真实方块在客户端会被隐藏,但对服务器仍是实心的,因此没有人能站在上面。被拒绝的推动(墙或其他方块)每个方块和目标格只计一次错误,直到某次推动成功,因此对着墙壁按住点击不会耗尽 maxAttempts。
  • Lever Order。 拉杆会以玩家到达面板时它在世界中的状态静置,从该状态开始切换,并在重置或顺序错误后恢复到该状态,即使它静置时是开启的。失败冷却期间的点击不会触及真实的拉杆。
  • Combination Lock。 编号从 0 开始:digits 中列出的第一个位置是数字 0,第二个是数字 1,依此类推。code 按点击顺序列出这些索引。例如,digits 中有四个按钮时,密码 [2, 0, 3] 表示:第三个按钮、第一个按钮、第四个按钮。code 中超出数字范围的值会使锁忽略所有按压;服务器日志会指出该值。
  • Pattern Placement。 pattern 逐行列出材质,宽度为 columns,其长度必须是 columns 的倍数。网格位于 gridOrigin 的 Y 高度处的水平面上,列沿 X 方向,行沿 Z 方向。预览悬浮在其上方 previewOffsetY 格处。开启 ghostBlocks 时,网格上会直接绘制半透明版本,正确的方块会在客户端显示,并从玩家身上扣除物品。错误的放置始终会被取消。tolerance 是进度重置之前允许的错误放置次数。
  • Coop Pressure。 当玩家的脚踩在该方块上,或其上方一格的方块上时,压力板就会被计入。每块板一名玩家。受众中的所有玩家都会参与,因此请用 /typewriter puzzle join <entry id> 添加他们。当压力板被坚持了 holdDuration 后,所有参与者都完成该谜题。
  • Item Frame。 展示框必须已存在于配置的位置;谜题从不会生成展示框。空的展示框只接受 requiredItem,并从玩家手中取走。每次点击已放入物品的展示框都会将其旋转一步(45 度),correctRotation 是正确位置所对应的步数,范围为 0 到 7。展示框是真实的实体,因此旋转对所有人都可见。
  • Pedestal。 requiredItem 可以通过右键点击给出,或丢在基座周围 pickupRadius 格以内。当开启 consumeDroppedItem 时,丢下的匹配物品会被移除。

命令​

所有命令都是 /typewriter(别名 /tw)的子命令。<id> 是谜题的条目 id。只有 admin 命令需要权限。

命令说明
/typewriter puzzle打开第一个 Puzzle Menu 条目的聊天菜单,或提示不存在。
/typewriter puzzle list列出已注册的谜题及其类型。
/typewriter puzzle start <id>将你自己加入某个谜题的受众。如果你已经解开了它,则会拒绝。
/typewriter puzzle join <id>加入一个已在运行的谜题,例如合作谜题。
/typewriter puzzle chain <id>通过条目 id 或名称启动一条谜题链。
/typewriter puzzle status显示你在每个谜题上的状态:激活、已完成、已停止或未激活。
/typewriter puzzle leaderboard <id>显示你在某个谜题上的统计数据以及前十名玩家。
/typewriter puzzle stop [id]停止一个谜题或你所有激活的谜题,并重置其进度。
/typewriter puzzle close关闭你已打开的物品栏。
/typewriter puzzle admin reset <player> <id>重置某位玩家在某个谜题上的状态并重新启动它。 对于共享谜题,会为该玩家的整个群组重新开启。
/typewriter puzzle admin reload清除所有运行时状态和谜题链。

权限​

权限授予
puzzle.admin/typewriter puzzle admin 命令。

配置​

持久化。 没有 Puzzle Artifact 时,不会保存任何内容。有了它,扩展会每 30 秒以及在关闭时保存状态和统计数据,并在启动时加载。请恰好创建一个构件,并保留其生成的 artifactId。 共享谜题必须使用该 artifact(参见共享谜题)。

断开连接后什么会保留

玩家断开连接时,其谜题状态会从内存中移除,下一次保存也不会包含它。统计数据会保留。若要永久记住已解开的谜题,请设置该谜题的 fact,并在你的条件中读取该事实。Puzzle Solved Fact 只反映内存中的状态。 共享谜题是例外:它的解开记录属于群组,并保存在 artifact 中。

消息。 游戏中显示的文本没有任何一条固定在代码里。属于单个谜题的文本是其条目的字段,命令的回复和所有谜题共用的两条消息则是 snippet。参见可编辑文本。

可编辑文本​

文本使用 MiniMessage,因此可以改写、翻译或重新着色。文本中的 {name} 会被下表所列的值替换;不存在的占位符会原样保留。PlaceholderAPI 占位符(%...%)会为接收文本的玩家解析。只有服务器控制台日志保持固定,为英文。

条目的字段​

这些字段位于 Web 面板中的条目上。每个字段都是按玩家显示的文本,因此支持变量,留空则不发送任何内容。现有页面保留其已保存的文本;下面的默认值适用于新条目,以及从未保存过该字段的页面。

条目字段默认值占位符
每个谜题hintMessage每种谜题类型的提示,例如 <yellow>Repeat the sequence! {progress}/{total}。{progress}, {total}
每个谜题completionMessage<green>Puzzle completed!无
Puzzle MenutitleText<gold><bold>Puzzles</bold> <gray>-无
Puzzle MenupuzzleLineText<green>{puzzle} <gray>- <aqua>click to start{puzzle}(谜题条目的 id)
Puzzle MenufooterText<gray>Use <white>/typewriter puzzle stop<gray> to stop all active puzzles.无
Memory SequencememorizeMessage<gold>Memorize the sequence…无
Memory SequenceyourTurnMessage<green>Your turn! <white>{progress}/{total}{progress}, {total}
Memory SequencestepCorrectMessage<green>Well done! <white>{progress}/{total}{progress}, {total}
Lever OrderwrongOrderMessage<red>Wrong order — the levers have been reset.无
Pattern PlacementprogressMessage<green>Pattern <white>{progress}/{total}{progress}, {total}
Item FramemissingFrameMessage<red>No item frame at <white>{x} {y} {z}{x}, {y}, {z}
Item FramewrongItemMessage<red>That is not the right item in the frame.无
Item FrameinsertingMessage<gray>Inserting the item…无
Item FramemissingItemMessage<yellow>First place the requested item in the frame.无
Item FrameitemPlacedMessage<green>Item placed — rotate the frame.无
Item FramerotationMessage<gray>Rotation {current}/{total}{current}, {total}

hintMessage、completionMessage 和聊天菜单字段发送到聊天栏;其余字段显示在动作栏。其中一些默认值在早期版本中是法语,现在是英语,已保存法语文本的页面会保留原文本。

Snippet​

/typewriter puzzle 命令输出的所有内容(包括管理命令)以及所有谜题共用的两条消息,都是 TypeWriter 的 snippet。打开 plugins/Typewriter/snippets.yml,找到 content.puzzle 下的键,修改值并运行 /tw reload。扩展在启动时会以默认文本注册其所有 snippet,因此首次启动后它们会出现在该文件中。

Snippet(位于 content.puzzle. 下)默认值占位符
command.no_menu<red>No puzzle menu configured.无
command.list.none<red>No puzzles configured.无
command.list.header<gold>=== Available Puzzles ===无
command.list.line<green>{puzzle} <gray>- {type}{puzzle}, {type}
command.puzzle_not_found<red>Puzzle not found: <white>{puzzle}{puzzle}
command.start.already_completed<yellow>Puzzle already completed. Use <white>/typewriter puzzle admin reset {player} {puzzle}<yellow> to replay it.{player}, {puzzle}
command.start.started<green>Starting puzzle: <white>{type}{type}
command.join.already_completed<yellow>Puzzle already completed for you: <white>{puzzle}{puzzle}
command.join.joined<green>Joined puzzle: <white>{type}{type}
command.stop.not_active<gray>Puzzle is not active: <white>{puzzle}{puzzle}
command.stop.stopped<yellow>Stopped puzzle: <white>{puzzle}{puzzle}
command.stop.all_none<gray>No active puzzle.无
command.stop.all_stopped<yellow>Stopped <white>{count} <yellow>puzzle(s).{count}
command.status.header<gold>=== Puzzle Status ===无
command.status.line<gray>{puzzle}: {status} <dark_gray>progress={progress}{puzzle}, {status}, {progress}
command.status.active<green>ACTIVE无
command.status.completed<aqua>COMPLETED无
command.status.stopped<yellow>STOPPED无
command.status.inactive<gray>INACTIVE无
command.chain.not_found<red>Chain not found: <white>{chain}{chain}
command.chain.invalid<red>Chain is invalid or contains unresolved puzzles: <white>{chain}{chain}
command.chain.empty<red>Chain has no resolvable puzzle entries.无
command.chain.started<green>Starting puzzle chain: <white>{chain}{chain}
command.leaderboard.header<gold>=== Puzzle Stats: <white>{puzzle} <gold>==={puzzle}
command.leaderboard.attempts<gray>Attempts: <white>{attempts}{attempts}
command.leaderboard.solves<gray>Solves: <white>{solves}{solves}
command.leaderboard.best_time<gray>Best time: <white>{seconds}s{seconds}
command.leaderboard.rows_header<gold>--- Leaderboard ---无
command.leaderboard.row<gray>#{rank} <white>{player} <gray>- <white>{solves} solves{rank}, {player}, {solves}
command.leaderboard.row_timed<gray>#{rank} <white>{player} <gray>- <white>{solves} solves <gray>{seconds}s{rank}, {player}, {solves}, {seconds}
command.admin.reset.player_not_found<red>Player not found: <white>{player}{player}
command.admin.reset.done<green>Reset puzzle <white>{puzzle} <green>for <white>{player}{puzzle}, {player}
command.admin.reset.done_group<green>Reset puzzle <white>{puzzle} <green>for <white>{player} <green>and its group (<white>{count}<green> online){puzzle}, {player}, {count}
command.admin.reload.done<green>Puzzle runtime states cleared.无
play.cooldown_wait<red>Puzzle on cooldown — <white>{seconds}s{seconds}
play.max_attempts<red>Too many mistakes — restart the puzzle to try again.无

{type} 是谜题类型的名称(Memory Sequence、Lever Order 等),{status} 是四个 command.status.* snippet 之一,因此两者都保留各自的颜色。其他占位符均为纯文本:玩家在命令中输入的内容无法为回复添加格式。

条目​

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

动作1
事实2
受众9
构件1
其他条目1

故障排查​

棋盘没有出现。 你必须位于谜题位置所在的世界,并且在其中某个位置的 activationRadius 范围内。保持为 0, 0, 0 的位置会被忽略,因此没有设置任何位置的谜题没有锚点。

点击时没有任何反应。 请检查你是否在受众中(条件必须匹配,并且受众筛选器必须包含你),以及该谜题是否已对你解开:使用 /typewriter puzzle status,并使用 /typewriter puzzle admin reset <player> <id> 重新游玩。失败冷却期间的点击会被忽略;动作栏会显示剩余时间。

/typewriter puzzle start 提示找不到该谜题。 谜题在扩展加载时按条目 id 注册。添加谜题后请重载,并使用条目 id 而不是名称。

记忆谜题始终无法开始。 buttons 至少需要 2 项,并且每一项都需要一个位置。

图案谜题忽略了我放置的方块。 pattern 的长度必须是 columns 的倍数,并且你必须在 gridOrigin 的 Y 高度处的网格上放置方块。错误的材质会被取消。

物品展示框谜题提示没有展示框。 请先在配置的位置放置一个物品展示框。日志中还会输出带有坐标的警告。

重新连接后进度丢失。 请参阅“配置”中的警告:使用 fact 来保留结果。

合作谜题始终无法完成。 每位玩家都必须在受众中(/typewriter puzzle join <id>),站在不同的压力板上,并在上面停留 holdDuration。压力板上的掉落物不计入。