From 0394bcf1c12865a19108efe65f97575fdef56344 Mon Sep 17 00:00:00 2001 From: Dystopian Date: Fri, 19 Aug 2022 19:12:59 +0300 Subject: [PATCH 01/14] Fix rope attachment on menu click --- addons/towing/XEH_postInit.sqf | 2 -- addons/towing/functions/fnc_startTow.sqf | 2 +- addons/towing/functions/fnc_towStateMachinePFH.sqf | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/addons/towing/XEH_postInit.sqf b/addons/towing/XEH_postInit.sqf index 455532f8897..8b64f90f4b2 100644 --- a/addons/towing/XEH_postInit.sqf +++ b/addons/towing/XEH_postInit.sqf @@ -1,5 +1,4 @@ #include "script_component.hpp" -["MouseButtonDown", LINKFUNC(onMouseButtonDown)] call CBA_fnc_addDisplayHandler; ["MouseButtonUp", LINKFUNC(onMouseButtonUp)] call CBA_fnc_addDisplayHandler; GVAR(mouseLeft) = false; GVAR(mouseRight) = false; @@ -11,4 +10,3 @@ GVAR(canAttach) = false; params ["_parent", "_child"]; _child setTowParent _parent; }] call CBA_fnc_addEventHandler; - diff --git a/addons/towing/functions/fnc_startTow.sqf b/addons/towing/functions/fnc_startTow.sqf index 7422674c6ad..6dbc0e114e5 100644 --- a/addons/towing/functions/fnc_startTow.sqf +++ b/addons/towing/functions/fnc_startTow.sqf @@ -30,5 +30,5 @@ _unit removeItem _ropeClass; GVAR(cancel) = false; GVAR(canAttach) = false; +GVAR(onMouseButtonDownEHID) = ["MouseButtonDown", LINKFUNC(onMouseButtonDown)] call CBA_fnc_addDisplayHandler; [LINKFUNC(towStateMachinePFH), 0, [TOW_STATE_ATTACH_PARENT, _unit, _target, objNull, _ropeLength, _ropeClass]] call CBA_fnc_addPerFrameHandler; - diff --git a/addons/towing/functions/fnc_towStateMachinePFH.sqf b/addons/towing/functions/fnc_towStateMachinePFH.sqf index 40c21bc8991..bd71cf6fb1a 100644 --- a/addons/towing/functions/fnc_towStateMachinePFH.sqf +++ b/addons/towing/functions/fnc_towStateMachinePFH.sqf @@ -147,8 +147,8 @@ switch (_state) do { TRACE_2("state cleanup",GVAR(attachHelper),_handle); deleteVehicle GVAR(attachHelper); [_handle] call CBA_fnc_removePerFrameHandler; + ["MouseButtonDown", GVAR(onMouseButtonDownEHID)] call CBA_fnc_removeDisplayHandler; _unit setVariable [QGVAR(hint), []]; call EFUNC(interaction,hideMouseHint); }; }; - From 436ed1289622f68f018097dc9d86845e89a44166 Mon Sep 17 00:00:00 2001 From: Dystopian Date: Wed, 24 Aug 2022 23:44:14 +0300 Subject: [PATCH 02/14] Add multiple towing --- addons/towing/CfgVehicles.hpp | 76 ++++++------------- addons/towing/XEH_PREP.hpp | 5 +- addons/towing/XEH_postInit.sqf | 27 ++++++- addons/towing/functions/fnc_attachRopePFH.sqf | 26 ++++++- .../towing/functions/fnc_attachVehicles.sqf | 58 ++++++++++++++ addons/towing/functions/fnc_canStartTow.sqf | 21 ----- addons/towing/functions/fnc_detach.sqf | 48 ------------ addons/towing/functions/fnc_detachChild.sqf | 32 ++++++++ addons/towing/functions/fnc_detachRope.sqf | 59 ++++++++++++++ .../functions/fnc_isSuitableSimulation.sqf | 5 +- .../functions/fnc_towStateMachinePFH.sqf | 72 +++++++----------- addons/towing/script_component.hpp | 5 +- 12 files changed, 253 insertions(+), 181 deletions(-) create mode 100644 addons/towing/functions/fnc_attachVehicles.sqf delete mode 100644 addons/towing/functions/fnc_canStartTow.sqf delete mode 100644 addons/towing/functions/fnc_detach.sqf create mode 100644 addons/towing/functions/fnc_detachChild.sqf create mode 100644 addons/towing/functions/fnc_detachRope.sqf diff --git a/addons/towing/CfgVehicles.hpp b/addons/towing/CfgVehicles.hpp index f74cf5d3009..2af2123529a 100644 --- a/addons/towing/CfgVehicles.hpp +++ b/addons/towing/CfgVehicles.hpp @@ -1,56 +1,26 @@ -#define TOW_ACTION \ +#define CONCAT(a,b) a##b +#define TOW_ACTION(length) \ + class GVAR(CONCAT(startTow,length)) {\ + displayName = CSTRING(CONCAT(start,length));\ + condition = QUOTE([ARR_2(_player, 'CONCAT(ACE_rope,length)')] call DEFUNC(common,hasItem));\ + statement = QUOTE([ARR_3(_player,_target,'CONCAT(ACE_rope,length)')] call DFUNC(startTow));\ + exceptions[] = { INTERACTION_EXCEPTIONS };\ + } +#define TOW_ACTIONS \ class ACE_Actions {\ class ACE_MainActions {\ class ADDON {\ displayName = CSTRING(displayName);\ distance = TOW_ACTION_DISTANCE;\ - condition = QUOTE([ARR_1(_target)] call FUNC(isSuitableSimulation));\ - statement = "";\ + condition = QUOTE(_target call DFUNC(isSuitableSimulation));\ exceptions[] = { INTERACTION_EXCEPTIONS };\ - showDisabled = 0;\ - icon = "";\ - class GVAR(startTow3) {\ - displayName = CSTRING(start3);\ - condition = QUOTE(([ARR_2(_player,_target)] call FUNC(canStartTow)) && [ARR_2(_player, 'ACE_rope3')] call EFUNC(common,hasItem));\ - statement = QUOTE([ARR_3(_player,_target,'ACE_rope3')] call FUNC(startTow));\ - exceptions[] = { INTERACTION_EXCEPTIONS };\ - };\ - class GVAR(startTow6) {\ - displayName = CSTRING(start6);\ - condition = QUOTE(([ARR_2(_player,_target)] call FUNC(canStartTow)) && [ARR_2(_player, 'ACE_rope6')] call EFUNC(common,hasItem));\ - statement = QUOTE([ARR_3(_player,_target,'ACE_rope6')] call FUNC(startTow));\ - exceptions[] = { INTERACTION_EXCEPTIONS };\ - };\ - class GVAR(startTow12) {\ - displayName = CSTRING(start12);\ - condition = QUOTE(([ARR_2(_player,_target)] call FUNC(canStartTow)) && [ARR_2(_player, 'ACE_rope12')] call EFUNC(common,hasItem));\ - statement = QUOTE([ARR_3(_player,_target,'ACE_rope12')] call FUNC(startTow));\ - exceptions[] = { INTERACTION_EXCEPTIONS };\ - };\ - class GVAR(startTow15) {\ - displayName = CSTRING(start15);\ - condition = QUOTE(([ARR_2(_player,_target)] call FUNC(canStartTow)) && [ARR_2(_player, 'ACE_rope15')] call EFUNC(common,hasItem));\ - statement = QUOTE([ARR_3(_player,_target,'ACE_rope15')] call FUNC(startTow));\ - exceptions[] = { INTERACTION_EXCEPTIONS };\ - };\ - class GVAR(startTow18) {\ - displayName = CSTRING(start18);\ - condition = QUOTE(([ARR_2(_player,_target)] call FUNC(canStartTow)) && [ARR_2(_player, 'ACE_rope18')] call EFUNC(common,hasItem));\ - statement = QUOTE([ARR_3(_player,_target,'ACE_rope18')] call FUNC(startTow));\ - exceptions[] = { INTERACTION_EXCEPTIONS };\ - };\ - class GVAR(startTow27) {\ - displayName = CSTRING(start27);\ - condition = QUOTE(([ARR_2(_player,_target)] call FUNC(canStartTow)) && [ARR_2(_player, 'ACE_rope27')] call EFUNC(common,hasItem));\ - statement = QUOTE([ARR_3(_player,_target,'ACE_rope27')] call FUNC(startTow));\ - exceptions[] = { INTERACTION_EXCEPTIONS };\ - };\ - class GVAR(startTow36) {\ - displayName = CSTRING(start36);\ - condition = QUOTE(([ARR_2(_player,_target)] call FUNC(canStartTow)) && [ARR_2(_player, 'ACE_rope36')] call EFUNC(common,hasItem));\ - statement = QUOTE([ARR_3(_player,_target,'ACE_rope36')] call FUNC(startTow));\ - exceptions[] = { INTERACTION_EXCEPTIONS };\ - };\ + TOW_ACTION(3);\ + TOW_ACTION(6);\ + TOW_ACTION(12);\ + TOW_ACTION(15);\ + TOW_ACTION(18);\ + TOW_ACTION(27);\ + TOW_ACTION(36);\ };\ };\ } @@ -58,11 +28,16 @@ class ACE_Actions {\ class CfgVehicles { class LandVehicle; class Car: LandVehicle { - TOW_ACTION; + TOW_ACTIONS; }; class Tank: LandVehicle { - TOW_ACTION; + TOW_ACTIONS; + }; + + class AllVehicles; + class Ship: AllVehicles { + TOW_ACTIONS; }; class ThingX; @@ -76,8 +51,7 @@ class CfgVehicles { class ACE_Actions { class ACE_MainActions { displayName = CSTRING(detach); - condition = "true"; - statement = QUOTE(private _parent = _target getVariable [ARR_2(QQGVAR(parent), objNull)]; private _child = _target getVariable [ARR_2(QQGVAR(child), objNull)]; [ARR_3(_player,_parent,_child)] call FUNC(detach)); + statement = QUOTE([ARR_2(_player,_target)] call DFUNC(detachRope)); distance = 2; }; }; diff --git a/addons/towing/XEH_PREP.hpp b/addons/towing/XEH_PREP.hpp index f3937e01c3c..af58c61f8c6 100644 --- a/addons/towing/XEH_PREP.hpp +++ b/addons/towing/XEH_PREP.hpp @@ -1,6 +1,7 @@ PREP(attachRopePFH); -PREP(canStartTow); -PREP(detach); +PREP(attachVehicles); +PREP(detachChild); +PREP(detachRope); PREP(isSuitableSimulation); PREP(onMouseButtonDown); PREP(onMouseButtonUp); diff --git a/addons/towing/XEH_postInit.sqf b/addons/towing/XEH_postInit.sqf index 8b64f90f4b2..7380f09a399 100644 --- a/addons/towing/XEH_postInit.sqf +++ b/addons/towing/XEH_postInit.sqf @@ -6,7 +6,28 @@ GVAR(mouseRight) = false; GVAR(cancel) = false; GVAR(canAttach) = false; -[QGVAR(setTowParent), { - params ["_parent", "_child"]; - _child setTowParent _parent; +[QGVAR(ropeAttachTo), { + params ["_child", "_relativeAttachPos", "_rope", "_helper"]; + TRACE_4("ropeAttachTo",_child,_relativeAttachPos,_rope,_helper); + _helper ropeDetach _rope; + [_child, _relativeAttachPos] ropeAttachTo _rope; + deleteVehicle _helper; +}] call CBA_fnc_addEventHandler; + +[QGVAR(attachVehicles), LINKFUNC(attachVehicles)] call CBA_fnc_addEventHandler; +[QGVAR(detachChild), LINKFUNC(detachChild)] call CBA_fnc_addEventHandler; + +if (!isServer) exitWith {}; + +[QGVAR(cleanupParent), { + params ["_parent"]; + TRACE_1("cleanupParent",_parent); + _parent removeEventHandler ["RopeBreak", _parent getVariable QGVAR(RopeBreakEHID)]; + _parent setVariable [QGVAR(RopeBreakEHID), -1]; + private _parentParentHooks = _parent getVariable [QGVAR(parentHooks), []]; + if (_parentParentHooks isEqualTo []) then { + TRACE_1("remove Deleted EH",_parent); + _parent removeEventHandler ["Deleted", _parent getVariable QGVAR(DeletedEHID)]; + _parent setVariable [QGVAR(DeletedEHID), -1]; + }; }] call CBA_fnc_addEventHandler; diff --git a/addons/towing/functions/fnc_attachRopePFH.sqf b/addons/towing/functions/fnc_attachRopePFH.sqf index 50cfeac5fec..b5ce53a3fb8 100644 --- a/addons/towing/functions/fnc_attachRopePFH.sqf +++ b/addons/towing/functions/fnc_attachRopePFH.sqf @@ -40,11 +40,30 @@ if (_intersections isNotEqualTo []) then { _intersectionToUse params ["_intersectPosition", "", "_intersectObject"]; - // if we have a target object, we assume we are attaching to the parent. If no target object, we are attaching to child - GVAR(canAttach) = (_intersectObject isNotEqualTo _ignoreParent) && { (!isNull _target && { _intersectObject isEqualTo _target }) || { isNull _target && { [_intersectObject] call FUNC(isSuitableSimulation) }}} && { !(_intersectObject getVariable [QGVAR(towing), false]) }; + GVAR(canAttach) = + _intersectObject isNotEqualTo _ignoreParent + && { + // if we have a target object, we assume we are attaching to the parent. If no target object, we are attaching to child + if (!isNull _target) then { + _intersectObject isEqualTo _target + } else { + [_intersectObject] call FUNC(isSuitableSimulation) + && { // ignore _intersectObject with parent + private _intersectObjectParent = _intersectObject getVariable [QGVAR(parent), objNull]; + isNull _intersectObjectParent || {_intersectObjectParent == _ignoreParent} + } && { // arma prevents making rings (ropeAttachTo silently fails) + private _ancestor = _ignoreParent getVariable [QGVAR(parent), objNull]; + while {!isNull _ancestor && {_ancestor != _intersectObject}} do { + _ancestor = _ancestor getVariable [QGVAR(parent), objNull]; + }; + isNull _ancestor + } + } + } + ; if (GVAR(canAttach)) then { - TRACE_4("can attach",_target,_intersectObject,_ignoreParent,_ignoreRope); + // TRACE_4("can attach",_target,_intersectObject,_ignoreParent,_ignoreRope); GVAR(attachHelper) setPosASL _intersectPosition; _hintLMB = localize LSTRING(attach); @@ -76,4 +95,3 @@ if (_hint isNotEqualTo (_unit getVariable [QGVAR(hint), []])) then { _unit setVariable [QGVAR(hint), _hint]; _hint call EFUNC(interaction,showMouseHint); }; - diff --git a/addons/towing/functions/fnc_attachVehicles.sqf b/addons/towing/functions/fnc_attachVehicles.sqf new file mode 100644 index 00000000000..1f49a8f4944 --- /dev/null +++ b/addons/towing/functions/fnc_attachVehicles.sqf @@ -0,0 +1,58 @@ +#include "script_component.hpp" +/* + * Author: Dystopian + * Attaches child to parent vehicle. + * Run globally. + * + * Arguments: + * 0: Vehicle to tow from + * 1: Vehicle to tow + * 2: Rope End Position + * 3: Rope + * 4: Attached Helper Object + * + * Return Value: + * None + * + * Example: + * [parent, cursorObject, [0,0,0], ropes parent select 0] call ace_towing_fnc_attachVehicles + * + * Public: No + */ +params ["_parent", "_child", "_relativeAttachPos", "_rope", "_helper"]; +TRACE_5("attachVehicles",_parent,_child,_relativeAttachPos,_rope,_helper); + +if (local _parent) then { + _helper ropeDetach _rope; + [_child, _relativeAttachPos] ropeAttachTo _rope; + deleteVehicle _helper; +}; + +_child setTowParent _parent; +if (!isServer) exitWith {}; + +_child setVariable [QGVAR(parent), _parent, true]; + +{ + if (-1 == _x getVariable [QGVAR(DeletedEHID), -1]) then { + _x setVariable [QGVAR(DeletedEHID), _x addEventHandler ["Deleted", { + params ["_entity"]; + TRACE_1("Deleted EH",_entity); + { + [objNull, _hook, _entity] call FUNC(detachRope); + } forEach ((_entity getVariable [QGVAR(childHooks), []]) + (_entity getVariable [QGVAR(parentHooks), []])); + }]]; + }; +} forEach [_parent, _child]; + +if (-1 == _parent getVariable [QGVAR(RopeBreakEHID), -1]) then { + _parent setVariable [QGVAR(RopeBreakEHID), _parent addEventHandler ["RopeBreak", { + params ["_parent", "_rope", "_child"]; + if (isNull _rope) exitWith {}; // happens + private _hook = _rope getVariable [QGVAR(hook), objNull]; + private _hookChild = _hook getVariable [QGVAR(child), objNull]; + if (isNull _hook || {_child != _hookChild}) exitWith {}; // handle helper detach + TRACE_4("RopeBreak EH",_parent,_rope,_child,_hook); + [objNull, _hook] call FUNC(detachRope); + }]]; +}; diff --git a/addons/towing/functions/fnc_canStartTow.sqf b/addons/towing/functions/fnc_canStartTow.sqf deleted file mode 100644 index 8f9d2136db9..00000000000 --- a/addons/towing/functions/fnc_canStartTow.sqf +++ /dev/null @@ -1,21 +0,0 @@ -#include "script_component.hpp" -/* - * Author: Dani (TCVM) - * Condition for whether or not we can tow from this object - * - * Arguments: - * 0: Unit wanting to start towing - * 1: Vehicle to tow from - * - * Return Value: - * Whether or not we can start towing - * - * Example: - * [player, cursorObject] call ace_towing_fnc_canStartTow - * - * Public: No - */ -params ["_unit", "_target"]; -private _isTowing = _target getVariable [QGVAR(towing), false]; -TRACE_1("is towing",_isTowing); -!_isTowing diff --git a/addons/towing/functions/fnc_detach.sqf b/addons/towing/functions/fnc_detach.sqf deleted file mode 100644 index f593d5309f1..00000000000 --- a/addons/towing/functions/fnc_detach.sqf +++ /dev/null @@ -1,48 +0,0 @@ -#include "script_component.hpp" -/* - * Author: Dani (TCVM) - * Detaches child from parent, and gives rope item back - * - * Arguments: - * 0: Parent - * 1: Child - * - * Return Value: - * None - * - * Example: - * [player, cursorObject] call ace_towing_fnc_detach - * - * Public: No - */ -params ["_unit", "_parent", "_child"]; -TRACE_3("detach",_unit,_parent,_child); - -private _hook = _child getVariable [QGVAR(hook), objNull]; - -_parent removeEventHandler ["Deleted", _hook getVariable QGVAR(parentDeleteEventHandler)]; -_hook setVariable [QGVAR(parentDeleteEventHandler), -1]; - -_child removeEventHandler ["Deleted", _hook getVariable QGVAR(childDeleteEventHandler)]; -_hook setVariable [QGVAR(childDeleteEventHandler), -1]; - -_parent removeEventHandler ["RopeBreak", _parent getVariable QGVAR(ropeBreakEventHandler)]; -_parent setVariable [QGVAR(ropeBreakEventHandler), -1]; - -private _rope = _child getVariable [QGVAR(rope), objNull]; -ropeDestroy _rope; - -private _ropeClass = _hook getVariable [QGVAR(ropeClass), ""]; -deleteVehicle _hook; - -TRACE_1("rope",_ropeClass); - -if (_ropeClass isNotEqualTo "") then { - [_unit, _ropeClass, true] call CBA_fnc_addItem; -}; - -[QGVAR(setTowParent), [objNull, _child], _child] call CBA_fnc_targetEvent; - -_child setVariable [QGVAR(towing), false, true]; -_parent setVariable [QGVAR(towing), false, true]; - diff --git a/addons/towing/functions/fnc_detachChild.sqf b/addons/towing/functions/fnc_detachChild.sqf new file mode 100644 index 00000000000..d1113a88cc9 --- /dev/null +++ b/addons/towing/functions/fnc_detachChild.sqf @@ -0,0 +1,32 @@ +#include "script_component.hpp" +/* + * Author: Dystopian + * Detaches child. + * Run globally. + * + * Arguments: + * 0: Child + * + * Return Value: + * None + * + * Example: + * cursorObject call ace_towing_fnc_detachChild + * + * Public: No + */ +params ["_child"]; +TRACE_1("detachChild",_child); + +_child setTowParent objNull; + +if (!isServer) exitWith {}; + +_child setVariable [QGVAR(parent), objNull, true]; + +private _childChildHooks = _child getVariable [QGVAR(childHooks), []]; +if (_childChildHooks isEqualTo []) then { + TRACE_1("remove Deleted EH",_child); + _child removeEventHandler ["Deleted", _child getVariable QGVAR(DeletedEHID)]; + _child setVariable [QGVAR(DeletedEHID), -1]; +}; diff --git a/addons/towing/functions/fnc_detachRope.sqf b/addons/towing/functions/fnc_detachRope.sqf new file mode 100644 index 00000000000..942875b3a36 --- /dev/null +++ b/addons/towing/functions/fnc_detachRope.sqf @@ -0,0 +1,59 @@ +#include "script_component.hpp" +/* + * Author: Dystopian + * Detaches rope of given hook and gives rope item back. + * + * Arguments: + * 0: Player + * 1: Rope Hook + * 2: Deleted object (default: objNull) + * + * Return Value: + * None + * + * Example: + * [player, cursorObject] call ace_towing_fnc_detachRope + * + * Public: No + */ +params ["_unit", "_hook", ["_deletedObject", objNull]]; + +private _parent = _hook getVariable QGVAR(parent); +private _child = _hook getVariable QGVAR(child); +private _rope = _hook getVariable QGVAR(rope); + +TRACE_6("detachRope",_unit,_parent,_child,_hook,_rope,_deletedObject); + +ropeDestroy _rope; // can run on client + +if (!isNull _unit) then { + private _ropeClass = _hook getVariable [QGVAR(ropeClass), ""]; + TRACE_1("rope",_ropeClass); + if (!isNull _unit && {_ropeClass isNotEqualTo ""}) then { + [_unit, _ropeClass, true] call CBA_fnc_addItem; + }; +}; + +detach _hook; +deleteVehicle _hook; + +// cleanup object variables and EHs only if function isn't called from Deleted EH +if (isNull _deletedObject || {_parent isNotEqualTo _deletedObject}) then { + private _parentChildHooks = _parent getVariable [QGVAR(childHooks), []]; + _parentChildHooks = _parentChildHooks - [_hook]; + _parent setVariable [QGVAR(childHooks), _parentChildHooks, true]; + + if (_parentChildHooks isEqualTo []) then { + [QGVAR(cleanupParent), _parent] call CBA_fnc_serverEvent; + }; +}; + +if (isNull _deletedObject || {_child isNotEqualTo _deletedObject}) then { + private _childParentHooks = _child getVariable [QGVAR(parentHooks), []]; + _childParentHooks = _childParentHooks - [_hook]; + _child setVariable [QGVAR(parentHooks), _childParentHooks, true]; + + if (_childParentHooks isEqualTo []) then { + [QGVAR(detachChild), _child] call CBA_fnc_globalEvent; + }; +}; diff --git a/addons/towing/functions/fnc_isSuitableSimulation.sqf b/addons/towing/functions/fnc_isSuitableSimulation.sqf index 025b43937ef..13e6453a2ea 100644 --- a/addons/towing/functions/fnc_isSuitableSimulation.sqf +++ b/addons/towing/functions/fnc_isSuitableSimulation.sqf @@ -19,8 +19,7 @@ params ["_target"]; // need toLower since apparently this isn't case sensitive private _simulationType = getText ((configOf _target) >> "simulation"); -TRACE_1("sim type",_simulationType); +// TRACE_1("sim type",_simulationType); // Biki lies, you can both tow and tow as either TankX or CarX -(toLower _simulationType) in ["tankx", "carx"] - +(toLower _simulationType) in ["tankx", "carx", "shipx", "helicopterrtd"] diff --git a/addons/towing/functions/fnc_towStateMachinePFH.sqf b/addons/towing/functions/fnc_towStateMachinePFH.sqf index bd71cf6fb1a..c0194d97231 100644 --- a/addons/towing/functions/fnc_towStateMachinePFH.sqf +++ b/addons/towing/functions/fnc_towStateMachinePFH.sqf @@ -1,7 +1,7 @@ #include "script_component.hpp" /* * Author: Dani (TCVM) - * Called per frame. Handles current unit state for attaching a rope to two vehicles + * Called per frame. Handles current unit state for attaching a rope to two vehicles. * * Arguments: * 0: PFEH Args @@ -35,14 +35,16 @@ if (_exitCondition && {_state < TOW_STATE_CANCEL}) then { switch (_state) do { case TOW_STATE_ATTACH_PARENT: { - TRACE_2("state attach parent",_unit,_parent); + // TRACE_2("state attach parent",_unit,_parent); [_unit, _parent, objNull, objNull, [0, 0, 0], _length] call FUNC(attachRopePFH); if (GVAR(canAttach) && { GVAR(mouseLeft) }) then { _args set [0, TOW_STATE_ATTACH_CHILD]; - _rope = ropeCreate [_parent, _parent worldToModelVisual ASLtoAGL getPosASLVisual GVAR(attachHelper), _length]; - [GVAR(attachHelper), [0, 0, 0]] ropeAttachTo _rope; - + // can't use unit hand because rope doesn't change position when hand moving + // can't use createVehicleLocal because rope can be non-local (like parent) and it must be attached to global vehicle + GVAR(h) = createVehicle ["ace_refuel_helper", [0, 0, 0], [], 0, "CAN_COLLIDE"];//////////////////////////////////////////////////////// + GVAR(h) attachTo [_unit, [0,0,0], "LeftHand", true]; + _rope = ropeCreate [_parent, _parent worldToModelVisual ASLtoAGL getPosASLVisual GVAR(attachHelper), GVAR(h), [0,0,0], _length]; _args set [3, _rope]; }; @@ -52,7 +54,7 @@ switch (_state) do { }; }; case TOW_STATE_ATTACH_CHILD: { - TRACE_3("state attach child",_unit,_parent,_rope); + // TRACE_3("state attach child",_unit,_parent,_rope); [_unit, objNull, _parent, _rope, getPosASLVisual _rope, _length] call FUNC(attachRopePFH); if (GVAR(canAttach) && { GVAR(mouseLeft) }) then { @@ -81,60 +83,38 @@ switch (_state) do { GVAR(cancel) = false; }; - [QGVAR(setTowParent), [_parent, _child], _parent] call CBA_fnc_targetEvent; - - GVAR(attachHelper) ropeDetach _rope; - [_child, _relativeAttachPos] ropeAttachTo _rope; + detach GVAR(h); + // can't delete GVAR(h) without ropeDetach which requires local rope (==parent), so pass it to owner + if (isNull (_child getVariable [QGVAR(parent), objNull])) then { + [QGVAR(attachVehicles), [_parent, _child, _relativeAttachPos, _rope, GVAR(h)]] call CBA_fnc_globalEvent; + } else { + [QGVAR(ropeAttachTo), [_child, _relativeAttachPos, _rope, GVAR(h)], _parent] call CBA_fnc_targetEvent; + }; - private _hook = createVehicle [QGVAR(hook), [0, 0, 0], [], 0, "NONE"]; + private _hook = createVehicle [QGVAR(hook), [0, 0, 0], [], 0, "CAN_COLLIDE"]; _hook attachTo [_child, _relativeAttachPos]; _hook setVariable [QGVAR(parent), _parent, true]; _hook setVariable [QGVAR(child), _child, true]; - _child setVariable [QGVAR(rope), _rope, true]; - _child setVariable [QGVAR(hook), _hook, true]; - - _parent setVariable [QGVAR(hook), _hook, true]; - + _hook setVariable [QGVAR(rope), _rope, true]; _hook setVariable [QGVAR(ropeClass), _ropeClass, true]; + _rope setVariable [QGVAR(hook), _hook, true]; - _child setVariable [QGVAR(towing), true, true]; - _parent setVariable [QGVAR(towing), true, true]; - - _hook setVariable [QGVAR(parentDeleteEventHandler), _parent addEventHandler ["Deleted", { - params ["_entity"]; - - private _hook = _entity getVariable [QGVAR(hook), objNull]; - private _child = _hook getVariable [QGVAR(child), objNull]; - private _parent = _hook getVariable [QGVAR(parent), objNull]; - - [objNull, _parent, _child] call FUNC(detach); - }], true]; - - _hook setVariable [QGVAR(childDeleteEventHandler), _child addEventHandler ["Deleted", { - params ["_entity"]; - - private _hook = _entity getVariable [QGVAR(hook), objNull]; - private _child = _hook getVariable [QGVAR(child), objNull]; - private _parent = _hook getVariable [QGVAR(parent), objNull]; - - [objNull, _parent, _child] call FUNC(detach); - }], true]; - - _parent setVariable [QGVAR(ropeBreakEventHandler), _parent addEventHandler ["RopeBreak", { - params ["_parent", "_rope", "_child"]; - - [objNull, _parent, _child] call FUNC(detach); + private _childParentHooks = _child getVariable [QGVAR(parentHooks), []]; + _childParentHooks pushBack _hook; + _child setVariable [QGVAR(parentHooks), _childParentHooks, true]; - _parent removeEventHandler ["RopeBreak", _parent getVariable QGVAR(ropeBreakEventHandler)]; - _parent setVariable [QGVAR(ropeBreakEventHandler), -1]; - }], true]; + private _parentChildHooks = _parent getVariable [QGVAR(childHooks), []]; + _parentChildHooks pushBack _hook; + _parent setVariable [QGVAR(childHooks), _parentChildHooks, true]; _args set [0, TOW_STATE_CLEANUP]; }; case TOW_STATE_CANCEL: { TRACE_1("state cancel",_rope); if !(isNull _rope) then { + detach GVAR(h); + deleteVehicle GVAR(h); ropeDestroy _rope; }; [_unit, _ropeClass, true] call CBA_fnc_addItem; diff --git a/addons/towing/script_component.hpp b/addons/towing/script_component.hpp index 2d9790ac20e..341b90fb0d4 100644 --- a/addons/towing/script_component.hpp +++ b/addons/towing/script_component.hpp @@ -2,8 +2,8 @@ #define COMPONENT_BEAUTIFIED Towing #include "\z\ace\addons\main\script_mod.hpp" -// #define DEBUG_MODE_FULL -// #define DISABLE_COMPILE_CACHE +#define DEBUG_MODE_FULL +#define DISABLE_COMPILE_CACHE // #define ENABLE_PERFORMANCE_COUNTERS #ifdef DEBUG_ENABLED_TOWING @@ -24,4 +24,3 @@ #define TOW_STATE_ATTACH 2 #define TOW_STATE_CANCEL 3 #define TOW_STATE_CLEANUP 4 - From 784355c92df127240cbb110922f651fed6099c15 Mon Sep 17 00:00:00 2001 From: Dystopian Date: Sun, 28 Aug 2022 00:15:25 +0300 Subject: [PATCH 03/14] Add JIP support --- addons/towing/XEH_postInit.sqf | 9 +++++++++ addons/towing/XEH_preInit.sqf | 16 ++++++++++++++++ addons/towing/functions/fnc_attachVehicles.sqf | 1 + addons/towing/functions/fnc_detachChild.sqf | 1 + 4 files changed, 27 insertions(+) diff --git a/addons/towing/XEH_postInit.sqf b/addons/towing/XEH_postInit.sqf index 7380f09a399..d2d1b49e861 100644 --- a/addons/towing/XEH_postInit.sqf +++ b/addons/towing/XEH_postInit.sqf @@ -1,4 +1,5 @@ #include "script_component.hpp" + ["MouseButtonUp", LINKFUNC(onMouseButtonUp)] call CBA_fnc_addDisplayHandler; GVAR(mouseLeft) = false; GVAR(mouseRight) = false; @@ -31,3 +32,11 @@ if (!isServer) exitWith {}; _parent setVariable [QGVAR(DeletedEHID), -1]; }; }] call CBA_fnc_addEventHandler; + +addMissionEventHandler ["PlayerConnected", { + if (GVAR(allChildren) isEqualTo []) exitWith {}; + params ["", "", "", "_jip", "_owner"]; + if (!_jip) exitWith {}; + TRACE_2("pushing children",_owner,GVAR(allChildren)); + [QGVAR(setTowParentAllChildren), [GVAR(allChildren)], _owner] call CBA_fnc_ownerEvent; +}]; diff --git a/addons/towing/XEH_preInit.sqf b/addons/towing/XEH_preInit.sqf index b47cf6628db..1e8988a094d 100644 --- a/addons/towing/XEH_preInit.sqf +++ b/addons/towing/XEH_preInit.sqf @@ -6,4 +6,20 @@ PREP_RECOMPILE_START; #include "XEH_PREP.hpp" PREP_RECOMPILE_END; +// handle JIP +if (isServer) then { + GVAR(allChildren) = []; +} else { + // can't use CBA EH in postInit because too late for server PlayerConnected EH + [QGVAR(setTowParentAllChildren), { + params ["_children"]; + TRACE_1("setTowParentAllChildren",_children); + { + private _parent = _x getVariable QGVAR(parent); + TRACE_2("setTowParent",_x,_parent); + _x setTowParent _parent; + } forEach _children; + }] call CBA_fnc_addEventHandler; +}; + ADDON = true; diff --git a/addons/towing/functions/fnc_attachVehicles.sqf b/addons/towing/functions/fnc_attachVehicles.sqf index 1f49a8f4944..1c87c22ee4c 100644 --- a/addons/towing/functions/fnc_attachVehicles.sqf +++ b/addons/towing/functions/fnc_attachVehicles.sqf @@ -32,6 +32,7 @@ _child setTowParent _parent; if (!isServer) exitWith {}; _child setVariable [QGVAR(parent), _parent, true]; +GVAR(allChildren) pushBack _child; { if (-1 == _x getVariable [QGVAR(DeletedEHID), -1]) then { diff --git a/addons/towing/functions/fnc_detachChild.sqf b/addons/towing/functions/fnc_detachChild.sqf index d1113a88cc9..29e4d14b6e0 100644 --- a/addons/towing/functions/fnc_detachChild.sqf +++ b/addons/towing/functions/fnc_detachChild.sqf @@ -23,6 +23,7 @@ _child setTowParent objNull; if (!isServer) exitWith {}; _child setVariable [QGVAR(parent), objNull, true]; +GVAR(allChildren) = GVAR(allChildren) - [_child]; private _childChildHooks = _child getVariable [QGVAR(childHooks), []]; if (_childChildHooks isEqualTo []) then { From d5e3198ff9bda4764ec26daac4960a2f319d8126 Mon Sep 17 00:00:00 2001 From: Dystopian Date: Sun, 28 Aug 2022 15:07:33 +0300 Subject: [PATCH 04/14] Replace hook model, add helper object --- addons/towing/CfgVehicles.hpp | 12 +++++++----- .../functions/fnc_towStateMachinePFH.sqf | 18 +++++++++--------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/addons/towing/CfgVehicles.hpp b/addons/towing/CfgVehicles.hpp index 2af2123529a..d9bdc076ce7 100644 --- a/addons/towing/CfgVehicles.hpp +++ b/addons/towing/CfgVehicles.hpp @@ -41,18 +41,20 @@ class CfgVehicles { }; class ThingX; - class GVAR(hook): ThingX { - displayName = "hook"; // not publicly visible, no stringtable needed + class GVAR(helper): ThingX { + displayName = "helper"; // not publicly visible, no stringtable needed scope = 1; scopeCurator = 1; - model = "\a3\Structures_F_Orange\VR\Helpers\Sign_sphere10cm_Geometry_F.p3d"; + model = "\A3\Weapons_f\empty"; destrType = "DestructNo"; - + }; + class GVAR(hook): GVAR(helper) { + displayName = "hook"; class ACE_Actions { class ACE_MainActions { displayName = CSTRING(detach); statement = QUOTE([ARR_2(_player,_target)] call DFUNC(detachRope)); - distance = 2; + distance = TOW_ACTION_DISTANCE; }; }; }; diff --git a/addons/towing/functions/fnc_towStateMachinePFH.sqf b/addons/towing/functions/fnc_towStateMachinePFH.sqf index c0194d97231..d03106988e6 100644 --- a/addons/towing/functions/fnc_towStateMachinePFH.sqf +++ b/addons/towing/functions/fnc_towStateMachinePFH.sqf @@ -42,9 +42,9 @@ switch (_state) do { _args set [0, TOW_STATE_ATTACH_CHILD]; // can't use unit hand because rope doesn't change position when hand moving // can't use createVehicleLocal because rope can be non-local (like parent) and it must be attached to global vehicle - GVAR(h) = createVehicle ["ace_refuel_helper", [0, 0, 0], [], 0, "CAN_COLLIDE"];//////////////////////////////////////////////////////// - GVAR(h) attachTo [_unit, [0,0,0], "LeftHand", true]; - _rope = ropeCreate [_parent, _parent worldToModelVisual ASLtoAGL getPosASLVisual GVAR(attachHelper), GVAR(h), [0,0,0], _length]; + GVAR(helper) = createVehicle [QGVAR(helper), [0, 0, 0], [], 0, "CAN_COLLIDE"]; + GVAR(helper) attachTo [_unit, [0,0,0], "LeftHand", true]; + _rope = ropeCreate [_parent, _parent worldToModelVisual ASLtoAGL getPosASLVisual GVAR(attachHelper), GVAR(helper), [0,0,0], _length]; _args set [3, _rope]; }; @@ -83,12 +83,12 @@ switch (_state) do { GVAR(cancel) = false; }; - detach GVAR(h); - // can't delete GVAR(h) without ropeDetach which requires local rope (==parent), so pass it to owner + detach GVAR(helper); + // can't delete GVAR(helper) without ropeDetach which requires local rope (==parent), so pass it to owner if (isNull (_child getVariable [QGVAR(parent), objNull])) then { - [QGVAR(attachVehicles), [_parent, _child, _relativeAttachPos, _rope, GVAR(h)]] call CBA_fnc_globalEvent; + [QGVAR(attachVehicles), [_parent, _child, _relativeAttachPos, _rope, GVAR(helper)]] call CBA_fnc_globalEvent; } else { - [QGVAR(ropeAttachTo), [_child, _relativeAttachPos, _rope, GVAR(h)], _parent] call CBA_fnc_targetEvent; + [QGVAR(ropeAttachTo), [_child, _relativeAttachPos, _rope, GVAR(helper)], _parent] call CBA_fnc_targetEvent; }; private _hook = createVehicle [QGVAR(hook), [0, 0, 0], [], 0, "CAN_COLLIDE"]; @@ -113,8 +113,8 @@ switch (_state) do { case TOW_STATE_CANCEL: { TRACE_1("state cancel",_rope); if !(isNull _rope) then { - detach GVAR(h); - deleteVehicle GVAR(h); + detach GVAR(helper); + deleteVehicle GVAR(helper); ropeDestroy _rope; }; [_unit, _ropeClass, true] call CBA_fnc_addItem; From 4310dfa0aeb6e2a0af10ba27743a9e6008b67aab Mon Sep 17 00:00:00 2001 From: Dystopian Date: Sun, 28 Aug 2022 15:08:26 +0300 Subject: [PATCH 05/14] Add parent hook --- addons/towing/functions/fnc_detachRope.sqf | 14 +++++++++++--- addons/towing/functions/fnc_towStateMachinePFH.sqf | 6 ++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/addons/towing/functions/fnc_detachRope.sqf b/addons/towing/functions/fnc_detachRope.sqf index 942875b3a36..0e8bd92c6dc 100644 --- a/addons/towing/functions/fnc_detachRope.sqf +++ b/addons/towing/functions/fnc_detachRope.sqf @@ -18,11 +18,17 @@ */ params ["_unit", "_hook", ["_deletedObject", objNull]]; +private _hookParent = _hook getVariable QGVAR(hookParent); +if (isNil "_hookParent") then { + _hookParent = _hook; + _hook = _hookParent getVariable QGVAR(hook); +}; + private _parent = _hook getVariable QGVAR(parent); private _child = _hook getVariable QGVAR(child); private _rope = _hook getVariable QGVAR(rope); -TRACE_6("detachRope",_unit,_parent,_child,_hook,_rope,_deletedObject); +TRACE_7("detachRope",_unit,_parent,_child,_hook,_hookParent,_rope,_deletedObject); ropeDestroy _rope; // can run on client @@ -34,8 +40,10 @@ if (!isNull _unit) then { }; }; -detach _hook; -deleteVehicle _hook; +{ + detach _x; + deleteVehicle _x; +} forEach [_hook, _hookParent]; // cleanup object variables and EHs only if function isn't called from Deleted EH if (isNull _deletedObject || {_parent isNotEqualTo _deletedObject}) then { diff --git a/addons/towing/functions/fnc_towStateMachinePFH.sqf b/addons/towing/functions/fnc_towStateMachinePFH.sqf index d03106988e6..a1881734b6a 100644 --- a/addons/towing/functions/fnc_towStateMachinePFH.sqf +++ b/addons/towing/functions/fnc_towStateMachinePFH.sqf @@ -91,6 +91,9 @@ switch (_state) do { [QGVAR(ropeAttachTo), [_child, _relativeAttachPos, _rope, GVAR(helper)], _parent] call CBA_fnc_targetEvent; }; + private _hookParent = createVehicle [QGVAR(hook), [0, 0, 0], [], 0, "CAN_COLLIDE"]; + _hookParent attachTo [_parent, _parent worldToModelVisual ASLtoAGL getPosASLVisual _rope]; + private _hook = createVehicle [QGVAR(hook), [0, 0, 0], [], 0, "CAN_COLLIDE"]; _hook attachTo [_child, _relativeAttachPos]; @@ -98,6 +101,9 @@ switch (_state) do { _hook setVariable [QGVAR(child), _child, true]; _hook setVariable [QGVAR(rope), _rope, true]; _hook setVariable [QGVAR(ropeClass), _ropeClass, true]; + _hook setVariable [QGVAR(hookParent), _hookParent, true]; + + _hookParent setVariable [QGVAR(hook), _hook, true]; _rope setVariable [QGVAR(hook), _hook, true]; private _childParentHooks = _child getVariable [QGVAR(parentHooks), []]; From 438119868b1b689bb084b3984430b02bae14eeab Mon Sep 17 00:00:00 2001 From: Dystopian Date: Mon, 29 Aug 2022 01:54:45 +0300 Subject: [PATCH 06/14] Decrease public setVar count --- addons/towing/functions/fnc_attachRopePFH.sqf | 2 +- addons/towing/functions/fnc_attachVehicles.sqf | 2 +- addons/towing/functions/fnc_detachRope.sqf | 14 +++++--------- addons/towing/functions/fnc_towStateMachinePFH.sqf | 8 +++----- 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/addons/towing/functions/fnc_attachRopePFH.sqf b/addons/towing/functions/fnc_attachRopePFH.sqf index b5ce53a3fb8..4152ed04346 100644 --- a/addons/towing/functions/fnc_attachRopePFH.sqf +++ b/addons/towing/functions/fnc_attachRopePFH.sqf @@ -48,7 +48,7 @@ if (_intersections isNotEqualTo []) then { _intersectObject isEqualTo _target } else { [_intersectObject] call FUNC(isSuitableSimulation) - && { // ignore _intersectObject with parent + && { // ignore _intersectObject which has parent != _ignoreParent private _intersectObjectParent = _intersectObject getVariable [QGVAR(parent), objNull]; isNull _intersectObjectParent || {_intersectObjectParent == _ignoreParent} } && { // arma prevents making rings (ropeAttachTo silently fails) diff --git a/addons/towing/functions/fnc_attachVehicles.sqf b/addons/towing/functions/fnc_attachVehicles.sqf index 1c87c22ee4c..c4cf7568a6e 100644 --- a/addons/towing/functions/fnc_attachVehicles.sqf +++ b/addons/towing/functions/fnc_attachVehicles.sqf @@ -51,7 +51,7 @@ if (-1 == _parent getVariable [QGVAR(RopeBreakEHID), -1]) then { params ["_parent", "_rope", "_child"]; if (isNull _rope) exitWith {}; // happens private _hook = _rope getVariable [QGVAR(hook), objNull]; - private _hookChild = _hook getVariable [QGVAR(child), objNull]; + private _hookChild = _hook getVariable [QGVAR(vars), []] param [1, objNull]; if (isNull _hook || {_child != _hookChild}) exitWith {}; // handle helper detach TRACE_4("RopeBreak EH",_parent,_rope,_child,_hook); [objNull, _hook] call FUNC(detachRope); diff --git a/addons/towing/functions/fnc_detachRope.sqf b/addons/towing/functions/fnc_detachRope.sqf index 0e8bd92c6dc..005c1dffc1d 100644 --- a/addons/towing/functions/fnc_detachRope.sqf +++ b/addons/towing/functions/fnc_detachRope.sqf @@ -18,22 +18,19 @@ */ params ["_unit", "_hook", ["_deletedObject", objNull]]; -private _hookParent = _hook getVariable QGVAR(hookParent); -if (isNil "_hookParent") then { - _hookParent = _hook; - _hook = _hookParent getVariable QGVAR(hook); +private _hookVars = _hook getVariable QGVAR(vars); +if (isNil "_hookVars") then { // this is hookParent + _hook = _hook getVariable QGVAR(hook); + _hookVars = _hook getVariable QGVAR(vars); }; -private _parent = _hook getVariable QGVAR(parent); -private _child = _hook getVariable QGVAR(child); -private _rope = _hook getVariable QGVAR(rope); +_hookVars params ["_parent", "_child", "_rope", "_ropeClass", "_hookParent"]; TRACE_7("detachRope",_unit,_parent,_child,_hook,_hookParent,_rope,_deletedObject); ropeDestroy _rope; // can run on client if (!isNull _unit) then { - private _ropeClass = _hook getVariable [QGVAR(ropeClass), ""]; TRACE_1("rope",_ropeClass); if (!isNull _unit && {_ropeClass isNotEqualTo ""}) then { [_unit, _ropeClass, true] call CBA_fnc_addItem; @@ -55,7 +52,6 @@ if (isNull _deletedObject || {_parent isNotEqualTo _deletedObject}) then { [QGVAR(cleanupParent), _parent] call CBA_fnc_serverEvent; }; }; - if (isNull _deletedObject || {_child isNotEqualTo _deletedObject}) then { private _childParentHooks = _child getVariable [QGVAR(parentHooks), []]; _childParentHooks = _childParentHooks - [_hook]; diff --git a/addons/towing/functions/fnc_towStateMachinePFH.sqf b/addons/towing/functions/fnc_towStateMachinePFH.sqf index a1881734b6a..39805555685 100644 --- a/addons/towing/functions/fnc_towStateMachinePFH.sqf +++ b/addons/towing/functions/fnc_towStateMachinePFH.sqf @@ -97,11 +97,9 @@ switch (_state) do { private _hook = createVehicle [QGVAR(hook), [0, 0, 0], [], 0, "CAN_COLLIDE"]; _hook attachTo [_child, _relativeAttachPos]; - _hook setVariable [QGVAR(parent), _parent, true]; - _hook setVariable [QGVAR(child), _child, true]; - _hook setVariable [QGVAR(rope), _rope, true]; - _hook setVariable [QGVAR(ropeClass), _ropeClass, true]; - _hook setVariable [QGVAR(hookParent), _hookParent, true]; + // use array to decrease public setVar count + private _hookVars = [_parent, _child, _rope, _ropeClass, _hookParent]; + _hook setVariable [QGVAR(vars), _hookVars, true]; _hookParent setVariable [QGVAR(hook), _hook, true]; _rope setVariable [QGVAR(hook), _hook, true]; From 3e9b821b13794af1b1a3adce59d0e2daa21c6365 Mon Sep 17 00:00:00 2001 From: Dystopian Date: Mon, 29 Aug 2022 01:56:42 +0300 Subject: [PATCH 07/14] Fix double cleanup after Deleted EH --- addons/towing/functions/fnc_attachVehicles.sqf | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/addons/towing/functions/fnc_attachVehicles.sqf b/addons/towing/functions/fnc_attachVehicles.sqf index c4cf7568a6e..c2e34b4786b 100644 --- a/addons/towing/functions/fnc_attachVehicles.sqf +++ b/addons/towing/functions/fnc_attachVehicles.sqf @@ -38,10 +38,16 @@ GVAR(allChildren) pushBack _child; if (-1 == _x getVariable [QGVAR(DeletedEHID), -1]) then { _x setVariable [QGVAR(DeletedEHID), _x addEventHandler ["Deleted", { params ["_entity"]; - TRACE_1("Deleted EH",_entity); + private _childHooks = _entity getVariable [QGVAR(childHooks), []]; + private _parentHooks = _entity getVariable [QGVAR(parentHooks), []]; + TRACE_3("Deleted EH",_entity,_childHooks,_parentHooks); { - [objNull, _hook, _entity] call FUNC(detachRope); - } forEach ((_entity getVariable [QGVAR(childHooks), []]) + (_entity getVariable [QGVAR(parentHooks), []])); + [objNull, _x, _entity] call FUNC(detachRope); + } forEach (_childHooks + _parentHooks); + if (_childHooks isNotEqualTo []) then { // only for parent + // because deleting lasts for several frames we have to delete RB EH to fix double cleanup + _entity removeEventHandler ["RopeBreak", _entity getVariable QGVAR(RopeBreakEHID)]; + }; }]]; }; } forEach [_parent, _child]; From 9dc8ded1aa8c5fa8ac5c5d94d208620e6b5b2526 Mon Sep 17 00:00:00 2001 From: Dystopian Date: Mon, 29 Aug 2022 03:51:43 +0300 Subject: [PATCH 08/14] Cleanup --- addons/towing/script_component.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/towing/script_component.hpp b/addons/towing/script_component.hpp index 341b90fb0d4..c52e84046e4 100644 --- a/addons/towing/script_component.hpp +++ b/addons/towing/script_component.hpp @@ -2,8 +2,8 @@ #define COMPONENT_BEAUTIFIED Towing #include "\z\ace\addons\main\script_mod.hpp" -#define DEBUG_MODE_FULL -#define DISABLE_COMPILE_CACHE +// #define DEBUG_MODE_FULL +// #define DISABLE_COMPILE_CACHE // #define ENABLE_PERFORMANCE_COUNTERS #ifdef DEBUG_ENABLED_TOWING From 54d842f73fbb256b2c50e8aa4a4b7cfe70870430 Mon Sep 17 00:00:00 2001 From: Dystopian Date: Thu, 3 Nov 2022 23:29:28 +0300 Subject: [PATCH 09/14] Add detach actions to vehicles --- addons/towing/CfgVehicles.hpp | 1 + addons/towing/XEH_PREP.hpp | 1 + .../towing/functions/fnc_getDetachActions.sqf | 40 +++++++++++++++++++ 3 files changed, 42 insertions(+) create mode 100644 addons/towing/functions/fnc_getDetachActions.sqf diff --git a/addons/towing/CfgVehicles.hpp b/addons/towing/CfgVehicles.hpp index d9bdc076ce7..417d5d3cd8d 100644 --- a/addons/towing/CfgVehicles.hpp +++ b/addons/towing/CfgVehicles.hpp @@ -14,6 +14,7 @@ class ACE_Actions {\ distance = TOW_ACTION_DISTANCE;\ condition = QUOTE(_target call DFUNC(isSuitableSimulation));\ exceptions[] = { INTERACTION_EXCEPTIONS };\ + insertChildren = QUOTE(_target call DFUNC(getDetachActions));\ TOW_ACTION(3);\ TOW_ACTION(6);\ TOW_ACTION(12);\ diff --git a/addons/towing/XEH_PREP.hpp b/addons/towing/XEH_PREP.hpp index 63c7c1875d3..b72f70c55b7 100644 --- a/addons/towing/XEH_PREP.hpp +++ b/addons/towing/XEH_PREP.hpp @@ -3,6 +3,7 @@ PREP(attachRopePFH); PREP(attachVehicles); PREP(detachChild); PREP(detachRope); +PREP(getDetachActions); PREP(isSuitableSimulation); PREP(onMouseButtonDown); PREP(onMouseButtonUp); diff --git a/addons/towing/functions/fnc_getDetachActions.sqf b/addons/towing/functions/fnc_getDetachActions.sqf new file mode 100644 index 00000000000..0dd50fa1b77 --- /dev/null +++ b/addons/towing/functions/fnc_getDetachActions.sqf @@ -0,0 +1,40 @@ +#include "script_component.hpp" +/* + * Author: Dystopian + * Creates vehicle detach actions for attached ropes. + * + * Arguments: + * 0: Vehicle + * + * Return Value: + * Detach actions + * + * Example: + * cursorObject call ace_towing_fnc_getDetachActions + * + * Public: No + */ +params ["_vehicle"]; + +private _statement = { + params ["", "_player", "_hook"]; + [_player, _hook] call FUNC(detachRope); +}; + +private _parentHooks = _vehicle getVariable [QGVAR(parentHooks), []]; +private _childHooks = _vehicle getVariable [QGVAR(childHooks), []]; + +(_parentHooks + _childHooks) apply { + private _hook = _x; + _hook getVariable QGVAR(vars) params ["_hookParent", "_hookChild"]; + private _partner = if (_vehicle == _hookParent) then {_hookChild} else {_hookParent}; + private _partnerName = getText (configOf _partner >> "displayName"); + private _partnerOwnerName = [_partner, true] call EFUNC(common,getName); + if (_partnerOwnerName != "") then { + _partnerName = format ["%1, %2", _partnerName, _partnerOwnerName]; + }; + private _name = format ["%1 (%2)", LLSTRING(detach), _partnerName]; + private _icon = [_partner] call EFUNC(common,getVehicleIcon); + private _action = [format ["%1", _hook], _name, _icon, _statement, {true}, {}, _hook] call EFUNC(interact_menu,createAction); + [_action, [], _vehicle] +} From 0565947fbc81060a0c49016ce2f15d1ea949665a Mon Sep 17 00:00:00 2001 From: Dystopian Date: Thu, 3 Nov 2022 23:30:35 +0300 Subject: [PATCH 10/14] Disable helicopters towing --- addons/towing/functions/fnc_isSuitableSimulation.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/towing/functions/fnc_isSuitableSimulation.sqf b/addons/towing/functions/fnc_isSuitableSimulation.sqf index 13e6453a2ea..b264c39a23d 100644 --- a/addons/towing/functions/fnc_isSuitableSimulation.sqf +++ b/addons/towing/functions/fnc_isSuitableSimulation.sqf @@ -22,4 +22,4 @@ private _simulationType = getText ((configOf _target) >> "simulation"); // TRACE_1("sim type",_simulationType); // Biki lies, you can both tow and tow as either TankX or CarX -(toLower _simulationType) in ["tankx", "carx", "shipx", "helicopterrtd"] +(toLower _simulationType) in ["tankx", "carx", "shipx"] From ddf8b5611105075f1f600d1497cea18d9254ef32 Mon Sep 17 00:00:00 2001 From: Dystopian Date: Sat, 5 Nov 2022 00:41:39 +0300 Subject: [PATCH 11/14] Add rope to ships --- addons/towing/CfgVehicles.hpp | 50 +++++++++++++++++----------------- addons/towing/initSettings.sqf | 5 ++-- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/addons/towing/CfgVehicles.hpp b/addons/towing/CfgVehicles.hpp index 417d5d3cd8d..4e40783bce3 100644 --- a/addons/towing/CfgVehicles.hpp +++ b/addons/towing/CfgVehicles.hpp @@ -1,30 +1,30 @@ #define CONCAT(a,b) a##b #define TOW_ACTION(length) \ - class GVAR(CONCAT(startTow,length)) {\ - displayName = CSTRING(CONCAT(start,length));\ - condition = QUOTE([ARR_2(_player, 'CONCAT(ACE_rope,length)')] call DEFUNC(common,hasItem));\ - statement = QUOTE([ARR_3(_player,_target,'CONCAT(ACE_rope,length)')] call DFUNC(startTow));\ - exceptions[] = { INTERACTION_EXCEPTIONS };\ - } + class GVAR(CONCAT(startTow,length)) {\ + displayName = CSTRING(CONCAT(start,length));\ + condition = QUOTE([ARR_2(_player,'CONCAT(ACE_rope,length)')] call DEFUNC(common,hasItem));\ + statement = QUOTE([ARR_3(_player,_target,'CONCAT(ACE_rope,length)')] call DFUNC(startTow));\ + exceptions[] = { INTERACTION_EXCEPTIONS };\ + } #define TOW_ACTIONS \ -class ACE_Actions {\ - class ACE_MainActions {\ - class ADDON {\ - displayName = CSTRING(displayName);\ - distance = TOW_ACTION_DISTANCE;\ - condition = QUOTE(_target call DFUNC(isSuitableSimulation));\ - exceptions[] = { INTERACTION_EXCEPTIONS };\ - insertChildren = QUOTE(_target call DFUNC(getDetachActions));\ - TOW_ACTION(3);\ - TOW_ACTION(6);\ - TOW_ACTION(12);\ - TOW_ACTION(15);\ - TOW_ACTION(18);\ - TOW_ACTION(27);\ - TOW_ACTION(36);\ + class ACE_Actions {\ + class ACE_MainActions {\ + class ADDON {\ + displayName = CSTRING(displayName);\ + distance = TOW_ACTION_DISTANCE;\ + condition = QUOTE(_target call DFUNC(isSuitableSimulation));\ + exceptions[] = { INTERACTION_EXCEPTIONS };\ + insertChildren = QUOTE(_target call DFUNC(getDetachActions));\ + TOW_ACTION(3);\ + TOW_ACTION(6);\ + TOW_ACTION(12);\ + TOW_ACTION(15);\ + TOW_ACTION(18);\ + TOW_ACTION(27);\ + TOW_ACTION(36);\ + };\ };\ - };\ -} + } class CfgVehicles { class LandVehicle; @@ -36,8 +36,8 @@ class CfgVehicles { TOW_ACTIONS; }; - class AllVehicles; - class Ship: AllVehicles { + class Ship; + class Ship_F: Ship { TOW_ACTIONS; }; diff --git a/addons/towing/initSettings.sqf b/addons/towing/initSettings.sqf index 8361dccccd7..309a9e753a7 100644 --- a/addons/towing/initSettings.sqf +++ b/addons/towing/initSettings.sqf @@ -7,7 +7,8 @@ { if !(_this && {isServer} && {isNil QGVAR(addRopeToVehicleInventory_initialized)}) exitWith {}; GVAR(addRopeToVehicleInventory_initialized) = true; - ["Tank", "initPost", LINKFUNC(addRopeToVehicle), true, [], true] call CBA_fnc_addClassEventHandler; - ["Car", "initPost", LINKFUNC(addRopeToVehicle), true, [], true] call CBA_fnc_addClassEventHandler; + { + [_x, "initPost", LINKFUNC(addRopeToVehicle), true, [], true] call CBA_fnc_addClassEventHandler; + } forEach ["Car", "Ship", "Tank"]; } ] call CBA_fnc_addSetting; From 9feaa72168c94b6f28389fb5e7e4be06b4ed11d5 Mon Sep 17 00:00:00 2001 From: Dystopian Date: Sat, 16 Sep 2023 01:31:03 +0300 Subject: [PATCH 12/14] Cleanup postInit assignments --- addons/towing/XEH_postInit.sqf | 3 --- 1 file changed, 3 deletions(-) diff --git a/addons/towing/XEH_postInit.sqf b/addons/towing/XEH_postInit.sqf index d2d1b49e861..4a64b5bb997 100644 --- a/addons/towing/XEH_postInit.sqf +++ b/addons/towing/XEH_postInit.sqf @@ -4,9 +4,6 @@ GVAR(mouseLeft) = false; GVAR(mouseRight) = false; -GVAR(cancel) = false; -GVAR(canAttach) = false; - [QGVAR(ropeAttachTo), { params ["_child", "_relativeAttachPos", "_rope", "_helper"]; TRACE_4("ropeAttachTo",_child,_relativeAttachPos,_rope,_helper); From ec35e15a5244b97788fe60521d58b804734a57f8 Mon Sep 17 00:00:00 2001 From: Dystopian Date: Sun, 24 Sep 2023 01:32:13 +0300 Subject: [PATCH 13/14] Fix interaction with dead vehicle --- addons/towing/CfgVehicles.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/towing/CfgVehicles.hpp b/addons/towing/CfgVehicles.hpp index 4e40783bce3..6775a8c9e21 100644 --- a/addons/towing/CfgVehicles.hpp +++ b/addons/towing/CfgVehicles.hpp @@ -12,7 +12,7 @@ class ADDON {\ displayName = CSTRING(displayName);\ distance = TOW_ACTION_DISTANCE;\ - condition = QUOTE(_target call DFUNC(isSuitableSimulation));\ + condition = QUOTE(alive _target && {_target call DFUNC(isSuitableSimulation)});\ exceptions[] = { INTERACTION_EXCEPTIONS };\ insertChildren = QUOTE(_target call DFUNC(getDetachActions));\ TOW_ACTION(3);\ From 323dd43b66410ee9fff7407a497f6f423eeed0c2 Mon Sep 17 00:00:00 2001 From: Dystopian Date: Sun, 5 Nov 2023 20:36:25 +0300 Subject: [PATCH 14/14] Apply suggestions from code review and Fix useless isNull check Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --- addons/towing/XEH_postInit.sqf | 4 ++-- addons/towing/functions/fnc_attachRopePFH.sqf | 2 +- addons/towing/functions/fnc_detachChild.sqf | 2 +- addons/towing/functions/fnc_detachRope.sqf | 9 +++------ addons/towing/functions/fnc_getDetachActions.sqf | 2 +- addons/towing/functions/fnc_towStateMachinePFH.sqf | 4 ++-- 6 files changed, 10 insertions(+), 13 deletions(-) diff --git a/addons/towing/XEH_postInit.sqf b/addons/towing/XEH_postInit.sqf index 4a64b5bb997..3c8f4e8ec18 100644 --- a/addons/towing/XEH_postInit.sqf +++ b/addons/towing/XEH_postInit.sqf @@ -20,12 +20,12 @@ if (!isServer) exitWith {}; [QGVAR(cleanupParent), { params ["_parent"]; TRACE_1("cleanupParent",_parent); - _parent removeEventHandler ["RopeBreak", _parent getVariable QGVAR(RopeBreakEHID)]; + _parent removeEventHandler ["RopeBreak", _parent getVariable [QGVAR(RopeBreakEHID), -1]]; _parent setVariable [QGVAR(RopeBreakEHID), -1]; private _parentParentHooks = _parent getVariable [QGVAR(parentHooks), []]; if (_parentParentHooks isEqualTo []) then { TRACE_1("remove Deleted EH",_parent); - _parent removeEventHandler ["Deleted", _parent getVariable QGVAR(DeletedEHID)]; + _parent removeEventHandler ["Deleted", _parent getVariable [QGVAR(DeletedEHID), -1]]; _parent setVariable [QGVAR(DeletedEHID), -1]; }; }] call CBA_fnc_addEventHandler; diff --git a/addons/towing/functions/fnc_attachRopePFH.sqf b/addons/towing/functions/fnc_attachRopePFH.sqf index c1b62a061f9..37f626e0a92 100644 --- a/addons/towing/functions/fnc_attachRopePFH.sqf +++ b/addons/towing/functions/fnc_attachRopePFH.sqf @@ -65,7 +65,7 @@ if (_intersections isNotEqualTo []) then { if (GVAR(canAttach)) then { // TRACE_4("can attach",_target,_intersectObject,_ignoreParent,_ignoreRope); GVAR(attachHelper) setPosASL _intersectPosition; - _hintLMB = localize LSTRING(attach); + _hintLMB = LLSTRING(attach); GVAR(attachHelper) setVariable [QGVAR(object), _intersectObject]; }; diff --git a/addons/towing/functions/fnc_detachChild.sqf b/addons/towing/functions/fnc_detachChild.sqf index c78f3e6ce84..a30f90d8c6e 100644 --- a/addons/towing/functions/fnc_detachChild.sqf +++ b/addons/towing/functions/fnc_detachChild.sqf @@ -28,6 +28,6 @@ GVAR(allChildren) = GVAR(allChildren) - [_child]; private _childChildHooks = _child getVariable [QGVAR(childHooks), []]; if (_childChildHooks isEqualTo []) then { TRACE_1("remove Deleted EH",_child); - _child removeEventHandler ["Deleted", _child getVariable QGVAR(DeletedEHID)]; + _child removeEventHandler ["Deleted", _child getVariable [QGVAR(DeletedEHID), -1]]; _child setVariable [QGVAR(DeletedEHID), -1]; }; diff --git a/addons/towing/functions/fnc_detachRope.sqf b/addons/towing/functions/fnc_detachRope.sqf index 4030649e06c..8baed5532d8 100644 --- a/addons/towing/functions/fnc_detachRope.sqf +++ b/addons/towing/functions/fnc_detachRope.sqf @@ -26,15 +26,12 @@ if (isNil "_hookVars") then { // this is hookParent _hookVars params ["_parent", "_child", "_rope", "_ropeClass", "_hookParent"]; -TRACE_7("detachRope",_unit,_parent,_child,_hook,_hookParent,_rope,_deletedObject); +TRACE_8("detachRope",_unit,_parent,_child,_hook,_hookParent,_rope,_ropeClass,_deletedObject); ropeDestroy _rope; // can run on client -if (!isNull _unit) then { - TRACE_1("rope",_ropeClass); - if (!isNull _unit && {_ropeClass isNotEqualTo ""}) then { - [_unit, _ropeClass, true] call CBA_fnc_addItem; - }; +if (!isNull _unit && {_ropeClass isNotEqualTo ""}) then { + [_unit, _ropeClass, true] call CBA_fnc_addItem; }; { diff --git a/addons/towing/functions/fnc_getDetachActions.sqf b/addons/towing/functions/fnc_getDetachActions.sqf index 2123aadf67a..4f86220797c 100644 --- a/addons/towing/functions/fnc_getDetachActions.sqf +++ b/addons/towing/functions/fnc_getDetachActions.sqf @@ -27,7 +27,7 @@ private _childHooks = _vehicle getVariable [QGVAR(childHooks), []]; (_parentHooks + _childHooks) apply { private _hook = _x; _hook getVariable QGVAR(vars) params ["_hookParent", "_hookChild"]; - private _partner = if (_vehicle == _hookParent) then {_hookChild} else {_hookParent}; + private _partner = [_hookParent, _hookChild] select (_vehicle == _hookParent); private _partnerName = getText (configOf _partner >> "displayName"); private _partnerOwnerName = [_partner, true] call EFUNC(common,getName); if (_partnerOwnerName != "") then { diff --git a/addons/towing/functions/fnc_towStateMachinePFH.sqf b/addons/towing/functions/fnc_towStateMachinePFH.sqf index dcc1467aecc..25d91e932cb 100644 --- a/addons/towing/functions/fnc_towStateMachinePFH.sqf +++ b/addons/towing/functions/fnc_towStateMachinePFH.sqf @@ -43,8 +43,8 @@ switch (_state) do { // can't use unit hand because rope doesn't change position when hand moving // can't use createVehicleLocal because rope can be non-local (like parent) and it must be attached to global vehicle GVAR(helper) = createVehicle [QGVAR(helper), [0, 0, 0], [], 0, "CAN_COLLIDE"]; - GVAR(helper) attachTo [_unit, [0,0,0], "LeftHand", true]; - _rope = ropeCreate [_parent, _parent worldToModelVisual ASLtoAGL getPosASLVisual GVAR(attachHelper), GVAR(helper), [0,0,0], _length]; + GVAR(helper) attachTo [_unit, [0, 0, 0], "LeftHand", true]; + _rope = ropeCreate [_parent, _parent worldToModelVisual ASLtoAGL getPosASLVisual GVAR(attachHelper), GVAR(helper), [0, 0, 0], _length]; _args set [3, _rope]; };