diff --git a/Moose Development/Moose/Core/Fsm.lua b/Moose Development/Moose/Core/Fsm.lua index 7a39fc64f..38ffcbf02 100644 --- a/Moose Development/Moose/Core/Fsm.lua +++ b/Moose Development/Moose/Core/Fsm.lua @@ -932,6 +932,22 @@ do -- FSM_PROCESS return NewFsm end + + --- Removes an FSM_PROCESS object. + -- @param #FSM_PROCESS self + -- @return #FSM_PROCESS + function FSM_PROCESS:Remove() + self:T( { self:GetClassNameAndID() } ) + + -- Copy Processes + for ProcessID, Process in pairs( self:GetProcesses() ) do + self:E( { Process} ) + Process.fsm:Remove() + Process.fsm = nil + end + + return self + end --- Sets the task of the process. -- @param #FSM_PROCESS self diff --git a/Moose Development/Moose/Core/ScheduleDispatcher.lua b/Moose Development/Moose/Core/ScheduleDispatcher.lua index 81ceaf3f1..a7962e677 100644 --- a/Moose Development/Moose/Core/ScheduleDispatcher.lua +++ b/Moose Development/Moose/Core/ScheduleDispatcher.lua @@ -64,7 +64,7 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr -- Initialize the ObjectSchedulers array, which is a weakly coupled table. -- If the object used as the key is nil, then the garbage collector will remove the item from the Functions array. - self.ObjectSchedulers = self.ObjectSchedulers or {} -- setmetatable( {}, { __mode = "v" } ) + self.ObjectSchedulers = self.ObjectSchedulers or setmetatable( {}, { __mode = "v" } ) -- or {} if Scheduler.MasterObject then self.ObjectSchedulers[self.CallID] = Scheduler diff --git a/Moose Development/Moose/Functional/Detection.lua b/Moose Development/Moose/Functional/Detection.lua index 5763bc583..ee8141cd9 100644 --- a/Moose Development/Moose/Functional/Detection.lua +++ b/Moose Development/Moose/Functional/Detection.lua @@ -930,6 +930,58 @@ do -- DETECTION_BASE return DetectedItem.FriendliesNearBy or false end + --- Background worker function to determine if there are friendlies nearby ... + -- @param #DETECTION_BASE self + function DETECTION_BASE:ReportFriendliesNearBy( ReportGroupData ) + self:F2() + + local DetectedItem = ReportGroupData.DetectedItem -- Functional.Detection#DETECTION_BASE.DetectedItem + local DetectedSet = ReportGroupData.DetectedItem.Set + local DetectedUnit = DetectedSet:GetFirst() + + DetectedItem.FriendliesNearBy = false + + local SphereSearch = { + id = world.VolumeType.SPHERE, + params = { + point = DetectedUnit:GetVec3(), + radius = 6000, + } + + } + + --- @param Dcs.DCSWrapper.Unit#Unit FoundDCSUnit + -- @param Wrapper.Group#GROUP ReportGroup + -- @param Set#SET_GROUP ReportSetGroup + local FindNearByFriendlies = function( FoundDCSUnit, ReportGroupData ) + + local DetectedItem = ReportGroupData.DetectedItem -- Functional.Detection#DETECTION_BASE.DetectedItem + local DetectedSet = ReportGroupData.DetectedItem.Set + local DetectedUnit = DetectedSet:GetFirst() -- Wrapper.Unit#UNIT + local ReportSetGroup = ReportGroupData.ReportSetGroup + + local EnemyCoalition = DetectedUnit:GetCoalition() + + local FoundUnitCoalition = FoundDCSUnit:getCoalition() + local FoundUnitName = FoundDCSUnit:getName() + local FoundUnitGroupName = FoundDCSUnit:getGroup():getName() + local EnemyUnitName = DetectedUnit:GetName() + local FoundUnitInReportSetGroup = ReportSetGroup:FindGroup( FoundUnitGroupName ) ~= nil + + self:T3( { "Friendlies search:", FoundUnitName, FoundUnitCoalition, EnemyUnitName, EnemyCoalition, FoundUnitInReportSetGroup } ) + + if FoundUnitCoalition ~= EnemyCoalition and FoundUnitInReportSetGroup == false then + DetectedItem.FriendliesNearBy = true + return false + end + + return true + end + + world.searchObjects( Object.Category.UNIT, SphereSearch, FindNearByFriendlies, ReportGroupData ) + + end + end --- Determines if a detected object has already been identified during detection processing. @@ -1193,6 +1245,44 @@ do -- DETECTION_UNITS return self end + + --- Make text documenting the changes of the detected zone. + -- @param #DETECTION_UNITS self + -- @param #DETECTION_UNITS.DetectedItem DetectedItem + -- @return #string The Changes text + function DETECTION_UNITS:GetChangeText( DetectedItem ) + self:F( DetectedItem ) + + local MT = {} + + for ChangeCode, ChangeData in pairs( DetectedItem.Changes ) do + + if ChangeCode == "AU" then + local MTUT = {} + for ChangeUnitType, ChangeUnitCount in pairs( ChangeData ) do + if ChangeUnitType ~= "ItemID" then + MTUT[#MTUT+1] = ChangeUnitCount .. " of " .. ChangeUnitType + end + end + MT[#MT+1] = " New target(s) detected: " .. table.concat( MTUT, ", " ) .. "." + end + + if ChangeCode == "RU" then + local MTUT = {} + for ChangeUnitType, ChangeUnitCount in pairs( ChangeData ) do + if ChangeUnitType ~= "ItemID" then + MTUT[#MTUT+1] = ChangeUnitCount .. " of " .. ChangeUnitType + end + end + MT[#MT+1] = " Invisible or destroyed target(s): " .. table.concat( MTUT, ", " ) .. "." + end + + end + + return table.concat( MT, "\n" ) + + end + --- Create the DetectedItems list from the DetectedObjects table. -- For each DetectedItem, a one field array is created containing the Unit detected. @@ -1201,24 +1291,70 @@ do -- DETECTION_UNITS function DETECTION_UNITS:CreateDetectionSets() self:F2( #self.DetectedObjects ) - self.DetectedItems = {} + -- Loop the current detected items, and check if each object still exists and is detected. + for DetectedItemID, DetectedItem in pairs( self.DetectedItems ) do + + local DetectedItemSet = DetectedItem:GetSet() -- Core.Set#SET_UNIT + local DetectedTypeName = DetectedItem.Type + + for DetectedUnitName, DetectedUnitData in pairs( DetectedItemSet ) do + local DetectedUnit = DetectedUnitData -- Wrapper.Unit#UNIT + + local DetectedObject = nil + if DetectedUnit:IsAlive() then + --self:E(DetectedUnit:GetName()) + DetectedObject = self:GetDetectedObject( DetectedUnit:GetName() ) + end + if DetectedObject then + + -- Yes, the DetectedUnit is still detected or exists. Flag as identified. + self:IdentifyDetectedObject( DetectedObject ) + else + -- There was no DetectedObject, remove DetectedUnit from the Set. + self:AddChangeUnit( DetectedItem, "RU", DetectedUnitName ) + DetectedItemSet:Remove( DetectedUnitName ) + end + end + end + + + -- Now we need to loop through the unidentified detected units and add these... These are all new items. for DetectedUnitName, DetectedObjectData in pairs( self.DetectedObjects ) do - self:T( { "Detected Unit #", DetectedUnitName } ) - - local DetectedUnit = UNIT:FindByName( DetectedUnitName ) -- Wrapper.Unit#UNIT - - if DetectedUnit then - - local DetectedItem = self:AddDetectedItem() - DetectedItem.Type = DetectedObjectData.Type - DetectedItem.Name = DetectedObjectData.Name - DetectedItem.Visible = DetectedObjectData.Visible - DetectedItem.Distance = DetectedObjectData.Distance - DetectedItem.Set:AddUnit( DetectedUnit ) + local DetectedObject = self:GetDetectedObject( DetectedUnitName ) + if DetectedObject then + self:T( { "Detected Unit #", DetectedUnitName } ) + + local DetectedUnit = UNIT:FindByName( DetectedUnitName ) -- Wrapper.Unit#UNIT + + if DetectedUnit then + local DetectedTypeName = DetectedUnit:GetTypeName() + local DetectedItem = self:GetDetectedItem( DetectedUnitName ) + if not DetectedItem then + self:T( "Added new DetectedItem" ) + DetectedItem = self:AddDetectedItem( DetectedUnitName ) + DetectedItem.Type = DetectedUnit:GetTypeName() + DetectedItem.Name = DetectedObjectData.Name + DetectedItem.Visible = DetectedObjectData.Visible + DetectedItem.Distance = DetectedObjectData.Distance + end + + DetectedItem.Set:AddUnit( DetectedUnit ) + self:AddChangeUnit( DetectedItem, "AU", DetectedTypeName ) + end end end + + for DetectedItemID, DetectedItemData in pairs( self.DetectedItems ) do + + local DetectedItem = DetectedItemData -- #DETECTION_BASE.DetectedItem + local DetectedSet = DetectedItem.Set + + self:ReportFriendliesNearBy( { DetectedItem = DetectedItem, ReportSetGroup = self.DetectionSetGroup } ) -- Fill the Friendlies table + --self:NearestFAC( DetectedItem ) + end + end --- Report summary of a DetectedItem using a given numeric index. @@ -1329,14 +1465,6 @@ do -- DETECTION_TYPES for ChangeCode, ChangeData in pairs( DetectedItem.Changes ) do - if ChangeCode == "AI" then - MT[#MT+1] = "Detected targets of new type " .. ChangeData.ItemUnitType .. "." - end - - if ChangeCode == "RI" then - MT[#MT+1] = "No more targets of type " .. ChangeData.ItemUnitType .. " detected." - end - if ChangeCode == "AU" then local MTUT = {} for ChangeUnitType, ChangeUnitCount in pairs( ChangeData ) do @@ -1344,7 +1472,7 @@ do -- DETECTION_TYPES MTUT[#MTUT+1] = ChangeUnitCount .. " of " .. ChangeUnitType end end - MT[#MT+1] = "New target(s) detected: " .. table.concat( MTUT, ", " ) .. "." + MT[#MT+1] = " New target(s) detected: " .. table.concat( MTUT, ", " ) .. "." end if ChangeCode == "RU" then @@ -1354,7 +1482,7 @@ do -- DETECTION_TYPES MTUT[#MTUT+1] = ChangeUnitCount .. " of " .. ChangeUnitType end end - MT[#MT+1] = "Invisible or destroyed target(s): " .. table.concat( MTUT, ", " ) .. "." + MT[#MT+1] = " Invisible or destroyed target(s): " .. table.concat( MTUT, ", " ) .. "." end end @@ -1396,11 +1524,6 @@ do -- DETECTION_TYPES DetectedItemSet:Remove( DetectedUnitName ) end end - - -- If all the detected units are removed from the DetectedItemSet, then we need to notify that. - if DetectedItemSet:Count() == 0 then - self:AddChangeItem( DetectedItem, "RI", DetectedTypeName ) - end end @@ -1419,7 +1542,6 @@ do -- DETECTION_TYPES if not DetectedItem then DetectedItem = self:AddDetectedItem( DetectedTypeName ) DetectedItem.Type = DetectedUnit:GetTypeName() - self:AddChangeItem( DetectedItem, "AI", DetectedTypeName ) end DetectedItem.Set:AddUnit( DetectedUnit ) @@ -1427,6 +1549,16 @@ do -- DETECTION_TYPES end end end + + for DetectedItemID, DetectedItemData in pairs( self.DetectedItems ) do + + local DetectedItem = DetectedItemData -- #DETECTION_BASE.DetectedItem + local DetectedSet = DetectedItem.Set + + self:ReportFriendliesNearBy( { DetectedItem = DetectedItem, ReportSetGroup = self.DetectionSetGroup } ) -- Fill the Friendlies table + --self:NearestFAC( DetectedItem ) + end + end --- Report summary of a DetectedItem using a given numeric index. @@ -1540,60 +1672,6 @@ do -- DETECTION_AREAS return nil end - --- Background worker function to determine if there are friendlies nearby ... - -- @param #DETECTION_AREAS self - -- @param Wrapper.Unit#UNIT ReportUnit - function DETECTION_AREAS:ReportFriendliesNearBy( ReportGroupData ) - self:F2() - - local DetectedItem = ReportGroupData.DetectedItem -- Functional.Detection#DETECTION_BASE.DetectedItem - local DetectedSet = ReportGroupData.DetectedItem.Set - local DetectedZone = ReportGroupData.DetectedItem.Zone - local DetectedZoneUnit = DetectedZone.ZoneUNIT - - DetectedItem.FriendliesNearBy = false - - local SphereSearch = { - id = world.VolumeType.SPHERE, - params = { - point = DetectedZoneUnit:GetVec3(), - radius = 6000, - } - - } - - --- @param Dcs.DCSWrapper.Unit#Unit FoundDCSUnit - -- @param Wrapper.Group#GROUP ReportGroup - -- @param Set#SET_GROUP ReportSetGroup - local FindNearByFriendlies = function( FoundDCSUnit, ReportGroupData ) - - local DetectedItem = ReportGroupData.DetectedItem -- Functional.Detection#DETECTION_BASE.DetectedItem - local DetectedSet = ReportGroupData.DetectedItem.Set - local DetectedZone = ReportGroupData.DetectedItem.Zone - local DetectedZoneUnit = DetectedZone.ZoneUNIT -- Wrapper.Unit#UNIT - local ReportSetGroup = ReportGroupData.ReportSetGroup - - local EnemyCoalition = DetectedZoneUnit:GetCoalition() - - local FoundUnitCoalition = FoundDCSUnit:getCoalition() - local FoundUnitName = FoundDCSUnit:getName() - local FoundUnitGroupName = FoundDCSUnit:getGroup():getName() - local EnemyUnitName = DetectedZoneUnit:GetName() - local FoundUnitInReportSetGroup = ReportSetGroup:FindGroup( FoundUnitGroupName ) ~= nil - - self:T3( { "Friendlies search:", FoundUnitName, FoundUnitCoalition, EnemyUnitName, EnemyCoalition, FoundUnitInReportSetGroup } ) - - if FoundUnitCoalition ~= EnemyCoalition and FoundUnitInReportSetGroup == false then - DetectedItem.FriendliesNearBy = true - return false - end - - return true - end - - world.searchObjects( Object.Category.UNIT, SphereSearch, FindNearByFriendlies, ReportGroupData ) - - end --- Returns if there are friendlies nearby the FAC units ... -- @param #DETECTION_AREAS self diff --git a/Moose Development/Moose/Tasking/Task.lua b/Moose Development/Moose/Tasking/Task.lua index 1990bd383..c08b72653 100644 --- a/Moose Development/Moose/Tasking/Task.lua +++ b/Moose Development/Moose/Tasking/Task.lua @@ -713,7 +713,9 @@ end function TASK:RemoveStateMachine( TaskUnit ) self:F( { TaskUnit, self.Fsm[TaskUnit] ~= nil } ) + self.Fsm[TaskUnit]:Remove() self.Fsm[TaskUnit] = nil + collectgarbage() self:T( "Garbage Collected, Processes should be finalized now ...") end @@ -830,6 +832,32 @@ function TASK:IsStatePlanned() return self:Is( "Planned" ) end +--- Sets a @{Task} to status **Aborted**. +-- @param #TASK self +function TASK:StateAborted() + self:SetState( self, "State", "Aborted" ) + return self +end + +--- Is the @{Task} status **Aborted**. +-- @param #TASK self +function TASK:IsStateAborted() + return self:Is( "Aborted" ) +end + +--- Sets a @{Task} to status **Cancelled**. +-- @param #TASK self +function TASK:StateCancelled() + self:SetState( self, "State", "Cancelled" ) + return self +end + +--- Is the @{Task} status **Cancelled**. +-- @param #TASK self +function TASK:IsStateCancelled() + return self:Is( "Cancelled" ) +end + --- Sets a @{Task} to status **Assigned**. -- @param #TASK self function TASK:StateAssigned() diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index ce1256f1b..75fc4c5d1 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -231,7 +231,7 @@ function GROUP:GetCategory() return nil end ---- Returns the category name of the DCS Group. +--- Returns the category name of the #GROUP. -- @param #GROUP self -- @return #string Category name = Helicopter, Airplane, Ground Unit, Ship function GROUP:GetCategoryName() diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index 697ac1616..56d26c9d9 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -522,6 +522,31 @@ function UNIT:GetLife0() return nil end +--- Returns the category name of the #UNIT. +-- @param #UNIT self +-- @return #string Category name = Helicopter, Airplane, Ground Unit, Ship +function UNIT:GetCategoryName() + self:F3( self.UnitName ) + + local DCSUnit = self:GetDCSObject() + if DCSUnit then + local CategoryNames = { + [Unit.Category.AIRPLANE] = "Airplane", + [Unit.Category.HELICOPTER] = "Helicopter", + [Unit.Category.GROUND_UNIT] = "Ground Unit", + [Unit.Category.SHIP] = "Ship", + [Unit.Category.STRUCTURE] = "Structure", + } + local UnitCategory = DCSUnit:getDesc().category + self:T3( UnitCategory ) + + return CategoryNames[UnitCategory] + end + + return nil +end + + --- Returns the Unit's A2G threat level on a scale from 1 to 10 ... -- The following threat levels are foreseen: -- diff --git a/Moose Mission Setup/Moose Mission Update/l10n/DEFAULT/Moose.lua b/Moose Mission Setup/Moose Mission Update/l10n/DEFAULT/Moose.lua index cac96a543..c4875bc19 100644 --- a/Moose Mission Setup/Moose Mission Update/l10n/DEFAULT/Moose.lua +++ b/Moose Mission Setup/Moose Mission Update/l10n/DEFAULT/Moose.lua @@ -1,5 +1,5 @@ env.info( '*** MOOSE DYNAMIC INCLUDE START *** ' ) -env.info( 'Moose Generation Timestamp: 20170312_1326' ) +env.info( 'Moose Generation Timestamp: 20170313_1139' ) local base = _G diff --git a/Moose Mission Setup/Moose.lua b/Moose Mission Setup/Moose.lua index cac96a543..c4875bc19 100644 --- a/Moose Mission Setup/Moose.lua +++ b/Moose Mission Setup/Moose.lua @@ -1,5 +1,5 @@ env.info( '*** MOOSE DYNAMIC INCLUDE START *** ' ) -env.info( 'Moose Generation Timestamp: 20170312_1326' ) +env.info( 'Moose Generation Timestamp: 20170313_1139' ) local base = _G diff --git a/Moose Test Missions/TAD - Task Dispatching/TAD-120 - A2G Task Dispatching DETECTION_UNITS/TAD-120 - A2G Task Dispatching DETECTION_UNITS.lua b/Moose Test Missions/TAD - Task Dispatching/TAD-120 - A2G Task Dispatching DETECTION_UNITS/TAD-120 - A2G Task Dispatching DETECTION_UNITS.lua new file mode 100644 index 000000000..1e355b8fb --- /dev/null +++ b/Moose Test Missions/TAD - Task Dispatching/TAD-120 - A2G Task Dispatching DETECTION_UNITS/TAD-120 - A2G Task Dispatching DETECTION_UNITS.lua @@ -0,0 +1,34 @@ + --- +-- Name: TAD-120 - A2G Task Dispatching DETECTION_UNITS +-- Author: FlightControl +-- Date Created: 13 Mar 2017 +-- +-- # Situation: +-- +-- This mission demonstrates the dynamic task dispatching for Air to Ground operations. +-- FACA's and FAC's are patrolling around the battle field, while detecting targets. +-- The detection method used is the DETECTION_UNITS method, which groups detected targets per detected unit. +-- +-- # Test cases: +-- +-- 1. Observe the FAC(A)'s detecting targets and grouping them. +-- 2. Check that the HQ provides menus to engage on a task set by the FACs. +-- +local HQ = GROUP:FindByName( "HQ", "Bravo HQ" ) + +local CommandCenter = COMMANDCENTER:New( HQ, "Lima" ) + +local Scoring = SCORING:New( "Detect Demo" ) + +local Mission = MISSION + :New( CommandCenter, "Overlord", "High", "Attack Detect Mission Briefing", coalition.side.RED ) + :AddScoring( Scoring ) + +local FACSet = SET_GROUP:New():FilterPrefixes( "FAC" ):FilterCoalitions("red"):FilterStart() + +local FACAreas = DETECTION_UNITS:New( FACSet ) + + +local AttackGroups = SET_GROUP:New():FilterCoalitions( "red" ):FilterPrefixes( "Attack" ):FilterStart() +local TaskDispatcher = TASK_A2G_DISPATCHER:New( Mission, HQ, AttackGroups, FACAreas ) + diff --git a/Moose Test Missions/TAD - Task Dispatching/TAD-120 - A2G Task Dispatching DETECTION_UNITS/TAD-120 - A2G Task Dispatching DETECTION_UNITS.miz b/Moose Test Missions/TAD - Task Dispatching/TAD-120 - A2G Task Dispatching DETECTION_UNITS/TAD-120 - A2G Task Dispatching DETECTION_UNITS.miz new file mode 100644 index 000000000..578dd1ab8 Binary files /dev/null and b/Moose Test Missions/TAD - Task Dispatching/TAD-120 - A2G Task Dispatching DETECTION_UNITS/TAD-120 - A2G Task Dispatching DETECTION_UNITS.miz differ