Optimized the boarding and unboarding of cargo. fixed bug when in defence of APC, cargo would not be loaded. The boarding and unboarding has become much more stable now.

This commit is contained in:
FlightControl 2018-10-18 07:27:50 +02:00
commit f0ac7818b3
8 changed files with 247 additions and 166 deletions

View File

@ -307,7 +307,7 @@ function AI_CARGO:onafterBoard( Carrier, From, Event, To, Cargo, CarrierUnit, Pi
if Carrier and Carrier:IsAlive() then
self:F({ IsLoaded = Cargo:IsLoaded(), Cargo:GetName(), Carrier:GetName() } )
if not Cargo:IsLoaded() then
if not Cargo:IsLoaded() and not Cargo:IsDestroyed() then
self:__Board( -10, Cargo, CarrierUnit, PickupZone )
return
end
@ -487,6 +487,7 @@ function AI_CARGO:onafterDeployed( Carrier, From, Event, To, DeployZone, Defend
self.Transporting = false
else
self:F( "Defending" )
end
end

View File

@ -276,9 +276,10 @@ function AI_CARGO_APC:onafterMonitor( APC, From, Event, To )
if self.CarrierCoordinate then
if self:IsTransporting() == true then
local Coordinate = APC:GetCoordinate()
if self:Is( "Unloaded" ) or self:Is( "Loaded" ) then
self.Zone:Scan( { Object.Category.UNIT } )
if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then
if self:Is( "Unloaded" ) or self:Is( "Following" ) then
if self:Is( "Unloaded" ) then
-- There are no enemies within combat radius. Load the CargoCarrier.
self:Load()
end
@ -288,7 +289,7 @@ function AI_CARGO_APC:onafterMonitor( APC, From, Event, To )
self:__Unload( 1, nil, true ) -- The 2nd parameter is true, which means that the unload is for defending the carrier, not to deploy!
else
if self:Is( "Unloaded" ) then
self:Follow()
--self:Follow()
end
self:F( "I am here" .. self:GetCurrentState() )
if self:Is( "Following" ) then
@ -313,6 +314,7 @@ function AI_CARGO_APC:onafterMonitor( APC, From, Event, To )
end
end
end
end
end
self.CarrierCoordinate = APC:GetCoordinate()
@ -456,6 +458,30 @@ function AI_CARGO_APC:onafterDeployed( APC, From, Event, To, DeployZone, Defend
self:GetParent( self, AI_CARGO_APC ).onafterDeployed( self, APC, From, Event, To, DeployZone, Defend )
-- If Defend == true then we need to scan for possible enemies within combat zone and engage only ground forces.
if Defend == true then
self.Zone:Scan( { Object.Category.UNIT } )
if not self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then
-- OK, enemies nearby, now find the enemies and attack them.
local AttackUnits = self.Zone:GetScannedUnits() -- #list<DCS#Unit>
local Move = {}
for CargoId, CargoData in pairs( self.CargoSet:GetSet() ) do
local CargoGroup = CargoData.CargoObject -- Wrapper.Group#GROUP
Move[#Move+1] = CargoGroup:GetCoordinate():WaypointGround( 70, "Custom" )
for UnitId, AttackUnit in pairs( AttackUnits ) do
local MooseUnit = UNIT:Find( AttackUnit )
if MooseUnit:GetCoalition() ~= CargoGroup:GetCoalition() then
Move[#Move+1] = MooseUnit:GetCoordinate():WaypointGround( 70, "Line abreast" )
--MoveTo.Task = CargoGroup:TaskCombo( CargoGroup:TaskAttackUnit( MooseUnit, true ) )
self:F( { MooseUnit = MooseUnit:GetName(), CargoGroup = CargoGroup:GetName() } )
end
end
CargoGroup:RoutePush( Move, 0.1 )
end
end
end
end

View File

@ -1143,7 +1143,7 @@ function AI_CARGO_DISPATCHER:onafterMonitor()
LargestLoadCapacity = LoadCapacity
end
end
-- So if there is aa carrier that has the required load capacity to load the total weight of the cargo, dispatch the carrier.
-- So if there is a carrier that has the required load capacity to load the total weight of the cargo, dispatch the carrier.
-- Otherwise break and go to the next carrier.
-- This will skip cargo which is too large to be able to be loaded by carriers
-- and will secure an efficient dispatching scheme.

View File

@ -20,9 +20,9 @@
do -- CARGO_GROUP
--- @type CARGO_GROUP
-- @extends Cargo.Cargo#CARGO_REPORTABLE
-- @field Core.Set#SET_CARGO CargoSet The collection of derived CARGO objects.
-- @field #string GroupName The name of the CargoGroup.
-- @extends Cargo.Cargo#CARGO_REPORTABLE
--- Defines a cargo that is represented by a @{Wrapper.Group} object within the simulator.
-- The cargo can be Loaded, UnLoaded, Boarded, UnBoarded to and from Carriers.
@ -291,29 +291,27 @@ do -- CARGO_GROUP
end
--- Enter Boarding State.
--- After Board Event.
-- @param #CARGO_GROUP self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
function CARGO_GROUP:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
function CARGO_GROUP:onafterBoard( From, Event, To, CargoCarrier, NearRadius, ... )
self:F( { CargoCarrier.UnitName, From, Event, To, NearRadius = NearRadius } )
NearRadius = NearRadius or self.NearRadius
if From == "UnLoaded" then
-- For each Cargo object within the CARGO_GROUPED, route each object to the CargoLoadPointVec2
self.CargoSet:ForEach(
function( Cargo, ... )
self:F( { "Board Unit", Cargo:GetName( ), Cargo:IsDestroyed(), Cargo.CargoObject:IsAlive() } )
Cargo:__Board( 1, CargoCarrier, NearRadius, ... )
end, ...
)
self:__Boarding( 1, CargoCarrier, NearRadius, ... )
end
self:__Boarding( -1, CargoCarrier, NearRadius, ... )
end
@ -323,15 +321,17 @@ do -- CARGO_GROUP
-- @param #string From
-- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier
function CARGO_GROUP:onenterLoaded( From, Event, To, CargoCarrier, ... )
function CARGO_GROUP:onafterLoad( From, Event, To, CargoCarrier, ... )
--self:F( { From, Event, To, CargoCarrier, ...} )
if From == "UnLoaded" then
-- For each Cargo object within the CARGO_GROUP, load each cargo to the CargoCarrier.
for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do
if not Cargo:IsDestroyed() then
Cargo:Load( CargoCarrier )
end
end
end
--self.CargoObject:Destroy()
self.CargoCarrier = CargoCarrier
@ -400,7 +400,7 @@ do -- CARGO_GROUP
-- @param #string To
-- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
function CARGO_GROUP:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... )
function CARGO_GROUP:onafterUnBoard( From, Event, To, ToPointVec2, NearRadius, ... )
self:F( {From, Event, To, ToPointVec2, NearRadius } )
NearRadius = NearRadius or 25
@ -443,7 +443,7 @@ do -- CARGO_GROUP
-- @param #string To
-- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
function CARGO_GROUP:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... )
function CARGO_GROUP:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... )
--self:F( { From, Event, To, ToPointVec2, NearRadius } )
--local NearRadius = NearRadius or 25
@ -464,7 +464,7 @@ do -- CARGO_GROUP
end
if UnBoarded then
return true
self:__UnLoad( 1, ToPointVec2, ... )
else
self:__UnBoarding( 1, ToPointVec2, NearRadius, ... )
end
@ -474,30 +474,13 @@ do -- CARGO_GROUP
end
--- UnBoard Event.
-- @param #CARGO_GROUP self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
function CARGO_GROUP:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... )
--self:F( { From, Event, To, ToPointVec2, NearRadius } )
--local NearRadius = NearRadius or 25
self:__UnLoad( 1, ToPointVec2, ... )
end
--- Enter UnLoaded State.
-- @param #CARGO_GROUP self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2
function CARGO_GROUP:onenterUnLoaded( From, Event, To, ToPointVec2, ... )
function CARGO_GROUP:onafterUnLoad( From, Event, To, ToPointVec2, ... )
--self:F( { From, Event, To, ToPointVec2 } )
if From == "Loaded" then
@ -507,7 +490,7 @@ do -- CARGO_GROUP
function( Cargo )
--Cargo:UnLoad( ToPointVec2 )
local RandomVec2=ToPointVec2:GetRandomPointVec2InRadius(20, 10)
Cargo:UnLoad( RandomVec2 )
Cargo:UnBoard( RandomVec2 )
end
)

