From 69c8d52f52da50ea3cbfc3dc934b16c1534b960f Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 16 Sep 2019 23:23:00 +0200 Subject: [PATCH] Ops --- Moose Development/Moose/Core/RadioQueue.lua | 3 + Moose Development/Moose/Ops/FlightControl.lua | 143 ++++++++---------- Moose Development/Moose/Ops/FlightGroup.lua | 120 ++++++++++++--- 3 files changed, 166 insertions(+), 100 deletions(-) diff --git a/Moose Development/Moose/Core/RadioQueue.lua b/Moose Development/Moose/Core/RadioQueue.lua index 8ee0d7749..2523c9d2d 100644 --- a/Moose Development/Moose/Core/RadioQueue.lua +++ b/Moose Development/Moose/Core/RadioQueue.lua @@ -169,6 +169,8 @@ function RADIOQUEUE:AddTransmission(transmission) -- Add to queue. table.insert(self.queue, transmission) + + --TODO: Start scheduler. return self end @@ -343,6 +345,7 @@ function RADIOQUEUE:_CheckRadioQueue() -- Check if queue is empty. if #self.queue==0 then + --TODO: stop scheduler. return end diff --git a/Moose Development/Moose/Ops/FlightControl.lua b/Moose Development/Moose/Ops/FlightControl.lua index e266e4d4d..0d55d914b 100644 --- a/Moose Development/Moose/Ops/FlightControl.lua +++ b/Moose Development/Moose/Ops/FlightControl.lua @@ -31,6 +31,8 @@ -- @field #table Qtakeoff Queue of aircraft about to takeoff. -- @field #table Qparking Queue of aircraft parking. -- @field #number activerwyno Number of active runway. +-- @field #number atcfreq ATC radio frequency. +-- @field Core.RadioQueue#RADIOQUEUE atcradio ATC radio queue. -- @extends Core.Fsm#FSM --- Be surprised! @@ -61,6 +63,8 @@ FLIGHTCONTROL = { Qtakeoff = {}, Qparking = {}, activerwyno = 1, + atcfreq = nil, + atcradio = nil, } --- Holding point @@ -222,6 +226,9 @@ function FLIGHTCONTROL:onafterStart() self:HandleEvent(EVENTS.EngineShutdown) self:HandleEvent(EVENTS.Crash) + self.atcradio=RADIOQUEUE:New(self.atcfreq or 305) + self.atcradio:Start(1, 0.01) + -- Init status updates. self:__Status(-1) end @@ -522,23 +529,44 @@ function FLIGHTCONTROL:_CheckQueues() -- Print queues self:_PrintQueue(self.flights, "All flights") - self:_PrintQueue(self.Qparking, "Parking") + self:_PrintQueue(self.Qparking, "Parking") self:_PrintQueue(self.Qtakeoff, "Takeoff") self:_PrintQueue(self.Qwaiting, "Holding") - self:_PrintQueue(self.Qlanding, "Landing") + self:_PrintQueue(self.Qlanding, "Landing") -- Get next wairing flight. - local flight=self:_GetNextWaitingFight() + local flight=self:_GetNextFightWaiting() - -- Number of groups landing. - local nlanding=#self.Qlanding + if flight then - -- Number of groups taking off. - local ntakeoff=#self.Qtakeoff + -- Number of groups landing. + local nlanding=#self.Qlanding + + -- Number of groups taking off. + local ntakeoff=#self.Qtakeoff + + if nlanding==0 and ntakeoff==0 then + local text=string.format("Flight %s, you are cleared to taxi to runway.", flight.groupname) + MESSAGE:New(text, 5, "FLIGHTCONTROL"):ToAll() + self:_LandAI(flight) + end + + else + + -- Get next wairing flight. + local flight=self:_GetNextFightParking() + + if flight then + local text=string.format("Flight %s, you are cleared to taxi to runway.", flight.groupname) + MESSAGE:New(text, 5, "FLIGHTCONTROL"):ToAll() + + flight.group:StartUncontrolled() + + flight:_UpdateRoute(1) + + self:_RemoveFlightFromQueue(self.Qparking, flight, "parking") + end - if flight and nlanding==0 and ntakeoff==0 then - self:_LandAI(flight) - self:_RemoveFlightFromQueue(self.Qwaiting, flight) end end @@ -596,7 +624,7 @@ end --- Get next flight waiting for landing clearance. -- @param #FLIGHTCONTROL self -- @return Ops.FlightGroup#FLIGHTGROUP Marshal flight next in line and ready to enter the pattern. Or nil if no flight is ready. -function FLIGHTCONTROL:_GetNextWaitingFight() +function FLIGHTCONTROL:_GetNextFightWaiting() -- Loop over all marshal flights. for _,_flight in pairs(self.Qwaiting) do @@ -611,6 +639,25 @@ function FLIGHTCONTROL:_GetNextWaitingFight() return nil end + +--- Get next flight waiting for landing clearance. +-- @param #FLIGHTCONTROL self +-- @return Ops.FlightGroup#FLIGHTGROUP Marshal flight next in line and ready to enter the pattern. Or nil if no flight is ready. +function FLIGHTCONTROL:_GetNextFightParking() + + -- Loop over all marshal flights. + for _,_flight in pairs(self.Qparking) do + local flight=_flight --Ops.FlightGroup#FLIGHTGROUP + + -- TODO: Sort by fuel, holding time. + + return flight + + end + + return nil +end + --- Print queue. -- @param #FLIGHTCONTROL self -- @param #table queue Queue to print. @@ -658,9 +705,12 @@ end -- @param #FLIGHTCONTROL self -- @param #table queue The queue from which the group will be removed. -- @param Ops.FlightGroup#FLIGHTGROUP flight Flight group that will be removed from queue. +-- @param #string queuename Name of the queue. -- @return #boolean True, flight was in Queue and removed. False otherwise. -- @return #number Table index of removed queue element or nil. -function FLIGHTCONTROL:_RemoveFlightFromQueue(queue, flight) +function FLIGHTCONTROL:_RemoveFlightFromQueue(queue, flight, queuename) + + queuename=queuename or "unknown" -- Loop over all flights in group. for i,_flight in pairs(queue) do @@ -668,33 +718,16 @@ function FLIGHTCONTROL:_RemoveFlightFromQueue(queue, flight) -- Check for name. if qflight.groupname==flight.groupname then - self:I(self.lid..string.format("Removing flight group %s from queue.", flight.groupname)) + self:I(self.lid..string.format("Removing flight group %s from %s queue.", flight.groupname, queuename)) table.remove(queue, i) return true, i end end - self:I(self.lid..string.format("Could NOT remove flight group %s from queue.", flight.groupname)) + self:I(self.lid..string.format("Could NOT remove flight group %s from %s queue.", flight.groupname, queuename)) return false, nil end ---- Set tookoff to true for the flight element. --- @param #FLIGHTCONTROL self --- @param Wrapper.Unit#UNIT unit The aircraft unit that was recovered. --- @return Ops.FlightGroup#FLIGHTGROUP Flight group of element. -function FLIGHTCONTROL:_ElementTookOff(unit) - - -- Get element of flight. - local element, idx, flight=self:_GetFlightElement(unit:GetName()) --#FLIGHTCONTROL.FlightElement - - -- Nil check. Could be if a helo landed or something else we dont know! - if element then - element.tookoff=true - end - - return flight -end - --- Add flight to landing queue and set recovered to false for all elements of the flight and its section members. -- @param #FLIGHTCONTROL self -- @param Ops.FlightGroup#FLIGHTGROUP flight Flight group of element. @@ -1119,53 +1152,11 @@ function FLIGHTCONTROL:_LandAI(flight) -- Add flight to landing queue. table.insert(self.Qlanding, flight) + -- Give signal to land. flight.flaghold:Set(1) - if true then - return - end - - - - -- Airbase position. - local airbase=self.airbase:GetCoordinate() - - -- Waypoints array. - local wp={} - - -- Current speed. - local CurrentSpeed=flight.group:GetVelocityKMH() - - -- Aircraft speed when flying the pattern. - local Speed=UTILS.KnotsToKmph(150) - - -- Current positon. - wp[#wp+1]=flight.group:GetCoordinate():WaypointAirTurningPoint(nil, CurrentSpeed, {}, "Current position") - - - -- Get active runway. - local runway=self:_GetActiveRunway() - - -- TODO: make dependend on AC type helos etc. - - -- Approach point: 10 NN in direction of runway. - local papproach=runway.position:Translate(UTILS.NMToMeters(10), runway.direction):SetAltitude(1000) - papproach:MarkToAll("Approach Point") - - -- Approach waypoint. - wp[#wp+1]=papproach:WaypointAirTurningPoint(nil ,Speed, {}, "Final Approach") - - -- Landing waypoint. - wp[#wp+1]=airbase:WaypointAirLanding(Speed, self.airbase, nil, "Landing") - - -- Reinit waypoints. - flight.group:WayPointInitialize(wp) - - -- Route group. - flight.group:Route(wp, 1) - - -- Add flight to landing queue. - table.insert(self.Qlanding, flight) + -- Remove flight from waiting queue. + self:_RemoveFlightFromQueue(self.Qwaiting, flight, "holding") end --- Function called when a group has reached the holding zone. diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index e451c8b69..814660dff 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -62,7 +62,7 @@ FLIGHTGROUP = { flightgroup = nil, grouptemplate = nil, type = nil, - waypoints = {}, + waypoints = nil, coordinates = {}, elements = {}, taskqueue = {}, @@ -121,6 +121,7 @@ FLIGHTGROUP.ElementStatus={ -- @field #string status Status, i.e. born, parking, taxiing. See @{#FLIGHTGROUP.ElementStatus}. -- @field #table pylons Table of pylons. -- @field #number damage Damage of element in percent. +-- @field Wrapper.Airbase#AIRBASE.ParkingSpot parking The parking spot table the element is parking on. --- Flight group tasks. -- @type FLIGHTGROUP.Mission @@ -180,7 +181,7 @@ FLIGHTGROUP.TaskType={ --- FLIGHTGROUP class version. -- @field #string version -FLIGHTGROUP.version="0.1.1" +FLIGHTGROUP.version="0.1.2" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -595,7 +596,7 @@ end function FLIGHTGROUP:onafterStart(From, Event, To) -- Short info. - local text=string.format("Starting flight group %s.", self.groupname) + local text=string.format("Starting flight group v%s", FLIGHTGROUP.version) self:I(self.sid..text) -- Check if the group is already alive and if so, add its elements. @@ -969,7 +970,18 @@ function FLIGHTGROUP:onafterElementSpawned(From, Event, To, Element) if Element.unit:InAir() then self:ElementAirborne(Element) else - self:ElementParking(Element) + + -- Get parking spot. + local spot, dist=self:GetParkingSpot(Element) + + if dist<10 then + + Element.parking=spot + + self:ElementParking(Element) + else + self:E(self.sid..string.format("Element spawned not in air but not on any parking spot.")) + end end end @@ -980,8 +992,8 @@ end -- @param #string To To state. -- @param #FLIGHTGROUP.Element Element The flight group element. function FLIGHTGROUP:onafterElementParking(From, Event, To, Element) - self:I(self.sid..string.format("Element parking %s.", Element.name)) - + self:I(self.sid..string.format("Element parking %s at spot %s.", Element.name, tostring(Element.parking.TerminalID))) + -- Set element status. self:_UpdateStatus(Element, FLIGHTGROUP.ElementStatus.PARKING) end @@ -994,6 +1006,9 @@ end -- @param #FLIGHTGROUP.Element Element The flight group element. function FLIGHTGROUP:onafterElementTaxiing(From, Event, To, Element) self:I(self.sid..string.format("Element taxiing %s.", Element.name)) + + -- Not parking any more. + Element.parking=nil -- Set element status. self:_UpdateStatus(Element, FLIGHTGROUP.ElementStatus.TAXIING) @@ -1082,15 +1097,38 @@ function FLIGHTGROUP:onafterFlightSpawned(From, Event, To) self.speedmax=self.group:GetSpeedMax() -- Init waypoints. - self:_InitWaypoints() - - -- Update route. - self:_UpdateRoute(1) - - -- Route flight group but now with passing waypoint tasks. - --self.group:Route(self.waypoints) + if not self.waypoints then + self:InitWaypoints() + end + end +--- On after "FlightParking" event. Add flight to flightcontrol of airbase. +-- @param #FLIGHTGROUP self +-- @param Wrapper.Group#GROUP Group Flight group. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function FLIGHTGROUP:onafterFlightParking(From, Event, To) + + local airbase=self.group:GetCoordinate():GetClosestAirbase() + + local airbasename=airbase:GetName() or "unknown" + + local flightcontrol=_DATABASE:GetFlightControl(airbasename) + + if flightcontrol then + self:SetFlightControl(flightcontrol) + + if self.flightcontrol then + + table.insert(self.flightcontrol.Qparking, self) + + end + end +end + + --- On after "FlightTaxiing" event. -- @param #FLIGHTGROUP self -- @param Wrapper.Group#GROUP Group Flight group. @@ -1119,7 +1157,7 @@ function FLIGHTGROUP:onafterFlightTakeoff(From, Event, To, airbase) self:I(self.sid..string.format("Flight takeoff %s at %s.", self.groupname, airbase and airbase:GetName() or "unknown airbase")) if self.flightcontrol and airbase and self.flightcontrol.airbasename==airbase:GetName() then - self.flightcontrol:_RemoveFlightFromQueue(self.flightcontrol.Qtakeoff, self) + self.flightcontrol:_RemoveFlightFromQueue(self.flightcontrol.Qtakeoff, self, "takeoff") end -- Trigger airborne event. @@ -1138,7 +1176,7 @@ function FLIGHTGROUP:onafterFlightAirborne(From, Event, To, airbase) -- Remove flight from FC takeoff queue. if self.flightcontrol and airbase and self.flightcontrol.airbasename==airbase:GetName() then - self.flightcontrol:_RemoveFlightFromQueue(self.flightcontrol.Qtakeoff, self) + self.flightcontrol:_RemoveFlightFromQueue(self.flightcontrol.Qtakeoff, self, "takeoff") end -- Update queue. @@ -1156,7 +1194,7 @@ function FLIGHTGROUP:onafterFlightLanded(From, Event, To, airbase) self:I(self.sid..string.format("Flight landed %s at %s.", self.groupname, airbase and airbase:GetName() or "unknown airbase")) if self.flightcontrol and airbase and self.flightcontrol.airbasename==airbase:GetName() then - self.flightcontrol:_RemoveFlightFromQueue(self.flightcontrol.Qlanding, self) + self.flightcontrol:_RemoveFlightFromQueue(self.flightcontrol.Qlanding, self, "landing") end end @@ -1305,11 +1343,14 @@ function FLIGHTGROUP:onafterHold(From, Event, To, airbase, SpeedTo, SpeedHold) MESSAGE:New(text, 10, "DEBUG"):ToAllIf(self.Debug) self:I(self.sid..text) - local fc=_DATABASE:GetFlightControl(airbase:GetName()) + -- Holding points. local p0=airbase:GetZone():GetRandomCoordinate():SetAltitude(UTILS.FeetToMeters(6000)) local p1=nil local wpap=nil + + -- Do we have a flight control? + local fc=_DATABASE:GetFlightControl(airbase:GetName()) if fc then -- Get holding point from flight control. local HoldingPoint=fc:_GetHoldingpoint(self) @@ -1325,11 +1366,11 @@ function FLIGHTGROUP:onafterHold(From, Event, To, airbase, SpeedTo, SpeedHold) -- TODO: make dependend on AC type helos etc. -- Approach point: 10 NN in direction of runway. - local papproach=runway.position:Translate(UTILS.NMToMeters(10), runway.direction):SetAltitude(1000) + local papproach=runway.position:Translate(UTILS.NMToMeters(15), runway.direction):SetAltitude(UTILS.FeetToMeters(1700)) papproach:MarkToAll("Approach Point") -- Approach waypoint. - wpap=papproach:WaypointAirTurningPoint(nil, UTILS.KnotsToKmph(SpeedTo), {}, "Final Approach") + wpap=papproach:WaypointAirTurningPoint(nil, UTILS.KnotsToKmph(170), {}, "Final Approach") -- Set flightcontrol for this flight. self:SetFlightControl(fc) @@ -1373,19 +1414,21 @@ function FLIGHTGROUP:onafterHold(From, Event, To, airbase, SpeedTo, SpeedHold) end + -- Route the group. self.group:Route(wp, 1) end ---- On after TaskPause event. --- @param Wrapper.Group#GROUP group --- @param #FLIGHTGROUP flightgroup +--- Function called when flight has reached the holding point. +-- @param Wrapper.Group#GROUP group Group object. +-- @param #FLIGHTGROUP flightgroup Flight group object. function FLIGHTGROUP._ReachedHolding(group, flightgroup) env.info(string.format("FF group %s reached holding point", group:GetName())) group:GetCoordinate():MarkToAll("Holding Point Reached") flightgroup.flaghold:Set(666) + -- Add flight to waiting/holding queue. if flightgroup.flightcontrol then table.insert(flightgroup.flightcontrol.Qwaiting, flightgroup) end @@ -2040,11 +2083,12 @@ end --- Initialize Mission Editor waypoints. -- @param #FLIGHTGROUP self +-- @param #table waypoints Table of waypoints. Default is from group template. -- @return #FLIGHTGROUP self -function FLIGHTGROUP:_InitWaypoints() +function FLIGHTGROUP:InitWaypoints(waypoints) -- Waypoints of group as defined in the ME. - self.waypoints=self.group:GetTemplateRoutePoints() + self.waypoints=waypoints or self.group:GetTemplateRoutePoints() -- Update waypoint tasks. self:_UpdateWaypointTasks() @@ -2073,6 +2117,11 @@ function FLIGHTGROUP:_InitWaypoints() -- Set current waypoint. Counting starts a one. self.currentwp=1 + + -- Update route. + if #self.waypoints>0 then + self:_UpdateRoute(1) + end return self end @@ -2670,6 +2719,29 @@ function FLIGHTGROUP:_GetPlayerUnitAndName(_unitName) return nil,nil end +--- Returns the coalition side. +-- @param #FLIGHTGROUP self +-- @return #number Coalition side number. +function FLIGHTGROUP:GetCoalition() + return self.group:GetCoalition() +end + +--- Returns the coalition side. +-- @param #FLIGHTGROUP self +-- @param #FLIGHTGROUP.Element element Element of the flight group. +-- @return Wrapper.Airbase#AIRBASE.ParkingSpot +-- @return #number Distance to spot in meters. +function FLIGHTGROUP:GetParkingSpot(element) + + local coord=element.unit:GetCoordinate() + + local ab=coord:GetClosestAirbase(nil, self:GetCoalition()) + + local _,_,dist,spot=coord:GetClosestParkingSpot(ab) + + return spot, dist +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------