Files
Henry_Du e76d0188db fix: 修复检票机首次加载黑屏及完善亮灯模块对接
- 增加外设初始化重试机制,等待monitor和检票机外设就绪(最多20秒),
  在等待期间显示进度提示,避免区块加载时脚本提前退出导致屏幕无显示
- 修复Socket.IO服务端未强制websocket传输配置,避免负载均衡环境下轮询产生400错误
- 所有业务拒绝(deny)场景下调用markFault触发红灯,包括:
  * 无效票/卡、卡ID缺失、票ID缺失
  * 站点不匹配、未进站/已出站、已进站/已出站
  * 余额不足、票价查询失败、网络错误
  * 外设写入/扣费失败等所有错误路径
- 版本号升级至v1.5.29
2026-08-11 14:29:03 +08:00

10 KiB
Raw Permalink Blame History

FSE Ticketing CC API

通用说明

  • 外设类型通过 peripheral.getType(name) 返回,或在 peripheral.wrap(name) 后通过 peripheral.call/方法调用使用。
  • 返回值约定:
    • 成功通常返回 true(部分方法额外返回数据)。
    • 失败通常返回 false, "error_message" 或 nil, "error_message"(取决于具体方法)。
  • 票/卡信息表(Lua table)中的字段 key 与模组 NBT key 一致,详见“数据字段”章节。

外设:ticket_vending_machine(售票机)

方法:issueTicket

发放一张票并从售票机正面吐出(生成掉落物)。

local ok, ticketId = vending.issueTicket(
  startNameEn,
  terminalNameEn,
  type,
  rides,
  cost,
  startStation,
  terminalStation,
  fromNameCnU,
  toNameCnU
)
  • 参数(均为可选,未提供时使用默认值)
    • startNameEn:起点(英文/标识),默认 "???"
    • terminalNameEn:终点(英文/标识),默认 "???"
    • type:票种,默认 "local"
      • "local":普通票(Local Ticket)
      • "limited_express":特急票(Exp Ticket)
      • "single":单程票(Single-trip Ticket)
    • rides:可乘坐次数,默认 1,最小会被钳制为 1
    • cost:金额,默认 0
    • startStation:起点站 ID/代码,默认 ""
    • terminalStation:终点站 ID/代码,默认 ""
    • fromNameCnU:中文起点名(可能包含 \u 转义),默认 ""
    • toNameCnU:中文终点名(可能包含 \u 转义),默认 ""
  • 返回
    • ok:true
    • ticketId:生成的票 ID(形如 AB-12345678)
  • 方块状态 / 模型切换(对应票种)
    • 当 type 为 "local" 时:成功调用后,方块模型暂时切换为 ticket_vending_machine_success_localticket(露出绿票 / 本地票图案)。
    • 当 type 为 "limited_express" 或 "single" 时:暂时切换为 ticket_vending_machine_success_expticket(露出橙红特急票 / 单程票图案)。
    • 两种状态持续约 20 tick(1 秒)后自动恢复基础款模型 ticket_vending_machine。

方法:issueICCard

发放一张 IC 卡并从售票机正面吐出(生成掉落物)。

local ok, cardId = vending.issueICCard(ownerName, balance)
  • 参数(可选)
    • ownerName:持有人名字,默认 ""
    • balance:初始余额,默认 0
  • 返回
    • ok:true
    • cardId:生成的卡号(形如 IC-xxxxxxxx)
  • 方块状态 / 模型切换
    • 方法成功返回时,方块模型暂时切换到 ticket_vending_machine_success_ic(正面露出 IC 卡图案),20 tick(1 秒)后自动恢复基础款模型。

方法:issueFSEPass

local ok, ticketId = vending.issueFSEPass(ownerName, startNameEn, terminalNameEn, cost)

发放一张 FSE Pass 通票(紫色 FSE_PASS 物品)并从售票机正面吐出。参数从左到右依次为:

  • 参数(均为可选)
    • ownerName:持有人名字,默认 ""
    • startNameEn:起点(英文/标识),默认 "???"
    • terminalNameEn:终点(英文/标识),默认 "???"
    • cost:金额,默认 0
  • 返回
    • ok:true
    • ticketId:生成的通票 ID(同样形如 AB-12345678)
  • 方块状态 / 模型切换
    • 方法成功返回时,方块模型暂时切换为 ticket_vending_machine_success_expticket(与特急票款外观),20 tick 后恢复基础款模型。

外设:ticket_inspection_machine(检票机)

检票机通过玩家右键扫描票/卡,保存“最近一次扫描”的数据,并向连接的 CC 电脑推送事件。

方法:getLastScanned

获取最近一次扫描到的票/卡信息表。

local infoOrNil, err = gate.getLastScanned()
  • 返回(成功)
    • infoOrNil:Lua table(票信息或 IC 信息)
  • 返回(失败)
    • nil, "no ticket scanned"

方法:destroyTicket

销毁最近一次扫描的物品(直接清空玩家手上那一张票/卡)。

local ok, err = gate.destroyTicket()
  • 返回
    • true:已投递到服务器主线程执行
    • false, "not server level":当前世界不是服务端世界

注意:该方法当前实现为“投递执行”,不会把实际销毁结果回传给 Lua;建议通过事件与 getLastScanned() 侧面确认状态。

  • 方块状态
    • 成功执行:方块模型切换到 ticket_inspection_machine_success(绿灯通过状态)
    • 执行失败(如找不到扫描玩家):切换到 ticket_inspection_machine_false(红灯拒绝状态)
    • 两种状态均持续约 40 tick(2 秒)后自动恢复 NONE 基础模型。

方法:deductICCard

对最近一次扫描到的 IC 卡扣费。