View File

@ -233,6 +233,8 @@ do -- CARGO_UNIT
--self:F({Unit=self.CargoObject:GetName()})
-- A cargo unit can only be boarded if it is not dead
-- Only move the group to the carrier when the cargo is not in the air
-- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea).
if not self.CargoInAir then
@ -272,7 +274,6 @@ do -- CARGO_UNIT
end
end
end
end
@ -286,19 +287,19 @@ do -- CARGO_UNIT
function CARGO_UNIT:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
self:F( { From, Event, To, CargoCarrier:GetName(), NearRadius = NearRadius } )
--self:F({Unit=self.CargoObject:GetName()})
self:F( { IsAlive=self.CargoObject:IsAlive() } )
if CargoCarrier and CargoCarrier:IsAlive() then -- and self.CargoObject and self.CargoObject:IsAlive() then
if (CargoCarrier:IsAir() and not CargoCarrier:InAir()) or true then
local NearRadius = NearRadius or CargoCarrier:GetBoundingRadius( NearRadius ) + 5
if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then
self:__Load( 1, CargoCarrier, ... )
self:__Load( -1, CargoCarrier, ... )
else
if self:IsNear( CargoCarrier:GetPointVec2(), 20 ) then
self:__Boarding( 1, CargoCarrier, NearRadius, ... )
self:__Boarding( -1, CargoCarrier, NearRadius, ... )
self.RunCount = self.RunCount + 1
else
self:__Boarding( 2, CargoCarrier, NearRadius, ... )
self:__Boarding( -2, CargoCarrier, NearRadius, ... )
self.RunCount = self.RunCount + 2
end
if self.RunCount >= 40 then

