Want to make all loot spawn like heli crash sites--once and permanent

joikd

Well-Known Member
There must be a simple way to spawn all loot upon server start, and not spawn again just like crash site loot. I'm guessing that it needs to be invoked in the dayz_server.pbo. I'm okay with changing files, and forcing players to download them.

Any help would be appreciated.
 
I want to prevent all loot farming, and is just one of a few big changes. The server should only really be significantly affected when the first person connects. After that no more loot will spawn, so I'm thinking that the server should actually run better than vanilla DayZ as far as loot is concerned.
 
I am interested in doing something similar and would be willing to assist in the development of this aspect.
 
Here's the untested code from the other thread. My issue is how to initiate upon server start, or when the first player joins, and prevent it from running again.

Code:
spawn_allBuildingLoot = {
    private["_center","_Chernarus","_allBldngs","_fastRun","_type","_config","_canLoot","_handle"];
 
    if (isDedicated) then {
        _center = getArray (configFile >> "CfgWorlds" >> _Chernarus >> "centerPosition";
        _allBldngs = _center nearObjects ["building",20000];
        _fastRun = _this select 0;
        {
            _type = typeOf _x;
            _config = configFile >> "CfgBuildingLoot" >> _type;
            _canLoot = isClass (_config);     
            if (_canLoot) then {             
                _handle = [_x,_fastRun] spawn building_spawnLoot;
                waitUntil{scriptDone _handle};
                _x setVariable ["permaLoot",true];
            };
        } forEach _allBldngs;
    };
};
 
I was able to get this to load up by throwing it into the init for the mission. It did not seem to do much and I did not have a lot of time to play with it last night. I will be going through it later today to see if I can figure out whats truely happening.
 
Maybe dayz_code\compile\building_spawnLoot needs this to be deleted (if it is loaded before any players enter the world)?

Code:
if (player distance _iPos2 > 5) then {
 
What about the initial loot spawn when the server is first started/restarted? Does that still take an hour?
 
No, It spawns normally, then an hour to cycle. So you'd have to remove all the loot in the spawns then wait an hour for it to respawn.
http://dayzmod.com/forum/index.php?...cation-of-the-dayz-loot-spawn-system-spoiler/

Dayz_code/compile/player_spawncheck.sqf

Find
Code:
    //diag_log ("SPAWN LOOT: " + _type + " Building is " + str(_age) + " old" );
                if ((_age > 10) and (!_cleared) and !_inVehicle) then {
Change to
Code:
            //diag_log ("SPAWN LOOT: " + _type + " Building is " + str(_age) + " old" );
                if ((_age > 60) and (!_cleared) and !_inVehicle) then {
Find
Code:
                if ((_age > 10) and (_cleared) and !_inVehicle) then {
                    //Register
Change to
Code:
                if ((_age > 60) and (_cleared) and !_inVehicle) then {
                    //Register
 
My server is not currently public, so it's not an issue. This was a quick fix is slow down loot cycling. I will most likely lower it to 30 minutes as my loot changes have reduced loot enough to not have COD with zombies.
 
I think he is saying that once loot cleanup occurs there is no loot until next spawn. Wouldn't it be better to extend loot cleanup to exceed the loot timer? Also putting loot timer past server restart time would basically cause it to spawn once and not again until server restart. Agaim love cleanup to exceed spawn timer.
 
If that can be done, is there a way to make the initial loot spawn immediately when a player enters the range? Currently, if nobody has been to a town it takes many minutes to get it to spawn.

Ideally, I would still like to figure out a way to get dayz_server.pbo to spawn the loot once. All of these timers and whatnot are a waste of resources if loot isn't going to get spawned again. I would much prefer to avoid using them.
 
EDIT: Got it fully integrated with dayz_server.pbo, updated post.
EDIT2: Fixed messed up instructions so they should actually work.. Thanks joikd for pointing out that they didn't work.


I guess this is as good an introduction as any: (EDIT: given the initially broken code, there could have been better)

I messed around with getting the server to spawn loot once on init on my LAN private hive last night and actually got it to work. It does have some quirks, however, and I don't know how feasible it would be to do this on a large server. On my private hive, performance actually got better after implementing this, but running well on a 6-person LAN server means nothing when dealing with 40+ player servers...

I'm fairly new to ArmA 2 scripting (6 months), so I don't know if it's the most efficient way to do this, but thought I'd share it anyways.

I'm using a modified version of your zombie spawn script, by the way. Thanks for sharing.

NOTES:
1. Loot can take around 5 minutes to fully spawn upon server start.
2. Without some changes to the streaming locations feature, nothing added by cfgTownGenerator will spawn loot.
3. No idea if it's BattleEye-safe. I play my homemade 'branch' of the mod with some friends on a private LAN without BE.

Approach 1: Server-Side loot spawn on Init (requires regular loot spawing to be removed from dayz_code)

Create the following sqf in dayz_server/compile/ :
This file is used by individual building to spawn loot and is a modded version of building_spawnLoot from dayz_code.

"server_spawnLoot.sqf"
Code:
private["_positions","_iArray","_iPos","_item","_obj","_type","_nearBy","_itemType","_itemChance","_lootChance","_weights","_index"];
_obj = 			_this;

_type = 		typeOf _obj;
_config = 		configFile >> "CfgBuildingLoot" >> _type;

_positions =	 [] + getArray (_config >> "lootPos");
_lootChance =	getNumber (_config >> "lootChance");
_itemType =		 [] + getArray (_config >> "itemType");
_itemChance =	 [] + getArray (_config >> "itemChance");	

{
	_iPos = _obj modelToWorld _x;
	_rnd = random 1;
	//Place something at each position
	if (player distance _iPos > 5) then {
		if (_rnd < _lootChance) then {
			_nearBy = nearestObjects [_iPos, ["WeaponHolder","WeaponHolderBase"],1];
			if (count _nearBy == 0) then {
				_weights = [_itemType,_itemChance] call fnc_buildWeightedArray;
				_index = _weights call BIS_fnc_selectRandom;
				if (_index >= 0) then {
					_iArray = +(_itemType select _index);
					_iArray set [2,_iPos];
					_iArray set [3,0];
					_iArray call spawn_loot;
					_iArray = [];
				//diag_log ("LOOTSPAWN");
				};
				_item setVariable ["created",(DateToNumber date),true];
				_item setVariable ["permaloot",true,true];
			};
		};
	};
} forEach _positions;


I'm not sure if this is needed, to be honest, but in dayz_code_system/building_monitor.sqf, you may have to comment this line out (I changed the system around a few times until it worked so I'm not sure, but objects marked with the permaloot variable may be immune to this):
Code:
{deleteVehicle _x;} forEach _items;


Then create an sqf in dayz_server/compile/ with the following:

"server_permaLootInit.sqf"
Code:
private["_center","_allBldngs","_type","_config","_canLoot","_cleared"];

if (isServer) then {
	_center = getMarkerPos "center";
	_allBldngs = _center nearObjects ["building",8500]; // (root(225000) / 2) + 1000 should get everything in Chernarus
	
	{
		_type = typeOf _x;
		_config = configFile >> "CfgBuildingLoot" >> _type;
		_canLoot = isClass (_config);
		_cleared = (_x getVariable ["cleared",true]);
		
		if (_canLoot) then {
			if (isNil("_cleared")) then {
				_x setVariable ["cleared",true,true];
				_cleared = true
			};
					
			if (_cleared) then {
				_x call server_spawnLoot;
				_x setVariable ["cleared",false,true];
			};
		};
	} forEach _allBldngs;
};


Then add this to dayz_server/init/server_functions.sqf:
Code:
server_spawnPermaLoot = compile preprocessFileLineNumbers "\z\addons\dayz_server\compile\server_spawnLoot.sqf";
server_permaLootInit = compile preprocessFileLineNumbers "\z\addons\dayz_server\compile\server_PermaLootInit.sqf";


Last, add the following to the bottom of dayz_server/system/server_monitor.sqf below the heli wreck spawns:

Code:
_id = [] call server_permaLootInit;




Approach 2:
Based on this, I also figured out how to make regularly spawned loot permanent and not respawn.


In dayz_code/compile/player_spawnCheck.sqf replace the whole block dealing with building spawns with the following:

Code:
_cleared = (_x getVariable ["cleared",true]);
				
if (isNil("_cleared")) then {
	_x setVariable ["cleared",true,true];
	_cleared = true
};

if (_cleared) then {
	_x setVariable ["cleared",false,true];
	[_x,_fastRun] call building_spawnLoot;
};

Add the following into dayz_code/compile/building_spawnLoot.sqf below the "created" variable:
Code:
_item setVariable ["permaloot",true,true];

make the same change to building_monitor as in the other approach so things don't get deleted by the building when you leave the vicinity.

The next post contains instructions on how to get the CFGTownGenerator objects to spawn permanently on server start.
 
EDIT: fixed the object filter statement, EDIT2: ...again...
EDIT3: sleep position fix.

Here's how to replace the location streaming function to get the above to spawn loot for the townGenerator objects:

(This one could affect performance as you're populating the map with everything that's usually streamed in, but also gives you control over which objects to spawn)

Delete the two lines with "call stream_locationCheck;" in dayz_code/system/player_monitor.fsm (lines 1087 and 1231 for me on 1.7.4.4). On a side-note, now all the buildings/wrecks/roadblocks added by the mod are gone if you want a blank slate to mod from, and all the objects are no longer local so the little oddities that come from that (such as climbing not showing up properly for other clients) should be gone :D

If you want to only spawn specific objects or stop some from spawning, take a look at the commented if statement

Create a new sqf named server_fillLocs.sqf in dayz_server/compile/ with the following:

Code:
private ["_configBase","_tempList"];

if (isServer) then {
	_tempList = ["Chernogorsk","Elektrozavodsk","Balota","Komarovo","Kamenka","Kamyshovo","Prigorodki","Kabanino","Solnichniy","StarySobor","NovySobor","SouthernAirport","NorthernAirport","Berezino","Lopatino","GreenMountain","Zelenogorsk","Nadezhdino","Kozlovka","Mogilevka","Pusta","Bor","Pulkovo","Vyshnoye","Drozhino","Pogorevka","Rogovo","Guglovo","Staroye","Pavlovo","Shakhovka","Sosnovka","Msta","Pustoshka","Dolina","Myshkino","Tulga","Vybor","Polana","Gorka","Orlovets","Grishino","Dubrovka","Nizhnoye","Gvozdno","Petrovka","Khelm","Krasnostav","Olsha"];
	for "_j" from 0 to ((count _tempList) - 1) do
	{
		_configBase = configFile >> "CfgTownGenerator" >> (_tempList select _j);

		for "_i" from 0 to ((count _configBase) - 1) do 
		{
			private ["_config","_type","_position","_dir","_onFire","_object"];
			
			_config = 	(_configBase select _i);
			if (isClass(_config)) then {
				//filter:
				
					_type = 	getText		(_config >> "type");
					//if (((getText (_config >> "type")) != "Body1") and ((getText (_config >> "type")) != "Body2")) then {
						_position = [] + getArray	(_config >> "position");
						_dir = 		getNumber	(_config >> "direction");
						_onFire = 	getNumber	(_config >> "onFire");
					
						_object =  _type createVehicle _position;
						_object setPos _position;
						_object setDir _dir;
						_object allowDamage false;
					
						//diag_log format["CreateObj: %1 / %2",_type,_position];
						/*
						if (_onFire > 0) then {
							nul=[_object,_onFire,time,false,false] spawn BIS_Effects_Burn;
						};
						*/
				//};
			};
			sleep 0.1; // for longer load, but better startup performance
		};
		//sleep 0.5; //comment the other sleep and uncomment this for faster load but slower startup performance
		diag_log ("Creating Objects: " + str(_configBase));
	};
	//diag_log ("Spawning all loot.");
	_id = [] call server_permaLootInit;
};

add it to server_functions
Code:
server_fillLocs =	compile preprocessFileLineNumbers "\z\addons\dayz_server\compile\server_fillLocs.sqf";

remove "_id = [] call server_permaLootInit;" from server_monitor from above post, and replace it with
Code:
_id = [] spawn server_fillLocs;

Have fun, it's been pretty entertaining so far having to actually go from town to town to get supplies.
 
Thanks, isathar. I will try this tonight. For the first five minutes, while loot is spawning, is the game playable? Just wondering. Even if it's not, that's very short term pain, for very long term gain. Awesome stuff!
 
It's not as bad as I expected it to be, actually. It takes a bit longer to load into the map, and is noticeably slower for a couple of minutes for me. But no more so than some servers I've connected to online. I just sit back and do something else for a couple of minutes to be on the safe side... earlier (failed) iterations of the script locked up the clients completely.
I've noticed that the overall performance after it's loaded is better on our server, since there aren't any objects besides zombies and such spawning around us in real-time. One of us crashed a couple of times while testing, but I'm hoping it was an unrelated issue.
 
Back
Top