Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
81 changes: 77 additions & 4 deletions src/en/general-development/codebase-info/conventions/ecs.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,21 +60,94 @@ When possible, try using the `EntitySystem` [proxy methods](https://github.com/s
<summary>Examples (click to expand)</summary>

```csharp
// Without proxy methods...
// Without proxy methods - bad
EntityManager.GetComponent<MetaDataComponent>(uid).EntityName;

// With proxy methods
// With proxy methods - good
Name(uid);

// Without proxy methods...
// Without proxy methods - bad
EntityManager.GetComponent<TransformComponent>(uid).Coordinates;

// With proxy methods
// With proxy methods - good
Transform(uid).Coordinates;
```

</details>

### 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<UpdateLoopExampleComponent>();
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<UpdateLoopExampleComponent, MapInitEvent>(OnMapInit)
}

private void OnMapInit(Entity<UpdateLoopExampleComponent> 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<UpdateLoopExampleComponent>();
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -97,8 +92,6 @@ flowchart TD
CoreShared --> GoobShared
CoreServer --> GoobServer
CoreClient --> GoobClient
GoobServer --> ModuleServer
GoobClient --> ModuleClient
```

This means:
Expand Down Expand Up @@ -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
Expand All @@ -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.
Expand All @@ -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
Expand All @@ -188,9 +173,6 @@ flowchart TD

Utils --> Goobstation
Utils --> Lavaland

Goobstation --> Modules
Lavaland --> Modules
```

## Special module projects
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
# Modules Conventions

```admonish warning "Attention: Placeholder!"
This section is a placeholder, pending an updated guide to be written
```
# Modules

## What?

Expand Down Expand Up @@ -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.
If you've done everything correctly, Content.Client or Content.Server should load your custom module on startup, with everything registering and initializing properly.
Loading