Killing Floor 2

Killing Floor 2

Controlled Difficulty
blackout  [developer] May 19, 2017 @ 2:33pm
On the delay between squad spawns
On multiplayer servers, MaxMonsters can't deliver adequate difficulty control by itself. I have ideas about how to fix this. This post describes both the problem and potential fixes that I'm investigating.

Some background about how KF2 spawning works

The spawn manager sleeps for at least one full second between spawning squads. It wakes up exactly once a second when SpawnMod=0, subject to potential error imposed by the interpreter's timer internals/thread scheduling/etc. This error tends to be on the order of single-digit milliseconds -- generally negligible. The spawn manager may wake up less frequently (i.e. sleep longer than a second) when SpawnMod>0. After waking, the spawn manager checks if LiveMonsters < MaxMonsters. If so, it spawns a squad. This squad's size ranges from about 1 to 10 in most cases. SpawnMod (and, in the vanilla game, the Game Conductor) can only add time to this one second interval; neither SpawnMod nor the GC can reduce the sleep time below one second. I'm glossing over a bit of details about TimeUntilNextSpawn, but this is basically accurate.

This one-second sleep is hardcoded in vanilla KF2, and CD has never changed this behavior to date. Project One had an option to control it, IIRC.

Competent 6-man teams clearing ever-higher MaxMonsters figures

I've been keeping an eye on 6-man win videos posted by mike_5879 and dandyboy. MaxMonsters has slowly but steadily climbed as these videos come out, and the number of apparent visible monsters has not kept pace with what you'd expect from the MaxMonsters figure. This one really hammers the point home: 10000 MM

https://www.youtube.com/watch?v=ZaOruj3HH5A

As dandyboy points out "At some point, even increasing Maxmonsters doesn't make difference because spawn speed of each spawnpoints can't catch limit of Maxmonsters, so it gets spawn bottleneck."

Known bottlenecks

I suspect this bottleneck is probably KF2's "spawn one squad a second" behavior. I haven't tested this hypothesis yet, so it could turn out to be wrong.

As a thought exercise, let's suppose the average squad size is 6. If the team is capable of sustaining an average aggregate kill throughput of 7 zed/second, then MaxMonsters is effectively irrelevant in the long term. The team is killing monsters faster than they can spawn, on average.

The exact average squad size is determined by the spawncycle (or the set of squads randomly selected by the vanilla system), availability of open spawnvolumes, and also by minor second-order effects related to kill order and kill timing wrt spawn manager wakeups.

Another potentially important factor is map design and TWI's spawnpoint selection algorithm. After a zed spawns, it has to physically walk out of the spawnvolume before another zed can successfully spawn. In the interim, this spawnvolume can be selected for another squad to use, but it may result in some or all of the zed pawns being destroyed due to a collision check failing (zeds inside each other). I think most maps probably have spawnvolumes available to accommodate double-digit zeds at any given time, but some of them could be far away from players. I don't know the intricacies of the spawnvolume selection algorithm, and I suppose it's possible that the spawnvolume selector might artificially restrict the set of allowable volumes the point that it bottlenecks things. It's also possible that the spawnvolume selection algorithm could be erroneously selecting congested volumes, spawning a bunch of zeds that fail the collision check, and going back to sleep, resulting in "wasted" wakeup intervals. These are things I can explore.

Fixes might include:

* Adding an option to control the spawn manager wakeup interval (Project One had something similar)
* Adding an option to make the spawn manager spawn as many squads as it can (subject to MaxMonsters and spawnvolume availability) every time it wakes up
* Tweaking the spawnvolume selection algorithm to permit a broader range of the map's volumes (if this turns out to be a bottleneck)
* Tweaking the spawn algorithm to retry spawns that fail the collision check, selecting a less-preferred volume for each retry, probably up to a hardcoded retry limit to enforce bounded time on the attempt (if collision checks turn out to be dragging down the average squad size)

Note that these fixes are all tentative. They are also not mutually exclusive.
Last edited by blackout; May 24, 2017 @ 5:59pm
< >
Showing 1-9 of 9 comments
Xylona May 19, 2017 @ 8:58pm 
wow!
Leenker May 19, 2017 @ 10:57pm 
Too hard to understand.
Slayer May 20, 2017 @ 12:22am 
I wonder if you can change the spawn point algorithm so it can utilise more spawn points simultaneously.Also if I'm understanding correctly if I make my squads in the ini file all squads of 10 then we are more likely to reach the maxmonsters limit?(as long as they aren't killed at 10 a second).So maps like Sahara and China temple should be able to reach a high max zed limit with spawn points utilised far away.
blackout  [developer] May 20, 2017 @ 1:14am 
"I wonder if you can change the spawn point algorithm so it can utilise more spawn points simultaneously" I'm investigating this. No verdict yet.

