Merge branch 'develop' of https://github.com/FlightControl-Master/MOOSE into develop

This commit is contained in:
Van De Velde
2018-07-05 08:48:17 +02:00
2 changed files with 115 additions and 55 deletions

View File

@@ -385,12 +385,12 @@ RAT={
onboardnum=nil, -- Tail number. onboardnum=nil, -- Tail number.
onboardnum0=1, -- (Optional) Starting value of the automatically appended numbering of aircraft within a flight. Default is one. onboardnum0=1, -- (Optional) Starting value of the automatically appended numbering of aircraft within a flight. Default is one.
checkonrunway=true, -- Check whether aircraft have been spawned on the runway. checkonrunway=true, -- Check whether aircraft have been spawned on the runway.
onrunwayradius=75, -- Distance from a runway spawn point until a unit is considered to have accidentally been spawned on a runway. onrunwayradius=75, -- Distance from a runway spawn point until a unit is considered to have accidentally been spawned on a runway.
onrunwaymaxretry=3, -- Number of respawn retries (on ground) at other airports if a group gets accidentally spawned on the runway. onrunwaymaxretry=3, -- Number of respawn retries (on ground) at other airports if a group gets accidentally spawned on the runway.
checkontop=false, -- Check whether aircraft have been spawned on top of another unit. checkontop=false, -- Check whether aircraft have been spawned on top of another unit.
ontopradius=2, -- Radius in meters until which a unit is considered to be on top of another. ontopradius=2, -- Radius in meters until which a unit is considered to be on top of another.
termtype=nil, -- Terminal type. termtype=nil, -- Terminal type.
parkingscanradius=50, -- Scan radius. parkingscanradius=40, -- Scan radius.
parkingscanscenery=false, -- Scan parking spots for scenery obstacles. parkingscanscenery=false, -- Scan parking spots for scenery obstacles.
parkingverysafe=false, -- Very safe option. parkingverysafe=false, -- Very safe option.
} }
@@ -511,7 +511,7 @@ RAT.id="RAT | "
--- RAT version. --- RAT version.
-- @list version -- @list version
RAT.version={ RAT.version={
version = "2.3.1", version = "2.3.2",
print = true, print = true,
} }
@@ -2124,10 +2124,16 @@ function RAT:_SpawnWithRoute(_departure, _destination, _takeoff, _landing, _live
if group:InAir() then if group:InAir() then
self.ratcraft[self.SpawnIndex]["Tground"]=nil self.ratcraft[self.SpawnIndex]["Tground"]=nil
self.ratcraft[self.SpawnIndex]["Pground"]=nil self.ratcraft[self.SpawnIndex]["Pground"]=nil
self.ratcraft[self.SpawnIndex]["Uground"]=nil
self.ratcraft[self.SpawnIndex]["Tlastcheck"]=nil self.ratcraft[self.SpawnIndex]["Tlastcheck"]=nil
else else
self.ratcraft[self.SpawnIndex]["Tground"]=timer.getTime() self.ratcraft[self.SpawnIndex]["Tground"]=timer.getTime()
self.ratcraft[self.SpawnIndex]["Pground"]=group:GetCoordinate() self.ratcraft[self.SpawnIndex]["Pground"]=group:GetCoordinate()
self.ratcraft[self.SpawnIndex]["Uground"]={}
for _,_unit in pairs(group:GetUnits()) do
local _unitname=_unit:GetName()
self.ratcraft[self.SpawnIndex]["Uground"][_unitname]=_unit:GetCoordinate()
end
self.ratcraft[self.SpawnIndex]["Tlastcheck"]=timer.getTime() self.ratcraft[self.SpawnIndex]["Tlastcheck"]=timer.getTime()
end end
-- Initial and current position. For calculating the travelled distance. -- Initial and current position. For calculating the travelled distance.
@@ -3361,6 +3367,7 @@ function RAT:Status(message, forID)
-- Aircraft is airborne. -- Aircraft is airborne.
ratcraft["Tground"]=nil ratcraft["Tground"]=nil
ratcraft["Pground"]=nil ratcraft["Pground"]=nil
ratcraft["Uground"]=nil
ratcraft["Tlastcheck"]=nil ratcraft["Tlastcheck"]=nil
else else
--Aircraft is on ground. --Aircraft is on ground.
@@ -3377,14 +3384,37 @@ function RAT:Status(message, forID)
-- If more than Tinactive seconds passed since last check ==> check how much we moved meanwhile. -- If more than Tinactive seconds passed since last check ==> check how much we moved meanwhile.
if dTlast > self.Tinactive then if dTlast > self.Tinactive then
-- If aircraft did not move more than 50 m since last check, we call it stationary and despawn it. --[[
-- Aircraft which are spawned uncontrolled or starting their engines are not counted.
if Dg<50 and active and status~=RAT.status.EventBirth then if Dg<50 and active and status~=RAT.status.EventBirth then
--if Dg<50 and active then
stationary=true stationary=true
end end
]]
-- Set the current time to know when the next check is necessary. -- Loop over all units.
for _,_unit in pairs(group:GetUnits()) do
if _unit and _unit:IsAlive() then
-- Unit name, coord and distance since last check.
local unitname=_unit:GetName()
local unitcoord=_unit:GetCoordinate()
local Ug=unitcoord:Get2DDistance(ratcraft.Uground[unitname])
-- Debug info
self:T2(RAT.id..string.format("Unit %s travelled distance on ground %.1f m since %d seconds.", unitname, Ug, dTlast))
-- If aircraft did not move more than 50 m since last check, we call it stationary and despawn it.
-- Aircraft which are spawned uncontrolled or starting their engines are not counted.
if Ug<50 and active and status~=RAT.status.EventBirth then
stationary=true
end
-- Update coords.
ratcraft["Uground"][unitname]=unitcoord
end
end
-- Set the current time to know when the next check is necessary.
ratcraft["Tlastcheck"]=Tnow ratcraft["Tlastcheck"]=Tnow
ratcraft["Pground"]=coords ratcraft["Pground"]=coords
end end
@@ -3394,6 +3424,11 @@ function RAT:Status(message, forID)
ratcraft["Tground"]=Tnow ratcraft["Tground"]=Tnow
ratcraft["Tlastcheck"]=Tnow ratcraft["Tlastcheck"]=Tnow
ratcraft["Pground"]=coords ratcraft["Pground"]=coords
ratcraft["Uground"]={}
for _,_unit in pairs(group:GetUnits()) do
local unitname=_unit:GetName()
ratcraft.Uground[unitname]=_unit:GetCoordinate()
end
end end
end end
@@ -3674,7 +3709,7 @@ function RAT:_OnBirth(EventData)
end end
if ontop then if ontop then
local text=string.format("ERROR: RAT group of %s was spawned on top of another unit. Group #%d will be despawned immediately!", self.alias, i) local text=string.format("ERROR: Group of %s was spawned on top of another unit. Group #%d will be despawned immediately!", self.alias, i)
MESSAGE:New(text,30):ToAllIf(self.Debug) MESSAGE:New(text,30):ToAllIf(self.Debug)
self:T(RAT.id..text) self:T(RAT.id..text)
if self.Debug then if self.Debug then
@@ -4283,16 +4318,13 @@ function RAT:_Waypoint(index, description, Type, Coord, Speed, Altitude, Airport
if AirbaseCategory == Airbase.Category.SHIP then if AirbaseCategory == Airbase.Category.SHIP then
RoutePoint.linkUnit = AirbaseID RoutePoint.linkUnit = AirbaseID
RoutePoint.helipadId = AirbaseID RoutePoint.helipadId = AirbaseID
--self:T(RAT.id.."WP: Ship id = "..AirbaseID)
elseif AirbaseCategory == Airbase.Category.HELIPAD then elseif AirbaseCategory == Airbase.Category.HELIPAD then
RoutePoint.linkUnit = AirbaseID RoutePoint.linkUnit = AirbaseID
RoutePoint.helipadId = AirbaseID RoutePoint.helipadId = AirbaseID
--self:T(RAT.id.."WP: Helipad id = "..AirbaseID)
elseif AirbaseCategory == Airbase.Category.AIRDROME then elseif AirbaseCategory == Airbase.Category.AIRDROME then
RoutePoint.airdromeId = AirbaseID RoutePoint.airdromeId = AirbaseID
--self:T(RAT.id.."WP: Airdrome id = "..AirbaseID)
else else
--self:E(RAT.id.."Unknown Airport categoryin _Waypoint()!") self:T(RAT.id.."Unknown Airport category in _Waypoint()!")
end end
end end
-- properties -- properties
@@ -5074,7 +5106,7 @@ function RAT:_ModifySpawnTemplate(waypoints, livery, spawnplace, departure, take
nfree=#spots nfree=#spots
if nfree<nunits then if nfree<nunits then
-- Not enough helo ports. Let's try also other terminal types. -- Not enough helo ports. Let's try also other terminal types.
self:T(RAT.id..string.format("Helo group %s is spawned at %s using terminal type %d.", self.alias, departure:GetName(), AIRBASE.TerminalType.HelicopterOnly)) self:T(RAT.id..string.format("Helo group %s is spawned at %s using terminal type %d.", self.alias, departure:GetName(), AIRBASE.TerminalType.HelicopterUsable))
spots=departure:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.HelicopterUsable, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits) spots=departure:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.HelicopterUsable, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits)
nfree=#spots nfree=#spots
end end
@@ -5181,13 +5213,13 @@ function RAT:_ModifySpawnTemplate(waypoints, livery, spawnplace, departure, take
waypoints[1].action = GROUPTEMPLATE.Takeoff[GROUP.Takeoff.Air][2] -- action = Turning Point waypoints[1].action = GROUPTEMPLATE.Takeoff[GROUP.Takeoff.Air][2] -- action = Turning Point
-- Adjust altitude to be 500-1000 m above the airbase. -- Adjust altitude to be 500-1000 m above the airbase.
PointVec3.x=PointVec3.x+math.random(-500,500) PointVec3.x=PointVec3.x+math.random(-1500,1500)
PointVec3.z=PointVec3.z+math.random(-500,500) PointVec3.z=PointVec3.z+math.random(-1500,1500)
if self.category==RAT.cat.heli then if self.category==RAT.cat.heli then
PointVec3.y=PointVec3:GetLandHeight()+math.random(100,1000) PointVec3.y=PointVec3:GetLandHeight()+math.random(100,1000)
else else
-- Randomize position so that multiple AC wont be spawned on top even in air. -- Randomize position so that multiple AC wont be spawned on top even in air.
PointVec3.y=PointVec3:GetLandHeight()+math.random(500,2500) PointVec3.y=PointVec3:GetLandHeight()+math.random(500,3000)
end end
else else
self:E(RAT.id..string.format("WARNING: Group %s has no parking spots at %s ==> No emergency air start or uncontrolled spawning ==> No spawn!", self.SpawnTemplatePrefix, departure:GetName())) self:E(RAT.id..string.format("WARNING: Group %s has no parking spots at %s ==> No emergency air start or uncontrolled spawning ==> No spawn!", self.SpawnTemplatePrefix, departure:GetName()))
@@ -5625,7 +5657,8 @@ end
-- @field #table min Minimum number of RAT groups alive. -- @field #table min Minimum number of RAT groups alive.
-- @field #number nrat Number of RAT objects. -- @field #number nrat Number of RAT objects.
-- @field #number ntot Total number of active RAT groups. -- @field #number ntot Total number of active RAT groups.
-- @field #number Tcheck Time interval between checking of alive groups. -- @field #number Tcheck Time interval in seconds between checking of alive groups.
-- @field #number dTspawn Time interval in seconds between spawns of groups.
-- @field Core.Scheduler#SCHEDULER manager Scheduler managing the RAT objects. -- @field Core.Scheduler#SCHEDULER manager Scheduler managing the RAT objects.
-- @field #number managerid Managing scheduler id. -- @field #number managerid Managing scheduler id.
-- @extends Core.Base#BASE -- @extends Core.Base#BASE
@@ -5676,7 +5709,8 @@ RATMANAGER={
min={}, min={},
nrat=0, nrat=0,
ntot=nil, ntot=nil,
Tcheck=30, Tcheck=60,
dTspawn=1.0,
manager=nil, manager=nil,
managerid=nil, managerid=nil,
} }
@@ -5772,21 +5806,31 @@ function RATMANAGER:_Start()
local N=self:_RollDice(self.nrat, self.ntot, self.min, self.alive) local N=self:_RollDice(self.nrat, self.ntot, self.min, self.alive)
-- Loop over all RAT objects and spawn groups. -- Loop over all RAT objects and spawn groups.
local time=0.0
for i=1,self.nrat do for i=1,self.nrat do
for j=1,N[i] do for j=1,N[i] do
self.rat[i]:_SpawnWithRoute() time=time+self.dTspawn
end SCHEDULER:New(nil, RAT._SpawnWithRoute, {self.rat[i]}, time)
-- Start activation scheduler for uncontrolled aircraft.
if self.rat[i].uncontrolled and self.rat[i].activate_uncontrolled then
SCHEDULER:New(nil, self.rat[i]._ActivateUncontrolled, {self.rat[i]}, self.rat[i].activate_delay, self.rat[i].activate_delta, self.rat[i].activate_frand)
end end
end end
-- Start activation scheduler for uncontrolled aircraft.
for i=1,self.nrat do
if self.rat[i].uncontrolled and self.rat[i].activate_uncontrolled then
-- Start activating stuff but not before the latest spawn has happend.
local Tactivate=math.max(time+1, self.rat[i].activate_delay)
SCHEDULER:New(self.rat[i], self.rat[i]._ActivateUncontrolled, {self.rat[i]}, Tactivate, self.rat[i].activate_delta, self.rat[i].activate_frand)
end
end
-- Start the manager. But not earlier than the latest spawn has happened!
local TstartManager=math.max(time+1, self.Tcheck)
-- Start manager scheduler. -- Start manager scheduler.
self.manager, self.managerid = SCHEDULER:New(nil, self._Manage, {self}, 5, self.Tcheck) --Core.Scheduler#SCHEDULER self.manager, self.managerid = SCHEDULER:New(self, self._Manage, {self}, TstartManager, self.Tcheck) --Core.Scheduler#SCHEDULER
-- Info -- Info
local text=string.format(RATMANAGER.id.."Starting RAT manager with scheduler ID %s.", self.managerid) local text=string.format(RATMANAGER.id.."Starting RAT manager with scheduler ID %s in %d seconds. Repeat interval %d seconds.", self.managerid, TstartManager, self.Tcheck)
self:E(text) self:E(text)
return self return self
@@ -5812,15 +5856,25 @@ function RATMANAGER:_Stop()
return self return self
end end
--- Sets the time interval between checks of alive RAT groups. Default is 30 seconds. --- Sets the time interval between checks of alive RAT groups. Default is 60 seconds.
-- @param #RATMANAGER self -- @param #RATMANAGER self
-- @param #number dt Time interval in seconds. -- @param #number dt Time interval in seconds.
-- @return #RATMANAGER RATMANAGER self object. -- @return #RATMANAGER RATMANAGER self object.
function RATMANAGER:SetTcheck(dt) function RATMANAGER:SetTcheck(dt)
self.Tcheck=dt or 30 self.Tcheck=dt or 60
return self return self
end end
--- Sets the time interval between spawning of groups.
-- @param #RATMANAGER self
-- @param #number dt Time interval in seconds. Default is 1 second.
-- @return #RATMANAGER RATMANAGER self object.
function RATMANAGER:SetTspawn(dt)
self.dTspawn=dt or 1.0
return self
end
--- Manager function. Calculating the number of current groups and respawning new groups if necessary. --- Manager function. Calculating the number of current groups and respawning new groups if necessary.
-- @param #RATMANAGER self -- @param #RATMANAGER self
function RATMANAGER:_Manage() function RATMANAGER:_Manage()
@@ -5829,18 +5883,18 @@ function RATMANAGER:_Manage()
local ntot=self:_Count() local ntot=self:_Count()
-- Debug info. -- Debug info.
if self.Debug then local text=string.format("Number of alive groups %d. New groups to be spawned %d.", ntot, self.ntot-ntot)
local text=string.format("Number of alive groups %d. New groups to be spawned %d.", ntot, self.ntot-ntot) self:T(RATMANAGER.id..text)
self:T(RATMANAGER.id..text)
end
-- Get number of necessary spawns. -- Get number of necessary spawns.
local N=self:_RollDice(self.nrat, self.ntot, self.min, self.alive) local N=self:_RollDice(self.nrat, self.ntot, self.min, self.alive)
-- Loop over all RAT objects and spawn new groups if necessary. -- Loop over all RAT objects and spawn new groups if necessary.
local time=0.0
for i=1,self.nrat do for i=1,self.nrat do
for j=1,N[i] do for j=1,N[i] do
self.rat[i]:_SpawnWithRoute() time=time+self.dTspawn
SCHEDULER:New(nil, RAT._SpawnWithRoute, {self.rat[i]}, time)
end end
end end
end end
@@ -5873,10 +5927,8 @@ function RATMANAGER:_Count()
ntotal=ntotal+n ntotal=ntotal+n
-- Debug output. -- Debug output.
if self.Debug then local text=string.format("Number of alive groups of %s = %d", self.name[i], n)
local text=string.format("Number of alive groups of %s = %d", self.name[i], n) self:T(RATMANAGER.id..text)
self:T(RATMANAGER.id..text)
end
end end
-- Return grand total. -- Return grand total.
@@ -5969,14 +6021,12 @@ function RATMANAGER:_RollDice(nrat,ntot,min,alive)
table.insert(done,j) table.insert(done,j)
-- Debug info -- Debug info
if self.Debug then local text=RATMANAGER.id.."\n"
local text=RATMANAGER.id.."\n" for i=1,nrat do
for i=1,nrat do text=text..string.format("%s: i=%d, alive=%d, min=%d, mini=%d, maxi=%d, add=%d\n", self.name[i], i, alive[i], min[i], mini[i], maxi[i], N[i])
text=text..string.format("%s: i=%d, alive=%d, min=%d, mini=%d, maxi=%d, add=%d\n", self.name[i], i, alive[i], min[i], mini[i], maxi[i], N[i])
end
text=text..string.format("Total # of groups to add = %d", sum(N, done))
self:T2(text)
end end
text=text..string.format("Total # of groups to add = %d", sum(N, done))
self:T(text)
-- Return number of groups to be spawned. -- Return number of groups to be spawned.
return N return N

View File

@@ -626,9 +626,9 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
end end
-- Function calculating the overlap of two (square) objects. -- Function calculating the overlap of two (square) objects.
local function _overlap(mooseobject, dcsobject, dist) local function _overlap(object1, mooseobject1, object2, mooseobject2, dist)
local l1=_GetObjectSize(mooseobject, true) local l1=_GetObjectSize(object1, mooseobject1)
local l2=_GetObjectSize(dcsobject) local l2=_GetObjectSize(object2, mooseobject2)
local safedist=(l1/2+l2/2)*1.1 local safedist=(l1/2+l2/2)*1.1
local safe = (dist > safedist) local safe = (dist > safedist)
self:T3(string.format("l1=%.1f l2=%.1f s=%.1f d=%.1f ==> safe=%s", l1,l2,safedist,dist,tostring(safe))) self:T3(string.format("l1=%.1f l2=%.1f s=%.1f d=%.1f ==> safe=%s", l1,l2,safedist,dist,tostring(safe)))
@@ -676,10 +676,10 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
local _termid=parkingspot.TerminalID local _termid=parkingspot.TerminalID
-- Very safe uses the DCS getParking() info to check if a spot is free. Unfortunately, the function returns free=false until the aircraft has actually taken-off. -- Very safe uses the DCS getParking() info to check if a spot is free. Unfortunately, the function returns free=false until the aircraft has actually taken-off.
if verysafe and parkingspot.Free==false then if verysafe and (parkingspot.Free==false or parkingspot.TOAC==true) then
-- DCS getParking() routine returned that spot is not free. -- DCS getParking() routine returned that spot is not free.
self:T(string.format("%s: Parking spot id %d NOT free (or aircraft has not taken off yet).", airport, parkingspot.TerminalID)) self:E(string.format("%s: Parking spot id %d NOT free (or aircraft has not taken off yet). Free=%s, TOAC=%s.", airport, parkingspot.TerminalID, tostring(parkingspot.Free), tostring(parkingspot.TOAC)))
else else
@@ -695,7 +695,7 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
local _vec3=unit:getPoint() local _vec3=unit:getPoint()
local _coord=COORDINATE:NewFromVec3(_vec3) local _coord=COORDINATE:NewFromVec3(_vec3)
local _dist=_coord:Get2DDistance(_spot) local _dist=_coord:Get2DDistance(_spot)
local _safe=_overlap(aircraft, unit, _dist) local _safe=_overlap(aircraft, true, unit, false,_dist)
if markobstacles then if markobstacles then
local l,x,y,z=_GetObjectSize(unit) local l,x,y,z=_GetObjectSize(unit)
@@ -712,7 +712,7 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
local _vec3=static:getPoint() local _vec3=static:getPoint()
local _coord=COORDINATE:NewFromVec3(_vec3) local _coord=COORDINATE:NewFromVec3(_vec3)
local _dist=_coord:Get2DDistance(_spot) local _dist=_coord:Get2DDistance(_spot)
local _safe=_overlap(aircraft, static, _dist) local _safe=_overlap(aircraft, true, static, false,_dist)
if markobstacles then if markobstacles then
local l,x,y,z=_GetObjectSize(static) local l,x,y,z=_GetObjectSize(static)
@@ -729,7 +729,7 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
local _vec3=scenery:getPoint() local _vec3=scenery:getPoint()
local _coord=COORDINATE:NewFromVec3(_vec3) local _coord=COORDINATE:NewFromVec3(_vec3)
local _dist=_coord:Get2DDistance(_spot) local _dist=_coord:Get2DDistance(_spot)
local _safe=_overlap(aircraft, scenery, _dist) local _safe=_overlap(aircraft, true, scenery, false,_dist)
if markobstacles then if markobstacles then
local l,x,y,z=_GetObjectSize(scenery) local l,x,y,z=_GetObjectSize(scenery)
@@ -741,6 +741,15 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
end end
end end
-- Now check the already given spots so that we do not put a large aircraft next to one we already assigned a nearby spot.
for _,_takenspot in pairs(validspots) do
local _dist=_takenspot.Coordinate:Get2DDistance(_spot)
local _safe=_overlap(aircraft, true, aircraft, true,_dist)
if not _safe then
occupied=true
end
end
--_spot:MarkToAll(string.format("Parking spot %d free=%s", parkingspot.TerminalID, tostring(not occupied))) --_spot:MarkToAll(string.format("Parking spot %d free=%s", parkingspot.TerminalID, tostring(not occupied)))
if occupied then if occupied then
self:T(string.format("%s: Parking spot id %d occupied.", airport, _termid)) self:T(string.format("%s: Parking spot id %d occupied.", airport, _termid))
@@ -752,12 +761,13 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
nvalid=nvalid+1 nvalid=nvalid+1
end end
end end -- loop over units
-- We found enough spots. -- We found enough spots.
if nvalid>=_nspots then if nvalid>=_nspots then
return validspots return validspots
end end
end end
-- Retrun spots we found, even if there were not enough. -- Retrun spots we found, even if there were not enough.