From 04fb7f7684a1d1715bde83930eb1386a074df388 Mon Sep 17 00:00:00 2001 From: Frank Date: Wed, 11 Mar 2020 19:35:42 +0100 Subject: [PATCH] Ops Improved mission handling on cancel, done and repeat. --- .../Moose/Functional/Warehouse.lua | 28 ++---- Moose Development/Moose/Ops/AirWing.lua | 48 +++++++++- Moose Development/Moose/Ops/Auftrag.lua | 88 +++++++++++++++---- Moose Development/Moose/Ops/FlightGroup.lua | 22 +++-- 4 files changed, 138 insertions(+), 48 deletions(-) diff --git a/Moose Development/Moose/Functional/Warehouse.lua b/Moose Development/Moose/Functional/Warehouse.lua index fd9936718..0f6138fbb 100644 --- a/Moose Development/Moose/Functional/Warehouse.lua +++ b/Moose Development/Moose/Functional/Warehouse.lua @@ -6288,7 +6288,7 @@ function WAREHOUSE:_UnitDead(deadunit, request) end - -- Not sure what this does actually and if it would be better to set it to true. + -- Dont trigger a Remove event for the group sets. local NoTriggerEvent=true if request.transporttype==WAREHOUSE.TransportType.SELFPROPELLED then @@ -6300,7 +6300,7 @@ function WAREHOUSE:_UnitDead(deadunit, request) -- Remove dead group from cargo group set. if groupdead==true then request.cargogroupset:Remove(groupname, NoTriggerEvent) - self:T(self.lid..string.format("Removed selfpropelled cargo %s: ncargo=%d.", groupname, request.cargogroupset:Count())) + self:T(self.lid..string.format("Removed selfpropelled cargo %s: ncargo=%d.", groupname, request.cargogroupset:Count())) end else @@ -7666,28 +7666,12 @@ end -- @return #string Name of the object without trailing #... function WAREHOUSE:_GetNameWithOut(group) - if group then - local name - if type(group)=="string" then - name=group - else - name=group:GetName() - end - - local namewithout=UTILS.Split(name, "#CARGO")[1] - - if namewithout then - return namewithout - else - return name - end - end + local groupname=type(group)=="string" and group or group:GetName() - - if type(group)=="string" then - return group + if groupname:find("CARGO") then + return UTILS.Split(groupname, "#CARGO")[1] else - return group:GetName() + return groupname end end diff --git a/Moose Development/Moose/Ops/AirWing.lua b/Moose Development/Moose/Ops/AirWing.lua index d7e850c03..bc6fe6b29 100644 --- a/Moose Development/Moose/Ops/AirWing.lua +++ b/Moose Development/Moose/Ops/AirWing.lua @@ -88,7 +88,7 @@ AIRWING = { --- AIRWING class version. -- @field #string version -AIRWING.version="0.1.4" +AIRWING.version="0.1.5" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ToDo list @@ -349,6 +349,30 @@ function AIRWING:GetSquadron(SquadronName) return self.squadrons[SquadronName] end +--- Get squadron of an asset. +-- @param #AIRWING self +-- @param #AIRWING.SquadronAsset Asset +-- @return #AIRWING.Squadron Squadron table. +function AIRWING:GetSquadronOfAsset(Asset) + return self:GetSquadron(Asset.assignment) +end + +--- Remove asset from squadron. +-- @param #AIRWING self +-- @param #AIRWING.SquadronAsset Asset +-- @return #AIRWING.Squadron Squadron table. +function AIRWING:RemoveAssetFromSquadron(Asset) + local squad=self:GetSquadronOfAsset(Asset) + if squad then + for i,_asset in pairs(squad.assets) do + local asset=_asset --#AIRWING.SquadronAsset + if asset.uid==Asset.uid then + table.remove(squad.assets, i) + return + end + end + end +end --- Add mission to queue. -- @param #AIRWING self @@ -1313,6 +1337,28 @@ function AIRWING:GetMissionByID(mid) return nil end +--- Returns the mission for a given request ID. +-- @param #AIRWING self +-- @param #number RequestID Unique ID of the request. +-- @return Ops.Auftrag#AUFTRAG Mission table or *nil*. +function AIRWING:GetMissionFromRequestID(RequestID) + for _,_mission in pairs(self.missionqueue) do + local mission=_mission --Ops.Auftrag#AUFTRAG + if mission.requestID and mission.requestID==RequestID then + return mission + end + end + return nil +end + +--- Returns the mission for a given request. +-- @param #AIRWING self +-- @param Functional.Warehouse#WAREHOUSE.Queueitem Request The warehouse request. +-- @return Ops.Auftrag#AUFTRAG Mission table or *nil*. +function AIRWING:GetMissionFromRequest(Request) + return self:GetMissionFromRequestID(Request.uid) +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Menu Functions diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index 32493a05e..4d51a2aa6 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -209,7 +209,7 @@ AUFTRAG.FlightStatus={ --- AUFTRAG class version. -- @field #string version -AUFTRAG.version="0.0.5" +AUFTRAG.version="0.0.7" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -688,6 +688,16 @@ function AUFTRAG:AddFlightGroup(FlightGroup) end +--- Remove a flight group to the mission. +-- @param #AUFTRAG self +-- @param Ops.FlightGroup#FLIGHTGROUP FlightGroup The FLIGHTGROUP object. +function AUFTRAG:DelFlightGroup(FlightGroup) + self:I(self.lid..string.format("Removing flight group %s", FlightGroup.groupname)) + + self.flightdata[FlightGroup.groupname]=nil + +end + --- Check if mission is PLANNED. -- @param #AUFTRAG self -- @return #boolean If true, mission is in the planning state. @@ -793,7 +803,7 @@ function AUFTRAG:onafterStatus(From, Event, To) local Cstop=self.Tstop and UTILS.SecondsToClock(self.Tstop, true) or "INF" -- Info message. - self:I(self.lid..string.format("Status \"%s\": T=%s-%s flights=%d, targets=%d", self.status, Cstart, Cstop, Nflights, Ntargets)) + self:I(self.lid..string.format("Status \"%s\": T=%s-%s assets=%d, flights=%d, targets=%d", self.status, Cstart, Cstop, #self.assets, Nflights, Ntargets)) -- Check for error. if fsmstate~=self.status then @@ -809,19 +819,33 @@ function AUFTRAG:onafterStatus(From, Event, To) end end ---- Set flightgroup mission status. +--- Evaluate mission outcome - success or failure. -- @param #AUFTRAG self --- @return #string status New status. +-- @return #AUFTRAG self function AUFTRAG:Evaluate() + -- Assume success and check if any failed condition applies. + local failed=false + + -- Current number of mission targets. local Ntargets=self:CountMissionTargets() - if self.Ntargets>Ntargets then + -- Number of current targets is still >0 ==> Not everything was destroyed. + if self.Ntargets>0 and Ntargets>0 then + failed=true + end + + --TODO: all assets dead? Is this a FAILED criterion even if all targets have been destroyed? What if there are no initial targets (e.g. when ORBIT, PATROL, RECON missions). + + self:I(self.lid..string.format("Evaluating mission: Initial Targets=%d, current targets=%d ==> success=%s", self.Ntargets, Ntargets, tostring(not failed))) + + if failed then self:Failed() else self:Success() end + return self end @@ -836,10 +860,15 @@ function AUFTRAG:SetFlightStatus(flightgroup, status) else self.flightdata[flightgroup.groupname].status=status end + + self:I(self.lid..string.format("Setting flight %s status to %s. IsNotOver=%s CheckFlightsDone=%s", flightgroup.groupname, self:GetFlightStatus(flightgroup), tostring(self:IsNotOver()), tostring(self:CheckFlightsDone()))) -- Check if ALL flights are done with their mission. if self:IsNotOver() and self:CheckFlightsDone() then + self:I(self.lid.."All flight done ==> mission DONE!") self:Done() + else + self:I(self.lid.."Mission NOT DONE yet!") end end @@ -896,18 +925,19 @@ function AUFTRAG:CheckFlightsDone() return false end - -- Assume we are done. - local done=true + -- Check status of all flight groups. for groupname,data in pairs(self.flightdata) do local flightdata=data --#AUFTRAG.FlightData - if flightdata.status~=AUFTRAG.FlightStatus.DONE and flightdata.status~=AUFTRAG.FlightStatus.CANCELLED then - -- At least one flight group is not DONE or CANCELLED yet! - done=false + if flightdata.status==AUFTRAG.FlightStatus.DONE or flightdata.status==AUFTRAG.FlightStatus.CANCELLED then + -- This one is done or cancelled. + else + -- At least this flight is not DONE or CANCELLED. + return false end end - return done + return true end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -1021,18 +1051,21 @@ end -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. --- @param Ops.AirWing#AIRWING.SquadronAsset +-- @param Ops.AirWing#AIRWING.SquadronAsset Asset The asset. function AUFTRAG:onafterAssetDead(From, Event, To, Asset) -- Delete asset from mission. self:DelAsset(Asset) + -- Remove flightgroup from mission. + self:DelFlightGroup(Asset.flightgroup) + -- All assets dead? if #self.assets==0 then if self:IsNotOver() then - -- Cancel mission. Wait for next update to evaluate SUCCESS or FAILURE. + -- Cancel mission. Wait for next mission update to evaluate SUCCESS or FAILURE. self:Cancel() else @@ -1041,6 +1074,10 @@ function AUFTRAG:onafterAssetDead(From, Event, To, Asset) end end + + if self.airwing then + self.airwing:RemoveAssetFromSquadron(Asset) + end end @@ -1097,11 +1134,13 @@ function AUFTRAG:onafterFailed(From, Event, To) if self.missionRepeated>=self.missionRepeatMax then + self:I(self.lid..string.format("Mission failed! Number of max repeats reached %d>=%d ==> Stopping mission!", self.missionRepeated, self.missionRepeatMax)) self:Stop() else -- Repeat mission. + self:I(self.lid..string.format("Mission failed! Repeating mission for the %d. time (max=%d) ==> Repeat mission!", self.missionRepeated+1, self.missionRepeatMax)) self:Repeat() end @@ -1132,7 +1171,13 @@ function AUFTRAG:onafterRepeat(From, Event, To) end -- No mission assets. - self.assets={} + self.assets={} + + -- No flight data. + self.flightdata={} + + -- Call status again. + self:__Status(-30) end @@ -1145,11 +1190,9 @@ end -- @param #string To To state. function AUFTRAG:onafterStop(From, Event, To) - self.status="Stopped" - self:I(self.lid..string.format("New mission status=%s. Removing missions from queues. Stopping CallScheduler!", self.status)) + self:I(self.lid..string.format("STOPPED mission in status=%s. Removing missions from queues. Stopping CallScheduler!", self.status)) - -- TODO: remove missions from queues in WINGCOMMANDER, AIRWING and FLIGHGROUPS! - + -- TODO: remove missions from queues in WINGCOMMANDER, AIRWING and FLIGHGROUPS! -- TODO: Mission should be OVER! we dont want to remove running missions from any queues. if self.wingcommander then @@ -1165,7 +1208,15 @@ function AUFTRAG:onafterStop(From, Event, To) flightdata.flightgroup:RemoveMission(self) end + -- No mission assets. + self.assets={} + + -- No flight data. + self.flightdata={} + + -- Clear pending scheduler calls. self.CallScheduler:Clear() + end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -1195,6 +1246,7 @@ function AUFTRAG:DelAsset(Asset) local asset=_asset --Ops.AirWing#AIRWING.SquadronAsset if asset.uid==Asset.uid then + self:I(self.lid..string.format("Removing asset \"%s\" from mission", tostring(asset.spawngroupname))) table.remove(self.assets, i) return self end diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index 3e8f8005b..6632bc1da 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -349,7 +349,7 @@ FLIGHTGROUP.ROT={ --- FLIGHTGROUP class version. -- @field #string version -FLIGHTGROUP.version="0.3.4" +FLIGHTGROUP.version="0.3.5" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -662,16 +662,16 @@ function FLIGHTGROUP:AddTaskEnrouteEngageTargetsInZone(ZoneRadius, TargetTypes, end ---- Remove task. +--- Remove task from task queue. -- @param #FLIGHTGROUP self --- @param #number taskid ID of the task to remove. +-- @param #FLIGHTGROUP.Task Task The task to be removed from the queue. -- @return #boolean True if task could be removed. -function FLIGHTGROUP:RemoveTask(taskid) +function FLIGHTGROUP:RemoveTask(Task) for i=#self.taskqueue,1,-1 do local task=self.taskqueue[i] --#FLIGHTGROUP.Task - if task.id==taskid then + if task.id==Task.id then -- Remove task from queue. table.remove(self.taskqueue, i) @@ -724,8 +724,15 @@ function FLIGHTGROUP:RemoveMission(Mission) local mission=_mission --Ops.Auftrag#AUFTRAG if mission.auftragsnummer==Mission.auftragsnummer then + + -- Remove mission waypoint task. + local Task=Mission:GetFlightWaypointTask(self) + self:RemoveTask(Task) + + -- Remove mission from queue. table.remove(self.missionqueue, i) - break + + return self end end @@ -3305,7 +3312,6 @@ end function FLIGHTGROUP:onafterMissionCancel(From, Event, To, Mission) -- Set missin flight status. - env.info("FF setting mission to cancelled") Mission:SetFlightStatus(self, AUFTRAG.FlightStatus.CANCELLED) if self.currentmission and Mission.auftragsnummer==self.currentmission then @@ -3343,6 +3349,8 @@ end -- @param #string To To state. -- @param Ops.Auftrag#AUFTRAG Mission function FLIGHTGROUP:onafterMissionDone(From, Event, To, Mission) + + self:I(self.lid..string.format("Mission %s DONE!", Mission.name)) -- Set Flight status. Mission:SetFlightStatus(self, AUFTRAG.FlightStatus.DONE)