View File

@ -12,7 +12,7 @@
-- * Strategic components such as capturing, defending and destroying warehouses and their associated infrastructure.
-- * Intelligent spawning of aircraft on airports (only if enough parking spots are available).
-- * Possibility to hook into events and customize actions.
-- * Persistance of assets. Warehouse assets can be saved and loaded from file.
-- * Persistence of assets. Warehouse assets can be saved and loaded from file.
-- * Can be easily interfaced to other MOOSE classes.
--
-- ===
@ -66,6 +66,9 @@
-- @field #table offroadpaths Table holding user defined paths from one warehouse to another.
-- @field #boolean autodefence When the warehouse is under attack, automatically spawn assets to defend the warehouse.
-- @field #number spawnzonemaxdist Max distance between warehouse and spawn zone. Default 5000 meters.
-- @field #boolean autosave Automatically save assets to file when mission ends.
-- @field #string autosavepath Path where the asset file is saved on auto save.
-- @field #string autosavefilename File name of the auto asset save file. Default is auto generated from warehouse id and name.
-- @extends Core.Fsm#FSM
--- Have your assets at the right place at the right time - or not!
@ -677,7 +680,7 @@
--
-- ===
--
-- # Persistance of Assets
-- # Persistence of Assets
--
-- Assets in stock of a warehouse can be saved to a file on your hard drive and then loaded from that file at a later point. This enables to restart the mission
-- and restore the warehouse stock.
@ -696,7 +699,7 @@
--
-- in the file "MissionScripting.lua", which is located in the subdirectory "Scripts" of your DCS installation root directory.
--
-- ### Don'ts
-- ### Don't!
--
-- Do not use **semi-colons** or **equal signs** in the group names of your assets as these are used as separators in the saved and loaded files texts.
-- If you do, it will cause problems and give you a headache!
@ -712,6 +715,12 @@
--
-- This will save all asset data to in "D:\\My Warehouse Data\\Warehouse-1234_Batumi.txt".
--
-- ### Automatic Save at Mission End
--
-- The assets can be saved automatically when the mission is ended via the @{WAREHOUSE.SetSaveOnMissionEnd}(*path*, *filename*) function, i.e.
--
-- warehouseBatumi:SetSaveOnMissionEnd("D:\\My Warehouse Data\\")
--
-- ## Load Assets
--
-- Loading assets data from file is achieved by the @{WAREHOUSE.Load}(*path*, *filename*) function. The parameter *path* specifies the path on the file system where the
@ -1543,6 +1552,9 @@ WAREHOUSE = {
offroadpaths = {},
autodefence = false,
spawnzonemaxdist = 5000,
autosave = false,
autosavepath = nil,
autosavefile = nil,
}
--- Item of the warehouse stock table.
@ -1714,7 +1726,7 @@ WAREHOUSE.db = {
--- Warehouse class version.
-- @field #string version
WAREHOUSE.version="0.6.3"
WAREHOUSE.version="0.6.4"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: Warehouse todo list.
@ -2397,6 +2409,18 @@ function WAREHOUSE:SetAutoDefenceOff()
return self
end
--- Set auto defence off. This is the default.
-- @param #WAREHOUSE self
-- @param #string path Path where to save the asset data file.
-- @param #string filename File name. Default is generated automatically from warehouse id.
-- @return #WAREHOUSE self
function WAREHOUSE:SetSaveOnMissionEnd(path, filename)
self.autosave=true
self.autosavepath=path
self.autosavefile=filename
return self
end
--- Set the airbase belonging to this warehouse.
-- Note that it has to be of the same coalition as the warehouse.
@ -3042,6 +3066,7 @@ function WAREHOUSE:onafterStart(From, Event, To)
self:HandleEvent(EVENTS.Crash, self._OnEventCrashOrDead)
self:HandleEvent(EVENTS.Dead, self._OnEventCrashOrDead)
self:HandleEvent(EVENTS.BaseCaptured, self._OnEventBaseCaptured)
self:HandleEvent(EVENTS.MissionEnd, self._OnEventMissionEnd)
-- This event triggers the arrived event for air assets.
-- TODO Might need to make this landing or optional!
@ -4925,6 +4950,7 @@ function WAREHOUSE:onbeforeLoad(From, Event, To, path, filename)
return true
else
self:_ErrorMessage(string.format("ERROR: file %s does not exist! Cannot load assets.", filename), 60)
return false
end
end
@ -4977,6 +5003,7 @@ function WAREHOUSE:onafterLoad(From, Event, To, path, filename)
local descriptors=UTILS.Split(asset,";")
local asset={}
local isasset=false
for _,descriptor in pairs(descriptors) do
local keyval=UTILS.Split(descriptor,"=")
@ -4989,11 +5016,16 @@ function WAREHOUSE:onafterLoad(From, Event, To, path, filename)
elseif keyval[1]=="country" then
-- Get country id.
Country=tonumber(keyval[2])
elseif #keyval==2 then
else
-- This is an asset.
isasset=true
local key=keyval[1]
local val=keyval[2]
--env.info(string.format("FF asset key=%s val=%s", key, val))
-- Livery or skill could be "nil".
if val=="nil" then
val=nil
@ -5011,13 +5043,14 @@ function WAREHOUSE:onafterLoad(From, Event, To, path, filename)
end
-- Add to table.
if isasset then
table.insert(assets, asset)
end
end
-- Respawn warehouse with prev coalition if necessary.
self:E(string.format("Changing country %d-->%d (before)", self:GetCountry(), Country))
if Country~=self:GetCountry() then
self:E(string.format("Changing country %d-->%d (after)", self:GetCountry(), Country))
self:T(self.wid..string.format("Changing warehouse country %d-->%d on loading assets.", self:GetCountry(), Country))
self:ChangeCountry(Country)
end
@ -5960,6 +5993,18 @@ function WAREHOUSE:_OnEventBaseCaptured(EventData)
end
end
--- Warehouse event handling function.
-- Handles the case when the mission is ended.
-- @param #WAREHOUSE self
-- @param Core.Event#EVENTDATA EventData Event data.
function WAREHOUSE:_OnEventMissionEnd(EventData)
self:T3(self.wid..string.format("Warehouse %s captured event mission end!",self.alias))
if self.autosave then
self:Save(self.autosavepath, self.autosavefile)
end
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Helper functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -7712,7 +7757,7 @@ end
function WAREHOUSE:_ErrorMessage(text, duration)
duration=duration or 20
if duration>0 then
MESSAGE:New(text, duration):ToAllIf()
MESSAGE:New(text, duration):ToAll()
end
self:E(self.wid..text)
end

View File

@ -1975,6 +1975,24 @@ do -- Route methods
return nil
end
--- Make the controllable to push follow a given route.
-- @param #CONTROLLABLE self
-- @param #table Route A table of Route Points.
-- @param #number DelaySeconds (Optional) Wait for the specified seconds before executing the Route. Default is one second.
-- @return #CONTROLLABLE The CONTROLLABLE.
function CONTROLLABLE:RoutePush( Route, DelaySeconds )
self:F2( Route )
local DCSControllable = self:GetDCSObject()
if DCSControllable then
local RouteTask = self:TaskRoute( Route ) -- Create a RouteTask, that will route the CONTROLLABLE to the Route.
self:PushTask( RouteTask, DelaySeconds or 1 ) -- Execute the RouteTask after the specified seconds (default is 1).
return self
end
return nil
end
--- Stops the movement of the vehicle on the route.
-- @param #CONTROLLABLE self

View File

@ -908,8 +908,10 @@ function UNIT:InAir()
-- Implementation of workaround. The original code is below.
-- This to simulate the landing on buildings.
-- local UnitInAir = DCSUnit:inAir()
local UnitInAir = true
local UnitCategory = DCSUnit:getDesc().category
if UnitCategory == Unit.Category.HELICOPTER then
local VelocityVec3 = DCSUnit:getVelocity()
local Velocity = ( VelocityVec3.x ^ 2 + VelocityVec3.y ^ 2 + VelocityVec3.z ^ 2 ) ^ 0.5 -- in meters / sec
local Coordinate = DCSUnit:getPoint()
@ -918,6 +920,11 @@ function UNIT:InAir()
if Velocity < 1 and Height <= 60 then
UnitInAir = false
end
else
UnitInAir = DCSUnit:inAir()
end
self:T3( UnitInAir )
return UnitInAir
end