Support #19453

How to get access to RUCK variables after onPlayerDisconnectd?

Added by tolko_download over 4 years ago. Updated about 4 years ago.

Status:Closed Start date:05/04/2011
Priority:Normal Due date:
Assignee:tcp % Done:

100%

Category:Script
Target version:-
Component:sys_ruck Affected Version:
Close Reason:

Description

ArmA II: CO 1.59.76900
ACE Build 484

I'm making saving system and I need to save player's stuff into server global variables. I can save almost all stuf but ACE's weapon on back and ruck inventory. Simple code called via

y1 - name of testing unit

onPlayerDisconnected "diag_log format[""fnc_StoreSave called via onPlayerDisconnected, _id=%1, _name=%2"", _id, _name]; [y1] call fnc_DB_SaveState;";

and fnc_DB_SaveState begins to store inventory data

...
_Store_PlayerHasRuck = false;
_Store_RuckMagazines = [];
_Store_RuckWeapons = [];
_Store_Stored = true;

if (_unit call ACE_fnc_HasRuck) then
{
    _Store_PlayerHasRuck = true;
    _Store_RuckMagazines = [_unit] call ACE_fnc_RuckMagazinesList;
    _Store_RuckWeapons = [_unit] call ACE_fnc_RuckWeaponsList;
};

_Store_BackWeapon = [_unit] call ACE_fnc_WeaponOnBackName;
_Store_Weapons = weapons _unit;
_Store_Magazines = magazines _unit;
...

// diag block
diag_log "-----------SAVE DATA------------";
diag_log format["_unit=%1, _Store_Weapons=%2, _Store_Magazines=%3, _Store_PlayerHasRuck=%4, _Store_RuckWeapons=%5, _Store_RuckMagazines=%6, _Store_BackWeapon=%7, _Store_Stored=%8", _unit, _Store_Weapons, _Store_Magazines, _Store_PlayerHasRuck, _Store_RuckWeapons, _Store_RuckMagazines, _Store_BackWeapon, _Store_Stored];

As result of that dubug code I have:

"_unit=y1, _Store_Weapons=["ACE_AK105_Kobra","Binocular","NVGoggles","MakarovSD","ItemGPS","ItemMap","ItemCompass","ItemWatch","ItemRadio"], _Store_Magazines=["30Rnd_545x39_AK","30Rnd_545x39_AK","30Rnd_545x39_AK","30Rnd_545x39_AK","30Rnd_545x39_AK","30Rnd_545x39_AK","HandGrenade_East","HandGrenade_East","SmokeShell","SmokeShellBlue","SmokeShellOrange","8Rnd_9x18_MakarovSD","8Rnd_9x18_MakarovSD","8Rnd_9x18_MakarovSD","8Rnd_9x18_MakarovSD","ACE_Bandage","ACE_Bandage","ACE_Morphine","ACE_Morphine","ACE_Epinephrine","ACE_Epinephrine"], _Store_PlayerHasRuck=false, _Store_RuckWeapons=[], _Store_RuckMagazines=[], _Store_BackWeapon=, _Store_Stored=true" 

There are no weapon on back and ammo/weapon classe in the ruck:

_Store_PlayerHasRuck=false (actualy it exists)
_Store_RuckWeapons=[] (too)
_Store_RuckMagazines=[] (too)
_Store_BackWeapon= (and too)

When I run listenserver or editor it works fine, those variable are initialized with classes, but in dedicated mode I have no values.

What am I doing wrong? I need that vars to save staff after exit)

History

Updated by tolko_download over 4 years ago

_unit call ACE_fnc_HasRuck

returns FALSE, but if I call fnc_DB_SaveState in the middle of the game via Debug Console:
[y1] call fnc_DB_SaveState; [y1] call fnc_DB_RestoreState;

it works fine.

Forcing RUCK checking with TRUE values doesn't help.

So I think the problem is in disconnecting process or event that causes this behaviour of ruck API. Any ideas?

Updated by Sickboy over 4 years ago

  • Status changed from New to Feedback
  • Assignee set to tcp

Ruck variables are only maintained where the unit is local.
Afaik rucks are dropped to the ground when the unit dies, and from there you can access it I guess.

Updated by tolko_download over 4 years ago

Hmmmm. And what about additional slot on the back? Can not get access to it.

Updated by Sickboy over 4 years ago

Doesn't drop the ground also?

Updated by tcp over 4 years ago

Yes, Sickboy has given all the right info. Since all variables are stored on the local client, you need to test if the ruck and WOB drop script has time to run before the player disconnects. If it does, than you need to write a client event (I use onKilled) that transmits the ruck and WOB stuff to the server. If it does not, which is probably the case, then you need to save their gear ahead of time, like every 5 minutes.

Why do you need the loadout of disconnected players? Do you want to restore it when they reconnect?

Updated by tolko_download over 4 years ago

Good day/night dear devs!

Sickboy
I'm begining to tests now) Was at work :)

tcp
Will onKilled work if client will be disconnected abormally? Like game crash or just will lost connection, or be kicked (for example by admin or BattlEye) I think will not :)

Yep. I'm making restore system for saving player state after disconnect and maybe if server needs full restart (like in City Life RPG 2). I want to make big multisession mission, but now at least need to save loadout for disconnected players :)

Ok. I'm starting...

Updated by tolko_download over 4 years ago

Ok. I've complete some tests and got results.

As I said above onKilled event cannot be executed if client drops connection or getting random game crash. I special tried to simulate it.

