饥饿值支付

PaymentHandler 是 signposts 自己的默认支付处理器,也是「无经济 mod 时」的兜底实现:它不消耗任何货币,而是扣玩家的饥饿值(food level / 饱食度)。经济 mod 若存在,支付逻辑可被 IPaymentHandler 的其他实现整体替换(见 Gollorum 集成)。

支付链路

客户端点击 Atlas 上的 signPost 标记
  → JumpMessage(markerId, paymentHandlerKey)
  → 服务端 JumpMessageHandler
  → SignPostsMod.playerJump(markerId, player, paymentHandlerKey)
      ├─ 查 paymentHandlers.get(paymentHandlerKey)
      ├─ MarkerToTileMap 反查路牌坐标 / 读 TileEntity 的 jumpX/Y/Z
      └─ if (creative || paymentHandler.pay(player, x, y, z)) → setPositionAndUpdate(...)

支付发生在传送之前,pay 返回 true 才执行 player.setPositionAndUpdate(jumpX, jumpY, jumpZ)。

创意模式免付费

if (player.capabilities.isCreativeMode || paymentHandler.pay(player, (int) jumpX, (int) jumpY, (int) jumpZ)) {

创造模式玩家直接短路,跳过任何 pay 调用。

扣费公式

double distance = Math.pow(Math.abs(player.posX - x), 2)
                + Math.pow(Math.abs(player.posY - y), 2)
                + Math.pow(Math.abs(player.posZ  - z), 2);
int distancePerHunger = ConfigurationHandler.getDistancePerPayment();  // 默认 10000
int maximumHunger    = ConfigurationHandler.getMaximumPayment();        // 默认 10
int exhaustion = (int) Math.min((Math.floor(distance / distancePerHunger)), maximumHunger);
player.getFoodStats().addStats(-1 * exhaustion, 0.0F);
return true;
项 值
距离度量 平方距离(各轴差值平方后相加,没有开方)
每点饱食度对应 distancePerPayment = 10000(平方单位)
换算成直线距离 sqrt(10000) = 100 格(单向满轴)
单次上限 maximumPayment = 10 点饱食度(饥饿条半根)
实际扣除 FoodStats.addStats(-exhaustion, 0.0F),饱和度增量固定 0.0
返回值 恒 true,无论玩家饱食度是否足够

需要注意的行为

  • 永远不会支付失败。pay 无论扣多少、玩家饿到什么程度都 return true,所以不会因付不起而被留在原地。原版 addStats 对负值只是减去 exhaustion,不会致死。
  • 平方距离使远距离传送异常便宜。maximumPayment 默认 10 意味着只要平方距离 ≥ 100000(直线约 316 格),一律只扣 10 点。实际游戏中「超过 316 格」这个门槛很容易达到。
  • 只能沿同维度传送。playerJump 不做维度检查,目标由路牌所在维度的 MarkerToTileMap 决定;但 playerJump 本身不校验 jumpX/jumpY/jumpZ 是否在玩家当前维度内。
  • 同坐标即失败。playerJump 要求 jumpX != 0 && jumpY != 0 && jumpZ != 0 三个轴都非 0 才传送,所以刻写在主世界原点(坐标 0 轴)的路牌无法作为传送目标使用。
  • 扣费坐标取整。传入 pay 的是 (int) jumpX, (int) jumpY, (int) jumpZ,距离计算基于取整后的整数坐标。

无权限校验

SignPostsMod.playerJump 与 JumpMessageHandler 中没有任何 OP / 权限等级检查(已 grep canPlayerEdit|CommandSender|permission|opLevel|isOp|ICommand|permissionLevel|getCommandSender,全仓库无匹配)。任何玩家都可以对任意路牌发起传送,费用对所有玩家一致(除创造模式免收)。

IPaymentHandler 接口

public interface IPaymentHandler {
    public boolean pay(EntityPlayer player, int x, int y, int z);
}
处理器 注册键 注册条件
PaymentHandler signposts preInit 中无条件 addPaymentHandler(new PaymentHandler(), ID)
GollorumPaymentHandler signpost 仅当 Loader.isModLoaded("signpost")

处理器键由客户端在 JumpMessage 中附带并由服务端查表,因此默认路径是 signposts(饥饿值)。若 Loader.isModLoaded("signpost") 成立,GollorumEventHandler 会把 Atlas 交互改指向 signpost 键,从而改用 Gollorum 的经济系统。

相关条目