Jump to content
  • 0
Sign in to follow this  
ekroemer

Looking for mod to prevent ammo cheat

Question

Hi there,

imo one of the most annoying things with A2 Epoch is that you have infinite ammo. Just keep a single bullet in the mag before reload, re-log and all mags are full, again. The same holds for any storage: put partially filled mags in and after a restart the magical ammo fairy has come.

That's a shame, especially on PvE servers where ammo should be a resource you have to scrounge for.

So, is there a mod out to prevent this?

Alternatively, what could be done about it. I could imagine a workaround that

  • would either delete a partially filled mag or, better
  • delete it with a probability of bullets_still_in_mag / mag_capacity
  • whenever a player logs out or
  • puts ammo into another storage.

But this exceeds my scripting ability, especially

  • where to put this functionality (there'll be a OnPlayerLogout, but where to catch all mag transfer into other storage?)
  • how to get current state and capacity of all ammo items in the gear.

Please tell me, someone has done this, already! ;)

Edited by ekroemer

Share this post


Link to post
Share on other sites

21 answers to this question

Recommended Posts

  • 1

That's a nice link :-)

I think, when I've time (not before the weekend), I'll activate some of the diag_logs, e.g in server_playerSync

		_playerGear = [weapons _character,_magazines];
		//diag_log ("playerGear: " +str(_playerGear));

and look at the format of _playerGear.

Then I'll hopefully find some commands to dissect that thing.

Share this post


Link to post
Share on other sites
  • 0

You do not need a mod to fix this problem. The reason why this is happening is because of a scripting issue. In ArmA 3 there is a command to add non-full mags to player's inventory but not sure if that command is also available in A2.

Share this post


Link to post
Share on other sites
  • 0

If I understand you correctly, the scripts that fill players' or objects' inventory at spawn time are flawed?

Could you be more specific about where that happens?

Also, while I've on occasion seen partially filled mag entries in the DB, I believe that has only been while the character was in-game. A logged off character seems to have full mag DB entries, only, so tweaking character setup won't be enough because the DB entry is already flawed.

Share this post


Link to post
Share on other sites
  • 0

Yes I think that script is indeed flawed. There are two ways to add a magazine to the player's inventory:

player addMagazine "30rnd_STANAG_NATO"; // Adds a full magazine of given classname
player addMagazine ["30rnd_STANAG_NATO", 2] // Adds given magazine with two bullets in it

Maybe that helps you? :)

Share this post


Link to post
Share on other sites
  • 0

Pardon my cluelessness, but I don't know where these scripts are located. Specifically those that

  • write player inventory to DB,
  • handle item movement between player inventory and other storage
  • and, according to your hint, read player inventory from DB.

Share this post


Link to post
Share on other sites
  • 0

Thanks!

server_playerSync looks right for saving gear and backpack to DB, and server_updateObject.sqf:_object_inventory seems to handle object inventories.

