Skip to content

Conversation

@slarticodefast
Copy link
Member

@slarticodefast slarticodefast commented Jan 6, 2026

Adds a guide to prediction, along with a few code examples and gifs showcasing the results.
I tried writing down everything that needs to be known, let me know if anything is wrong or unclear.

Draft until I had a few contributors and maintainers proofreading this and give feedback.
Especially the section on ApplyingState seems like it could be explained a little better, but it's a complicated topic.

ToDo in a future PR: Update the Basic Networking and you doc to include sections on field deltas, NetSerializableAttribute and how EntityUids are converted into NetEntities by the source generator.

@slarticodefast slarticodefast marked this pull request as draft January 7, 2026 00:10
@Pok27
Copy link

Pok27 commented Jan 7, 2026

Very cool job!

Copy link

@VerinSenpai VerinSenpai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partial review. Just some minor wording and grammar nitpicks. Its beautiful 🥺

@VerinSenpai
Copy link

Occurs to me that I reviewed this like a 500 word english essay that's due in 3 weeks. 😅

Copy link
Member

@SlamBamActionman SlamBamActionman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Baller guide. You're the GOAT.

```
Don't forget the client-side system, even if it's empty. Otherwise the client won't be able to instanciate the system class and it will remain unpredicted.

Avoid shared abstract components. Some ancient code is still doing this, but nowadays we just instead put the entire component into `Content.Shared`, even if some datafields are only used on the server or client. This is minimally worse for performance, but makes the code much more readable, simplifies any API methods and makes it easier to use `TryComp` and `Resolve`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good place to re-mention netSync and serverOnly here!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait is serverOnly even mentioned? I think the only thing related to server-only datafields is when you imply not adding AutoNetworkedField to fields that shouldn't be networked.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be honest I never used serverOnly so far, so no clue. Usually most components just keep the datafield on the client, even if it's only used on the server. Probably because it's just a microoptimization.

Copy link
Member

@Tayrtahn Tayrtahn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking great! Thanks for writing all of this up!

@slarticodefast slarticodefast marked this pull request as ready for review January 27, 2026 19:08
@slarticodefast
Copy link
Member Author

Ok, I have rewritten some explanations and I hope they should be more clear now.
I think this should be good to be merged.

Copy link
Member

@ArtisticRoomba ArtisticRoomba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

T'was a very good read before bed.


To reduce the network load the server usually does not send the full game state, but only the changes between each game tick (unless the client is freshly connecting or has major lag spikes).

Keep in mind that each client can only predict their own inputs and their results, as those of other players will still need to be networked to you first.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A good example that can semi lead into mispredicts: take an instance where you and another player try to grab a tool at nearly the same time. You'll appear to pick up the tool, but suddenly the tool is gone from your hand and is in their hand instead. In this instance the client assumed that you grabbed the tool, but the server decided that the other player had grabbed the tool first. You might have experienced this before.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I already got a similar example above, where you interact with something but someone else killed you before your client knows about it.


#### IRobustCloneable

Prediction repeatedly resets any dirtied datafield back to a previous game state and resimulates the player input. However, if your datafield is a [reference type](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/reference-types) it will only reset the reference to that datafield, not the datafield's current value. This can lead to [mispredicts](https://github.com/space-wizards/space-station-14/pull/34838) and even [major graphical glitches](https://github.com/space-wizards/space-station-14/issues/38512) if not handled correctly. To fix this make sure to implement the `IRobustCloneable` interface when using autonetworking with any custom reference type you are networking and the source generator will make sure to create a deep copy of the datafield for each game state. A code example for this is the [`Solution`](https://github.com/space-wizards/space-station-14/blob/master/Content.Shared/Chemistry/Components/Solution.cs) class used in the [`SolutionComponent`](https://github.com/space-wizards/space-station-14/blob/master/Content.Shared/Chemistry/Components/SolutionComponent.cs).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If IRobustClonable is only necessary for reference types then that means that we shouldn't put them on structs like HeatContainers? If so then it probably should be a warn-as-error type thing.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Structs may still contain pointers that would then have the same problem because those pointers would be copied by value.
HeatContainers would be fine without I guess, but it does not hurt to implement the interface in case someone expands them in the future.


#### Only use NetworkedComponentAttribute for shared components
Adding `[NetworkedComponent]` to a purely server- or client-side component (i.e. not in `Content.Shared`) does not make any sense since those cannot be networked in the first place.
However at the time of writing RobustToolbox is not preventing you from doing so and instead of creating a warning or error it will just break silently. The sympoms include random other components no longer being networked to the client, which will cause a huge range of bugs, for example mispredicts and UIs not being populated. So this is something you should keep an eye on during reviews or when writing new code.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Symptoms*

Also Jesus Christ.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, someone on the dev bus spent several days trying to figure out why their fork suddenly was bugging out everywhere. Turns out a completely unrelated PR had a single NetworkedComponent on a server side component.
This really needs an analyzer.

Copy link
Member

@ArtisticRoomba ArtisticRoomba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah.

@ArtisticRoomba ArtisticRoomba merged commit 43feec7 into space-wizards:master Jan 28, 2026
4 checks passed
@slarticodefast slarticodefast deleted the prediction-guide branch January 28, 2026 20:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants