From a9b0017c046dcfed88dc8bbb43ac24e7e59e5d69 Mon Sep 17 00:00:00 2001 From: Frank Date: Sun, 1 Jan 2023 20:01:36 +0100 Subject: [PATCH] OPS request --- .../Moose/Functional/Warehouse.lua | 219 +++++++++--------- Moose Development/Moose/Ops/Auftrag.lua | 63 ++++- Moose Development/Moose/Ops/Brigade.lua | 19 +- Moose Development/Moose/Ops/Legion.lua | 68 +++++- 4 files changed, 247 insertions(+), 122 deletions(-) diff --git a/Moose Development/Moose/Functional/Warehouse.lua b/Moose Development/Moose/Functional/Warehouse.lua index cc82caa61..e02ba3008 100644 --- a/Moose Development/Moose/Functional/Warehouse.lua +++ b/Moose Development/Moose/Functional/Warehouse.lua @@ -7987,120 +7987,123 @@ function WAREHOUSE:_FindParkingForAssets(airbase, assets) -- Loop over all assets that need a parking psot. for _,asset in pairs(assets) do local _asset=asset --#WAREHOUSE.Assetitem - - -- Get terminal type of this asset - local terminaltype=asset.terminalType or self:_GetTerminal(asset.attribute, self:GetAirbaseCategory()) - - -- Asset specific parking. - parking[_asset.uid]={} - - -- Loop over all units - each one needs a spot. - for i=1,_asset.nunits do - -- Asset name - local assetname=_asset.spawngroupname.."-"..tostring(i) + if not _asset.spawned then - -- Loop over all parking spots. - local gotit=false - for _,_parkingspot in pairs(parkingdata) do - local parkingspot=_parkingspot --Wrapper.Airbase#AIRBASE.ParkingSpot - - -- Parking valid? - local valid=true - - if asset.parkingIDs then - -- If asset has assigned parking spots, we take these no matter what. - valid=self:_CheckParkingAsset(parkingspot, asset) - else - - -- Valid terminal type depending on attribute. - local validTerminal=AIRBASE._CheckTerminalType(parkingspot.TerminalType, terminaltype) + -- Get terminal type of this asset + local terminaltype=asset.terminalType or self:_GetTerminal(asset.attribute, self:GetAirbaseCategory()) + + -- Asset specific parking. + parking[_asset.uid]={} + + -- Loop over all units - each one needs a spot. + for i=1,_asset.nunits do + + -- Asset name + local assetname=_asset.spawngroupname.."-"..tostring(i) + + -- Loop over all parking spots. + local gotit=false + for _,_parkingspot in pairs(parkingdata) do + local parkingspot=_parkingspot --Wrapper.Airbase#AIRBASE.ParkingSpot - -- Valid parking list. - local validParking=self:_CheckParkingValid(parkingspot) + -- Parking valid? + local valid=true - -- Black and white list. - local validBWlist=airbase:_CheckParkingLists(parkingspot.TerminalID) - - -- Debug info. - --env.info(string.format("FF validTerminal = %s", tostring(validTerminal))) - --env.info(string.format("FF validParking = %s", tostring(validParking))) - --env.info(string.format("FF validBWlist = %s", tostring(validBWlist))) - - -- Check if all are true - valid=validTerminal and validParking and validBWlist - end - - - -- Check correct terminal type for asset. We don't want helos in shelters etc. - if valid then - - -- Coordinate of the parking spot. - local _spot=parkingspot.Coordinate -- Core.Point#COORDINATE - local _termid=parkingspot.TerminalID - local free=true - local problem=nil - - -- Loop over all obstacles. - for _,obstacle in pairs(obstacles) do - - -- Check if aircraft overlaps with any obstacle. - local dist=_spot:Get2DDistance(obstacle.coord) - local safe=_overlap(_asset.size, obstacle.size, dist) - - -- Spot is blocked. - if not safe then - self:T3(self.lid..string.format("FF asset=%s (id=%d): spot id=%d dist=%.1fm is NOT SAFE", assetname, _asset.uid, _termid, dist)) - free=false - problem=obstacle - problem.dist=dist - break - else - --env.info(string.format("FF asset=%s (id=%d): spot id=%d dist=%.1fm is SAFE", assetname, _asset.uid, _termid, dist)) - end - - end - - -- Check if spot is free - if free then - - -- Add parkingspot for this asset unit. - table.insert(parking[_asset.uid], parkingspot) - - -- Debug - self:T(self.lid..string.format("Parking spot %d is free for asset %s [id=%d]!", _termid, assetname, _asset.uid)) - - -- Add the unit as obstacle so that this spot will not be available for the next unit. - table.insert(obstacles, {coord=_spot, size=_asset.size, name=assetname, type="asset"}) - - gotit=true - break - + if asset.parkingIDs then + -- If asset has assigned parking spots, we take these no matter what. + valid=self:_CheckParkingAsset(parkingspot, asset) else - - -- Debug output for occupied spots. - if self.Debug then - local coord=problem.coord --Core.Point#COORDINATE - local text=string.format("Obstacle %s [type=%s] blocking spot=%d! Size=%.1f m and distance=%.1f m.", problem.name, problem.type, _termid, problem.size, problem.dist) - self:I(self.lid..text) - coord:MarkToAll(string.format(text)) - else - self:T(self.lid..string.format("Parking spot %d is occupied or not big enough!", _termid)) - end - + + -- Valid terminal type depending on attribute. + local validTerminal=AIRBASE._CheckTerminalType(parkingspot.TerminalType, terminaltype) + + -- Valid parking list. + local validParking=self:_CheckParkingValid(parkingspot) + + -- Black and white list. + local validBWlist=airbase:_CheckParkingLists(parkingspot.TerminalID) + + -- Debug info. + --env.info(string.format("FF validTerminal = %s", tostring(validTerminal))) + --env.info(string.format("FF validParking = %s", tostring(validParking))) + --env.info(string.format("FF validBWlist = %s", tostring(validBWlist))) + + -- Check if all are true + valid=validTerminal and validParking and validBWlist end - - else - self:T2(self.lid..string.format("Terminal ID=%d: type=%s not supported", parkingspot.TerminalID, parkingspot.TerminalType)) - end -- check terminal type - end -- loop over parking spots - - -- No parking spot for at least one asset :( - if not gotit then - self:I(self.lid..string.format("WARNING: No free parking spot for asset %s [id=%d]", assetname, _asset.uid)) - return nil - end - end -- loop over asset units + + + -- Check correct terminal type for asset. We don't want helos in shelters etc. + if valid then + + -- Coordinate of the parking spot. + local _spot=parkingspot.Coordinate -- Core.Point#COORDINATE + local _termid=parkingspot.TerminalID + local free=true + local problem=nil + + -- Loop over all obstacles. + for _,obstacle in pairs(obstacles) do + + -- Check if aircraft overlaps with any obstacle. + local dist=_spot:Get2DDistance(obstacle.coord) + local safe=_overlap(_asset.size, obstacle.size, dist) + + -- Spot is blocked. + if not safe then + self:T3(self.lid..string.format("FF asset=%s (id=%d): spot id=%d dist=%.1fm is NOT SAFE", assetname, _asset.uid, _termid, dist)) + free=false + problem=obstacle + problem.dist=dist + break + else + --env.info(string.format("FF asset=%s (id=%d): spot id=%d dist=%.1fm is SAFE", assetname, _asset.uid, _termid, dist)) + end + + end + + -- Check if spot is free + if free then + + -- Add parkingspot for this asset unit. + table.insert(parking[_asset.uid], parkingspot) + + -- Debug + self:T(self.lid..string.format("Parking spot %d is free for asset %s [id=%d]!", _termid, assetname, _asset.uid)) + + -- Add the unit as obstacle so that this spot will not be available for the next unit. + table.insert(obstacles, {coord=_spot, size=_asset.size, name=assetname, type="asset"}) + + gotit=true + break + + else + + -- Debug output for occupied spots. + if self.Debug then + local coord=problem.coord --Core.Point#COORDINATE + local text=string.format("Obstacle %s [type=%s] blocking spot=%d! Size=%.1f m and distance=%.1f m.", problem.name, problem.type, _termid, problem.size, problem.dist) + self:I(self.lid..text) + coord:MarkToAll(string.format(text)) + else + self:T(self.lid..string.format("Parking spot %d is occupied or not big enough!", _termid)) + end + + end + + else + self:T2(self.lid..string.format("Terminal ID=%d: type=%s not supported", parkingspot.TerminalID, parkingspot.TerminalType)) + end -- check terminal type + end -- loop over parking spots + + -- No parking spot for at least one asset :( + if not gotit then + self:I(self.lid..string.format("WARNING: No free parking spot for asset %s [id=%d]", assetname, _asset.uid)) + return nil + end + end -- loop over asset units + end -- Asset spawned check end -- loop over asset groups return parking diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index 74e27a915..aa32bc83f 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -5467,16 +5467,73 @@ function AUFTRAG:_SetLogID() end ---- Update DCS task. +--- Get request ID from legion this mission requested assets from -- @param #AUFTRAG self --- @return #AUFTRAG self -function AUFTRAG:_UpdateTask() +-- @param Ops.Legion#LEGION Legion The legion from which to get the request ID. +-- @return #number Request ID (if any). +function AUFTRAG:_GetRequestID(Legion) + local requestid=nil + local name=nil + if type(Legion)=="string" then + name=Legion + else + name=Legion.alias + end + + if name then + requestid=self.requestID[name] + end + + return nil +end + + +--- Get request from legion this mission requested assets from. +-- @param #AUFTRAG self +-- @param Ops.Legion#LEGION Legion The legion from which to get the request ID. +-- @return Functional.Warehouse#WAREHOUSE.PendingItem Request. +function AUFTRAG:_GetRequest(Legion) + + local request=nil + + local requestID=self:_GetRequestID(Legion) + + if requestID then + request=Legion:GetRequestByID(requestID) + end + + return request +end + +--- Set request ID from legion this mission requested assets from +-- @param #AUFTRAG self +-- @param Ops.Legion#LEGION Legion The legion from which to get the request ID. +-- @param #number RequestID Request ID. +-- @return #AUFTRAG self +function AUFTRAG:_SetRequestID(Legion, RequestID) + + local requestid=nil + local name=nil + + if type(Legion)=="string" then + name=Legion + else + name=Legion.alias + end + + if name then + if self.requestID[name] then + self:I(self.lid..string.format("WARNING: Mission already has a request ID=%d!", self.requestID[name])) + end + self.requestID[name]=RequestID + end return self end + --- Update mission F10 map marker. -- @param #AUFTRAG self -- @return #AUFTRAG self diff --git a/Moose Development/Moose/Ops/Brigade.lua b/Moose Development/Moose/Ops/Brigade.lua index 3ce1e6be1..73ae5e043 100644 --- a/Moose Development/Moose/Ops/Brigade.lua +++ b/Moose Development/Moose/Ops/Brigade.lua @@ -572,9 +572,9 @@ function BRIGADE:onafterStatus(From, Event, To) self:I(self.lid..text) end - ------------------- + --------------------- -- Refuelling Info -- - ------------------- + --------------------- if self.verbose>=4 then local text="Refuelling Zones:" for i,_refuellingzone in pairs(self.refuellingZones) do @@ -583,7 +583,20 @@ function BRIGADE:onafterStatus(From, Event, To) text=text..string.format("\n* %s: Mission status=%s, suppliers=%d", refuellingzone.zone:GetName(), refuellingzone.mission:GetState(), refuellingzone.mission:CountOpsGroups()) end self:I(self.lid..text) - end + end + + ---------------- + -- Asset Info -- + ---------------- + if self.verbose>=5 then + local text="Assets in stock:" + for i,_asset in pairs(self.stock) do + local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem + -- Info text. + text=text..string.format("\n* %s: spawned=%s", asset.spawngroupname, tostring(asset.spawned)) + end + self:I(self.lid..text) + end end diff --git a/Moose Development/Moose/Ops/Legion.lua b/Moose Development/Moose/Ops/Legion.lua index df441a2ec..141c74c31 100644 --- a/Moose Development/Moose/Ops/Legion.lua +++ b/Moose Development/Moose/Ops/Legion.lua @@ -839,6 +839,58 @@ function LEGION:onafterMissionAssign(From, Event, To, Mission, Legions) end +--- Create a request and add it to the warehouse queue. +-- @param #LEGION self +-- @param Functional.Warehouse#WAREHOUSE.Descriptor AssetDescriptor Descriptor describing the asset that is requested. +-- @param AssetDescriptorValue Value of the asset descriptor. Type depends on descriptor, i.e. could be a string, etc. +-- @param #number nAsset Number of groups requested that match the asset specification. +-- @param #number Prio Priority of the request. Number ranging from 1=high to 100=low. +-- @param #string Assignment A keyword or text that can later be used to identify this request and postprocess the assets. +function LEGION:_AddRequest(AssetDescriptor, AssetDescriptorValue, nAsset, Prio, Assignment) + + -- Defaults. + nAsset=nAsset or 1 + Prio=Prio or 50 + + -- Increase id. + self.queueid=self.queueid+1 + + -- Request queue table item. + local request={ + uid=self.queueid, + prio=Prio, + warehouse=self, + assetdesc=AssetDescriptor, + assetdescval=AssetDescriptorValue, + nasset=nAsset, + transporttype=WAREHOUSE.TransportType.SELFPROPELLED, + ntransport=0, + assignment=tostring(Assignment), + airbase=self:GetAirbase(), + category=self:GetAirbaseCategory(), + ndelivered=0, + ntransporthome=0, + assets={}, + toself=true, + } --Functional.Warehouse#WAREHOUSE.Queueitem + + + -- Add request to queue. + table.insert(self.queue, request) + + local descval="assetlist" + if request.assetdesc==WAREHOUSE.Descriptor.ASSETLIST then + + else + descval=tostring(request.assetdescval) + end + + local text=string.format("Warehouse %s: New request from warehouse %s.\nDescriptor %s=%s, #assets=%s; Transport=%s, #transports=%s.", + self.alias, self.alias, request.assetdesc, descval, tostring(request.nasset), request.transporttype, tostring(request.ntransport)) + self:_DebugMessage(text, 5) + +end + --- On after "MissionRequest" event. Performs a self request to the warehouse for the mission assets. Sets mission status to REQUESTED. -- @param #LEGION self @@ -914,11 +966,8 @@ function LEGION:onafterMissionRequest(From, Event, To, Mission) if Mission.type==AUFTRAG.Type.RELOCATECOHORT then cancel=true - -- Get request ID. - local requestID=currM.requestID[self.alias] - -- Get request. - local request=self:GetRequestByID(requestID) + local request=currM:_GetRequest(self) if request then self:T2(self.lid.."Removing group from cargoset") @@ -999,7 +1048,8 @@ function LEGION:onafterMissionRequest(From, Event, To, Mission) local assignment=string.format("Mission-%d", Mission.auftragsnummer) -- Add request to legion warehouse. - self:AddRequest(self, WAREHOUSE.Descriptor.ASSETLIST, Assetlist, #Assetlist, nil, nil, Mission.prio, assignment) + --self:AddRequest(self, WAREHOUSE.Descriptor.ASSETLIST, Assetlist, #Assetlist, nil, nil, Mission.prio, assignment) + self:_AddRequest(WAREHOUSE.Descriptor.ASSETLIST, Assetlist, #Assetlist, Mission.prio, assignment) -- The queueid has been increased in the onafterAddRequest function. So we can simply use it here. Mission.requestID[self.alias]=self.queueid @@ -1091,7 +1141,8 @@ function LEGION:onafterTransportRequest(From, Event, To, OpsTransport) local assignment=string.format("Transport-%d", OpsTransport.uid) -- Add request to legion warehouse. - self:AddRequest(self, WAREHOUSE.Descriptor.ASSETLIST, AssetList, #AssetList, nil, nil, OpsTransport.prio, assignment) + --self:AddRequest(self, WAREHOUSE.Descriptor.ASSETLIST, AssetList, #AssetList, nil, nil, OpsTransport.prio, assignment) + self:_AddRequest(WAREHOUSE.Descriptor.ASSETLIST, AssetList, #AssetList, OpsTransport.prio, assignment) -- The queueid has been increased in the onafterAddRequest function. So we can simply use it here. OpsTransport.requestID[self.alias]=self.queueid @@ -1198,8 +1249,9 @@ function LEGION:onafterMissionCancel(From, Event, To, Mission) end -- Remove queued request (if any). - if Mission.requestID[self.alias] then - self:_DeleteQueueItemByID(Mission.requestID[self.alias], self.queue) + local requestID=Mission:_GetRequestID(self) + if requestID then + self:_DeleteQueueItemByID(requestID, self.queue) end end