From f65f6e9b729ed3462bbf1e8ab70adbd099e52004 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Sun, 27 Sep 2015 17:19:40 +0100 Subject: [PATCH] Add support for virtual cargo Allows cargo objects to be added via classname and reduces simulation/synchronization overhead. Objects become physical upon unloading and cannot be re-made virtual, only scripts can add such virtual objects. Also separates the player feedback from the loading/unloading code and adds a progress bar. --- addons/cargo/XEH_postInit.sqf | 44 ++++++++++++++++++- addons/cargo/functions/fnc_addCargoItem.sqf | 17 ++----- addons/cargo/functions/fnc_canLoadItemIn.sqf | 24 +++++++--- addons/cargo/functions/fnc_canUnloadItem.sqf | 9 ++-- addons/cargo/functions/fnc_getSizeItem.sqf | 22 +++++++--- .../cargo/functions/fnc_handleDestroyed.sqf | 9 ++-- addons/cargo/functions/fnc_loadItem.sqf | 25 ++++------- addons/cargo/functions/fnc_onMenuOpen.sqf | 5 ++- addons/cargo/functions/fnc_startLoadIn.sqf | 21 ++++++--- addons/cargo/functions/fnc_startUnload.sqf | 17 ++++++- addons/cargo/functions/fnc_unloadItem.sqf | 38 +++++++--------- .../functions/fnc_validateCargoSpace.sqf | 4 +- addons/cargo/stringtable.xml | 12 +++++ 13 files changed, 159 insertions(+), 88 deletions(-) diff --git a/addons/cargo/XEH_postInit.sqf b/addons/cargo/XEH_postInit.sqf index 6501044c9d..2aeb3ab630 100644 --- a/addons/cargo/XEH_postInit.sqf +++ b/addons/cargo/XEH_postInit.sqf @@ -1,5 +1,45 @@ #include "script_component.hpp" -["LoadCargo", {_this call FUNC(loadItem)}] call EFUNC(common,addEventHandler); -["UnloadCargo", {_this call FUNC(unloadItem)}] call EFUNC(common,addEventHandler); ["AddCargoByClass", {_this call FUNC(addCargoItem)}] call EFUNC(common,addEventHandler); + +["LoadCargo", { + (_this select 0) params ["_item","_vehicle"]; + private ["_loaded", "_hint", "_itemName", "_vehicleName"]; + + _loaded = [_item, _vehicle] call FUNC(loadItem); + + // Show hint as feedback + _hint = [LSTRING(LoadingFailed), LSTRING(LoadedItem)] select _loaded; + _itemName = getText (configFile >> "CfgVehicles" >> typeOf _item >> "displayName"); + _vehicleName = getText (configFile >> "CfgVehicles" >> typeOf _vehicle >> "displayName"); + + ["displayTextStructured", [[_hint, _itemName, _vehicleName], 3.0]] call EFUNC(common,localEvent); + + if (_loaded) then { + // Invoke listenable event + ["cargoLoaded", [_item, _vehicle]] call EFUNC(common,globalEvent); + }; +}] call EFUNC(common,addEventHandler); + +["UnloadCargo", { + (_this select 0) params ["_item","_vehicle"]; + private ["_unloaded", "_itemClass", "_hint", "_itemName", "_vehicleName"]; + + _unloaded = [_item, _vehicle] call FUNC(unloadItem); + + _itemClass = if (typeName _item == "STRING") then {_item} else {typeOf _item}; + + // Show hint as feedback + _hint = [LSTRING(UnloadingFailed), LSTRING(UnloadedItem)] select _unloaded; + _itemName = getText (configFile >> "CfgVehicles" >> _itemClass >> "displayName"); + _vehicleName = getText (configFile >> "CfgVehicles" >> typeOf _vehicle >> "displayName"); + + ["displayTextStructured", [[_hint, _itemName, _vehicleName], 3.0]] call EFUNC(common,localEvent); + + if (_unloaded) then { + // Invoke listenable event + ["cargoUnloaded", [_item, _vehicle]] call EFUNC(common,globalEvent); + }; + + // TOOO maybe drag/carry the unloaded item? +}] call EFUNC(common,addEventHandler); diff --git a/addons/cargo/functions/fnc_addCargoItem.sqf b/addons/cargo/functions/fnc_addCargoItem.sqf index 1233d0228d..f3282d7718 100644 --- a/addons/cargo/functions/fnc_addCargoItem.sqf +++ b/addons/cargo/functions/fnc_addCargoItem.sqf @@ -21,18 +21,9 @@ private ["_position", "_item", "_i"]; params ["_itemClass", "_vehicle", ["_amount", 1]]; TRACE_3("params",_itemClass,_vehicle,_amount); -_position = getPos _vehicle; -_position set [1, (_position select 1) + 1]; -_position set [2, (_position select 2) + 7.5]; - for "_i" from 1 to _amount do { - _item = createVehicle [_itemClass, _position, [], 0, "CAN_COLLIDE"]; - - // Load item or delete it if no space left - if !([_item, _vehicle] call FUNC(loadItem)) exitWith { - deleteVehicle _item; - }; - - // Invoke listenable event - ["cargoAddedByClass", [_itemClass, _vehicle, _amount]] call EFUNC(common,globalEvent); + [_item, _vehicle] call FUNC(loadItem); }; + +// Invoke listenable event +["cargoAddedByClass", [_itemClass, _vehicle, _amount]] call EFUNC(common,globalEvent); diff --git a/addons/cargo/functions/fnc_canLoadItemIn.sqf b/addons/cargo/functions/fnc_canLoadItemIn.sqf index 8cfe9e194b..fda60aaf65 100644 --- a/addons/cargo/functions/fnc_canLoadItemIn.sqf +++ b/addons/cargo/functions/fnc_canLoadItemIn.sqf @@ -3,7 +3,7 @@ * Check if item can be loaded into other Object. * * Arguments: - * 0: Item Object + * 0: Item * 1: Holder Object (Vehicle) * * Return value: @@ -16,14 +16,24 @@ */ #include "script_component.hpp" -params ["_item", "_vehicle"]; +params [["_item", "", [objNull,""]], "_vehicle"]; if (speed _vehicle > 1 || (((getPos _vehicle) select 2) > 3)) exitWith {false}; -private "_itemSize"; -_itemSize = ([_item] call FUNC(getSizeItem)); +private ["_itemSize", "_validItem"]; +_itemSize = [_item] call FUNC(getSizeItem); -(_itemSize > 0) && -{alive _item && alive _vehicle} && -{(_item distance _vehicle <= MAX_LOAD_DISTANCE)} && +if (typeName _item == "STRING") then { + _validItem = + isClass (configFile >> "CfgVehicles" >> _item) && + {getNumber (configFile >> "CfgVehicles" >> _item >> QGVAR(canLoad)) == 1}; +} else { + _validItem = + (alive _item) && + {(_item distance _vehicle) <= MAX_LOAD_DISTANCE}; +}; + +_validItem && +{_itemSize > 0} && +{alive _vehicle} && {_itemSize <= ([_vehicle] call FUNC(getCargoSpaceLeft))} diff --git a/addons/cargo/functions/fnc_canUnloadItem.sqf b/addons/cargo/functions/fnc_canUnloadItem.sqf index 779a7533a9..8c741a5448 100644 --- a/addons/cargo/functions/fnc_canUnloadItem.sqf +++ b/addons/cargo/functions/fnc_canUnloadItem.sqf @@ -16,18 +16,19 @@ */ #include "script_component.hpp" -private ["_loaded", "_validVehiclestate", "_emptyPos"]; - params ["_item", "_vehicle"]; +private ["_loaded", "_itemClass", "_validVehiclestate", "_emptyPos"]; _loaded = _vehicle getVariable [QGVAR(loaded), []]; if !(_item in _loaded) exitWith {false}; +_itemClass = if (typeName _item == "STRING") then {_item} else {typeOf _item}; + _validVehiclestate = true; _emptyPos = []; if (_vehicle isKindOf "Ship" ) then { if !(speed _vehicle <1 && {(((getPosATL _vehicle) select 2) < 2)}) then {_validVehiclestate = false}; - _emptyPos = ((getPosASL _vehicle) call EFUNC(common,ASLtoPosition) findEmptyPosition [0, 15, typeOf _item]); // TODO: if spot is underwater pick another spot. + _emptyPos = ((getPosASL _vehicle) call EFUNC(common,ASLtoPosition) findEmptyPosition [0, 15, _itemClass]); // TODO: if spot is underwater pick another spot. } else { if (_vehicle isKindOf "Air" ) then { if !(speed _vehicle <1 && {isTouchingGround _vehicle}) then {_validVehiclestate = false}; @@ -35,7 +36,7 @@ if (_vehicle isKindOf "Ship" ) then { _emptyPos = [(_emptyPos select 0) + random(5), (_emptyPos select 1) + random(5), _emptyPos select 2 ]; } else { if !(speed _vehicle <1 && {(((getPosATL _vehicle) select 2) < 2)}) then {_validVehiclestate = false}; - _emptyPos = ((getPosASL _vehicle) call EFUNC(common,ASLtoPosition) findEmptyPosition [0, 15, typeOf _item]); + _emptyPos = ((getPosASL _vehicle) call EFUNC(common,ASLtoPosition) findEmptyPosition [0, 15, _itemClass]); }; }; diff --git a/addons/cargo/functions/fnc_getSizeItem.sqf b/addons/cargo/functions/fnc_getSizeItem.sqf index dacd6a4982..807251365c 100644 --- a/addons/cargo/functions/fnc_getSizeItem.sqf +++ b/addons/cargo/functions/fnc_getSizeItem.sqf @@ -3,7 +3,7 @@ * Get the cargo size of an object. * * Arguments: - * 0: Object + * 0: Item * * Return value: * Cargo size (default: -1) @@ -15,14 +15,24 @@ */ #include "script_component.hpp" -private "_config"; - params ["_item"]; +private ["_isVirtual","_itemClass","_config"]; +scopeName "return"; -_config = (configFile >> "CfgVehicles" >> typeOf _item >> QGVAR(size)); +_isVirtual = (typeName _item == "STRING"); +_itemClass = if (_isVirtual) then {_item} else {typeOf _item}; +_config = (configFile >> "CfgVehicles" >> _itemClass >> QGVAR(size)); -if (isNumber (_config)) exitWith { - _item getVariable [QGVAR(size), getNumber (_config)] +if (_isVirtual) then { + if (isNumber _config) then { + (getNumber _config) breakOut "return"; + }; +} else { + _config = (configFile >> "CfgVehicles" >> typeOf _item >> QGVAR(size)); + + if (isNumber _config) then { + (_item getVariable [QGVAR(size), getNumber _config]) breakOut "return"; + }; }; -1 diff --git a/addons/cargo/functions/fnc_handleDestroyed.sqf b/addons/cargo/functions/fnc_handleDestroyed.sqf index c11dd3bfad..1022497719 100644 --- a/addons/cargo/functions/fnc_handleDestroyed.sqf +++ b/addons/cargo/functions/fnc_handleDestroyed.sqf @@ -20,12 +20,13 @@ params ["_vehicle"]; private["_loaded"]; _loaded = _vehicle getVariable [QGVAR(loaded), []]; -if (count _loaded == 0) exitWith {}; +if (_loaded isEqualTo []) exitWith {}; { - // TODO deleteVehicle or just delete vehicle? Do we want to be able to recover destroyed equipment? - deleteVehicle _x; - //_x setDamage 1; + // TODO Do we want to be able to recover destroyed equipment? + if (typeName _x == "OBJECT") then { + deleteVehicle _x; + }; } count _loaded; [_vehicle] call FUNC(validateCargoSpace); diff --git a/addons/cargo/functions/fnc_loadItem.sqf b/addons/cargo/functions/fnc_loadItem.sqf index 3c79604a04..5f519476ef 100644 --- a/addons/cargo/functions/fnc_loadItem.sqf +++ b/addons/cargo/functions/fnc_loadItem.sqf @@ -1,9 +1,10 @@ /* * Author: Glowbal * Load object into vehicle. + * Objects loaded via classname remain virtual until unloaded. * * Arguments: - * 0: Object + * 0: Item * 1: Vehicle * * Return value: @@ -16,10 +17,9 @@ */ #include "script_component.hpp" +params [["_item","",[objNull,""]], ["_vehicle",objNull,[objNull]]]; private ["_loaded", "_space", "_itemSize"]; -params ["_item", "_vehicle"]; - if !([_item, _vehicle] call FUNC(canLoadItemIn)) exitWith {false}; _loaded = _vehicle getVariable [QGVAR(loaded), []]; @@ -30,19 +30,10 @@ _space = [_vehicle] call FUNC(getCargoSpaceLeft); _itemSize = [_item] call FUNC(getSizeItem); _vehicle setVariable [QGVAR(space), _space - _itemSize, true]; -detach _item; -_item attachTo [_vehicle,[0,0,100]]; -["hideObjectGlobal", [_item, true]] call EFUNC(common,serverEvent); - -// show hint -private ["_itemName", "_vehicleName"]; - -_itemName = getText (configFile >> "CfgVehicles" >> typeOf _item >> "displayName"); -_vehicleName = getText (configFile >> "CfgVehicles" >> typeOf _vehicle >> "displayName"); - -["displayTextStructured", [[localize LSTRING(LoadedItem), _itemName, _vehicleName], 3.0]] call EFUNC(common,localEvent); - -// Invoke listenable event -["cargoLoaded", [_item, _vehicle]] call EFUNC(common,globalEvent); +if (typeName _item == "OBJECT") then { + detach _item; + _item attachTo [_vehicle,[0,0,-100]]; + ["hideObjectGlobal", [_item, true]] call EFUNC(common,serverEvent); +}; true diff --git a/addons/cargo/functions/fnc_onMenuOpen.sqf b/addons/cargo/functions/fnc_onMenuOpen.sqf index 031bea01cc..85557835bf 100644 --- a/addons/cargo/functions/fnc_onMenuOpen.sqf +++ b/addons/cargo/functions/fnc_onMenuOpen.sqf @@ -22,7 +22,7 @@ params ["_display"]; uiNamespace setVariable [QGVAR(menuDisplay), _display]; [{ - private ["_display","_loaded", "_ctrl", "_label"]; + private ["_display","_loaded", "_ctrl", "_class", "_label"]; disableSerialization; _display = uiNamespace getVariable QGVAR(menuDisplay); if (isnil "_display") exitWith { @@ -40,7 +40,8 @@ uiNamespace setVariable [QGVAR(menuDisplay), _display]; lbClear _ctrl; { - _ctrl lbAdd (getText(configfile >> "CfgVehicles" >> typeOf _x >> "displayName")); + _class = if (typeName _x == "STRING") then {_x} else {typeOf _x}; + _ctrl lbAdd (getText(configfile >> "CfgVehicles" >> _class >> "displayName")); true } count _loaded; diff --git a/addons/cargo/functions/fnc_startLoadIn.sqf b/addons/cargo/functions/fnc_startLoadIn.sqf index b4ba50fbb6..1ce5d62407 100644 --- a/addons/cargo/functions/fnc_startLoadIn.sqf +++ b/addons/cargo/functions/fnc_startLoadIn.sqf @@ -16,16 +16,25 @@ #include "script_component.hpp" params ["_player", "_object"]; +private ["_vehicle", "_size", "_displayName"]; -private ["_nearestVehicle"]; -_nearestVehicle = [_player] call FUNC(findNearestVehicle); +_vehicle = [_player] call FUNC(findNearestVehicle); -if (isNull _nearestVehicle || _nearestVehicle isKindOf "Cargo_Base_F") then { +if (isNull _vehicle || _vehicle isKindOf "Cargo_Base_F") then { { - if ([_object, _x] call FUNC(canLoadItemIn)) exitWith {_nearestVehicle = _x}; + if ([_object, _x] call FUNC(canLoadItemIn)) exitWith {_vehicle = _x}; } foreach (nearestObjects [_player, ["Cargo_base_F", "Land_PaperBox_closed_F"], MAX_LOAD_DISTANCE]); }; -if (isNull _nearestVehicle) exitWith {false}; +if (isNull _vehicle) exitWith {false}; -[_object, _nearestVehicle] call FUNC(loadItem) +// Start progress bar +if ([_object, _vehicle] call FUNC(canLoadItemIn)) then { + _size = [_object] call FUNC(getSizeItem); + + [5 * _size, [_object,_vehicle], "LoadCargo", {}, localize LSTRING(LoadingItem)] call EFUNC(common,progressBar); +} else { + _displayName = getText (configFile >> "CfgVehicles" >> typeOf _object >> "displayName"); + + ["displayTextStructured", [[LSTRING(LoadingFailed), _displayName], 3.0]] call EFUNC(common,localEvent); +}; diff --git a/addons/cargo/functions/fnc_startUnload.sqf b/addons/cargo/functions/fnc_startUnload.sqf index 28ae034167..013de1dc64 100644 --- a/addons/cargo/functions/fnc_startUnload.sqf +++ b/addons/cargo/functions/fnc_startUnload.sqf @@ -20,7 +20,7 @@ private ["_display", "_loaded", "_ctrl", "_selected", "_item"]; disableSerialization; _display = uiNamespace getVariable QGVAR(menuDisplay); -if (isnil "_display") exitWith {}; +if (isNil "_display") exitWith {}; _loaded = GVAR(interactionVehicle) getVariable [QGVAR(loaded), []]; if (count _loaded == 0) exitWith {}; @@ -32,4 +32,17 @@ _selected = (lbCurSel _ctrl) max 0; if (count _loaded <= _selected) exitWith {}; _item = _loaded select _selected; -[_item, GVAR(interactionVehicle)] call FUNC(unloadItem); + +// Start progress bar +private ["_size", "_itemClass", "_displayName"]; + +if ([_item, GVAR(interactionVehicle)] call FUNC(canUnloadItem)) then { + _size = [_item] call FUNC(getSizeItem); + + [5 * _size, [_item, GVAR(interactionVehicle)], "UnloadCargo", {}, localize LSTRING(UnloadingItem)] call EFUNC(common,progressBar); +} else { + _itemClass = if (typeName _item == "STRING") then {_item} else {typeOf _item}; + _displayName = getText (configFile >> "CfgVehicles" >> _itemClass >> "displayName"); + + ["displayTextStructured", [[LSTRING(UnloadingFailed), _displayName], 3.0]] call EFUNC(common,localEvent); +}; diff --git a/addons/cargo/functions/fnc_unloadItem.sqf b/addons/cargo/functions/fnc_unloadItem.sqf index 2630f2104a..81cca7154b 100644 --- a/addons/cargo/functions/fnc_unloadItem.sqf +++ b/addons/cargo/functions/fnc_unloadItem.sqf @@ -3,7 +3,7 @@ * Unload object from vehicle. * * Arguments: - * 0: Object + * 0: Item * 1: Vehicle * * Return value: @@ -16,20 +16,21 @@ */ #include "script_component.hpp" -private ["_loaded", "_space", "_itemSize", "_emptyPos", "_validVehiclestate"]; - params ["_item", "_vehicle"]; +private ["_loaded", "_space", "_itemSize", "_emptyPos", "_validVehiclestate"]; if !([_item, _vehicle] call FUNC(canUnloadItem)) exitWith { false }; +_itemClass = if (typeName _item == "STRING") then {_item} else {typeOf _item}; + _validVehiclestate = true; _emptyPos = []; if (_vehicle isKindOf "Ship" ) then { if !(speed _vehicle <1 && {(((getPosATL _vehicle) select 2) < 2)}) then {_validVehiclestate = false}; TRACE_1("SHIP Ground Check", getPosATL _vehicle ); - _emptyPos = ((getPosASL _vehicle) call EFUNC(common,ASLtoPosition) findEmptyPosition [0, 15, typeOf _item]); // TODO: if spot is underwater pick another spot. + _emptyPos = ((getPosASL _vehicle) call EFUNC(common,ASLtoPosition) findEmptyPosition [0, 15, _itemClass]); // TODO: if spot is underwater pick another spot. } else { if (_vehicle isKindOf "Air" ) then { if !(speed _vehicle <1 && {isTouchingGround _vehicle}) then {_validVehiclestate = false}; @@ -39,38 +40,29 @@ if (_vehicle isKindOf "Ship" ) then { } else { if !(speed _vehicle <1 && {(((getPosATL _vehicle) select 2) < 2)}) then {_validVehiclestate = false}; TRACE_1("Vehicle Ground Check", isTouchingGround _vehicle); - _emptyPos = ((getPosASL _vehicle) call EFUNC(common,ASLtoPosition) findEmptyPosition [0, 13, typeOf _item]); + _emptyPos = ((getPosASL _vehicle) call EFUNC(common,ASLtoPosition) findEmptyPosition [0, 13, _itemClass]); }; }; TRACE_1("getPosASL Vehicle Check", getPosASL _vehicle); if (!_validVehiclestate) exitWith {false}; -if (count _emptyPos == 0) exitWith {false}; //consider displaying text saying there are no safe places to exit the vehicle +if (count _emptyPos == 0) exitWith {false}; _loaded = _vehicle getVariable [QGVAR(loaded), []]; -_loaded = _loaded - [_item]; +_loaded deleteAt (_loaded find _item); _vehicle setVariable [QGVAR(loaded), _loaded, true]; _space = [_vehicle] call FUNC(getCargoSpaceLeft); _itemSize = [_item] call FUNC(getSizeItem); _vehicle setVariable [QGVAR(space), (_space + _itemSize), true]; -detach _item; -_item setPosASL (_emptyPos call EFUNC(common,PositiontoASL)); -["hideObjectGlobal", [_item, false]] call EFUNC(common,serverEvent); - -// show hint -private ["_itemName", "_vehicleName"]; - -_itemName = getText (configFile >> "CfgVehicles" >> typeOf _item >> "displayName"); -_vehicleName = getText (configFile >> "CfgVehicles" >> typeOf _vehicle >> "displayName"); - -["displayTextStructured", [[localize LSTRING(UnloadedItem), _itemName, _vehicleName], 3.0]] call EFUNC(common,localEvent); - -// TOOO maybe drag/carry the unloaded item? - -// Invoke listenable event -["cargoUnloaded", [_item, _vehicle]] call EFUNC(common,globalEvent); +if (typeName _item == "OBJECT") then { + detach _item; + _item setPosASL (_emptyPos call EFUNC(common,PositiontoASL)); + ["hideObjectGlobal", [_item, false]] call EFUNC(common,serverEvent); +} else { + createVehicle [_item, _emptyPos, [], 0, ""]; +}; true diff --git a/addons/cargo/functions/fnc_validateCargoSpace.sqf b/addons/cargo/functions/fnc_validateCargoSpace.sqf index 6caf664ca5..7634b131e6 100644 --- a/addons/cargo/functions/fnc_validateCargoSpace.sqf +++ b/addons/cargo/functions/fnc_validateCargoSpace.sqf @@ -24,7 +24,7 @@ _loaded = _vehicle getVariable [QGVAR(loaded), []]; _newLoaded = []; _totalSpaceOccupied = 0; { - if !(isNull _x) then { + if ((typeName _x == "STRING") || {!isNull _x}) then { _newLoaded pushback _x; _totalSpaceOccupied = _totalSpaceOccupied + ([_x] call FUNC(getSizeItem)); }; @@ -35,4 +35,4 @@ if (count _loaded != count _newLoaded) then { _vehicle setVariable [QGVAR(loaded), _newLoaded, true]; }; -_vehicle setVariable [QGVAR(space), getNumber (configFile >> "CfgVehicles" >> typeof _vehicle >> QGVAR(space)) - _totalSpaceOccupied, true]; +_vehicle setVariable [QGVAR(space), getNumber (configFile >> "CfgVehicles" >> typeOf _vehicle >> QGVAR(space)) - _totalSpaceOccupied, true]; diff --git a/addons/cargo/stringtable.xml b/addons/cargo/stringtable.xml index 7f9ac40a15..6902a1aae1 100644 --- a/addons/cargo/stringtable.xml +++ b/addons/cargo/stringtable.xml @@ -95,5 +95,17 @@ 1%<br/>kirakodva ebből:<br/>%2 %1<br/>разгружен из<br/>%2 + + Loading Cargo + + + Unloading Cargo + + + %1<br/>could not be loaded + + + %1<br/>could not be unloaded +