- 增加外设初始化重试机制,等待monitor和检票机外设就绪(最多20秒), 在等待期间显示进度提示,避免区块加载时脚本提前退出导致屏幕无显示 - 修复Socket.IO服务端未强制websocket传输配置,避免负载均衡环境下轮询产生400错误 - 所有业务拒绝(deny)场景下调用markFault触发红灯,包括: * 无效票/卡、卡ID缺失、票ID缺失 * 站点不匹配、未进站/已出站、已进站/已出站 * 余额不足、票价查询失败、网络错误 * 外设写入/扣费失败等所有错误路径 - 版本号升级至v1.5.29
10 KiB
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,最小会被钳制为1cost:金额,默认0startStation:起点站 ID/代码,默认""terminalStation:终点站 ID/代码,默认""fromNameCnU:中文起点名(可能包含\u转义),默认""toNameCnU:中文终点名(可能包含\u转义),默认""
- 返回
ok:trueticketId:生成的票 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:truecardId:生成的卡号(形如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:trueticketId:生成的通票 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模型,不会额外切换。
- 玩家右键把 IC 卡(手持
方法: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:票 IDtimestamp:签发时间戳(毫秒)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 返回中提供)