Having the server spawn all zombies once at server start

joikd

Well-Known Member
After moving loot and road debris over to the server for spawning upon server start, it occurred to me that the same could probably be done with zombies. My goal is to have all zombies spawn by the server once upon server start. This should, hopefully, allow for many, many more zombies to be present simultaneously without lag, and eliminate all of the zombie spawning issues.

The changes I have made so far are emulating the loot changes I made. But, I am not seeing any zombies in-game. The rpt file shows them being spawned then deleted. I commented out one "delete vehicle" line and changed all of the zombiemonitor.fsm lines with 300 to 1 with the next line to equal "true" to show that a player is present, but I think something else in one of the fsm files is still deleting them. Notepad++ doesn't seem to scan fsm files when I do a file search, so it has been slow going.

Anyone have any ideas on what else needs to be changed?
 
If you haven't already, take a look at dayz_server\compile\zombie_findOwner.sqf. It's called in the else part of the same block in zombie_monitor.fsm as the deleteVehicle command and also deletes the zombie it's called on. I'm guessing it used to or will at some point do something else besides deleting the unit since it seems odd to have a conditional check if the zombie just gets deleted either way.
 
Hey there, isathar. It figures that it would be you responding to this. :) Thanks for responding. I really want to see what happens if this works.

You are correct-that one did need to be changed. I had already progressed past zombie deletion issues, but I never updated here since there seemed to be zero interest.

I am now stuck with zombie_agent.fsm issues. I used the FSM editor to remove all of the zombie cleanup code. Where the process comes to a standstill according to the .rpt is at the loiter:

Code:
_isAlive = alive _agent;
_target = _agent call zombie_findTargetAgent;
 
_agent forceSpeed 2;

That's the vanilla code, but it doesn't like it with the server spawning the zombies for some reason.

Any idea what second hand zombies are? Also, what is "count _this>2" referring to? The entire init code in the zombie_agent.fsm is :

Code:
_position =    _this select 0;
_agent =        _this select 1;
_secondHand = false;
 
if (count _this > 2) then {
    _secondHand = true;
    diag_log ("Second Hand Zombie Initialized: " + str(_this));
};
 
Well, after some more testing, none of the zombies pass the "!isnull" condition in zombie_agent.fsm. So, it looks like the server-spawned zombies are no good before they even get to zombie_agent.fsm. The zombie sqf files work fine for spawning zombies by a player, though.

Any ideas?
 
I made some progress, but I'm not there yet. Per the .rpt file zombies now spawn without any errors. CPU load went from 5% to 35%. But, I see zero zombies in-game.

Any help would be greatly appreciated.
 
I got it to work. Zombies kept getting killed on spawn by the general_cleanup state in server_cleanup.fsm, the part that has the comment "killing a hacker". I also had some issues with zombies not appearing, but resolved it by calling the spawning function with spawn instead of call (probably a bad idea, but hey, it worked). I'm not sure about second hand zombies, in testing, I ended up taking the _secondHand variable out altogether, and it's still working.

It does have a couple of issues: Zombies are slower than they should be and take a second to pathfind, and anything over 3000 or so zombies will be slow (to be expected), but the little hitches from spawning zombies in real-time are gone.
 
That's great, isathar!!! You are the man!!!

I was able to get them to spawn as well, but it took 4 hours to spawn them all (a little over 4000). At first they were spawning around 20 every second, but by the end it was 1 or 2 every 18 seconds. Using nearestObjects must be the reason I didn't see them in my post above--I was on the coast, but it was spawning from the "center" outward. My debug FPS went from 47 (no zombies) to 7, but, surprisingly, everything was smooth in-game. I noticed the same two zombie issues--delayed aggro and slowish movement with some sliding. But, my rpt showed losCheck error (I didn't move the code over from dayz_code/init/compiles.sqf), although they still chased me.

To summarize what I did:

--moved the following sqf files from dayz_code over to dayz_server (first three were heavily tweaked, first two used call instead of spawn): player_spawnCheck, building_spawnZombies, zombie_generate, zombie_findTargetAgent, zombie_loiter, and zombie_agent.fsm.

--adjusted all of the "compile preprocessFileLineNumbers" in dayz_code/init/compiles.sqf & dayz_server/init/server_functions.sqf to account for moving those files.

--added "_id = [] spawn player_spawnCheck;" to the server_monitor.sqf (by the way player_spawnCheck only contained zombie code since I spawn loot separately)

--used the FSM editor in zombie_agent.fsm to remove everything to the right of, and including, "is Dedicated", "Not Alive", and "Nobody Near" (basically, all of the cleanup code--I want all of the dead zombies to remain). Removed all "second hand" and dayz_clientPreLoad code.

