Add CultCache geometry documents

This commit is contained in:
Meta Vens 2026-05-29 23:25:36 +01:00
commit 69ac7b5b4b
7 changed files with 752 additions and 13 deletions

View file

@ -25,61 +25,167 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCult.Networking.Tests",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCult.Caching.Tests", "tests\GameCult.Caching.Tests\GameCult.Caching.Tests.csproj", "{EB15435B-7147-4BD9-BB9C-B0A14318D3D5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCult.Geometry", "src\GameCult.Geometry\GameCult.Geometry.csproj", "{94C086DA-3359-424B-9688-29A198806481}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCult.Geometry.Tests", "tests\GameCult.Geometry.Tests\GameCult.Geometry.Tests.csproj", "{C95A9A21-34FA-4D82-BE5B-88FBDA836D31}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{72AEDD42-E881-4EB7-99A8-FD3B9667189C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{72AEDD42-E881-4EB7-99A8-FD3B9667189C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{72AEDD42-E881-4EB7-99A8-FD3B9667189C}.Debug|x64.ActiveCfg = Debug|Any CPU
{72AEDD42-E881-4EB7-99A8-FD3B9667189C}.Debug|x64.Build.0 = Debug|Any CPU
{72AEDD42-E881-4EB7-99A8-FD3B9667189C}.Debug|x86.ActiveCfg = Debug|Any CPU
{72AEDD42-E881-4EB7-99A8-FD3B9667189C}.Debug|x86.Build.0 = Debug|Any CPU
{72AEDD42-E881-4EB7-99A8-FD3B9667189C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{72AEDD42-E881-4EB7-99A8-FD3B9667189C}.Release|Any CPU.Build.0 = Release|Any CPU
{72AEDD42-E881-4EB7-99A8-FD3B9667189C}.Release|x64.ActiveCfg = Release|Any CPU
{72AEDD42-E881-4EB7-99A8-FD3B9667189C}.Release|x64.Build.0 = Release|Any CPU
{72AEDD42-E881-4EB7-99A8-FD3B9667189C}.Release|x86.ActiveCfg = Release|Any CPU
{72AEDD42-E881-4EB7-99A8-FD3B9667189C}.Release|x86.Build.0 = Release|Any CPU
{9DDA917D-B4DB-4AC1-9B9A-4ECF06A5ABA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9DDA917D-B4DB-4AC1-9B9A-4ECF06A5ABA1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9DDA917D-B4DB-4AC1-9B9A-4ECF06A5ABA1}.Debug|x64.ActiveCfg = Debug|Any CPU
{9DDA917D-B4DB-4AC1-9B9A-4ECF06A5ABA1}.Debug|x64.Build.0 = Debug|Any CPU
{9DDA917D-B4DB-4AC1-9B9A-4ECF06A5ABA1}.Debug|x86.ActiveCfg = Debug|Any CPU
{9DDA917D-B4DB-4AC1-9B9A-4ECF06A5ABA1}.Debug|x86.Build.0 = Debug|Any CPU
{9DDA917D-B4DB-4AC1-9B9A-4ECF06A5ABA1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9DDA917D-B4DB-4AC1-9B9A-4ECF06A5ABA1}.Release|Any CPU.Build.0 = Release|Any CPU
{9DDA917D-B4DB-4AC1-9B9A-4ECF06A5ABA1}.Release|x64.ActiveCfg = Release|Any CPU
{9DDA917D-B4DB-4AC1-9B9A-4ECF06A5ABA1}.Release|x64.Build.0 = Release|Any CPU
{9DDA917D-B4DB-4AC1-9B9A-4ECF06A5ABA1}.Release|x86.ActiveCfg = Release|Any CPU
{9DDA917D-B4DB-4AC1-9B9A-4ECF06A5ABA1}.Release|x86.Build.0 = Release|Any CPU
{26EE4C38-F06E-4E7A-A89C-908318BCB0DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{26EE4C38-F06E-4E7A-A89C-908318BCB0DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{26EE4C38-F06E-4E7A-A89C-908318BCB0DB}.Debug|x64.ActiveCfg = Debug|Any CPU
{26EE4C38-F06E-4E7A-A89C-908318BCB0DB}.Debug|x64.Build.0 = Debug|Any CPU
{26EE4C38-F06E-4E7A-A89C-908318BCB0DB}.Debug|x86.ActiveCfg = Debug|Any CPU
{26EE4C38-F06E-4E7A-A89C-908318BCB0DB}.Debug|x86.Build.0 = Debug|Any CPU
{26EE4C38-F06E-4E7A-A89C-908318BCB0DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{26EE4C38-F06E-4E7A-A89C-908318BCB0DB}.Release|Any CPU.Build.0 = Release|Any CPU
{67383F6C-C9C3-4C5B-95D4-5C50C20EDD4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{67383F6C-C9C3-4C5B-95D4-5C50C20EDD4F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{67383F6C-C9C3-4C5B-95D4-5C50C20EDD4F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{67383F6C-C9C3-4C5B-95D4-5C50C20EDD4F}.Release|Any CPU.Build.0 = Release|Any CPU
{8D1B01A7-BF9E-44E6-88E1-B17255728B42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8D1B01A7-BF9E-44E6-88E1-B17255728B42}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8D1B01A7-BF9E-44E6-88E1-B17255728B42}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8D1B01A7-BF9E-44E6-88E1-B17255728B42}.Release|Any CPU.Build.0 = Release|Any CPU
{E2DC8FF6-D39E-4FCA-9549-1F7681F0AA81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E2DC8FF6-D39E-4FCA-9549-1F7681F0AA81}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E2DC8FF6-D39E-4FCA-9549-1F7681F0AA81}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E2DC8FF6-D39E-4FCA-9549-1F7681F0AA81}.Release|Any CPU.Build.0 = Release|Any CPU
{EB15435B-7147-4BD9-BB9C-B0A14318D3D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EB15435B-7147-4BD9-BB9C-B0A14318D3D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EB15435B-7147-4BD9-BB9C-B0A14318D3D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EB15435B-7147-4BD9-BB9C-B0A14318D3D5}.Release|Any CPU.Build.0 = Release|Any CPU
{26EE4C38-F06E-4E7A-A89C-908318BCB0DB}.Release|x64.ActiveCfg = Release|Any CPU
{26EE4C38-F06E-4E7A-A89C-908318BCB0DB}.Release|x64.Build.0 = Release|Any CPU
{26EE4C38-F06E-4E7A-A89C-908318BCB0DB}.Release|x86.ActiveCfg = Release|Any CPU
{26EE4C38-F06E-4E7A-A89C-908318BCB0DB}.Release|x86.Build.0 = Release|Any CPU
{0E990C96-3808-450E-9349-A0C3262195ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0E990C96-3808-450E-9349-A0C3262195ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0E990C96-3808-450E-9349-A0C3262195ED}.Debug|x64.ActiveCfg = Debug|Any CPU
{0E990C96-3808-450E-9349-A0C3262195ED}.Debug|x64.Build.0 = Debug|Any CPU
{0E990C96-3808-450E-9349-A0C3262195ED}.Debug|x86.ActiveCfg = Debug|Any CPU
{0E990C96-3808-450E-9349-A0C3262195ED}.Debug|x86.Build.0 = Debug|Any CPU
{0E990C96-3808-450E-9349-A0C3262195ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0E990C96-3808-450E-9349-A0C3262195ED}.Release|Any CPU.Build.0 = Release|Any CPU
{0E990C96-3808-450E-9349-A0C3262195ED}.Release|x64.ActiveCfg = Release|Any CPU
{0E990C96-3808-450E-9349-A0C3262195ED}.Release|x64.Build.0 = Release|Any CPU
{0E990C96-3808-450E-9349-A0C3262195ED}.Release|x86.ActiveCfg = Release|Any CPU
{0E990C96-3808-450E-9349-A0C3262195ED}.Release|x86.Build.0 = Release|Any CPU
{DBE06954-EC85-4034-9049-72C7D27556DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DBE06954-EC85-4034-9049-72C7D27556DF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DBE06954-EC85-4034-9049-72C7D27556DF}.Debug|x64.ActiveCfg = Debug|Any CPU
{DBE06954-EC85-4034-9049-72C7D27556DF}.Debug|x64.Build.0 = Debug|Any CPU
{DBE06954-EC85-4034-9049-72C7D27556DF}.Debug|x86.ActiveCfg = Debug|Any CPU
{DBE06954-EC85-4034-9049-72C7D27556DF}.Debug|x86.Build.0 = Debug|Any CPU
{DBE06954-EC85-4034-9049-72C7D27556DF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DBE06954-EC85-4034-9049-72C7D27556DF}.Release|Any CPU.Build.0 = Release|Any CPU
{DBE06954-EC85-4034-9049-72C7D27556DF}.Release|x64.ActiveCfg = Release|Any CPU
{DBE06954-EC85-4034-9049-72C7D27556DF}.Release|x64.Build.0 = Release|Any CPU
{DBE06954-EC85-4034-9049-72C7D27556DF}.Release|x86.ActiveCfg = Release|Any CPU
{DBE06954-EC85-4034-9049-72C7D27556DF}.Release|x86.Build.0 = Release|Any CPU
{67383F6C-C9C3-4C5B-95D4-5C50C20EDD4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{67383F6C-C9C3-4C5B-95D4-5C50C20EDD4F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{67383F6C-C9C3-4C5B-95D4-5C50C20EDD4F}.Debug|x64.ActiveCfg = Debug|Any CPU
{67383F6C-C9C3-4C5B-95D4-5C50C20EDD4F}.Debug|x64.Build.0 = Debug|Any CPU
{67383F6C-C9C3-4C5B-95D4-5C50C20EDD4F}.Debug|x86.ActiveCfg = Debug|Any CPU
{67383F6C-C9C3-4C5B-95D4-5C50C20EDD4F}.Debug|x86.Build.0 = Debug|Any CPU
{67383F6C-C9C3-4C5B-95D4-5C50C20EDD4F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{67383F6C-C9C3-4C5B-95D4-5C50C20EDD4F}.Release|Any CPU.Build.0 = Release|Any CPU
{67383F6C-C9C3-4C5B-95D4-5C50C20EDD4F}.Release|x64.ActiveCfg = Release|Any CPU
{67383F6C-C9C3-4C5B-95D4-5C50C20EDD4F}.Release|x64.Build.0 = Release|Any CPU
{67383F6C-C9C3-4C5B-95D4-5C50C20EDD4F}.Release|x86.ActiveCfg = Release|Any CPU
{67383F6C-C9C3-4C5B-95D4-5C50C20EDD4F}.Release|x86.Build.0 = Release|Any CPU
{8D1B01A7-BF9E-44E6-88E1-B17255728B42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8D1B01A7-BF9E-44E6-88E1-B17255728B42}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8D1B01A7-BF9E-44E6-88E1-B17255728B42}.Debug|x64.ActiveCfg = Debug|Any CPU
{8D1B01A7-BF9E-44E6-88E1-B17255728B42}.Debug|x64.Build.0 = Debug|Any CPU
{8D1B01A7-BF9E-44E6-88E1-B17255728B42}.Debug|x86.ActiveCfg = Debug|Any CPU
{8D1B01A7-BF9E-44E6-88E1-B17255728B42}.Debug|x86.Build.0 = Debug|Any CPU
{8D1B01A7-BF9E-44E6-88E1-B17255728B42}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8D1B01A7-BF9E-44E6-88E1-B17255728B42}.Release|Any CPU.Build.0 = Release|Any CPU
{8D1B01A7-BF9E-44E6-88E1-B17255728B42}.Release|x64.ActiveCfg = Release|Any CPU
{8D1B01A7-BF9E-44E6-88E1-B17255728B42}.Release|x64.Build.0 = Release|Any CPU
{8D1B01A7-BF9E-44E6-88E1-B17255728B42}.Release|x86.ActiveCfg = Release|Any CPU
{8D1B01A7-BF9E-44E6-88E1-B17255728B42}.Release|x86.Build.0 = Release|Any CPU
{E2DC8FF6-D39E-4FCA-9549-1F7681F0AA81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E2DC8FF6-D39E-4FCA-9549-1F7681F0AA81}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E2DC8FF6-D39E-4FCA-9549-1F7681F0AA81}.Debug|x64.ActiveCfg = Debug|Any CPU
{E2DC8FF6-D39E-4FCA-9549-1F7681F0AA81}.Debug|x64.Build.0 = Debug|Any CPU
{E2DC8FF6-D39E-4FCA-9549-1F7681F0AA81}.Debug|x86.ActiveCfg = Debug|Any CPU
{E2DC8FF6-D39E-4FCA-9549-1F7681F0AA81}.Debug|x86.Build.0 = Debug|Any CPU
{E2DC8FF6-D39E-4FCA-9549-1F7681F0AA81}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E2DC8FF6-D39E-4FCA-9549-1F7681F0AA81}.Release|Any CPU.Build.0 = Release|Any CPU
{E2DC8FF6-D39E-4FCA-9549-1F7681F0AA81}.Release|x64.ActiveCfg = Release|Any CPU
{E2DC8FF6-D39E-4FCA-9549-1F7681F0AA81}.Release|x64.Build.0 = Release|Any CPU
{E2DC8FF6-D39E-4FCA-9549-1F7681F0AA81}.Release|x86.ActiveCfg = Release|Any CPU
{E2DC8FF6-D39E-4FCA-9549-1F7681F0AA81}.Release|x86.Build.0 = Release|Any CPU
{EB15435B-7147-4BD9-BB9C-B0A14318D3D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EB15435B-7147-4BD9-BB9C-B0A14318D3D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EB15435B-7147-4BD9-BB9C-B0A14318D3D5}.Debug|x64.ActiveCfg = Debug|Any CPU
{EB15435B-7147-4BD9-BB9C-B0A14318D3D5}.Debug|x64.Build.0 = Debug|Any CPU
{EB15435B-7147-4BD9-BB9C-B0A14318D3D5}.Debug|x86.ActiveCfg = Debug|Any CPU
{EB15435B-7147-4BD9-BB9C-B0A14318D3D5}.Debug|x86.Build.0 = Debug|Any CPU
{EB15435B-7147-4BD9-BB9C-B0A14318D3D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EB15435B-7147-4BD9-BB9C-B0A14318D3D5}.Release|Any CPU.Build.0 = Release|Any CPU
{EB15435B-7147-4BD9-BB9C-B0A14318D3D5}.Release|x64.ActiveCfg = Release|Any CPU
{EB15435B-7147-4BD9-BB9C-B0A14318D3D5}.Release|x64.Build.0 = Release|Any CPU
{EB15435B-7147-4BD9-BB9C-B0A14318D3D5}.Release|x86.ActiveCfg = Release|Any CPU
{EB15435B-7147-4BD9-BB9C-B0A14318D3D5}.Release|x86.Build.0 = Release|Any CPU
{94C086DA-3359-424B-9688-29A198806481}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{94C086DA-3359-424B-9688-29A198806481}.Debug|Any CPU.Build.0 = Debug|Any CPU
{94C086DA-3359-424B-9688-29A198806481}.Debug|x64.ActiveCfg = Debug|Any CPU
{94C086DA-3359-424B-9688-29A198806481}.Debug|x64.Build.0 = Debug|Any CPU
{94C086DA-3359-424B-9688-29A198806481}.Debug|x86.ActiveCfg = Debug|Any CPU
{94C086DA-3359-424B-9688-29A198806481}.Debug|x86.Build.0 = Debug|Any CPU
{94C086DA-3359-424B-9688-29A198806481}.Release|Any CPU.ActiveCfg = Release|Any CPU
{94C086DA-3359-424B-9688-29A198806481}.Release|Any CPU.Build.0 = Release|Any CPU
{94C086DA-3359-424B-9688-29A198806481}.Release|x64.ActiveCfg = Release|Any CPU
{94C086DA-3359-424B-9688-29A198806481}.Release|x64.Build.0 = Release|Any CPU
{94C086DA-3359-424B-9688-29A198806481}.Release|x86.ActiveCfg = Release|Any CPU
{94C086DA-3359-424B-9688-29A198806481}.Release|x86.Build.0 = Release|Any CPU
{C95A9A21-34FA-4D82-BE5B-88FBDA836D31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C95A9A21-34FA-4D82-BE5B-88FBDA836D31}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C95A9A21-34FA-4D82-BE5B-88FBDA836D31}.Debug|x64.ActiveCfg = Debug|Any CPU
{C95A9A21-34FA-4D82-BE5B-88FBDA836D31}.Debug|x64.Build.0 = Debug|Any CPU
{C95A9A21-34FA-4D82-BE5B-88FBDA836D31}.Debug|x86.ActiveCfg = Debug|Any CPU
{C95A9A21-34FA-4D82-BE5B-88FBDA836D31}.Debug|x86.Build.0 = Debug|Any CPU
{C95A9A21-34FA-4D82-BE5B-88FBDA836D31}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C95A9A21-34FA-4D82-BE5B-88FBDA836D31}.Release|Any CPU.Build.0 = Release|Any CPU
{C95A9A21-34FA-4D82-BE5B-88FBDA836D31}.Release|x64.ActiveCfg = Release|Any CPU
{C95A9A21-34FA-4D82-BE5B-88FBDA836D31}.Release|x64.Build.0 = Release|Any CPU
{C95A9A21-34FA-4D82-BE5B-88FBDA836D31}.Release|x86.ActiveCfg = Release|Any CPU
{C95A9A21-34FA-4D82-BE5B-88FBDA836D31}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{72AEDD42-E881-4EB7-99A8-FD3B9667189C} = {E733CBFF-42AE-4B6A-B5B9-0071ECFB45F1}
{9DDA917D-B4DB-4AC1-9B9A-4ECF06A5ABA1} = {E733CBFF-42AE-4B6A-B5B9-0071ECFB45F1}
{26EE4C38-F06E-4E7A-A89C-908318BCB0DB} = {E733CBFF-42AE-4B6A-B5B9-0071ECFB45F1}
{0E990C96-3808-450E-9349-A0C3262195ED} = {E733CBFF-42AE-4B6A-B5B9-0071ECFB45F1}
{DBE06954-EC85-4034-9049-72C7D27556DF} = {E733CBFF-42AE-4B6A-B5B9-0071ECFB45F1}
{67383F6C-C9C3-4C5B-95D4-5C50C20EDD4F} = {E733CBFF-42AE-4B6A-B5B9-0071ECFB45F1}
{8D1B01A7-BF9E-44E6-88E1-B17255728B42} = {E733CBFF-42AE-4B6A-B5B9-0071ECFB45F1}
{E2DC8FF6-D39E-4FCA-9549-1F7681F0AA81} = {39D316AB-ABB5-49A2-8E83-CAF4C75B48F4}
{EB15435B-7147-4BD9-BB9C-B0A14318D3D5} = {39D316AB-ABB5-49A2-8E83-CAF4C75B48F4}
{0E990C96-3808-450E-9349-A0C3262195ED} = {E733CBFF-42AE-4B6A-B5B9-0071ECFB45F1}
{DBE06954-EC85-4034-9049-72C7D27556DF} = {E733CBFF-42AE-4B6A-B5B9-0071ECFB45F1}
{94C086DA-3359-424B-9688-29A198806481} = {E733CBFF-42AE-4B6A-B5B9-0071ECFB45F1}
{C95A9A21-34FA-4D82-BE5B-88FBDA836D31} = {39D316AB-ABB5-49A2-8E83-CAF4C75B48F4}
EndGlobalSection
EndGlobal

