New Event Dispatching based on priorities

-- First _DATABASE
-- then SETS
-- then the rest
-- changed AIRBASEPOLICE
This commit is contained in:
FlightControl 2017-02-03 22:18:51 +01:00
parent 33af2b4f95
commit ab345f5ad2
13 changed files with 291 additions and 71 deletions

View File

@ -1,4 +1,4 @@
rem This script will pull the latest changes from the remote repository, and update the submodules accordingly. rem This script will pull the latest changes from the remote repository, and update the submodules accordingly.
git pull C:\Program Files (x86)\Git\bin\git pull
git submodule update --init C:\Program Files (x86)\Git\bin\git submodule update --init

View File

@ -55,6 +55,8 @@ DATABASE = {
CLIENTS = {}, CLIENTS = {},
AIRBASES = {}, AIRBASES = {},
NavPoints = {}, NavPoints = {},
EventPriority = 1, -- Used to sort the DCS event order processing (complicated). Database has highest priority.
} }
local _DATABASECoalition = local _DATABASECoalition =
@ -228,6 +230,7 @@ end
function DATABASE:AddGroup( GroupName ) function DATABASE:AddGroup( GroupName )
if not self.GROUPS[GroupName] then if not self.GROUPS[GroupName] then
self:E( { "Add GROUP:", GroupName } )
self.GROUPS[GroupName] = GROUP:Register( GroupName ) self.GROUPS[GroupName] = GROUP:Register( GroupName )
end end
@ -569,6 +572,8 @@ function DATABASE:_EventOnPlayerEnterUnit( Event )
self:F2( { Event } ) self:F2( { Event } )
if Event.IniUnit then if Event.IniUnit then
self:AddUnit( Event.IniDCSUnitName )
self:AddGroup( Event.IniDCSGroupName )
local PlayerName = Event.IniUnit:GetPlayerName() local PlayerName = Event.IniUnit:GetPlayerName()
if not self.PLAYERS[PlayerName] then if not self.PLAYERS[PlayerName] then
self:AddPlayer( Event.IniUnitName, PlayerName ) self:AddPlayer( Event.IniUnitName, PlayerName )

View File

@ -21,6 +21,7 @@
EVENT = { EVENT = {
ClassName = "EVENT", ClassName = "EVENT",
ClassID = 0, ClassID = 0,
SortedEvents = {},
} }
local _EVENTCODES = { local _EVENTCODES = {
@ -50,6 +51,33 @@ local _EVENTCODES = {
"S_EVENT_MAX", "S_EVENT_MAX",
} }
local _EVENTORDER = {
[world.event.S_EVENT_SHOT] = 1,
[world.event.S_EVENT_HIT] = 1,
[world.event.S_EVENT_TAKEOFF] = 1,
[world.event.S_EVENT_LAND] = 1,
[world.event.S_EVENT_CRASH] = -1,
[world.event.S_EVENT_EJECTION] = -1,
[world.event.S_EVENT_REFUELING] = 1,
[world.event.S_EVENT_DEAD] = -1,
[world.event.S_EVENT_PILOT_DEAD] = -1,
[world.event.S_EVENT_BASE_CAPTURED] = 1,
[world.event.S_EVENT_MISSION_START] = 1,
[world.event.S_EVENT_MISSION_END] = -1,
[world.event.S_EVENT_TOOK_CONTROL] = 1,
[world.event.S_EVENT_REFUELING_STOP] = 1,
[world.event.S_EVENT_BIRTH] = 1,
[world.event.S_EVENT_HUMAN_FAILURE] = 1,
[world.event.S_EVENT_ENGINE_STARTUP] = 1,
[world.event.S_EVENT_ENGINE_SHUTDOWN] = 1,
[world.event.S_EVENT_PLAYER_ENTER_UNIT] = 1,
[world.event.S_EVENT_PLAYER_LEAVE_UNIT] = -1,
[world.event.S_EVENT_PLAYER_COMMENT] = 1,
[world.event.S_EVENT_SHOOTING_START] = 1,
[world.event.S_EVENT_SHOOTING_END] = 1,
[world.event.S_EVENT_MAX] = 1,
}
--- The Event structure --- The Event structure
-- @type EVENTDATA -- @type EVENTDATA
-- @field id -- @field id
@ -102,7 +130,7 @@ function EVENT:Init( EventID, EventClass )
if not self.Events[EventID] then if not self.Events[EventID] then
-- Create a WEAK table to ensure that the garbage collector is cleaning the event links when the object usage is cleaned. -- Create a WEAK table to ensure that the garbage collector is cleaning the event links when the object usage is cleaned.
self.Events[EventID] = setmetatable( {}, { __mode = "k" } ) self.Events[EventID] = setmetatable( {}, { __mode = "k" } )
self.SortedEvents[EventID] = setmetatable( {}, { __mode = "k" } )
end end
if not self.Events[EventID][EventClass] then if not self.Events[EventID][EventClass] then
@ -121,6 +149,12 @@ function EVENT:Remove( EventClass, EventID )
local EventClass = EventClass local EventClass = EventClass
self.Events[EventID][EventClass] = nil self.Events[EventID][EventClass] = nil
self.SortedEvents[EventID] = nil
self.SortedEvents[EventID] = {}
for EventClass, Event in pairs(self.Events[EventID]) do table.insert( self.SortedEvents[EventID], Event) end
table.sort( self.SortedEvents[EventID], function( Event1, Event2 ) return Event1.EventTime < Event2.EventTime end )
end end
--- Clears all event subscriptions for a @{Core.Base#BASE} derived object. --- Clears all event subscriptions for a @{Core.Base#BASE} derived object.
@ -132,6 +166,7 @@ function EVENT:RemoveAll( EventObject )
local EventClass = EventObject:GetClassNameAndID() local EventClass = EventObject:GetClassNameAndID()
for EventID, EventData in pairs( self.Events ) do for EventID, EventData in pairs( self.Events ) do
self.Events[EventID][EventClass] = nil self.Events[EventID][EventClass] = nil
self.SortedEvents[EventID] = nil
end end
end end
@ -165,6 +200,13 @@ function EVENT:OnEventGeneric( EventFunction, EventClass, EventID )
local Event = self:Init( EventID, EventClass ) local Event = self:Init( EventID, EventClass )
Event.EventFunction = EventFunction Event.EventFunction = EventFunction
Event.EventClass = EventClass Event.EventClass = EventClass
Event.EventTime = EventClass.EventPriority and EventClass.EventPriority or 10
self.SortedEvents[EventID] = nil
self.SortedEvents[EventID] = {}
for EventClass, Event in pairs(self.Events[EventID]) do table.insert( self.SortedEvents[EventID], Event) end
table.sort( self.SortedEvents[EventID], function( Event1, Event2 ) return Event1.EventTime < Event2.EventTime end )
return self return self
end end
@ -741,6 +783,8 @@ function EVENT:onEvent( Event )
Event.IniDCSGroupName = "" Event.IniDCSGroupName = ""
if Event.IniDCSGroup and Event.IniDCSGroup:isExist() then if Event.IniDCSGroup and Event.IniDCSGroup:isExist() then
Event.IniDCSGroupName = Event.IniDCSGroup:getName() Event.IniDCSGroupName = Event.IniDCSGroup:getName()
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
self:E( { IniGroup = Event.IniGroup } )
end end
end end
if Event.target then if Event.target then
@ -763,11 +807,27 @@ function EVENT:onEvent( Event )
end end
self:E( { _EVENTCODES[Event.id], Event, Event.IniDCSUnitName, Event.TgtDCSUnitName } ) self:E( { _EVENTCODES[Event.id], Event, Event.IniDCSUnitName, Event.TgtDCSUnitName } )
-- Okay, we got the event from DCS. Now loop the self.Events[] table for the received Event.id, and for each EventData registered, check if a function needs to be called. local function pairsByEventSorted( EventSorted, Order )
for EventClass, EventData in pairs( self.Events[Event.id] ) do local i = Order == -1 and #EventSorted or 0
local iter = function()
i = i + Order
if EventSorted[i] == nil then
return nil
else
return EventSorted[i].EventClass, EventSorted[i]
end
end
return iter
end
self:E( { Order = _EVENTORDER[Event.id] } )
-- Okay, we got the event from DCS. Now loop the SORTED self.EventSorted[] table for the received Event.id, and for each EventData registered, check if a function needs to be called.
for EventClass, EventData in pairsByEventSorted( self.SortedEvents[Event.id], _EVENTORDER[Event.id] ) do
-- If the EventData is for a UNIT, the call directly the EventClass EventFunction for that UNIT. -- If the EventData is for a UNIT, the call directly the EventClass EventFunction for that UNIT.
if Event.IniDCSUnitName and EventData.IniUnit and EventData.IniUnit[Event.IniDCSUnitName] then if Event.IniDCSUnitName and EventData.IniUnit and EventData.IniUnit[Event.IniDCSUnitName] then
self:T( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName } ) self:E( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventData.EventTime } )
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
local Result, Value = xpcall( function() return EventData.IniUnit[Event.IniDCSUnitName].EventFunction( EventData.IniUnit[Event.IniDCSUnitName].EventClass, Event ) end, ErrorHandler ) local Result, Value = xpcall( function() return EventData.IniUnit[Event.IniDCSUnitName].EventFunction( EventData.IniUnit[Event.IniDCSUnitName].EventClass, Event ) end, ErrorHandler )
--EventData.IniUnit[Event.IniDCSUnitName].EventFunction( EventData.IniUnit[Event.IniDCSUnitName].EventClass, Event ) --EventData.IniUnit[Event.IniDCSUnitName].EventFunction( EventData.IniUnit[Event.IniDCSUnitName].EventClass, Event )
else else
@ -775,7 +835,8 @@ function EVENT:onEvent( Event )
-- Note that here the EventFunction will need to implement and determine the logic for the relevant source- or target unit, or weapon. -- Note that here the EventFunction will need to implement and determine the logic for the relevant source- or target unit, or weapon.
if Event.IniDCSUnit and not EventData.IniUnit then if Event.IniDCSUnit and not EventData.IniUnit then
if EventClass == EventData.EventClass then if EventClass == EventData.EventClass then
self:T( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID() } ) self:E( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID(), EventData.EventTime } )
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
local Result, Value = xpcall( function() return EventData.EventFunction( EventData.EventClass, Event ) end, ErrorHandler ) local Result, Value = xpcall( function() return EventData.EventFunction( EventData.EventClass, Event ) end, ErrorHandler )
--EventData.EventFunction( EventData.EventClass, Event ) --EventData.EventFunction( EventData.EventClass, Event )
end end

