From f54a396e0f6b4b49458eb87eb03cd346454fb33f Mon Sep 17 00:00:00 2001 From: PiZZAD0X Date: Fri, 10 Jan 2020 21:54:03 -0800 Subject: [PATCH 1/6] StateMachine condition frequency check from optional config entry --- addons/statemachine/CBA_FSMEditor.cfg | 2 ++ addons/statemachine/fnc_addTransition.sqf | 6 ++++-- addons/statemachine/fnc_clockwork.sqf | 8 ++++++-- addons/statemachine/fnc_createFromConfig.sqf | 3 ++- addons/statemachine/fnc_manualTransition.sqf | 1 + 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/addons/statemachine/CBA_FSMEditor.cfg b/addons/statemachine/CBA_FSMEditor.cfg index bbcd4469be..585d689f7d 100644 --- a/addons/statemachine/CBA_FSMEditor.cfg +++ b/addons/statemachine/CBA_FSMEditor.cfg @@ -19,6 +19,7 @@ Usage: 4.2 'condition' is parsed as condition = QUOTE(x) 4.3 'action' is parsed as is, and may contain onTransition = "" and/or events[] = {} + 4.4 'preCondition' is parsed as is, and may contain condFrequency = Dependencies: In order to properly function, script_macros_common.hpp must be included. @@ -52,6 +53,7 @@ class Compile { print_transition = "class %(linkname) {\n"; indent_transitionOpen = 12; print_target = "targetState = QUOTE(%(to));\n"; + print_condFrequency = "%(condPrecondition);\n"; print_condition = "condition = QUOTE(%(condition));"; indent_transitionContents = 12; // Neccessary to preserve formatting. print_transitionContents = "%(action)\n"; diff --git a/addons/statemachine/fnc_addTransition.sqf b/addons/statemachine/fnc_addTransition.sqf index d80bbe4d24..306ec8fa45 100644 --- a/addons/statemachine/fnc_addTransition.sqf +++ b/addons/statemachine/fnc_addTransition.sqf @@ -14,6 +14,7 @@ Parameters: (Default: {}) _name - name for this specific transition (Default: "NONAME") + _condFrequency - time needed between transition condition checks Returns: _wasCreated - check if the transition was created @@ -38,7 +39,8 @@ params [ ["_targetState", "", [""]], ["_condition", {}, [{}]], ["_onTransition", {}, [{}]], - ["_name", "NONAME", [""]] + ["_name", "NONAME", [""]], + ["_condFrequency", 0, [0]] ]; private _states = _stateMachine getVariable QGVAR(states); @@ -50,7 +52,7 @@ if (isNull _stateMachine ) exitWith {false}; private _transitions = _stateMachine getVariable TRANSITIONS(_originalState); -_transitions pushBack [_name, _condition, _targetState, _onTransition]; +_transitions pushBack [_name, _condition, _targetState, _onTransition, _condFrequency]; _stateMachine setVariable [TRANSITIONS(_originalState), _transitions]; true diff --git a/addons/statemachine/fnc_clockwork.sqf b/addons/statemachine/fnc_clockwork.sqf index 4aa130f51a..48d5efe9cd 100644 --- a/addons/statemachine/fnc_clockwork.sqf +++ b/addons/statemachine/fnc_clockwork.sqf @@ -57,12 +57,14 @@ SCRIPT(clockwork); private _current = _list select _tick; private _thisState = _current getVariable (QGVAR(state) + str _id); + private _lastCheck = _current getVariable [(QGVAR(lastCheck) + str _id),CBA_missionTime]; if (isNil "_thisState") then { // Item is new and gets set to the intial state, onStateEntered // function of initial state gets executed as well. _thisState = _stateMachine getVariable QGVAR(initialState); _current setVariable [QGVAR(state) + str _id, _thisState]; + _current setVariable [QGVAR(lastCheck) + str _id, CBA_missionTime]; _current call (_stateMachine getVariable ONSTATEENTERED(_thisState)); }; @@ -74,7 +76,8 @@ SCRIPT(clockwork); private _thisOrigin = _thisState; { - _x params ["_thisTransition", "_condition", "_thisTarget", "_onTransition"]; + _x params ["_thisTransition", "_condition", "_thisTarget", "_onTransition", "_condFrequency"]; + private _timeCheck = (CBA_missionTime >= (_lastCheck + _condFrequency)); // Transition conditions, onTransition, onStateLeaving and // onStateEntered functions can use: // _stateMachine - the state machine @@ -88,10 +91,11 @@ SCRIPT(clockwork); // _thisTarget variable. // Note: onStateEntered functions of initial states won't have // some of these variables defined. - if (_current call _condition) exitWith { + if ((CBA_missionTime >= (_lastCheck + _condFrequency)) && {_current call _condition}) exitWith { _current call (_stateMachine getVariable ONSTATELEAVING(_thisOrigin)); _current call _onTransition; _current setVariable [QGVAR(state) + str _id, _thisTarget]; + _current setVariable [QGVAR(lastCheck) + str _id, CBA_missionTime]; _current call (_stateMachine getVariable ONSTATEENTERED(_thisTarget)); }; } forEach (_stateMachine getVariable TRANSITIONS(_thisState)); diff --git a/addons/statemachine/fnc_createFromConfig.sqf b/addons/statemachine/fnc_createFromConfig.sqf index 3607bb0de2..01ea34d25c 100644 --- a/addons/statemachine/fnc_createFromConfig.sqf +++ b/addons/statemachine/fnc_createFromConfig.sqf @@ -48,12 +48,13 @@ private _stateMachine = [_list, _skipNull] call FUNC(create); if (isText (_x >> "targetState")) then { _targetState = getText (_x >> "targetState"); }; + private _condFrequency = getNumber (_x >> "condFrequency"); GET_FUNCTION(_condition,_x >> "condition"); GET_FUNCTION(_onTransition,_x >> "onTransition"); private _events = getArray (_x >> "events"); if (_events isEqualTo []) then { - [_stateMachine, _state, _targetState, _condition, _onTransition, _transition] call FUNC(addTransition); + [_stateMachine, _state, _targetState, _condition, _onTransition, _transition, _condFrequency] call FUNC(addTransition); } else { [_stateMachine, _state, _targetState, _events, _condition, _onTransition, _transition] call FUNC(addEventTransition); }; diff --git a/addons/statemachine/fnc_manualTransition.sqf b/addons/statemachine/fnc_manualTransition.sqf index dde13ae104..c91a22f7f6 100644 --- a/addons/statemachine/fnc_manualTransition.sqf +++ b/addons/statemachine/fnc_manualTransition.sqf @@ -46,4 +46,5 @@ private _id = _stateMachine getVariable QGVAR(ID); _listItem call (_stateMachine getVariable ONSTATELEAVING(_thisOrigin)); _listItem call _onTransition; _listItem setVariable [QGVAR(state) + str _id, _thisTarget]; +_listItem setVariable [QGVAR(lastCheck) + str _id, CBA_missionTime]; _listItem call (_stateMachine getVariable ONSTATEENTERED(_thisTarget)); From f75fb2c1fa2f31e52a2e577a7d1afd9a21250121 Mon Sep 17 00:00:00 2001 From: PiZZAD0X Date: Sun, 12 Jan 2020 03:34:23 -0800 Subject: [PATCH 2/6] remove debug timecheck --- addons/statemachine/fnc_clockwork.sqf | 1 - 1 file changed, 1 deletion(-) diff --git a/addons/statemachine/fnc_clockwork.sqf b/addons/statemachine/fnc_clockwork.sqf index 48d5efe9cd..87333a1c7e 100644 --- a/addons/statemachine/fnc_clockwork.sqf +++ b/addons/statemachine/fnc_clockwork.sqf @@ -77,7 +77,6 @@ SCRIPT(clockwork); private _thisOrigin = _thisState; { _x params ["_thisTransition", "_condition", "_thisTarget", "_onTransition", "_condFrequency"]; - private _timeCheck = (CBA_missionTime >= (_lastCheck + _condFrequency)); // Transition conditions, onTransition, onStateLeaving and // onStateEntered functions can use: // _stateMachine - the state machine From ca08831e688333be3a145bed8e1a0b622c6a17d8 Mon Sep 17 00:00:00 2001 From: PiZZAD0X Date: Sun, 12 Jan 2020 03:41:27 -0800 Subject: [PATCH 3/6] default `_condFrequency` in transition params --- addons/statemachine/fnc_clockwork.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/statemachine/fnc_clockwork.sqf b/addons/statemachine/fnc_clockwork.sqf index 87333a1c7e..2d4023ba07 100644 --- a/addons/statemachine/fnc_clockwork.sqf +++ b/addons/statemachine/fnc_clockwork.sqf @@ -76,7 +76,7 @@ SCRIPT(clockwork); private _thisOrigin = _thisState; { - _x params ["_thisTransition", "_condition", "_thisTarget", "_onTransition", "_condFrequency"]; + _x params ["_thisTransition", "_condition", "_thisTarget", "_onTransition", ["_condFrequency",0,[0]]]; // Transition conditions, onTransition, onStateLeaving and // onStateEntered functions can use: // _stateMachine - the state machine From 62ca9fc47ad955e6a9b555d6a27d4db5db5622b3 Mon Sep 17 00:00:00 2001 From: PiZZAD0X Date: Sun, 19 Jan 2020 09:09:48 -0800 Subject: [PATCH 4/6] - Compiled wait/frequency check into condition call - cfgName to `conditionFrequency` --- addons/statemachine/CBA_FSMEditor.cfg | 2 +- addons/statemachine/fnc_addTransition.sqf | 29 ++++++++++++++++++-- addons/statemachine/fnc_clockwork.sqf | 7 ++--- addons/statemachine/fnc_createFromConfig.sqf | 4 +-- addons/statemachine/fnc_manualTransition.sqf | 1 - addons/statemachine/script_component.hpp | 1 + 6 files changed, 32 insertions(+), 12 deletions(-) diff --git a/addons/statemachine/CBA_FSMEditor.cfg b/addons/statemachine/CBA_FSMEditor.cfg index 585d689f7d..8bc79e3c4f 100644 --- a/addons/statemachine/CBA_FSMEditor.cfg +++ b/addons/statemachine/CBA_FSMEditor.cfg @@ -19,7 +19,7 @@ Usage: 4.2 'condition' is parsed as condition = QUOTE(x) 4.3 'action' is parsed as is, and may contain onTransition = "" and/or events[] = {} - 4.4 'preCondition' is parsed as is, and may contain condFrequency = + 4.4 'preCondition' is parsed as is, and may contain conditionFrequency = Dependencies: In order to properly function, script_macros_common.hpp must be included. diff --git a/addons/statemachine/fnc_addTransition.sqf b/addons/statemachine/fnc_addTransition.sqf index 306ec8fa45..ab0b096d8b 100644 --- a/addons/statemachine/fnc_addTransition.sqf +++ b/addons/statemachine/fnc_addTransition.sqf @@ -14,7 +14,6 @@ Parameters: (Default: {}) _name - name for this specific transition (Default: "NONAME") - _condFrequency - time needed between transition condition checks Returns: _wasCreated - check if the transition was created @@ -40,7 +39,7 @@ params [ ["_condition", {}, [{}]], ["_onTransition", {}, [{}]], ["_name", "NONAME", [""]], - ["_condFrequency", 0, [0]] + ["_conditionFrequency", 0, [0]] ]; private _states = _stateMachine getVariable QGVAR(states); @@ -51,8 +50,32 @@ if (isNull _stateMachine || {_condition isEqualTo {}} ) exitWith {false}; +if (_conditionFrequency > 0) then { + _condition = compile format [QUOTE( \ + true && \ + { \ + private _return = false; \ + if ((_current getVariable [ARR_2((QQGVAR(lastCheckedState) + str _id), '')]) isEqualTo _thisState) then { \ + private _lastCheckedTime = _current getVariable [ARR_2((QQGVAR(lastCheckedTime) + str _id), CBA_MissionTime)]; \ + if (CBA_MissionTime >= (_lastCheckedTime + %2)) then { \ + _current setVariable [ARR_2((QQGVAR(lastCheckedTime) + str _id), CBA_MissionTime)]; \ + _return = true; \ + } else { \ + _return = false; \ + }; \ + } else { \ + _current setVariable [ARR_2((QQGVAR(lastCheckedState) + str _id), _thisState)]; \ + _current setVariable [ARR_2((QQGVAR(lastCheckedTime) + str _id), CBA_MissionTime)]; \ + _return = false; \ + }; \ + _return \ + } && \ + %1 \ + ), _condition, _conditionFrequency]; +}; + private _transitions = _stateMachine getVariable TRANSITIONS(_originalState); -_transitions pushBack [_name, _condition, _targetState, _onTransition, _condFrequency]; +_transitions pushBack [_name, _condition, _targetState, _onTransition]; _stateMachine setVariable [TRANSITIONS(_originalState), _transitions]; true diff --git a/addons/statemachine/fnc_clockwork.sqf b/addons/statemachine/fnc_clockwork.sqf index 2d4023ba07..4aa130f51a 100644 --- a/addons/statemachine/fnc_clockwork.sqf +++ b/addons/statemachine/fnc_clockwork.sqf @@ -57,14 +57,12 @@ SCRIPT(clockwork); private _current = _list select _tick; private _thisState = _current getVariable (QGVAR(state) + str _id); - private _lastCheck = _current getVariable [(QGVAR(lastCheck) + str _id),CBA_missionTime]; if (isNil "_thisState") then { // Item is new and gets set to the intial state, onStateEntered // function of initial state gets executed as well. _thisState = _stateMachine getVariable QGVAR(initialState); _current setVariable [QGVAR(state) + str _id, _thisState]; - _current setVariable [QGVAR(lastCheck) + str _id, CBA_missionTime]; _current call (_stateMachine getVariable ONSTATEENTERED(_thisState)); }; @@ -76,7 +74,7 @@ SCRIPT(clockwork); private _thisOrigin = _thisState; { - _x params ["_thisTransition", "_condition", "_thisTarget", "_onTransition", ["_condFrequency",0,[0]]]; + _x params ["_thisTransition", "_condition", "_thisTarget", "_onTransition"]; // Transition conditions, onTransition, onStateLeaving and // onStateEntered functions can use: // _stateMachine - the state machine @@ -90,11 +88,10 @@ SCRIPT(clockwork); // _thisTarget variable. // Note: onStateEntered functions of initial states won't have // some of these variables defined. - if ((CBA_missionTime >= (_lastCheck + _condFrequency)) && {_current call _condition}) exitWith { + if (_current call _condition) exitWith { _current call (_stateMachine getVariable ONSTATELEAVING(_thisOrigin)); _current call _onTransition; _current setVariable [QGVAR(state) + str _id, _thisTarget]; - _current setVariable [QGVAR(lastCheck) + str _id, CBA_missionTime]; _current call (_stateMachine getVariable ONSTATEENTERED(_thisTarget)); }; } forEach (_stateMachine getVariable TRANSITIONS(_thisState)); diff --git a/addons/statemachine/fnc_createFromConfig.sqf b/addons/statemachine/fnc_createFromConfig.sqf index 01ea34d25c..9054c1dec4 100644 --- a/addons/statemachine/fnc_createFromConfig.sqf +++ b/addons/statemachine/fnc_createFromConfig.sqf @@ -48,13 +48,13 @@ private _stateMachine = [_list, _skipNull] call FUNC(create); if (isText (_x >> "targetState")) then { _targetState = getText (_x >> "targetState"); }; - private _condFrequency = getNumber (_x >> "condFrequency"); + private _conditionFrequency = getNumber (_x >> "conditionFrequency"); GET_FUNCTION(_condition,_x >> "condition"); GET_FUNCTION(_onTransition,_x >> "onTransition"); private _events = getArray (_x >> "events"); if (_events isEqualTo []) then { - [_stateMachine, _state, _targetState, _condition, _onTransition, _transition, _condFrequency] call FUNC(addTransition); + [_stateMachine, _state, _targetState, _condition, _onTransition, _transition, _conditionFrequency] call FUNC(addTransition); } else { [_stateMachine, _state, _targetState, _events, _condition, _onTransition, _transition] call FUNC(addEventTransition); }; diff --git a/addons/statemachine/fnc_manualTransition.sqf b/addons/statemachine/fnc_manualTransition.sqf index c91a22f7f6..dde13ae104 100644 --- a/addons/statemachine/fnc_manualTransition.sqf +++ b/addons/statemachine/fnc_manualTransition.sqf @@ -46,5 +46,4 @@ private _id = _stateMachine getVariable QGVAR(ID); _listItem call (_stateMachine getVariable ONSTATELEAVING(_thisOrigin)); _listItem call _onTransition; _listItem setVariable [QGVAR(state) + str _id, _thisTarget]; -_listItem setVariable [QGVAR(lastCheck) + str _id, CBA_missionTime]; _listItem call (_stateMachine getVariable ONSTATEENTERED(_thisTarget)); diff --git a/addons/statemachine/script_component.hpp b/addons/statemachine/script_component.hpp index bb3c66eba1..a82a0ff059 100644 --- a/addons/statemachine/script_component.hpp +++ b/addons/statemachine/script_component.hpp @@ -3,6 +3,7 @@ // #define DISABLE_COMPILE_CACHE // #define STATEMACHINE_PERFORMANCE_COUNTERS +// #define DEBUG_ENABLED_STATEMACHINE #ifdef DEBUG_ENABLED_STATEMACHINE #define DEBUG_MODE_FULL From 8ca57c4184da54f86692310d7a3dae27d47449e2 Mon Sep 17 00:00:00 2001 From: PiZZAD0X Date: Sun, 19 Jan 2020 10:38:15 -0800 Subject: [PATCH 5/6] Removed space before escaped newline --- addons/statemachine/fnc_addTransition.sqf | 40 +++++++++++------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/addons/statemachine/fnc_addTransition.sqf b/addons/statemachine/fnc_addTransition.sqf index ab0b096d8b..47fb301aa7 100644 --- a/addons/statemachine/fnc_addTransition.sqf +++ b/addons/statemachine/fnc_addTransition.sqf @@ -51,26 +51,26 @@ if (isNull _stateMachine ) exitWith {false}; if (_conditionFrequency > 0) then { - _condition = compile format [QUOTE( \ - true && \ - { \ - private _return = false; \ - if ((_current getVariable [ARR_2((QQGVAR(lastCheckedState) + str _id), '')]) isEqualTo _thisState) then { \ - private _lastCheckedTime = _current getVariable [ARR_2((QQGVAR(lastCheckedTime) + str _id), CBA_MissionTime)]; \ - if (CBA_MissionTime >= (_lastCheckedTime + %2)) then { \ - _current setVariable [ARR_2((QQGVAR(lastCheckedTime) + str _id), CBA_MissionTime)]; \ - _return = true; \ - } else { \ - _return = false; \ - }; \ - } else { \ - _current setVariable [ARR_2((QQGVAR(lastCheckedState) + str _id), _thisState)]; \ - _current setVariable [ARR_2((QQGVAR(lastCheckedTime) + str _id), CBA_MissionTime)]; \ - _return = false; \ - }; \ - _return \ - } && \ - %1 \ + _condition = compile format [QUOTE(\ + true &&\ + {\ + private _return = false;\ + if ((_current getVariable [ARR_2((QQGVAR(lastCheckedState) + str _id), '')]) isEqualTo _thisState) then {\ + private _lastCheckedTime = _current getVariable [ARR_2((QQGVAR(lastCheckedTime) + str _id), CBA_MissionTime)];\ + if (CBA_MissionTime >= (_lastCheckedTime + %2)) then {\ + _current setVariable [ARR_2((QQGVAR(lastCheckedTime) + str _id), CBA_MissionTime)];\ + _return = true;\ + } else {\ + _return = false;\ + };\ + } else {\ + _current setVariable [ARR_2((QQGVAR(lastCheckedState) + str _id), _thisState)];\ + _current setVariable [ARR_2((QQGVAR(lastCheckedTime) + str _id), CBA_MissionTime)];\ + _return = false;\ + };\ + _return\ + } &&\ + %1\ ), _condition, _conditionFrequency]; }; From eec68ce602a1941566712d37d073c2a9f9ce5905 Mon Sep 17 00:00:00 2001 From: PiZZAD0X Date: Sun, 19 Jan 2020 11:02:33 -0800 Subject: [PATCH 6/6] removed unnecessary bool & codeblock; return var && original condition --- addons/statemachine/fnc_addTransition.sqf | 28 ++++++++++------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/addons/statemachine/fnc_addTransition.sqf b/addons/statemachine/fnc_addTransition.sqf index 47fb301aa7..5745e53c02 100644 --- a/addons/statemachine/fnc_addTransition.sqf +++ b/addons/statemachine/fnc_addTransition.sqf @@ -52,25 +52,21 @@ if (isNull _stateMachine if (_conditionFrequency > 0) then { _condition = compile format [QUOTE(\ - true &&\ - {\ - private _return = false;\ - if ((_current getVariable [ARR_2((QQGVAR(lastCheckedState) + str _id), '')]) isEqualTo _thisState) then {\ - private _lastCheckedTime = _current getVariable [ARR_2((QQGVAR(lastCheckedTime) + str _id), CBA_MissionTime)];\ - if (CBA_MissionTime >= (_lastCheckedTime + %2)) then {\ - _current setVariable [ARR_2((QQGVAR(lastCheckedTime) + str _id), CBA_MissionTime)];\ - _return = true;\ - } else {\ - _return = false;\ - };\ - } else {\ - _current setVariable [ARR_2((QQGVAR(lastCheckedState) + str _id), _thisState)];\ + private _return = false;\ + if ((_current getVariable [ARR_2((QQGVAR(lastCheckedState) + str _id), '')]) isEqualTo _thisState) then {\ + private _lastCheckedTime = _current getVariable [ARR_2((QQGVAR(lastCheckedTime) + str _id), CBA_MissionTime)];\ + if (CBA_MissionTime >= (_lastCheckedTime + %2)) then {\ _current setVariable [ARR_2((QQGVAR(lastCheckedTime) + str _id), CBA_MissionTime)];\ + _return = true;\ + } else {\ _return = false;\ };\ - _return\ - } &&\ - %1\ + } else {\ + _current setVariable [ARR_2((QQGVAR(lastCheckedState) + str _id), _thisState)];\ + _current setVariable [ARR_2((QQGVAR(lastCheckedTime) + str _id), CBA_MissionTime)];\ + _return = false;\ + };\ + _return && %1\ ), _condition, _conditionFrequency]; };