updateSlowFromRace
Definition
-- @/lua/ge/extensions/core/lapTimes.lua:240
-- Update slow-changing data from race state
local function updateSlowFromRace(race, playerId)
if not race or not race.states or not race.states[playerId] then
return
end
local state = race.states[playerId]
-- Update status from race state
if state.complete == true then
status = "complete"
elseif race.suspended == true then
status = "paused"
elseif race.started == true then
status = "started"
else
status = "stopped"
end
-- Update current lap/segment
if state.complete == true then
-- When race is complete, show max values
currentLap = totalLaps
currentSegment = totalSegments
else
currentLap = (state.currentLap or 0) + 1
currentSegment = (#state.currentTimes) + 1
end
-- Process historical lap times to find best lap
local bestLap = nil
local lapData = {} -- Temporary for this function only
for i = 1, #state.historicTimes do
local l = state.historicTimes[i]
local duration = l.duration or ((l.endTime or 0) - (l.beginTime or 0))
if not bestLap or duration < bestLap then
bestLap = duration
end
-- Store minimal data needed for stream building
lapData[i] = {
lap = (l.lap or (i - 1)) + 1,
startTime = l.beginTime,
endTime = l.endTime,
duration = duration,
time = l.endTime
}
end
-- Build historical segment times and find bests
table.clear(segmentTimes)
table.clear(segmentTimesByLap)
table.clear(bestSegmentTimes)
table.clear(bestSegmentLaps)
local bestPerIndex = {}
-- Process completed laps from historicTimes
for i = 1, #state.historicTimes do
local l = state.historicTimes[i]
local oneBasedLap = (l.lap or (i - 1)) + 1
for idx = 1, #l.segmentTimes do
local s = l.segmentTimes[idx]
local duration = s.duration or ((s.endTime or 0) - (s.beginTime or 0))
if not bestPerIndex[idx] or duration < bestPerIndex[idx] then
bestPerIndex[idx] = duration
bestSegmentTimes[idx] = duration
bestSegmentLaps[idx] = oneBasedLap
end
local segEntry = {
lap = oneBasedLap,
segment = idx,
startTime = s.beginTime,
endTime = s.endTime,
duration = duration,
skipped = false,
isBest = false,
diffToPrevious = nil,
diffToBest = nil
}
table.insert(segmentTimes, segEntry)
segmentTimesByLap[oneBasedLap] = segmentTimesByLap[oneBasedLap] or {}
segmentTimesByLap[oneBasedLap][idx] = segEntry
end
end
-- Process current lap segments from currentTimes
for idx = 1, #state.currentTimes do
local s = state.currentTimes[idx]
local duration = s.duration or ((s.endTime or 0) - (s.beginTime or 0))
if not bestPerIndex[idx] or duration < bestPerIndex[idx] then
bestPerIndex[idx] = duration
bestSegmentTimes[idx] = duration
bestSegmentLaps[idx] = (state.currentLap or 0) + 1
end
local segEntry = {
lap = (state.currentLap or 0) + 1,
segment = idx,
startTime = s.beginTime,
endTime = s.endTime,
duration = duration,
skipped = false,
isBest = false,
diffToPrevious = nil,
diffToBest = nil
}
table.insert(segmentTimes, segEntry)
local currentLapIndex1 = (state.currentLap or 0) + 1
segmentTimesByLap[currentLapIndex1] = segmentTimesByLap[currentLapIndex1] or {}
segmentTimesByLap[currentLapIndex1][idx] = segEntry
end
-- Compute diffs and mark bests
-- Build quick access map lap->index->duration
local lapIndexToDuration = {}
for _, seg in ipairs(segmentTimes) do
lapIndexToDuration[seg.lap] = lapIndexToDuration[seg.lap] or {}
lapIndexToDuration[seg.lap][seg.segment] = seg.duration
end
for _, seg in ipairs(segmentTimes) do
if lapIndexToDuration[seg.lap - 1] and lapIndexToDuration[seg.lap - 1][seg.segment] then
seg.diffToPrevious = seg.duration - lapIndexToDuration[seg.lap - 1][seg.segment]
end
local bestAtIdx = bestPerIndex[seg.segment]
seg.diffToBest = bestAtIdx and (seg.duration - bestAtIdx) or nil
if bestAtIdx and seg.duration == bestAtIdx then
seg.isBest = true
end
end
-- Update best lap tracking
bestLapTime = bestLap
bestLapIndex = 0
if bestLapTime then
for i, lap in ipairs(lapData) do
if lap.duration == bestLapTime then
bestLapIndex = i
break
end
end
end
-- Populate slow stream data directly
table.clear(slowStreamData)
-- Race status
slowStreamData.status = status
-- Current lap and segment
slowStreamData.currentLap = currentLap
slowStreamData.currentSegment = currentSegment
-- Best times
slowStreamData.bestLapTimeFormatted = bestLapTime and M.formatTime(bestLapTime) or nil
slowStreamData.bestLapIndex = bestLapIndex
-- Format best segment times with lap information
slowStreamData.bestSegmentTimesFormatted = {}
for segmentIndex, time in pairs(bestSegmentTimes) do
local lap = bestSegmentLaps[segmentIndex] or 1
slowStreamData.bestSegmentTimesFormatted[segmentIndex] = {
time = M.formatTime(time),
lap = lap
}
end
-- Historical lap times - build stream directly from temporary data
slowStreamData.lapTimes = {}
local prevLapDuration = nil
for i, lap in ipairs(lapData) do
-- Calculate diffs
local diffToPrevious = prevLapDuration and (lap.duration - prevLapDuration) or nil
local diffToBest = bestLapTime and (lap.duration - bestLapTime) or nil
local isBest = bestLapTime and lap.duration == bestLapTime or false
-- Only mark as best if there are multiple laps to compare
local hasMultipleLaps = #lapData > 1
local lapInfo = {
lap = lap.lap,
durationFormatted = M.formatTime(lap.duration),
timeFormatted = lap.time and M.formatTime(lap.time) or nil,
endTimeFormatted = M.formatTime(lap.endTime),
lapFlavor = (isBest and hasMultipleLaps) and 'best' or 'default',
diffToPreviousFormatted = diffToPrevious and M.formatTime(diffToPrevious, true) or nil,
diffToBestFormatted = diffToBest and M.formatTime(diffToBest, true) or nil,
diffToPreviousFlavor = diffToPrevious and getDiffFlavor(diffToPrevious) or 'default',
diffToBestFlavor = diffToBest and getDiffFlavor(diffToBest) or 'default'
}
table.insert(slowStreamData.lapTimes, lapInfo)
prevLapDuration = lap.duration
end
-- Historical segment times
slowStreamData.segmentTimes = {}
-- Count how many times each segment index appears
local segmentCounts = {}
for _, segment in ipairs(segmentTimes) do
segmentCounts[segment.segment] = (segmentCounts[segment.segment] or 0) + 1
end
for i, segment in ipairs(segmentTimes) do
-- Only mark as best if there are multiple instances of this segment to compare
local hasMultipleInstances = segmentCounts[segment.segment] > 1
local segmentInfo = {
segment = segment.lap and (segment.lap .. '-' .. segment.segment) or segment.segment,
durationFormatted = M.formatTime(segment.duration),
timeFormatted = segment.time and M.formatTime(segment.time) or nil,
endTimeFormatted = M.formatTime(segment.endTime),
segmentFlavor = (segment.isBest and hasMultipleInstances) and 'best' or 'default',
diffToPreviousFormatted = segment.diffToPrevious and M.formatTime(segment.diffToPrevious, true) or nil,
diffToBestFormatted = segment.diffToBest and M.formatTime(segment.diffToBest, true) or nil,
diffToPreviousFlavor = segment.diffToPrevious and getDiffFlavor(segment.diffToPrevious) or 'default',
diffToBestFlavor = segment.diffToBest and getDiffFlavor(segment.diffToBest) or 'default'
}
table.insert(slowStreamData.segmentTimes, segmentInfo)
end
-- Combined lap+segment list (alternating segments then lap for completed laps, plus current lap segments)
slowStreamData.combinedTimes = {}
-- Include completed laps (from historicTimes)
for i, lap in ipairs(lapData) do
-- Add all segments for this lap
if segmentTimesByLap[lap.lap] then
for segmentIndex = 1, totalSegments do
local segment = segmentTimesByLap[lap.lap][segmentIndex]
if segment then
local hasMultipleInstances = segmentCounts[segment.segment] > 1
local combinedSegmentInfo = {
type = 'segment',
lap = segment.lap,
segment = segment.segment,
identifier = segment.lap .. '-' .. segment.segment,
durationFormatted = M.formatTime(segment.duration),
timeFormatted = segment.time and M.formatTime(segment.time) or nil,
endTimeFormatted = M.formatTime(segment.endTime),
flavor = (segment.isBest and hasMultipleInstances) and 'best' or 'default',
diffToPreviousFormatted = segment.diffToPrevious and M.formatTime(segment.diffToPrevious, true) or nil,
diffToBestFormatted = segment.diffToBest and M.formatTime(segment.diffToBest, true) or nil,
diffToPreviousFlavor = segment.diffToPrevious and getDiffFlavor(segment.diffToPrevious) or 'default',
diffToBestFlavor = segment.diffToBest and getDiffFlavor(segment.diffToBest) or 'default'
}
table.insert(slowStreamData.combinedTimes, combinedSegmentInfo)
end
end
end
-- Add the lap itself after all its segments
local diffToPrevious = i > 1 and (lap.duration - lapData[i-1].duration) or nil
local diffToBest = bestLapTime and (lap.duration - bestLapTime) or nil
local isBest = bestLapTime and lap.duration == bestLapTime or false
local hasMultipleLaps = #lapData > 1
local combinedLapInfo = {
type = 'lap',
lap = lap.lap,
identifier = lap.lap,
durationFormatted = M.formatTime(lap.duration),
timeFormatted = lap.time and M.formatTime(lap.time) or nil,
endTimeFormatted = M.formatTime(lap.endTime),
flavor = (isBest and hasMultipleLaps) and 'best' or 'default',
diffToPreviousFormatted = diffToPrevious and M.formatTime(diffToPrevious, true) or nil,
diffToBestFormatted = diffToBest and M.formatTime(diffToBest, true) or nil,
diffToPreviousFlavor = diffToPrevious and getDiffFlavor(diffToPrevious) or 'default',
diffToBestFlavor = diffToBest and getDiffFlavor(diffToBest) or 'default'
}
table.insert(slowStreamData.combinedTimes, combinedLapInfo)
end
-- Add completed segments from current lap (if any)
local currentLapIndex1 = (state.currentLap or 0) + 1
if segmentTimesByLap[currentLapIndex1] and not state.complete then
for segmentIndex = 1, totalSegments do
local segment = segmentTimesByLap[currentLapIndex1][segmentIndex]
if segment then
local hasMultipleInstances = segmentCounts[segment.segment] > 1
local combinedSegmentInfo = {
type = 'segment',
lap = segment.lap,
segment = segment.segment,
identifier = segment.lap .. '-' .. segment.segment,
durationFormatted = M.formatTime(segment.duration),
timeFormatted = segment.time and M.formatTime(segment.time) or nil,
endTimeFormatted = M.formatTime(segment.endTime),
flavor = (segment.isBest and hasMultipleInstances) and 'best' or 'default',
diffToPreviousFormatted = segment.diffToPrevious and M.formatTime(segment.diffToPrevious, true) or nil,
diffToBestFormatted = segment.diffToBest and M.formatTime(segment.diffToBest, true) or nil,
diffToPreviousFlavor = segment.diffToPrevious and getDiffFlavor(segment.diffToPrevious) or 'default',
diffToBestFlavor = segment.diffToBest and getDiffFlavor(segment.diffToBest) or 'default'
}
table.insert(slowStreamData.combinedTimes, combinedSegmentInfo)
end
end
end
-- Set flag for onUpdate to send the stream
needSlowStream = true
end
Callers
@/lua/ge/extensions/gameplay/crawl/utils.lua
updateRaceDataStructure(crawlerId, state, state.raceData)
core_lapTimes.updateSlowFromRace(state.raceData, crawlerId)
end
updateRaceDataStructure(crawlerId, state, state.raceData)
core_lapTimes.updateSlowFromRace(state.raceData, crawlerId)
end
updateRaceDataStructure(crawlerId, state, state.raceData)
core_lapTimes.updateSlowFromRace(state.raceData, crawlerId)
core_lapTimes.onRaceStop()
@/lua/ge/extensions/gameplay/race/race.lua
if core_lapTimes.updateSlowFromRace then
core_lapTimes.updateSlowFromRace(self, id)
end
if core_lapTimes.updateSlowFromRace then
core_lapTimes.updateSlowFromRace(self, id)
end
if core_lapTimes.updateSlowFromRace then
core_lapTimes.updateSlowFromRace(self, id)
end
if core_lapTimes.updateSlowFromRace then
core_lapTimes.updateSlowFromRace(self, id)
end