Skip to content

Commit 2666137

Browse files
committed
chore: repo maintenance
1 parent 374c041 commit 2666137

7 files changed

Lines changed: 444 additions & 261 deletions

File tree

.github/workflows/sync-wiki.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name: Sync Wiki
33
on:
44
workflow_run:
55
workflows:
6-
- .NET CI
6+
- build-and-test
77
types:
88
- completed
99
branches:

AGENTS.md

Lines changed: 328 additions & 205 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 85 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,38 @@
99
[![License](https://img.shields.io/github/license/mrdav30/GridForge.svg)](https://github.com/mrdav30/GridForge/blob/main/LICENSE)
1010
[![Frameworks](https://img.shields.io/badge/frameworks-netstandard2.1%20%7C%20net8.0-512BD4.svg)](https://github.com/mrdav30/GridForge)
1111

12-
**GridForge** is a deterministic, high-performance voxel-grid library for spatial partitioning, simulation, and game-development workflows.
12+
**GridForge** is a deterministic voxel-world library for building fast spatial systems in games, simulations, tools, and server runtimes.
1313

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
1544

1645
## Install
1746

@@ -23,35 +52,23 @@ GridForge targets `netstandard2.1` and `net8.0`.
2352

2453
### Package Variants
2554

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:
3856

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`. |
4261

43-
- Lean package:
62+
Install the lean package with:
4463

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+
```
5067

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:
5369

54-
### Unity
70+
- `Release` builds the standard `GridForge` package.
71+
- `ReleaseLean` builds the `GridForge.Lean` package.
5572

5673
Unity-specific integration lives in the separate [GridForge-Unity](https://github.com/mrdav30/GridForge-Unity) repository.
5774

@@ -65,7 +82,7 @@ using GridForge.Grids;
6582

6683
using GridWorld world = new GridWorld();
6784

68-
GridConfiguration configuration = new(
85+
GridConfiguration configuration = new GridConfiguration(
6986
new Vector3d(-10, 0, -10),
7087
new Vector3d(10, 0, 10),
7188
scanCellSize: 8);
@@ -74,7 +91,7 @@ if (!world.TryAddGrid(configuration, out ushort gridIndex))
7491
throw new InvalidOperationException("Failed to add grid.");
7592

7693
VoxelGrid grid = world.ActiveGrids[gridIndex];
77-
Vector3d position = new(2, 0, -3);
94+
Vector3d position = new Vector3d(2, 0, -3);
7895

7996
if (world.TryGetGridAndVoxel(position, out VoxelGrid resolvedGrid, out Voxel voxel))
8097
{
@@ -84,22 +101,41 @@ if (world.TryGetGridAndVoxel(position, out VoxelGrid resolvedGrid, out Voxel vox
84101
}
85102
```
86103

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:
88115

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.
92120

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.
94122

95-
Having `GridWorld` own world state makes it practical to build:
123+
## Core Concepts
96124

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. |
101135

102-
## Start With The Wiki
136+
## Documentation
137+
138+
Start with the wiki:
103139

104140
- [Wiki Home](https://github.com/mrdav30/GridForge/wiki/Home)
105141
- [Getting Started](https://github.com/mrdav30/GridForge/wiki/Getting-Started)
@@ -109,6 +145,8 @@ Having `GridWorld` own world state makes it practical to build:
109145
- [Recipes](https://github.com/mrdav30/GridForge/wiki/Recipes)
110146
- [FAQ and Troubleshooting](https://github.com/mrdav30/GridForge/wiki/FAQ-and-Troubleshooting)
111147

148+
The source for those pages lives in [`docs/wiki`](docs/wiki).
149+
112150
## Local Validation
113151

114152
```bash
@@ -117,21 +155,27 @@ dotnet build GridForge.slnx --configuration Debug
117155
dotnet test GridForge.slnx --configuration Debug --no-build
118156
```
119157

158+
CI validates both `Release` and `ReleaseLean` on Ubuntu and Windows.
159+
120160
For benchmark discovery:
121161

122162
```bash
123163
dotnet run --project tests/GridForge.Benchmarks/GridForge.Benchmarks.csproj -c Release -- list
124164
```
125165

166+
Benchmarks are especially useful when changing pooling, tracing, grid registration, scan flow, or other allocation-sensitive paths.
167+
126168
## Contributing
127169

128170
See [CONTRIBUTING.md](CONTRIBUTING.md) for contribution guidelines and workflow details.
129171

130-
## Community & Support
172+
When working on core behavior, keep the library deterministic, world-scoped, allocation-conscious, and free of engine-specific assumptions.
173+
174+
## Community And Support
131175

132176
For questions, discussions, or general support, join the official Discord community:
133177

134-
👉 **[Join the Discord Server](https://discord.gg/mhwK2QFNBA)**
178+
**[Join the Discord Server](https://discord.gg/mhwK2QFNBA)**
135179

136180
For bug reports or feature requests, please open an issue in this repository.
137181

docs/wiki/Diagnostics-and-Logging.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,5 +201,5 @@ GridForgeLogger.MinimumLevel = DiagnosticLevel.Warning;
201201
## Read This Next
202202

203203
- [Common Workflows](Common-Workflows.md) for small examples that may benefit from temporary info-level logging
204-
- [Testing and Benchmarking](Testing-and-Benchmarking.md) once that page exists, for validation-focused diagnostics habits
204+
- [Testing and Benchmarking](Testing-and-Benchmarking.md) for validation-focused diagnostics habits
205205
- [Home](Home.md) for the repo-wide invariant that logging should stay centralized

docs/wiki/Home.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ With GridForge as "a world primitive," multiple worlds can exist in the same pro
1515
- Obstacle, blocker, occupant, and partition workflows
1616
- Allocation-conscious internals backed by pooling and `SwiftCollections`
1717
- Cross-target support for `netstandard2.1` and `net8.0`
18+
- Standard and lean package variants for `MemoryPack` and no-`MemoryPack` dependency profiles
1819

1920
## Who This Wiki Is For
2021

@@ -51,7 +52,7 @@ With GridForge as "a world primitive," multiple worlds can exist in the same pro
5152
- Target frameworks: `netstandard2.1`, `net8.0`
5253
- Test framework: xUnit v3
5354
- Benchmark framework: BenchmarkDotNet
54-
- Key packages: `FixedMathSharp`, `SwiftCollections`, `MemoryPack`
55+
- Key packages: `FixedMathSharp`, `SwiftCollections`, and optional `MemoryPack`
5556
- Packaging note: `GeneratePackageOnBuild` is enabled, so library builds also emit NuGet packages
5657

5758
## The Core Mental Model
@@ -69,6 +70,8 @@ The library is easiest to reason about in this order:
6970
The most important architectural reality is that GridForge is world-scoped. If something feels "global," that is usually either:
7071

7172
- state owned by one explicit `GridWorld`
73+
- a static manager API that still requires a `GridWorld` argument
74+
- a convenience layer over world-owned grids, voxels, scan cells, blockers, or occupants
7275

7376
## Architecture At A Glance
7477

docs/wiki/Occupants-and-Partitions.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,9 @@ That is why the occupant system is tightly coupled to scan-cell activation state
112112

113113
## Common Occupant Entry Points
114114

115-
Use `GridOccupantManager.TryRegister(occupant)` when:
115+
Use `GridOccupantManager.TryRegister(world, occupant)` when:
116116

117+
- you have the owning `GridWorld`
117118
- the occupant already knows its world-space `Position`
118119
- you want the manager to resolve the correct grid and voxel automatically
119120

@@ -123,13 +124,14 @@ Use `grid.TryAddVoxelOccupant(...)` overloads when:
123124
- you already know the target `Voxel` or `VoxelIndex`
124125
- you want to avoid repeating global lookup
125126

126-
Use `TryDeregister(...)` or `TryRemoveVoxelOccupant(...)` when:
127+
Use `GridOccupantManager.TryDeregister(world, occupant)` or `TryRemoveVoxelOccupant(...)` when:
127128

129+
- you have the owning `GridWorld`
128130
- cleaning up an entity
129131
- moving an occupant from one voxel to another
130132
- unloading game state tied to a grid
131133

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`.
133135

134136
## The Partition Contract
135137

docs/wiki/Repository-Layout-and-Build.md

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ The root solution file is `GridForge.slnx`.
3030
| `tests/GridForge.Benchmarks` | Focused perf and allocation scenarios |
3131
| `.github/workflows` | CI automation |
3232
| `.assets/scripts` | Release-oriented PowerShell helpers |
33-
| `GridForge.wiki` | GitHub wiki content used as the deeper documentation companion |
33+
| `docs/wiki` | GitHub wiki source content used as the deeper documentation companion |
3434

3535
The solution also exposes a small set of root-level "solution items" such as `.editorconfig`, `README.md`, `AGENTS.md`, `LICENSE`, and `coverlet.runsettings`.
3636

@@ -41,22 +41,31 @@ The library project in `src/GridForge/GridForge.csproj` establishes a few import
4141
- language version is C# 11
4242
- target frameworks are `netstandard2.1` and `net8.0`
4343
- `ImplicitUsings` is disabled
44-
- `Nullable` is disabled
44+
- `Nullable` is enabled in the library project
4545
- XML documentation files are generated
4646
- deterministic and CI build flags are enabled
4747
- `GeneratePackageOnBuild` is enabled
48+
- the supported configurations are `Debug`, `Release`, and `ReleaseLean`
4849

4950
That last item is easy to miss: building the library also produces NuGet artifacts.
5051

5152
## Package And Dependency Notes
5253

53-
The main library currently depends on:
54+
The standard package currently depends on:
5455

5556
- `FixedMathSharp`
5657
- `SwiftCollections`
5758
- `MemoryPack`
5859
- `System.Text.Json` for the `netstandard2.1` target only
5960

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+
6069
Packaging also includes the root `README.md`, `LICENSE`, `NOTICE`, `COPYRIGHT`, and `icon.png`.
6170

6271
## Versioning Behavior
@@ -89,6 +98,7 @@ The test project:
8998
- targets `net8.0`
9099
- is marked as a test project and not packable
91100
- references the main library project directly
101+
- supports `Debug`, `Release`, and `ReleaseLean`
92102
- uses xUnit v3 plus the Visual Studio runner and console runner
93103
- includes `coverlet.collector`
94104
- points to `coverlet.runsettings`
@@ -102,6 +112,7 @@ The benchmark project:
102112
- targets `net8.0`
103113
- is an executable
104114
- references the main library project directly
115+
- supports `Debug`, `Release`, and `ReleaseLean`
105116
- uses BenchmarkDotNet
106117
- is optimized for benchmark runs
107118

@@ -133,12 +144,12 @@ At a high level it:
133144

134145
- runs on `ubuntu-latest` and `windows-latest`
135146
- 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`
137148
- installs .NET 8
138149
- installs and executes GitVersion
139150
- 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`
142153

143154
This is a useful sanity check when deciding whether a change is likely to be cross-platform safe.
144155

@@ -150,9 +161,9 @@ Its flow is:
150161

151162
1. locate the solution root
152163
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`
156167

157168
That makes it the practical handoff script for release packaging, not just a convenience wrapper around `dotnet build`.
158169

0 commit comments

Comments
 (0)