功能(站点广播): 实现延误与停运列车的双语广播功能

添加所有中日文广播所需的音频资源文件
将应用版本更新至v1.0.37
修复列车状态原因映射逻辑,补充广播所需的缺失字段
实现根据延误、停运状态生成对应双语广播序列的逻辑
更新测试脚本以适配区块阅读器并正确解析CRN的NBT数据
添加示例NBT转储文件作为参考
This commit is contained in:
2026-08-02 18:50:49 +08:00
parent f922ace154
commit 39dc446958
40 changed files with 190 additions and 75 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+27 -15
View File
@@ -1865,8 +1865,11 @@ function handleTrainApproaching(ws, data) {
const cleanPlatform = String(platform).replace(/\D/g, ''); // 提取数字部分 const cleanPlatform = String(platform).replace(/\D/g, ''); // 提取数字部分
const finalPlatform = cleanPlatform || '1'; const finalPlatform = cleanPlatform || '1';
const lineCode = data.lineCode || (stationCode ? stationCode.split('-')[0] : 'UNK');
const destCode = data.destCode || getStationCodeFromName(data.destination) || 'UNK'; const destCode = data.destCode || getStationCodeFromName(data.destination) || 'UNK';
const delay = Number(data.delay) || 0; // 获取延误信息(分钟) const delay = Math.max(0, Number(data.delay) || 0); // 获取延误信息(分钟)
const cancelled = Boolean(data.cancelled);
const rawReason = String(data.reason || '').trim();
log('INFO', `Train ${trainId} approaching ${stationName} (Delay: ${delay} min). Broadcasting pre-arrival...`); log('INFO', `Train ${trainId} approaching ${stationName} (Delay: ${delay} min). Broadcasting pre-arrival...`);
@@ -1877,24 +1880,33 @@ function handleTrainApproaching(ws, data) {
trainId trainId
})); }));
// Pre-arrival Audio Logic
// 提示音:ksts
// 日文:ja-fc1 + ja-站台编号 + ja-fc2 + ja-终点编号 + ja-fc3
// 中文:ch-fc1 + ch-fc2 + ch-fc3 + ch-终点编号 + ch-fc4
const seq = ['ksts']; const seq = ['ksts'];
// 拼接日文
seq.push('ja-fc1', `ja-${finalPlatform}`, 'ja-fc2', `ja-${destCode}`, 'ja-fc3'); seq.push('ja-fc1', `ja-${finalPlatform}`, 'ja-fc2', `ja-${destCode}`, 'ja-fc3');
if (delay > 0) {
// TODO: 根据用户的延误音频设计在这里插入日文延误播报
// 例如: seq.push('ja-delay-prefix', `ja-${delay}`, 'ja-delay-suffix');
}
// 拼接中文
seq.push('ch-fc1', 'ch-fc2', 'ch-fc3', `ch-${destCode}`, 'ch-fc4'); seq.push('ch-fc1', 'ch-fc2', 'ch-fc3', `ch-${destCode}`, 'ch-fc4');
if (delay > 0) {
// TODO: 根据用户的延误音频设计在这里插入中文延误播报 const normalizeReason = (reason, lang) => {
// 例如: seq.push('ch-delay-prefix', `ch-${delay}`, 'ch-delay-suffix'); let r = String(reason || '').trim();
if (!r || r === 'delay') r = 'default_delay';
if (lang === 'ch' && r === 'train') r = 'delaytrain';
return r;
};
if (cancelled) {
seq.push(
'ksts',
'ja-cancel1', `ja-${lineCode}`, 'ja-cancel2',
'ch-cancel1', `ch-${lineCode}`, 'ch-cancel2'
);
} else if (delay > 0) {
const d = Math.max(1, Math.round(delay));
const jaReason = normalizeReason(rawReason, 'ja');
const chReason = normalizeReason(rawReason, 'ch');
seq.push(
'ksts',
'ja-delay1', `ja-${lineCode}`, `ja-${jaReason}`, 'ja-delay2', `ja-${d}min`, 'ja-delay3',
'ch-delay1', `ch-${lineCode}`, 'ch-delay2', `ch-${chReason}`, 'ch-delay3', `ch-${d}`, 'ch-min', 'ch-delay4'
);
} }
enqueueHlsPush(stationName, seq); enqueueHlsPush(stationName, seq);
+122
View File
@@ -0,0 +1,122 @@
{
IsController = 1,
Platform = "",
TrainStops = {
{
IsLast = 1,
State = 2,
FirstStop = "HC-01 1",
Stopovers = {
"HC-02 2",
},
Train = {
Carriages = 1,
StateData = {
[ "1" ] = {
CategoryId = {
0,
0,
0,
0,
},
Color = 0,
LineId = {
0,
0,
0,
0,
},
DisplayName = "[Local]1123",
},
[ "0" ] = {
CategoryId = {
0,
0,
0,
0,
},
Color = 0,
LineId = {
0,
0,
0,
0,
},
DisplayName = "[Local]1123",
},
},
Status = {
"createrailwaysnavigator:delay_from_previous_journey",
},
Cancelled = 0,
Icon = "create:traditional",
Id = {
768288300,
-1947906833,
-1592998865,
1043383053,
},
},
IsPrevSectionExcluded = 0,
IsNextSectionExcluded = 0,
Station = {
ScheduledStation = {
Id = {
0,
0,
0,
0,
},
StationInfo = {
Platform = "",
},
StationName = "HC-01 1",
TagName = "HC-01 1",
},
RealTimeDeparture = 122228,
ScheduledArrival = 122029,
RealTimeStation = {
Id = {
0,
0,
0,
0,
},
StationInfo = {
Platform = "",
},
StationName = "HC-01 1",
TagName = "HC-01 1",
},
RealTimeArrival = 123428,
Index = 0,
ScheduledDeparture = 123229,
Destination = "HC-01 1",
TrainName = "[Local]1123",
},
IsFirst = 1,
},
},
DisplaySettings = {
FontColor = -1,
BackColor = 0,
PlatformWidthNextStop = -1,
TimeDisplay = 1,
TrainNameWidth = 12,
ShowLineColor = 1,
TrainNameWidthNextStop = -1,
ShowTrainMultipleTimes = 1,
TrainText = 0,
PlatformWidth = -1,
},
Glowing = 0,
LastRefreshed = 122113,
YSize = 1,
Filter = "HC-01 1",
Material = {
Name = "create:copycat_base",
},
XSize = 3,
DisplayId = "createrailwaysnavigator:platform/focus",
Item = {},
}
+6 -4
View File
@@ -2,7 +2,7 @@
-- ============================================================================ -- ============================================================================
-- 1. Configuration & Constants -- 1. Configuration & Constants
-- ============================================================================ -- ============================================================================
local APP_VERSION_TEXT = "v1.0.36" local APP_VERSION_TEXT = "v1.0.37"
local CONFIG = { local CONFIG = {
CLOUD_URL = "ws://stabadmin.fse-media.group", CLOUD_URL = "ws://stabadmin.fse-media.group",
@@ -2403,8 +2403,8 @@ local function mapTrainStatusReason(statusId)
operational_disruption = "ops", operational_disruption = "ops",
special_journey = "special", special_journey = "special",
out_of_service = "oos", out_of_service = "oos",
default_delay = "delay", default_delay = "default_delay",
cancelled = "cancel" cancelled = "cancelled"
} }
return known[tail] or tail return known[tail] or tail
end end
@@ -2537,7 +2537,9 @@ function Main.loop()
destination = destination, destination = destination,
eta = tostring(etaSeconds) .. "s", eta = tostring(etaSeconds) .. "s",
etaSeconds = etaSeconds, etaSeconds = etaSeconds,
delay = delayMinutes delay = delayMinutes,
cancelled = cancelled,
reason = reason
}) })
end end
end end
+33 -54
View File
@@ -1,68 +1,47 @@
local target = peripheral.find("create_target") local reader = peripheral.find("blockReader")
if not reader then
if not target then print("Error: Block Reader not found!")
print("Error: Target block not found! Please check if Wired Modem is connected and activated (red ring).")
return return
end end
pcall(target.resize, 80, 10)
-- A helper function to parse the Create station summary line
-- Example input: "1 ?? [Local]1123 HC-02 2"
local function parseTrainLine(line)
-- Format we are parsing:
-- "<Time_Number> <Time_Unit> <Train_Name> <Destination>"
-- Example: "1 ?? [Local]1123 HC-02 2"
-- Example: "现在 ?? [Local]1123 HC-02 2" (assuming "现在" might replace the number and unit)
local timeValue, timeUnit, trainName, destination
-- Try parsing format with a number first (e.g., "1 ?? ...")
timeValue, timeUnit, trainName, destination = string.match(line, "^(%d+)%s+(.-)%s+(%[.-%][^%s]*)%s+(.*)$")
-- If that fails, it might be the "Now" (现在) format which might not have digits at the start
if not trainName then
timeValue, timeUnit, trainName, destination = string.match(line, "^([^%s]+)%s+(.-)%s+(%[.-%][^%s]*)%s+(.*)$")
end
-- Fallback for extremely weird formatting
if not trainName then
timeValue, timeUnit, trainName, destination = string.match(line, "^([^%s]+)%s+(.-)%s+([^%s]+)%s+(.*)$")
end
return {
eta_value = timeValue or "N/A",
eta_unit = timeUnit or "N/A",
trainName = trainName or "N/A",
destination = destination or "N/A",
raw = line
}
end
while true do while true do
term.clear() term.clear()
term.setCursorPos(1,1) term.setCursorPos(1,1)
print("=== Receiving Station Data ===") print("=== CRN Advanced Display Parser ===")
local lines = target.dump() local success, data = pcall(reader.getBlockData)
local hasData = false
for i, lineText in pairs(lines) do if success and data and data.TrainStops then
if lineText and lineText ~= "" and lineText:match("[%w%?%[]") then local now = os.epoch("utc") / 50 -- Minecraft ticks (approx)
print("--- Line " .. i .. " ---")
print("Raw: " .. lineText)
local parsed = parseTrainLine(lineText) for i, stop in ipairs(data.TrainStops) do
print(" Train Name : " .. parsed.trainName) local st = stop.Station
print(" Destination: " .. parsed.destination) if st then
print(" ETA Value : " .. parsed.eta_value) local trainName = st.TrainName or "Unknown"
print(" ETA Unit : " .. parsed.eta_unit) local dest = st.Destination or "Unknown"
hasData = true
-- 时间计算
local scheduledArrival = st.ScheduledArrival or 0
local realArrival = st.RealTimeArrival or 0
-- 计算 ETA (秒)
local etaTicks = realArrival - data.LastRefreshed
local etaSeconds = math.floor(etaTicks / 20)
if etaSeconds < 0 then etaSeconds = 0 end
-- 计算 Delay (分钟)
local delayTicks = realArrival - scheduledArrival
local delayMinutes = math.floor(delayTicks / (20 * 60))
if delayMinutes < 0 then delayMinutes = 0 end
print(string.format("[%d] Train: %s -> %s", i, trainName, dest))
print(string.format(" ETA: %d seconds", etaSeconds))
print(string.format(" Delay: %d minutes", delayMinutes))
print("---------------------------------")
end end
end end
else
if not hasData then print("Waiting for CRN data...")
print("No active trains incoming/departing...")
end end
os.sleep(1) os.sleep(1)