diff --git a/Moose Development/Moose/Core/Fsm.lua b/Moose Development/Moose/Core/Fsm.lua index fb7be648b..972071634 100644 --- a/Moose Development/Moose/Core/Fsm.lua +++ b/Moose Development/Moose/Core/Fsm.lua @@ -5,6 +5,8 @@ -- -- === -- +-- A Finite State Machine (FSM) models a process flow that transitions between various **States** through triggered **Events**. +-- -- A FSM can only be in one of a finite number of states. -- The machine is in only one state at a time; the state it is in at any given time is called the **current state**. -- It can change from one state to another when initiated by an **__internal__ or __external__ triggering event**, which is called a **transition**. @@ -90,8 +92,43 @@ do -- FSM -- @extends Core.Base#BASE - --- # 1) FSM class, extends @{Base#BASE} + --- # FSM class, extends @{Base#BASE} -- + -- A Finite State Machine (FSM) models a process flow that transitions between various **States** through triggered **Events**. + -- + -- A FSM can only be in one of a finite number of states. + -- The machine is in only one state at a time; the state it is in at any given time is called the **current state**. + -- It can change from one state to another when initiated by an **__internal__ or __external__ triggering event**, which is called a **transition**. + -- An **FSM implementation** is defined by **a list of its states**, **its initial state**, and **the triggering events** for **each possible transition**. + -- An FSM implementation is composed out of **two parts**, a set of **state transition rules**, and an implementation set of **state transition handlers**, implementing those transitions. + -- + -- The FSM class supports a **hierarchical implementation of a Finite State Machine**, + -- that is, it allows to **embed existing FSM implementations in a master FSM**. + -- FSM hierarchies allow for efficient FSM re-use, **not having to re-invent the wheel every time again** when designing complex processes. + -- + --  + -- + -- The above diagram shows a graphical representation of a FSM implementation for a **Task**, which guides a Human towards a Zone, + -- orders him to destroy x targets and account the results. + -- Other examples of ready made FSM could be: + -- + -- * route a plane to a zone flown by a human + -- * detect targets by an AI and report to humans + -- * account for destroyed targets by human players + -- * handle AI infantry to deploy from or embark to a helicopter or airplane or vehicle + -- * let an AI patrol a zone + -- + -- The **MOOSE framework** uses extensively the FSM class and derived FSM\_ classes, + -- because **the goal of MOOSE is to simplify mission design complexity for mission building**. + -- By efficiently utilizing the FSM class and derived classes, MOOSE allows mission designers to quickly build processes. + -- **Ready made FSM-based implementations classes** exist within the MOOSE framework that **can easily be re-used, + -- and tailored** by mission designers through **the implementation of Transition Handlers**. + -- Each of these FSM implementation classes start either with: + -- + -- * an acronym **AI\_**, which indicates an FSM implementation directing **AI controlled** @{GROUP} and/or @{UNIT}. These AI\_ classes derive the @{#FSM_CONTROLLABLE} class. + -- * an acronym **TASK\_**, which indicates an FSM implementation executing a @{TASK} executed by Groups of players. These TASK\_ classes derive the @{#FSM_TASK} class. + -- * an acronym **ACT\_**, which indicates an Sub-FSM implementation, directing **Humans actions** that need to be done in a @{TASK}, seated in a @{CLIENT} (slot) or a @{UNIT} (CA join). These ACT\_ classes derive the @{#FSM_PROCESS} class. + -- --  -- -- The FSM class is the base class of all FSM\_ derived classes. It implements the main functionality to define and execute Finite State Machines. @@ -114,13 +151,13 @@ do -- FSM -- As explained above, a FSM supports **Linear State Transitions** and **Hierarchical State Transitions**, and both can be mixed to make a comprehensive FSM implementation. -- The below documentation has a seperate chapter explaining both transition modes, taking into account the **Transition Rules**, **Transition Handlers** and **Event Triggers**. -- - -- ## 1.1) FSM Linear Transitions + -- ## FSM Linear Transitions -- -- Linear Transitions are Transition Rules allowing an FSM to transition from one or multiple possible **From** state(s) towards a **To** state upon a Triggered **Event**. -- The Lineair transition rule evaluation will always be done from the **current state** of the FSM. -- If no valid Transition Rule can be found in the FSM, the FSM will log an error and stop. -- - -- ### 1.1.1) FSM Transition Rules + -- ### FSM Transition Rules -- -- The FSM has transition rules that it follows and validates, as it walks the process. -- These rules define when an FSM can transition from a specific state towards an other specific state upon a triggered event. @@ -145,7 +182,7 @@ do -- FSM -- * It can be switched **Off** by triggering event **SwitchOff**. -- * Note that once the Switch is **On** or **Middle**, it can only be switched **Off**. -- - -- ### Some additional comments: + -- #### Some additional comments: -- -- Note that Linear Transition Rules **can be declared in a few variations**: -- @@ -156,7 +193,7 @@ do -- FSM -- -- FsmSwitch:AddTransition( { "On", "Middle" }, "SwitchOff", "Off" ) -- - -- ### 1.1.2) Transition Handling + -- ### Transition Handling -- --  -- @@ -178,7 +215,7 @@ do -- FSM -- -- On top, each of these methods can have a variable amount of parameters passed. See the example in section [1.1.3](#1.1.3\)-event-triggers). -- - -- ### 1.1.3) Event Triggers + -- ### Event Triggers -- --  -- @@ -216,7 +253,7 @@ do -- FSM -- -- Because ... When Event was asynchronously processed after 5 seconds, Amount was set to 2. So be careful when processing and passing values and objects in asynchronous processing! -- - -- ### 1.1.4) Linear Transition Example + -- ### Linear Transition Example -- -- This example is fully implemented in the MOOSE test mission on GITHUB: [FSM-100 - Transition Explanation](https://github.com/FlightControl-Master/MOOSE/blob/master/Moose%20Test%20Missions/FSM%20-%20Finite%20State%20Machine/FSM-100%20-%20Transition%20Explanation/FSM-100%20-%20Transition%20Explanation.lua) -- @@ -298,7 +335,7 @@ do -- FSM -- So... When FsmDemo:Stop() is being triggered, the state of FsmDemo will transition from Red or Green to Stopped. -- And there is no transition handling method defined for that transition, thus, no new event is being triggered causing the FsmDemo process flow to halt. -- - -- ## 1.5) FSM Hierarchical Transitions + -- ## FSM Hierarchical Transitions -- -- Hierarchical Transitions allow to re-use readily available and implemented FSMs. -- This becomes in very useful for mission building, where mission designers build complex processes and workflows, diff --git a/Moose Development/Moose/Core/Scheduler.lua b/Moose Development/Moose/Core/Scheduler.lua index 2244d9b1b..cf31ecf8e 100644 --- a/Moose Development/Moose/Core/Scheduler.lua +++ b/Moose Development/Moose/Core/Scheduler.lua @@ -4,31 +4,30 @@ -- -- === -- --- # 1) @{Scheduler#SCHEDULER} class, extends @{Base#BASE} +-- SCHEDULER manages the **scheduling of functions**: -- --- The @{Scheduler#SCHEDULER} class creates schedule. --- --- ## 1.1) SCHEDULER constructor --- --- The SCHEDULER class is quite easy to use, but note that the New constructor has variable parameters: --- --- * @{Scheduler#SCHEDULER.New}( nil ): Setup a new SCHEDULER object, which is persistently executed after garbage collection. --- * @{Scheduler#SCHEDULER.New}( Object ): Setup a new SCHEDULER object, which is linked to the Object. When the Object is nillified or destroyed, the SCHEDULER object will also be destroyed and stopped after garbage collection. --- * @{Scheduler#SCHEDULER.New}( nil, Function, FunctionArguments, Start, ... ): Setup a new persistent SCHEDULER object, and start a new schedule for the Function with the defined FunctionArguments according the Start and sequent parameters. --- * @{Scheduler#SCHEDULER.New}( Object, Function, FunctionArguments, Start, ... ): Setup a new SCHEDULER object, linked to Object, and start a new schedule for the Function with the defined FunctionArguments according the Start and sequent parameters. --- --- ## 1.2) SCHEDULER timer stopping and (re-)starting. --- --- The SCHEDULER can be stopped and restarted with the following methods: --- --- * @{Scheduler#SCHEDULER.Start}(): (Re-)Start the schedules within the SCHEDULER object. If a CallID is provided to :Start(), only the schedule referenced by CallID will be (re-)started. --- * @{Scheduler#SCHEDULER.Stop}(): Stop the schedules within the SCHEDULER object. If a CallID is provided to :Stop(), then only the schedule referenced by CallID will be stopped. --- --- ## 1.3) Create a new schedule --- --- With @{Scheduler#SCHEDULER.Schedule}() a new time event can be scheduled. This function is used by the :New() constructor when a new schedule is planned. +-- * optionally in an optional specified time interval, +-- * optionally **repeating** with a specified time repeat interval, +-- * optionally **randomizing** with a specified time interval randomization factor, +-- * optionally **stop** the repeating after a specified time interval. -- -- === +-- +-- # Demo Missions +-- +-- ### [SCHEDULER Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/SCH%20-%20Scheduler) +-- +-- ### [SCHEDULER Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SCH%20-%20Scheduler) +-- +-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases) +-- +-- ==== +-- +-- # YouTube Channel +-- +-- ### [SCHEDULER YouTube Channel (none)]() +-- +-- ==== -- -- ### Contributions: -- @@ -38,10 +37,6 @@ -- -- * FlightControl : Design & Programming -- --- ### Test Missions: --- --- * SCH - Scheduler --- -- === -- -- @module Scheduler @@ -51,6 +46,153 @@ -- @type SCHEDULER -- @field #number ScheduleID the ID of the scheduler. -- @extends Core.Base#BASE + + +--- # SCHEDULER class, extends @{Base#BASE} +-- +-- The SCHEDULER class creates schedule. +-- +-- A SCHEDULER can manage **multiple** (repeating) schedules. Each planned or executing schedule has a unique **ScheduleID**. +-- The ScheduleID is returned when the method @{#SCHEDULER.Schedule}() is called. +-- It is recommended to store the ScheduleID in a variable, as it is used in the methods @{SCHEDULER.Start}() and @{SCHEDULER.Stop}(), +-- which can start and stop specific repeating schedules respectively within a SCHEDULER object. +-- +-- ## SCHEDULER constructor +-- +-- The SCHEDULER class is quite easy to use, but note that the New constructor has variable parameters: +-- +-- The @{#SCHEDULER.New}() method returns 2 variables: +-- +-- 1. The SCHEDULER object reference. +-- 2. The first schedule planned in the SCHEDULER object. +-- +-- To clarify the different appliances, lets have a look at the following examples: +-- +-- ### Construct a SCHEDULER object without a persistent schedule. +-- +-- * @{#SCHEDULER.New}( nil ): Setup a new SCHEDULER object, which is persistently executed after garbage collection. +-- +-- SchedulerObject = SCHEDULER:New() +-- SchedulerID = SchedulerObject:Schedule( nil, ScheduleFunction, {} ) +-- +-- The above example creates a new SchedulerObject, but does not schedule anything. +-- A separate schedule is created by using the SchedulerObject using the method :Schedule..., which returns a ScheduleID +-- +-- ### Construct a SCHEDULER object without a volatile schedule, but volatile to the Object existence... +-- +-- * @{#SCHEDULER.New}( Object ): Setup a new SCHEDULER object, which is linked to the Object. When the Object is nillified or destroyed, the SCHEDULER object will also be destroyed and stopped after garbage collection. +-- +-- ZoneObject = ZONE:New( "ZoneName" ) +-- SchedulerObject = SCHEDULER:New( ZoneObject ) +-- SchedulerID = SchedulerObject:Schedule( ZoneObject, ScheduleFunction, {} ) +-- ... +-- ZoneObject = nil +-- garbagecollect() +-- +-- The above example creates a new SchedulerObject, but does not schedule anything, and is bound to the existence of ZoneObject, which is a ZONE. +-- A separate schedule is created by using the SchedulerObject using the method :Schedule()..., which returns a ScheduleID +-- Later in the logic, the ZoneObject is put to nil, and garbage is collected. +-- As a result, the ScheduleObject will cancel any planned schedule. +-- +-- ### Construct a SCHEDULER object with a persistent schedule. +-- +-- * @{#SCHEDULER.New}( nil, Function, FunctionArguments, Start, ... ): Setup a new persistent SCHEDULER object, and start a new schedule for the Function with the defined FunctionArguments according the Start and sequent parameters. +-- +-- SchedulerObject, SchedulerID = SCHEDULER:New( nil, ScheduleFunction, {} ) +-- +-- The above example creates a new SchedulerObject, and does schedule the first schedule as part of the call. +-- Note that 2 variables are returned here: SchedulerObject, ScheduleID... +-- +-- ### Construct a SCHEDULER object without a schedule, but volatile to the Object existence... +-- +-- * @{#SCHEDULER.New}( Object, Function, FunctionArguments, Start, ... ): Setup a new SCHEDULER object, linked to Object, and start a new schedule for the Function with the defined FunctionArguments according the Start and sequent parameters. +-- +-- ZoneObject = ZONE:New( "ZoneName" ) +-- SchedulerObject, SchedulerID = SCHEDULER:New( ZoneObject, ScheduleFunction, {} ) +-- SchedulerID = SchedulerObject:Schedule( ZoneObject, ScheduleFunction, {} ) +-- ... +-- ZoneObject = nil +-- garbagecollect() +-- +-- The above example creates a new SchedulerObject, and schedules a method call (ScheduleFunction), +-- and is bound to the existence of ZoneObject, which is a ZONE object (ZoneObject). +-- Both a ScheduleObject and a SchedulerID variable are returned. +-- Later in the logic, the ZoneObject is put to nil, and garbage is collected. +-- As a result, the ScheduleObject will cancel the planned schedule. +-- +-- ## SCHEDULER timer stopping and (re-)starting. +-- +-- The SCHEDULER can be stopped and restarted with the following methods: +-- +-- * @{#SCHEDULER.Start}(): (Re-)Start the schedules within the SCHEDULER object. If a CallID is provided to :Start(), only the schedule referenced by CallID will be (re-)started. +-- * @{#SCHEDULER.Stop}(): Stop the schedules within the SCHEDULER object. If a CallID is provided to :Stop(), then only the schedule referenced by CallID will be stopped. +-- +-- ZoneObject = ZONE:New( "ZoneName" ) +-- SchedulerObject, SchedulerID = SCHEDULER:New( ZoneObject, ScheduleFunction, {} ) +-- SchedulerID = SchedulerObject:Schedule( ZoneObject, ScheduleFunction, {}, 10, 10 ) +-- ... +-- SchedulerObject:Stop( SchedulerID ) +-- ... +-- SchedulerObject:Start( SchedulerID ) +-- +-- The above example creates a new SchedulerObject, and does schedule the first schedule as part of the call. +-- Note that 2 variables are returned here: SchedulerObject, ScheduleID... +-- Later in the logic, the repeating schedule with SchedulerID is stopped. +-- A bit later, the repeating schedule with SchedulerId is (re)-started. +-- +-- ## Create a new schedule +-- +-- With the method @{#SCHEDULER.Schedule}() a new time event can be scheduled. +-- This method is used by the :New() constructor when a new schedule is planned. +-- +-- Consider the following code fragment of the SCHEDULER object creation. +-- +-- ZoneObject = ZONE:New( "ZoneName" ) +-- SchedulerObject = SCHEDULER:New( ZoneObject ) +-- +-- Several parameters can be specified that influence the behaviour of a Schedule. +-- +-- ### A single schedule, immediately executed +-- +-- SchedulerID = SchedulerObject:Schedule( ZoneObject, ScheduleFunction, {} ) +-- +-- The above example schedules a new ScheduleFunction call to be executed asynchronously, within milleseconds ... +-- +-- ### A single schedule, planned over time +-- +-- SchedulerID = SchedulerObject:Schedule( ZoneObject, ScheduleFunction, {}, 10 ) +-- +-- The above example schedules a new ScheduleFunction call to be executed asynchronously, within 10 seconds ... +-- +-- ### A schedule with a repeating time interval, planned over time +-- +-- SchedulerID = SchedulerObject:Schedule( ZoneObject, ScheduleFunction, {}, 10, 60 ) +-- +-- The above example schedules a new ScheduleFunction call to be executed asynchronously, within 10 seconds, +-- and repeating 60 every seconds ... +-- +-- ### A schedule with a repeating time interval, planned over time, with time interval randomization +-- +-- SchedulerID = SchedulerObject:Schedule( ZoneObject, ScheduleFunction, {}, 10, 60, 0.5 ) +-- +-- The above example schedules a new ScheduleFunction call to be executed asynchronously, within 10 seconds, +-- and repeating 60 seconds, with a 50% time interval randomization ... +-- So the repeating time interval will be randomized using the **0.5**, +-- and will calculate between **60 - ( 60 * 0.5 )** and **60 + ( 60 * 0.5 )** for each repeat, +-- which is in this example between **30** and **90** seconds. +-- +-- ### A schedule with a repeating time interval, planned over time, with time interval randomization, and stop after a time interval +-- +-- SchedulerID = SchedulerObject:Schedule( ZoneObject, ScheduleFunction, {}, 10, 60, 0.5, 300 ) +-- +-- The above example schedules a new ScheduleFunction call to be executed asynchronously, within 10 seconds, +-- The schedule will repeat every 60 seconds. +-- So the repeating time interval will be randomized using the **0.5**, +-- and will calculate between **60 - ( 60 * 0.5 )** and **60 + ( 60 * 0.5 )** for each repeat, +-- which is in this example between **30** and **90** seconds. +-- The schedule will stop after **300** seconds. +-- +-- @field #SCHEDULER SCHEDULER = { ClassName = "SCHEDULER", Schedules = {}, diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index d7c00ae39..713ca5eb2 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -66,8 +66,7 @@ -- @module Zone ---- The ZONE_BASE class --- @type ZONE_BASE +--- @type ZONE_BASE -- @field #string ZoneName Name of the zone. -- @field #number ZoneProbability A value between 0 and 1. 0 = 0% and 1 = 100% probability. -- @extends Core.Base#BASE @@ -83,19 +82,26 @@ -- -- ## Each zone implements two polymorphic functions defined in @{Zone#ZONE_BASE}: -- --- * @{#ZONE_BASE.IsVec2InZone}(): Returns if a Vec2 is within the zone. --- * @{#ZONE_BASE.IsVec3InZone}(): Returns if a Vec3 is within the zone. +-- * @{#ZONE_BASE.IsVec2InZone}(): Returns if a 2D vector is within the zone. +-- * @{#ZONE_BASE.IsVec3InZone}(): Returns if a 3D vector is within the zone. +-- * @{#ZONE_BASE.IsPointVec2InZone}(): Returns if a 2D point vector is within the zone. +-- * @{#ZONE_BASE.IsPointVec3InZone}(): Returns if a 3D point vector is within the zone. -- -- ## A zone has a probability factor that can be set to randomize a selection between zones: -- --- * @{#ZONE_BASE.SetRandomizeProbability}(): Set the randomization probability of a zone to be selected, taking a value between 0 and 1 ( 0 = 0%, 1 = 100% ) --- * @{#ZONE_BASE.GetRandomizeProbability}(): Get the randomization probability of a zone to be selected, passing a value between 0 and 1 ( 0 = 0%, 1 = 100% ) +-- * @{#ZONE_BASE.SetZoneProbability}(): Set the randomization probability of a zone to be selected, taking a value between 0 and 1 ( 0 = 0%, 1 = 100% ) +-- * @{#ZONE_BASE.GetZoneProbability}(): Get the randomization probability of a zone to be selected, passing a value between 0 and 1 ( 0 = 0%, 1 = 100% ) -- * @{#ZONE_BASE.GetZoneMaybe}(): Get the zone taking into account the randomization probability. nil is returned if this zone is not a candidate. -- --- ## A zone manages Vectors: +-- ## A zone manages vectors: -- --- * @{#ZONE_BASE.GetVec2}(): Returns the @{DCSTypes#Vec2} coordinate of the zone. --- * @{#ZONE_BASE.GetRandomVec2}(): Define a random @{DCSTypes#Vec2} within the zone. +-- * @{#ZONE_BASE.GetVec2}(): Returns the 2D vector coordinate of the zone. +-- * @{#ZONE_BASE.GetVec3}(): Returns the 3D vector coordinate of the zone. +-- * @{#ZONE_BASE.GetPointVec2}(): Returns the 2D point vector coordinate of the zone. +-- * @{#ZONE_BASE.GetPointVec3}(): Returns the 3D point vector coordinate of the zone. +-- * @{#ZONE_BASE.GetRandomVec2}(): Define a random 2D vector within the zone. +-- * @{#ZONE_BASE.GetRandomPointVec2}(): Define a random 2D point vector within the zone. +-- * @{#ZONE_BASE.GetRandomPointVec3}(): Define a random 3D point vector within the zone. -- -- ## A zone has a bounding square: -- @@ -106,8 +112,7 @@ -- * @{#ZONE_BASE.SmokeZone}(): Smokes the zone boundaries in a color. -- * @{#ZONE_BASE.FlareZone}(): Flares the zone boundaries in a color. -- --- @field #ZONE_BASE ZONE_BASE --- +-- @field #ZONE_BASE ZONE_BASE = { ClassName = "ZONE_BASE", ZoneName = "", @@ -366,8 +371,7 @@ end -- * @{#ZONE_RADIUS.GetRandomPointVec2}(): Gets a @{Point#POINT_VEC2} object representing a random 2D point in the zone. -- * @{#ZONE_RADIUS.GetRandomPointVec3}(): Gets a @{Point#POINT_VEC3} object representing a random 3D point in the zone. Note that the height of the point is at landheight. -- --- @field #ZONE_RADIUS ZONE_RADIUS --- +-- @field #ZONE_RADIUS ZONE_RADIUS = { ClassName="ZONE_RADIUS", } @@ -648,8 +652,7 @@ end -- The ZONE class, defined by the zone name as defined within the Mission Editor. -- This class implements the inherited functions from @{#ZONE_RADIUS} taking into account the own zone format and properties. -- --- @field #ZONE ZONE --- +-- @field #ZONE ZONE = { ClassName="ZONE", } @@ -686,8 +689,7 @@ end -- The ZONE_UNIT class defined by a zone around a @{Unit#UNIT} with a radius. -- This class implements the inherited functions from @{#ZONE_RADIUS} taking into account the own zone format and properties. -- --- @field #ZONE_UNIT ZONE_UNIT --- +-- @field #ZONE_UNIT ZONE_UNIT = { ClassName="ZONE_UNIT", } @@ -769,7 +771,6 @@ function ZONE_UNIT:GetVec3( Height ) end --- @type ZONE_GROUP --- @field Wrapper.Group#GROUP ZoneGROUP -- @extends #ZONE_RADIUS @@ -778,8 +779,7 @@ end -- The ZONE_GROUP class defines by a zone around a @{Group#GROUP} with a radius. The current leader of the group defines the center of the zone. -- This class implements the inherited functions from @{Zone#ZONE_RADIUS} taking into account the own zone format and properties. -- --- @field #ZONE_GROUP ZONE_GROUP --- +-- @field #ZONE_GROUP ZONE_GROUP = { ClassName="ZONE_GROUP", } @@ -794,7 +794,7 @@ function ZONE_GROUP:New( ZoneName, ZoneGROUP, Radius ) local self = BASE:Inherit( self, ZONE_RADIUS:New( ZoneName, ZoneGROUP:GetVec2(), Radius ) ) self:F( { ZoneName, ZoneGROUP:GetVec2(), Radius } ) - self.ZoneGROUP = ZoneGROUP + self._.ZoneGROUP = ZoneGROUP return self end @@ -806,7 +806,7 @@ end function ZONE_GROUP:GetVec2() self:F( self.ZoneName ) - local ZoneVec2 = self.ZoneGROUP:GetVec2() + local ZoneVec2 = self._.ZoneGROUP:GetVec2() self:T( { ZoneVec2 } ) @@ -820,7 +820,7 @@ function ZONE_GROUP:GetRandomVec2() self:F( self.ZoneName ) local Point = {} - local Vec2 = self.ZoneGROUP:GetVec2() + local Vec2 = self._.ZoneGROUP:GetVec2() local angle = math.random() * math.pi*2; Point.x = Vec2.x + math.cos( angle ) * math.random() * self:GetRadius(); @@ -834,7 +834,7 @@ end --- @type ZONE_POLYGON_BASE --- @field #ZONE_POLYGON_BASE.ListVec2 Polygon The polygon defined by an array of @{DCSTypes#Vec2}. +-- --@field #ZONE_POLYGON_BASE.ListVec2 Polygon The polygon defined by an array of @{DCSTypes#Vec2}. -- @extends #ZONE_BASE @@ -852,8 +852,7 @@ end -- * @{#ZONE_POLYGON_BASE.GetRandomPointVec2}(): Return a @{Point#POINT_VEC2} object representing a random 2D point within the zone. -- * @{#ZONE_POLYGON_BASE.GetRandomPointVec3}(): Return a @{Point#POINT_VEC3} object representing a random 3D point at landheight within the zone. -- --- @field #ZONE_POLYGON_BASE ZONE_POLYGON_BASE --- +-- @field #ZONE_POLYGON_BASE ZONE_POLYGON_BASE = { ClassName="ZONE_POLYGON_BASE", } @@ -874,12 +873,12 @@ function ZONE_POLYGON_BASE:New( ZoneName, PointsArray ) local i = 0 - self.Polygon = {} + self._.Polygon = {} for i = 1, #PointsArray do - self.Polygon[i] = {} - self.Polygon[i].x = PointsArray[i].x - self.Polygon[i].y = PointsArray[i].y + self._.Polygon[i] = {} + self._.Polygon[i].x = PointsArray[i].x + self._.Polygon[i].y = PointsArray[i].y end return self @@ -902,7 +901,7 @@ end function ZONE_POLYGON_BASE:Flush() self:F2() - self:E( { Polygon = self.ZoneName, Coordinates = self.Polygon } ) + self:E( { Polygon = self.ZoneName, Coordinates = self._.Polygon } ) return self end @@ -918,17 +917,17 @@ function ZONE_POLYGON_BASE:BoundZone( UnBound ) local Segments = 10 i = 1 - j = #self.Polygon + j = #self._.Polygon - while i <= #self.Polygon do - self:T( { i, j, self.Polygon[i], self.Polygon[j] } ) + while i <= #self._.Polygon do + self:T( { i, j, self._.Polygon[i], self._.Polygon[j] } ) - local DeltaX = self.Polygon[j].x - self.Polygon[i].x - local DeltaY = self.Polygon[j].y - self.Polygon[i].y + local DeltaX = self._.Polygon[j].x - self._.Polygon[i].x + local DeltaY = self._.Polygon[j].y - self._.Polygon[i].y for Segment = 0, Segments do -- We divide each line in 5 segments and smoke a point on the line. - local PointX = self.Polygon[i].x + ( Segment * DeltaX / Segments ) - local PointY = self.Polygon[i].y + ( Segment * DeltaY / Segments ) + local PointX = self._.Polygon[i].x + ( Segment * DeltaX / Segments ) + local PointY = self._.Polygon[i].y + ( Segment * DeltaY / Segments ) local Tire = { ["country"] = "USA", ["category"] = "Fortifications", @@ -968,17 +967,17 @@ function ZONE_POLYGON_BASE:SmokeZone( SmokeColor ) local Segments = 10 i = 1 - j = #self.Polygon + j = #self._.Polygon - while i <= #self.Polygon do - self:T( { i, j, self.Polygon[i], self.Polygon[j] } ) + while i <= #self._.Polygon do + self:T( { i, j, self._.Polygon[i], self._.Polygon[j] } ) - local DeltaX = self.Polygon[j].x - self.Polygon[i].x - local DeltaY = self.Polygon[j].y - self.Polygon[i].y + local DeltaX = self._.Polygon[j].x - self._.Polygon[i].x + local DeltaY = self._.Polygon[j].y - self._.Polygon[i].y for Segment = 0, Segments do -- We divide each line in 5 segments and smoke a point on the line. - local PointX = self.Polygon[i].x + ( Segment * DeltaX / Segments ) - local PointY = self.Polygon[i].y + ( Segment * DeltaY / Segments ) + local PointX = self._.Polygon[i].x + ( Segment * DeltaX / Segments ) + local PointY = self._.Polygon[i].y + ( Segment * DeltaY / Segments ) POINT_VEC2:New( PointX, PointY ):Smoke( SmokeColor ) end j = i @@ -1004,12 +1003,12 @@ function ZONE_POLYGON_BASE:IsVec2InZone( Vec2 ) local InPolygon = false Next = 1 - Prev = #self.Polygon + Prev = #self._.Polygon - while Next <= #self.Polygon do - self:T( { Next, Prev, self.Polygon[Next], self.Polygon[Prev] } ) - if ( ( ( self.Polygon[Next].y > Vec2.y ) ~= ( self.Polygon[Prev].y > Vec2.y ) ) and - ( Vec2.x < ( self.Polygon[Prev].x - self.Polygon[Next].x ) * ( Vec2.y - self.Polygon[Next].y ) / ( self.Polygon[Prev].y - self.Polygon[Next].y ) + self.Polygon[Next].x ) + while Next <= #self._.Polygon do + self:T( { Next, Prev, self._.Polygon[Next], self._.Polygon[Prev] } ) + if ( ( ( self._.Polygon[Next].y > Vec2.y ) ~= ( self._.Polygon[Prev].y > Vec2.y ) ) and + ( Vec2.x < ( self._.Polygon[Prev].x - self._.Polygon[Next].x ) * ( Vec2.y - self._.Polygon[Next].y ) / ( self._.Polygon[Prev].y - self._.Polygon[Next].y ) + self._.Polygon[Next].x ) ) then InPolygon = not InPolygon end @@ -1080,17 +1079,17 @@ end -- @return #ZONE_POLYGON_BASE.BoundingSquare The bounding square. function ZONE_POLYGON_BASE:GetBoundingSquare() - local x1 = self.Polygon[1].x - local y1 = self.Polygon[1].y - local x2 = self.Polygon[1].x - local y2 = self.Polygon[1].y + local x1 = self._.Polygon[1].x + local y1 = self._.Polygon[1].y + local x2 = self._.Polygon[1].x + local y2 = self._.Polygon[1].y - for i = 2, #self.Polygon do - self:T2( { self.Polygon[i], x1, y1, x2, y2 } ) - x1 = ( x1 > self.Polygon[i].x ) and self.Polygon[i].x or x1 - x2 = ( x2 < self.Polygon[i].x ) and self.Polygon[i].x or x2 - y1 = ( y1 > self.Polygon[i].y ) and self.Polygon[i].y or y1 - y2 = ( y2 < self.Polygon[i].y ) and self.Polygon[i].y or y2 + for i = 2, #self._.Polygon do + self:T2( { self._.Polygon[i], x1, y1, x2, y2 } ) + x1 = ( x1 > self._.Polygon[i].x ) and self._.Polygon[i].x or x1 + x2 = ( x2 < self._.Polygon[i].x ) and self._.Polygon[i].x or x2 + y1 = ( y1 > self._.Polygon[i].y ) and self._.Polygon[i].y or y1 + y2 = ( y2 < self._.Polygon[i].y ) and self._.Polygon[i].y or y2 end @@ -1107,8 +1106,7 @@ end -- The ZONE_POLYGON class defined by a sequence of @{Group#GROUP} waypoints within the Mission Editor, forming a polygon. -- This class implements the inherited functions from @{Zone#ZONE_RADIUS} taking into account the own zone format and properties. -- --- @field #ZONE_POLYGON ZONE_POLYGON --- +-- @field #ZONE_POLYGON ZONE_POLYGON = { ClassName="ZONE_POLYGON", } @@ -1124,7 +1122,7 @@ function ZONE_POLYGON:New( ZoneName, ZoneGroup ) local GroupPoints = ZoneGroup:GetTaskRoute() local self = BASE:Inherit( self, ZONE_POLYGON_BASE:New( ZoneName, GroupPoints ) ) - self:F( { ZoneName, ZoneGroup, self.Polygon } ) + self:F( { ZoneName, ZoneGroup, self._.Polygon } ) return self end diff --git a/docs/Documentation/Detection.html b/docs/Documentation/Detection.html index dc52c4036..75eb0145f 100644 --- a/docs/Documentation/Detection.html +++ b/docs/Documentation/Detection.html @@ -2172,6 +2172,7 @@ self
A Finite State Machine (FSM) models a process flow that transitions between various States through triggered Events.
+A FSM can only be in one of a finite number of states. The machine is in only one state at a time; the state it is in at any given time is called the current state. It can change from one state to another when initiated by an internal or external triggering event, which is called a transition. @@ -199,11 +201,9 @@ YYYY-MM-DD: CLASS:NewFunction( Params ) added
The FSM class is the base class of all FSM_ derived classes.
+A Finite State Machine (FSM) models a process flow that transitions between various States through triggered Events.
A Finite State Machine (FSM) models a process flow that transitions between various States through triggered Events.
+ + + +A FSM can only be in one of a finite number of states. +The machine is in only one state at a time; the state it is in at any given time is called the current state. +It can change from one state to another when initiated by an internal or external triggering event, which is called a transition. +An FSM implementation is defined by a list of its states, its initial state, and the triggering events for each possible transition. +An FSM implementation is composed out of two parts, a set of state transition rules, and an implementation set of state transition handlers, implementing those transitions.
+ +The FSM class supports a hierarchical implementation of a Finite State Machine, +that is, it allows to embed existing FSM implementations in a master FSM. +FSM hierarchies allow for efficient FSM re-use, not having to re-invent the wheel every time again when designing complex processes.
+ +The above diagram shows a graphical representation of a FSM implementation for a Task, which guides a Human towards a Zone, +orders him to destroy x targets and account the results. +Other examples of ready made FSM could be:
+ +The MOOSE framework uses extensively the FSM class and derived FSM_ classes, +because the goal of MOOSE is to simplify mission design complexity for mission building. +By efficiently utilizing the FSM class and derived classes, MOOSE allows mission designers to quickly build processes. +Ready made FSM-based implementations classes exist within the MOOSE framework that can easily be re-used, +and tailored by mission designers through the implementation of Transition Handlers. +Each of these FSM implementation classes start either with:
+ +The FSM class is the base class of all FSM_ derived classes.
- - -It implements the main functionality to define and execute Finite State Machines. +
The FSM class is the base class of all FSM_ derived classes. It implements the main functionality to define and execute Finite State Machines. The derived FSM_ classes extend the Finite State Machine functionality to run a workflow process for a specific purpose or component.
Finite State Machines have Transition Rules, Transition Handlers and Event Triggers.
@@ -753,13 +791,13 @@ Most of the time, these Event Triggers are used within the Transition Handler meAs explained above, a FSM supports Linear State Transitions and Hierarchical State Transitions, and both can be mixed to make a comprehensive FSM implementation. The below documentation has a seperate chapter explaining both transition modes, taking into account the Transition Rules, Transition Handlers and Event Triggers.
-Linear Transitions are Transition Rules allowing an FSM to transition from one or multiple possible From state(s) towards a To state upon a Triggered Event. The Lineair transition rule evaluation will always be done from the current state of the FSM. If no valid Transition Rule can be found in the FSM, the FSM will log an error and stop.
-The FSM has transition rules that it follows and validates, as it walks the process. These rules define when an FSM can transition from a specific state towards an other specific state upon a triggered event.
@@ -787,7 +825,7 @@ These rules define when an FSM can transition from a specific state towards an oNote that Linear Transition Rules can be declared in a few variations:
@@ -801,7 +839,7 @@ These rules define when an FSM can transition from a specific state towards an o FsmSwitch:AddTransition( { "On", "Middle" }, "SwitchOff", "Off" )
-On top, each of these methods can have a variable amount of parameters passed. See the example in section 1.1.3.
-Because ... When Event was asynchronously processed after 5 seconds, Amount was set to 2. So be careful when processing and passing values and objects in asynchronous processing!
-This example is fully implemented in the MOOSE test mission on GITHUB: FSM-100 - Transition Explanation
@@ -960,7 +998,7 @@ The transition for event Stop can be executed if the current state of the FSM isSo... When FsmDemo:Stop() is being triggered, the state of FsmDemo will transition from Red or Green to Stopped. And there is no transition handling method defined for that transition, thus, no new event is being triggered causing the FsmDemo process flow to halt.
-Hierarchical Transitions allow to re-use readily available and implemented FSMs. This becomes in very useful for mission building, where mission designers build complex processes and workflows, @@ -1582,7 +1620,7 @@ A string defining the start state.
Contains the counter how many units are currently alive
+The Scheduler#SCHEDULER class creates schedule.
- -The SCHEDULER class is quite easy to use, but note that the New constructor has variable parameters:
+SCHEDULER manages the scheduling of functions:
The SCHEDULER can be stopped and restarted with the following methods:
+With Scheduler#SCHEDULER.Schedule() a new time event can be scheduled. This function is used by the :New() constructor when a new schedule is planned.
+The SCHEDULER class creates schedule.
SCHEDULER| SCHEDULER.ClassName | -- - | -||
| SCHEDULER:Clear() |
Clears all pending schedules. @@ -203,12 +190,6 @@ | SCHEDULER.SchedulerObject | - | -
| SCHEDULER.Schedules | -- | ||
| ZONE_GROUP:New(ZoneName, ZoneGROUP, Radius) |
Constructor to create a ZONE_GROUP instance, taking the zone name, a zone Group#GROUP and a radius. - |
- ||
| ZONE_GROUP.ZoneGROUP | -- |
Constructor to create a ZONEPOLYGONBASE instance, taking the zone name and an array of DCSTypes#Vec2, forming a polygon.
-The polygon defined by an array of DCSTypes#Vec2.
ZONE_BASEThe ZONE_BASE class
- -#ZONE_GROUP: self
- -#ZONEPOLYGONBASE: self
- - -The polygon defined by an array of DCSTypes#Vec2.
-