From 218aaabb50dffb8c25c1f3fabec174c0098a6569 Mon Sep 17 00:00:00 2001 From: HenryDu8133 <813367384@qq.com> Date: Fri, 31 Jul 2026 21:53:12 +0800 Subject: [PATCH] fix(station): remove arrival and departure preview audio flow Delete the station-side arrival/departure announcement requests and drop the server handlers for train arrival, train departure, and play_sequence messages so preview audio no longer interrupts live music. --- CloudServer/server.js | 132 ------------------------------- station_broadcast.lua | 176 +----------------------------------------- 2 files changed, 1 insertion(+), 307 deletions(-) diff --git a/CloudServer/server.js b/CloudServer/server.js index a708449..2755f45 100644 --- a/CloudServer/server.js +++ b/CloudServer/server.js @@ -1370,18 +1370,9 @@ function handleMessage(ws, data) { case 'station_register': handleStationRegister(ws, data); break; - case 'train_arrival': - handleTrainArrival(data); - break; - case 'train_departure': - handleTrainDeparture(data); - break; case 'request_station_time': handleStationTimeRequest(ws, data); break; - case 'play_sequence': - handlePlaySequence(ws, data); - break; case 'request_list_txt': // TODO: Send list.txt content break; @@ -1393,33 +1384,6 @@ function handleMessage(ws, data) { } } -function getDestinationFromSchedule(schedule) { - if (!schedule || !schedule.entries) return "Unknown"; - const entries = schedule.entries; - let dest = "Unknown"; - - // Convert entries to array if it's an object with numeric keys - const entryList = Array.isArray(entries) ? entries : Object.values(entries); - - // 1. Look for explicit destination instructions - for (const entry of entryList) { - if (entry.instruction?.id === 'create:destination') { - dest = entry.instruction.data?.text || entry.instruction.text || dest; - } - } - - // 2. If still Unknown, find the very last station instruction - if (dest === "Unknown") { - for (let i = entryList.length - 1; i >= 0; i--) { - if (entryList[i].instruction?.id === 'create:station') { - dest = entryList[i].instruction.data?.text || entryList[i].instruction.text || dest; - break; - } - } - } - return dest; -} - function getCorrectStationName(name) { const cleanName = String(name || '').trim(); const station = findStationByFlexibleName(cleanName); @@ -1483,40 +1447,6 @@ function handleStationRegister(ws, data) { broadcastUpdate(); } -function handleTrainArrival(data) { - let { trainId, stationName, arrivalTime, destination, source, schedule } = data; - stationName = getCorrectStationName(stationName); - const baseId = getBaseTrainId(trainId); - - const cooldownKey = `${baseId}|${stationName}|arrival`; - const lastEventTime = trainEventCooldown.get(cooldownKey); - if (lastEventTime && Date.now() - lastEventTime < 45000) return; - trainEventCooldown.set(cooldownKey, Date.now()); - - log('INFO', `Train ${trainId} (Consist ${baseId}) arrived at ${stationName}`); - - // Add or update active train using base ID to group cars - const existingIndex = activeTrains.findIndex(t => getBaseTrainId(t.trainId) === baseId); - - // Create history entry - let trainData = { - trainId, - currentStation: stationName, - destination: destination || (existingIndex >= 0 ? activeTrains[existingIndex].destination : "Unknown"), - status: "At Station", - lastUpdate: Date.now(), - schedule: schedule || (existingIndex >= 0 ? activeTrains[existingIndex].schedule : null) - }; - - if (existingIndex >= 0) { - activeTrains[existingIndex] = { ...activeTrains[existingIndex], ...trainData }; - } else { - activeTrains.push(trainData); - } - - broadcastUpdate(); -} - function getBaseName(name) { if (!name) return ""; return String(name).toLowerCase() @@ -1599,68 +1529,6 @@ function findStationByFlexibleName(targetName) { return null; } -function handleTrainDeparture(data) { - let { trainId, stationName, destination, schedule, source } = data; - stationName = getCorrectStationName(stationName); - const baseId = getBaseTrainId(trainId); - - const cooldownKey = `${baseId}|${stationName}|departure`; - const lastEventTime = trainEventCooldown.get(cooldownKey); - if (lastEventTime && Date.now() - lastEventTime < 45000) return; - trainEventCooldown.set(cooldownKey, Date.now()); - - log('INFO', `Train ${trainId} (Consist ${baseId}) departed from ${stationName}`); - - const existingIndex = activeTrains.findIndex(t => getBaseTrainId(t.trainId) === baseId); - if (existingIndex >= 0) { - const train = activeTrains[existingIndex]; - train.status = "Departed"; - train.currentStation = stationName; - train.lastUpdate = Date.now(); - train.lastStation = stationName; - train.departureTime = Date.now(); - train.destination = destination || train.destination; - train.schedule = schedule || train.schedule; - } - broadcastUpdate(); -} - -function handlePlaySequence(ws, data) { - const { stationName, seq, requestId } = data; - const cleanStation = stationName.trim(); - const correctStation = getCorrectStationName(cleanStation); - const streamName = getStationStreamName(cleanStation); - const hlsUrl = getStationHlsUrl(streamName); - - log('INFO', `Playing sequence for ${correctStation}: ${seq.join(', ')}`); - - const builtAudio = buildSequenceWavFile(seq); - if (builtAudio) { - const priority = Number.isFinite(Number(data.priority)) - ? Number(data.priority) - : (String(data.category || '').toLowerCase() === 'station' ? 0 : 1); - const interruptMode = data.interruptMode || getInterruptModeForPriority(priority); - const source = data.source || data.category || 'sequence'; - - const audioId = String(requestId || `${Date.now()}-${Math.random().toString(16).slice(2)}`); - - enqueueStationAudioTask(cleanStation, ws, { - audioFormat: builtAudio.audioFormat, - streamUrl: builtAudio.streamUrl, - durationSec: builtAudio.durationSec, - priority, - interruptMode, - source, - audioId, - requeueOnPreempt: priority <= 0, - consoleStreamStart: { type: 'stream_start', station: cleanStation, seq: seq, streamName, hlsUrl }, - consoleStreamEnd: { type: 'stream_end', station: cleanStation } - }); - } else { - log('WARN', `Unable to build WAV sequence for ${cleanStation}`); - } -} - function handleStationTimeRequest(ws, data) { // Simple logic: default to 60s or lookup schedule const stationTime = 60; diff --git a/station_broadcast.lua b/station_broadcast.lua index a18fec2..70f1bb5 100644 --- a/station_broadcast.lua +++ b/station_broadcast.lua @@ -38,15 +38,11 @@ local State = { currentTrain = nil, logs = {}, logScrollOffset = 0, - departingPlayed = false, - arrivalTonePlayed = false, - shortStopMode = false, audioRx = nil, audioQueue = {}, currentPlaying = nil, currentPriority = -1, - interruptSeq = 0, - lastArrivalPlayAt = 0 + interruptSeq = 0 } -- ============================================================================ @@ -952,133 +948,11 @@ function Utils.getStationAudio(code, langPrefix) return langPrefix .. code end -function Audio.announceArrival(trainId, trainType, platform, dest, useAltJz3) - local seq = {} - Utils.log("DEBUG", string.format("Announcing Arrival: %s, Type: %s, Plat: %s, Dest: %s", - tostring(trainId), tostring(trainType), tostring(platform), tostring(dest))) - - table.insert(seq, "ksts") -- Chime - table.insert(seq, "__DELAY_1__") - - local destCode = Utils.getStationCode(dest) - if (not destCode or destCode == "unknown") and dest ~= "Unknown" then - -- Fallback to broadcast code if regular code failed - destCode = Utils.getBroadcastStationCode(dest) - Utils.log("DEBUG", "Station code fallback for " .. tostring(dest) .. ": " .. tostring(destCode)) - end - - Utils.log("DEBUG", "Final destination code for " .. tostring(dest) .. ": " .. tostring(destCode)) - - local chJz3 = useAltJz3 and "ch-jz3-1" or "ch-jz3" - local enJz3 = useAltJz3 and "en-jz3-1" or "en-jz3" - - -- Chinese - table.insert(seq, "ch-jz1") - if destCode then - table.insert(seq, Utils.getStationAudio(destCode, "ch-")) - end - table.insert(seq, "ch-jz2") - table.insert(seq, trainType == "express" and "ch-tj" or "ch-pt") - table.insert(seq, chJz3) - - -- Platform Number (Chinese) - local pAudio = Utils.getChineseNumberAudio(platform) - for _, a in ipairs(pAudio) do table.insert(seq, a) end - - table.insert(seq, "ch-zt") - table.insert(seq, "ch-jz4") - - -- English - table.insert(seq, "en-jz1") - table.insert(seq, trainType == "express" and "en-tj" or "en-pt") - table.insert(seq, "en-jz2") - if destCode then - table.insert(seq, Utils.getStationAudio(destCode, "en-")) - end - table.insert(seq, enJz3) - table.insert(seq, "en-zt") - - -- English Platform Number - local pDigit, pLetter = tostring(platform):match("^(%d+)([a-zA-Z])$") - if pDigit and pLetter then - table.insert(seq, "en-" .. pDigit) - table.insert(seq, pLetter:upper()) - else - table.insert(seq, "en-" .. platform) - end - - table.insert(seq, "en-jz4") - - Audio.play(seq) -end - -function Audio.announceDeparture(trainId, trainType, platform, dest, time) - local seq = {} - table.insert(seq, "fcts") - table.insert(seq, "__DELAY_1__") - - local destCode = Utils.getStationCode(dest) - - -- Chinese - -- Platform Number - local pAudio = Utils.getChineseNumberAudio(platform) - for _, a in ipairs(pAudio) do table.insert(seq, a) end - - table.insert(seq, "ch-zt") - table.insert(seq, "ch-fc1") - table.insert(seq, trainType == "express" and "ch-tj" or "ch-pt") - table.insert(seq, "ch-fc2") - if destCode then - table.insert(seq, Utils.getStationAudio(destCode, "ch-")) - end - table.insert(seq, "ch-fc3") - - -- English - table.insert(seq, "en-fc1") - table.insert(seq, trainType == "express" and "en-tj" or "en-pt") - table.insert(seq, "en-fc2") - table.insert(seq, "en-zt") - - -- English Platform Number - local pDigit, pLetter = tostring(platform):match("^(%d+)([a-zA-Z])$") - if pDigit and pLetter then - table.insert(seq, "en-" .. pDigit) - table.insert(seq, pLetter:upper()) - else - table.insert(seq, "en-" .. platform) - end - - table.insert(seq, "en-fc3") - if destCode then - table.insert(seq, Utils.getStationAudio(destCode, "en-")) - end - table.insert(seq, "en-fc4") - - Audio.play(seq) -end - -- ============================================================================ -- 6. Network System -- ============================================================================ local Network = {} -function Audio.play(files) - if not State.ws then - Utils.log("WARN", "Cannot play audio: Not connected to server") - return - end - - Utils.log("INFO", "Requesting server to play sequence...") - Network.send({ - type = "play_sequence", - stationName = State.stationName, - seq = files, - category = "train", - priority = 1, - requestId = tostring(os.epoch("utc")) .. "-" .. tostring(math.random(100000, 999999)) - }) -end - function Network.connect() if State.ws then return end Utils.log("INFO", "Connecting to cloud...") @@ -1526,58 +1400,10 @@ function Main.loop() departureTime = now + stationTime, platform = Utils.getPlatformNumber(State.stationName, "1") } - - Network.send({ - type = "train_arrival", - trainId = id, - stationName = State.stationName, - destination = dest - }) - - if not State.arrivalTonePlayed then - if stationTime < 50 then - Utils.log("INFO", "Short stop (<50s) and no pre-arrival. Skipping arrival announcement.") - State.shortStopMode = true - else - Utils.log("INFO", "Train arrived. Playing arrival announcement (alt).") - Audio.announceArrival(State.currentTrain.id, State.currentTrain.trainType, State.currentTrain.platform, State.currentTrain.dest, true) - end - State.arrivalTonePlayed = true - end - else - -- Train currently at station - local now = os.epoch("utc") / 1000 - local remaining = State.currentTrain.departureTime - now - - if State.shortStopMode then - -- Play fcts.wav only in the last 10 seconds - if remaining <= 10 and not State.departingPlayed then - Utils.log("INFO", "Short stop mode: playing fcts.wav only.") - Audio.play({"fcts"}) - State.departingPlayed = true - end - else - if remaining <= 50 and not State.departingPlayed then - Audio.announceDeparture(State.currentTrain.id, State.currentTrain.trainType, State.currentTrain.platform, State.currentTrain.dest, 60) - State.departingPlayed = true - end - end end else if State.currentTrain then - -- Train just left - Network.send({ - type = "train_departure", - trainId = State.currentTrain.id, - stationName = State.stationName, - destination = State.currentTrain.dest, - schedule = State.currentTrain.schedule, - stationTime = math.floor((os.epoch("utc") / 1000) - State.currentTrain.arrivalTime) - }) State.currentTrain = nil - State.arrivalTonePlayed = false - State.departingPlayed = false - State.shortStopMode = false end end