diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index 6bd87bdd8..430542f5e 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -902,7 +902,7 @@ end function DATABASE:_RegisterAirbases() for DCSAirbaseId, DCSAirbase in pairs(world.getAirbases()) do - + -- Get the airbase name. local DCSAirbaseName = DCSAirbase:getName() @@ -914,7 +914,7 @@ function DATABASE:_RegisterAirbases() -- Debug output. self:I(string.format("Register Airbase: %s, getID=%d, GetID=%d (unique=%d)", DCSAirbaseName, DCSAirbase:getID(), airbase:GetID(), airbase:GetID(true))) - + end return self diff --git a/Moose Development/Moose/Utilities/Profiler.lua b/Moose Development/Moose/Utilities/Profiler.lua index a4bce95b5..84e4829b0 100644 --- a/Moose Development/Moose/Utilities/Profiler.lua +++ b/Moose Development/Moose/Utilities/Profiler.lua @@ -5,9 +5,9 @@ -- === -- -- ### Author: **TAW CougarNL**, *funkyfranky* --- +-- -- @module Utilities.PROFILER --- @image MOOSE.JPG +-- @image Utils_Profiler.jpg --- PROFILER class. @@ -26,67 +26,79 @@ -- @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?* -- -- === -- -- ![Banner Image](..\Presentations\Utilities\PROFILER_Main.jpg) -- -- # 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 perfomance of your code. --- +-- -- # Prerequisites --- --- The modules **os** and **lfs** need to be desanizied. --- --- +-- +-- 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 --- +-- -- The profiler can simply be started with the @{#PROFILER.Start}(*Delay, Duration*) function --- +-- -- PROFILER.Start() --- +-- -- The optional parameter *Delay* can be used to delay the start by a certain amount of seconds and the optional parameter *Duration* can be used to -- stop the profiler after a certain amount of seconds. --- +-- -- # Stop --- +-- -- The profiler automatically stops when the mission ends. But it can be stopped any time with the @{#PROFILER.Stop}(*Delay*) function --- +-- -- PROFILER.Stop() --- +-- -- The optional parameter *Delay* can be used to specify a delay after which the profiler is stopped. --- +-- -- When the profiler is stopped, the output is written to a file. --- +-- -- # Output --- +-- -- The profiler output is written to a file in your DCS home folder --- +-- -- X:\User\\Saved Games\DCS OpenBeta\Logs --- +-- -- The default file name is "MooseProfiler.txt". If that file exists, the file name is "MooseProfiler-001.txt" etc. --- +-- -- ## Data --- +-- -- The data in the output file provides information on the functions that were called in the mission. --- +-- -- It will tell you how many times a function was called in total, how many times per second, how much time in total and the percentage of time. --- +-- -- If you only want output for functions that are called more than *X* times per second, you can set --- +-- -- PROFILER.ThreshCPS=1.5 --- +-- -- With this setting, only functions which are called more than 1.5 times per second are displayed. The default setting is PROFILER.ThreshCPS=0.0 (no threshold). --- +-- -- Furthermore, you can limit the output for functions that consumed a certain amount of CPU time in total by --- +-- -- PROFILER.ThreshTtot=0.005 --- +-- -- With this setting, which is also the default, only functions which in total used more than 5 milliseconds CPU time. --- +-- -- @field #PROFILER PROFILER = { ClassName = "PROFILER", @@ -128,11 +140,11 @@ function PROFILER.Start(Delay, Duration) if not io then env.error("ERROR: Profiler needs io to be desanitized!") go=false - end + end if not lfs then env.error("ERROR: Profiler needs lfs to be desanitized!") go=false - end + end if not go then return end @@ -140,14 +152,14 @@ function PROFILER.Start(Delay, Duration) if Delay and Delay>0 then BASE:ScheduleOnce(Delay, PROFILER.Start, 0, Duration) else - + -- Set start time. PROFILER.TstartGame=timer.getTime() PROFILER.TstartOS=os.clock() - + -- Add event handler. world.addEventHandler(PROFILER.eventHandler) - + -- Info in log. env.info('############################ Profiler Started ############################') if Duration then @@ -160,22 +172,22 @@ function PROFILER.Start(Delay, Duration) 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) - + -- Set hook. debug.sethook(PROFILER.hook, "cr") - + -- Auto stop profiler. if Duration then PROFILER.Stop(Duration) end - + end - + end --- Stop profiler. @@ -183,24 +195,24 @@ 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 - + -- Run time real OS. local runTimeOS=os.clock()-PROFILER.TstartOS - + -- Show info. PROFILER.showInfo(runTimeGame, runTimeOS) - + end end @@ -221,35 +233,35 @@ end function PROFILER.hook(event) local f=debug.getinfo(2, "f").func - + if event=='call' then - + if PROFILER.Counters[f]==nil then - + PROFILER.Counters[f]=1 PROFILER.dInfo[f]=debug.getinfo(2,"Sn") - + 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() end - + 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 end - + end - + end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -265,12 +277,12 @@ end function PROFILER.getData(func) local n=PROFILER.dInfo[func] - + if n.what=="C" then return n.name, "?", "?", PROFILER.fTimeTotal[func] end - - return n.name, n.short_src, n.linedefined, PROFILER.fTimeTotal[func] + + return n.name, n.short_src, n.linedefined, PROFILER.fTimeTotal[func] end --- Write text to log file. @@ -287,24 +299,24 @@ end function PROFILER.showTable(data, f, runTimeGame) -- Loop over data. - for i=1, #data do + for i=1, #data do local t=data[i] --#PROFILER.Data - + -- Calls per second. local cps=t.count/runTimeGame - + 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) - + end end - + end --- Print csv file. @@ -319,20 +331,20 @@ function PROFILER.printCSV(data, runTimeGame) -- 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") - + -- Loop over data. - for i=1, #data do + 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") - + end - + -- Close file. g:close() end @@ -344,23 +356,23 @@ end function PROFILER.getfilename(ext) local dir=lfs.writedir()..[[Logs\]] - + ext=ext or PROFILER.fileNameSuffix - + local file=dir..PROFILER.fileNamePrefix.."."..ext - + if not UTILS.FileExists(file) then return file end - + for i=1,999 do - + local file=string.format("%s%s-%03d.%s", dir,PROFILER.fileNamePrefix, i, ext) if not UTILS.FileExists(file) then return file end - + end end @@ -372,30 +384,30 @@ function PROFILER.showInfo(runTimeGame, runTimeOS) -- Output file. local file=PROFILER.getfilename(PROFILER.fileNameSuffix) - local f=io.open(file, 'w') - + local f=io.open(file, 'w') + -- Gather data. local Ttot=0 local Calls=0 - + local t={} - + 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) - + if PROFILER.logUnknown==true then if s==nil then s="" end end - + if s~=nil then - + -- Profile data. local T= { func=s, @@ -404,7 +416,7 @@ function PROFILER.showInfo(runTimeGame, runTimeOS) 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 if tcopy==nil then @@ -419,49 +431,49 @@ function PROFILER.showInfo(runTimeGame, runTimeOS) else tserialize.count=tserialize.count+T.count tserialize.tm=tserialize.tm+T.tm - end + end elseif s=="(for generator)" then if tforgen==nil then tforgen=T else tforgen.count=tforgen.count+T.count tforgen.tm=tforgen.tm+T.tm - end + end elseif s=="pairs" then if tpairs==nil then tpairs=T else tpairs.count=tpairs.count+T.count tpairs.tm=tpairs.tm+T.tm - end + end else table.insert(t, T) end - + -- Total function time. Ttot=Ttot+tm - + -- Total number of calls. 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) - end - + 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)) @@ -470,11 +482,11 @@ function PROFILER.showInfo(runTimeGame, runTimeOS) 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("##############################################################################") + -- Sort by total time. table.sort(t, function(a,b) return a.tm>b.tm end) - + -- Write data. PROFILER._flog(f,"") PROFILER._flog(f,"************************************************************************************************************************") @@ -493,7 +505,7 @@ function PROFILER.showInfo(runTimeGame, runTimeOS) 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,string.format("* Total func time threshold = %.3f sec", PROFILER.ThreshTtot)) PROFILER._flog(f,"") PROFILER._flog(f,"************************************************************************************************************************") PROFILER._flog(f,"") @@ -501,7 +513,7 @@ function PROFILER.showInfo(runTimeGame, runTimeOS) -- Sort by number of calls. table.sort(t, function(a,b) return a.tm/a.count>b.tm/b.count end) - + -- Detailed data. PROFILER._flog(f,"") PROFILER._flog(f,"************************************************************************************************************************") @@ -511,10 +523,10 @@ function PROFILER.showInfo(runTimeGame, runTimeOS) 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) - + -- Detailed data. PROFILER._flog(f,"") PROFILER._flog(f,"************************************************************************************************************************") @@ -524,7 +536,7 @@ function PROFILER.showInfo(runTimeGame, runTimeOS) PROFILER._flog(f,"------------------------------------") PROFILER._flog(f,"") PROFILER.showTable(t, f, runTimeGame) - + -- Closing. PROFILER._flog(f,"") PROFILER._flog(f,"************************************************************************************************************************") @@ -532,8 +544,7 @@ function PROFILER.showInfo(runTimeGame, runTimeOS) PROFILER._flog(f,"************************************************************************************************************************") -- Close file. f:close() - + -- Print csv file. PROFILER.printCSV(t, runTimeGame) end - diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index 3e3d7de16..1c344c896 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -461,19 +461,19 @@ function AIRBASE:Register(AirbaseName) -- Inherit everything from positionable. local self=BASE:Inherit(self, POSITIONABLE:New(AirbaseName)) --#AIRBASE - + -- Set airbase name. self.AirbaseName=AirbaseName - + -- Set airbase ID. self.AirbaseID=self:GetID(true) - + -- Get descriptors. self.descriptors=self:GetDesc() - + -- Category. self.category=self.descriptors and self.descriptors.category or Airbase.Category.AIRDROME - + -- Set category. if self.category==Airbase.Category.AIRDROME then self.isAirdrome=true @@ -484,14 +484,14 @@ function AIRBASE:Register(AirbaseName) else self:E("ERROR: Unknown airbase category!") end - + self:_InitParkingSpots() - + local vec2=self:GetVec2() - + -- Init coordinate. self:GetCoordinate() - + if vec2 then -- TODO: For ships we need a moving zone. self.AirbaseZone=ZONE_RADIUS:New( AirbaseName, vec2, 2500 ) @@ -628,7 +628,7 @@ function AIRBASE:GetID(unique) local airbaseID=tonumber(DCSAirbase:getID()) local airbaseCategory=self:GetAirbaseCategory() - + if AirbaseName==self.AirbaseName then if airbaseCategory==Airbase.Category.SHIP or airbaseCategory==Airbase.Category.HELIPAD then -- Ships get a negative sign as their unit number might be the same as the ID of another airbase. @@ -819,16 +819,16 @@ function AIRBASE:_InitParkingSpots() -- Init table. self.parking={} self.parkingByID={} - + self.NparkingTotal=0 self.NparkingTerminal={} for _,terminalType in pairs(AIRBASE.TerminalType) do self.NparkingTerminal[terminalType]=0 - end + end -- Put coordinates of parking spots into table. for _,spot in pairs(parkingdata) do - + -- New parking spot. local park={} --#AIRBASE.ParkingSpot park.Vec3=spot.vTerminalPos @@ -839,13 +839,13 @@ function AIRBASE:_InitParkingSpots() park.TerminalID0=spot.Term_Index_0 park.TerminalType=spot.Term_Type park.TOAC=spot.TO_AC - + for _,terminalType in pairs(AIRBASE.TerminalType) do if self._CheckTerminalType(terminalType, park.TerminalType) then self.NparkingTerminal[terminalType]=self.NparkingTerminal[terminalType]+1 end - end - + end + self.parkingByID[park.TerminalID]=park table.insert(self.parking, park) end @@ -869,7 +869,7 @@ function AIRBASE:GetParkingSpotsTable(termtype) -- Get parking data of all spots (free or occupied) local parkingdata=self:GetParkingData(false) - + -- Get parking data of all free spots. local parkingfree=self:GetParkingData(true) @@ -886,17 +886,17 @@ function AIRBASE:GetParkingSpotsTable(termtype) -- Put coordinates of parking spots into table. local spots={} for _,_spot in pairs(parkingdata) do - + if AIRBASE._CheckTerminalType(_spot.Term_Type, termtype) then - + local spot=self:_GetParkingSpotByID(_spot.Term_Index) - + spot.Free=_isfree(_spot) -- updated spot.TOAC=_spot.TO_AC -- updated - + table.insert(spots, spot) end - + end return spots @@ -917,14 +917,14 @@ function AIRBASE:GetFreeParkingSpotsTable(termtype, allowTOAC) for _,_spot in pairs(parkingfree) do if AIRBASE._CheckTerminalType(_spot.Term_Type, termtype) and _spot.Term_Index>0 then if (allowTOAC and allowTOAC==true) or _spot.TO_AC==false then - + local spot=self:_GetParkingSpotByID(_spot.Term_Index) spot.Free=true -- updated spot.TOAC=_spot.TO_AC -- updated - + table.insert(freespots, spot) - + end end end @@ -1245,7 +1245,7 @@ function AIRBASE:GetRunwayData(magvar, mark) -- Get spawn points on runway. These can be used to determine the runway heading. local runwaycoords=self:GetParkingSpotsCoordinates(AIRBASE.TerminalType.Runway) - + -- Debug: For finding the numbers of the spawn points belonging to each runway. if false then for i,_coord in pairs(runwaycoords) do @@ -1264,7 +1264,7 @@ function AIRBASE:GetRunwayData(magvar, mark) -- Airbase name. local name=self:GetName() - + -- Exceptions if name==AIRBASE.Nevada.Jean_Airport or @@ -1277,35 +1277,35 @@ function AIRBASE:GetRunwayData(magvar, mark) -- 1-->4, 2-->3, 3-->2, 4-->1 exception=1 - - elseif UTILS.GetDCSMap()==DCSMAP.Syria and N>=2 and + + elseif UTILS.GetDCSMap()==DCSMAP.Syria and N>=2 and name~=AIRBASE.Syria.Minakh and name~=AIRBASE.Syria.Damascus and name~=AIRBASE.Syria.Khalkhalah and name~=AIRBASE.Syria.Marj_Ruhayyil and name~=AIRBASE.Syria.Beirut_Rafic_Hariri then - + -- 1-->3, 2-->4, 3-->1, 4-->2 exception=2 - + end - + local function f(i) local j - + if exception==1 then - + j=N-(i+1) -- 1-->4, 2-->3 - + elseif exception==2 then - + if i<=N2 then j=i+N2 -- 1-->3, 2-->4 else j=i-N2 -- 3-->1, 4-->3 end - + else if i%2==0 then @@ -1313,9 +1313,9 @@ function AIRBASE:GetRunwayData(magvar, mark) else j=i+1 -- odd 1-->2, 3-->4 end - + end - + -- Special case where there is no obvious order. if name==AIRBASE.Syria.Beirut_Rafic_Hariri then if i==1 then @@ -1348,7 +1348,7 @@ function AIRBASE:GetRunwayData(magvar, mark) j=2 end end - + return j end diff --git a/Moose Development/Moose/Wrapper/Marker.lua b/Moose Development/Moose/Wrapper/Marker.lua index 5d65d3fbe..88a868501 100644 --- a/Moose Development/Moose/Wrapper/Marker.lua +++ b/Moose Development/Moose/Wrapper/Marker.lua @@ -1,5 +1,5 @@ --- **Wrapper** - Markers On the F10 map. --- +-- -- **Main Features:** -- -- * Convenient handling of markers via multiple user API functions. @@ -8,7 +8,7 @@ -- * Retrieve data such as text and coordinate. -- * Marker specific FSM events when a marker is added, removed or changed. -- * Additional FSM events when marker text or position is changed. --- +-- -- === -- -- ### Author: **funkyfranky** @@ -36,104 +36,104 @@ -- ![Banner Image](..\Presentations\MARKER\Marker_Main.jpg) -- -- # The MARKER Class Idea --- +-- -- The MARKER class simplifies creating, updating and removing of markers on the F10 map. --- +-- -- # Create a Marker --- +-- -- -- Create a MARKER object at Batumi with a trivial text. -- local Coordinate=AIRBASE:FindByName("Batumi"):GetCoordinate() -- mymarker=MARKER:New(Coordinate, "I am Batumi Airfield") --- --- Now this does **not** show the marker yet. We still need to specifiy to whom it is shown. There are several options, i.e. +-- +-- Now this does **not** show the marker yet. We still need to specifiy to whom it is shown. There are several options, i.e. -- show the marker to everyone, to a speficic coaliton only, or only to a specific group. --- +-- -- ## For Everyone --- +-- -- If the marker should be visible to everyone, you can use the :ToAll() function. -- -- mymarker=MARKER:New(Coordinate, "I am Batumi Airfield"):ToAll() --- +-- -- ## For a Coaliton --- +-- -- If the maker should be visible to a specific coalition, you can use the :ToCoalition() function. --- +-- -- mymarker=MARKER:New(Coordinate, "I am Batumi Airfield"):ToCoaliton(coaliton.side.BLUE) --- +-- -- ### To Blue Coaliton --- +-- -- ### To Red Coalition --- +-- -- This would show the marker only to the Blue coaliton. --- +-- -- ## For a Group --- --- +-- +-- -- # Removing a Marker --- --- +-- +-- -- # Updating a Marker --- +-- -- The marker text and coordinate can be updated easily as shown below. --- +-- -- However, note that **updateing involves to remove and recreate the marker if either text or its coordinate is changed**. --- *This is a DCS scripting engine limitation.* --- +-- *This is a DCS scripting engine limitation.* +-- -- ## Update Text --- +-- -- If you created a marker "mymarker" as shown above, you can update the dispayed test by --- +-- -- mymarker:UpdateText("I am the new text at Batumi") --- +-- -- The update can also be delayed by, e.g. 90 seconds, using --- +-- -- mymarker:UpdateText("I am the new text at Batumi", 90) --- +-- -- ## Update Coordinate --- +-- -- If you created a marker "mymarker" as shown above, you can update its coordinate on the F10 map by --- +-- -- mymarker:UpdateCoordinate(NewCoordinate) --- +-- -- The update can also be delayed by, e.g. 60 seconds, using --- +-- -- mymarker:UpdateCoordinate(NewCoordinate, 60) --- +-- -- # Retrieve Data --- +-- -- The important data as the displayed text and the coordinate of the marker can be retrieved easily. --- +-- -- ## Text --- +-- -- local text=mymarker:GetText() -- env.info("Marker Text = " .. text) --- +-- -- ## Coordinate --- +-- -- local Coordinate=mymarker:GetCoordinate() -- env.info("Marker Coordinate LL DSM = " .. Coordinate:ToStringLLDMS()) --- --- +-- +-- -- # FSM Events --- +-- -- Moose creates addditonal events, so called FSM event, when markers are added, changed, removed, and text or the coordianteis updated. --- +-- -- These events can be captured and used for processing via OnAfter functions as shown below. --- +-- -- ## Added --- +-- -- ## Changed --- +-- -- ## Removed --- +-- -- ## TextUpdate --- +-- -- ## CoordUpdate --- --- +-- +-- -- # Examples --- --- +-- +-- -- @field #MARKER MARKER = { ClassName = "MARKER", @@ -170,29 +170,29 @@ MARKER.version="0.1.0" --- Create a new MARKER class object. -- @param #MARKER self -- @param Core.Point#COORDINATE Coordinate Coordinate where to place the marker. --- @param #string Text Text displayed on the mark panel. +-- @param #string Text Text displayed on the mark panel. -- @return #MARKER self function MARKER:New(Coordinate, Text) -- Inherit everything from FSM class. local self=BASE:Inherit(self, FSM:New()) -- #MARKER - + self.coordinate=Coordinate - + self.text=Text - + -- Defaults self.readonly=false self.message="" - - -- New marker ID. This is not the one of the actual marker. + + -- New marker ID. This is not the one of the actual marker. _MARKERID=_MARKERID+1 - + self.myid=_MARKERID - + -- Log ID. self.lid=string.format("Marker #%d | ", self.myid) - + -- Start State. self:SetStartState("Invisible") @@ -201,7 +201,7 @@ function MARKER:New(Coordinate, Text) self:AddTransition("Invisible", "Added", "Visible") -- Marker was added. self:AddTransition("Visible", "Removed", "Invisible") -- Marker was removed. self:AddTransition("*", "Changed", "*") -- Marker was changed. - + self:AddTransition("*", "TextUpdate", "*") -- Text updated. self:AddTransition("*", "CoordUpdate", "*") -- Coordinates updated. @@ -304,8 +304,8 @@ function MARKER:New(Coordinate, Text) self:HandleEvent(EVENTS.MarkAdded) self:HandleEvent(EVENTS.MarkRemoved) self:HandleEvent(EVENTS.MarkChange) - - return self + + return self end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -318,7 +318,7 @@ end function MARKER:ReadOnly() self.readonly=true - + return self end @@ -329,7 +329,7 @@ end function MARKER:Message(Text) self.message=Text or "" - + return self end @@ -349,14 +349,14 @@ function MARKER:ToAll(Delay) self.togroup=nil self.groupname=nil self.groupid=nil - + -- First remove an existing mark. - if self.shown then - self:Remove() + if self.shown then + self:Remove() end - + self.mid=UTILS.GetMarkID() - + -- Call DCS function. trigger.action.markToAll(self.mid, self.text, self.coordinate:GetVec3(), self.readonly, self.message) @@ -377,25 +377,25 @@ function MARKER:ToCoalition(Coalition, Delay) else self.coalition=Coalition - + self.tocoaliton=true self.toall=false self.togroup=false self.groupname=nil self.groupid=nil - + -- First remove an existing mark. - if self.shown then - self:Remove() + if self.shown then + self:Remove() end - + self.mid=UTILS.GetMarkID() - + -- Call DCS function. trigger.action.markToCoalition(self.mid, self.text, self.coordinate:GetVec3(), self.coalition, self.readonly, self.message) - + end - + return self end @@ -440,36 +440,36 @@ function MARKER:ToGroup(Group, Delay) -- Check if group exists. if Group and Group:IsAlive()~=nil then - + self.groupid=Group:GetID() - + if self.groupid then - + self.groupname=Group:GetName() - + self.togroup=true self.tocoaliton=nil self.coalition=nil self.toall=nil - + -- First remove an existing mark. - if self.shown then - self:Remove() + if self.shown then + self:Remove() end - + self.mid=UTILS.GetMarkID() - + -- Call DCS function. trigger.action.markToGroup(self.mid, self.text, self.coordinate:GetVec3(), self.groupid, self.readonly, self.message) - + end - + else - --TODO: Warning! + --TODO: Warning! end - + end - + return self end @@ -482,14 +482,14 @@ function MARKER:UpdateText(Text, Delay) if Delay and Delay>0 then self:ScheduleOnce(Delay, MARKER.UpdateText, self, Text) - else + else self.text=tostring(Text) - + self:Refresh() - + self:TextUpdate(tostring(Text)) - + end return self @@ -504,14 +504,14 @@ function MARKER:UpdateCoordinate(Coordinate, Delay) if Delay and Delay>0 then self:ScheduleOnce(Delay, MARKER.UpdateCoordinate, self, Coordinate) - else + else self.coordinate=Coordinate - + self:Refresh() - + self:CoordUpdate(Coordinate) - + end return self @@ -525,26 +525,26 @@ function MARKER:Refresh(Delay) if Delay and Delay>0 then self:ScheduleOnce(Delay, MARKER.Refresh, self) - else + else if self.toall then - + self:ToAll() - + elseif self.tocoaliton then - + self:ToCoalition(self.coalition) - + elseif self.togroup then - + local group=GROUP:FindByName(self.groupname) - + self:ToGroup(group) - + else self:E(self.lid.."ERROR: unknown To in :Refresh()!") end - + end return self @@ -564,9 +564,9 @@ function MARKER:Remove(Delay) -- Call DCS function. trigger.action.removeMark(self.mid) - + end - + end return self @@ -605,7 +605,7 @@ end --- Check if marker is currently invisible on the F10 map. -- @param #MARKER self --- @return +-- @return function MARKER:IsInvisible() return self:Is("Invisible") end @@ -620,17 +620,17 @@ end function MARKER:OnEventMarkAdded(EventData) if EventData and EventData.MarkID then - + local MarkID=EventData.MarkID - + self:T3(self.lid..string.format("Captured event MarkAdded for Mark ID=%s", tostring(MarkID))) - + if MarkID==self.mid then - + self.shown=true - + self:Added(EventData) - + end end @@ -643,21 +643,21 @@ end function MARKER:OnEventMarkRemoved(EventData) if EventData and EventData.MarkID then - + local MarkID=EventData.MarkID - + self:T3(self.lid..string.format("Captured event MarkAdded for Mark ID=%s", tostring(MarkID))) - + if MarkID==self.mid then - + self.shown=false - + self:Removed(EventData) - + end end - + end --- Event function when a MARKER changed. @@ -666,17 +666,17 @@ end function MARKER:OnEventMarkChange(EventData) if EventData and EventData.MarkID then - + local MarkID=EventData.MarkID - + self:T3(self.lid..string.format("Captured event MarkChange for Mark ID=%s", tostring(MarkID))) - + if MarkID==self.mid then - + self:Changed(EventData) - + self:TextChanged(tostring(EventData.MarkText)) - + end end @@ -696,7 +696,7 @@ end function MARKER:onafterAdded(From, Event, To, EventData) -- Debug info. - local text=string.format("Captured event MarkAdded for myself:\n") + local text=string.format("Captured event MarkAdded for myself:\n") text=text..string.format("Marker ID = %s\n", tostring(EventData.MarkID)) text=text..string.format("Coalition = %s\n", tostring(EventData.MarkCoalition)) text=text..string.format("Group ID = %s\n", tostring(EventData.MarkGroupID)) @@ -716,7 +716,7 @@ end function MARKER:onafterRemoved(From, Event, To, EventData) -- Debug info. - local text=string.format("Captured event MarkRemoved for myself:\n") + local text=string.format("Captured event MarkRemoved for myself:\n") text=text..string.format("Marker ID = %s\n", tostring(EventData.MarkID)) text=text..string.format("Coalition = %s\n", tostring(EventData.MarkCoalition)) text=text..string.format("Group ID = %s\n", tostring(EventData.MarkGroupID)) @@ -736,7 +736,7 @@ end function MARKER:onafterChanged(From, Event, To, EventData) -- Debug info. - local text=string.format("Captured event MarkChange for myself:\n") + local text=string.format("Captured event MarkChange for myself:\n") text=text..string.format("Marker ID = %s\n", tostring(EventData.MarkID)) text=text..string.format("Coalition = %s\n", tostring(EventData.MarkCoalition)) text=text..string.format("Group ID = %s\n", tostring(EventData.MarkGroupID)) @@ -768,7 +768,7 @@ end function MARKER:onafterCoordUpdate(From, Event, To, Coordinate) self:T(self.lid..string.format("New Marker Coordinate in LL DMS: %s", Coordinate:ToStringLLDMS())) - + end -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------