View file

@ -8,6 +8,7 @@ The libraries cover three main areas:
- a typed in-memory cache with pluggable persistence
- LiteNetLib-based networking with encrypted credential exchange and signed session tokens
- CultMesh distributed realtime database and simulation-consensus primitives
- typed geometry domain/chunk documents for distributed CSG and LOD streaming
- declarative Unity UI composition and reflective runtime inspector tooling
## Which Package Do I Want?
@ -18,12 +19,15 @@ and pretending the label makes it furniture.
| Job | Start With | Owns | Use When | Do Not Use It For |
| --- | --- | --- | --- | --- |
| Local typed state | `GameCult.Caching` / CultCache | Document identity, schema compatibility, record keys, indexes, globals, and local persistence | You need a typed cache, file-compatible save data, local reactive reads, or a stable domain document model | Peer discovery, transport security, shard routing, or mesh consensus |
| Procedural geometry state | `GameCult.Geometry` | CultCache-native domain trees, LOD build requests, selected-cut diagnostics, and chunk artifact payloads | Rust, Unity, or remote workers need to share CSG/LOD geometry and graph metadata as typed state | Transport policy, peer discovery, or gameplay authority |
| Network transport and database plumbing | `GameCult.Networking` / CultNet | LiteNetLib transport, authentication, schema-v0 wire contracts, shard authority, raw document replication, snapshots, and subscriptions | You need a client/server pipe, login/session flow, schema discovery, or a low-level distributed CultCache lane | Gameplay-facing mesh ergonomics, Verse policy, mod branches, or simulation consensus composition |
| Distributed realtime gameplay state | `GameCult.Mesh` / CultMesh | Public mesh entrypoints, Verse discovery, peer exchange, shard replication defaults, authority leases, client prediction, and witness consensus | You want the game to treat clients and servers as one reactive database for persistent state, input state, and simulation facts | A tiny local-only tool, a bare transport client, or a storage format contract |
Quick rule:
- Choose CultCache when the problem is "how do I model and persist typed state?"
- Choose GameCult.Geometry when the problem is "how do geometry workers share
domain trees, LOD build requests, and mesh chunks as typed state?"
- Choose CultNet when the problem is "how do peers exchange authenticated,
schema-aware database messages?"
- Choose CultMesh when the problem is "how does a game join a Verse and share
@ -51,6 +55,7 @@ The solution includes:
- `GameCult.Caching.NewtonsoftJson`: Newtonsoft.Json-backed persistence for the cache
- `GameCult.Caching.MessagePack.Generator`: source generator for MessagePack formatters for cache models
- `GameCult.Caching.MessagePack.Analyzers`: packaging project that delivers the generator to consuming projects
- `GameCult.Geometry`: CultCache-native geometry domain, selected-cut, and chunk artifact documents for VibeGeometry/Fensalir-style pipelines
- `GameCult.Networking`: encrypted login/register/verify flows and message dispatch over LiteNetLib
- `GameCult.Mesh`: CultMesh package home for distributed realtime database, shard replication, client prediction, Verse discovery, and mesh witness consensus
- `GameCult.Caching.Tests`: NUnit tests for cache and backing-store behavior
@ -67,11 +72,13 @@ src/
GameCult.Caching.NewtonsoftJson/
GameCult.Caching.MessagePack.Generator/
GameCult.Caching.MessagePack.Analyzers/
GameCult.Geometry/
GameCult.Networking/
GameCult.Mesh/
GameCult.Unity/
tests/
GameCult.Caching.Tests/
GameCult.Geometry.Tests/
GameCult.Networking.Tests/
```

View file

@ -0,0 +1,435 @@
using System;
using System.Globalization;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using GameCult.Caching;
using MessagePack;
using static GameCult.Geometry.CultGeometryDocuments;
namespace GameCult.Geometry
{
/// <summary>
/// Schema versions for CultCache-native geometry pipeline documents.
/// </summary>
public static class CultGeometrySchemaVersions
{
public const string Domain = "gamecult.geometry.domain.v1";
public const string BuildRequest = "gamecult.geometry.build_request.v1";
public const string SelectedCut = "gamecult.geometry.selected_cut.v1";
public const string ChunkArtifact = "gamecult.geometry.chunk_artifact.v1";
}
/// <summary>
/// CultCache document containing a hierarchical geometry domain tree.
/// </summary>
[MessagePackObject]
[CultDocument("gamecult.geometry.domain", CultGeometrySchemaVersions.Domain)]
public sealed class CultGeometryDomainDocument
{
[Key(0)]
[CultName]
public string DomainId { get; set; } = string.Empty;
[Key(1)]
[CultIndex]
public string RootKey { get; set; } = string.Empty;
[Key(2)]
public string SourceRuntime { get; set; } = string.Empty;
[Key(3)]
public CultGeometryDomainNode Root { get; set; } = new CultGeometryDomainNode();
[Key(4)]
public string CreatedAt { get; set; } = string.Empty;
public static CultRecordKey CreateRecordKey(CultGeometryDomainDocument domain)
{
if (domain == null) throw new ArgumentNullException(nameof(domain));
return new CultRecordKey("geometry:domain:" + StableHash(
domain.RootKey,
domain.SourceRuntime,
domain.Root.StableFingerprint()));
}
}
/// <summary>
/// One node in a geometry domain tree.
/// </summary>
[MessagePackObject]
public sealed class CultGeometryDomainNode
{
[Key(0)]
public string Name { get; set; } = string.Empty;
[Key(1)]
public string Kind { get; set; } = string.Empty;
[Key(2)]
public float[] Translation { get; set; } = Array.Empty<float>();
[Key(3)]
public float[] RotationXyzw { get; set; } = Array.Empty<float>();
[Key(4)]
public ulong Seed { get; set; }
[Key(5)]
public CultGeometryFeatureClaim[] Claims { get; set; } = Array.Empty<CultGeometryFeatureClaim>();
[Key(6)]
public CultGeometryDomainNode[] Children { get; set; } = Array.Empty<CultGeometryDomainNode>();
public string StableFingerprint()
{
var builder = new StringBuilder()
.Append(Name).Append('\u001f')
.Append(Kind).Append('\u001f')
.Append(Seed.ToString(CultureInfo.InvariantCulture)).Append('\u001f')
.AppendVector(Translation).Append('\u001f')
.AppendVector(RotationXyzw);
foreach (var claim in Claims)
{
builder.Append('\u001e').Append(claim.StableFingerprint());
}
foreach (var child in Children)
{
builder.Append('\u001d').Append(child.StableFingerprint());
}
return builder.ToString();
}
}
/// <summary>
/// A domain feature claim before CSG lowering.
/// </summary>
[MessagePackObject]
public sealed class CultGeometryFeatureClaim
{
[Key(0)]
public string Name { get; set; } = string.Empty;
[Key(1)]
public float[] Translation { get; set; } = Array.Empty<float>();
[Key(2)]
public float[] RotationXyzw { get; set; } = Array.Empty<float>();
[Key(3)]
public float[] SupportCenter { get; set; } = Array.Empty<float>();
[Key(4)]
public float[] SupportSize { get; set; } = Array.Empty<float>();
[Key(5)]
public string Kind { get; set; } = string.Empty;
[Key(6)]
public uint Material { get; set; }
[Key(7)]
public string LoweringPolicy { get; set; } = string.Empty;
public string StableFingerprint() => new StringBuilder()
.Append(Name).Append('\u001f')
.Append(Kind).Append('\u001f')
.Append(Material.ToString(CultureInfo.InvariantCulture)).Append('\u001f')
.Append(LoweringPolicy).Append('\u001f')
.AppendVector(Translation).Append('\u001f')
.AppendVector(RotationXyzw).Append('\u001f')
.AppendVector(SupportCenter).Append('\u001f')
.AppendVector(SupportSize)
.ToString();
}
/// <summary>
/// CultCache document requesting one geometry LOD build.
/// </summary>
[MessagePackObject]
[CultDocument("gamecult.geometry.build_request", CultGeometrySchemaVersions.BuildRequest)]
public sealed class CultGeometryBuildRequest
{
[Key(0)]
[CultName]
public string RequestId { get; set; } = string.Empty;
[Key(1)]
[CultReference(typeof(CultGeometryDomainDocument))]
public string DomainKey { get; set; } = string.Empty;
[Key(2)]
[CultIndex]
public string WorkerGroup { get; set; } = string.Empty;
[Key(3)]
public float[] CameraPosition { get; set; } = Array.Empty<float>();
[Key(4)]
public float[] FrustumMin { get; set; } = Array.Empty<float>();
[Key(5)]
public float[] FrustumMax { get; set; } = Array.Empty<float>();
[Key(6)]
public float ViewportHeightPixels { get; set; }
[Key(7)]
public float VerticalFovRadians { get; set; }
[Key(8)]
public float TargetError { get; set; }
[Key(9)]
public int TriangleBudget { get; set; }
[Key(10)]
public int ColliderBudget { get; set; }
[Key(11)]
public string[] SemanticFilter { get; set; } = Array.Empty<string>();
[Key(12)]
public string[] RequestedChunkKeys { get; set; } = Array.Empty<string>();
[Key(13)]
public string[] DirtyDomainKeys { get; set; } = Array.Empty<string>();
[Key(14)]
public string CreatedAt { get; set; } = string.Empty;
public static CultRecordKey CreateRecordKey(CultGeometryBuildRequest request)
{
if (request == null) throw new ArgumentNullException(nameof(request));
return new CultRecordKey("geometry:request:" + StableHash(
request.DomainKey,
request.WorkerGroup,
StableVector(request.CameraPosition),
StableVector(request.FrustumMin),
StableVector(request.FrustumMax),
request.ViewportHeightPixels.ToString("R", CultureInfo.InvariantCulture),
request.VerticalFovRadians.ToString("R", CultureInfo.InvariantCulture),
request.TargetError.ToString("R", CultureInfo.InvariantCulture),
request.TriangleBudget.ToString(CultureInfo.InvariantCulture),
request.ColliderBudget.ToString(CultureInfo.InvariantCulture),
StableArray(request.SemanticFilter),
StableArray(request.RequestedChunkKeys),
StableArray(request.DirtyDomainKeys)));
}
}
/// <summary>
/// CultCache document describing the selected domain cut produced for one build request.
/// </summary>
[MessagePackObject]
[CultDocument("gamecult.geometry.selected_cut", CultGeometrySchemaVersions.SelectedCut)]
public sealed class CultGeometrySelectedCutManifest
{
[Key(0)]
[CultName]
public string CutId { get; set; } = string.Empty;
[Key(1)]
[CultReference(typeof(CultGeometryBuildRequest))]
public string RequestKey { get; set; } = string.Empty;
[Key(2)]
public string[] SelectedNodes { get; set; } = Array.Empty<string>();
[Key(3)]
public string[] DeferredChildRequests { get; set; } = Array.Empty<string>();
[Key(4)]
public string[] ParentFallbackNodes { get; set; } = Array.Empty<string>();
[Key(5)]
public CultGeometryContributionRow[] Diagnostics { get; set; } = Array.Empty<CultGeometryContributionRow>();
public static CultRecordKey CreateRecordKey(CultGeometrySelectedCutManifest cut)
{
if (cut == null) throw new ArgumentNullException(nameof(cut));
return new CultRecordKey("geometry:cut:" + StableHash(
cut.RequestKey,
cut.CutId,
StableArray(cut.SelectedNodes),
StableArray(cut.DeferredChildRequests),
StableArray(cut.ParentFallbackNodes)));
}
}
/// <summary>
/// One diagnostic row explaining selected-cut pressure.
/// </summary>
[MessagePackObject]
public sealed class CultGeometryContributionRow
{
[Key(0)]
public string DomainKey { get; set; } = string.Empty;
[Key(1)]
public string Kind { get; set; } = string.Empty;
[Key(2)]
public float Contribution { get; set; }
[Key(3)]
public float ProjectedScreenError { get; set; }
[Key(4)]
public float SemanticPriority { get; set; }
[Key(5)]
public int EstimatedTriangleCost { get; set; }
[Key(6)]
public int ChildCost { get; set; }
[Key(7)]
public int RemainingTriangleBudget { get; set; }
[Key(8)]
public bool Requested { get; set; }
[Key(9)]
public bool Dirty { get; set; }
[Key(10)]
public bool Selected { get; set; }
[Key(11)]
public bool UsedFallback { get; set; }
[Key(12)]
public bool DeferredByBudget { get; set; }
}
/// <summary>
/// CultCache document carrying one emitted geometry chunk and its collider payload.
/// </summary>
[MessagePackObject]
[CultDocument("gamecult.geometry.chunk_artifact", CultGeometrySchemaVersions.ChunkArtifact)]
public sealed class CultGeometryChunkArtifact
{
[Key(0)]
[CultName]
public string ChunkId { get; set; } = string.Empty;
[Key(1)]
[CultReference(typeof(CultGeometrySelectedCutManifest))]
public string CutKey { get; set; } = string.Empty;
[Key(2)]
[CultIndex]
public string SelectedCutId { get; set; } = string.Empty;
[Key(3)]
public float[] BoundsMin { get; set; } = Array.Empty<float>();
[Key(4)]
public float[] BoundsMax { get; set; } = Array.Empty<float>();
[Key(5)]
public string[] SourceDomainKeys { get; set; } = Array.Empty<string>();
[Key(6)]
public string[] SourceClaimKeys { get; set; } = Array.Empty<string>();
[Key(7)]
public CultGeometryTriangleMesh RenderMesh { get; set; } = new CultGeometryTriangleMesh();
[Key(8)]
public CultGeometryTriangleMesh? ColliderMesh { get; set; }
[Key(9)]
public int InputBrushes { get; set; }
[Key(10)]
public int CandidatePairs { get; set; }
[Key(11)]
public int RejectedPairs { get; set; }
[Key(12)]
public ulong StableClipSeed { get; set; }
[Key(13)]
public bool SupportsParentChildCoexistence { get; set; }
public static CultRecordKey CreateRecordKey(CultGeometryChunkArtifact chunk)
{
if (chunk == null) throw new ArgumentNullException(nameof(chunk));
return new CultRecordKey("geometry:chunk:" + StableHash(
chunk.CutKey,
chunk.ChunkId,
chunk.SelectedCutId,
StableArray(chunk.SourceDomainKeys),
StableArray(chunk.SourceClaimKeys),
chunk.RenderMesh.StableFingerprint(),
chunk.ColliderMesh?.StableFingerprint() ?? string.Empty));
}
}
/// <summary>
/// Packed triangle mesh payload for CultCache persistence and CultNet replication.
/// </summary>
[MessagePackObject]
public sealed class CultGeometryTriangleMesh
{
[Key(0)]
public float[] Positions { get; set; } = Array.Empty<float>();
[Key(1)]
public float[] Normals { get; set; } = Array.Empty<float>();
[Key(2)]
public float[] Uvs { get; set; } = Array.Empty<float>();
[Key(3)]
public uint[] Indices { get; set; } = Array.Empty<uint>();
[Key(4)]
public uint[] TriangleMaterials { get; set; } = Array.Empty<uint>();
[IgnoreMember]
public int TriangleCount => Indices.Length / 3;
public string StableFingerprint() => StableHash(
StableVector(Positions),
StableVector(Normals),
StableVector(Uvs),
string.Join(",", Indices.Select(value => value.ToString(CultureInfo.InvariantCulture))),
string.Join(",", TriangleMaterials.Select(value => value.ToString(CultureInfo.InvariantCulture))));
}
internal static class CultGeometryDocuments
{
public static string StableHash(params string[] parts)
{
using var sha = SHA256.Create();
var canonical = string.Join("\u001f", parts);
var bytes = sha.ComputeHash(Encoding.UTF8.GetBytes(canonical));
return string.Concat(bytes.Select(value => value.ToString("x2")));
}
public static string StableVector(float[] values)
{
return string.Join(",", values.Select(value => value.ToString("R", CultureInfo.InvariantCulture)));
}
public static string StableArray(string[] values)
{
return string.Join("\u001e", values);
}
}
internal static class CultGeometryStringBuilderExtensions
{
public static StringBuilder AppendVector(this StringBuilder builder, float[] values)
{
builder.Append(StableVector(values));
return builder;
}
}
}

View file

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>Typed CultCache geometry domain and chunk artifact documents for VibeGeometry and Fensalir</Description>
<PackageId>GameCult.Geometry</PackageId>
<PackageTags>game;geometry;csg;lod;cultcache;cultmesh;vibegeometry;fensalir</PackageTags>
<PackageReadmeFile>README.md</PackageReadmeFile>
<NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\GameCult.Caching\GameCult.Caching.csproj" />
<PackageReference Include="MessagePack" Version="3.1.4" />
</ItemGroup>
<ItemGroup>
<None Include="README.md" Pack="true" PackagePath="\" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,16 @@
# GameCult.Geometry
`GameCult.Geometry` defines CultCache-native documents for procedural geometry
domains, LOD build requests, selected-cut manifests, and mesh chunk artifacts.
The package is deliberately substrate-shaped:
- CultCache owns document identity, schema compatibility, references, and local
persistence.
- CultNet can distribute these documents through the normal raw document lane.
- CultMesh can use them as worker-visible shared state for simulation and
geometry pipelines.
- JSON is not a runtime transport here. It may publish schema descriptions at
the xeno boundary, but the live machine eats and emits typed CultCache
documents.

View file

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<IsPackable>false</IsPackable>
<RootNamespace>GameCult.Geometry.Tests</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\GameCult.Caching.MessagePack\GameCult.Caching.MessagePack.csproj" />
<ProjectReference Include="..\..\src\GameCult.Geometry\GameCult.Geometry.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="NUnit" Version="4.*" />
<PackageReference Include="NUnit3TestAdapter" Version="6.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.4.0" />
<PackageReference Include="FluentAssertions" Version="8.9.0" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,138 @@
using FluentAssertions;
using GameCult.Caching;
using GameCult.Caching.MessagePack;
using NUnit.Framework;
namespace GameCult.Geometry.Tests
{
public sealed class GeometryDocumentTests
{
[Test]
public void GeometryDocuments_Register_AsCultCacheSchemas()
{
var cache = new CultCache();
cache.Registry.GetRequired<CultGeometryDomainDocument>().SchemaVersion
.Should().Be(CultGeometrySchemaVersions.Domain);
cache.Registry.GetRequired<CultGeometryBuildRequest>().SchemaVersion
.Should().Be(CultGeometrySchemaVersions.BuildRequest);
cache.Registry.GetRequired<CultGeometrySelectedCutManifest>().SchemaVersion
.Should().Be(CultGeometrySchemaVersions.SelectedCut);
cache.Registry.GetRequired<CultGeometryChunkArtifact>().SchemaVersion
.Should().Be(CultGeometrySchemaVersions.ChunkArtifact);
}
[Test]
public void GeometryBuildRequest_UsesStableCultCacheKey()
{
var domain = SampleDomain();
var domainKey = CultGeometryDomainDocument.CreateRecordKey(domain);
var request = new CultGeometryBuildRequest
{
DomainKey = domainKey.Value,
WorkerGroup = "ragnarok-column-workers",
CameraPosition = [36f, -42f, 30f],
FrustumMin = [-75f, -75f, -30f],
FrustumMax = [75f, 75f, 120f],
ViewportHeightPixels = 1080f,
VerticalFovRadians = 1.0471976f,
TargetError = 0.01f,
TriangleBudget = 10_000,
ColliderBudget = 10_000,
SemanticFilter = [],
RequestedChunkKeys = [],
DirtyDomainKeys = []
};
var first = CultGeometryBuildRequest.CreateRecordKey(request);
var second = CultGeometryBuildRequest.CreateRecordKey(request);
request.TriangleBudget++;
var changed = CultGeometryBuildRequest.CreateRecordKey(request);
second.Should().Be(first);
changed.Should().NotBe(first);
first.Value.Should().StartWith("geometry:request:");
}
[Test]
public void ChunkArtifact_RoundTrips_ThroughCultCacheMessagePack()
{
var chunk = new CultGeometryChunkArtifact
{
ChunkId = "chunk/ragnarok-column/column-00",
CutKey = "geometry:cut:test",
SelectedCutId = "cut-test",
BoundsMin = [-1f, -1f, 0f],
BoundsMax = [1f, 1f, 1f],
SourceDomainKeys = ["ragnarok-column/stellarator-column-00"],
SourceClaimKeys = ["ragnarok-column/stellarator-column-00/claim/support"],
RenderMesh = new CultGeometryTriangleMesh
{
Positions = [0f, 0f, 0f, 1f, 0f, 0f, 0f, 1f, 0f],
Normals = [0f, 0f, 1f, 0f, 0f, 1f, 0f, 0f, 1f],
Uvs = [0f, 0f, 1f, 0f, 0f, 1f],
Indices = [0u, 1u, 2u],
TriangleMaterials = [20u]
},
ColliderMesh = null,
InputBrushes = 1,
StableClipSeed = 1234,
SupportsParentChildCoexistence = true
};
var payload = CultDocumentMessagePackSerialization.Serialize(chunk);
var decoded = CultDocumentMessagePackSerialization.Deserialize<CultGeometryChunkArtifact>(payload);
decoded.ChunkId.Should().Be(chunk.ChunkId);
decoded.RenderMesh.TriangleCount.Should().Be(1);
CultGeometryChunkArtifact.CreateRecordKey(decoded)
.Should().Be(CultGeometryChunkArtifact.CreateRecordKey(chunk));
}
private static CultGeometryDomainDocument SampleDomain()
{
return new CultGeometryDomainDocument
{
DomainId = "ragnarok-column",
RootKey = "ragnarok-column",
SourceRuntime = "vg-csg",
CreatedAt = "2026-05-29T00:00:00.0000000Z",
Root = new CultGeometryDomainNode
{
Name = "ragnarok-column",
Kind = "Root",
Translation = [0f, 0f, 0f],
RotationXyzw = [0f, 0f, 0f, 1f],
Seed = 0x5EED,
Claims = [],
Children =
[
new CultGeometryDomainNode
{
Name = "stellarator-column-00",
Kind = "Column",
Translation = [0f, 0f, 0f],
RotationXyzw = [0f, 0f, 0f, 1f],
Seed = 0xC0110000,
Claims =
[
new CultGeometryFeatureClaim
{
Name = "column-support-shell",
Translation = [0f, 0f, 0f],
RotationXyzw = [0f, 0f, 0f, 1f],
SupportCenter = [0f, 0f, 45f],
SupportSize = [18f, 18f, 96f],
Kind = "SupportShell",
Material = 10,
LoweringPolicy = "RenderAndCollider"
}
],
Children = []
}
]
}
};
}
}
}