mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
Last Updates
This commit is contained in:
2488
Moose Development/Moose/Utilities/Routines.lua
Normal file
2488
Moose Development/Moose/Utilities/Routines.lua
Normal file
File diff suppressed because it is too large
Load Diff
246
Moose Development/Moose/Utilities/StatHandler.lua
Normal file
246
Moose Development/Moose/Utilities/StatHandler.lua
Normal file
@@ -0,0 +1,246 @@
|
||||
--- Provides a logging of statistics in a running DCS Mission.
|
||||
-- @script eStatHandler
|
||||
|
||||
|
||||
|
||||
|
||||
--Handler table
|
||||
local eStatHandler = {}
|
||||
local _StatRunID
|
||||
|
||||
--Neccessary tables for string instead of integers
|
||||
SETCoalition =
|
||||
{
|
||||
[1] = "red",
|
||||
[2] = "blue",
|
||||
}
|
||||
|
||||
SETGroupCat =
|
||||
{
|
||||
[1] = "AIRPLANE",
|
||||
[2] = "HELICOPTER",
|
||||
[3] = "GROUND",
|
||||
[4] = "SHIP",
|
||||
[5] = "STRUCTURE",
|
||||
}
|
||||
|
||||
SETWeaponCatName =
|
||||
{
|
||||
[0] = "SHELL",
|
||||
[1] = "MISSILE",
|
||||
[2] = "ROCKET",
|
||||
[3] = "BOMB",
|
||||
}
|
||||
|
||||
wEvent = {
|
||||
"S_EVENT_SHOT",
|
||||
"S_EVENT_HIT",
|
||||
"S_EVENT_TAKEOFF",
|
||||
"S_EVENT_LAND",
|
||||
"S_EVENT_CRASH",
|
||||
"S_EVENT_EJECTION",
|
||||
"S_EVENT_REFUELING",
|
||||
"S_EVENT_DEAD",
|
||||
"S_EVENT_PILOT_DEAD",
|
||||
"S_EVENT_BASE_CAPTURED",
|
||||
"S_EVENT_MISSION_START",
|
||||
"S_EVENT_MISSION_END",
|
||||
"S_EVENT_TOOK_CONTROL",
|
||||
"S_EVENT_REFUELING_STOP",
|
||||
"S_EVENT_BIRTH",
|
||||
"S_EVENT_HUMAN_FAILURE",
|
||||
"S_EVENT_ENGINE_STARTUP",
|
||||
"S_EVENT_ENGINE_SHUTDOWN",
|
||||
"S_EVENT_PLAYER_ENTER_UNIT",
|
||||
"S_EVENT_PLAYER_LEAVE_UNIT",
|
||||
"S_EVENT_PLAYER_COMMENT",
|
||||
"S_EVENT_SHOOTING_START",
|
||||
"S_EVENT_SHOOTING_END",
|
||||
"S_EVENT_MAX",
|
||||
}
|
||||
|
||||
statEventsTable = {}
|
||||
|
||||
|
||||
function SecondsToClock(sSeconds)
|
||||
local nSeconds = sSeconds
|
||||
if nSeconds == 0 then
|
||||
--return nil;
|
||||
return "00:00:00";
|
||||
else
|
||||
nHours = string.format("%02.f", math.floor(nSeconds/3600));
|
||||
nMins = string.format("%02.f", math.floor(nSeconds/60 - (nHours*60)));
|
||||
nSecs = string.format("%02.f", math.floor(nSeconds - nHours*3600 - nMins *60));
|
||||
return nHours..":"..nMins..":"..nSecs
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function eStatHandler:onEvent(e)
|
||||
local InitID_ = ""
|
||||
local InitName = ""
|
||||
local WorldEvent = wEvent[e.id]
|
||||
local InitCoa = ""
|
||||
local InitGroupCat = ""
|
||||
local InitType = ""
|
||||
local InitPlayer = ""
|
||||
local eWeaponCat = ""
|
||||
local eWeaponName = ""
|
||||
local TargID_ = ""
|
||||
local TargName = ""
|
||||
local TargType = ""
|
||||
local TargPlayer = ""
|
||||
local TargCoa = ""
|
||||
local TargGroupCat = ""
|
||||
|
||||
if e.initiator and Object.getCategory(e.initiator) == Object.Category.UNIT then
|
||||
--Initiator variables
|
||||
local InitGroup = e.initiator:getGroup()
|
||||
InitID_ = e.initiator.id_
|
||||
if e.initiator:getName() then
|
||||
InitName = e.initiator:getName()
|
||||
end
|
||||
if InitGroup:getCoalition() then
|
||||
InitCoa = SETCoalition[InitGroup:getCoalition()]
|
||||
end
|
||||
if InitGroup:getCategory() then
|
||||
InitGroupCat = SETGroupCat[InitGroup:getCategory() + 1]
|
||||
end
|
||||
InitType = e.initiator:getTypeName()
|
||||
|
||||
--Get initiator player name or AI if NIL
|
||||
if e.initiator:getPlayerName() == nil then
|
||||
InitPlayer = "AI"
|
||||
else
|
||||
InitPlayer = e.initiator:getPlayerName()
|
||||
end
|
||||
else
|
||||
if e.initiator then
|
||||
local InitGroup = e.initiator:getGroup()
|
||||
InitID_ = e.initiator.id_
|
||||
if e.initiator:getName() then
|
||||
InitName = e.initiator:getName()
|
||||
end
|
||||
InitCoa = SETCoalition[InitGroup:getCoalition()]
|
||||
InitGroupCat = SETGroupCat[InitGroup:getCategory() + 1]
|
||||
InitType = e.initiator:getTypeName()
|
||||
|
||||
--Get initiator player name or AI if NIL
|
||||
if e.initiator:getPlayerName() == nil then
|
||||
InitPlayer = "AI"
|
||||
else
|
||||
InitPlayer = e.initiator:getPlayerName()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--Weapon variables
|
||||
if e.weapon == nil then
|
||||
eWeaponCat = ""
|
||||
eWeaponName = ""
|
||||
else
|
||||
local eWeaponDesc = e.weapon:getDesc()
|
||||
eWeaponCat = SETWeaponCatName[eWeaponDesc.category]
|
||||
eWeaponName = eWeaponDesc.displayName
|
||||
end
|
||||
|
||||
--Target variables
|
||||
if e.target == nil then
|
||||
TargID_ = ""
|
||||
TargName = ""
|
||||
TargType = ""
|
||||
TargPlayer = ""
|
||||
TargCoa = ""
|
||||
TargGroupCat = ""
|
||||
elseif Object.getCategory(e.target) == Object.Category.UNIT then
|
||||
local TargGroup = e.target:getGroup()
|
||||
TargID_ = e.target.id_
|
||||
if e.target:getName() then
|
||||
TargName = e.target:getName()
|
||||
end
|
||||
TargType = e.target:getTypeName()
|
||||
TargCoa = SETCoalition[TargGroup:getCoalition()]
|
||||
TargGroupCat = SETGroupCat[TargGroup:getCategory() + 1]
|
||||
|
||||
--Get target player name or AI if NIL
|
||||
if not e.target:getPlayerName() then
|
||||
TargPlayer = "AI"
|
||||
else
|
||||
TargPlayer = e.target:getPlayerName()
|
||||
end
|
||||
else
|
||||
TargType = e.target:getTypeName()
|
||||
TargID_ = ""
|
||||
TargName = ""
|
||||
TargPlayer = ""
|
||||
TargCoa = ""
|
||||
TargGroupCat = ""
|
||||
end
|
||||
|
||||
--write events to table
|
||||
statEventsTable[#statEventsTable + 1] =
|
||||
{
|
||||
[1] = _StatRunID,
|
||||
[2] = SecondsToClock(timer.getTime()),
|
||||
[3] = WorldEvent,
|
||||
[4] = InitID_,
|
||||
[5] = InitName,
|
||||
[6] = InitCoa,
|
||||
[7] = InitGroupCat,
|
||||
[8] = InitType,
|
||||
[9] = InitPlayer,
|
||||
[10] = eWeaponCat,
|
||||
[11] = eWeaponName,
|
||||
[12] = TargID_,
|
||||
[13] = TargName,
|
||||
[14] = TargCoa,
|
||||
[15] = TargGroupCat,
|
||||
[16] = TargType,
|
||||
[17] = TargPlayer,
|
||||
}
|
||||
env.info( 'Event: ' .. _StatRunID .. '~ ' .. SecondsToClock(timer.getTime()) .. '~ ' .. WorldEvent .. '~ ' .. InitID_ .. '~ ' .. InitName .. '~ ' .. InitCoa .. '~ ' .. InitGroupCat .. '~ ' .. InitType .. '~ ' .. InitPlayer ..
|
||||
'~ ' .. eWeaponCat .. '~ ' .. eWeaponName .. '~ ' .. TargID_ .. '~ ' .. TargName .. '~ ' .. TargCoa .. '~ ' .. TargGroupCat .. '~ ' .. TargType .. '~ ' .. TargPlayer )
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
do
|
||||
|
||||
local StatFile,err
|
||||
|
||||
|
||||
function StatOpen()
|
||||
local fdir = lfs.writedir() .. [[Logs\]] .. "Events_" .. os.date( "%Y-%m-%d_%H-%M-%S" ) .. ".csv"
|
||||
StatFile,err = io.open(fdir,"w+")
|
||||
if not StatFile then
|
||||
local errmsg = 'Error: No Logs folder found in the User\\Saved Games\\DCS\\Logs directory...' .. 'Save_stat . sample: C:\\Users\\youname\\Saved Games\\DCS\\Logs'
|
||||
trigger.action.outText(errmsg, 10)
|
||||
return print(err)
|
||||
end
|
||||
StatFile:write("RunID~Time~Event~Initiator ID~Initiator Name~Initiator Coalition~Initiator Group Category~Initiator Type~Initiator Player~Weapon Category~Weapon Name~Target ID~Target Name~Target Coalition~Target Group Category~Target Type~Target Player\n")
|
||||
|
||||
_StatRunID = os.date("%y-%m-%d_%H-%M-%S")
|
||||
routines.scheduleFunction( StatSave, { }, timer.getTime() + 1, 1)
|
||||
end
|
||||
|
||||
function StatSave()
|
||||
--write statistic information to file
|
||||
for Index, eDetails in ipairs(statEventsTable) do
|
||||
for eInfoName, eInfoData in ipairs(eDetails) do
|
||||
StatFile:write(eInfoData.."~")
|
||||
end
|
||||
StatFile:write("\n")
|
||||
end
|
||||
statEventsTable = {}
|
||||
end
|
||||
|
||||
function StatClose()
|
||||
StatFile:close()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
world.addEventHandler(eStatHandler)
|
||||
StatOpen()
|
||||
|
||||
295
Moose Development/Moose/Utilities/Utils.lua
Normal file
295
Moose Development/Moose/Utilities/Utils.lua
Normal file
@@ -0,0 +1,295 @@
|
||||
--- This module contains derived utilities taken from the MIST framework,
|
||||
-- which are excellent tools to be reused in an OO environment!.
|
||||
--
|
||||
-- ### Authors:
|
||||
--
|
||||
-- * Grimes : Design & Programming of the MIST framework.
|
||||
--
|
||||
-- ### Contributions:
|
||||
--
|
||||
-- * FlightControl : Rework to OO framework
|
||||
--
|
||||
-- @module Utils
|
||||
|
||||
|
||||
--- @type SMOKECOLOR
|
||||
-- @field Green
|
||||
-- @field Red
|
||||
-- @field White
|
||||
-- @field Orange
|
||||
-- @field Blue
|
||||
|
||||
SMOKECOLOR = trigger.smokeColor -- #SMOKECOLOR
|
||||
|
||||
--- @type FLARECOLOR
|
||||
-- @field Green
|
||||
-- @field Red
|
||||
-- @field White
|
||||
-- @field Yellow
|
||||
|
||||
FLARECOLOR = trigger.flareColor -- #FLARECOLOR
|
||||
|
||||
--- Utilities static class.
|
||||
-- @type UTILS
|
||||
UTILS = {}
|
||||
|
||||
|
||||
--from http://lua-users.org/wiki/CopyTable
|
||||
UTILS.DeepCopy = function(object)
|
||||
local lookup_table = {}
|
||||
local function _copy(object)
|
||||
if type(object) ~= "table" then
|
||||
return object
|
||||
elseif lookup_table[object] then
|
||||
return lookup_table[object]
|
||||
end
|
||||
local new_table = {}
|
||||
lookup_table[object] = new_table
|
||||
for index, value in pairs(object) do
|
||||
new_table[_copy(index)] = _copy(value)
|
||||
end
|
||||
return setmetatable(new_table, getmetatable(object))
|
||||
end
|
||||
local objectreturn = _copy(object)
|
||||
return objectreturn
|
||||
end
|
||||
|
||||
|
||||
-- porting in Slmod's serialize_slmod2
|
||||
UTILS.OneLineSerialize = function( tbl ) -- serialization of a table all on a single line, no comments, made to replace old get_table_string function
|
||||
|
||||
lookup_table = {}
|
||||
|
||||
local function _Serialize( tbl )
|
||||
|
||||
if type(tbl) == 'table' then --function only works for tables!
|
||||
|
||||
if lookup_table[tbl] then
|
||||
return lookup_table[object]
|
||||
end
|
||||
|
||||
local tbl_str = {}
|
||||
|
||||
lookup_table[tbl] = tbl_str
|
||||
|
||||
tbl_str[#tbl_str + 1] = '{'
|
||||
|
||||
for ind,val in pairs(tbl) do -- serialize its fields
|
||||
local ind_str = {}
|
||||
if type(ind) == "number" then
|
||||
ind_str[#ind_str + 1] = '['
|
||||
ind_str[#ind_str + 1] = tostring(ind)
|
||||
ind_str[#ind_str + 1] = ']='
|
||||
else --must be a string
|
||||
ind_str[#ind_str + 1] = '['
|
||||
ind_str[#ind_str + 1] = routines.utils.basicSerialize(ind)
|
||||
ind_str[#ind_str + 1] = ']='
|
||||
end
|
||||
|
||||
local val_str = {}
|
||||
if ((type(val) == 'number') or (type(val) == 'boolean')) then
|
||||
val_str[#val_str + 1] = tostring(val)
|
||||
val_str[#val_str + 1] = ','
|
||||
tbl_str[#tbl_str + 1] = table.concat(ind_str)
|
||||
tbl_str[#tbl_str + 1] = table.concat(val_str)
|
||||
elseif type(val) == 'string' then
|
||||
val_str[#val_str + 1] = routines.utils.basicSerialize(val)
|
||||
val_str[#val_str + 1] = ','
|
||||
tbl_str[#tbl_str + 1] = table.concat(ind_str)
|
||||
tbl_str[#tbl_str + 1] = table.concat(val_str)
|
||||
elseif type(val) == 'nil' then -- won't ever happen, right?
|
||||
val_str[#val_str + 1] = 'nil,'
|
||||
tbl_str[#tbl_str + 1] = table.concat(ind_str)
|
||||
tbl_str[#tbl_str + 1] = table.concat(val_str)
|
||||
elseif type(val) == 'table' then
|
||||
if ind == "__index" then
|
||||
-- tbl_str[#tbl_str + 1] = "__index"
|
||||
-- tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it
|
||||
else
|
||||
|
||||
val_str[#val_str + 1] = _Serialize(val)
|
||||
val_str[#val_str + 1] = ',' --I think this is right, I just added it
|
||||
tbl_str[#tbl_str + 1] = table.concat(ind_str)
|
||||
tbl_str[#tbl_str + 1] = table.concat(val_str)
|
||||
end
|
||||
elseif type(val) == 'function' then
|
||||
-- tbl_str[#tbl_str + 1] = "function " .. tostring(ind)
|
||||
-- tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it
|
||||
else
|
||||
-- env.info('unable to serialize value type ' .. routines.utils.basicSerialize(type(val)) .. ' at index ' .. tostring(ind))
|
||||
-- env.info( debug.traceback() )
|
||||
end
|
||||
|
||||
end
|
||||
tbl_str[#tbl_str + 1] = '}'
|
||||
return table.concat(tbl_str)
|
||||
else
|
||||
return tostring(tbl)
|
||||
end
|
||||
end
|
||||
|
||||
local objectreturn = _Serialize(tbl)
|
||||
return objectreturn
|
||||
end
|
||||
|
||||
--porting in Slmod's "safestring" basic serialize
|
||||
UTILS.BasicSerialize = function(s)
|
||||
if s == nil then
|
||||
return "\"\""
|
||||
else
|
||||
if ((type(s) == 'number') or (type(s) == 'boolean') or (type(s) == 'function') or (type(s) == 'table') or (type(s) == 'userdata') ) then
|
||||
return tostring(s)
|
||||
elseif type(s) == 'string' then
|
||||
s = string.format('%q', s)
|
||||
return s
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
UTILS.ToDegree = function(angle)
|
||||
return angle*180/math.pi
|
||||
end
|
||||
|
||||
UTILS.ToRadian = function(angle)
|
||||
return angle*math.pi/180
|
||||
end
|
||||
|
||||
UTILS.MetersToNM = function(meters)
|
||||
return meters/1852
|
||||
end
|
||||
|
||||
UTILS.MetersToFeet = function(meters)
|
||||
return meters/0.3048
|
||||
end
|
||||
|
||||
UTILS.NMToMeters = function(NM)
|
||||
return NM*1852
|
||||
end
|
||||
|
||||
UTILS.FeetToMeters = function(feet)
|
||||
return feet*0.3048
|
||||
end
|
||||
|
||||
UTILS.MpsToKnots = function(mps)
|
||||
return mps*3600/1852
|
||||
end
|
||||
|
||||
UTILS.MpsToKmph = function(mps)
|
||||
return mps*3.6
|
||||
end
|
||||
|
||||
UTILS.KnotsToMps = function(knots)
|
||||
return knots*1852/3600
|
||||
end
|
||||
|
||||
UTILS.KmphToMps = function(kmph)
|
||||
return kmph/3.6
|
||||
end
|
||||
|
||||
--[[acc:
|
||||
in DM: decimal point of minutes.
|
||||
In DMS: decimal point of seconds.
|
||||
position after the decimal of the least significant digit:
|
||||
So:
|
||||
42.32 - acc of 2.
|
||||
]]
|
||||
UTILS.tostringLL = function( lat, lon, acc, DMS)
|
||||
|
||||
local latHemi, lonHemi
|
||||
if lat > 0 then
|
||||
latHemi = 'N'
|
||||
else
|
||||
latHemi = 'S'
|
||||
end
|
||||
|
||||
if lon > 0 then
|
||||
lonHemi = 'E'
|
||||
else
|
||||
lonHemi = 'W'
|
||||
end
|
||||
|
||||
lat = math.abs(lat)
|
||||
lon = math.abs(lon)
|
||||
|
||||
local latDeg = math.floor(lat)
|
||||
local latMin = (lat - latDeg)*60
|
||||
|
||||
local lonDeg = math.floor(lon)
|
||||
local lonMin = (lon - lonDeg)*60
|
||||
|
||||
if DMS then -- degrees, minutes, and seconds.
|
||||
local oldLatMin = latMin
|
||||
latMin = math.floor(latMin)
|
||||
local latSec = UTILS.Round((oldLatMin - latMin)*60, acc)
|
||||
|
||||
local oldLonMin = lonMin
|
||||
lonMin = math.floor(lonMin)
|
||||
local lonSec = UTILS.Round((oldLonMin - lonMin)*60, acc)
|
||||
|
||||
if latSec == 60 then
|
||||
latSec = 0
|
||||
latMin = latMin + 1
|
||||
end
|
||||
|
||||
if lonSec == 60 then
|
||||
lonSec = 0
|
||||
lonMin = lonMin + 1
|
||||
end
|
||||
|
||||
local secFrmtStr -- create the formatting string for the seconds place
|
||||
if acc <= 0 then -- no decimal place.
|
||||
secFrmtStr = '%02d'
|
||||
else
|
||||
local width = 3 + acc -- 01.310 - that's a width of 6, for example.
|
||||
secFrmtStr = '%0' .. width .. '.' .. acc .. 'f'
|
||||
end
|
||||
|
||||
return string.format('%02d', latDeg) .. ' ' .. string.format('%02d', latMin) .. '\' ' .. string.format(secFrmtStr, latSec) .. '"' .. latHemi .. ' '
|
||||
.. string.format('%02d', lonDeg) .. ' ' .. string.format('%02d', lonMin) .. '\' ' .. string.format(secFrmtStr, lonSec) .. '"' .. lonHemi
|
||||
|
||||
else -- degrees, decimal minutes.
|
||||
latMin = UTILS.Round(latMin, acc)
|
||||
lonMin = UTILS.Round(lonMin, acc)
|
||||
|
||||
if latMin == 60 then
|
||||
latMin = 0
|
||||
latDeg = latDeg + 1
|
||||
end
|
||||
|
||||
if lonMin == 60 then
|
||||
lonMin = 0
|
||||
lonDeg = lonDeg + 1
|
||||
end
|
||||
|
||||
local minFrmtStr -- create the formatting string for the minutes place
|
||||
if acc <= 0 then -- no decimal place.
|
||||
minFrmtStr = '%02d'
|
||||
else
|
||||
local width = 3 + acc -- 01.310 - that's a width of 6, for example.
|
||||
minFrmtStr = '%0' .. width .. '.' .. acc .. 'f'
|
||||
end
|
||||
|
||||
return string.format('%02d', latDeg) .. ' ' .. string.format(minFrmtStr, latMin) .. '\'' .. latHemi .. ' '
|
||||
.. string.format('%02d', lonDeg) .. ' ' .. string.format(minFrmtStr, lonMin) .. '\'' .. lonHemi
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- From http://lua-users.org/wiki/SimpleRound
|
||||
-- use negative idp for rounding ahead of decimal place, positive for rounding after decimal place
|
||||
function UTILS.Round( num, idp )
|
||||
local mult = 10 ^ ( idp or 0 )
|
||||
return math.floor( num * mult + 0.5 ) / mult
|
||||
end
|
||||
|
||||
-- porting in Slmod's dostring
|
||||
function UTILS.DoString( s )
|
||||
local f, err = loadstring( s )
|
||||
if f then
|
||||
return true, f()
|
||||
else
|
||||
return false, err
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user