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
commit 9f644b65fd
2 changed files with 115 additions and 55 deletions

View File

@ -385,12 +385,12 @@ RAT={
onboardnum=nil, -- Tail number.
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.
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.
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.
termtype=nil, -- Terminal type.
parkingscanradius=50, -- Scan radius.
parkingscanradius=40, -- Scan radius.
parkingscanscenery=false, -- Scan parking spots for scenery obstacles.
parkingverysafe=false, -- Very safe option.
}
@ -511,7 +511,7 @@ RAT.id="RAT | "
--- RAT version.
-- @list version
RAT.version={
version = "2.3.1",
version = "2.3.2",
print = true,
}
@ -2124,10 +2124,16 @@ function RAT:_SpawnWithRoute(_departure, _destination, _takeoff, _landing, _live
if group:InAir() then
self.ratcraft[self.SpawnIndex]["Tground"]=nil
self.ratcraft[self.SpawnIndex]["Pground"]=nil
self.ratcraft[self.SpawnIndex]["Uground"]=nil
self.ratcraft[self.SpawnIndex]["Tlastcheck"]=nil
else
self.ratcraft[self.SpawnIndex]["Tground"]=timer.getTime()
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()
end
-- Initial and current position. For calculating the travelled distance.
@ -3361,6 +3367,7 @@ function RAT:Status(message, forID)
-- Aircraft is airborne.
ratcraft["Tground"]=nil
ratcraft["Pground"]=nil
ratcraft["Uground"]=nil
ratcraft["Tlastcheck"]=nil
else
--Aircraft is on ground.
@ -3377,16 +3384,39 @@ function RAT:Status(message, forID)
-- If more than Tinactive seconds passed since last check ==> check how much we moved meanwhile.
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 then
stationary=true
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["Pground"]=coords
ratcraft["Pground"]=coords
end
else
@ -3394,6 +3424,11 @@ function RAT:Status(message, forID)
ratcraft["Tground"]=Tnow
ratcraft["Tlastcheck"]=Tnow
ratcraft["Pground"]=coords
ratcraft["Uground"]={}
for _,_unit in pairs(group:GetUnits()) do
local unitname=_unit:GetName()
ratcraft.Uground[unitname]=_unit:GetCoordinate()
end
end
end
@ -3605,7 +3640,7 @@ function RAT:_OnBirth(EventData)
end
self:_SetStatus(SpawnGroup, status)
-- Get some info ablout this flight.
-- Get some info ablout this flight.
local i=self:GetSpawnIndexFromGroup(SpawnGroup)
local _departure=self.ratcraft[i].departure:GetName()
local _destination=self.ratcraft[i].destination:GetName()
@ -3674,7 +3709,7 @@ function RAT:_OnBirth(EventData)
end
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)
self:T(RAT.id..text)
if self.Debug then
@ -4283,16 +4318,13 @@ function RAT:_Waypoint(index, description, Type, Coord, Speed, Altitude, Airport
if AirbaseCategory == Airbase.Category.SHIP then
RoutePoint.linkUnit = AirbaseID
RoutePoint.helipadId = AirbaseID
--self:T(RAT.id.."WP: Ship id = "..AirbaseID)
elseif AirbaseCategory == Airbase.Category.HELIPAD then
RoutePoint.linkUnit = AirbaseID
RoutePoint.helipadId = AirbaseID
--self:T(RAT.id.."WP: Helipad id = "..AirbaseID)
elseif AirbaseCategory == Airbase.Category.AIRDROME then
RoutePoint.airdromeId = AirbaseID
--self:T(RAT.id.."WP: Airdrome id = "..AirbaseID)
else
--self:E(RAT.id.."Unknown Airport categoryin _Waypoint()!")
self:T(RAT.id.."Unknown Airport category in _Waypoint()!")
end
end
-- properties
@ -5074,7 +5106,7 @@ function RAT:_ModifySpawnTemplate(waypoints, livery, spawnplace, departure, take
nfree=#spots
if nfree<nunits then
-- 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)
nfree=#spots
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
-- Adjust altitude to be 500-1000 m above the airbase.
PointVec3.x=PointVec3.x+math.random(-500,500)
PointVec3.z=PointVec3.z+math.random(-500,500)
PointVec3.x=PointVec3.x+math.random(-1500,1500)
PointVec3.z=PointVec3.z+math.random(-1500,1500)
if self.category==RAT.cat.heli then
PointVec3.y=PointVec3:GetLandHeight()+math.random(100,1000)
else
-- 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
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()))
@ -5625,7 +5657,8 @@ end
-- @field #table min Minimum number of RAT groups alive.
-- @field #number nrat Number of RAT objects.
-- @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 #number managerid Managing scheduler id.
-- @extends Core.Base#BASE
@ -5676,7 +5709,8 @@ RATMANAGER={
min={},
nrat=0,
ntot=nil,
Tcheck=30,
Tcheck=60,
dTspawn=1.0,
manager=nil,
managerid=nil,
}
@ -5772,21 +5806,31 @@ function RATMANAGER:_Start()
local N=self:_RollDice(self.nrat, self.ntot, self.min, self.alive)
-- Loop over all RAT objects and spawn groups.
local time=0.0
for i=1,self.nrat do
for j=1,N[i] do
self.rat[i]:_SpawnWithRoute()
end
-- 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)
time=time+self.dTspawn
SCHEDULER:New(nil, RAT._SpawnWithRoute, {self.rat[i]}, time)
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.
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
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)
return self
@ -5812,15 +5856,25 @@ function RATMANAGER:_Stop()
return self
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 #number dt Time interval in seconds.
-- @return #RATMANAGER RATMANAGER self object.
function RATMANAGER:SetTcheck(dt)
self.Tcheck=dt or 30
self.Tcheck=dt or 60
return self
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.
-- @param #RATMANAGER self
function RATMANAGER:_Manage()
@ -5829,18 +5883,18 @@ function RATMANAGER:_Manage()
local ntot=self:_Count()
-- 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)
self:T(RATMANAGER.id..text)
end
local text=string.format("Number of alive groups %d. New groups to be spawned %d.", ntot, self.ntot-ntot)
self:T(RATMANAGER.id..text)
-- Get number of necessary spawns.
local N=self:_RollDice(self.nrat, self.ntot, self.min, self.alive)
-- Loop over all RAT objects and spawn new groups if necessary.
local time=0.0
for i=1,self.nrat 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
@ -5873,10 +5927,8 @@ function RATMANAGER:_Count()
ntotal=ntotal+n
-- Debug output.
if self.Debug then
local text=string.format("Number of alive groups of %s = %d", self.name[i], n)
self:T(RATMANAGER.id..text)
end
local text=string.format("Number of alive groups of %s = %d", self.name[i], n)
self:T(RATMANAGER.id..text)
end
-- Return grand total.
@ -5969,14 +6021,12 @@ function RATMANAGER:_RollDice(nrat,ntot,min,alive)
table.insert(done,j)
-- Debug info
if self.Debug then
local text=RATMANAGER.id.."\n"
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])
end
text=text..string.format("Total # of groups to add = %d", sum(N, done))
self:T2(text)
local text=RATMANAGER.id.."\n"
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])
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 N

