Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Towing - Fix some issues #9007

Merged
merged 23 commits into from
Feb 5, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
0394bcf
Fix rope attachment on menu click
Dystopian Aug 19, 2022
436ed12
Add multiple towing
Dystopian Aug 24, 2022
784355c
Add JIP support
Dystopian Aug 27, 2022
d5e3198
Replace hook model, add helper object
Dystopian Aug 28, 2022
4310dfa
Add parent hook
Dystopian Aug 28, 2022
4381198
Decrease public setVar count
Dystopian Aug 28, 2022
3e9b821
Fix double cleanup after Deleted EH
Dystopian Aug 28, 2022
9dc8ded
Cleanup
Dystopian Aug 29, 2022
c118b01
Merge remote-tracking branch 'upstream/master' into towing-fix-attach…
Dystopian Aug 29, 2022
54d842f
Add detach actions to vehicles
Dystopian Nov 3, 2022
0565947
Disable helicopters towing
Dystopian Nov 3, 2022
ddf8b56
Add rope to ships
Dystopian Nov 4, 2022
9f5ed64
Merge branch 'master' into towing-fix-attach-on-click
Dystopian Jun 23, 2023
42c0cd4
Merge remote-tracking branch 'upstream/master' into towing-fix-attach…
Dystopian Sep 11, 2023
81eb091
Merge branch 'towing-fix-attach-on-click' of github.com:Dystopian/ACE…
Dystopian Sep 11, 2023
9feaa72
Cleanup postInit assignments
Dystopian Sep 15, 2023
7423ce0
Merge remote-tracking branch 'upstream/master' into towing-fix-attach…
Dystopian Sep 16, 2023
ec35e15
Fix interaction with dead vehicle
Dystopian Sep 23, 2023
323dd43
Apply suggestions from code review and Fix useless isNull check
Dystopian Nov 5, 2023
ae0616f
Merge branch 'master' into towing-fix-attach-on-click
Dystopian Nov 5, 2023
f993822
Merge branch 'master' into towing-fix-attach-on-click
Dystopian Nov 20, 2023
597b772
Merge remote-tracking branch 'upstream/master' into pr/Dystopian/9007
LinkIsGrim Feb 4, 2024
ec04b3c
Merge remote-tracking branch 'upstream/master' into pr/Dystopian/9007
LinkIsGrim Feb 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 39 additions & 62 deletions addons/towing/CfgVehicles.hpp
Original file line number Diff line number Diff line change
@@ -1,84 +1,61 @@
#define TOW_ACTION \
class ACE_Actions {\
class ACE_MainActions {\
class ADDON {\
displayName = CSTRING(displayName);\
distance = TOW_ACTION_DISTANCE;\
condition = QUOTE([ARR_1(_target)] call FUNC(isSuitableSimulation));\
statement = "";\
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));\
#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(_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;
class Car: LandVehicle {
TOW_ACTION;
TOW_ACTIONS;
};

class Tank: LandVehicle {
TOW_ACTION;
TOW_ACTIONS;
};

class Ship;
class Ship_F: Ship {
TOW_ACTIONS;
};

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);
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));
distance = 2;
statement = QUOTE([ARR_2(_player,_target)] call DFUNC(detachRope));
distance = TOW_ACTION_DISTANCE;
};
};
};
Expand Down
6 changes: 4 additions & 2 deletions addons/towing/XEH_PREP.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
PREP(addRopeToVehicle);
PREP(attachRopePFH);
PREP(canStartTow);
PREP(detach);
PREP(attachVehicles);
PREP(detachChild);
PREP(detachRope);
PREP(getDetachActions);
PREP(isSuitableSimulation);
PREP(onMouseButtonDown);
PREP(onMouseButtonUp);
Expand Down
36 changes: 32 additions & 4 deletions addons/towing/XEH_postInit.sqf
Original file line number Diff line number Diff line change
@@ -1,14 +1,42 @@
#include "script_component.hpp"
["MouseButtonDown", LINKFUNC(onMouseButtonDown)] call CBA_fnc_addDisplayHandler;

["MouseButtonUp", LINKFUNC(onMouseButtonUp)] call CBA_fnc_addDisplayHandler;
GVAR(mouseLeft) = false;
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;

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;
}];
16 changes: 16 additions & 0 deletions addons/towing/XEH_preInit.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,20 @@ PREP_RECOMPILE_END;

#include "initSettings.sqf"

// 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;
26 changes: 22 additions & 4 deletions addons/towing/functions/fnc_attachRopePFH.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -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 which has parent != _ignoreParent
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);

Expand Down Expand Up @@ -76,4 +95,3 @@ if (_hint isNotEqualTo (_unit getVariable [QGVAR(hint), []])) then {
_unit setVariable [QGVAR(hint), _hint];
_hint call EFUNC(interaction,showMouseHint);
};

65 changes: 65 additions & 0 deletions addons/towing/functions/fnc_attachVehicles.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#include "script_component.hpp"
/*
* Author: Dystopian
* Attaches child to parent vehicle.
* Run globally.
Copy link
Contributor

@rautamiekka rautamiekka Jun 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be much better if the fnc did the 'Run globally' parts for themselves automatically.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't get you. Do you mean I should replace one global event and one function with 3 events and its own functions (1 for parent owner, 1 global setTowParent run and 1 for server)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean the script is changed to Must be run on the server and the Server runs it globally, otherwise remoteExeced.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still can't understand how it could be better to move script executing to server and split 1 global event to 3 events (1 of those is global anyway) and functions. In any case we have to run globally setTowParent part. I don't see any profit from function splitting.

*
* Arguments:
* 0: Vehicle to tow from <OBJECT>
* 1: Vehicle to tow <OBJECT>
* 2: Rope End Position <ARRAY>
* 3: Rope <OBJECT>
* 4: Attached Helper Object <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];
GVAR(allChildren) pushBack _child;

{
if (-1 == _x getVariable [QGVAR(DeletedEHID), -1]) then {
_x setVariable [QGVAR(DeletedEHID), _x addEventHandler ["Deleted", {
params ["_entity"];
private _childHooks = _entity getVariable [QGVAR(childHooks), []];
private _parentHooks = _entity getVariable [QGVAR(parentHooks), []];
TRACE_3("Deleted EH",_entity,_childHooks,_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];

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(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);
}]];
};
21 changes: 0 additions & 21 deletions addons/towing/functions/fnc_canStartTow.sqf

This file was deleted.

48 changes: 0 additions & 48 deletions addons/towing/functions/fnc_detach.sqf

This file was deleted.

Loading