From c1191e286af760d0ed3ede4bd1921bb0d165289f Mon Sep 17 00:00:00 2001 From: FlightControl Date: Tue, 11 Sep 2018 09:00:30 +0200 Subject: [PATCH 1/4] Added the new event S_EVENT_REMOVE_UNIT to trigger the removal of units (from groups also) when a :Destroy(false) or :Destroy() is called for a UNIT object. The units are then removed from each SET that is subscribed to a set of UNIT objects or GROUP objects! Also the DATABASE is correctly managing this new removal method. This to prevent the DATABASE getting corrupted with dead units, which were removed with :Destroy(), but which weren't cleaned from the database. --- Moose Development/Moose/Core/Base.lua | 16 ++++++++++ Moose Development/Moose/Core/Database.lua | 7 +--- Moose Development/Moose/Core/Event.lua | 14 ++++++-- Moose Development/Moose/Core/Set.lua | 4 ++- Moose Development/Moose/Wrapper/Group.lua | 6 ++-- .../Moose/Wrapper/Positionable.lua | 32 +++++++++++++++++++ Moose Development/Moose/Wrapper/Unit.lua | 28 ---------------- 7 files changed, 68 insertions(+), 39 deletions(-) diff --git a/Moose Development/Moose/Core/Base.lua b/Moose Development/Moose/Core/Base.lua index 1b4d96efb..3d6af24d3 100644 --- a/Moose Development/Moose/Core/Base.lua +++ b/Moose Development/Moose/Core/Base.lua @@ -656,6 +656,22 @@ function BASE:CreateEventDead( EventTime, Initiator ) world.onEvent( Event ) end +--- Creation of a Remove Unit Event. +-- @param #BASE self +-- @param DCS#Time EventTime The time stamp of the event. +-- @param DCS#Object Initiator The initiating object of the event. +function BASE:CreateEventRemoveUnit( EventTime, Initiator ) + self:F( { EventTime, Initiator } ) + + local Event = { + id = EVENTS.RemoveUnit, + time = EventTime, + initiator = Initiator, + } + + world.onEvent( Event ) +end + --- Creation of a Takeoff Event. -- @param #BASE self -- @param DCS#Time EventTime The time stamp of the event. diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index e497e306d..913ec4fe9 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -95,6 +95,7 @@ function DATABASE:New() self:HandleEvent( EVENTS.Birth, self._EventOnBirth ) self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash ) self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash ) + self:HandleEvent( EVENTS.RemoveUnit, self._EventOnDeadOrCrash ) self:HandleEvent( EVENTS.Hit, self.AccountHits ) self:HandleEvent( EVENTS.NewCargo ) self:HandleEvent( EVENTS.DeleteCargo ) @@ -1347,18 +1348,12 @@ end self:T( { TargetUnitName, TargetGroupName, TargetPlayerName, TargetCoalition, TargetCategory, TargetType } ) end - self:T( "Something got destroyed" ) - local Destroyed = false -- What is the player destroying? if self.HITS[Event.IniUnitName] then -- Was there a hit for this unit for this player before registered??? - - self.DESTROYS[Event.IniUnitName] = self.DESTROYS[Event.IniUnitName] or {} - self.DESTROYS[Event.IniUnitName] = true - end end diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index c7f937c8b..c493a453f 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -181,6 +181,8 @@ world.event.S_EVENT_NEW_CARGO = world.event.S_EVENT_MAX + 1000 world.event.S_EVENT_DELETE_CARGO = world.event.S_EVENT_MAX + 1001 world.event.S_EVENT_NEW_ZONE = world.event.S_EVENT_MAX + 1002 world.event.S_EVENT_DELETE_ZONE = world.event.S_EVENT_MAX + 1003 +world.event.S_EVENT_REMOVE_UNIT = world.event.S_EVENT_MAX + 1004 + --- The different types of events supported by MOOSE. -- Use this structure to subscribe to events using the @{Core.Base#BASE.HandleEvent}() method. @@ -216,6 +218,7 @@ EVENTS = { DeleteCargo = world.event.S_EVENT_DELETE_CARGO, NewZone = world.event.S_EVENT_NEW_ZONE, DeleteZone = world.event.S_EVENT_DELETE_ZONE, + RemoveUnit = world.event.S_EVENT_REMOVE_UNIT, } --- The Event structure @@ -441,6 +444,11 @@ local _EVENTMETA = { Event = "OnEventDeleteZone", Text = "S_EVENT_DELETE_ZONE" }, + [EVENTS.RemoveUnit] = { + Order = -1, + Event = "OnEventRemoveUnit", + Text = "S_EVENT_REMOVE_UNIT" + }, } @@ -985,7 +993,8 @@ function EVENT:onEvent( Event ) if EventClass:IsAlive() or Event.id == EVENTS.PlayerEnterUnit or Event.id == EVENTS.Crash or - Event.id == EVENTS.Dead then + Event.id == EVENTS.Dead or + Event.id == EVENTS.RemoveUnit then local UnitName = EventClass:GetName() @@ -1035,7 +1044,8 @@ function EVENT:onEvent( Event ) if EventClass:IsAlive() or Event.id == EVENTS.PlayerEnterUnit or Event.id == EVENTS.Crash or - Event.id == EVENTS.Dead then + Event.id == EVENTS.Dead or + Event.id == EVENTS.RemoveUnit then -- We can get the name of the EventClass, which is now always a GROUP object. local GroupName = EventClass:GetName() diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index 650c22323..262cbed56 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -1023,6 +1023,7 @@ function SET_GROUP:FilterStart() self:HandleEvent( EVENTS.Birth, self._EventOnBirth ) self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash ) self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash ) + self:HandleEvent( EVENTS.RemoveUnit, self._EventOnDeadOrCrash ) end @@ -1804,8 +1805,9 @@ do -- SET_UNIT if _DATABASE then self:_FilterStart() self:HandleEvent( EVENTS.Birth, self._EventOnBirth ) - self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash ) + self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrashOr ) self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash ) + self:HandleEvent( EVENTS.RemoveUnit, self._EventOnDeadOrCrash ) end return self diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 81d26911e..dc31a60d6 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -261,13 +261,15 @@ function GROUP:Destroy( GenerateEvent ) local DCSGroup = self:GetDCSObject() if DCSGroup then - if GenerateEvent and GenerateEvent == true then - for Index, UnitData in pairs( DCSGroup:getUnits() ) do + for Index, UnitData in pairs( DCSGroup:getUnits() ) do + if GenerateEvent and GenerateEvent == true then if self:IsAir() then self:CreateEventCrash( timer.getTime(), UnitData ) else self:CreateEventDead( timer.getTime(), UnitData ) end + else + self:CreateEventRemove( timer.getTime(), UnitData ) end end USERFLAG:New( self:GetName() ):Set( 100 ) diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index aabd88670..20bbfe9d2 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -69,6 +69,38 @@ function POSITIONABLE:New( PositionableName ) return self end +--- Destroys the POSITIONABLE. +-- @param #POSITIONABLE self +-- @param #boolean GenerateEvent (Optional) true if you want to generate a crash or dead event for the unit. +-- @return #nil The DCS Unit is not existing or alive. +function POSITIONABLE:Destroy( GenerateEvent ) + self:F2( self.ObjectName ) + + local DCSObject = self:GetDCSObject() + + if DCSObject then + + local UnitGroup = self:GetGroup() + local UnitGroupName = UnitGroup:GetName() + self:F( { UnitGroupName = UnitGroupName } ) + + if GenerateEvent and GenerateEvent == true then + if self:IsAir() then + self:CreateEventCrash( timer.getTime(), DCSObject ) + else + self:CreateEventDead( timer.getTime(), DCSObject ) + end + else + self:CreateEventRemoveUnit( timer.getTime(), DCSObject ) + end + + USERFLAG:New( UnitGroupName ):Set( 100 ) + DCSObject:destroy() + end + + return nil +end + --- Returns the @{DCS#Position3} position vectors indicating the point and direction vectors in 3D of the POSITIONABLE within the mission. -- @param Wrapper.Positionable#POSITIONABLE self -- @return DCS#Position The 3D position vectors of the POSITIONABLE. diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index 059a0266c..f50ca5c61 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -157,35 +157,7 @@ function UNIT:GetDCSObject() return nil end ---- Destroys the UNIT. --- @param #UNIT self --- @param #boolean GenerateEvent (Optional) true if you want to generate a crash or dead event for the unit. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:Destroy( GenerateEvent ) - self:F2( self.ObjectName ) - local DCSObject = self:GetDCSObject() - - if DCSObject then - - local UnitGroup = self:GetGroup() - local UnitGroupName = UnitGroup:GetName() - self:F( { UnitGroupName = UnitGroupName } ) - - if GenerateEvent and GenerateEvent == true then - if self:IsAir() then - self:CreateEventCrash( timer.getTime(), DCSObject ) - else - self:CreateEventDead( timer.getTime(), DCSObject ) - end - end - - USERFLAG:New( UnitGroupName ):Set( 100 ) - DCSObject:destroy() - end - - return nil -end --- Respawn the @{Wrapper.Unit} using a (tweaked) template of the parent Group. From 9647a1a84e329de064039a67d4df284b6d1e252f Mon Sep 17 00:00:00 2001 From: FlightControl Date: Tue, 11 Sep 2018 10:04:33 +0200 Subject: [PATCH 2/4] Implementation of unit maintenance in DATABASE and SETs for Cargo objects. Pls retest. --- Moose Development/Moose/Cargo/Cargo.lua | 2 +- Moose Development/Moose/Cargo/CargoCrate.lua | 1 + Moose Development/Moose/Cargo/CargoGroup.lua | 5 +++-- Moose Development/Moose/Cargo/CargoSlingload.lua | 1 + 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index a8cd46b66..433836ba5 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -531,7 +531,7 @@ do -- CARGO -- @param #CARGO self function CARGO:Destroy() if self.CargoObject then - self.CargoObject:Destroy( false ) + self.CargoObject:Destroy() end self:Destroyed() end diff --git a/Moose Development/Moose/Cargo/CargoCrate.lua b/Moose Development/Moose/Cargo/CargoCrate.lua index a1258d633..fce280625 100644 --- a/Moose Development/Moose/Cargo/CargoCrate.lua +++ b/Moose Development/Moose/Cargo/CargoCrate.lua @@ -63,6 +63,7 @@ do -- CARGO_CRATE self:HandleEvent( EVENTS.Dead, self.OnEventCargoDead ) self:HandleEvent( EVENTS.Crash, self.OnEventCargoDead ) + self:HandleEvent( EVENTS.RemoveUnit, self.OnEventCargoDead ) self:HandleEvent( EVENTS.PlayerLeaveUnit, self.OnEventCargoDead ) self:SetEventPriority( 4 ) diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua index 9bb3a8c1b..aa0917810 100644 --- a/Moose Development/Moose/Cargo/CargoGroup.lua +++ b/Moose Development/Moose/Cargo/CargoGroup.lua @@ -69,7 +69,7 @@ do -- CARGO_GROUP local WeightGroup = 0 local VolumeGroup = 0 - self.CargoGroup:Destroy( true ) -- generate the crash events, so that the database gets cleaned, and the linked sets get properly cleaned. + self.CargoGroup:Destroy() -- destroy and generate a unit removal event, so that the database gets cleaned, and the linked sets get properly cleaned. local GroupName = CargoGroup:GetName() self.CargoName = Name @@ -121,6 +121,7 @@ do -- CARGO_GROUP self:HandleEvent( EVENTS.Dead, self.OnEventCargoDead ) self:HandleEvent( EVENTS.Crash, self.OnEventCargoDead ) + self:HandleEvent( EVENTS.RemoveUnit, self.OnEventCargoDead ) self:HandleEvent( EVENTS.PlayerLeaveUnit, self.OnEventCargoDead ) self:SetEventPriority( 4 ) @@ -137,7 +138,7 @@ do -- CARGO_GROUP for CargoID, CargoData in pairs( self.CargoSet:GetSet() ) do local Cargo = CargoData -- Cargo.Cargo#CARGO - Cargo:Destroy() + Cargo:Destroy() -- Destroy the cargo and generate a remove unit event to update the sets. Cargo:SetStartState( "UnLoaded" ) end diff --git a/Moose Development/Moose/Cargo/CargoSlingload.lua b/Moose Development/Moose/Cargo/CargoSlingload.lua index 452bbe3e8..c22fdb38b 100644 --- a/Moose Development/Moose/Cargo/CargoSlingload.lua +++ b/Moose Development/Moose/Cargo/CargoSlingload.lua @@ -56,6 +56,7 @@ do -- CARGO_SLINGLOAD self:HandleEvent( EVENTS.Dead, self.OnEventCargoDead ) self:HandleEvent( EVENTS.Crash, self.OnEventCargoDead ) + self:HandleEvent( EVENTS.RemoveUnit, self.OnEventCargoDead ) self:HandleEvent( EVENTS.PlayerLeaveUnit, self.OnEventCargoDead ) self:SetEventPriority( 4 ) From d5e2365bb370a4d8bd871f8c120bdbda56b95b7d Mon Sep 17 00:00:00 2001 From: FlightControl Date: Tue, 11 Sep 2018 15:26:23 +0200 Subject: [PATCH 3/4] More updates to fix the RemoveUnit problems for DATABASE and SETs. --- Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua | 4 ++-- Moose Development/Moose/Wrapper/Group.lua | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua index 4b40ae379..6d390c500 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua @@ -885,7 +885,7 @@ function AI_CARGO_DISPATCHER:onafterMonitor() -- The Pickup sequence ... -- Check if this Carrier need to go and Pickup something... -- So, if the cargo bay is not full yet with cargo to be loaded ... - self:I( { IsRelocating = AI_Cargo:IsRelocating(), IsTransporting = AI_Cargo:IsTransporting() } ) + self:I( { Carrier = CarrierGroupName, IsRelocating = AI_Cargo:IsRelocating(), IsTransporting = AI_Cargo:IsTransporting() } ) if AI_Cargo:IsRelocating() == false and AI_Cargo:IsTransporting() == false then -- ok, so there is a free Carrier -- now find the first cargo that is Unloaded @@ -944,7 +944,7 @@ function AI_CARGO_DISPATCHER:onafterMonitor() if self.HomeZone then if not self.CarrierHome[Carrier] then self.CarrierHome[Carrier] = true - AI_Cargo:__Home( 60, self.HomeZone:GetRandomPointVec2(), math.random( self.PickupMinSpeed, self.PickupMaxSpeed ), self.HomeZone ) + AI_Cargo:Home( self.HomeZone:GetRandomPointVec2(), math.random( self.PickupMinSpeed, self.PickupMaxSpeed ), self.HomeZone ) end end end diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index dc31a60d6..44ca57d5f 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -269,7 +269,7 @@ function GROUP:Destroy( GenerateEvent ) self:CreateEventDead( timer.getTime(), UnitData ) end else - self:CreateEventRemove( timer.getTime(), UnitData ) + self:CreateEventRemoveUnit( timer.getTime(), UnitData ) end end USERFLAG:New( self:GetName() ):Set( 100 ) From 9c9633ba23c1472d187b7c1968054e083b30d9b0 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Tue, 11 Sep 2018 20:38:09 +0200 Subject: [PATCH 4/4] Added FilterActive() method in SET\_UNIT, SET\GROUP, SET\_CLIENT. Haven't tested the behaviour for CLIENTs joining and leaving. --- Moose Development/Moose/AI/AI_Cargo.lua | 2 +- Moose Development/Moose/Cargo/CargoGroup.lua | 3 +- Moose Development/Moose/Core/Set.lua | 214 ++++++++++++++----- Moose Development/Moose/Core/Settings.lua | 1 - Moose Development/Moose/Wrapper/Group.lua | 30 ++- 5 files changed, 186 insertions(+), 64 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo.lua b/Moose Development/Moose/AI/AI_Cargo.lua index 2da2566e7..1d358b735 100644 --- a/Moose Development/Moose/AI/AI_Cargo.lua +++ b/Moose Development/Moose/AI/AI_Cargo.lua @@ -178,7 +178,7 @@ function AI_CARGO:onbeforeLoad( Carrier, From, Event, To, PickupZone ) local Boarding = false - local LoadInterval = 10 + local LoadInterval = 2 local LoadDelay = 0 local Carrier_List = {} local Carrier_Weight = {} diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua index aa0917810..7c3a2530c 100644 --- a/Moose Development/Moose/Cargo/CargoGroup.lua +++ b/Moose Development/Moose/Cargo/CargoGroup.lua @@ -258,7 +258,6 @@ do -- CARGO_GROUP --- @param #CARGO_GROUP self -- @param Core.Event#EVENTDATA EventData function CARGO_GROUP:OnEventCargoDead( EventData ) - self:I( EventData ) local Destroyed = false @@ -424,7 +423,7 @@ do -- CARGO_GROUP ToVec=ToPointVec2 end Cargo:__UnBoard( Timer, ToVec, NearRadius ) - Timer = Timer + 3 + Timer = Timer + 1 end end, { NearRadius } ) diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index 262cbed56..45a0f4091 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -636,7 +636,7 @@ function SET_BASE:Flush( MasterObject ) for ObjectName, Object in pairs( self.Set ) do ObjectNames = ObjectNames .. ObjectName .. ", " end - self:I( { MasterObject = MasterObject and MasterObject:GetClassNameAndID(), "Objects in Set:", ObjectNames } ) + self:F( { MasterObject = MasterObject and MasterObject:GetClassNameAndID(), "Objects in Set:", ObjectNames } ) return ObjectNames end @@ -672,6 +672,7 @@ end -- * @{#SET_GROUP.FilterCategories}: Builds the SET_GROUP with the groups belonging to the category(ies). -- * @{#SET_GROUP.FilterCountries}: Builds the SET_GROUP with the gruops belonging to the country(ies). -- * @{#SET_GROUP.FilterPrefixes}: Builds the SET_GROUP with the groups starting with the same prefix string(s). +-- * @{#SET_GROUP.FilterActive}: Builds the SET_GROUP with the groups that are only active. Groups that are inactive (late activation) won't be included in the set! -- -- For the Category Filter, extra methods have been added: -- @@ -685,6 +686,7 @@ end -- Once the filter criteria have been set for the SET_GROUP, you can start filtering using: -- -- * @{#SET_GROUP.FilterStart}: Starts the filtering of the groups within the SET_GROUP and add or remove GROUP objects **dynamically**. +-- * @{#SET_GROUP.FilterOnce}: Filters of the groups **once**. -- -- Planned filter criteria within development are (so these are not yet available): -- @@ -783,7 +785,9 @@ SET_GROUP = { function SET_GROUP:New() -- Inherits from BASE - local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.GROUPS ) ) + local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.GROUPS ) ) -- #SET_GROUP + + self:FilterActive( false ) return self end @@ -1012,6 +1016,32 @@ function SET_GROUP:FilterPrefixes( Prefixes ) return self end +--- Builds a set of groups that are only active. +-- Only the groups that are active will be included within the set. +-- @param #SET_GROUP self +-- @param #boolean Active (optional) Include only active groups to the set. +-- Include inactive groups if you provide false. +-- @return #SET_GROUP self +-- @usage +-- +-- -- Include only active groups to the set. +-- GroupSet = SET_GROUP:New():FilterActive():FilterStart() +-- +-- -- Include only active groups to the set of the blue coalition, and filter one time. +-- GroupSet = SET_GROUP:New():FilterActive():FilterCoalition( "blue" ):FilterOnce() +-- +-- -- Include only active groups to the set of the blue coalition, and filter one time. +-- -- Later, reset to include back inactive groups to the set. +-- GroupSet = SET_GROUP:New():FilterActive():FilterCoalition( "blue" ):FilterOnce() +-- ... logic ... +-- GroupSet = SET_GROUP:New():FilterActive( false ):FilterCoalition( "blue" ):FilterOnce() +-- +function SET_GROUP:FilterActive( Active ) + Active = Active or not ( Active == false ) + self.Filter.Active = Active + return self +end + --- Starts the filtering. -- @param #SET_GROUP self @@ -1377,58 +1407,67 @@ end --- -- @param #SET_GROUP self --- @param Wrapper.Group#GROUP MooseGroup +-- @param Wrapper.Group#GROUP MGroup The group that is checked for inclusion. -- @return #SET_GROUP self -function SET_GROUP:IsIncludeObject( MooseGroup ) - self:F2( MooseGroup ) - local MooseGroupInclude = true +function SET_GROUP:IsIncludeObject( MGroup ) + self:F2( MGroup ) + local MGroupInclude = true + if self.Filter.Active ~= nil then + local MGroupActive = false + self:F( { Active = self.Filter.Active } ) + if self.Filter.Active == false or ( self.Filter.Active == true and MGroup:IsActive() == true ) then + MGroupActive = true + end + MGroupInclude = MGroupInclude and MGroupActive + end + if self.Filter.Coalitions then - local MooseGroupCoalition = false + local MGroupCoalition = false for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do - self:T3( { "Coalition:", MooseGroup:GetCoalition(), self.FilterMeta.Coalitions[CoalitionName], CoalitionName } ) - if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName] == MooseGroup:GetCoalition() then - MooseGroupCoalition = true + self:T3( { "Coalition:", MGroup:GetCoalition(), self.FilterMeta.Coalitions[CoalitionName], CoalitionName } ) + if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName] == MGroup:GetCoalition() then + MGroupCoalition = true end end - MooseGroupInclude = MooseGroupInclude and MooseGroupCoalition + MGroupInclude = MGroupInclude and MGroupCoalition end if self.Filter.Categories then - local MooseGroupCategory = false + local MGroupCategory = false for CategoryID, CategoryName in pairs( self.Filter.Categories ) do - self:T3( { "Category:", MooseGroup:GetCategory(), self.FilterMeta.Categories[CategoryName], CategoryName } ) - if self.FilterMeta.Categories[CategoryName] and self.FilterMeta.Categories[CategoryName] == MooseGroup:GetCategory() then - MooseGroupCategory = true + self:T3( { "Category:", MGroup:GetCategory(), self.FilterMeta.Categories[CategoryName], CategoryName } ) + if self.FilterMeta.Categories[CategoryName] and self.FilterMeta.Categories[CategoryName] == MGroup:GetCategory() then + MGroupCategory = true end end - MooseGroupInclude = MooseGroupInclude and MooseGroupCategory + MGroupInclude = MGroupInclude and MGroupCategory end if self.Filter.Countries then - local MooseGroupCountry = false + local MGroupCountry = false for CountryID, CountryName in pairs( self.Filter.Countries ) do - self:T3( { "Country:", MooseGroup:GetCountry(), CountryName } ) - if country.id[CountryName] == MooseGroup:GetCountry() then - MooseGroupCountry = true + self:T3( { "Country:", MGroup:GetCountry(), CountryName } ) + if country.id[CountryName] == MGroup:GetCountry() then + MGroupCountry = true end end - MooseGroupInclude = MooseGroupInclude and MooseGroupCountry + MGroupInclude = MGroupInclude and MGroupCountry end if self.Filter.GroupPrefixes then - local MooseGroupPrefix = false + local MGroupPrefix = false for GroupPrefixId, GroupPrefix in pairs( self.Filter.GroupPrefixes ) do - self:T3( { "Prefix:", string.find( MooseGroup:GetName(), GroupPrefix, 1 ), GroupPrefix } ) - if string.find( MooseGroup:GetName(), GroupPrefix:gsub ("-", "%%-"), 1 ) then - MooseGroupPrefix = true + self:T3( { "Prefix:", string.find( MGroup:GetName(), GroupPrefix, 1 ), GroupPrefix } ) + if string.find( MGroup:GetName(), GroupPrefix:gsub ("-", "%%-"), 1 ) then + MGroupPrefix = true end end - MooseGroupInclude = MooseGroupInclude and MooseGroupPrefix + MGroupInclude = MGroupInclude and MGroupPrefix end - self:T2( MooseGroupInclude ) - return MooseGroupInclude + self:T2( MGroupInclude ) + return MGroupInclude end @@ -1463,18 +1502,18 @@ do -- SET_UNIT -- * Unit types -- * Starting with certain prefix strings. -- - -- ## SET_UNIT constructor + -- ## 1) SET_UNIT constructor -- -- Create a new SET_UNIT object with the @{#SET_UNIT.New} method: -- -- * @{#SET_UNIT.New}: Creates a new SET_UNIT object. -- - -- ## Add or Remove UNIT(s) from SET_UNIT + -- ## 2) Add or Remove UNIT(s) from SET_UNIT -- -- UNITs can be added and removed using the @{Core.Set#SET_UNIT.AddUnitsByName} and @{Core.Set#SET_UNIT.RemoveUnitsByName} respectively. -- These methods take a single UNIT name or an array of UNIT names to be added or removed from SET_UNIT. -- - -- ## SET_UNIT filter criteria + -- ## 3) SET_UNIT filter criteria -- -- You can set filter criteria to define the set of units within the SET_UNIT. -- Filter criteria are defined by: @@ -1484,24 +1523,26 @@ do -- SET_UNIT -- * @{#SET_UNIT.FilterTypes}: Builds the SET_UNIT with the units belonging to the unit type(s). -- * @{#SET_UNIT.FilterCountries}: Builds the SET_UNIT with the units belonging to the country(ies). -- * @{#SET_UNIT.FilterPrefixes}: Builds the SET_UNIT with the units starting with the same prefix string(s). + -- * @{#SET_UNIT.FilterActive}: Builds the SET_UNIT with the units that are only active. Units that are inactive (late activation) won't be included in the set! -- -- Once the filter criteria have been set for the SET_UNIT, you can start filtering using: -- - -- * @{#SET_UNIT.FilterStart}: Starts the filtering of the units within the SET_UNIT. + -- * @{#SET_UNIT.FilterStart}: Starts the filtering of the units **dynamically**. + -- * @{#SET_UNIT.FilterOnce}: Filters of the units **once**. -- -- Planned filter criteria within development are (so these are not yet available): -- -- * @{#SET_UNIT.FilterZones}: Builds the SET_UNIT with the units within a @{Core.Zone#ZONE}. -- - -- ## SET_UNIT iterators + -- ## 4) SET_UNIT iterators -- -- Once the filters have been defined and the SET_UNIT has been built, you can iterate the SET_UNIT with the available iterator methods. -- The iterator methods will walk the SET_UNIT set, and call for each element within the set a function that you provide. -- The following iterator methods are currently available within the SET_UNIT: -- -- * @{#SET_UNIT.ForEachUnit}: Calls a function for each alive unit it finds within the SET_UNIT. - -- * @{#SET_GROUP.ForEachGroupCompletelyInZone}: Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence completely in a @{Zone}, providing the GROUP and optional parameters to the called function. - -- * @{#SET_GROUP.ForEachGroupNotInZone}: Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence not in a @{Zone}, providing the GROUP and optional parameters to the called function. + -- * @{#SET_UNIT.ForEachUnitInZone}: Iterate the SET_UNIT and call an iterator function for each **alive** UNIT object presence completely in a @{Zone}, providing the UNIT object and optional parameters to the called function. + -- * @{#SET_UNIT.ForEachUnitNotInZone}: Iterate the SET_UNIT and call an iterator function for each **alive** UNIT object presence not in a @{Zone}, providing the UNIT object and optional parameters to the called function. -- -- Planned iterators methods in development are (so these are not yet available): -- @@ -1509,27 +1550,17 @@ do -- SET_UNIT -- * @{#SET_UNIT.ForEachUnitCompletelyInZone}: Iterate and call an iterator function for each **alive** UNIT presence completely in a @{Zone}, providing the UNIT and optional parameters to the called function. -- * @{#SET_UNIT.ForEachUnitNotInZone}: Iterate and call an iterator function for each **alive** UNIT presence not in a @{Zone}, providing the UNIT and optional parameters to the called function. -- - -- ## SET_UNIT atomic methods + -- ## 5) SET_UNIT atomic methods -- -- Various methods exist for a SET_UNIT to perform actions or calculations and retrieve results from the SET_UNIT: -- -- * @{#SET_UNIT.GetTypeNames}(): Retrieve the type names of the @{Wrapper.Unit}s in the SET, delimited by a comma. -- - -- ## SET_UNIT iterators - -- - -- Once the filters have been defined and the SET_UNIT has been built, you can iterate the SET_UNIT with the available iterator methods. - -- The iterator methods will walk the SET_UNIT set, and call for each element within the set a function that you provide. - -- The following iterator methods are currently available within the SET_UNIT: - -- - -- * @{#SET_UNIT.ForEachUnit}: Calls a function for each alive group it finds within the SET_UNIT. - -- * @{#SET_UNIT.ForEachUnitInZone}: Iterate the SET_UNIT and call an iterator function for each **alive** UNIT object presence completely in a @{Zone}, providing the UNIT object and optional parameters to the called function. - -- * @{#SET_UNIT.ForEachUnitNotInZone}: Iterate the SET_UNIT and call an iterator function for each **alive** UNIT object presence not in a @{Zone}, providing the UNIT object and optional parameters to the called function. - -- - -- ## SET_UNIT trigger events on the UNIT objects. + -- ## 6) SET_UNIT trigger events on the UNIT objects. -- -- The SET is derived from the FSM class, which provides extra capabilities to track the contents of the UNIT objects in the SET_UNIT. -- - -- ### When a UNIT object crashes or is dead, the SET_UNIT will trigger a **Dead** event. + -- ### 6.1) When a UNIT object crashes or is dead, the SET_UNIT will trigger a **Dead** event. -- -- You can handle the event using the OnBefore and OnAfter event handlers. -- The event handlers need to have the paramters From, Event, To, GroupObject. @@ -1611,7 +1642,9 @@ do -- SET_UNIT function SET_UNIT:New() -- Inherits from BASE - local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.UNITS ) ) -- Core.Set#SET_UNIT + local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.UNITS ) ) -- #SET_UNIT + + self:FilterActive( false ) return self end @@ -1769,6 +1802,32 @@ do -- SET_UNIT return self end + --- Builds a set of units that are only active. + -- Only the units that are active will be included within the set. + -- @param #SET_UNIT self + -- @param #boolean Active (optional) Include only active units to the set. + -- Include inactive units if you provide false. + -- @return #SET_UNIT self + -- @usage + -- + -- -- Include only active units to the set. + -- UnitSet = SET_UNIT:New():FilterActive():FilterStart() + -- + -- -- Include only active units to the set of the blue coalition, and filter one time. + -- UnitSet = SET_UNIT:New():FilterActive():FilterCoalition( "blue" ):FilterOnce() + -- + -- -- Include only active units to the set of the blue coalition, and filter one time. + -- -- Later, reset to include back inactive units to the set. + -- UnitSet = SET_UNIT:New():FilterActive():FilterCoalition( "blue" ):FilterOnce() + -- ... logic ... + -- UnitSet = SET_UNIT:New():FilterActive( false ):FilterCoalition( "blue" ):FilterOnce() + -- + function SET_UNIT:FilterActive( Active ) + Active = Active or not ( Active == false ) + self.Filter.Active = Active + return self + end + --- Builds a set of units having a radar of give types. -- All the units having a radar of a given type will be included within the set. -- @param #SET_UNIT self @@ -2343,6 +2402,14 @@ do -- SET_UNIT self:F2( MUnit ) local MUnitInclude = true + if self.Filter.Active ~= nil then + local MUnitActive = false + if self.Filter.Active == false or ( self.Filter.Active == true and MUnit:IsActive() == true ) then + MUnitActive = true + end + MUnitInclude = MUnitInclude and MUnitActive + end + if self.Filter.Coalitions then local MUnitCoalition = false for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do @@ -3155,18 +3222,18 @@ end -- * Client types -- * Starting with certain prefix strings. -- --- ## SET_CLIENT constructor +-- ## 1) SET_CLIENT constructor -- -- Create a new SET_CLIENT object with the @{#SET_CLIENT.New} method: -- -- * @{#SET_CLIENT.New}: Creates a new SET_CLIENT object. -- --- ## Add or Remove CLIENT(s) from SET_CLIENT +-- ## 2) Add or Remove CLIENT(s) from SET_CLIENT -- -- CLIENTs can be added and removed using the @{Core.Set#SET_CLIENT.AddClientsByName} and @{Core.Set#SET_CLIENT.RemoveClientsByName} respectively. -- These methods take a single CLIENT name or an array of CLIENT names to be added or removed from SET_CLIENT. -- --- ## SET_CLIENT filter criteria +-- ## 3) SET_CLIENT filter criteria -- -- You can set filter criteria to define the set of clients within the SET_CLIENT. -- Filter criteria are defined by: @@ -3176,16 +3243,18 @@ end -- * @{#SET_CLIENT.FilterTypes}: Builds the SET_CLIENT with the clients belonging to the client type(s). -- * @{#SET_CLIENT.FilterCountries}: Builds the SET_CLIENT with the clients belonging to the country(ies). -- * @{#SET_CLIENT.FilterPrefixes}: Builds the SET_CLIENT with the clients starting with the same prefix string(s). +-- * @{#SET_CLIENT.FilterActive}: Builds the SET_CLIENT with the units that are only active. Units that are inactive (late activation) won't be included in the set! -- -- Once the filter criteria have been set for the SET_CLIENT, you can start filtering using: -- --- * @{#SET_CLIENT.FilterStart}: Starts the filtering of the clients within the SET_CLIENT. +-- * @{#SET_CLIENT.FilterStart}: Starts the filtering of the clients **dynamically**. +-- * @{#SET_CLIENT.FilterOnce}: Filters the clients **once**. -- -- Planned filter criteria within development are (so these are not yet available): -- -- * @{#SET_CLIENT.FilterZones}: Builds the SET_CLIENT with the clients within a @{Core.Zone#ZONE}. -- --- ## SET_CLIENT iterators +-- ## 4) SET_CLIENT iterators -- -- Once the filters have been defined and the SET_CLIENT has been built, you can iterate the SET_CLIENT with the available iterator methods. -- The iterator methods will walk the SET_CLIENT set, and call for each element within the set a function that you provide. @@ -3230,7 +3299,9 @@ SET_CLIENT = { -- DBObject = SET_CLIENT:New() function SET_CLIENT:New() -- Inherits from BASE - local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.CLIENTS ) ) + local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.CLIENTS ) ) -- #SET_CLIENT + + self:FilterActive( false ) return self end @@ -3372,6 +3443,31 @@ function SET_CLIENT:FilterPrefixes( Prefixes ) return self end +--- Builds a set of clients that are only active. +-- Only the clients that are active will be included within the set. +-- @param #SET_CLIENT self +-- @param #boolean Active (optional) Include only active clients to the set. +-- Include inactive clients if you provide false. +-- @return #SET_CLIENT self +-- @usage +-- +-- -- Include only active clients to the set. +-- ClientSet = SET_CLIENT:New():FilterActive():FilterStart() +-- +-- -- Include only active clients to the set of the blue coalition, and filter one time. +-- ClientSet = SET_CLIENT:New():FilterActive():FilterCoalition( "blue" ):FilterOnce() +-- +-- -- Include only active clients to the set of the blue coalition, and filter one time. +-- -- Later, reset to include back inactive clients to the set. +-- ClientSet = SET_CLIENT:New():FilterActive():FilterCoalition( "blue" ):FilterOnce() +-- ... logic ... +-- ClientSet = SET_CLIENT:New():FilterActive( false ):FilterCoalition( "blue" ):FilterOnce() +-- +function SET_CLIENT:FilterActive( Active ) + Active = Active or not ( Active == false ) + self.Filter.Active = Active + return self +end @@ -3482,6 +3578,14 @@ function SET_CLIENT:IsIncludeObject( MClient ) if MClient then local MClientName = MClient.UnitName + if self.Filter.Active ~= nil then + local MClientActive = false + if self.Filter.Active == false or ( self.Filter.Active == true and MClient:IsActive() == true ) then + MClientActive = true + end + MClientInclude = MClientInclude and MClientActive + end + if self.Filter.Coalitions then local MClientCoalition = false for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do diff --git a/Moose Development/Moose/Core/Settings.lua b/Moose Development/Moose/Core/Settings.lua index 819690607..20935af35 100644 --- a/Moose Development/Moose/Core/Settings.lua +++ b/Moose Development/Moose/Core/Settings.lua @@ -364,7 +364,6 @@ do -- SETTINGS -- @param #SETTINGS self -- @return #boolean true if BRA function SETTINGS:IsA2A_BRAA() - self:E( { BRA = ( self.A2ASystem and self.A2ASystem == "BRAA" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_BRAA() ) } ) return ( self.A2ASystem and self.A2ASystem == "BRAA" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_BRAA() ) end diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 44ca57d5f..470de56b4 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -205,18 +205,18 @@ function GROUP:GetPositionVec3() -- Overridden from POSITIONABLE:GetPositionVec3 return nil end ---- Returns if the Group is alive. +--- Returns if the group is alive. -- The Group must: -- -- * Exist at run-time. -- * Has at least one unit. -- --- When the first @{Wrapper.Unit} of the Group is active, it will return true. --- If the first @{Wrapper.Unit} of the Group is inactive, it will return false. +-- When the first @{Wrapper.Unit} of the group is active, it will return true. +-- If the first @{Wrapper.Unit} of the group is inactive, it will return false. -- -- @param #GROUP self --- @return #boolean true if the Group is alive and active. --- @return #boolean false if the Group is alive but inactive. +-- @return #boolean true if the group is alive and active. +-- @return #boolean false if the group is alive but inactive. -- @return #nil if the group does not exist anymore. function GROUP:IsAlive() self:F2( self.GroupName ) @@ -237,6 +237,26 @@ function GROUP:IsAlive() return nil end +--- Returns if the group is activated. +-- @param #GROUP self +-- @return #boolean true if group is activated. +-- @return #nil The group is not existing or alive. +function GROUP:IsActive() + self:F2( self.GroupName ) + + local DCSGroup = self:GetDCSObject() -- DCS#Group + + if DCSGroup then + + local GroupIsActive = DCSGroup:getUnit(1):isActive() + return GroupIsActive + end + + return nil +end + + + --- Destroys the DCS Group and all of its DCS Units. -- Note that this destroy method also can raise a destroy event at run-time. -- So all event listeners will catch the destroy event of this group for each unit in the group.