diff --git a/src/SUMMARY.md b/src/SUMMARY.md
index 464dfbd..8dfae67 100644
--- a/src/SUMMARY.md
+++ b/src/SUMMARY.md
@@ -32,12 +32,12 @@ General Development
- [General programming](en/general-development/codebase-info/conventions/general.md)
- [Project programming](en/general-development/codebase-info/conventions/project.md)
- [ECS Conventions](en/general-development/codebase-info/conventions/ecs.md)
- - [Architecture](en/general-development/codebase-info/conventions/architecture.md)
+ - [Architecture Conventions](en/general-development/codebase-info/conventions/architecture.md)
- [Networking Conventions](en/general-development/codebase-info/conventions/networking.md)
- [Resource Conventions](en/general-development/codebase-info/conventions/resources.md)
- - [Module Conventions](en/general-development/codebase-info/conventions/modules.md)
- [Pull Request Guidelines](en/general-development/codebase-info/pull-request-guidelines.md)
- [Codebase Organization](en/general-development/codebase-info/codebase-organization.md)
+ - [Modules](en/general-development/codebase-info/modules.md)
- [Goob Reforged](en/general-development/codebase-info/goob-reforged/goob-reforged.md)
- [Reforged Modules](en/general-development/codebase-info/goob-reforged/reforged-modules.md)
- [Feature Proposals](en/general-development/feature-proposals.md)
diff --git a/src/en/general-development/codebase-info/conventions/ecs.md b/src/en/general-development/codebase-info/conventions/ecs.md
index 81b88cc..b74d4ea 100644
--- a/src/en/general-development/codebase-info/conventions/ecs.md
+++ b/src/en/general-development/codebase-info/conventions/ecs.md
@@ -60,21 +60,94 @@ When possible, try using the `EntitySystem` [proxy methods](https://github.com/s
Examples (click to expand)
```csharp
-// Without proxy methods...
+// Without proxy methods - bad
EntityManager.GetComponent(uid).EntityName;
-// With proxy methods
+// With proxy methods - good
Name(uid);
-// Without proxy methods...
+// Without proxy methods - bad
EntityManager.GetComponent(uid).Coordinates;
-// With proxy methods
+// With proxy methods - good
Transform(uid).Coordinates;
```
+### Update loops
+A lot of old code is accumulating frametime inside update loops to decide when to next run it.
+
+Accumulator example (bad):
+```csharp
+ public override void Update(float frameTime)
+ {
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var uid, out var comp))
+ {
+ comp.Accumulator += frameTime;
+
+ if (comp.Accumulator < UpdateInterval)
+ continue;
+
+ comp.Accumulator -= UpdateInterval;
+
+ // Code here
+ }
+```
+
+This is bad because of those reasons:
+1. This makes the update loop impossible to synchronize between server and client, causing prediction and networking issues.
+2. This approach uses the `float` type, and it is not precise enough in case of update loops, so it may cause rounding issues when the game is launched for a long time.
+3. This constantly does the addition operation, which isn't bad on its own, but when there are hundreds of systems doing that the overhead can beocme noticeable.
+
+All of the above problems can be fixed by using `TimeSpan` type and `IGameTiming`.
+
+TimeSpan example (good):
+```csharp
+ [Dependency] private readonly IGameTiming _timing = default!;
+
+ public override void Initialize()
+ {
+ SubscribeLocalEvent(OnMapInit)
+ }
+
+ private void OnMapInit(Entity ent, ref MapInitEvent args)
+ {
+ // Set the first update time after the entity is spawned.
+ // Without this it would update every single tick until NextUpdate catches up with the server time.
+ ent.Comp.NextUpdate = _timing.CurTime + ent.Comp.UpdateInterval;
+ Dirty(ent);
+ }
+
+ public override void Update(float frameTime)
+ {
+ // CurTime is calculated so we do it only once outside the update loop instead of for every sigle entity.
+ var curTime = _timing.Curtime;
+ // Loop over all components, ignoring paused entities.
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var uid, out var comp))
+ {
+ if (comp.NextUpdate < curTime)
+ continue; // Not enough time has passed since the last update.
+
+ // Set the time for the next update.
+ // Don't use
+ // comp.NextUpdate = curTime + UpdateInterval;
+ // because that eats the remainder with every update, causing the update loop to run slightly less often
+ // than given by UpdateInterval, which will be imprecise and can cause problems over large time durations.
+ comp.NextUpdate += UpdateInterval;
+
+ // Dirty the component so that the client can reroll the NextUpdate datafield during predcition.
+ // Without this you will get mispredicts.
+ Dirty(uid, comp);
+
+ // Do stuff here.
+ }
+ }
+```
+
+
## Events
### Method Events vs Entity System Methods
diff --git a/src/en/general-development/codebase-info/goob-reforged/reforged-modules.md b/src/en/general-development/codebase-info/goob-reforged/reforged-modules.md
index e6fd084..86bd3c7 100644
--- a/src/en/general-development/codebase-info/goob-reforged/reforged-modules.md
+++ b/src/en/general-development/codebase-info/goob-reforged/reforged-modules.md
@@ -62,11 +62,6 @@ flowchart TD
style GoobShared stroke:#3498db
GoobCommon[Content.Goobstation.Common]
style GoobCommon stroke:#3498db
-
- ModuleServer[Content.Modules.Server]
- style GoobShared stroke:#3498db
- ModuleClient[Content.Modules.Client]
- style GoobCommon stroke:#3498db
subgraph CoreModules["Core Modules"]
CoreServer
@@ -97,8 +92,6 @@ flowchart TD
CoreShared --> GoobShared
CoreServer --> GoobServer
CoreClient --> GoobClient
- GoobServer --> ModuleServer
- GoobClient --> ModuleClient
```
This means:
@@ -137,8 +130,6 @@ flowchart TD
style Lavaland stroke:#6b9bb3
Utils[Utils]
style Utils stroke:#6b9bb3
- Modules[".Modules projects (end)"]
- style Utils stroke:#6b9bb3
subgraph CustomModules["Custom Modules"]
Goobstation
@@ -150,10 +141,6 @@ flowchart TD
Core --> Goobstation
Core --> Lavaland
Core --> Utils
-
- Goobstation --> Modules
- Lavaland --> Modules
- Utils --> Modules
```
The only exception for that convention are **library modules** that provide some general tools or API for other modules to use.
@@ -174,8 +161,6 @@ flowchart TD
style Lavaland stroke:#6b9bb3
Utils[Utils]
style Utils stroke:#6b9bb3
- Modules[".Modules projects (end)"]
- style Utils stroke:#6b9bb3
subgraph CustomModules["Custom Modules"]
Goobstation
@@ -188,9 +173,6 @@ flowchart TD
Utils --> Goobstation
Utils --> Lavaland
-
- Goobstation --> Modules
- Lavaland --> Modules
```
## Special module projects
diff --git a/src/en/general-development/codebase-info/conventions/modules.md b/src/en/general-development/codebase-info/modules.md
similarity index 94%
rename from src/en/general-development/codebase-info/conventions/modules.md
rename to src/en/general-development/codebase-info/modules.md
index 5b05ca6..5d6916a 100644
--- a/src/en/general-development/codebase-info/conventions/modules.md
+++ b/src/en/general-development/codebase-info/modules.md
@@ -1,8 +1,4 @@
-# Modules Conventions
-
-```admonish warning "Attention: Placeholder!"
-This section is a placeholder, pending an updated guide to be written
-```
+# Modules
## What?
@@ -100,4 +96,4 @@ When building your project:
## Verification
-If you've done everything correctly, Content.Client or Content.Server should load your custom module on startup, with everything registering and initializing properly.
\ No newline at end of file
+If you've done everything correctly, Content.Client or Content.Server should load your custom module on startup, with everything registering and initializing properly.