Sickboy, I cant find dropped ruck and weapon on the ground if client disconnected (but if he's died in the game I can find it). There is simple code demonstrates it:

y1 - name of testing unit

initServer.sqf

// Searching nearest object for disconnected player in 2 m range
onPlayerDisconnected "_nObjects = (nearestObjects [y1, [], 2]); diag_log format[""%1"", _nObjects];";

arma2oaserver.RPT

"[y1]" 

:)

I think grandfather's method (In Russia we're calling "Grandfather's method" old things with simple, reliable but not best solutions :)) by tcp will work. Server in saving loop will retrieve client data and write or it will make client loop every N minutes. There's some exploit: in the middle of battle for example client has powerfull Javelin rockets, he has its in his ruck inventory. He can shoot with Javelin and then rejoin server and will get ammo back in ruck.

So i tried to save loadout at disconnect only but in the middle of the game.

Updated by Raptorko over 4 years ago

What about trying to combine both methods and having them rewrite the data of each other? That way you would have your equipment stored every n minutes in case you crashed, but will also save your equipment (and rewrite the "saved in the event of crash" equipment) when you disconnect normally.

Would it be possible?

Updated by tolko_download over 4 years ago

It is possible but it is way for cheating: if player has limited (and for example expensive like in Warfare) weapon he can duplicate it because saving ruck inventory will be delayed on loop's timeout:

while {true} do
{
    [somePlayer] call fnc_DB_SaveState; //Saving with updating RUCK staff
    sleep 300;
};

onPlayerDisconnected = "[somePlayer] call fnc_DB_SaveState;"; //Saving without updating RUCK staff

As I said above if player will place something in ruck, wait for saving via loop and then drop this thing on the ground, dsconnect, saving again without saving ruck, connect... restoring all stuff and he will get all his staff back with droped thing. It's a way to duplicate good sniper rifles and ammo, AT and other powerfull staff. :(

Sometimes I can save "ACE_weapononback", "ACE_RuckMagContents" and "ACE_RuckWepContents", but in most cases these vars get erased after onPlayerDisconnected commits.

Updated by tcp over 4 years ago

Well, CBA local event hooks could be added to the ACE ruck actions, so that when WOB or ruck contents are accessed it can trigger whatever script you need to save the contents. Regular gear (ammo) is handled by the engine and is global so it can be done with onPlayerDisconnected. I will try to add these hook sometime tomorrow.

Updated by tolko_download about 4 years ago

Would be nice :)

I found way, it's not best but also are working

Simple scheme:

// Simple loop with minimum actions
while {true} do
{
    player setVariable["SomeNonACEVariable", player getVariable "ACE_SomeACEVariable", false];
    sleep 1;
};

Storing function contains

...
_Store_SomeVariable = _unit getVariable "SomeNonACEVariable";
...

_Store_SomeVariable wil be send to server via global array. As you can see I use non-ACE var instead of native ACE var to prevent erasing data at onPlayerDisconnected.

Using this method I can get access to any ACE local vars. Yep, loops are bad solution, but at least it allows to send fresh data.

Updated by tolko_download about 4 years ago

Just tested

ace_2_nonace.sqf

waitUntil {local player};

while {local player} do
{
    _var = player getVariable "ace_w_state";
    if (!(isNil "_var")) then
    {
        player setVariable[ "nonace_w_state", _var, true];
    };
    sleep 1;
};

ace_w_state is being copied to nonace_w_state. It's working fine. :)

Updated by tcp about 4 years ago

That's really bad for the network. You should avoid making object variables public, and, if you have to do it, don't do it every second. Since ruck contents changes only originate from the individual player, you should store the last transmitted ruck array locally and compare it to the current array when deciding whether to transmit it. Also, I think there are CBA functions that handle network transmissions more efficiently.

You should be able to do away with any loops for rucks because I am in the process of making the events that you can hook into for ruck changes. You will have to wait for the next version for the changes to be released though.

Updated by tolko_download about 4 years ago

Yep I know, it's not good solution and I'm waiting for new with event system. Can you explain some things? As I understand your words I have to:

1. Local event handler decides (by flag "updated = false"): was some local client data changed from last calling, if yes - it should be updated to server. No data is transfered between server and client.

2. Desired local data is copied in a special clientArray - special prepared variable (or buffer) which can be transmitted via network with special structure.

3. clientArray is copied to the serverArray and event handlers sets local flag "updated = true".

We transmit data if CBA event called and if some local client data was changed only. Is it correct?

But I have some questions:
1. I don't want to publish clientArray and serverArray for any other clients, is it possible? In other words clientArray and serverArray should be seen for one client and server only.

2. Which CBA function I should to use for transmitting data?

Thanks for attention tcp :)

Updated by tcp about 4 years ago

Can't answer your question right now, might come back to it.

See 48993833744cad70efdabefcd9aa8803a528f3e0

Added localEvent "ace_sys_ruck_changed" with parameter [_amount,_type,_class]

_amount - int, negative or positive count
_type - int, 0 for WOB, 1 for weapon, 2 for magazine
_class - string, class name

Updated by tcp about 4 years ago

  • Category set to Script
  • Status changed from Feedback to Resolved
  • Target version set to 1.11
  • % Done changed from 0 to 100
  • Component set to sys_ruck

Updated by tcp about 4 years ago

  • Target version deleted (1.11)

Updated by tolko_download about 4 years ago

Cool! Thank you very much dear TCP!!! :)

Updated by Anunnaki about 4 years ago

to TCP: great, thank you very much for this EH.

to tolko_download:
can you please send me your work on saving system ?
I am starting work on my own saving system, but perhaps with your permission, i can use parts (or whole) from your work.
Please, send it to or publish it here, when you agree. Thank you very very much.

Updated by rocko about 4 years ago

  • Status changed from Resolved to Closed

Also available in: Atom PDF