View File

@ -626,9 +626,9 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
end
-- Function calculating the overlap of two (square) objects.
local function _overlap(mooseobject, dcsobject, dist)
local l1=_GetObjectSize(mooseobject, true)
local l2=_GetObjectSize(dcsobject)
local function _overlap(object1, mooseobject1, object2, mooseobject2, dist)
local l1=_GetObjectSize(object1, mooseobject1)
local l2=_GetObjectSize(object2, mooseobject2)
local safedist=(l1/2+l2/2)*1.1
local safe = (dist > safedist)
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
-- 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.
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
@ -695,7 +695,7 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
local _vec3=unit:getPoint()
local _coord=COORDINATE:NewFromVec3(_vec3)
local _dist=_coord:Get2DDistance(_spot)
local _safe=_overlap(aircraft, unit, _dist)
local _safe=_overlap(aircraft, true, unit, false,_dist)
if markobstacles then
local l,x,y,z=_GetObjectSize(unit)
@ -712,7 +712,7 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
local _vec3=static:getPoint()
local _coord=COORDINATE:NewFromVec3(_vec3)
local _dist=_coord:Get2DDistance(_spot)
local _safe=_overlap(aircraft, static, _dist)
local _safe=_overlap(aircraft, true, static, false,_dist)
if markobstacles then
local l,x,y,z=_GetObjectSize(static)
@ -728,8 +728,8 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
for _,scenery in pairs(_sceneries) do
local _vec3=scenery:getPoint()
local _coord=COORDINATE:NewFromVec3(_vec3)
local _dist=_coord:Get2DDistance(_spot)
local _safe=_overlap(aircraft, scenery, _dist)
local _dist=_coord:Get2DDistance(_spot)
local _safe=_overlap(aircraft, true, scenery, false,_dist)
if markobstacles then
local l,x,y,z=_GetObjectSize(scenery)
@ -741,6 +741,15 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
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)))
if occupied then
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
end
end
end -- loop over units
-- We found enough spots.
if nvalid>=_nspots then
return validspots
end
end
-- Retrun spots we found, even if there were not enough.