Now the 'only' thing one would have to do, would be to analyze the magazine variable (hopefully it's an array, not a string), identify elements signifying partially filled mags (assuming at this place this information is still present) and deleting them with a suitable probability RndLeft/RndMax.

I'm still afraid that exceeds my scripting ability....any hint on how to get the number of rounds in a mag from it's classname?

 

 

Share this post


Link to post
Share on other sites
  • 0

Config files seem to have the round number in them so you can more than likely fetch max rounds but i have no idea how you would go about saving how many rounds are left in each mag

https://github.com/vbawol/DayZ-Epoch/blob/master/SQF/dayz_code/Configs/CfgMagazines/Ammo.hpp

 

That's just something i found on git but can't seem to find it in client files so i guess most of them are pre-defined somewhere in arma itself

Share this post


Link to post
Share on other sites
  • 0

In the past when I asked about this, I was told you couldn't have partial mags saved to an inventory because there's no classnames for them. You'd need a classname for all possible ammo amounts. For example, 30rnd_STANAG_NATO is a STANAG magazine with 30 rounds. There's no 29rnd_STANAG_NATO for 29 rounds. 

Share this post


Link to post
Share on other sites
  • 0

That's right but imo no problem.

Shamelessly citing myself (bah, the new forum SW seems to disallow copy&paste from posts?), http://epochmod.com/forum/index.php?/topic/2704-ammo-mags-refilling-after-relog/&do=findComment&comment=22276, while a player is in game the database record shows a rather involved syntax, e.g. ["100Rnd_762x54_PK",5] while a full mag simply appears as "100Rnd_762x54_PK" (no array).

That means that in principle the ammo information is available.

I expect (will test on weekend, if I have time) that the inventory array in the sqfs shows exactly this information, that is then discarded when writing to DB.

I don't want to try to preserve the whole information - if that would be within my abilities it would have been done long ago.

But it should be possible to code something that on average will have the same effect - random choice between full and no mag, the chance depending on the fill ratio

E.g. a full 100rnd mag won't disappear ever, with 99rnds in it it has a 1% chance of not being saved to DB, with 1rnd the chance of disappearing would be 99%.

To be clear: I'm only talking about manipulating the saving of the current in-game status to DB (relevant at the last writing time, for a character that's at logut). There'll be nothing changed in-game.

Share this post


Link to post
Share on other sites
  • 0

That is correct for object_data.inventory, but I'm quite sure that in character_data multiple items in the players inventory (not backpack!) are listed separately, leading to substrings like

["mag", 3], ["mag", 1], "mag", "mag", "mag"

describing 3 full and 2 partially filled mags of the same type.

 

Thinking about it, the syntax for object_data.inventory isn't [["magA", numA], ["magB", numB]] either, but

[["magA", "magB"],[numA, numB]].

 

But be that as it may, fact is that in-game the information about rounds remaining in a partially used mag is present and thus there has to be a way of accessing it before it get's pressed into DB-format.

Share this post


Link to post
Share on other sites
  • 0

[["magA", "magB"],[numA, numB]]

The first sub-array lists all the different ammo magazines. The second sub-array lists the amount of mags for each listed mag. So, the example above does not include the amount of bullets inside the mag.

Share this post


Link to post
Share on other sites
  • 0

I know.

I detailed that to show that your claim ["mag",5] meant 5 mags of type "mag" did not apply here.

We concur that ammo count is not normally written into DB, but if you have a look at character_data for an in-game player you'll see that, sometimes, it is (but apparently never after logout).

And, anyhow, the point is moot because I want to access the information in-game, not from the DB.

Share this post


Link to post
Share on other sites
  • 0

I can confirm that the game saves ammo count in DB while you are ingame so it looks like this

[["BAF_L86A2_ACOG","ItemKeyBlack1972"],["30Rnd_556x45_Stanag",["30Rnd_556x45_Stanag",5]]]

Where second one has 5 rounds left and the other is full

However it doesn't save ammo count while mags are in your backpack, even if it's just the one with 5 rounds left.

["DZ_LargeGunBag_EP1",[[],[]],[["30Rnd_556x45_Stanag"],[1]]]

 

Edit: Unless you're looking to overwrite epoch/dayz inventory saving system there's pretty much no way to stop this

Edited by Antichrist

Share this post


Link to post
Share on other sites
  • 0

I wouldn't dream of trying lowlevel changes ;-)

But I think it will be possible to identify the entry ["30Rnd_556x45_Stanag",5] in server_playerSync's variables _playerGear and _playerBackp and to delete it there before it can be written to DB. Same for any object inventory.

Of course I'd like to make this deletion dependent on the actual amount of ammo left in relation to the full amount - but that's a secondary problem.

Regarding the backpack: here, I guess, the save-to-DB procedure is the same as for storage objects, storing only classname information. Nevertheless, in-game the round count is available: you can't refill a magazine by putting it into storage and getting it out, again without a server restart (that forces DB read instead of internal information use).

 