View File

@ -240,6 +240,7 @@ SET_BASE = {
Filter = {}, Filter = {},
Set = {}, Set = {},
List = {}, List = {},
EventPriority = 2, -- Used to sort the DCS event order processing (complicated)
} }
--- Creates a new SET_BASE object, building a set of units belonging to a coalitions, categories, countries, types or with defined prefix names. --- Creates a new SET_BASE object, building a set of units belonging to a coalitions, categories, countries, types or with defined prefix names.

View File

@ -182,7 +182,7 @@ function AIRBASEPOLICE_BASE:_AirbaseMonitor()
Client:SetState( self, "Warnings", SpeedingWarnings + 1 ) Client:SetState( self, "Warnings", SpeedingWarnings + 1 )
else else
MESSAGE:New( "Player " .. Client:GetPlayerName() .. " has been removed from the airbase, due to a speeding violation ...", 10, "Airbase Police" ):ToAll() MESSAGE:New( "Player " .. Client:GetPlayerName() .. " has been removed from the airbase, due to a speeding violation ...", 10, "Airbase Police" ):ToAll()
Client:GetGroup():Destroy() Client:Destroy()
Client:SetState( self, "Speeding", false ) Client:SetState( self, "Speeding", false )
Client:SetState( self, "Warnings", 0 ) Client:SetState( self, "Warnings", 0 )
end end

View File

@ -81,7 +81,8 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
local PlayerUnit = EventData.IniUnit local PlayerUnit = EventData.IniUnit
for MissionID, Mission in pairs( self:GetMissions() ) do for MissionID, Mission in pairs( self:GetMissions() ) do
local Mission = Mission -- Tasking.Mission#MISSION local Mission = Mission -- Tasking.Mission#MISSION
Mission:JoinUnit( PlayerUnit ) local PlayerGroup = EventData.IniGroup -- The GROUP object should be filled!
Mission:JoinUnit( PlayerUnit, PlayerGroup )
Mission:ReportDetails() Mission:ReportDetails()
end end
@ -100,7 +101,8 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
local PlayerUnit = EventData.IniUnit local PlayerUnit = EventData.IniUnit
for MissionID, Mission in pairs( self:GetMissions() ) do for MissionID, Mission in pairs( self:GetMissions() ) do
local Mission = Mission -- Tasking.Mission#MISSION local Mission = Mission -- Tasking.Mission#MISSION
Mission:JoinUnit( PlayerUnit ) local PlayerGroup = EventData.IniGroup -- The GROUP object should be filled!
Mission:JoinUnit( PlayerUnit, PlayerGroup )
Mission:ReportDetails() Mission:ReportDetails()
end end
end end
@ -115,6 +117,7 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
function( self, EventData ) function( self, EventData )
local PlayerUnit = EventData.IniUnit local PlayerUnit = EventData.IniUnit
for MissionID, Mission in pairs( self:GetMissions() ) do for MissionID, Mission in pairs( self:GetMissions() ) do
local Mission = Mission -- Tasking.Mission#MISSION
Mission:AbortUnit( PlayerUnit ) Mission:AbortUnit( PlayerUnit )
end end
end end

View File

@ -103,15 +103,16 @@ end
-- If the Unit is part of a Task in the Mission, true is returned. -- If the Unit is part of a Task in the Mission, true is returned.
-- @param #MISSION self -- @param #MISSION self
-- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player joining the Mission. -- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player joining the Mission.
-- @param Wrapper.Group#GROUP PlayerGroup The GROUP of the player joining the Mission.
-- @return #boolean true if Unit is part of a Task in the Mission. -- @return #boolean true if Unit is part of a Task in the Mission.
function MISSION:JoinUnit( PlayerUnit ) function MISSION:JoinUnit( PlayerUnit, PlayerGroup )
self:F( { PlayerUnit = PlayerUnit } ) self:F( { PlayerUnit = PlayerUnit, PlayerGroup = PlayerGroup } )
local PlayerUnitAdded = false local PlayerUnitAdded = false
for TaskID, Task in pairs( self:GetTasks() ) do for TaskID, Task in pairs( self:GetTasks() ) do
local Task = Task -- Tasking.Task#TASK local Task = Task -- Tasking.Task#TASK
if Task:JoinUnit( PlayerUnit ) then if Task:JoinUnit( PlayerUnit, PlayerGroup ) then
PlayerUnitAdded = true PlayerUnitAdded = true
end end
end end

