You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
**GridForge** is a deterministic, high-performance voxel-grid library for spatial partitioning, simulation, and game-development workflows.
12
+
**GridForge** is a deterministicvoxel-world library for building fast spatial systems in games, simulations, tools, and server runtimes.
13
13
14
-
The core unit is an explicit `GridWorld`. That lets you run multiple isolated worlds in one process without leaking grid registration, tracing, blockers, occupants, or scan queries across world boundaries.
14
+
It gives you the low-level grid infrastructure that many systems end up reinventing: snapped voxel bounds, world-scoped grid registration, conjoined-grid neighbor awareness, scan-cell query overlays, blocker and obstacle state, occupant tracking, and fixed-point spatial math.
15
+
16
+
The interesting part is the shape of the model. GridForge does not force you into one giant grid, a hand-managed tile map, or a premature hierarchy. It gives you an explicit `GridWorld` that can own one grid, many conjoined grids, or a streamed set of active grids, while still leaving room for higher-level sector, region, planet, or shard systems above it.
17
+
18
+
## Why GridForge?
19
+
20
+
Grid-based systems tend to split into three common approaches:
21
+
22
+
| Approach | Best fit | Tradeoff |
23
+
| --- | --- | --- |
24
+
| Single large grid | Small or fixed worlds | Simple, but can become wasteful or awkward to stream |
25
+
| Multiple conjoined grids | Large worlds, loaded regions, tiled simulation spaces | More flexible, but needs reliable ownership and neighbor handling |
26
+
| Hierarchical grids | Very large or multi-scale worlds | Powerful, but easy to overbuild too early |
27
+
28
+
GridForge is designed around the most flexible foundation: **conjoined grids inside explicit worlds**.
29
+
30
+
That means you can start with a single grid, add neighboring grids as the world grows, remove inactive grids as regions unload, and build hierarchy above the library only when your game or simulation actually needs it.
31
+
32
+
## What It Provides
33
+
34
+
- Explicit `GridWorld` ownership for isolated runtime state
35
+
- Multiple active grids per world, with conjoined boundary neighbor lookup
36
+
- Deterministic fixed-point math through `FixedMathSharp`
37
+
- Fast world-space lookup through snapped bounds and a spatial hash
38
+
- Scan-cell overlays for efficient radius and occupant queries
39
+
- Region coverage through `GridTracer`
40
+
- Blocker and obstacle workflows for world-space blocked areas
41
+
- Occupant and partition extension points for gameplay or simulation metadata
42
+
- Allocation-conscious internals built on `SwiftCollections` pools and containers
43
+
- Standard and lean package variants for different dependency needs
15
44
16
45
## Install
17
46
@@ -23,35 +52,23 @@ GridForge targets `netstandard2.1` and `net8.0`.
23
52
24
53
### Package Variants
25
54
26
-
GridForge is published in two build variants so you can choose between built-in `MemoryPack` support and a leaner dependency set:
27
-
28
-
-`GridForge`
29
-
Includes `MemoryPack` and depends on the standard `FixedMathSharp` and `SwiftCollections` packages. This is the best default choice for most .NET applications.
30
-
-`GridForge.Lean`
31
-
Excludes the `MemoryPack` package, swaps to `FixedMathSharp.NoMemoryPack` and `SwiftCollections.Lean`, and uses internal shim attributes so the same source can compile without the dependency. Choose this when you do not need built-in MemoryPack serialization, when you prefer a different serializer, or when you want the leanest dependency surface.
32
-
33
-
Both variants expose the same core voxel-grid API. The main difference is whether `MemoryPack` and the standard dependency chain are included.
34
-
35
-
Install via NuGet:
36
-
37
-
- Standard package:
55
+
GridForge is published in two build variants:
38
56
39
-
```bash
40
-
dotnet add package GridForge
41
-
```
57
+
| Package | Use when |
58
+
| --- | --- |
59
+
|`GridForge`| You want the default package with `MemoryPack`, `FixedMathSharp`, and `SwiftCollections`. |
60
+
|`GridForge.Lean`| You want the same core voxel-grid API without the direct `MemoryPack` dependency, using `FixedMathSharp.Lean` and `SwiftCollections.Lean`. |
42
61
43
-
- Lean package:
62
+
Install the lean package with:
44
63
45
-
```bash
46
-
dotnet add package GridForge.Lean
47
-
```
48
-
49
-
If you build from source, the repository also provides matching release configurations:
64
+
```bash
65
+
dotnet add package GridForge.Lean
66
+
```
50
67
51
-
-`Release` builds the standard `GridForge` package and release archives.
52
-
-`ReleaseLean` builds the `GridForge.Lean` package and release archives.
68
+
Source builds also expose matching configurations:
53
69
54
-
### Unity
70
+
-`Release` builds the standard `GridForge` package.
71
+
-`ReleaseLean` builds the `GridForge.Lean` package.
55
72
56
73
Unity-specific integration lives in the separate [GridForge-Unity](https://github.com/mrdav30/GridForge-Unity) repository.
@@ -74,7 +91,7 @@ if (!world.TryAddGrid(configuration, out ushort gridIndex))
74
91
thrownewInvalidOperationException("Failed to add grid.");
75
92
76
93
VoxelGridgrid=world.ActiveGrids[gridIndex];
77
-
Vector3dposition=new(2, 0, -3);
94
+
Vector3dposition=newVector3d(2, 0, -3);
78
95
79
96
if (world.TryGetGridAndVoxel(position, outVoxelGridresolvedGrid, outVoxelvoxel))
80
97
{
@@ -84,22 +101,41 @@ if (world.TryGetGridAndVoxel(position, out VoxelGrid resolvedGrid, out Voxel vox
84
101
}
85
102
```
86
103
87
-
Key ideas:
104
+
The key mental model is:
105
+
106
+
1. Create a `GridWorld`.
107
+
2. Register one or more `VoxelGrid` instances from `GridConfiguration`.
108
+
3. Resolve world-space positions into grids and voxels.
109
+
4. Layer scans, blockers, occupants, partitions, or higher-level systems on top.
110
+
5. Reset or dispose the world when that simulation boundary is done.
111
+
112
+
## Conjoined Grids And Dynamic Worlds
113
+
114
+
The library is built for worlds that grow, stream, and split responsibility cleanly:
88
115
89
-
-`GridWorld` owns runtime state such as voxel size, spatial hash size, active grids, tracing, blocker reactivity, and world-space lookup.
90
-
-`VoxelGrid` is world-local. `GridIndex` is unique only within its owning world.
91
-
-`WorldVoxelIndex` is the cross-system identity for a voxel and includes world scope.
116
+
- A small game can use one `GridWorld` with one `VoxelGrid`.
117
+
- A streamed world can load and unload grids around the player or active simulation area.
118
+
- A server can run multiple isolated `GridWorld` instances in one process.
119
+
- A larger architecture can put sectors, planets, regions, or hierarchy above GridForge without reworking the voxel layer.
92
120
93
-
## Why Explicit Worlds
121
+
GridForge tracks world-local grid slots, grid spawn tokens, and `WorldVoxelIndex` values so systems can reason about identity even as grids are removed, reused, or replaced.
94
122
95
-
Having `GridWorld` own world state makes it practical to build:
123
+
## Core Concepts
96
124
97
-
- multi-world simulations with overlapping local coordinates
98
-
- streamed loading and unloading without cross-world state leakage
99
-
- save and load flows keyed by world identity
100
-
- higher-level orchestration such as galaxies, sectors, or planet registries above the library
125
+
| Concept | Role |
126
+
| --- | --- |
127
+
|`GridWorld`| Owns voxel size, spatial hashing, active grids, lifecycle, events, and top-level lookup for one isolated world. |
128
+
|`VoxelGrid`| Owns one grid's snapped bounds, voxels, scan cells, neighbor relationships, obstacle summary state, and versioning. |
129
+
|`Voxel`| Represents one snapped cell with obstacle, occupant, partition, boundary, and cached neighbor state. |
130
+
|`ScanCell`| Groups voxels into query buckets so radius scans can skip empty regions. |
131
+
|`GridTracer`| Converts lines and bounds into covered voxels or scan cells across the active grids in a world. |
132
+
|`BoundsBlocker`| Applies and removes obstacle state over traced world-space bounds. |
133
+
|`IVoxelOccupant`| Represents dynamic entities that can be registered, deregistered, and scanned. |
134
+
|`IVoxelPartition`| Attaches typed voxel-local metadata or behavior directly to a voxel. |
Copy file name to clipboardExpand all lines: docs/wiki/Occupants-and-Partitions.md
+5-3Lines changed: 5 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -112,8 +112,9 @@ That is why the occupant system is tightly coupled to scan-cell activation state
112
112
113
113
## Common Occupant Entry Points
114
114
115
-
Use `GridOccupantManager.TryRegister(occupant)` when:
115
+
Use `GridOccupantManager.TryRegister(world, occupant)` when:
116
116
117
+
- you have the owning `GridWorld`
117
118
- the occupant already knows its world-space `Position`
118
119
- you want the manager to resolve the correct grid and voxel automatically
119
120
@@ -123,13 +124,14 @@ Use `grid.TryAddVoxelOccupant(...)` overloads when:
123
124
- you already know the target `Voxel` or `VoxelIndex`
124
125
- you want to avoid repeating global lookup
125
126
126
-
Use `TryDeregister(...)` or `TryRemoveVoxelOccupant(...)` when:
127
+
Use `GridOccupantManager.TryDeregister(world, occupant)` or `TryRemoveVoxelOccupant(...)` when:
127
128
129
+
- you have the owning `GridWorld`
128
130
- cleaning up an entity
129
131
- moving an occupant from one voxel to another
130
132
- unloading game state tied to a grid
131
133
132
-
`TryDeregister(...)` is especially useful when an occupant has already moved in world space. GridForge removes the occupant from the voxel registrations it is actually tracking rather than relying on the occupant's current `Position`.
134
+
`TryDeregister(world, occupant)` is especially useful when an occupant has already moved in world space. GridForge removes the occupant from the voxel registrations it is actually tracking rather than relying on the occupant's current `Position`.
|`GridForge.wiki`| GitHub wiki content used as the deeper documentation companion |
33
+
|`docs/wiki`| GitHub wiki source content used as the deeper documentation companion |
34
34
35
35
The solution also exposes a small set of root-level "solution items" such as `.editorconfig`, `README.md`, `AGENTS.md`, `LICENSE`, and `coverlet.runsettings`.
36
36
@@ -41,22 +41,31 @@ The library project in `src/GridForge/GridForge.csproj` establishes a few import
41
41
- language version is C# 11
42
42
- target frameworks are `netstandard2.1` and `net8.0`
43
43
-`ImplicitUsings` is disabled
44
-
-`Nullable` is disabled
44
+
-`Nullable` is enabled in the library project
45
45
- XML documentation files are generated
46
46
- deterministic and CI build flags are enabled
47
47
-`GeneratePackageOnBuild` is enabled
48
+
- the supported configurations are `Debug`, `Release`, and `ReleaseLean`
48
49
49
50
That last item is easy to miss: building the library also produces NuGet artifacts.
50
51
51
52
## Package And Dependency Notes
52
53
53
-
The main library currently depends on:
54
+
The standard package currently depends on:
54
55
55
56
-`FixedMathSharp`
56
57
-`SwiftCollections`
57
58
-`MemoryPack`
58
59
-`System.Text.Json` for the `netstandard2.1` target only
59
60
61
+
The lean package is built by `ReleaseLean` or `DisableMemoryPack=true` and uses:
62
+
63
+
-`FixedMathSharp.Lean`
64
+
-`SwiftCollections.Lean`
65
+
- the `GRIDFORGE_DISABLE_MEMORYPACK` compilation symbol
66
+
67
+
Both package variants expose the same core voxel-grid API.
68
+
60
69
Packaging also includes the root `README.md`, `LICENSE`, `NOTICE`, `COPYRIGHT`, and `icon.png`.
61
70
62
71
## Versioning Behavior
@@ -89,6 +98,7 @@ The test project:
89
98
- targets `net8.0`
90
99
- is marked as a test project and not packable
91
100
- references the main library project directly
101
+
- supports `Debug`, `Release`, and `ReleaseLean`
92
102
- uses xUnit v3 plus the Visual Studio runner and console runner
93
103
- includes `coverlet.collector`
94
104
- points to `coverlet.runsettings`
@@ -102,6 +112,7 @@ The benchmark project:
102
112
- targets `net8.0`
103
113
- is an executable
104
114
- references the main library project directly
115
+
- supports `Debug`, `Release`, and `ReleaseLean`
105
116
- uses BenchmarkDotNet
106
117
- is optimized for benchmark runs
107
118
@@ -133,12 +144,12 @@ At a high level it:
133
144
134
145
- runs on `ubuntu-latest` and `windows-latest`
135
146
- triggers on pushes except `dependabot/**`, `gh-pages`, and version tags like `v*`
136
-
- triggers on pull requests targeting `main`
147
+
- triggers on pull requests targeting `main` or `develop`
137
148
- installs .NET 8
138
149
- installs and executes GitVersion
139
150
- restores dependencies
140
-
- builds the solution in `Debug`
141
-
- runs the test suite in `Debug`
151
+
- builds the solution in both `Release` and `ReleaseLean`
152
+
- runs the test suite in both `Release` and `ReleaseLean`
142
153
143
154
This is a useful sanity check when deciding whether a change is likely to be cross-platform safe.
144
155
@@ -150,9 +161,9 @@ Its flow is:
150
161
151
162
1. locate the solution root
152
163
2. ensure GitVersion environment variables are present
153
-
3. build the project in the requested configuration
154
-
4. walk each Release target-framework output folder
155
-
5. zip each framework output into a versioned archive
164
+
3. build both `Release` and `ReleaseLean`
165
+
4. walk each release target-framework output folder
166
+
5. zip each framework output into a versioned archive under `artifacts/releases`
156
167
157
168
That makes it the practical handoff script for release packaging, not just a convenience wrapper around `dotnet build`.
0 commit comments