--used the FSM editor in player_monitor.fsm to remove dayz_lootCheck in "Initialize" at the bottom and everything in "Stream" except for "endLoadingScreen;" (using isathar's stream upon server start method).

--used the FSM editor in server_cleanup.fsm to remove the "too many objects" and "cleanup objects" boxes of code.

I think that is everything. If I remember anything else I'll post it here. I still need to move the losCheck code over.


Isathar, I know you must have made a lot of changes. When you get a chance, please post what you did. I'm sure that you did some (or many) things differently than I did, and I would like to try them out (sounds like it didn't take 4 hours for your zombies to spawn). If we can figure out the two zombie movement issues, we're good-to-go!
 
Good to see you got it running. Looks like we messed with the same files in general, I'll post what I had to do at some point today. I'll have to gather up the files and look through them first. The zombie_agent in particular needed so few changes in the end that I felt kind of bad about how much I butchered it to begin with :D

Yeah, the zombie numbers are a bit high with default spawn settings, you'll have to adjust the maxroaming var in the building loot list. I'm still experimenting with it, but lowering residential spawns to 1 or 2 max and putting higher values on buildings that are more rare and military buildings is working nicely so far: still a reasonable amount of zombies (12-30 in villages, over 100 in Cherno and Balota airfield in my tests, with a total of 2200).

Initially it took hours to spawn them for me, as well, the thing that ended up making it manageable was changing the call method to the function that would have replaced building_spawnLoot from call to spawn; no idea why, but the zombie spawning function doesn't like call. Loading time went from a couple of hours (or more, I was impatient and stopped it) to 5-10 minutes.
 
Yeah, I butchered a lot of stuff, too. I'm looking forward to your write-up!

I kept getting an error whenever there was anything referring to the config.cpp with "_config >>". I had moved all of those files from dayz_code to dayz_server, but not the dayz_code config.cpp. In order to prevent those errors, I had to manually choose the variable, so I lost all of the other options. How did you prevent that?

I just spawned one zombie per legit spawn point (guess there are 4057 of them) due to my issue with not being able to reference the config.cpp.

I will definitely try using spawn--10 minutes is much better than 4 hours for playing and testing!:D

I'm also trying to find every zombie related file that can be moved to dayz_server.
 
By the way, I'm thinking of dropping in the 1.7.5 development files on top of a fresh 1.7.4 install. It sounds like there are a lot of optimizations that have been done. You haven't done this before by chance?
 
You are very correct, isathar. Using spawn is the key. It took 2.5 minutes to spawn 4057 zombies.
 