View File

@ -234,14 +234,14 @@ end
-- If the Unit is part of the Task, true is returned. -- If the Unit is part of the Task, true is returned.
-- @param #TASK self -- @param #TASK self
-- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player joining the Mission. -- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player joining the Mission.
-- @param Wrapper.Group#GROUP PlayerGroup The GROUP of the player joining the Mission.
-- @return #boolean true if Unit is part of the Task. -- @return #boolean true if Unit is part of the Task.
function TASK:JoinUnit( PlayerUnit ) function TASK:JoinUnit( PlayerUnit, PlayerGroup )
self:F( { PlayerUnit = PlayerUnit } ) self:F( { PlayerUnit = PlayerUnit, PlayerGroup = PlayerGroup } )
local PlayerUnitAdded = false local PlayerUnitAdded = false
local PlayerGroups = self:GetGroups() local PlayerGroups = self:GetGroups()
local PlayerGroup = PlayerUnit:GetGroup()
-- Is the PlayerGroup part of the PlayerGroups? -- Is the PlayerGroup part of the PlayerGroups?
if PlayerGroups:IsIncludeObject( PlayerGroup ) then if PlayerGroups:IsIncludeObject( PlayerGroup ) then
@ -394,7 +394,6 @@ end
-- @return #boolean -- @return #boolean
function TASK:HasGroup( FindGroup ) function TASK:HasGroup( FindGroup )
self:GetGroups():FilterOnce() -- Ensure that the filter is updated.
return self:GetGroups():IsIncludeObject( FindGroup ) return self:GetGroups():IsIncludeObject( FindGroup )
end end

View File

