Skip to content

Commit 7432372

Browse files
csharp
1 parent 6d46ab5 commit 7432372

File tree

1 file changed

+13
-13
lines changed

1 file changed

+13
-13
lines changed

src/en/ss14-by-example/prediction-guide.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ When setting breakpoints or printing to the console you will notice that the pre
5252
## Prediction Code example
5353
Let's look at a simple unpredicted example component and predict it.
5454

55-
```C#
55+
```csharp
5656
// In Content.Server/PredictionExample/PredictionExampleComponent.cs
5757
5858
using Robust.Shared.Audio;
@@ -81,7 +81,7 @@ public sealed partial class PredictionExampleComponent : Component
8181
}
8282
```
8383

84-
```C#
84+
```csharp
8585
// In Content.Server/PredictionExample/PredictionExampleSystem.cs
8686
8787
using Content.Shared.Examine;
@@ -165,7 +165,7 @@ If we look at this in-game we notice the verb, examination text, popup and sound
165165
166166
Now let's move the code to shared and network and predict it.
167167
168-
```C#
168+
```csharp
169169
// In Content.Shared/PredictionExample/PredictionExampleComponent.cs
170170

171171
using Robust.Shared.Audio;
@@ -194,7 +194,7 @@ public sealed partial class PredictionExampleComponent : Component
194194
}
195195

196196
```
197-
```C#
197+
```csharp
198198
// In Content.Shared/PredictionExample/PredictionExampleSystem.cs
199199
200200
using Content.Shared.Examine;
@@ -274,7 +274,7 @@ The result is much more responsive without the delay for the popup, audio or UI
274274
Shared code can only call other shared code, whereas server-side code can use both server-side and shared code. This means if you want to predict an EntitySystem you will need predict all its dependencies first so that you can use them in Shared, which often turns prediction PRs into much larger tasks than initially expected.
275275

276276
Some systems cannot be predicted, but you might still want to call some API methods that are only available on the server from Shared. To work around this you can add an empty virtual API method in the corresponding shared system and override it on the server. Here's an example from [`SharedExplosionSystem`](https://github.com/space-wizards/space-station-14/blob/master/Content.Shared/Explosion/EntitySystems/SharedExplosionSystem.cs):
277-
```C#
277+
```csharp
278278
// In Content.Shared/Explosion/EntitySystems/SharedExplosionSystem.cs
279279
// This method is empty and does nothing on the client.
280280
public virtual void TriggerExplosive(EntityUid uid, ExplosiveComponent? explosive = null, bool delete = true, float? totalIntensity = null, float? radius = null, EntityUid? user = null)
@@ -341,7 +341,7 @@ B) The insertion of the entity into the container is not predicted (for example
341341
This is done that way to allow a client to update UIs even if they did not predict the event, for example the storage window of your backpack, your hand indicator or the damage overlay, but it also may cause problems during subscriptions as any changes done inside them are already networked separately within the same game state, meaning they will be applied multiple times, causing mispredicts.
342342

343343
Let's look at an example from `GlueSystem`
344-
```C#
344+
```csharp
345345
// GluedComponent will make an item temporarily unremovable if you pick it up.
346346
private void OnHandPickUp(Entity<GluedComponent> entity, ref GotEquippedHandEvent args)
347347
{
@@ -385,7 +385,7 @@ The most common ones are
385385

386386
## Predicted update loop example
387387
A lot of old code is accumulating frametime inside update loops to decide when to next run it.
388-
```C#
388+
```csharp
389389
/// <summary>
390390
/// Unpredicted example.
391391
/// </summary>
@@ -430,7 +430,7 @@ public sealed class UpdateLoopExampleSystem : EntitySystem
430430
```
431431
This is bad for prediction, as dirtying the accumulator datafield every single tick would be expensive due to the network load if we repeatedly have to send game state updates from the server. So instead of accumulating frame time we use a time stamp indicating when the next update is supposed to happen and compare that with the current server time.
432432

433-
```C#
433+
```csharp
434434
/// <summary>
435435
/// Predicted example.
436436
/// We need to network the component for this.
@@ -547,7 +547,7 @@ Here is an example of a mispredict happening when gibbing someone, so that you k
547547
In the future Robust Toolbox will have methods for predicted randomness, but at the time of writing the [PR for RandomPredicted](https://github.com/space-wizards/RobustToolbox/pull/5849) has not been merged yet.
548548
As a workaround you can use a new `System.Random` instance and set the seed to something the server and client agree on, for example a combination of an entity's `NetEntity` id and the current game tick (if you would only the game tick here then all randomness within the same game tick would yield the same result, so we need both).
549549

550-
```C#
550+
```csharp
551551
// EntitySystem dependencies:
552552
// [Dependency] private readonly IGameTiming _timing = default!;
553553
// [Dependency] private readonly IRobustRandom _random = default!;
@@ -601,7 +601,7 @@ Dirtying and networking is expensive. Avoid dirtying entities every single tick
601601

602602
When setting a datafield it is recommended to add a guard statement to check if the datafield has a new value before calling `Dirty` so that we only network it when actually necessary.
603603

604-
```C#
604+
```csharp
605605
// inside an EntitySystem
606606
607607
public void SetExampleDataField(Entity<ExampleComponent?> ent, int newValue)
@@ -632,7 +632,7 @@ Prediction repeatedly resets any dirtied datafield back to a previous game state
632632

633633
#### Conventions for shared systems and components
634634
EntitySystems should either be non-abstract and shared, for example:
635-
```C#
635+
```csharp
636636
// In Content.Shared/SomeNamespace/SomeSystem.cs
637637
public sealed class SomeSystem : EntitySystem
638638
{
@@ -642,7 +642,7 @@ public sealed class SomeSystem : EntitySystem
642642
```
643643
or have a shared abstract system that is inherited on the server and client.
644644

645-
```C#
645+
```csharp
646646
// In Content.Shared/SomeNamespace/SharedSomeSystem.cs
647647
public abstract class SharedSomeSystem : EntitySystem
648648
{
@@ -670,7 +670,7 @@ There is currently some weird behaviour with solution entities and PVS, which ma
670670

671671
This debug assert happens if a predicted update loops calls `SharedSolutionContainerSystem.ResolveSolution`, and the entity containing the solution entity leaves PVS range. This should not be happening since entities are paused when moved outside PVS range, meaning the update loop should no longer run on the client, but for some reason this still causes the debug assert and needs a workaround until this is fixed properly in a way that does not need this boilerplate code.
672672

673-
```C#
673+
```csharp
674674
private void OnEntRemoved(Entity<UdderComponent> entity, ref EntRemovedFromContainerMessage args)
675675
{
676676
// Make sure the removed entity was our contained solution

0 commit comments

Comments
 (0)