After doing a clean server install of 1.7.4 and adding the 1.7.5 dev files on top, I edited the necessary files in the most minimal way possible in order to have the server spawn the zombies with no errors (most was simply moving the files from dayz_code to dayz_server, and wrapping everything in "if (isdedicated)".

I have yet to find a fix for the delayed zombie actions, though. Maybe it has to do with the need for the server to transmit all of the zombie actions to the client rather the client receiving instant data when the zombies are client controlled?

I was thinking that maybe a hybrid approach to zombies would work best. Let the server spawn all of them initially, but let the player take them over when within 1000 (or some number), and give them back to the server at over 1000. Maybe get the best of both worlds?
 
I also messed with the 1.7.5 files for a while, ended up integrating the zombie and player damage performance fixes and rewriting player_zombieAttack to break car windows and pull people from cars when they're broken.
Yeah, the slow reaction time is most likely due to the amount of agents the server is running, then again the survivor/bandit AIs I have running around aren't affected even though they're run by he server, too. I know people do something similar to what you're talking about in warfare missions, but I have no idea how to go about setting it up at the moment.

I'm having some issues with the amount of time it takes to spawn zombies after a few changes, once they're fixed I'll post some info on what I did.
 
I ran a test where I placed a "sleep 1000;" towards the beginning of the zombie_agent.fsm. This froze all spawned zombies in place (could still hit me if I got close), but my server FPS went back up to 48 from 7. This seems to indicate that if we could "sleep" all server spawned zombies outside a certain specific of players, and only "awaken" them when players got within that specific range, the server wouldn't be bogged down, and maybe that would fix the zombie lag. I don't know if this will be any smoother than having the client spawning the zombies, but I suspect so since they are already spawned.
 
I'm experimenting with running the zombies on a headless client and moving them over to players that get near them. I'll probably drop the headless client part as it doesn't speed up the zombies by itself (while server fps goes up nicely) and I don't always have access to a second computer, but I'll report back on how the setOwner testing went in while.
 
That would be sweet if it works! So, maybe the server would be able to spawn like 10,000 zombies (server FPS goes way down), "sleep" the zombies with a "while" loop or something until a player comes into range (server FPS goes back up), then hand the zombies over to the client when in range (server FPS stays up)????

The gain would be the degree to which ownership transfer is less taxing than vanilla client spawning.
 
Good idea about setting them to sleep to begin with. I created a sleep state the zombies enter when no players are around and tweaked the chase state's latency a bit. They're still a little bit slower, but a lot better than initially. I'll test different numbers of zombies some more, but it's stable and running well at around 2000 zombies so far. I'll post implementation details after some more tests and tweaks.
 
After repeatedly breaking the zombie AI and killing server performance, I thought I'd share the parts that work before going back to regular spawns.

I added this to my server compiles as server_spawnZombies and called it from every building on load (same as permanent loot):
spawning code executed from server_monitor:
Code:
private["_center","_allBldngs","_type","_config","_canLoot","_cleared"];
 
if (isServer) then {
//diag_log ("Started Spawning Zombies...");
 
_center = getMarkerPos "center";
_allBldngs = _center nearObjects ["building",12500];
 
{
_type = typeOf _x;
_config = configFile >> "CfgBuildingLoot" >> _type;
_canLoot = isClass (_config);
 
if (_canLoot) then {
_x spawn server_spawnZombies;
 
};
} forEach _allBldngs;
 
//diag_log ("Finished Spawning zombies...");
};

server_spawnZombies:
dayz_server/compiles/server_spawnZombies.sqf
Code:
private["_obj","_type","_config","_canLoot","_originalPos","_unitTypes","_min","_max","_num","_zombieChance","_rnd"];
 
_obj = _this;
_type = typeOf _obj;
_config = configFile >> "CfgBuildingLoot" >> _type;
_canLoot = isClass (_config);
_originalPos = getPosATL _obj;
 
if (_canLoot) then {
    //Get zombie class
    _unitTypes = getArray (_config >> "zombieClass");
    _max = getNumber (_config >> "maxRoaming");
    _min = getNumber (_config >> "minRoaming");
   
    //Walking Zombies
    _num = round(random _max) max _min;
    _config = configFile >> "CfgBuildingLoot" >> _type;
   
    //Get zombie class
    _zombieChance = getNumber (_config >> "zombieChance");
    _rnd = random 1;
 
    if (_rnd < _zombieChance) then {
        //diag_log ("Class: " + _type + " / Zombies: " + str(_unitTypes) + " / Walking: " + str(_num));
        for "_i" from 1 to _num do
        {
            [_originalPos,_unitTypes] call server_zombieGen;
        };
    };
};

This is the server_zombieGen file, compiled on the server:
dayz_server/compiles/server_zombieGen.sqf
Code:
private["_position","_unitTypes","_doLoiter","_loot","_array","_agent","_type","_radius","_method","_myDest","_newDest","_lootType"];
 
_position =    _this select 0;
_unitTypes =    _this select 1;
_doLoiter =    true;
_loot =    "";
_array =    [];
_agent =    objNull;
 
if (count _unitTypes == 0) then {
    _unitTypes =    []+ getArray (configFile >> "CfgBuildingLoot" >> "Default" >> "zombieClass");
};
_type = _unitTypes call BIS_fnc_selectRandom;
 
//Create the Group and populate it
//diag_log ("Spawned: " + _type);
_radius = 0;
_method = "CAN_COLLIDE";
if (_doLoiter) then {
    _radius = 40;
    _method = "NONE";
};
 
//diag_log ("Spawned: " + str([_type, _position, [], _radius, _method]));
_agent = createAgent [_type, _position, [], _radius, _method];
 
_position = getPosATL _agent;
_position = [_position,64,(random 360),false,[1,64]] call SHK_pos;
 
if (_doLoiter) then {
    _agent setPosATL _position;
    //_agent setVariable ["doLoiter",true,true];
} else {
    _agent setVariable ["doLoiter",false,true];
};
 
diag_log ("CREATE INFECTED: " + str(_type));
 
 
if (random 1 > 0.7) then {
    _agent setUnitPos "Middle";
};
 
//diag_log ("CREATED: "  + str(_agent));
_agent setPos _position;
 
if (isNull _agent) exitWith {};
 
_myDest = getPosATL _agent;
_newDest = getPosATL _agent;
_agent setVariable ["myDest",_myDest];
_agent setVariable ["newDest",_newDest];
 
//Add some loot
_rnd = random 1;
if (_rnd > 0.3) then {
    _lootType =        configFile >> "CfgVehicles" >> _type >> "zombieLoot";
    if (isText _lootType) then {
        _array = []+ getArray (configFile >> "cfgLoot" >> getText(_lootType));
        if (count _array > 0) then {
            _loot = _array call BIS_fnc_selectRandomWeighted;
            if(!isNil "_array") then {
                _agent addMagazine _loot;
            };
        };
    };
};
 
//Start behavior
_id = [_position,_agent] execFSM "\z\AddOns\dayz_code\system\zombie_agent.fsm";

The _position code will be different on yours, I'm using a separate script to generate random positions for them.

I'll have to figure out what worked in the end from my zombie_agent.fsm, I'll post that when I do.
 
Well, I guess I'll let go of the server-spawned zombie idea, then. Thanks for all of your help (once again), isathar. I really appreciate your willingness to give your time and expertise to my crazy ideas. At least I learned a lot about FSM files! :)

I wonder if there are other, less resource hungry things that could be switched over to the server (like animal spawning--once upon server start:D ) to utilize more server power, and free up client power (= more smoothness for players). There just seems to be a big disparity between the two in vanilla DayZ (20% server CPU vs 75% client CPU).
 
Back
Top