Share this post


Link to post
Share on other sites
  • 0

I tested a bit in server_playerSync.sqf, changing

	if (_isNewGear || _forceGear) then {
		//diag_log ("gear..."); sleep 0.05;
		_playerGear = [weapons _character,_magazines];

to

	private ["_kr_magazines", "_chanceToDelete"];
    if (_isNewGear || _forceGear) then {
		//diag_log ("gear..."); sleep 0.05;
		_kr_magazines = [];
		{ 
		  diag_log ("_magazines entry: " +str(_x)); 
          if (typeName _x == "ARRAY") then {
		    _chanceToDelete = 1;
		  } else {
		    _chanceToDelete = 0;
		  };
		  if ( random 1 > _chanceToDelete ) then {
	 	    _kr_magazines set [count _kr_magazines, _x];
		  };
		} forEach _magazines;
		diag_log ("_magazines: " +str(_magazines));
		diag_log ("_kr_magazines: " +str(_kr_magazines));

		_playerGear = [weapons _character, _kr_magazines];

Up to a point that did what I expected, namely deleting all magazines not completely filled from the array:

18:41:53 "_magazines: ["ItemPainkiller","ItemPainkiller","FoodCanFrankBeans",["100Rnd_762x51_M240",40],["100Rnd_762x51_M240",92],"100Rnd_762x51_M240","ItemBandage","ItemBandage","ItemBandage","ItemBandage","ItemBandage","ItemBandage","ItemBandage","15Rnd_9x19_M9SD"]"
18:41:53 "_kr_magazines: ["ItemPainkiller","ItemPainkiller","FoodCanFrankBeans","100Rnd_762x51_M240","ItemBandage","ItemBandage","ItemBandage","ItemBandage","ItemBandage","ItemBandage","ItemBandage","15Rnd_9x19_M9SD"]"

and propagating the new set of gear nicely into the DB.

 

But: after a while, be it after picking up something or logging off, the variables _magazines (that is a parameter to server_playerSync) reverted to

"100Rnd_762x51_M240", "100Rnd_762x51_M240", "100Rnd_762x51_M240"

instead of the

["100Rnd_762x51_M240",40],["100Rnd_762x51_M240",92],"100Rnd_762x51_M240"

it had a moment before, while, of course, in-game the mags are still only partially filled. (Of course that fits right in with my earlier impression that the DB, when a player is still in-game, sometimes, but not always shows the correct ammo status.

 

So the fault lies within the routine calling server_playerSync.

Which function, other than server_onPlayerDisconnect (that is not the culprit) calls server_playerSync?

Edit: found a call in dayz_code\system\player_monitor.fsm (Action to "Initialized"). Quite interestingly here the _magazineArray seems to be set up containing the correct ammo count.

//Primary Mags
for "_i" from 109 to 120 do 
{
	_control = 	_dialog displayCtrl _i;
	_item = 	gearSlotData _control;
	_val =		gearSlotAmmoCount _control;
	_max = 		getNumber (configFile >> "CfgMagazines" >> _item >> "count");
	if (_item != "") then {
		if (_val != _max) then {
			_magazineArray set [count _magazineArray,[_item,_val]];
		} else {
			_magazineArray set [count _magazineArray,_item];
		};
	};
};

So, when, where and why does that method fail or where is yet another call to server_playerSync?

 

Edit2: Found another one, I think. dayz_code\system\player_spawn_2.sqf has a block

	if (dayz_unsaved) then {
		if ((time - dayz_lastSave) > DZE_SaveTime) then {
			_dayzMags = if (!isNil "dayz_Magazines" && {typeName dayz_Magazines == "ARRAY"} && {count dayz_Magazines > 0}) then {dayz_Magazines} else {magazines player};
			PVDZE_plr_Save = [player,_dayzMags,false,false];
			publicVariableServer "PVDZE_plr_Save";
			dayz_unsaved = false;
			dayz_lastSave = time;
			dayz_Magazines = [];
		};
	};

Now I don't know for sure what player_spawn_2 does but it seems to care for a periodic player status update.

 

Here's what I gleaned about the mechanisms involved:

  • server_playerSync writes player state to DB and is called with an argument _magazines
  • server_playerSync is linked via addPublicVariableEventHandler to a public variable PVDZE_plr_Save
  • the magazine part of this variable is defined (correctly) in player_monitor.fsm where, simultaneously a global variable dayz_Magazines is defined but emptied afterwards. (does not make 100% sense to use it and then to delete it)
  • there is also dayz_code\compile\player_gearSync.sqf which defines dayz_Magazines in the same way that player_monitor.fsm does

The problem is the following:

  • while player_gearSync.sqf and player_monitor.fsm play nice and generate the correct magazine information,
  • server_playerSync does not use it because dayz_Magazines has been set to [].
  • Instead magazines player ist used and that generates only full mags.

 

Looking at all occurrences of dayz_Magazines I don't understand why it is set to [].

The only location where it is referenced without being set locally, before, is in player_spawn_2,sqf and there, imo, its value of [] results in information loss.

Edited by ekroemer

Share this post


Link to post
Share on other sites
  • 0

I have modified server_playerSync to

	if (_isNewGear || _forceGear) then {
		//diag_log ("gear..."); sleep 0.05;

		// build an alternative _magazine potentially skipping mags with less than full ammo
		_kr_magazines = [];
		{ 
		  diag_log ("_magazines entry: " +str(_x)); 
          if (typeName _x == "ARRAY") then {
		    _actMagClass = (_x select 0);
			_actAmmo = (_x select 1);
			_maxAmmo = getNumber (configFile >> "CfgMagazines">> _actMagClass >> "count");
		    _chanceToDelete = 1.0 - _actAmmo/_maxAmmo;
			diag_log (str(_actMagClass)+", chance to delete: " + str(_chanceToDelete));
		  } else {
		    _actMagClass = _x;
		    _chanceToDelete = 0;
		  };
		  if ( random 1 > _chanceToDelete ) then {
	 	    _kr_magazines set [count _kr_magazines, _actMagClass];
		  };
		} forEach _magazines;
		diag_log ("_magazines: " + str(_magazines));
		diag_log ("_kr_magazines: " + str(_kr_magazines));

		_playerGear = [weapons _character, _kr_magazines];

and that piece of code does what it should.

I've also changed player_monitor.sqm and player_spawn_2.sqf commenting out the lines dayz_Magazines = [];

 

But still server_playerSync sometimes is called with a parameter _magazines not containing the ammo count...I have yet to find from where.

 

Another question: where is the transfer from the player's main gear to backpack or other storage handled?

Share this post


Link to post
Share on other sites
  • 0

It seems I'm too daft to load my modified player_monitor.sqm.

In MPMission's init.sqf I'm calling custom\compiles.sqf, that one has

player_monitor = compile preprocessFileLineNumbers "custom\AntiAmmoCheat\player_monitor.sqf";

and that one has

diag_log ("player_monitor.sqf: calling modified version of player_monitor.fsm");
_id = [] execFSM "custom\AntiAmmoCheat\player_monitor.fsm";

But I don't even see the diag_log from player_monitor.sqf, let alone the from the sqm.

What am I doing wrong?

 

Edit: got it: player_monitor is not only defined in compiles.sqf but also directly in init.sqf.

 

Edit2: now I get a 'you have an outdated version of Epoch' when connecting - obviously the game does not like changing player_monitor....

 

Edit3: tried replacing player_monitor from scratch, works now and the full ammo information persists until the very end....but the DB write at disconnect still only has full mags.

Reason: server_onPlayerDisconnect has

		// prevent saving more than 20 magazine items
		_magazines = [(magazines _playerObj),20] call array_reduceSize;

		[_playerObj,_magazines,true,true,_isplayernearby] call server_playerSync;

in it and (magazines _playerObj) just fetches the classnames, not the ammo stats.

Changing that to

		// prevent saving more than 20 magazine items
		//_magazines = [(magazines _playerObj),20] call array_reduceSize;
		if ( (count (magazines _playerObj)) > 20 ) then {
		  _magazines = [(magazines _playerObj),20] call array_reduceSize;
		  [_playerObj,_magazines,true,true,_isplayernearby] call server_playerSync;
		} else {
		  [_playerObj,dayz_Magazines,true,true,_isplayernearby] call server_playerSync;
		};

finally seems to do the trick.

 

 

 

Edited by ekroemer

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Answer this question...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
Sign in to follow this  

  • Similar Content

    • By DirtySanchez
      Like its so hard to share things.
      We were all raised to share our stuff with our friends and I consider this community my friends with all the help and info and other goodies we all give back and forth in these threads.

      Too many people are asking individual questions on items and dumb comments and replies result.

      SO HERE ARE MY LISTS all laid out in the proper fashion for easy copy and paste.

      You will only need to format it properly for the database.
      This can be used for so many different things.

      ENJOY

      ps. These are good as of Marksmen and have the proper mags changed over


      ammo

      http://pastebin.com/SKgWFfRq

      food health

      http://pastebin.com/F7ddfcRL

      guns

      http://pastebin.com/1Q0Hbbcr

      uniforms

      http://pastebin.com/QzCq2wj4

      vehicles

      http://pastebin.com/QLxrkVT2

      backpacks

      http://pastebin.com/wMKfRyR5

      vests

      http://pastebin.com/bYhp6evs
    • By danmac
      Hi guys, first post so please be gentle and let me know if it needs an edit or two :)
       
      Since the 1.42 / 0.3.0.2 update we have noticed the Zafir has become incompatible with it's ammo.
       
      We have done the following tests, here's what stopped working:
      Existing ammo stored prior to update Ammo spawned using admin menu (Skaronator) spawn menu Ammo bought at the trader The following does work:
      Ammo spawned using admin menu "Give Ammo" option Ammo taken from dead AI In addition, the ammo that does load correctly, cannot be sold at the trader. It doesn't seem to matter where you got the gun, the problem from what we can tell is with the ammo. We haven't yet had time to test ammo from loot spawns.
       
      I assume the ArmA 1.42 update has changed the internal name of the ammo or something, but the Epoch side of things (trader / admin spawn menu / existing database) still has the old ones?
       
      Sorry I'm not totally knowledgable and not the owner of the server in question just trying to help out our GLORIOUS LEADER. Thanks for reading and a big thank you to the devs and community for this awesome work.
    • By oSoDirty
      I was trying to add ammo for the F35 and the Apache into mission crates. When trying i find that there are no pictures associated with the classnames. i get an error when opening the crate. dont remember the exact path for the missing .paa
      but when i had it written down (lost it) i couldnt find the folder it was referring to. I was just wondering if anyone knew if it was possible to add the .paa from another ammo type and just rename it to the new classname and make it work, and if so which PBO is the folder located in?
    • By oSoDirty
      As some of you know the newest WAI update no longer supports static ammo crates. I was wondering if anyone knew of a way to pull certain scripts/files from the older version to make a system made to just spawn in a few static crates throughout the map?
       or a way to merge and edit some files from old to new to make it work again? i tried the 1st but i dont really know what im doing so it was a fail lol. I need this to work for my Bandit/Hero ai camps. without the crates its really not worth people risking heli/vehicle patrols and a 12 man paradrop to raid the camps. Im ok with editing out the missions from the original as well if there is a way to make them work alonside one and other. ANY help is appreciated, thank you in advance!
    • By calamity
      I thought I would share my list of all weaposn/ammo and damage
      please share if I missed any...
       
      http://pastebin.com/h0Ja35FW
  • Advertisement
  • Supporters
  • Discord

×
×
  • Create New...