Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Entity baselines are of questionable utility #1321

Open
slipher opened this issue Sep 25, 2024 · 1 comment
Open

Entity baselines are of questionable utility #1321

slipher opened this issue Sep 25, 2024 · 1 comment
Labels
A-Network T-Improvement Improvement for an existing feature T-Performance

Comments

@slipher
Copy link
Member

slipher commented Sep 25, 2024

When the server transmits an entity state to a client, it is always delta encoded against some base entity state. This base entity state is one of the following, in order of priority:

  1. The entity's state in the client's most recently acknowledged snapshot
  2. The entity's state in the "entity baseline"
  3. An all-zeroes entity state

I think (1) should be used the majority of the time under normal conditions. But when an entity first enters the client's PVS, (1) won't be available. Assuming entities stay in roughly the same position from frame to frame, and the network is not too flaky, (1) will start being available after a delay roughly equal to the client's ping. I assume (2) is intended to make things more efficient during that window.

This issue is about (2). So what is the entity baseline? I always imagined that entity baselines and delta compression work like keyframes in a video: periodically you get a new baseline/keyframe, and then for the next few seconds each frame is encoded via the diff from that base. (1) is kind of like that, but (2) is stupider: a baseline is taken only once, when the map is first loaded. It's never updated, not even on a map_restart (the cause of the inconsistent behavior in Unvanquished/Unvanquished#2124). It's like if the entire video were encoded based on diffs from the first frame. This was probably good for Quake, since most entities that existed at the start could never be destroyed. But we have buildables that can be destroyed and moved, and beacons for those buildables. Entity numbers are recycled, so it's likely that the baseline entity with a given number isn't even the same type as the currently existing entity. It's likely that using the entity baseline results in more bandwidth consumption in such cases.

What should we do about this? The easiest thing would be to NUKE or disable baselines. Maybe they can be considered an unnecessary micro-optimization from today's standpoint. If not, we could try some of the following ideas:

  • Remove an entity from the baseline once it dies. If we do this (and never add any new entities), we could keep the advantages of the baseline just for permanent stuff like doors.
  • When a new entity spawns, update its baseline entity.
  • Transmit baselines lazily instead of all at once.
  • Remember states of entities received by the client even after they leave the PVS. This would be more an extension of (1) that would replace the baseline concept.
@slipher
Copy link
Member Author

slipher commented Sep 27, 2024

@DolceTriade and I tested this on a server, having around 200 ping. On a torture test layout with around 600 buildables in a single room, baselines do have a significant advantage. With baselines turned off, the lag spike during the interval between the buildables entering the PVS and the client acknowledging the first snapshot is very noticeable. A bad thing is that the server has to keep sending the entities' full state every frame for several frames during this period, since there is not yet an acknowledged snapshot to delta against.

Note that the baseline advantage is only present when the entities already existed when the map started. If the layout was loaded with /layoutload, or if the buildables were manually constructed, it's the same as having no baseline. We would like to come up with a new design that works well for the latter scenario too. The tower defense mod is an example of a situation where you might construct hundreds of buildables in one room that aren't in the initial layout.

We discussed a couple possibilities based on transferring base states when entities enter PVS:
(A) Get rid of the concept of baselines, and instead allow using entity deltas against arbitrarily old snapshots. This means there would be a lag spike the first time you enter a room full of entities, but once you have seen the entities for the first time, it would be smooth the next time you enter.
(B) Lazily transmit entity baselines the first time an entity enters the PVS. The advantage over (A) is that the full entity states would only have to be transferred once, not several times while we await a snapshot. The drawback is that if the baseline packet were to be dropped or arrive late, some snapshots would not be fully readable. If we got a snapshot without having all up-to-date baselines, we would have to either discard it, or render it with some entities missing.

Another idea is to just continuously keep clients updated with the baseline for all entities, but we didn't like that this would disclose secret information about the enemy base location.

If option (B) is implemented, we need the sgame to have some control over baseline management. A simple idea is to set a baseline whenever a new entity spawns, if it is of a type that is likely to exist for a long time. Though for buildables it seems better to wait until construction finishes first. So we'd need some flags and/or trap calls to control baselines.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Network T-Improvement Improvement for an existing feature T-Performance
Projects
None yet
Development

No branches or pull requests

1 participant