@ -1,5 +1,5 @@
env.info( '*** MOOSE STATIC INCLUDE START *** ' ) env.info( '*** MOOSE STATIC INCLUDE START *** ' )
env.info( 'Moose Generation Timestamp: 20170124_1109' ) env.info( 'Moose Generation Timestamp: 20170203_2208' )
local base = _G local base = _G
Include = {} Include = {}
@ -4211,6 +4211,7 @@ end
EVENT = { EVENT = {
ClassName = "EVENT", ClassName = "EVENT",
ClassID = 0, ClassID = 0,
SortedEvents = {},
} }
local _EVENTCODES = { local _EVENTCODES = {
@ -4240,6 +4241,33 @@ local _EVENTCODES = {
"S_EVENT_MAX", "S_EVENT_MAX",
} }
local _EVENTORDER = {
[world.event.S_EVENT_SHOT] = 1,
[world.event.S_EVENT_HIT] = 1,
[world.event.S_EVENT_TAKEOFF] = 1,
[world.event.S_EVENT_LAND] = 1,
[world.event.S_EVENT_CRASH] = -1,
[world.event.S_EVENT_EJECTION] = -1,
[world.event.S_EVENT_REFUELING] = 1,
[world.event.S_EVENT_DEAD] = -1,
[world.event.S_EVENT_PILOT_DEAD] = -1,
[world.event.S_EVENT_BASE_CAPTURED] = 1,
[world.event.S_EVENT_MISSION_START] = 1,
[world.event.S_EVENT_MISSION_END] = -1,
[world.event.S_EVENT_TOOK_CONTROL] = 1,
[world.event.S_EVENT_REFUELING_STOP] = 1,
[world.event.S_EVENT_BIRTH] = 1,
[world.event.S_EVENT_HUMAN_FAILURE] = 1,
[world.event.S_EVENT_ENGINE_STARTUP] = 1,
[world.event.S_EVENT_ENGINE_SHUTDOWN] = 1,
[world.event.S_EVENT_PLAYER_ENTER_UNIT] = 1,
[world.event.S_EVENT_PLAYER_LEAVE_UNIT] = -1,
[world.event.S_EVENT_PLAYER_COMMENT] = 1,
[world.event.S_EVENT_SHOOTING_START] = 1,
[world.event.S_EVENT_SHOOTING_END] = 1,
[world.event.S_EVENT_MAX] = 1,
}
--- The Event structure --- The Event structure
-- @type EVENTDATA -- @type EVENTDATA
-- @field id -- @field id
@ -4292,7 +4320,7 @@ function EVENT:Init( EventID, EventClass )
if not self.Events[EventID] then if not self.Events[EventID] then
-- Create a WEAK table to ensure that the garbage collector is cleaning the event links when the object usage is cleaned. -- Create a WEAK table to ensure that the garbage collector is cleaning the event links when the object usage is cleaned.
self.Events[EventID] = setmetatable( {}, { __mode = "k" } ) self.Events[EventID] = setmetatable( {}, { __mode = "k" } )
self.SortedEvents[EventID] = setmetatable( {}, { __mode = "k" } )
end end
if not self.Events[EventID][EventClass] then if not self.Events[EventID][EventClass] then
@ -4311,6 +4339,12 @@ function EVENT:Remove( EventClass, EventID )
local EventClass = EventClass local EventClass = EventClass
self.Events[EventID][EventClass] = nil self.Events[EventID][EventClass] = nil
self.SortedEvents[EventID] = nil
self.SortedEvents[EventID] = {}
for EventClass, Event in pairs(self.Events[EventID]) do table.insert( self.SortedEvents[EventID], Event) end
table.sort( self.SortedEvents[EventID], function( Event1, Event2 ) return Event1.EventTime < Event2.EventTime end )
end end
--- Clears all event subscriptions for a @{Core.Base#BASE} derived object. --- Clears all event subscriptions for a @{Core.Base#BASE} derived object.
@ -4322,6 +4356,7 @@ function EVENT:RemoveAll( EventObject )
local EventClass = EventObject:GetClassNameAndID() local EventClass = EventObject:GetClassNameAndID()
for EventID, EventData in pairs( self.Events ) do for EventID, EventData in pairs( self.Events ) do
self.Events[EventID][EventClass] = nil self.Events[EventID][EventClass] = nil
self.SortedEvents[EventID] = nil
end end
end end
@ -4355,6 +4390,13 @@ function EVENT:OnEventGeneric( EventFunction, EventClass, EventID )
local Event = self:Init( EventID, EventClass ) local Event = self:Init( EventID, EventClass )
Event.EventFunction = EventFunction Event.EventFunction = EventFunction
Event.EventClass = EventClass Event.EventClass = EventClass
Event.EventTime = EventClass.EventPriority and EventClass.EventPriority or 10
self.SortedEvents[EventID] = nil
self.SortedEvents[EventID] = {}
for EventClass, Event in pairs(self.Events[EventID]) do table.insert( self.SortedEvents[EventID], Event) end
table.sort( self.SortedEvents[EventID], function( Event1, Event2 ) return Event1.EventTime < Event2.EventTime end )
return self return self
end end
@ -4931,6 +4973,8 @@ function EVENT:onEvent( Event )
Event.IniDCSGroupName = "" Event.IniDCSGroupName = ""
if Event.IniDCSGroup and Event.IniDCSGroup:isExist() then if Event.IniDCSGroup and Event.IniDCSGroup:isExist() then
Event.IniDCSGroupName = Event.IniDCSGroup:getName() Event.IniDCSGroupName = Event.IniDCSGroup:getName()
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
self:E( { IniGroup = Event.IniGroup } )
end end
end end
if Event.target then if Event.target then
@ -4953,11 +4997,27 @@ function EVENT:onEvent( Event )
end end
self:E( { _EVENTCODES[Event.id], Event, Event.IniDCSUnitName, Event.TgtDCSUnitName } ) self:E( { _EVENTCODES[Event.id], Event, Event.IniDCSUnitName, Event.TgtDCSUnitName } )
-- Okay, we got the event from DCS. Now loop the self.Events[] table for the received Event.id, and for each EventData registered, check if a function needs to be called. local function pairsByEventSorted( EventSorted, Order )
for EventClass, EventData in pairs( self.Events[Event.id] ) do local i = Order == -1 and #EventSorted or 0
local iter = function()
i = i + Order
if EventSorted[i] == nil then
return nil
else
return EventSorted[i].EventClass, EventSorted[i]
end
end
return iter
end
self:E( { Order = _EVENTORDER[Event.id] } )
-- Okay, we got the event from DCS. Now loop the SORTED self.EventSorted[] table for the received Event.id, and for each EventData registered, check if a function needs to be called.
for EventClass, EventData in pairsByEventSorted( self.SortedEvents[Event.id], _EVENTORDER[Event.id] ) do
-- If the EventData is for a UNIT, the call directly the EventClass EventFunction for that UNIT. -- If the EventData is for a UNIT, the call directly the EventClass EventFunction for that UNIT.
if Event.IniDCSUnitName and EventData.IniUnit and EventData.IniUnit[Event.IniDCSUnitName] then if Event.IniDCSUnitName and EventData.IniUnit and EventData.IniUnit[Event.IniDCSUnitName] then
self:T( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName } ) self:E( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventData.EventTime } )
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
local Result, Value = xpcall( function() return EventData.IniUnit[Event.IniDCSUnitName].EventFunction( EventData.IniUnit[Event.IniDCSUnitName].EventClass, Event ) end, ErrorHandler ) local Result, Value = xpcall( function() return EventData.IniUnit[Event.IniDCSUnitName].EventFunction( EventData.IniUnit[Event.IniDCSUnitName].EventClass, Event ) end, ErrorHandler )
--EventData.IniUnit[Event.IniDCSUnitName].EventFunction( EventData.IniUnit[Event.IniDCSUnitName].EventClass, Event ) --EventData.IniUnit[Event.IniDCSUnitName].EventFunction( EventData.IniUnit[Event.IniDCSUnitName].EventClass, Event )
else else
@ -4965,7 +5025,8 @@ function EVENT:onEvent( Event )
-- Note that here the EventFunction will need to implement and determine the logic for the relevant source- or target unit, or weapon. -- Note that here the EventFunction will need to implement and determine the logic for the relevant source- or target unit, or weapon.
if Event.IniDCSUnit and not EventData.IniUnit then if Event.IniDCSUnit and not EventData.IniUnit then
if EventClass == EventData.EventClass then if EventClass == EventData.EventClass then
self:T( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID() } ) self:E( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID(), EventData.EventTime } )
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
local Result, Value = xpcall( function() return EventData.EventFunction( EventData.EventClass, Event ) end, ErrorHandler ) local Result, Value = xpcall( function() return EventData.EventFunction( EventData.EventClass, Event ) end, ErrorHandler )
--EventData.EventFunction( EventData.EventClass, Event ) --EventData.EventFunction( EventData.EventClass, Event )
end end
@ -5765,7 +5826,7 @@ do
end end
end end
self:F( { MenuGroup:GetName(), MenuText, ParentMenu.MenuPath } ) --self:F( { MenuGroup:GetName(), MenuText, ParentMenu.MenuPath } )
return self return self
end end
@ -5844,7 +5905,7 @@ do
end end
end end
self:F( { MenuGroup:GetName(), MenuText, ParentMenu.MenuPath } ) --self:F( { MenuGroup:GetName(), MenuText, ParentMenu.MenuPath } )
return self return self
end end
@ -6321,16 +6382,20 @@ end
--- Returns a random location within the zone. --- Returns a random location within the zone.
-- @param #ZONE_RADIUS self -- @param #ZONE_RADIUS self
-- @param #number inner minimal distance from the center of the zone
-- @param #number outer minimal distance from the outer edge of the zone
-- @return Dcs.DCSTypes#Vec2 The random location within the zone. -- @return Dcs.DCSTypes#Vec2 The random location within the zone.
function ZONE_RADIUS:GetRandomVec2() function ZONE_RADIUS:GetRandomVec2(inner, outer)
self:F( self.ZoneName ) self:F( self.ZoneName, inner, outer )
local Point = {} local Point = {}
local Vec2 = self:GetVec2() local Vec2 = self:GetVec2()
local _inner = inner or 0
local _outer = outer or self:GetRadius()
local angle = math.random() * math.pi*2; local angle = math.random() * math.pi * 2;
Point.x = Vec2.x + math.cos( angle ) * math.random() * self:GetRadius(); Point.x = Vec2.x + math.cos( angle ) * math.random(_inner, _outer);
Point.y = Vec2.y + math.sin( angle ) * math.random() * self:GetRadius(); Point.y = Vec2.y + math.sin( angle ) * math.random(_inner, _outer);
self:T( { Point } ) self:T( { Point } )
@ -6757,6 +6822,8 @@ DATABASE = {
CLIENTS = {}, CLIENTS = {},
AIRBASES = {}, AIRBASES = {},
NavPoints = {}, NavPoints = {},
EventPriority = 1, -- Used to sort the DCS event order processing (complicated). Database has highest priority.
} }
local _DATABASECoalition = local _DATABASECoalition =
@ -6930,6 +6997,7 @@ end
function DATABASE:AddGroup( GroupName ) function DATABASE:AddGroup( GroupName )
if not self.GROUPS[GroupName] then if not self.GROUPS[GroupName] then
self:E( { "Add GROUP:", GroupName } )
self.GROUPS[GroupName] = GROUP:Register( GroupName ) self.GROUPS[GroupName] = GROUP:Register( GroupName )
end end
@ -7271,6 +7339,8 @@ function DATABASE:_EventOnPlayerEnterUnit( Event )
self:F2( { Event } ) self:F2( { Event } )
if Event.IniUnit then if Event.IniUnit then
self:AddUnit( Event.IniDCSUnitName )
self:AddGroup( Event.IniDCSGroupName )
local PlayerName = Event.IniUnit:GetPlayerName() local PlayerName = Event.IniUnit:GetPlayerName()
if not self.PLAYERS[PlayerName] then if not self.PLAYERS[PlayerName] then
self:AddPlayer( Event.IniUnitName, PlayerName ) self:AddPlayer( Event.IniUnitName, PlayerName )
@ -7721,6 +7791,7 @@ SET_BASE = {
Filter = {}, Filter = {},
Set = {}, Set = {},
List = {}, List = {},
EventPriority = 2, -- Used to sort the DCS event order processing (complicated)
} }
--- Creates a new SET_BASE object, building a set of units belonging to a coalitions, categories, countries, types or with defined prefix names. --- Creates a new SET_BASE object, building a set of units belonging to a coalitions, categories, countries, types or with defined prefix names.
@ -22398,7 +22469,7 @@ function AIRBASEPOLICE_BASE:_AirbaseMonitor()
Client:SetState( self, "Warnings", SpeedingWarnings + 1 ) Client:SetState( self, "Warnings", SpeedingWarnings + 1 )
else else
MESSAGE:New( "Player " .. Client:GetPlayerName() .. " has been removed from the airbase, due to a speeding violation ...", 10, "Airbase Police" ):ToAll() MESSAGE:New( "Player " .. Client:GetPlayerName() .. " has been removed from the airbase, due to a speeding violation ...", 10, "Airbase Police" ):ToAll()
Client:GetGroup():Destroy() Client:Destroy()
Client:SetState( self, "Speeding", false ) Client:SetState( self, "Speeding", false )
Client:SetState( self, "Warnings", 0 ) Client:SetState( self, "Warnings", 0 )
end end
@ -24867,13 +24938,14 @@ AI_PATROL_ZONE = {
-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. -- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. -- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h.
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. -- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
-- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
-- @return #AI_PATROL_ZONE self -- @return #AI_PATROL_ZONE self
-- @usage -- @usage
-- -- Define a new AI_PATROL_ZONE Object. This PatrolArea will patrol an AIControllable within PatrolZone between 3000 and 6000 meters, with a variying speed between 600 and 900 km/h. -- -- Define a new AI_PATROL_ZONE Object. This PatrolArea will patrol an AIControllable within PatrolZone between 3000 and 6000 meters, with a variying speed between 600 and 900 km/h.
-- PatrolZone = ZONE:New( 'PatrolZone' ) -- PatrolZone = ZONE:New( 'PatrolZone' )
-- PatrolSpawn = SPAWN:New( 'Patrol Group' ) -- PatrolSpawn = SPAWN:New( 'Patrol Group' )
-- PatrolArea = AI_PATROL_ZONE:New( PatrolZone, 3000, 6000, 600, 900 ) -- PatrolArea = AI_PATROL_ZONE:New( PatrolZone, 3000, 6000, 600, 900 )
function AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed ) function AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
-- Inherits from BASE -- Inherits from BASE
local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- #AI_PATROL_ZONE local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- #AI_PATROL_ZONE
@ -24885,6 +24957,9 @@ function AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltit
self.PatrolMinSpeed = PatrolMinSpeed self.PatrolMinSpeed = PatrolMinSpeed
self.PatrolMaxSpeed = PatrolMaxSpeed self.PatrolMaxSpeed = PatrolMaxSpeed
-- defafult PatrolAltType to "RADIO" if not specified
self.PatrolAltType = PatrolAltType or "RADIO"
self:SetDetectionOn() self:SetDetectionOn()
self.CheckStatus = true self.CheckStatus = true
@ -25390,7 +25465,7 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y ) local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
local ToPatrolZoneSpeed = self.PatrolMaxSpeed local ToPatrolZoneSpeed = self.PatrolMaxSpeed
local CurrentRoutePoint = CurrentPointVec3:RoutePointAir( local CurrentRoutePoint = CurrentPointVec3:RoutePointAir(
POINT_VEC3.RoutePointAltType.BARO, self.PatrolAltType,
POINT_VEC3.RoutePointType.TakeOffParking, POINT_VEC3.RoutePointType.TakeOffParking,
POINT_VEC3.RoutePointAction.FromParkingArea, POINT_VEC3.RoutePointAction.FromParkingArea,
ToPatrolZoneSpeed, ToPatrolZoneSpeed,
@ -25405,7 +25480,7 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y ) local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
local ToPatrolZoneSpeed = self.PatrolMaxSpeed local ToPatrolZoneSpeed = self.PatrolMaxSpeed
local CurrentRoutePoint = CurrentPointVec3:RoutePointAir( local CurrentRoutePoint = CurrentPointVec3:RoutePointAir(
POINT_VEC3.RoutePointAltType.BARO, self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint,
ToPatrolZoneSpeed, ToPatrolZoneSpeed,
@ -25431,7 +25506,7 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
--- Create a route point of type air. --- Create a route point of type air.
local ToTargetRoutePoint = ToTargetPointVec3:RoutePointAir( local ToTargetRoutePoint = ToTargetPointVec3:RoutePointAir(
POINT_VEC3.RoutePointAltType.BARO, self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint,
ToTargetSpeed, ToTargetSpeed,
@ -25519,7 +25594,7 @@ function AI_PATROL_ZONE:onafterRTB()
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y ) local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
local ToPatrolZoneSpeed = self.PatrolMaxSpeed local ToPatrolZoneSpeed = self.PatrolMaxSpeed
local CurrentRoutePoint = CurrentPointVec3:RoutePointAir( local CurrentRoutePoint = CurrentPointVec3:RoutePointAir(
POINT_VEC3.RoutePointAltType.BARO, self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint,
ToPatrolZoneSpeed, ToPatrolZoneSpeed,
@ -25709,12 +25784,13 @@ AI_CAS_ZONE = {
-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. -- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. -- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h.
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. -- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
-- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
-- @param Core.Zone#ZONE EngageZone -- @param Core.Zone#ZONE EngageZone
-- @return #AI_CAS_ZONE self -- @return #AI_CAS_ZONE self
function AI_CAS_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageZone ) function AI_CAS_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageZone, PatrolAltType )
-- Inherits from BASE -- Inherits from BASE
local self = BASE:Inherit( self, AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed ) ) -- #AI_CAS_ZONE local self = BASE:Inherit( self, AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) ) -- #AI_CAS_ZONE
self.EngageZone = EngageZone self.EngageZone = EngageZone
self.Accomplished = false self.Accomplished = false
@ -25953,7 +26029,7 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To )
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y ) local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
local ToEngageZoneSpeed = self.PatrolMaxSpeed local ToEngageZoneSpeed = self.PatrolMaxSpeed
local CurrentRoutePoint = CurrentPointVec3:RoutePointAir( local CurrentRoutePoint = CurrentPointVec3:RoutePointAir(
POINT_VEC3.RoutePointAltType.BARO, self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint,
ToEngageZoneSpeed, ToEngageZoneSpeed,
@ -25979,7 +26055,7 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To )
-- Create a route point of type air. -- Create a route point of type air.
local ToEngageZoneRoutePoint = ToEngageZonePointVec3:RoutePointAir( local ToEngageZoneRoutePoint = ToEngageZonePointVec3:RoutePointAir(
POINT_VEC3.RoutePointAltType.BARO, self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint,
ToEngageZoneSpeed, ToEngageZoneSpeed,
@ -26006,7 +26082,7 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To )
--- Create a route point of type air. --- Create a route point of type air.
local ToTargetRoutePoint = ToTargetPointVec3:RoutePointAir( local ToTargetRoutePoint = ToTargetPointVec3:RoutePointAir(
POINT_VEC3.RoutePointAltType.BARO, self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint,
ToTargetSpeed, ToTargetSpeed,
@ -26220,11 +26296,12 @@ AI_CAP_ZONE = {
-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. -- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. -- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h.
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. -- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
-- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
-- @return #AI_CAP_ZONE self -- @return #AI_CAP_ZONE self
function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed ) function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
-- Inherits from BASE -- Inherits from BASE
local self = BASE:Inherit( self, AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed ) ) -- #AI_CAP_ZONE local self = BASE:Inherit( self, AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) ) -- #AI_CAP_ZONE
self.Accomplished = false self.Accomplished = false
self.Engaging = false self.Engaging = false
@ -26501,7 +26578,7 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y ) local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
local ToEngageZoneSpeed = self.PatrolMaxSpeed local ToEngageZoneSpeed = self.PatrolMaxSpeed
local CurrentRoutePoint = CurrentPointVec3:RoutePointAir( local CurrentRoutePoint = CurrentPointVec3:RoutePointAir(
POINT_VEC3.RoutePointAltType.BARO, self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint,
ToEngageZoneSpeed, ToEngageZoneSpeed,
@ -26525,7 +26602,7 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
--- Create a route point of type air. --- Create a route point of type air.
local ToPatrolRoutePoint = ToTargetPointVec3:RoutePointAir( local ToPatrolRoutePoint = ToTargetPointVec3:RoutePointAir(
POINT_VEC3.RoutePointAltType.BARO, self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint,
ToTargetSpeed, ToTargetSpeed,
@ -28739,7 +28816,8 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
local PlayerUnit = EventData.IniUnit local PlayerUnit = EventData.IniUnit
for MissionID, Mission in pairs( self:GetMissions() ) do for MissionID, Mission in pairs( self:GetMissions() ) do
local Mission = Mission -- Tasking.Mission#MISSION local Mission = Mission -- Tasking.Mission#MISSION
Mission:JoinUnit( PlayerUnit ) local PlayerGroup = EventData.IniGroup -- The GROUP object should be filled!
Mission:JoinUnit( PlayerUnit, PlayerGroup )
Mission:ReportDetails() Mission:ReportDetails()
end end
@ -28758,7 +28836,8 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
local PlayerUnit = EventData.IniUnit local PlayerUnit = EventData.IniUnit
for MissionID, Mission in pairs( self:GetMissions() ) do for MissionID, Mission in pairs( self:GetMissions() ) do
local Mission = Mission -- Tasking.Mission#MISSION local Mission = Mission -- Tasking.Mission#MISSION
Mission:JoinUnit( PlayerUnit ) local PlayerGroup = EventData.IniGroup -- The GROUP object should be filled!
Mission:JoinUnit( PlayerUnit, PlayerGroup )
Mission:ReportDetails() Mission:ReportDetails()
end end
end end
@ -28773,6 +28852,7 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
function( self, EventData ) function( self, EventData )
local PlayerUnit = EventData.IniUnit local PlayerUnit = EventData.IniUnit
for MissionID, Mission in pairs( self:GetMissions() ) do for MissionID, Mission in pairs( self:GetMissions() ) do
local Mission = Mission -- Tasking.Mission#MISSION
Mission:AbortUnit( PlayerUnit ) Mission:AbortUnit( PlayerUnit )
end end
end end
@ -29040,15 +29120,16 @@ end
-- If the Unit is part of a Task in the Mission, true is returned. -- If the Unit is part of a Task in the Mission, true is returned.
-- @param #MISSION self -- @param #MISSION self
-- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player joining the Mission. -- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player joining the Mission.
-- @param Wrapper.Group#GROUP PlayerGroup The GROUP of the player joining the Mission.
-- @return #boolean true if Unit is part of a Task in the Mission. -- @return #boolean true if Unit is part of a Task in the Mission.
function MISSION:JoinUnit( PlayerUnit ) function MISSION:JoinUnit( PlayerUnit, PlayerGroup )
self:F( { PlayerUnit = PlayerUnit } ) self:F( { PlayerUnit = PlayerUnit, PlayerGroup = PlayerGroup } )
local PlayerUnitAdded = false local PlayerUnitAdded = false
for TaskID, Task in pairs( self:GetTasks() ) do for TaskID, Task in pairs( self:GetTasks() ) do
local Task = Task -- Tasking.Task#TASK local Task = Task -- Tasking.Task#TASK
if Task:JoinUnit( PlayerUnit ) then if Task:JoinUnit( PlayerUnit, PlayerGroup ) then
PlayerUnitAdded = true PlayerUnitAdded = true
end end
end end
@ -30125,14 +30206,14 @@ end
-- If the Unit is part of the Task, true is returned. -- If the Unit is part of the Task, true is returned.
-- @param #TASK self -- @param #TASK self
-- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player joining the Mission. -- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player joining the Mission.
-- @param Wrapper.Group#GROUP PlayerGroup The GROUP of the player joining the Mission.
-- @return #boolean true if Unit is part of the Task. -- @return #boolean true if Unit is part of the Task.
function TASK:JoinUnit( PlayerUnit ) function TASK:JoinUnit( PlayerUnit, PlayerGroup )
self:F( { PlayerUnit = PlayerUnit } ) self:F( { PlayerUnit = PlayerUnit, PlayerGroup = PlayerGroup } )
local PlayerUnitAdded = false local PlayerUnitAdded = false
local PlayerGroups = self:GetGroups() local PlayerGroups = self:GetGroups()
local PlayerGroup = PlayerUnit:GetGroup()
-- Is the PlayerGroup part of the PlayerGroups? -- Is the PlayerGroup part of the PlayerGroups?
if PlayerGroups:IsIncludeObject( PlayerGroup ) then if PlayerGroups:IsIncludeObject( PlayerGroup ) then
@ -30285,7 +30366,6 @@ end
-- @return #boolean -- @return #boolean
function TASK:HasGroup( FindGroup ) function TASK:HasGroup( FindGroup )
self:GetGroups():FilterOnce() -- Ensure that the filter is updated.
return self:GetGroups():IsIncludeObject( FindGroup ) return self:GetGroups():IsIncludeObject( FindGroup )
end end
@ -30911,7 +30991,7 @@ end
end -- Reporting end -- Reporting
-- This module contains the DETECTION_MANAGER class and derived classes. --- This module contains the DETECTION_MANAGER class and derived classes.
-- --
-- === -- ===
-- --

View File

@ -1,5 +1,5 @@
env.info( '*** MOOSE STATIC INCLUDE START *** ' ) env.info( '*** MOOSE STATIC INCLUDE START *** ' )
env.info( 'Moose Generation Timestamp: "20170202_2257"' ) env.info( 'Moose Generation Timestamp: 20170203_2208' )
local base = _G local base = _G
Include = {} Include = {}
@ -4211,6 +4211,7 @@ end
EVENT = { EVENT = {
ClassName = "EVENT", ClassName = "EVENT",
ClassID = 0, ClassID = 0,
SortedEvents = {},
} }
local _EVENTCODES = { local _EVENTCODES = {
@ -4240,6 +4241,33 @@ local _EVENTCODES = {
"S_EVENT_MAX", "S_EVENT_MAX",
} }
local _EVENTORDER = {
[world.event.S_EVENT_SHOT] = 1,
[world.event.S_EVENT_HIT] = 1,
[world.event.S_EVENT_TAKEOFF] = 1,
[world.event.S_EVENT_LAND] = 1,
[world.event.S_EVENT_CRASH] = -1,
[world.event.S_EVENT_EJECTION] = -1,
[world.event.S_EVENT_REFUELING] = 1,
[world.event.S_EVENT_DEAD] = -1,
[world.event.S_EVENT_PILOT_DEAD] = -1,
[world.event.S_EVENT_BASE_CAPTURED] = 1,
[world.event.S_EVENT_MISSION_START] = 1,
[world.event.S_EVENT_MISSION_END] = -1,
[world.event.S_EVENT_TOOK_CONTROL] = 1,
[world.event.S_EVENT_REFUELING_STOP] = 1,
[world.event.S_EVENT_BIRTH] = 1,
[world.event.S_EVENT_HUMAN_FAILURE] = 1,
[world.event.S_EVENT_ENGINE_STARTUP] = 1,
[world.event.S_EVENT_ENGINE_SHUTDOWN] = 1,
[world.event.S_EVENT_PLAYER_ENTER_UNIT] = 1,
[world.event.S_EVENT_PLAYER_LEAVE_UNIT] = -1,
[world.event.S_EVENT_PLAYER_COMMENT] = 1,
[world.event.S_EVENT_SHOOTING_START] = 1,
[world.event.S_EVENT_SHOOTING_END] = 1,
[world.event.S_EVENT_MAX] = 1,
}
--- The Event structure --- The Event structure
-- @type EVENTDATA -- @type EVENTDATA
-- @field id -- @field id
@ -4292,7 +4320,7 @@ function EVENT:Init( EventID, EventClass )
if not self.Events[EventID] then if not self.Events[EventID] then
-- Create a WEAK table to ensure that the garbage collector is cleaning the event links when the object usage is cleaned. -- Create a WEAK table to ensure that the garbage collector is cleaning the event links when the object usage is cleaned.
self.Events[EventID] = setmetatable( {}, { __mode = "k" } ) self.Events[EventID] = setmetatable( {}, { __mode = "k" } )
self.SortedEvents[EventID] = setmetatable( {}, { __mode = "k" } )
end end
if not self.Events[EventID][EventClass] then if not self.Events[EventID][EventClass] then
@ -4311,6 +4339,12 @@ function EVENT:Remove( EventClass, EventID )
local EventClass = EventClass local EventClass = EventClass
self.Events[EventID][EventClass] = nil self.Events[EventID][EventClass] = nil
self.SortedEvents[EventID] = nil
self.SortedEvents[EventID] = {}
for EventClass, Event in pairs(self.Events[EventID]) do table.insert( self.SortedEvents[EventID], Event) end
table.sort( self.SortedEvents[EventID], function( Event1, Event2 ) return Event1.EventTime < Event2.EventTime end )
end end
--- Clears all event subscriptions for a @{Core.Base#BASE} derived object. --- Clears all event subscriptions for a @{Core.Base#BASE} derived object.
@ -4322,6 +4356,7 @@ function EVENT:RemoveAll( EventObject )
local EventClass = EventObject:GetClassNameAndID() local EventClass = EventObject:GetClassNameAndID()
for EventID, EventData in pairs( self.Events ) do for EventID, EventData in pairs( self.Events ) do
self.Events[EventID][EventClass] = nil self.Events[EventID][EventClass] = nil
self.SortedEvents[EventID] = nil
end end
end end
@ -4355,6 +4390,13 @@ function EVENT:OnEventGeneric( EventFunction, EventClass, EventID )
local Event = self:Init( EventID, EventClass ) local Event = self:Init( EventID, EventClass )
Event.EventFunction = EventFunction Event.EventFunction = EventFunction
Event.EventClass = EventClass Event.EventClass = EventClass
Event.EventTime = EventClass.EventPriority and EventClass.EventPriority or 10
self.SortedEvents[EventID] = nil
self.SortedEvents[EventID] = {}
for EventClass, Event in pairs(self.Events[EventID]) do table.insert( self.SortedEvents[EventID], Event) end
table.sort( self.SortedEvents[EventID], function( Event1, Event2 ) return Event1.EventTime < Event2.EventTime end )
return self return self
end end
@ -4931,6 +4973,8 @@ function EVENT:onEvent( Event )
Event.IniDCSGroupName = "" Event.IniDCSGroupName = ""
if Event.IniDCSGroup and Event.IniDCSGroup:isExist() then if Event.IniDCSGroup and Event.IniDCSGroup:isExist() then
Event.IniDCSGroupName = Event.IniDCSGroup:getName() Event.IniDCSGroupName = Event.IniDCSGroup:getName()
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
self:E( { IniGroup = Event.IniGroup } )
end end
end end
if Event.target then if Event.target then
@ -4953,11 +4997,27 @@ function EVENT:onEvent( Event )
end end
self:E( { _EVENTCODES[Event.id], Event, Event.IniDCSUnitName, Event.TgtDCSUnitName } ) self:E( { _EVENTCODES[Event.id], Event, Event.IniDCSUnitName, Event.TgtDCSUnitName } )
-- Okay, we got the event from DCS. Now loop the self.Events[] table for the received Event.id, and for each EventData registered, check if a function needs to be called. local function pairsByEventSorted( EventSorted, Order )
for EventClass, EventData in pairs( self.Events[Event.id] ) do local i = Order == -1 and #EventSorted or 0
local iter = function()
i = i + Order
if EventSorted[i] == nil then
return nil
else
return EventSorted[i].EventClass, EventSorted[i]
end
end
return iter
end
self:E( { Order = _EVENTORDER[Event.id] } )
-- Okay, we got the event from DCS. Now loop the SORTED self.EventSorted[] table for the received Event.id, and for each EventData registered, check if a function needs to be called.
for EventClass, EventData in pairsByEventSorted( self.SortedEvents[Event.id], _EVENTORDER[Event.id] ) do
-- If the EventData is for a UNIT, the call directly the EventClass EventFunction for that UNIT. -- If the EventData is for a UNIT, the call directly the EventClass EventFunction for that UNIT.
if Event.IniDCSUnitName and EventData.IniUnit and EventData.IniUnit[Event.IniDCSUnitName] then if Event.IniDCSUnitName and EventData.IniUnit and EventData.IniUnit[Event.IniDCSUnitName] then
self:T( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName } ) self:E( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventData.EventTime } )
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
local Result, Value = xpcall( function() return EventData.IniUnit[Event.IniDCSUnitName].EventFunction( EventData.IniUnit[Event.IniDCSUnitName].EventClass, Event ) end, ErrorHandler ) local Result, Value = xpcall( function() return EventData.IniUnit[Event.IniDCSUnitName].EventFunction( EventData.IniUnit[Event.IniDCSUnitName].EventClass, Event ) end, ErrorHandler )
--EventData.IniUnit[Event.IniDCSUnitName].EventFunction( EventData.IniUnit[Event.IniDCSUnitName].EventClass, Event ) --EventData.IniUnit[Event.IniDCSUnitName].EventFunction( EventData.IniUnit[Event.IniDCSUnitName].EventClass, Event )
else else
@ -4965,7 +5025,8 @@ function EVENT:onEvent( Event )
-- Note that here the EventFunction will need to implement and determine the logic for the relevant source- or target unit, or weapon. -- Note that here the EventFunction will need to implement and determine the logic for the relevant source- or target unit, or weapon.
if Event.IniDCSUnit and not EventData.IniUnit then if Event.IniDCSUnit and not EventData.IniUnit then
if EventClass == EventData.EventClass then if EventClass == EventData.EventClass then
self:T( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID() } ) self:E( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID(), EventData.EventTime } )
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
local Result, Value = xpcall( function() return EventData.EventFunction( EventData.EventClass, Event ) end, ErrorHandler ) local Result, Value = xpcall( function() return EventData.EventFunction( EventData.EventClass, Event ) end, ErrorHandler )
--EventData.EventFunction( EventData.EventClass, Event ) --EventData.EventFunction( EventData.EventClass, Event )
end end
@ -6761,6 +6822,8 @@ DATABASE = {
CLIENTS = {}, CLIENTS = {},
AIRBASES = {}, AIRBASES = {},
NavPoints = {}, NavPoints = {},
EventPriority = 1, -- Used to sort the DCS event order processing (complicated). Database has highest priority.
} }
local _DATABASECoalition = local _DATABASECoalition =
@ -6934,6 +6997,7 @@ end
function DATABASE:AddGroup( GroupName ) function DATABASE:AddGroup( GroupName )
if not self.GROUPS[GroupName] then if not self.GROUPS[GroupName] then
self:E( { "Add GROUP:", GroupName } )
self.GROUPS[GroupName] = GROUP:Register( GroupName ) self.GROUPS[GroupName] = GROUP:Register( GroupName )
end end
@ -7275,6 +7339,8 @@ function DATABASE:_EventOnPlayerEnterUnit( Event )
self:F2( { Event } ) self:F2( { Event } )
if Event.IniUnit then if Event.IniUnit then
self:AddUnit( Event.IniDCSUnitName )
self:AddGroup( Event.IniDCSGroupName )
local PlayerName = Event.IniUnit:GetPlayerName() local PlayerName = Event.IniUnit:GetPlayerName()
if not self.PLAYERS[PlayerName] then if not self.PLAYERS[PlayerName] then
self:AddPlayer( Event.IniUnitName, PlayerName ) self:AddPlayer( Event.IniUnitName, PlayerName )
@ -7725,6 +7791,7 @@ SET_BASE = {
Filter = {}, Filter = {},
Set = {}, Set = {},
List = {}, List = {},
EventPriority = 2, -- Used to sort the DCS event order processing (complicated)
} }
--- Creates a new SET_BASE object, building a set of units belonging to a coalitions, categories, countries, types or with defined prefix names. --- Creates a new SET_BASE object, building a set of units belonging to a coalitions, categories, countries, types or with defined prefix names.
@ -22402,7 +22469,7 @@ function AIRBASEPOLICE_BASE:_AirbaseMonitor()
Client:SetState( self, "Warnings", SpeedingWarnings + 1 ) Client:SetState( self, "Warnings", SpeedingWarnings + 1 )
else else
MESSAGE:New( "Player " .. Client:GetPlayerName() .. " has been removed from the airbase, due to a speeding violation ...", 10, "Airbase Police" ):ToAll() MESSAGE:New( "Player " .. Client:GetPlayerName() .. " has been removed from the airbase, due to a speeding violation ...", 10, "Airbase Police" ):ToAll()
Client:GetGroup():Destroy() Client:Destroy()
Client:SetState( self, "Speeding", false ) Client:SetState( self, "Speeding", false )
Client:SetState( self, "Warnings", 0 ) Client:SetState( self, "Warnings", 0 )
end end
@ -28749,7 +28816,8 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
local PlayerUnit = EventData.IniUnit local PlayerUnit = EventData.IniUnit
for MissionID, Mission in pairs( self:GetMissions() ) do for MissionID, Mission in pairs( self:GetMissions() ) do
local Mission = Mission -- Tasking.Mission#MISSION local Mission = Mission -- Tasking.Mission#MISSION
Mission:JoinUnit( PlayerUnit ) local PlayerGroup = EventData.IniGroup -- The GROUP object should be filled!
Mission:JoinUnit( PlayerUnit, PlayerGroup )
Mission:ReportDetails() Mission:ReportDetails()
end end
@ -28768,7 +28836,8 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
local PlayerUnit = EventData.IniUnit local PlayerUnit = EventData.IniUnit
for MissionID, Mission in pairs( self:GetMissions() ) do for MissionID, Mission in pairs( self:GetMissions() ) do
local Mission = Mission -- Tasking.Mission#MISSION local Mission = Mission -- Tasking.Mission#MISSION
Mission:JoinUnit( PlayerUnit ) local PlayerGroup = EventData.IniGroup -- The GROUP object should be filled!
Mission:JoinUnit( PlayerUnit, PlayerGroup )
Mission:ReportDetails() Mission:ReportDetails()
end end
end end
@ -28783,6 +28852,7 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
function( self, EventData ) function( self, EventData )
local PlayerUnit = EventData.IniUnit local PlayerUnit = EventData.IniUnit
for MissionID, Mission in pairs( self:GetMissions() ) do for MissionID, Mission in pairs( self:GetMissions() ) do
local Mission = Mission -- Tasking.Mission#MISSION
Mission:AbortUnit( PlayerUnit ) Mission:AbortUnit( PlayerUnit )
end end
end end
@ -29050,15 +29120,16 @@ end
-- If the Unit is part of a Task in the Mission, true is returned. -- If the Unit is part of a Task in the Mission, true is returned.
-- @param #MISSION self -- @param #MISSION self
-- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player joining the Mission. -- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player joining the Mission.
-- @param Wrapper.Group#GROUP PlayerGroup The GROUP of the player joining the Mission.
-- @return #boolean true if Unit is part of a Task in the Mission. -- @return #boolean true if Unit is part of a Task in the Mission.
function MISSION:JoinUnit( PlayerUnit ) function MISSION:JoinUnit( PlayerUnit, PlayerGroup )
self:F( { PlayerUnit = PlayerUnit } ) self:F( { PlayerUnit = PlayerUnit, PlayerGroup = PlayerGroup } )
local PlayerUnitAdded = false local PlayerUnitAdded = false
for TaskID, Task in pairs( self:GetTasks() ) do for TaskID, Task in pairs( self:GetTasks() ) do
local Task = Task -- Tasking.Task#TASK local Task = Task -- Tasking.Task#TASK
if Task:JoinUnit( PlayerUnit ) then if Task:JoinUnit( PlayerUnit, PlayerGroup ) then
PlayerUnitAdded = true PlayerUnitAdded = true
end end
end end
@ -30135,14 +30206,14 @@ end
-- If the Unit is part of the Task, true is returned. -- If the Unit is part of the Task, true is returned.
-- @param #TASK self -- @param #TASK self
-- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player joining the Mission. -- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player joining the Mission.
-- @param Wrapper.Group#GROUP PlayerGroup The GROUP of the player joining the Mission.
-- @return #boolean true if Unit is part of the Task. -- @return #boolean true if Unit is part of the Task.
function TASK:JoinUnit( PlayerUnit ) function TASK:JoinUnit( PlayerUnit, PlayerGroup )
self:F( { PlayerUnit = PlayerUnit } ) self:F( { PlayerUnit = PlayerUnit, PlayerGroup = PlayerGroup } )
local PlayerUnitAdded = false local PlayerUnitAdded = false
local PlayerGroups = self:GetGroups() local PlayerGroups = self:GetGroups()
local PlayerGroup = PlayerUnit:GetGroup()
-- Is the PlayerGroup part of the PlayerGroups? -- Is the PlayerGroup part of the PlayerGroups?
if PlayerGroups:IsIncludeObject( PlayerGroup ) then if PlayerGroups:IsIncludeObject( PlayerGroup ) then
@ -30295,7 +30366,6 @@ end
-- @return #boolean -- @return #boolean
function TASK:HasGroup( FindGroup ) function TASK:HasGroup( FindGroup )
self:GetGroups():FilterOnce() -- Ensure that the filter is updated.
return self:GetGroups():IsIncludeObject( FindGroup ) return self:GetGroups():IsIncludeObject( FindGroup )
end end