Add metrics combinator entity, GUI, and related functionality; enhance power and production stats tracking
Greatly improved train trip perfomance by culling table after sending Fixed formatting in many places
This commit is contained in:
235
train-stats.lua
235
train-stats.lua
@@ -1,6 +1,6 @@
|
||||
function ScanTrains()
|
||||
storage.trains = {}
|
||||
for _,train in pairs(game.train_manager.get_trains({})) do
|
||||
for _, train in pairs(game.train_manager.get_trains({})) do
|
||||
storage.trains[train.id] = train
|
||||
end
|
||||
end
|
||||
@@ -12,101 +12,126 @@ function GetTrainName(train)
|
||||
return train.locomotives.front_movers[1].backer_name or ""
|
||||
elseif train.locomotives.back_movers[1] then
|
||||
return train.locomotives.back_movers[1].backer_name or ""
|
||||
end
|
||||
end
|
||||
return ""
|
||||
end
|
||||
|
||||
function GetTrainsInDepot()
|
||||
local trainsInDepot = 0
|
||||
for trainsID, train in pairs(storage.trains) do
|
||||
if train.state == defines.train_state.wait_station
|
||||
and train.station and train.station.backer_name == autotrainDepotName then
|
||||
if train.state == defines.train_state.wait_station
|
||||
and train.station and train.station.backer_name == autotrainDepotName then
|
||||
trainsInDepot = trainsInDepot + 1
|
||||
end
|
||||
end
|
||||
local trainsInGroup = #game.train_manager.get_trains({group=autotrainGroupName})
|
||||
return ("---autotrain-stats---\n%d:%d"):format(trainsInDepot,trainsInGroup)
|
||||
local trainsInGroup = #game.train_manager.get_trains({ group = autotrainGroupName })
|
||||
return ("---autotrain-stats---\n%d:%d"):format(trainsInDepot, trainsInGroup)
|
||||
end
|
||||
|
||||
function GetTrainPlayerKills()
|
||||
local trainKills = {}
|
||||
trainKills[#trainKills+1] = "---train-player-kills---"
|
||||
trainKills[#trainKills + 1] = "---train-player-kills---"
|
||||
---@type LuaTrain
|
||||
for _, train in pairs(storage.trains ) do
|
||||
for killedPlayerID,killedPlayerCount in pairs(train.killed_players) do
|
||||
trainKills[#trainKills+1] = ("%s:%s:%s:%s:%d"):format(train.id,GetTrainName(train),killedPlayerID,game.players[killedPlayerID].name,killedPlayerCount)
|
||||
for _, train in pairs(storage.trains) do
|
||||
for killedPlayerID, killedPlayerCount in pairs(train.killed_players) do
|
||||
trainKills[#trainKills + 1] = ("%s:%s:%s:%s:%d"):format(train.id, GetTrainName(train), killedPlayerID,
|
||||
game.players[killedPlayerID].name, killedPlayerCount)
|
||||
end
|
||||
end
|
||||
return table.concat(trainKills,"\n")
|
||||
return table.concat(trainKills, "\n")
|
||||
end
|
||||
|
||||
|
||||
function GetTrainTotalKills()
|
||||
local trainKills = {}
|
||||
trainKills[#trainKills+1] = "---train-total-kills---"
|
||||
trainKills[#trainKills + 1] = "---train-total-kills---"
|
||||
---@type LuaTrain
|
||||
for _, train in pairs(storage.trains) do
|
||||
trainKills[#trainKills+1] = ("%s:%s:%d"):format(train.id,GetTrainName(train),train.kill_count)
|
||||
trainKills[#trainKills + 1] = ("%s:%s:%d"):format(train.id, GetTrainName(train), train.kill_count)
|
||||
end
|
||||
return table.concat(trainKills,"\n")
|
||||
return table.concat(trainKills, "\n")
|
||||
end
|
||||
|
||||
--TODO: Seperate by surface
|
||||
function GetTrainStates()
|
||||
local trainsDriving = 0
|
||||
local trainsWaiting = 0
|
||||
local trainsProblems = 0
|
||||
local trainsManual = 0
|
||||
local trainsWaiting = {}
|
||||
local trainsDriving = {}
|
||||
local trainsManual = {}
|
||||
local trainsProblems = {}
|
||||
for _, train in pairs(storage.trains) do
|
||||
if train.state == defines.train_state.wait_station
|
||||
or train.state == defines.train_state.destination_full
|
||||
or train.state == defines.train_state.no_schedule
|
||||
then trainsWaiting = trainsWaiting + 1
|
||||
|
||||
elseif train.state == defines.train_state.on_the_path
|
||||
or train.state == defines.train_state.arrive_signal
|
||||
or train.state == defines.train_state.arrive_station
|
||||
or train.state == defines.train_state.wait_signal
|
||||
then trainsDriving = trainsDriving + 1
|
||||
|
||||
elseif train.state == defines.train_state.manual_control
|
||||
or train.state == defines.train_state.manual_control_stop
|
||||
then trainsManual = trainsManual + 1
|
||||
|
||||
elseif train.state == defines.train_state.no_path
|
||||
then trainsProblems = trainsProblems + 1 end
|
||||
local surfaceName
|
||||
if train.locomotives then
|
||||
if train.locomotives.front_movers[1] then
|
||||
surfaceName = train.locomotives.front_movers[1].surface.name
|
||||
end
|
||||
elseif train.locomotives.back_movers[1] then
|
||||
surfaceName = train.locomotives.back_movers[1].surface.name
|
||||
end
|
||||
if surfaceName then
|
||||
if train.state == defines.train_state.wait_station
|
||||
or train.state == defines.train_state.destination_full
|
||||
or train.state == defines.train_state.no_schedule
|
||||
then
|
||||
trainsWaiting[surfaceName] = (trainsWaiting[surfaceName] or 0) + 1
|
||||
elseif train.state == defines.train_state.on_the_path
|
||||
or train.state == defines.train_state.arrive_signal
|
||||
or train.state == defines.train_state.arrive_station
|
||||
or train.state == defines.train_state.wait_signal
|
||||
then
|
||||
trainsDriving[surfaceName] = (trainsDriving[surfaceName] or 0) + 1
|
||||
elseif train.state == defines.train_state.manual_control
|
||||
or train.state == defines.train_state.manual_control_stop
|
||||
then
|
||||
trainsManual[surfaceName] = (trainsManual[surfaceName] or 0) + 1
|
||||
elseif train.state == defines.train_state.no_path
|
||||
then
|
||||
trainsProblems[surfaceName] = (trainsProblems[surfaceName] or 0) + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
return ("---trains-states---\n%d:%d:%d:%d"):format(trainsDriving,trainsManual,trainsProblems,trainsWaiting)
|
||||
local stateParts = {}
|
||||
stateParts[#stateParts + 1] = "---trains-states---\n"
|
||||
for _, surface in pairs(game.surfaces) do
|
||||
local surfaceName = surface.name
|
||||
stateParts[#stateParts + 1] = ("%s:%d:%d:%d:%d"):format(
|
||||
surfaceName,
|
||||
trainsDriving[surfaceName] or 0,
|
||||
trainsManual[surfaceName] or 0,
|
||||
trainsProblems[surfaceName] or 0,
|
||||
trainsWaiting[surfaceName] or 0)
|
||||
end
|
||||
return table.concat(stateParts, "\n")
|
||||
end
|
||||
|
||||
---@class trainStat
|
||||
trainStat = {
|
||||
trainID = 0,
|
||||
trainName = "",
|
||||
lastInventory={},
|
||||
currentInventory={},
|
||||
lastInventory = {},
|
||||
currentInventory = {},
|
||||
lastState = 0,
|
||||
lastStationUnitNumber = 0,
|
||||
currentStationUnitNumber = 0,
|
||||
totalCargoCount = 0,
|
||||
totalCargoCount = 0,
|
||||
totalCargo = {},
|
||||
lastArrivalTime = 0,
|
||||
currentArrivalTime = 0,
|
||||
---@type trip
|
||||
trips = {}
|
||||
trips = {}
|
||||
}
|
||||
---@class trip
|
||||
trip = {
|
||||
startStation= {},
|
||||
endStation = {},
|
||||
timeTaken = 0
|
||||
}
|
||||
trip = {
|
||||
startStation = {},
|
||||
endStation = {},
|
||||
timeTaken = 0,
|
||||
tick = 0
|
||||
}
|
||||
|
||||
---@param inv table[]
|
||||
---@return table<string, table>
|
||||
local function toLookup(inv)
|
||||
local t = {}
|
||||
for _, item in ipairs(inv) do
|
||||
local key = item.name .. ":" .. (item.quality or 0) -- eindeutiger Key
|
||||
local key = item.name .. ":" .. (item.quality or 0) -- eindeutiger Key
|
||||
t[key] = item.count
|
||||
end
|
||||
return t
|
||||
@@ -166,7 +191,6 @@ function onTrainStateChange(event)
|
||||
stat.trainName = GetTrainName(train)
|
||||
|
||||
if event.train.state == defines.train_state.wait_station then
|
||||
|
||||
if not train.station then return end
|
||||
if train.station.unit_number == stat.lastStationUnitNumber then return end
|
||||
|
||||
@@ -179,19 +203,21 @@ function onTrainStateChange(event)
|
||||
stat.currentArrivalTime = game.tick
|
||||
|
||||
if stat.lastStationUnitNumber
|
||||
and stat.currentStationUnitNumber
|
||||
and (stat.lastStationUnitNumber ~= stat.currentStationUnitNumber) then
|
||||
local tripIdentifier = tostring(stat.lastStationUnitNumber) .. tostring(stat.currentStationUnitNumber)
|
||||
stat.trips[tripIdentifier] = {
|
||||
startStation = game.get_entity_by_unit_number(stat.lastStationUnitNumber),
|
||||
endStation = game.get_entity_by_unit_number(stat.currentStationUnitNumber),
|
||||
timeTaken = stat.currentArrivalTime-stat.lastArrivalTime}
|
||||
and stat.currentStationUnitNumber
|
||||
and (stat.lastStationUnitNumber ~= stat.currentStationUnitNumber) then
|
||||
local tripIdentifier = tostring(stat.lastStationUnitNumber) .. tostring(stat.currentStationUnitNumber)
|
||||
stat.trips[tripIdentifier] = {
|
||||
startStation = game.get_entity_by_unit_number(stat.lastStationUnitNumber),
|
||||
endStation = game.get_entity_by_unit_number(stat.currentStationUnitNumber),
|
||||
timeTaken = stat.currentArrivalTime - stat.lastArrivalTime,
|
||||
time = game.tick
|
||||
}
|
||||
end
|
||||
|
||||
if stat.currentInventory and stat.lastInventory then
|
||||
--Get Total Cargo
|
||||
for key, value in pairs(inventoryDiff(stat.lastInventory,stat.currentInventory)) do
|
||||
stat.totalCargoCount = (stat.totalCargoCount or 0) + math.abs(value.delta)
|
||||
--Get Total Cargo
|
||||
for key, value in pairs(inventoryDiff(stat.lastInventory, stat.currentInventory)) do
|
||||
stat.totalCargoCount = (stat.totalCargoCount or 0) + math.abs(value.delta)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -199,14 +225,15 @@ function onTrainStateChange(event)
|
||||
end
|
||||
--log("inEvent")
|
||||
end
|
||||
|
||||
--Checks if trip is still valid by checking of st
|
||||
function isTripValid(trip,tripID,trainID)
|
||||
function isTripValid(trip, tripID, trainID)
|
||||
if trip.startStation == nil
|
||||
or trip.endStation==nil
|
||||
or trip.startStation.valid == false
|
||||
or trip.endStation.valid == false then
|
||||
--One station is nil so we delete this trip
|
||||
log("Deleting trip"..tripID)
|
||||
or trip.endStation == nil
|
||||
or trip.startStation.valid == false
|
||||
or trip.endStation.valid == false then
|
||||
--One station is nil so we delete this trip
|
||||
log("Deleting trip" .. tripID)
|
||||
storage.trainStats[trainID].trips[tripID] = nil
|
||||
return false
|
||||
end
|
||||
@@ -214,40 +241,55 @@ function isTripValid(trip,tripID,trainID)
|
||||
return true
|
||||
end
|
||||
|
||||
function SortTrips()
|
||||
for trainID, stat in pairs(storage.trainStats) do
|
||||
table.sort(stat.trips, function(a, b)
|
||||
return a.tick > b.tick
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
function GetTrainTripStats()
|
||||
--SortTrips()
|
||||
local tripParts = {}
|
||||
local tripCount = 0
|
||||
tripParts[#tripParts+1] = "---train-trips---\n"
|
||||
for trainID,stats in pairs(storage.trainStats) do
|
||||
for tripIndex,trip in pairs(stats.trips or {}) do
|
||||
if isTripValid(trip,tripIndex,trainID) then
|
||||
tripParts[#tripParts+1] =
|
||||
("%d:%s:%s:%s:%d"):format(
|
||||
trainID,
|
||||
stats.trainName,
|
||||
trip.startStation.backer_name,
|
||||
trip.endStation.backer_name,
|
||||
trip.timeTaken)
|
||||
tripCount = tripCount + 1
|
||||
tripParts[#tripParts + 1] = "---train-trips---\n"
|
||||
for trainID, stats in pairs(storage.trainStats) do
|
||||
for tripIndex, trip in pairs(stats.trips or {}) do
|
||||
if isTripValid(trip, tripIndex, trainID) then
|
||||
tripParts[#tripParts + 1] =
|
||||
("%d:%s:%s:%s:%s:%d"):format(
|
||||
trainID,
|
||||
stats.trainName,
|
||||
trip.startStation.surface.name,
|
||||
trip.startStation.backer_name,
|
||||
trip.endStation.backer_name,
|
||||
trip.timeTaken)
|
||||
tripCount = tripCount + 1
|
||||
end
|
||||
--To clean up, we delete this trip now
|
||||
stats.trips[tripIndex] = nil
|
||||
end
|
||||
if #tripParts > 400 then
|
||||
log("Sending at "..tripCount.." trips")
|
||||
helpers.send_udp(udpAddress,table.concat(tripParts,"\n"),serverIndex)
|
||||
log("Sending at " .. tripCount .. " trips")
|
||||
helpers.send_udp(udpAddress, table.concat(tripParts, "\n"), serverIndex)
|
||||
tripParts = {}
|
||||
tripParts[#tripParts + 1] = "---train-trips---\n"
|
||||
end
|
||||
end
|
||||
log("Counted "..tripCount.." trips")
|
||||
--tripParts[#tripParts+1] = "--train-fin--"
|
||||
helpers.send_udp(udpAddress, table.concat(tripParts, "\n"), serverIndex)
|
||||
log("Counted " .. tripCount .. " trips")
|
||||
--return table.concat(tripParts,"\n")
|
||||
end
|
||||
|
||||
function GetTrainStatistics()
|
||||
local trainParts = {}
|
||||
trainParts[#trainParts+1] = "---train-total-statistics---\n"
|
||||
trainParts[#trainParts + 1] = "---train-total-statistics---\n"
|
||||
for trainID, stat in pairs(storage.trainStats) do
|
||||
trainParts[#trainParts+1] = ("%d:%s:%d"):format(trainID,stat.trainName,stat.totalCargoCount or 0)
|
||||
trainParts[#trainParts + 1] = ("%d:%s:%d"):format(trainID, stat.trainName, stat.totalCargoCount or 0)
|
||||
end
|
||||
return table.concat(trainParts,"\n")
|
||||
return table.concat(trainParts, "\n")
|
||||
end
|
||||
|
||||
---Purges stats for trains that no longer exist
|
||||
@@ -270,21 +312,20 @@ function PurgeDeadTrainStats(trainID)
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
function SendTrainStats()
|
||||
if options.enableTrains then
|
||||
ScanTrains()
|
||||
PurgeDeadTrainStats()
|
||||
local returnParts = {}
|
||||
returnParts[#returnParts+1] = GetTrainPlayerKills()
|
||||
returnParts[#returnParts+1] = GetTrainTotalKills()
|
||||
returnParts[#returnParts+1] = GetTrainStates()
|
||||
returnParts[#returnParts+1] = GetTrainStatistics()
|
||||
returnParts[#returnParts+1] = GetTrainsInDepot()
|
||||
if options.enableTrainTrips then
|
||||
GetTrainTripStats()
|
||||
ScanTrains()
|
||||
PurgeDeadTrainStats()
|
||||
local returnParts = {}
|
||||
returnParts[#returnParts + 1] = GetTrainPlayerKills()
|
||||
returnParts[#returnParts + 1] = GetTrainTotalKills()
|
||||
returnParts[#returnParts + 1] = GetTrainStates()
|
||||
returnParts[#returnParts + 1] = GetTrainStatistics()
|
||||
returnParts[#returnParts + 1] = GetTrainsInDepot()
|
||||
if options.enableTrainTrips then
|
||||
GetTrainTripStats()
|
||||
end
|
||||
log("Sending Train statistics")
|
||||
helpers.send_udp(udpAddress, table.concat(returnParts, "\n"), serverIndex)
|
||||
end
|
||||
log("Sending Train statistics")
|
||||
helpers.send_udp(udpAddress,table.concat(returnParts,"\n"),serverIndex)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user