"Also if I'm understanding correctly if I make my squads in the ini file all squads of 10 then we are more likely to reach the maxmonsters limit?(as long as they aren't killed at 10 a second)" This is accurate. However, this issue is, along with dynamic zed scaling/gradients, at the top of my todo list right now, so I'm hoping to introduce options to fix it in my next release.
BardzBeast May 20, 2017 @ 5:56am 
good work
Nice. I've been playing with making a custom spawn manager and one of the mistakes I made was use .25s wakup for the CustomSpawner and omit the RefreshMonsterAliveCount() so quickly ended up with 200+ active Zeds.

Here's my (now fixed) code: https://github.com/amimoto/Dodeca/blob/master/Classes/DAISpawnManager.uc

My intention is to be able to allow map makers to script specific squads at particular KFSpawnVolumes. The actual spawning at the volume seems to be native so I had to reimplement that portion. Maybe some of the concepts in my code might be useful?

Darn fun to see the higher level play that dandyboy and folks do.
blackout  [developer] May 20, 2017 @ 2:58pm 
@Teriyaki being able to spawn zeds at specific volumes seems really powerful. That's neat. Is there any public workshop item or page describing what you're working on? Looks like there's a bunch of code there going back months, but I didn't have much time to poke around the repo just now.

If you mean KFSpawnVolume.SpawnWave(...), yeah, it's native and it's annoying. The second parameter to that function is called bAllOrNothing (or something like that), but the function does not account for pawns failing the collision check and getting destroyed, so it seems pointless to even have that param. I also have my suspicions about their native implementation of custom projectile collision tracing, considering how husk fireballs behave these days... wish I could see that source.
blackout  [developer] May 20, 2017 @ 3:09pm 
Update on spawning:

Last night, I implemented the concept of a spawn cohort. This is a group of multiple squads that all spawn at the same time.

To the user, this exposes two new configuration dimensions:

* CohortSize: the maximum number of zeds the spawnmanager will spawn on any given wakeup. It may have to spawn less than this number if the map's spawnpoints are already saturated by zeds.
* MinSpawnInterval: this floating point number sets the minimum time, in seconds, between spawnmanager wakeups. This is not mutually exclusive with SpawnMod. SpawnMod=0 will cause the spawner to wakeup every MinSpawnInterval seconds; SpawnMod>0 means the spawner might sleep longer than MinSpawnInterval, depending on TWI's usual padding logic (which incorporates a time-varying sinewave, whether there's a pending leftover spawn squad, whether it's an early wave, etc.).

Internally, this works by sorting the list of available spawnvolumes from most to least preferred according to TWI's standard preference algorithm, then spawning one zed per volume until either the cohort size is reached or the list of eligible volumes is exhausted. It obeys MaxMonsters.

I've also added an option to disable KFAIController.bCanTeleportCloser.

I think this will alleviate bottlenecking, insofar as the map has sufficient spawnvolumes to accomodate zeds. For instance, on outpost, setting MinSpawnInterval=0.250 and CohortSize=48 resulted in over 154 zeds spawning in under a second when the first wave started (after the standard 5 second delay between wave start and first spawn, which has been in the game a long time and which I haven't altered).

Everything I described above is implemented locally, and now I'm just documenting and polishing it (adding chat commands, config options, etc.).

There's one more thing I'm contemplating adding -- what I'm about to describe below is not done yet. These options are useful new dimensions of control, but they also make it hard to estimate the real difficulty of any given CD configuration. I'm considering making CD keep running spawnrate statistics within each wave, then echoing them at the end of the wave. So, in trader time, maybe CD could automatically say what the average spawnrate, in zeds/sec, was over the whole last wave (really time of first spawn to time of last spawn, not beginning or end of the wave itself), 60 sec peak, 30 sec peak, or something like that.
Last edited by blackout; May 21, 2017 @ 1:52pm
smbrr May 21, 2017 @ 4:32am 
I like the idea of feedback during trader time, it might be the only way to be able to tweak the difficulty efficiently and detect eventual spawn bottlenecks

Great work on overcoming the 1s delay, keep it up!
< >
Showing 1-9 of 9 comments
Per page: 1530 50