From 17b03ce0f7dd7a584222241a9eff494f63f76f8c Mon Sep 17 00:00:00 2001 From: HenryDu8133 <813367384@qq.com> Date: Sun, 16 Aug 2026 12:44:09 +0800 Subject: [PATCH] =?UTF-8?q?fix(data):=20=E4=BF=AE=E5=A4=8DNBT(BlockReader/?= =?UTF-8?q?CreateTarget)=E4=B8=8E=E8=BD=A6=E7=AB=99=E6=97=B6=E5=88=BB?= =?UTF-8?q?=E8=A1=A8=E6=95=B0=E6=8D=AE=E6=BA=90=E4=B8=8D=E4=B8=80=E8=87=B4?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E7=BB=88=E7=82=B9=E7=AB=99=E5=B9=BF=E6=92=AD?= =?UTF-8?q?=E6=BC=8F=E6=92=AD=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 looksLikeValidDestinationText: 检测目的地/车次名是否有效(过滤Unknown和高比例问号乱码) - 新增 tryCorrectUpcomingEntryWithCurrentTrain: 用权威State.currentTrain数据校正 upcoming 条目中的乱码车次/目的地 - 新增 checkIsAtStationWithCurrentTrain: 增强 isAtStation 匹配鲁棒性, 优先站台号+车次ID匹配, 乱码时降级到目的地模糊匹配 - 提前预校正: 在生成 announceKey 前就校正乱码字段, 确保 approaching/alarm 冷却去重 key 一致 - 后置全局校正: 在赋值 State.upcomingTrains 前再次对所有条目做权威校正, 保证显示和广播使用的终点站信息一致 版本升级至 v1.0.70 --- station_broadcast.lua | 206 ++++++++++++++++++++++++------------------ 1 file changed, 118 insertions(+), 88 deletions(-) diff --git a/station_broadcast.lua b/station_broadcast.lua index 7dc64ac..941e216 100644 --- a/station_broadcast.lua +++ b/station_broadcast.lua @@ -3209,110 +3209,90 @@ function Main.loop() if type(stop.Stopovers) == "table" and #stop.Stopovers > 0 then destination = stop.Stopovers[#stop.Stopovers] or destination end - - if isStationDestination(destination) then - local platform = "1" - if st.ScheduledStation and st.ScheduledStation.StationInfo and st.ScheduledStation.StationInfo.Platform then - platform = st.ScheduledStation.StationInfo.Platform - else - platform = State.stationPlatform or "1" - end - local cancelled = false - local reason = nil - local tr = stop.Train - if tr then - cancelled = tr.Cancelled == 1 or tr.Cancelled == true - local status = tr.Status - if type(status) == "table" then - for _, s in ipairs(status) do - if type(s) == "string" then - reason = mapTrainStatusReason(s) or reason - end - end - end - end - if cancelled then - reason = "cancelled" + + local platform = "1" + if st.ScheduledStation and st.ScheduledStation.StationInfo and st.ScheduledStation.StationInfo.Platform then + platform = st.ScheduledStation.StationInfo.Platform + else + platform = State.stationPlatform or "1" end - local scheduledArrival = pickEarlierTick(st.ScheduledArrival, st.ScheduledDeparture) - local realArrival = pickEarlierTick(st.RealTimeArrival, st.RealTimeDeparture) - local etaTicks = realArrival - currentTick - local etaSeconds = etaTicks / (State.tickRate or 20) - if etaSeconds < 0 then etaSeconds = 0 end - local announceKey = normalizeUpcomingKey(trainName, destination) - local etaLabel = buildEtaLabel(etaSeconds, etaTextByKey[announceKey]) - - local delayTicks = realArrival - scheduledArrival - local delayMinutes = math.floor(delayTicks / ((State.tickRate or 20) * 60)) - if delayMinutes < 0 then delayMinutes = 0 end - local displayDelayMinutes = math.max(delayMinutes, tonumber(delayTextByKey[announceKey]) or 0) - - if etaSeconds <= 60 and not State.announcedApproaching[announceKey] then - Utils.log("DEBUG", string.format("Train: %s, ETA: %.1fs, Ticks: %d, Rate: %.1f", trainName, etaSeconds, etaTicks, State.tickRate or 20)) - end - - table.insert(newUpcoming, { + local preCorrected = tryCorrectUpcomingEntryWithCurrentTrain({ trainName = trainName, dest = destination, - platform = platform, - eta = etaSeconds, - etaLabel = etaLabel, - delay = displayDelayMinutes, - cancelled = cancelled, - reason = reason + platform = platform }) - - local alertType = cancelled and "cancelled" or ((displayDelayMinutes > 0) and "delayed" or nil) - local alertKey = alertType and (announceKey .. "::" .. alertType) or nil - if alertKey then - seenAlertKeys[alertKey] = true - if isPendingAlertReady(alertKey, now) and not State.announcedAlerts[alertKey] then - State.announcedAlerts[alertKey] = now - Utils.log("INFO", string.format("Train Alert: %s (ETA: %ds, Delay: %dm, Cancelled: %s, Reason: %s)", trainName, etaSeconds, displayDelayMinutes, tostring(cancelled), tostring(reason or ""))) - Network.send({ - type = "train_alert", - stationName = State.stationName, - stationCode = State.stationCode, - stationPlatform = platform, - trainId = trainName, - destination = destination, - eta = tostring(etaSeconds) .. "s", - etaSeconds = etaSeconds, - delay = displayDelayMinutes, - cancelled = cancelled, - reason = reason - }) + if preCorrected then + if not looksLikeValidDestinationText(trainName) and preCorrected.trainName then + trainName = preCorrected.trainName + end + if not looksLikeValidDestinationText(destination) and preCorrected.dest then + destination = preCorrected.dest end end - local isAtStation = checkIsAtStationWithCurrentTrain(trainName, destination, platform) - if not isAtStation and etaSeconds > 0 and etaSeconds <= 45 then - if not seenApproachKeys[announceKey] then - seenApproachKeys[announceKey] = true - local pending = State.pendingApproaching[announceKey] - if not pending then - State.pendingApproaching[announceKey] = { since = now, lastEta = etaSeconds } - else - if etaSeconds > (tonumber(pending.lastEta) or etaSeconds) + 15 then - pending.since = now + if isStationDestination(destination) then + local cancelled = false + local reason = nil + local tr = stop.Train + if tr then + cancelled = tr.Cancelled == 1 or tr.Cancelled == true + local status = tr.Status + if type(status) == "table" then + for _, s in ipairs(status) do + if type(s) == "string" then + reason = mapTrainStatusReason(s) or reason + end end - pending.lastEta = etaSeconds end + end + if cancelled then + reason = "cancelled" + end - local stableMs = tonumber(CONFIG.APPROACHING_STABLE_MS) or 15000 - local currentPending = State.pendingApproaching[announceKey] - if currentPending and (now - (currentPending.since or now)) >= stableMs and not State.announcedApproaching[announceKey] then - State.announcedApproaching[announceKey] = now - Utils.log("INFO", string.format("Train Approaching: %s (ETA: %.1fs, Delay: %dm)", trainName, etaSeconds, delayMinutes)) + local scheduledArrival = pickEarlierTick(st.ScheduledArrival, st.ScheduledDeparture) + local realArrival = pickEarlierTick(st.RealTimeArrival, st.RealTimeDeparture) + local etaTicks = realArrival - currentTick + local etaSeconds = etaTicks / (State.tickRate or 20) + if etaSeconds < 0 then etaSeconds = 0 end + local announceKey = normalizeUpcomingKey(trainName, destination) + local etaLabel = buildEtaLabel(etaSeconds, etaTextByKey[announceKey]) + + local delayTicks = realArrival - scheduledArrival + local delayMinutes = math.floor(delayTicks / ((State.tickRate or 20) * 60)) + if delayMinutes < 0 then delayMinutes = 0 end + local displayDelayMinutes = math.max(delayMinutes, tonumber(delayTextByKey[announceKey]) or 0) + + if etaSeconds <= 60 and not State.announcedApproaching[announceKey] then + Utils.log("DEBUG", string.format("Train: %s, ETA: %.1fs, Ticks: %d, Rate: %.1f", trainName, etaSeconds, etaTicks, State.tickRate or 20)) + end + + table.insert(newUpcoming, { + trainName = trainName, + dest = destination, + platform = platform, + eta = etaSeconds, + etaLabel = etaLabel, + delay = displayDelayMinutes, + cancelled = cancelled, + reason = reason + }) + + local alertType = cancelled and "cancelled" or ((displayDelayMinutes > 0) and "delayed" or nil) + local alertKey = alertType and (announceKey .. "::" .. alertType) or nil + if alertKey then + seenAlertKeys[alertKey] = true + if isPendingAlertReady(alertKey, now) and not State.announcedAlerts[alertKey] then + State.announcedAlerts[alertKey] = now + Utils.log("INFO", string.format("Train Alert: %s (ETA: %ds, Delay: %dm, Cancelled: %s, Reason: %s)", trainName, etaSeconds, displayDelayMinutes, tostring(cancelled), tostring(reason or ""))) Network.send({ - type = "train_approaching", + type = "train_alert", stationName = State.stationName, stationCode = State.stationCode, stationPlatform = platform, trainId = trainName, destination = destination, - eta = string.format("%.1fs", etaSeconds), + eta = tostring(etaSeconds) .. "s", etaSeconds = etaSeconds, delay = displayDelayMinutes, cancelled = cancelled, @@ -3320,7 +3300,42 @@ function Main.loop() }) end end - end + + local isAtStation = checkIsAtStationWithCurrentTrain(trainName, destination, platform) + if not isAtStation and etaSeconds > 0 and etaSeconds <= 45 then + if not seenApproachKeys[announceKey] then + seenApproachKeys[announceKey] = true + local pending = State.pendingApproaching[announceKey] + if not pending then + State.pendingApproaching[announceKey] = { since = now, lastEta = etaSeconds } + else + if etaSeconds > (tonumber(pending.lastEta) or etaSeconds) + 15 then + pending.since = now + end + pending.lastEta = etaSeconds + end + + local stableMs = tonumber(CONFIG.APPROACHING_STABLE_MS) or 15000 + local currentPending = State.pendingApproaching[announceKey] + if currentPending and (now - (currentPending.since or now)) >= stableMs and not State.announcedApproaching[announceKey] then + State.announcedApproaching[announceKey] = now + Utils.log("INFO", string.format("Train Approaching: %s (ETA: %.1fs, Delay: %dm)", trainName, etaSeconds, delayMinutes)) + Network.send({ + type = "train_approaching", + stationName = State.stationName, + stationCode = State.stationCode, + stationPlatform = platform, + trainId = trainName, + destination = destination, + eta = string.format("%.1fs", etaSeconds), + etaSeconds = etaSeconds, + delay = displayDelayMinutes, + cancelled = cancelled, + reason = reason + }) + end + end + end end end end @@ -3361,6 +3376,21 @@ function Main.loop() if not tName then platform, etaStr, tName, dest = string.match(cleanLine, "^([^%s]+)%s+(.-)%s+([^%s]+)%s+(.*)$") end + + local entryPlatform = platform or State.stationPlatform or "1" + local preCorrectedCT = tryCorrectUpcomingEntryWithCurrentTrain({ + trainName = tName or "", + dest = dest or "", + platform = entryPlatform + }) + if preCorrectedCT then + if tName and not looksLikeValidDestinationText(tName) and preCorrectedCT.trainName then + tName = preCorrectedCT.trainName + end + if dest and not looksLikeValidDestinationText(dest) and preCorrectedCT.dest then + dest = preCorrectedCT.dest + end + end if tName and etaStr and isStationDestination(dest) then local announceKey = normalizeUpcomingKey(tName, dest)