local ok, err = gate.deductICCard(amount)
  • 参数
    • amount:扣费金额(double)
  • 返回
    • true:已投递到服务器主线程执行
    • false, "not server level":当前世界不是服务端世界

注意:当前实现同样不会把扣费后的余额回传给 Lua;如果需要余额,请调用 getLastScanned() 或使用充值机外设完成扣费/查询。

  • 方块状态
    • 成功扣费:_success(绿灯)40 tick
    • 失败(非 IC 卡 / 找不到玩家 / 卡片不匹配 / 余额不足):_false(红灯)40 tick

方法:markEntered

将最近一次扫描的票/卡标记为已进站,并(可选)写入进站站点。

local ok, err = gate.markEntered(entryStationId)
  • 参数(可选)
    • entryStationId:站点 ID/代码,默认 ""(为空则不写入)
  • 返回
    • true:已投递到服务器主线程执行
    • false, "not server level"

执行后会推送 ticket_state_updated 或 ic_card_state_updated 事件(取决于最近扫描的是票还是卡)。

  • 方块状态
    • 成功写入:_success(绿灯)40 tick
    • 失败(玩家/票卡无效):_false(红灯)40 tick

方法:markExited

将最近一次扫描的票/卡标记为已出站,并清理进站站点字段。

local ok, err = gate.markExited()
  • 返回
    • true:已投递到服务器主线程执行
    • false, "not server level"
  • 方块状态
    • 成功写入:_success(绿灯)40 tick
    • 失败(玩家/票卡无效):_false(红灯)40 tick

方法:resetTicketState

将最近一次扫描的票/卡状态复位(entered/exited 均为 false,并清理进站站点字段)。

local ok, err = gate.resetTicketState()
  • 返回
    • true:已投递到服务器主线程执行
    • false, "not server level"
  • 方块状态
    • 成功复位:_success(绿灯)40 tick
    • 失败(玩家/票卡无效):_false(红灯)40 tick

方法:markFault

CC 侧业务判断失败时,主动触发红灯拒绝状态(例如业务逻辑拒绝进站/出站,但 CC 侧又不想调用 resetTicketState 时)。

local ok, err = gate.markFault()
  • 返回
    • true:已投递到服务器主线程执行(红灯亮起)
    • false, "not server level":当前世界不是服务端世界
  • 方块状态
    • 调用后立即切换到 ticket_inspection_machine_false(红灯拒绝状态),持续 40 tick(2 秒)后自动恢复 NONE 基础款。
    • 与 markEntered/markExited 等方法内部业务错误触发的红灯效果完全相同。

事件

检票机对所有已连接电脑(attach 过的电脑)推送以下事件。事件参数为 1 个 table:

  • ticket_scanned(info)
  • ic_card_scanned(info)
  • ticket_state_updated(info)
  • ic_card_state_updated(info)

info 结构见“数据字段”章节(包含 passenger 字段,值为扫描者玩家名)。

外设:ic_refill_machine(IC 充值机)

充值机要求玩家先把 IC 卡插入机器(右键把 IC 卡放进去)。只有在机器内有卡时,Lua 方法才可用。

  • 方块状态 / 模型切换
    • 玩家右键把 IC 卡(手持 limitcard 物品)插入机器 → HAS_CARD=true,方块模型切换为 ic_refill_machine_inserted(卡片露出卡槽状态),同时 scheduleTick 100 tick(5 秒超时)。
    • 玩家右键空手拿走卡、或取出卡、或 5 秒超时(tick() 触发)→ HAS_CARD=false,模型切回基础款 ic_refill_machine。
    • 充值 / 扣费时(refill、deduct)只要卡还在,始终保持 _inserted 模型,不会额外切换。

方法:getCardInfo

local infoOrNil, err = refill.getCardInfo()
  • 返回(成功)
    • infoOrNil:Lua table(IC 卡信息)
  • 返回(失败)
    • nil, "no card":机器内没有插卡

方法:refill

local okOrNil, r2 = refill.refill(amount)
  • 参数
    • amount:充值金额(double)
  • 返回(成功)
    • true, newBalance
  • 返回(失败)
    • nil, "no card"

方法:deduct

local okOrNil, r2 = refill.deduct(amount)
  • 参数
    • amount:扣费金额(double)
  • 返回(成功)
    • true, newBalance
  • 返回(失败)
    • nil, "no card"
    • false, "insufficient":余额不足(扣费后会变成负数时阻止)

数据字段(info table keys)

票信息(ticket_* / ticket_state_updated / getLastScanned 返回为票时)

  • start_name_en:起点名(英文/标识)
  • terminal_name_en:终点名(英文/标识)
  • start_station:起点站 ID/代码
  • terminal_station:终点站 ID/代码
  • fromNameCnU:中文起点名(可能包含 \u 转义)
  • toNameCnU:中文终点名(可能包含 \u 转义)
  • type:票种(local / limited_express / single)
  • rides:剩余/可用次数
  • entered:是否已进站
  • exited:是否已出站
  • ticketId:票 ID
  • timestamp:签发时间戳(毫秒)
  • cost:金额
  • order_datetime:下单/签发时间字符串(yyyy-MM-dd HH:mm:ss)
  • passenger:扫描者玩家名(仅检票机事件与 getLastScanned 返回中提供)

注意:单程票的 line_name 当前不在 info table 中返回(仅保存在票的 NBT 内)。

IC 信息(ic_* / ic_card_state_updated / getLastScanned 返回为卡时)

  • cardId:卡号
  • ownerName:持有人
  • balance:余额
  • entered:是否已进站
  • entry_station:进站站点 ID/代码(可能为空)
  • passenger:扫描者玩家名(仅检票机事件与 getLastScanned 返回中提供)