mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
#Changes from Develop
This commit is contained in:
@@ -509,7 +509,7 @@ ENUMS.ReportingName =
|
||||
Atlas = "A400",
|
||||
Lancer = "B1-B",
|
||||
Stratofortress = "B-52H",
|
||||
Hercules = "C-130",
|
||||
Hercules = "C-130",
|
||||
Super_Hercules = "Hercules",
|
||||
Globemaster = "C-17",
|
||||
Greyhound = "C-2A",
|
||||
|
||||
@@ -20,11 +20,11 @@ do
|
||||
-- @type FIFO
|
||||
-- @field #string ClassName Name of the class.
|
||||
-- @field #string lid Class id string for output to DCS log file.
|
||||
-- @field #string version Version of FiFo
|
||||
-- @field #number counter
|
||||
-- @field #number pointer
|
||||
-- @field #table stackbypointer
|
||||
-- @field #table stackbyid
|
||||
-- @field #string version Version of FiFo.
|
||||
-- @field #number counter Counter.
|
||||
-- @field #number pointer Pointer.
|
||||
-- @field #table stackbypointer Stack by pointer.
|
||||
-- @field #table stackbyid Stack by ID.
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
---
|
||||
@@ -45,12 +45,12 @@ FIFO = {
|
||||
stackbyid = {}
|
||||
}
|
||||
|
||||
--- Instantiate a new FIFO Stack
|
||||
--- Instantiate a new FIFO Stack.
|
||||
-- @param #FIFO self
|
||||
-- @return #FIFO self
|
||||
function FIFO:New()
|
||||
-- Inherit everything from BASE class.
|
||||
local self=BASE:Inherit(self, BASE:New())
|
||||
local self=BASE:Inherit(self, BASE:New()) --#FIFO
|
||||
self.pointer = 0
|
||||
self.counter = 0
|
||||
self.stackbypointer = {}
|
||||
@@ -62,7 +62,7 @@ function FIFO:New()
|
||||
return self
|
||||
end
|
||||
|
||||
--- Empty FIFO Stack
|
||||
--- Empty FIFO Stack.
|
||||
-- @param #FIFO self
|
||||
-- @return #FIFO self
|
||||
function FIFO:Clear()
|
||||
@@ -77,7 +77,7 @@ function FIFO:Clear()
|
||||
return self
|
||||
end
|
||||
|
||||
--- FIFO Push Object to Stack
|
||||
--- FIFO Push Object to Stack.
|
||||
-- @param #FIFO self
|
||||
-- @param #table Object
|
||||
-- @param #string UniqueID (optional) - will default to current pointer + 1. Note - if you intend to use `FIFO:GetIDStackSorted()` keep the UniqueID numerical!
|
||||
@@ -97,7 +97,7 @@ function FIFO:Push(Object,UniqueID)
|
||||
return self
|
||||
end
|
||||
|
||||
--- FIFO Pull Object from Stack
|
||||
--- FIFO Pull Object from Stack.
|
||||
-- @param #FIFO self
|
||||
-- @return #table Object or nil if stack is empty
|
||||
function FIFO:Pull()
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
-- ### Author: **TAW CougarNL**, *funkyfranky*
|
||||
--
|
||||
-- @module Utilities.PROFILER
|
||||
-- @image MOOSE.JPG
|
||||
-- @image Utils_Profiler.jpg
|
||||
|
||||
--- PROFILER class.
|
||||
-- @type PROFILER
|
||||
@@ -24,7 +24,8 @@
|
||||
-- @field #number ThreshTtot Total time threshold. Only write output if total function CPU time is more than this value.
|
||||
-- @field #string fileNamePrefix Output file name prefix, e.g. "MooseProfiler".
|
||||
-- @field #string fileNameSuffix Output file name prefix, e.g. "txt"
|
||||
--- *The emperor counsels simplicity. First principles. Of each particular thing, ask: What is it in itself, in its own constitution? What is its causal nature? *
|
||||
|
||||
--- *The emperor counsels simplicity.* *First principles. Of each particular thing, ask: What is it in itself, in its own constitution? What is its causal nature?*
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -33,11 +34,24 @@
|
||||
-- # The PROFILER Concept
|
||||
--
|
||||
-- Profile your lua code. This tells you, which functions are called very often and which consume most real time.
|
||||
-- With this information you can optimize the performance of your code.
|
||||
-- With this information you can optimize the perfomance of your code.
|
||||
--
|
||||
-- # Prerequisites
|
||||
--
|
||||
-- The modules **os** and **lfs** need to be de-sanitized.
|
||||
-- The modules **os**, **io** and **lfs** need to be desanizied. Comment out the lines
|
||||
--
|
||||
-- --sanitizeModule('os')
|
||||
-- --sanitizeModule('io')
|
||||
-- --sanitizeModule('lfs')
|
||||
--
|
||||
-- in your *"DCS World OpenBeta/Scripts/MissionScripting.lua"* file.
|
||||
--
|
||||
-- But be aware that these changes can make you system vulnerable to attacks.
|
||||
--
|
||||
-- # Disclaimer
|
||||
--
|
||||
-- **Profiling itself is CPU expensive!** Don't use this when you want to fly or host a mission.
|
||||
--
|
||||
--
|
||||
-- # Start
|
||||
--
|
||||
@@ -123,12 +137,12 @@ function PROFILER.Start( Delay, Duration )
|
||||
go = false
|
||||
end
|
||||
if not io then
|
||||
env.error( "ERROR: Profiler needs io to be de-sanitized!" )
|
||||
go = false
|
||||
env.error("ERROR: Profiler needs io to be desanitized!")
|
||||
go=false
|
||||
end
|
||||
if not lfs then
|
||||
env.error( "ERROR: Profiler needs lfs to be de-sanitized!" )
|
||||
go = false
|
||||
env.error("ERROR: Profiler needs lfs to be desanitized!")
|
||||
go=false
|
||||
end
|
||||
if not go then
|
||||
return
|
||||
@@ -139,11 +153,11 @@ function PROFILER.Start( Delay, Duration )
|
||||
else
|
||||
|
||||
-- Set start time.
|
||||
PROFILER.TstartGame = timer.getTime()
|
||||
PROFILER.TstartOS = os.clock()
|
||||
PROFILER.TstartGame=timer.getTime()
|
||||
PROFILER.TstartOS=os.clock()
|
||||
|
||||
-- Add event handler.
|
||||
world.addEventHandler( PROFILER.eventHandler )
|
||||
world.addEventHandler(PROFILER.eventHandler)
|
||||
|
||||
-- Info in log.
|
||||
env.info( '############################ Profiler Started ############################' )
|
||||
@@ -152,18 +166,19 @@ function PROFILER.Start( Delay, Duration )
|
||||
else
|
||||
env.info( string.format( "- Will be stopped when mission ends" ) )
|
||||
end
|
||||
env.info( string.format( "- Calls per second threshold %.3f/sec", PROFILER.ThreshCPS ) )
|
||||
env.info( string.format( "- Total function time threshold %.3f sec", PROFILER.ThreshTtot ) )
|
||||
env.info( string.format( "- Output file \"%s\" in your DCS log file folder", PROFILER.getfilename( PROFILER.fileNameSuffix ) ) )
|
||||
env.info( string.format( "- Output file \"%s\" in CSV format", PROFILER.getfilename( "csv" ) ) )
|
||||
env.info( '###############################################################################' )
|
||||
env.info(string.format("- Calls per second threshold %.3f/sec", PROFILER.ThreshCPS))
|
||||
env.info(string.format("- Total function time threshold %.3f sec", PROFILER.ThreshTtot))
|
||||
env.info(string.format("- Output file \"%s\" in your DCS log file folder", PROFILER.getfilename(PROFILER.fileNameSuffix)))
|
||||
env.info(string.format("- Output file \"%s\" in CSV format", PROFILER.getfilename("csv")))
|
||||
env.info('###############################################################################')
|
||||
|
||||
|
||||
-- Message on screen
|
||||
local duration = Duration or 600
|
||||
trigger.action.outText( "### Profiler running ###", duration )
|
||||
local duration=Duration or 600
|
||||
trigger.action.outText("### Profiler running ###", duration)
|
||||
|
||||
-- Set hook.
|
||||
debug.sethook( PROFILER.hook, "cr" )
|
||||
debug.sethook(PROFILER.hook, "cr")
|
||||
|
||||
-- Auto stop profiler.
|
||||
if Duration then
|
||||
@@ -181,20 +196,29 @@ function PROFILER.Stop( Delay )
|
||||
if Delay and Delay > 0 then
|
||||
|
||||
BASE:ScheduleOnce( Delay, PROFILER.Stop )
|
||||
end
|
||||
end
|
||||
|
||||
function PROFILER.Stop(Delay)
|
||||
|
||||
if Delay and Delay>0 then
|
||||
|
||||
BASE:ScheduleOnce(Delay, PROFILER.Stop)
|
||||
|
||||
else
|
||||
|
||||
-- Remove hook.
|
||||
debug.sethook()
|
||||
|
||||
|
||||
-- Run time game.
|
||||
local runTimeGame = timer.getTime() - PROFILER.TstartGame
|
||||
local runTimeGame=timer.getTime()-PROFILER.TstartGame
|
||||
|
||||
-- Run time real OS.
|
||||
local runTimeOS = os.clock() - PROFILER.TstartOS
|
||||
local runTimeOS=os.clock()-PROFILER.TstartOS
|
||||
|
||||
-- Show info.
|
||||
PROFILER.showInfo( runTimeGame, runTimeOS )
|
||||
PROFILER.showInfo(runTimeGame, runTimeOS)
|
||||
|
||||
end
|
||||
|
||||
@@ -213,34 +237,34 @@ end
|
||||
|
||||
--- Debug hook.
|
||||
-- @param #table event Event.
|
||||
function PROFILER.hook( event )
|
||||
function PROFILER.hook(event)
|
||||
|
||||
local f = debug.getinfo( 2, "f" ).func
|
||||
local f=debug.getinfo(2, "f").func
|
||||
|
||||
if event == 'call' then
|
||||
if event=='call' then
|
||||
|
||||
if PROFILER.Counters[f] == nil then
|
||||
if PROFILER.Counters[f]==nil then
|
||||
|
||||
PROFILER.Counters[f] = 1
|
||||
PROFILER.dInfo[f] = debug.getinfo( 2, "Sn" )
|
||||
PROFILER.Counters[f]=1
|
||||
PROFILER.dInfo[f]=debug.getinfo(2,"Sn")
|
||||
|
||||
if PROFILER.fTimeTotal[f] == nil then
|
||||
PROFILER.fTimeTotal[f] = 0
|
||||
if PROFILER.fTimeTotal[f]==nil then
|
||||
PROFILER.fTimeTotal[f]=0
|
||||
end
|
||||
|
||||
else
|
||||
PROFILER.Counters[f] = PROFILER.Counters[f] + 1
|
||||
end
|
||||
|
||||
if PROFILER.fTime[f] == nil then
|
||||
PROFILER.fTime[f] = os.clock()
|
||||
if PROFILER.fTime[f]==nil then
|
||||
PROFILER.fTime[f]=os.clock()
|
||||
end
|
||||
|
||||
elseif (event == 'return') then
|
||||
elseif (event=='return') then
|
||||
|
||||
if PROFILER.fTime[f] ~= nil then
|
||||
PROFILER.fTimeTotal[f] = PROFILER.fTimeTotal[f] + (os.clock() - PROFILER.fTime[f])
|
||||
PROFILER.fTime[f] = nil
|
||||
if PROFILER.fTime[f]~=nil then
|
||||
PROFILER.fTimeTotal[f]=PROFILER.fTimeTotal[f]+(os.clock()-PROFILER.fTime[f])
|
||||
PROFILER.fTime[f]=nil
|
||||
end
|
||||
|
||||
end
|
||||
@@ -259,9 +283,9 @@ end
|
||||
-- @return #number Function time in seconds.
|
||||
function PROFILER.getData( func )
|
||||
|
||||
local n = PROFILER.dInfo[func]
|
||||
local n=PROFILER.dInfo[func]
|
||||
|
||||
if n.what == "C" then
|
||||
if n.what=="C" then
|
||||
return n.name, "?", "?", PROFILER.fTimeTotal[func]
|
||||
end
|
||||
|
||||
@@ -282,20 +306,20 @@ end
|
||||
function PROFILER.showTable( data, f, runTimeGame )
|
||||
|
||||
-- Loop over data.
|
||||
for i = 1, #data do
|
||||
local t = data[i] -- #PROFILER.Data
|
||||
for i=1, #data do
|
||||
local t=data[i] --#PROFILER.Data
|
||||
|
||||
-- Calls per second.
|
||||
local cps = t.count / runTimeGame
|
||||
local cps=t.count/runTimeGame
|
||||
|
||||
local threshCPS = cps >= PROFILER.ThreshCPS
|
||||
local threshTot = t.tm >= PROFILER.ThreshTtot
|
||||
local threshCPS=cps>=PROFILER.ThreshCPS
|
||||
local threshTot=t.tm>=PROFILER.ThreshTtot
|
||||
|
||||
if threshCPS and threshTot then
|
||||
|
||||
-- Output
|
||||
local text = string.format( "%30s: %8d calls %8.1f/sec - Time Total %8.3f sec (%.3f %%) %5.3f sec/call %s line %s", t.func, t.count, cps, t.tm, t.tm / runTimeGame * 100, t.tm / t.count, tostring( t.src ), tostring( t.line ) )
|
||||
PROFILER._flog( f, text )
|
||||
local text=string.format("%30s: %8d calls %8.1f/sec - Time Total %8.3f sec (%.3f %%) %5.3f sec/call %s line %s", t.func, t.count, cps, t.tm, t.tm/runTimeGame*100, t.tm/t.count, tostring(t.src), tostring(t.line))
|
||||
PROFILER._flog(f, text)
|
||||
|
||||
end
|
||||
end
|
||||
@@ -312,19 +336,19 @@ function PROFILER.printCSV( data, runTimeGame )
|
||||
local g = io.open( file, 'w' )
|
||||
|
||||
-- Header.
|
||||
local text = "Function,Total Calls,Calls per Sec,Total Time,Total in %,Sec per Call,Source File;Line Number,"
|
||||
g:write( text .. "\r\n" )
|
||||
local text="Function,Total Calls,Calls per Sec,Total Time,Total in %,Sec per Call,Source File;Line Number,"
|
||||
g:write(text.."\r\n")
|
||||
|
||||
-- Loop over data.
|
||||
for i = 1, #data do
|
||||
local t = data[i] -- #PROFILER.Data
|
||||
for i=1, #data do
|
||||
local t=data[i] --#PROFILER.Data
|
||||
|
||||
-- Calls per second.
|
||||
local cps = t.count / runTimeGame
|
||||
|
||||
-- Output
|
||||
local txt = string.format( "%s,%d,%.1f,%.3f,%.3f,%.3f,%s,%s,", t.func, t.count, cps, t.tm, t.tm / runTimeGame * 100, t.tm / t.count, tostring( t.src ), tostring( t.line ) )
|
||||
g:write( txt .. "\r\n" )
|
||||
local txt=string.format("%s,%d,%.1f,%.3f,%.3f,%.3f,%s,%s,", t.func, t.count, cps, t.tm, t.tm/runTimeGame*100, t.tm/t.count, tostring(t.src), tostring(t.line))
|
||||
g:write(txt.."\r\n")
|
||||
|
||||
end
|
||||
|
||||
@@ -335,15 +359,15 @@ end
|
||||
--- Write info to output file.
|
||||
-- @param #string ext Extension.
|
||||
-- @return #string File name.
|
||||
function PROFILER.getfilename( ext )
|
||||
function PROFILER.getfilename(ext)
|
||||
|
||||
local dir = lfs.writedir() .. [[Logs\]]
|
||||
local dir=lfs.writedir()..[[Logs\]]
|
||||
|
||||
ext = ext or PROFILER.fileNameSuffix
|
||||
ext=ext or PROFILER.fileNameSuffix
|
||||
|
||||
local file = dir .. PROFILER.fileNamePrefix .. "." .. ext
|
||||
local file=dir..PROFILER.fileNamePrefix.."."..ext
|
||||
|
||||
if not UTILS.FileExists( file ) then
|
||||
if not UTILS.FileExists(file) then
|
||||
return file
|
||||
end
|
||||
|
||||
@@ -365,34 +389,39 @@ end
|
||||
function PROFILER.showInfo( runTimeGame, runTimeOS )
|
||||
|
||||
-- Output file.
|
||||
local file = PROFILER.getfilename( PROFILER.fileNameSuffix )
|
||||
local f = io.open( file, 'w' )
|
||||
local file=PROFILER.getfilename(PROFILER.fileNameSuffix)
|
||||
local f=io.open(file, 'w')
|
||||
|
||||
-- Gather data.
|
||||
local Ttot = 0
|
||||
local Calls = 0
|
||||
local Ttot=0
|
||||
local Calls=0
|
||||
|
||||
local t = {}
|
||||
local t={}
|
||||
|
||||
local tcopy = nil -- #PROFILER.Data
|
||||
local tserialize = nil -- #PROFILER.Data
|
||||
local tforgen = nil -- #PROFILER.Data
|
||||
local tpairs = nil -- #PROFILER.Data
|
||||
local tcopy=nil --#PROFILER.Data
|
||||
local tserialize=nil --#PROFILER.Data
|
||||
local tforgen=nil --#PROFILER.Data
|
||||
local tpairs=nil --#PROFILER.Data
|
||||
|
||||
for func, count in pairs( PROFILER.Counters ) do
|
||||
|
||||
local s, src, line, tm = PROFILER.getData( func )
|
||||
for func, count in pairs(PROFILER.Counters) do
|
||||
|
||||
if PROFILER.logUnknown == true then
|
||||
if s == nil then
|
||||
s = "<Unknown>"
|
||||
end
|
||||
local s,src,line,tm=PROFILER.getData(func)
|
||||
|
||||
if PROFILER.logUnknown==true then
|
||||
if s==nil then s="<Unknown>" end
|
||||
end
|
||||
|
||||
if s ~= nil then
|
||||
if s~=nil then
|
||||
|
||||
-- Profile data.
|
||||
local T = { func = s, src = src, line = line, count = count, tm = tm } -- #PROFILER.Data
|
||||
local T=
|
||||
{ func=s,
|
||||
src=src,
|
||||
line=line,
|
||||
count=count,
|
||||
tm=tm,
|
||||
} --#PROFILER.Data
|
||||
|
||||
-- Collect special cases. Somehow, e.g. "_copy" appears multiple times so we try to gather all data.
|
||||
if s == "_copy" then
|
||||
@@ -406,119 +435,113 @@ function PROFILER.showInfo( runTimeGame, runTimeOS )
|
||||
if tserialize == nil then
|
||||
tserialize = T
|
||||
else
|
||||
tserialize.count = tserialize.count + T.count
|
||||
tserialize.tm = tserialize.tm + T.tm
|
||||
tserialize.count=tserialize.count+T.count
|
||||
tserialize.tm=tserialize.tm+T.tm
|
||||
end
|
||||
elseif s == "(for generator)" then
|
||||
if tforgen == nil then
|
||||
tforgen = T
|
||||
elseif s=="(for generator)" then
|
||||
if tforgen==nil then
|
||||
tforgen=T
|
||||
else
|
||||
tforgen.count = tforgen.count + T.count
|
||||
tforgen.tm = tforgen.tm + T.tm
|
||||
tforgen.count=tforgen.count+T.count
|
||||
tforgen.tm=tforgen.tm+T.tm
|
||||
end
|
||||
elseif s == "pairs" then
|
||||
if tpairs == nil then
|
||||
tpairs = T
|
||||
elseif s=="pairs" then
|
||||
if tpairs==nil then
|
||||
tpairs=T
|
||||
else
|
||||
tpairs.count = tpairs.count + T.count
|
||||
tpairs.tm = tpairs.tm + T.tm
|
||||
tpairs.count=tpairs.count+T.count
|
||||
tpairs.tm=tpairs.tm+T.tm
|
||||
end
|
||||
else
|
||||
table.insert( t, T )
|
||||
end
|
||||
|
||||
-- Total function time.
|
||||
Ttot = Ttot + tm
|
||||
Ttot=Ttot+tm
|
||||
|
||||
-- Total number of calls.
|
||||
Calls = Calls + count
|
||||
Calls=Calls+count
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Add special cases.
|
||||
-- Add special cases.
|
||||
if tcopy then
|
||||
table.insert( t, tcopy )
|
||||
end
|
||||
if tserialize then
|
||||
table.insert( t, tserialize )
|
||||
table.insert(t, tserialize)
|
||||
end
|
||||
if tforgen then
|
||||
table.insert( t, tforgen )
|
||||
end
|
||||
if tpairs then
|
||||
table.insert( t, tpairs )
|
||||
table.insert(t, tpairs)
|
||||
end
|
||||
|
||||
env.info( '############################ Profiler Stopped ############################' )
|
||||
env.info( string.format( "* Runtime Game : %s = %d sec", UTILS.SecondsToClock( runTimeGame, true ), runTimeGame ) )
|
||||
env.info( string.format( "* Runtime Real : %s = %d sec", UTILS.SecondsToClock( runTimeOS, true ), runTimeOS ) )
|
||||
env.info( string.format( "* Function time : %s = %.1f sec (%.1f percent of runtime game)", UTILS.SecondsToClock( Ttot, true ), Ttot, Ttot / runTimeGame * 100 ) )
|
||||
env.info( string.format( "* Total functions : %d", #t ) )
|
||||
env.info( string.format( "* Total func calls : %d", Calls ) )
|
||||
env.info( string.format( "* Writing to file : \"%s\"", file ) )
|
||||
env.info( string.format( "* Writing to file : \"%s\"", PROFILER.getfilename( "csv" ) ) )
|
||||
env.info( "##############################################################################" )
|
||||
env.info('############################ Profiler Stopped ############################')
|
||||
env.info(string.format("* Runtime Game : %s = %d sec", UTILS.SecondsToClock(runTimeGame, true), runTimeGame))
|
||||
env.info(string.format("* Runtime Real : %s = %d sec", UTILS.SecondsToClock(runTimeOS, true), runTimeOS))
|
||||
env.info(string.format("* Function time : %s = %.1f sec (%.1f percent of runtime game)", UTILS.SecondsToClock(Ttot, true), Ttot, Ttot/runTimeGame*100))
|
||||
env.info(string.format("* Total functions : %d", #t))
|
||||
env.info(string.format("* Total func calls : %d", Calls))
|
||||
env.info(string.format("* Writing to file : \"%s\"", file))
|
||||
env.info(string.format("* Writing to file : \"%s\"", PROFILER.getfilename("csv")))
|
||||
env.info("##############################################################################")
|
||||
|
||||
-- Sort by total time.
|
||||
table.sort( t, function( a, b )
|
||||
return a.tm > b.tm
|
||||
end )
|
||||
table.sort(t, function(a,b) return a.tm>b.tm end)
|
||||
|
||||
-- Write data.
|
||||
PROFILER._flog( f, "" )
|
||||
PROFILER._flog( f, "************************************************************************************************************************" )
|
||||
PROFILER._flog( f, "************************************************************************************************************************" )
|
||||
PROFILER._flog( f, "************************************************************************************************************************" )
|
||||
PROFILER._flog( f, "" )
|
||||
PROFILER._flog( f, "-------------------------" )
|
||||
PROFILER._flog( f, "---- Profiler Report ----" )
|
||||
PROFILER._flog( f, "-------------------------" )
|
||||
PROFILER._flog( f, "" )
|
||||
PROFILER._flog( f, string.format( "* Runtime Game : %s = %.1f sec", UTILS.SecondsToClock( runTimeGame, true ), runTimeGame ) )
|
||||
PROFILER._flog( f, string.format( "* Runtime Real : %s = %.1f sec", UTILS.SecondsToClock( runTimeOS, true ), runTimeOS ) )
|
||||
PROFILER._flog( f, string.format( "* Function time : %s = %.1f sec (%.1f %% of runtime game)", UTILS.SecondsToClock( Ttot, true ), Ttot, Ttot / runTimeGame * 100 ) )
|
||||
PROFILER._flog( f, "" )
|
||||
PROFILER._flog( f, string.format( "* Total functions = %d", #t ) )
|
||||
PROFILER._flog( f, string.format( "* Total func calls = %d", Calls ) )
|
||||
PROFILER._flog( f, "" )
|
||||
PROFILER._flog( f, string.format( "* Calls per second threshold = %.3f/sec", PROFILER.ThreshCPS ) )
|
||||
PROFILER._flog( f, string.format( "* Total func time threshold = %.3f sec", PROFILER.ThreshTtot ) )
|
||||
PROFILER._flog( f, "" )
|
||||
PROFILER._flog( f, "************************************************************************************************************************" )
|
||||
PROFILER._flog( f, "" )
|
||||
PROFILER.showTable( t, f, runTimeGame )
|
||||
PROFILER._flog(f,"")
|
||||
PROFILER._flog(f,"************************************************************************************************************************")
|
||||
PROFILER._flog(f,"************************************************************************************************************************")
|
||||
PROFILER._flog(f,"************************************************************************************************************************")
|
||||
PROFILER._flog(f,"")
|
||||
PROFILER._flog(f,"-------------------------")
|
||||
PROFILER._flog(f,"---- Profiler Report ----")
|
||||
PROFILER._flog(f,"-------------------------")
|
||||
PROFILER._flog(f,"")
|
||||
PROFILER._flog(f,string.format("* Runtime Game : %s = %.1f sec", UTILS.SecondsToClock(runTimeGame, true), runTimeGame))
|
||||
PROFILER._flog(f,string.format("* Runtime Real : %s = %.1f sec", UTILS.SecondsToClock(runTimeOS, true), runTimeOS))
|
||||
PROFILER._flog(f,string.format("* Function time : %s = %.1f sec (%.1f %% of runtime game)", UTILS.SecondsToClock(Ttot, true), Ttot, Ttot/runTimeGame*100))
|
||||
PROFILER._flog(f,"")
|
||||
PROFILER._flog(f,string.format("* Total functions = %d", #t))
|
||||
PROFILER._flog(f,string.format("* Total func calls = %d", Calls))
|
||||
PROFILER._flog(f,"")
|
||||
PROFILER._flog(f,string.format("* Calls per second threshold = %.3f/sec", PROFILER.ThreshCPS))
|
||||
PROFILER._flog(f,string.format("* Total func time threshold = %.3f sec", PROFILER.ThreshTtot))
|
||||
PROFILER._flog(f,"")
|
||||
PROFILER._flog(f,"************************************************************************************************************************")
|
||||
PROFILER._flog(f,"")
|
||||
PROFILER.showTable(t, f, runTimeGame)
|
||||
|
||||
-- Sort by number of calls.
|
||||
table.sort( t, function( a, b )
|
||||
return a.tm / a.count > b.tm / b.count
|
||||
end )
|
||||
table.sort(t, function(a,b) return a.tm/a.count>b.tm/b.count end)
|
||||
|
||||
-- Detailed data.
|
||||
PROFILER._flog( f, "" )
|
||||
PROFILER._flog( f, "************************************************************************************************************************" )
|
||||
PROFILER._flog( f, "" )
|
||||
PROFILER._flog( f, "--------------------------------------" )
|
||||
PROFILER._flog( f, "---- Data Sorted by Time per Call ----" )
|
||||
PROFILER._flog( f, "--------------------------------------" )
|
||||
PROFILER._flog( f, "" )
|
||||
PROFILER.showTable( t, f, runTimeGame )
|
||||
PROFILER._flog(f,"")
|
||||
PROFILER._flog(f,"************************************************************************************************************************")
|
||||
PROFILER._flog(f,"")
|
||||
PROFILER._flog(f,"--------------------------------------")
|
||||
PROFILER._flog(f,"---- Data Sorted by Time per Call ----")
|
||||
PROFILER._flog(f,"--------------------------------------")
|
||||
PROFILER._flog(f,"")
|
||||
PROFILER.showTable(t, f, runTimeGame)
|
||||
|
||||
-- Sort by number of calls.
|
||||
table.sort( t, function( a, b )
|
||||
return a.count > b.count
|
||||
end )
|
||||
table.sort(t, function(a,b) return a.count>b.count end)
|
||||
|
||||
-- Detailed data.
|
||||
PROFILER._flog( f, "" )
|
||||
PROFILER._flog( f, "************************************************************************************************************************" )
|
||||
PROFILER._flog( f, "" )
|
||||
PROFILER._flog( f, "------------------------------------" )
|
||||
PROFILER._flog( f, "---- Data Sorted by Total Calls ----" )
|
||||
PROFILER._flog( f, "------------------------------------" )
|
||||
PROFILER._flog( f, "" )
|
||||
PROFILER.showTable( t, f, runTimeGame )
|
||||
PROFILER._flog(f,"")
|
||||
PROFILER._flog(f,"************************************************************************************************************************")
|
||||
PROFILER._flog(f,"")
|
||||
PROFILER._flog(f,"------------------------------------")
|
||||
PROFILER._flog(f,"---- Data Sorted by Total Calls ----")
|
||||
PROFILER._flog(f,"------------------------------------")
|
||||
PROFILER._flog(f,"")
|
||||
PROFILER.showTable(t, f, runTimeGame)
|
||||
|
||||
-- Closing.
|
||||
PROFILER._flog( f, "" )
|
||||
|
||||
@@ -494,330 +494,343 @@ routines.ground = {}
|
||||
routines.fixedWing = {}
|
||||
routines.heli = {}
|
||||
|
||||
routines.ground.buildWP = function( point, overRideForm, overRideSpeed )
|
||||
routines.ground.buildWP = function(point, overRideForm, overRideSpeed)
|
||||
|
||||
local wp = {}
|
||||
wp.x = point.x
|
||||
local wp = {}
|
||||
wp.x = point.x
|
||||
|
||||
if point.z then
|
||||
wp.y = point.z
|
||||
else
|
||||
wp.y = point.y
|
||||
end
|
||||
local form, speed
|
||||
if point.z then
|
||||
wp.y = point.z
|
||||
else
|
||||
wp.y = point.y
|
||||
end
|
||||
local form, speed
|
||||
|
||||
if point.speed and not overRideSpeed then
|
||||
wp.speed = point.speed
|
||||
elseif type( overRideSpeed ) == 'number' then
|
||||
wp.speed = overRideSpeed
|
||||
else
|
||||
wp.speed = routines.utils.kmphToMps( 20 )
|
||||
end
|
||||
if point.speed and not overRideSpeed then
|
||||
wp.speed = point.speed
|
||||
elseif type(overRideSpeed) == 'number' then
|
||||
wp.speed = overRideSpeed
|
||||
else
|
||||
wp.speed = routines.utils.kmphToMps(20)
|
||||
end
|
||||
|
||||
if point.form and not overRideForm then
|
||||
form = point.form
|
||||
else
|
||||
form = overRideForm
|
||||
end
|
||||
if point.form and not overRideForm then
|
||||
form = point.form
|
||||
else
|
||||
form = overRideForm
|
||||
end
|
||||
|
||||
if not form then
|
||||
wp.action = 'Cone'
|
||||
else
|
||||
form = string.lower( form )
|
||||
if form == 'off_road' or form == 'off road' then
|
||||
wp.action = 'Off Road'
|
||||
elseif form == 'on_road' or form == 'on road' then
|
||||
wp.action = 'On Road'
|
||||
elseif form == 'rank' or form == 'line_abrest' or form == 'line abrest' or form == 'lineabrest' then
|
||||
wp.action = 'Rank'
|
||||
elseif form == 'cone' then
|
||||
wp.action = 'Cone'
|
||||
elseif form == 'diamond' then
|
||||
wp.action = 'Diamond'
|
||||
elseif form == 'vee' then
|
||||
wp.action = 'Vee'
|
||||
elseif form == 'echelon_left' or form == 'echelon left' or form == 'echelonl' then
|
||||
wp.action = 'EchelonL'
|
||||
elseif form == 'echelon_right' or form == 'echelon right' or form == 'echelonr' then
|
||||
wp.action = 'EchelonR'
|
||||
else
|
||||
wp.action = 'Cone' -- if nothing matched
|
||||
end
|
||||
end
|
||||
if not form then
|
||||
wp.action = 'Cone'
|
||||
else
|
||||
form = string.lower(form)
|
||||
if form == 'off_road' or form == 'off road' then
|
||||
wp.action = 'Off Road'
|
||||
elseif form == 'on_road' or form == 'on road' then
|
||||
wp.action = 'On Road'
|
||||
elseif form == 'rank' or form == 'line_abrest' or form == 'line abrest' or form == 'lineabrest'then
|
||||
wp.action = 'Rank'
|
||||
elseif form == 'cone' then
|
||||
wp.action = 'Cone'
|
||||
elseif form == 'diamond' then
|
||||
wp.action = 'Diamond'
|
||||
elseif form == 'vee' then
|
||||
wp.action = 'Vee'
|
||||
elseif form == 'echelon_left' or form == 'echelon left' or form == 'echelonl' then
|
||||
wp.action = 'EchelonL'
|
||||
elseif form == 'echelon_right' or form == 'echelon right' or form == 'echelonr' then
|
||||
wp.action = 'EchelonR'
|
||||
else
|
||||
wp.action = 'Cone' -- if nothing matched
|
||||
end
|
||||
end
|
||||
|
||||
wp.type = 'Turning Point'
|
||||
|
||||
return wp
|
||||
|
||||
wp.type = 'Turning Point'
|
||||
return wp
|
||||
end
|
||||
|
||||
routines.fixedWing.buildWP = function( point, WPtype, speed, alt, altType )
|
||||
routines.fixedWing.buildWP = function(point, WPtype, speed, alt, altType)
|
||||
|
||||
local wp = {}
|
||||
wp.x = point.x
|
||||
local wp = {}
|
||||
wp.x = point.x
|
||||
|
||||
if point.z then
|
||||
wp.y = point.z
|
||||
else
|
||||
wp.y = point.y
|
||||
end
|
||||
if point.z then
|
||||
wp.y = point.z
|
||||
else
|
||||
wp.y = point.y
|
||||
end
|
||||
|
||||
if alt and type( alt ) == 'number' then
|
||||
wp.alt = alt
|
||||
else
|
||||
wp.alt = 2000
|
||||
end
|
||||
if alt and type(alt) == 'number' then
|
||||
wp.alt = alt
|
||||
else
|
||||
wp.alt = 2000
|
||||
end
|
||||
|
||||
if altType then
|
||||
altType = string.lower( altType )
|
||||
if altType == 'radio' or 'agl' then
|
||||
wp.alt_type = 'RADIO'
|
||||
elseif altType == 'baro' or 'asl' then
|
||||
wp.alt_type = 'BARO'
|
||||
end
|
||||
else
|
||||
wp.alt_type = 'RADIO'
|
||||
end
|
||||
if altType then
|
||||
altType = string.lower(altType)
|
||||
if altType == 'radio' or 'agl' then
|
||||
wp.alt_type = 'RADIO'
|
||||
elseif altType == 'baro' or 'asl' then
|
||||
wp.alt_type = 'BARO'
|
||||
end
|
||||
else
|
||||
wp.alt_type = 'RADIO'
|
||||
end
|
||||
|
||||
if point.speed then
|
||||
speed = point.speed
|
||||
end
|
||||
if point.speed then
|
||||
speed = point.speed
|
||||
end
|
||||
|
||||
if point.type then
|
||||
WPtype = point.type
|
||||
end
|
||||
if point.type then
|
||||
WPtype = point.type
|
||||
end
|
||||
|
||||
if not speed then
|
||||
wp.speed = routines.utils.kmphToMps( 500 )
|
||||
else
|
||||
wp.speed = speed
|
||||
end
|
||||
if not speed then
|
||||
wp.speed = routines.utils.kmphToMps(500)
|
||||
else
|
||||
wp.speed = speed
|
||||
end
|
||||
|
||||
if not WPtype then
|
||||
wp.action = 'Turning Point'
|
||||
else
|
||||
WPtype = string.lower( WPtype )
|
||||
if WPtype == 'flyover' or WPtype == 'fly over' or WPtype == 'fly_over' then
|
||||
wp.action = 'Fly Over Point'
|
||||
elseif WPtype == 'turningpoint' or WPtype == 'turning point' or WPtype == 'turning_point' then
|
||||
wp.action = 'Turning Point'
|
||||
else
|
||||
wp.action = 'Turning Point'
|
||||
end
|
||||
end
|
||||
if not WPtype then
|
||||
wp.action = 'Turning Point'
|
||||
else
|
||||
WPtype = string.lower(WPtype)
|
||||
if WPtype == 'flyover' or WPtype == 'fly over' or WPtype == 'fly_over' then
|
||||
wp.action = 'Fly Over Point'
|
||||
elseif WPtype == 'turningpoint' or WPtype == 'turning point' or WPtype == 'turning_point' then
|
||||
wp.action = 'Turning Point'
|
||||
else
|
||||
wp.action = 'Turning Point'
|
||||
end
|
||||
end
|
||||
|
||||
wp.type = 'Turning Point'
|
||||
return wp
|
||||
wp.type = 'Turning Point'
|
||||
return wp
|
||||
end
|
||||
|
||||
routines.heli.buildWP = function( point, WPtype, speed, alt, altType )
|
||||
routines.heli.buildWP = function(point, WPtype, speed, alt, altType)
|
||||
|
||||
local wp = {}
|
||||
wp.x = point.x
|
||||
local wp = {}
|
||||
wp.x = point.x
|
||||
|
||||
if point.z then
|
||||
wp.y = point.z
|
||||
else
|
||||
wp.y = point.y
|
||||
end
|
||||
if point.z then
|
||||
wp.y = point.z
|
||||
else
|
||||
wp.y = point.y
|
||||
end
|
||||
|
||||
if alt and type( alt ) == 'number' then
|
||||
wp.alt = alt
|
||||
else
|
||||
wp.alt = 500
|
||||
end
|
||||
if alt and type(alt) == 'number' then
|
||||
wp.alt = alt
|
||||
else
|
||||
wp.alt = 500
|
||||
end
|
||||
|
||||
if altType then
|
||||
altType = string.lower( altType )
|
||||
if altType == 'radio' or 'agl' then
|
||||
wp.alt_type = 'RADIO'
|
||||
elseif altType == 'baro' or 'asl' then
|
||||
wp.alt_type = 'BARO'
|
||||
end
|
||||
else
|
||||
wp.alt_type = 'RADIO'
|
||||
end
|
||||
if altType then
|
||||
altType = string.lower(altType)
|
||||
if altType == 'radio' or 'agl' then
|
||||
wp.alt_type = 'RADIO'
|
||||
elseif altType == 'baro' or 'asl' then
|
||||
wp.alt_type = 'BARO'
|
||||
end
|
||||
else
|
||||
wp.alt_type = 'RADIO'
|
||||
end
|
||||
|
||||
if point.speed then
|
||||
speed = point.speed
|
||||
end
|
||||
if point.speed then
|
||||
speed = point.speed
|
||||
end
|
||||
|
||||
if point.type then
|
||||
WPtype = point.type
|
||||
end
|
||||
if point.type then
|
||||
WPtype = point.type
|
||||
end
|
||||
|
||||
if not speed then
|
||||
wp.speed = routines.utils.kmphToMps( 200 )
|
||||
else
|
||||
wp.speed = speed
|
||||
end
|
||||
if not speed then
|
||||
wp.speed = routines.utils.kmphToMps(200)
|
||||
else
|
||||
wp.speed = speed
|
||||
end
|
||||
|
||||
if not WPtype then
|
||||
wp.action = 'Turning Point'
|
||||
else
|
||||
WPtype = string.lower( WPtype )
|
||||
if WPtype == 'flyover' or WPtype == 'fly over' or WPtype == 'fly_over' then
|
||||
wp.action = 'Fly Over Point'
|
||||
elseif WPtype == 'turningpoint' or WPtype == 'turning point' or WPtype == 'turning_point' then
|
||||
wp.action = 'Turning Point'
|
||||
else
|
||||
wp.action = 'Turning Point'
|
||||
end
|
||||
end
|
||||
if not WPtype then
|
||||
wp.action = 'Turning Point'
|
||||
else
|
||||
WPtype = string.lower(WPtype)
|
||||
if WPtype == 'flyover' or WPtype == 'fly over' or WPtype == 'fly_over' then
|
||||
wp.action = 'Fly Over Point'
|
||||
elseif WPtype == 'turningpoint' or WPtype == 'turning point' or WPtype == 'turning_point' then
|
||||
wp.action = 'Turning Point'
|
||||
else
|
||||
wp.action = 'Turning Point'
|
||||
end
|
||||
end
|
||||
|
||||
wp.type = 'Turning Point'
|
||||
return wp
|
||||
wp.type = 'Turning Point'
|
||||
return wp
|
||||
end
|
||||
|
||||
routines.groupToRandomPoint = function( vars )
|
||||
local group = vars.group -- Required
|
||||
local point = vars.point -- required
|
||||
local radius = vars.radius or 0
|
||||
local innerRadius = vars.innerRadius
|
||||
local form = vars.form or 'Cone'
|
||||
local heading = vars.heading or math.random() * 2 * math.pi
|
||||
local headingDegrees = vars.headingDegrees
|
||||
local speed = vars.speed or routines.utils.kmphToMps( 20 )
|
||||
routines.groupToRandomPoint = function(vars)
|
||||
local group = vars.group --Required
|
||||
local point = vars.point --required
|
||||
local radius = vars.radius or 0
|
||||
local innerRadius = vars.innerRadius
|
||||
local form = vars.form or 'Cone'
|
||||
local heading = vars.heading or math.random()*2*math.pi
|
||||
local headingDegrees = vars.headingDegrees
|
||||
local speed = vars.speed or routines.utils.kmphToMps(20)
|
||||
|
||||
local useRoads
|
||||
if not vars.disableRoads then
|
||||
useRoads = true
|
||||
else
|
||||
useRoads = false
|
||||
end
|
||||
|
||||
local path = {}
|
||||
local useRoads
|
||||
if not vars.disableRoads then
|
||||
useRoads = true
|
||||
else
|
||||
useRoads = false
|
||||
end
|
||||
|
||||
if headingDegrees then
|
||||
heading = headingDegrees * math.pi / 180
|
||||
end
|
||||
local path = {}
|
||||
|
||||
if heading >= 2 * math.pi then
|
||||
heading = heading - 2 * math.pi
|
||||
end
|
||||
if headingDegrees then
|
||||
heading = headingDegrees*math.pi/180
|
||||
end
|
||||
|
||||
local rndCoord = routines.getRandPointInCircle( point, radius, innerRadius )
|
||||
if heading >= 2*math.pi then
|
||||
heading = heading - 2*math.pi
|
||||
end
|
||||
|
||||
local offset = {}
|
||||
local posStart = routines.getLeadPos( group )
|
||||
local rndCoord = routines.getRandPointInCircle(point, radius, innerRadius)
|
||||
|
||||
offset.x = routines.utils.round( math.sin( heading - (math.pi / 2) ) * 50 + rndCoord.x, 3 )
|
||||
offset.z = routines.utils.round( math.cos( heading + (math.pi / 2) ) * 50 + rndCoord.y, 3 )
|
||||
path[#path + 1] = routines.ground.buildWP( posStart, form, speed )
|
||||
local offset = {}
|
||||
local posStart = routines.getLeadPos(group)
|
||||
|
||||
if useRoads == true and ((point.x - posStart.x) ^ 2 + (point.z - posStart.z) ^ 2) ^ 0.5 > radius * 1.3 then
|
||||
path[#path + 1] = routines.ground.buildWP( { ['x'] = posStart.x + 11, ['z'] = posStart.z + 11 }, 'off_road', speed )
|
||||
path[#path + 1] = routines.ground.buildWP( posStart, 'on_road', speed )
|
||||
path[#path + 1] = routines.ground.buildWP( offset, 'on_road', speed )
|
||||
else
|
||||
path[#path + 1] = routines.ground.buildWP( { ['x'] = posStart.x + 25, ['z'] = posStart.z + 25 }, form, speed )
|
||||
end
|
||||
offset.x = routines.utils.round(math.sin(heading - (math.pi/2)) * 50 + rndCoord.x, 3)
|
||||
offset.z = routines.utils.round(math.cos(heading + (math.pi/2)) * 50 + rndCoord.y, 3)
|
||||
path[#path + 1] = routines.ground.buildWP(posStart, form, speed)
|
||||
|
||||
path[#path + 1] = routines.ground.buildWP( offset, form, speed )
|
||||
path[#path + 1] = routines.ground.buildWP( rndCoord, form, speed )
|
||||
|
||||
routines.goRoute( group, path )
|
||||
if useRoads == true and ((point.x - posStart.x)^2 + (point.z - posStart.z)^2)^0.5 > radius * 1.3 then
|
||||
path[#path + 1] = routines.ground.buildWP({['x'] = posStart.x + 11, ['z'] = posStart.z + 11}, 'off_road', speed)
|
||||
path[#path + 1] = routines.ground.buildWP(posStart, 'on_road', speed)
|
||||
path[#path + 1] = routines.ground.buildWP(offset, 'on_road', speed)
|
||||
else
|
||||
path[#path + 1] = routines.ground.buildWP({['x'] = posStart.x + 25, ['z'] = posStart.z + 25}, form, speed)
|
||||
end
|
||||
|
||||
path[#path + 1] = routines.ground.buildWP(offset, form, speed)
|
||||
path[#path + 1] = routines.ground.buildWP(rndCoord, form, speed)
|
||||
|
||||
routines.goRoute(group, path)
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
routines.groupRandomDistSelf = function( gpData, dist, form, heading, speed )
|
||||
local pos = routines.getLeadPos( gpData )
|
||||
local fakeZone = {}
|
||||
fakeZone.radius = dist or math.random( 300, 1000 )
|
||||
fakeZone.point = { x = pos.x, y, pos.y, z = pos.z }
|
||||
routines.groupToRandomZone( gpData, fakeZone, form, heading, speed )
|
||||
routines.groupRandomDistSelf = function(gpData, dist, form, heading, speed)
|
||||
local pos = routines.getLeadPos(gpData)
|
||||
local fakeZone = {}
|
||||
fakeZone.radius = dist or math.random(300, 1000)
|
||||
fakeZone.point = {x = pos.x, y = pos.y, z = pos.z}
|
||||
routines.groupToRandomZone(gpData, fakeZone, form, heading, speed)
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
routines.groupToRandomZone = function( gpData, zone, form, heading, speed )
|
||||
if type( gpData ) == 'string' then
|
||||
gpData = Group.getByName( gpData )
|
||||
end
|
||||
routines.groupToRandomZone = function(gpData, zone, form, heading, speed)
|
||||
if type(gpData) == 'string' then
|
||||
gpData = Group.getByName(gpData)
|
||||
end
|
||||
|
||||
if type( zone ) == 'string' then
|
||||
zone = trigger.misc.getZone( zone )
|
||||
elseif type( zone ) == 'table' and not zone.radius then
|
||||
zone = trigger.misc.getZone( zone[math.random( 1, #zone )] )
|
||||
end
|
||||
if type(zone) == 'string' then
|
||||
zone = trigger.misc.getZone(zone)
|
||||
elseif type(zone) == 'table' and not zone.radius then
|
||||
zone = trigger.misc.getZone(zone[math.random(1, #zone)])
|
||||
end
|
||||
|
||||
if speed then
|
||||
speed = routines.utils.kmphToMps( speed )
|
||||
end
|
||||
if speed then
|
||||
speed = routines.utils.kmphToMps(speed)
|
||||
end
|
||||
|
||||
local vars = {}
|
||||
vars.group = gpData
|
||||
vars.radius = zone.radius
|
||||
vars.form = form
|
||||
vars.headingDegrees = heading
|
||||
vars.speed = speed
|
||||
vars.point = routines.utils.zoneToVec3( zone )
|
||||
local vars = {}
|
||||
vars.group = gpData
|
||||
vars.radius = zone.radius
|
||||
vars.form = form
|
||||
vars.headingDegrees = heading
|
||||
vars.speed = speed
|
||||
vars.point = routines.utils.zoneToVec3(zone)
|
||||
|
||||
routines.groupToRandomPoint( vars )
|
||||
routines.groupToRandomPoint(vars)
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
routines.isTerrainValid = function( coord, terrainTypes ) -- vec2/3 and enum or table of acceptable terrain types
|
||||
if coord.z then
|
||||
coord.y = coord.z
|
||||
end
|
||||
local typeConverted = {}
|
||||
routines.isTerrainValid = function(coord, terrainTypes) -- vec2/3 and enum or table of acceptable terrain types
|
||||
if coord.z then
|
||||
coord.y = coord.z
|
||||
end
|
||||
local typeConverted = {}
|
||||
|
||||
if type( terrainTypes ) == 'string' then -- if its a string it does this check
|
||||
for constId, constData in pairs( land.SurfaceType ) do
|
||||
if string.lower( constId ) == string.lower( terrainTypes ) or string.lower( constData ) == string.lower( terrainTypes ) then
|
||||
table.insert( typeConverted, constId )
|
||||
end
|
||||
end
|
||||
elseif type( terrainTypes ) == 'table' then -- if its a table it does this check
|
||||
for typeId, typeData in pairs( terrainTypes ) do
|
||||
for constId, constData in pairs( land.SurfaceType ) do
|
||||
if string.lower( constId ) == string.lower( typeData ) or string.lower( constData ) == string.lower( typeId ) then
|
||||
table.insert( typeConverted, constId )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
for validIndex, validData in pairs( typeConverted ) do
|
||||
if land.getSurfaceType( coord ) == land.SurfaceType[validData] then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
if type(terrainTypes) == 'string' then -- if its a string it does this check
|
||||
for constId, constData in pairs(land.SurfaceType) do
|
||||
if string.lower(constId) == string.lower(terrainTypes) or string.lower(constData) == string.lower(terrainTypes) then
|
||||
table.insert(typeConverted, constId)
|
||||
end
|
||||
end
|
||||
elseif type(terrainTypes) == 'table' then -- if its a table it does this check
|
||||
for typeId, typeData in pairs(terrainTypes) do
|
||||
for constId, constData in pairs(land.SurfaceType) do
|
||||
if string.lower(constId) == string.lower(typeData) or string.lower(constData) == string.lower(typeId) then
|
||||
table.insert(typeConverted, constId)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
for validIndex, validData in pairs(typeConverted) do
|
||||
if land.getSurfaceType(coord) == land.SurfaceType[validData] then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
routines.groupToPoint = function( gpData, point, form, heading, speed, useRoads )
|
||||
if type( point ) == 'string' then
|
||||
point = trigger.misc.getZone( point )
|
||||
end
|
||||
if speed then
|
||||
speed = routines.utils.kmphToMps( speed )
|
||||
end
|
||||
routines.groupToPoint = function(gpData, point, form, heading, speed, useRoads)
|
||||
if type(point) == 'string' then
|
||||
point = trigger.misc.getZone(point)
|
||||
end
|
||||
if speed then
|
||||
speed = routines.utils.kmphToMps(speed)
|
||||
end
|
||||
|
||||
local vars = {}
|
||||
vars.group = gpData
|
||||
vars.form = form
|
||||
vars.headingDegrees = heading
|
||||
vars.speed = speed
|
||||
vars.disableRoads = useRoads
|
||||
vars.point = routines.utils.zoneToVec3( point )
|
||||
routines.groupToRandomPoint( vars )
|
||||
local vars = {}
|
||||
vars.group = gpData
|
||||
vars.form = form
|
||||
vars.headingDegrees = heading
|
||||
vars.speed = speed
|
||||
vars.disableRoads = useRoads
|
||||
vars.point = routines.utils.zoneToVec3(point)
|
||||
routines.groupToRandomPoint(vars)
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
routines.getLeadPos = function( group )
|
||||
if type( group ) == 'string' then -- group name
|
||||
group = Group.getByName( group )
|
||||
end
|
||||
|
||||
local units = group:getUnits()
|
||||
routines.getLeadPos = function(group)
|
||||
if type(group) == 'string' then -- group name
|
||||
group = Group.getByName(group)
|
||||
end
|
||||
|
||||
local leader = units[1]
|
||||
if not leader then -- SHOULD be good, but if there is a bug, this code future-proofs it then.
|
||||
local lowestInd = math.huge
|
||||
for ind, unit in pairs( units ) do
|
||||
if ind < lowestInd then
|
||||
lowestInd = ind
|
||||
leader = unit
|
||||
end
|
||||
end
|
||||
end
|
||||
if leader and Unit.isExist( leader ) then -- maybe a little too paranoid now...
|
||||
return leader:getPosition().p
|
||||
end
|
||||
local units = group:getUnits()
|
||||
|
||||
local leader = units[1]
|
||||
if not leader then -- SHOULD be good, but if there is a bug, this code future-proofs it then.
|
||||
local lowestInd = math.huge
|
||||
for ind, unit in pairs(units) do
|
||||
if ind < lowestInd then
|
||||
lowestInd = ind
|
||||
leader = unit
|
||||
end
|
||||
end
|
||||
end
|
||||
if leader and Unit.isExist(leader) then -- maybe a little too paranoid now...
|
||||
return leader:getPosition().p
|
||||
end
|
||||
end
|
||||
|
||||
--[[ vars for routines.getMGRSString:
|
||||
|
||||
@@ -126,8 +126,11 @@ end
|
||||
-- So length of msg / 8.3 = number of seconds needed to read it. rounded down to 8 chars per sec map function:
|
||||
--
|
||||
-- * (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min
|
||||
--
|
||||
function STTS.getSpeechTime( length, speed, isGoogle )
|
||||
--
|
||||
-- @param #number length can also be passed as #string
|
||||
-- @param #number speed Defaults to 1.0
|
||||
-- @param #boolean isGoogle We're using Google TTS
|
||||
function STTS.getSpeechTime(length,speed,isGoogle)
|
||||
|
||||
local maxRateRatio = 3
|
||||
|
||||
@@ -153,7 +156,7 @@ function STTS.getSpeechTime( length, speed, isGoogle )
|
||||
length = string.len( length )
|
||||
end
|
||||
|
||||
return math.ceil( length / cps )
|
||||
return length/cps --math.ceil(length/cps)
|
||||
end
|
||||
|
||||
--- Text to speech function.
|
||||
|
||||
152
Moose Development/Moose/Utilities/Socket.lua
Normal file
152
Moose Development/Moose/Utilities/Socket.lua
Normal file
@@ -0,0 +1,152 @@
|
||||
--- **Utilities** - Socket.
|
||||
--
|
||||
-- **Main Features:**
|
||||
--
|
||||
-- * Creates UDP Sockets
|
||||
-- * Send messages to Discord
|
||||
-- * Compatible with [FunkMan](https://github.com/funkyfranky/FunkMan)
|
||||
-- * Compatible with [DCSServerBot](https://github.com/Special-K-s-Flightsim-Bots/DCSServerBot)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **funkyfranky**
|
||||
-- @module Utilities.Socket
|
||||
-- @image Utilities_Socket.png
|
||||
|
||||
|
||||
--- SOCKET class.
|
||||
-- @type SOCKET
|
||||
-- @field #string ClassName Name of the class.
|
||||
-- @field #number verbose Verbosity level.
|
||||
-- @field #string lid Class id string for output to DCS log file.
|
||||
-- @field #table socket The socket.
|
||||
-- @field #number port The port.
|
||||
-- @field #string host The host.
|
||||
-- @field #table json JSON.
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
--- **At times I feel like a socket that remembers its tooth.** -- Saul Bellow
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- # The SOCKET Concept
|
||||
--
|
||||
-- Create a UDP socket server. It enables you to send messages to discord servers via discord bots.
|
||||
--
|
||||
-- **Note** that you have to **de-sanitize** `require` and `package` in your `MissionScripting.lua` file, which is in your `DCS/Scripts` folder.
|
||||
--
|
||||
--
|
||||
-- @field #SOCKET
|
||||
SOCKET = {
|
||||
ClassName = "SOCKET",
|
||||
verbose = 0,
|
||||
lid = nil,
|
||||
}
|
||||
|
||||
--- Data type. This is the keyword the socket listener uses.
|
||||
-- @field #string TEXT Plain text.
|
||||
-- @field #string BOMBRESULT Range bombing.
|
||||
-- @field #string STRAFERESULT Range strafeing result.
|
||||
-- @field #string LSOGRADE Airboss LSO grade.
|
||||
SOCKET.DataType={
|
||||
TEXT="moose_text",
|
||||
BOMBRESULT="moose_bomb_result",
|
||||
STRAFERESULT="moose_strafe_result",
|
||||
LSOGRADE="moose_lso_grade",
|
||||
}
|
||||
|
||||
|
||||
--- SOCKET class version.
|
||||
-- @field #string version
|
||||
SOCKET.version="0.1.0"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: A lot!
|
||||
-- TODO: Messages as spoiler.
|
||||
-- TODO: Send images?
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Constructor
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Create a new SOCKET object.
|
||||
-- @param #SOCKET self
|
||||
-- @param #number Port UDP port. Default `10042`.
|
||||
-- @param #string Host Host. Default `"127.0.0.1"`.
|
||||
-- @return #SOCKET self
|
||||
function SOCKET:New(Port, Host)
|
||||
|
||||
-- Inherit everything from FSM class.
|
||||
local self=BASE:Inherit(self, FSM:New()) --#SOCKET
|
||||
|
||||
package.path = package.path..";.\\LuaSocket\\?.lua;"
|
||||
package.cpath = package.cpath..";.\\LuaSocket\\?.dll;"
|
||||
|
||||
self.socket = require("socket")
|
||||
|
||||
self.port=Port or 10042
|
||||
self.host=Host or "127.0.0.1"
|
||||
|
||||
self.json=loadfile("Scripts\\JSON.lua")()
|
||||
|
||||
self.UDPSendSocket=self.socket.udp()
|
||||
self.UDPSendSocket:settimeout(0)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set port.
|
||||
-- @param #SOCKET self
|
||||
-- @param #number Port Port. Default 10042.
|
||||
-- @return #SOCKET self
|
||||
function SOCKET:SetPort(Port)
|
||||
self.port=Port or 10042
|
||||
end
|
||||
|
||||
--- Set host.
|
||||
-- @param #SOCKET self
|
||||
-- @param #string Host Host. Default `"127.0.0.1"`.
|
||||
-- @return #SOCKET self
|
||||
function SOCKET:SetHost(Host)
|
||||
self.host=Host or "127.0.0.1"
|
||||
end
|
||||
|
||||
|
||||
--- Send a table.
|
||||
-- @param #SOCKET self
|
||||
-- @param #table Table Table to send.
|
||||
-- @return #SOCKET self
|
||||
function SOCKET:SendTable(Table)
|
||||
|
||||
local json= self.json:encode(Table)
|
||||
|
||||
-- Debug info.
|
||||
self:T("Json table:")
|
||||
self:T(json)
|
||||
|
||||
-- Send data.
|
||||
self.socket.try(self.UDPSendSocket:sendto(json, self.host, self.port))
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Send a text message.
|
||||
-- @param #SOCKET self
|
||||
-- @param #string Text Test message.
|
||||
-- @return #SOCKET self
|
||||
function SOCKET:SendText(Text)
|
||||
|
||||
local message={}
|
||||
|
||||
message.command = SOCKET.DataType.TEXT
|
||||
message.text = Text
|
||||
|
||||
self:SendTable(message)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
@@ -1155,7 +1155,7 @@ function UTILS.VecHdg(a)
|
||||
end
|
||||
|
||||
--- Calculate "heading" of a 2D vector in the X-Y plane.
|
||||
-- @param DCS#Vec2 a Vector in "D with x, y components.
|
||||
-- @param DCS#Vec2 a Vector in 2D with x, y components.
|
||||
-- @return #number Heading in degrees in [0,360).
|
||||
function UTILS.Vec2Hdg(a)
|
||||
local h=math.deg(math.atan2(a.y, a.x))
|
||||
@@ -1724,17 +1724,17 @@ end
|
||||
--- Get OS time. Needs os to be desanitized!
|
||||
-- @return #number Os time in seconds.
|
||||
function UTILS.GetOSTime()
|
||||
if os then
|
||||
local ts = 0
|
||||
local t = os.date("*t")
|
||||
local s = t.sec
|
||||
local m = t.min * 60
|
||||
local h = t.hour * 3600
|
||||
ts = s+m+h
|
||||
return ts
|
||||
else
|
||||
return nil
|
||||
end
|
||||
if os then
|
||||
local ts = 0
|
||||
local t = os.date("*t")
|
||||
local s = t.sec
|
||||
local m = t.min * 60
|
||||
local h = t.hour * 3600
|
||||
ts = s+m+h
|
||||
return ts
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
--- Shuffle a table accoring to Fisher Yeates algorithm
|
||||
|
||||
Reference in New Issue
Block a user