From 38b79a8d897ac5e2f3b3b24313a051b8b9a47a30 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Fri, 8 May 2026 01:49:44 +0100 Subject: [PATCH 001/283] Seed HLSL-shaped math library --- .gitignore | 7 ++ CultMath.slnx | 8 ++ README.md | 43 ++++++++ docs/design.md | 21 ++++ global.json | 6 ++ src/CultMath/CultMath.csproj | 21 ++++ src/CultMath/float2.cs | 26 +++++ src/CultMath/float3.cs | 31 ++++++ src/CultMath/float4.cs | 31 ++++++ src/CultMath/math.cs | 114 +++++++++++++++++++++ tests/CultMath.Tests/CultMath.Tests.csproj | 20 ++++ tests/CultMath.Tests/MathTests.cs | 38 +++++++ 12 files changed, 366 insertions(+) create mode 100644 .gitignore create mode 100644 CultMath.slnx create mode 100644 README.md create mode 100644 docs/design.md create mode 100644 global.json create mode 100644 src/CultMath/CultMath.csproj create mode 100644 src/CultMath/float2.cs create mode 100644 src/CultMath/float3.cs create mode 100644 src/CultMath/float4.cs create mode 100644 src/CultMath/math.cs create mode 100644 tests/CultMath.Tests/CultMath.Tests.csproj create mode 100644 tests/CultMath.Tests/MathTests.cs diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..59e67361 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +**/bin/ +**/obj/ +artifacts/ +*.user +*.suo +.vs/ +.idea/ diff --git a/CultMath.slnx b/CultMath.slnx new file mode 100644 index 00000000..95834573 --- /dev/null +++ b/CultMath.slnx @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/README.md b/README.md new file mode 100644 index 00000000..c3b1809d --- /dev/null +++ b/README.md @@ -0,0 +1,43 @@ +# CultMath + +Clean-room C# math shaped for people who think in HLSL. + +CultMath provides lowercase vector types and shader-style intrinsics so +math-heavy renderer code can move between C# and HLSL without turning every +line into a translation exercise. It is not a Unity.Mathematics clone. It is a +small, Aquarium-born library built from public shader semantics and plain .NET. + +## Current Surface + +- `float2`, `float3`, `float4` +- component-wise arithmetic +- scalar-to-vector splats +- swizzles for common lanes +- conversions to and from `System.Numerics` +- `math` intrinsics: `radians`, `degrees`, `abs`, `floor`, `ceil`, `frac`, + `min`, `max`, `clamp`, `saturate`, `lerp`, `step`, `smoothstep`, `dot`, + `cross`, `length`, `distance`, `normalize`, and `reflect` + +## Example + +```csharp +using CultMath; + +float3 normal = math.normalize(new float3(0.25f, 1.0f, -0.1f)); +float rim = math.saturate(1.0f - math.dot(normal, new float3(0.0f, 0.0f, -1.0f))); +float glow = math.smoothstep(0.2f, 1.0f, rim); +``` + +## Build + +```powershell +dotnet build CultMath.slnx +dotnet test CultMath.slnx +``` + +## Doctrine + +The goal is mechanical sympathy between CPU-side authoring and GPU-side shader +math. If an intrinsic exists here, it should behave like the shader concept +unless .NET numeric rules make that impossible. Weird deviations get tests and +documentation, not folklore. diff --git a/docs/design.md b/docs/design.md new file mode 100644 index 00000000..62102739 --- /dev/null +++ b/docs/design.md @@ -0,0 +1,21 @@ +# Design + +CultMath exists to make renderer math readable in both places it needs to live: +C# host code and HLSL shader code. + +## Rules + +- Keep type names HLSL-shaped: `float2`, `float3`, `float4`, and `math`. +- Implement public shader semantics directly; do not copy Unity.Mathematics. +- Prefer small immutable value types. +- Prefer component-wise overloads over clever generic machinery until the API + earns that complexity. +- Keep the first surface boring and exact. Noise, matrices, quaternions, and + packing helpers come later. + +## Non-Goals + +- Compiling C# to shaders. +- Replacing `System.Numerics` for general .NET work. +- Recreating every Unity.Mathematics type because a spreadsheet somewhere says + “coverage.” That way lies decorative obesity. diff --git a/global.json b/global.json new file mode 100644 index 00000000..99b1511d --- /dev/null +++ b/global.json @@ -0,0 +1,6 @@ +{ + "sdk": { + "version": "10.0.202", + "rollForward": "latestFeature" + } +} diff --git a/src/CultMath/CultMath.csproj b/src/CultMath/CultMath.csproj new file mode 100644 index 00000000..f06b8bed --- /dev/null +++ b/src/CultMath/CultMath.csproj @@ -0,0 +1,21 @@ + + + + net8.0 + enable + enable + CultMath + CultMath + CultMath + Clean-room C# math shaped for HLSL-style renderer code. + GameCult + https://github.com/GameCult/CultMath + README.md + $(NoWarn);CS8981 + + + + + + + diff --git a/src/CultMath/float2.cs b/src/CultMath/float2.cs new file mode 100644 index 00000000..1f1d66b1 --- /dev/null +++ b/src/CultMath/float2.cs @@ -0,0 +1,26 @@ +namespace CultMath; + +public readonly record struct float2(float x, float y) +{ + public static readonly float2 zero = new(0.0f, 0.0f); + public static readonly float2 one = new(1.0f, 1.0f); + + public float this[int index] => index switch + { + 0 => x, + 1 => y, + _ => throw new ArgumentOutOfRangeException(nameof(index)), + }; + + public static implicit operator float2(float value) => new(value, value); + public static explicit operator System.Numerics.Vector2(float2 value) => new(value.x, value.y); + public static explicit operator float2(System.Numerics.Vector2 value) => new(value.X, value.Y); + + public static float2 operator +(float2 value) => value; + public static float2 operator -(float2 value) => new(-value.x, -value.y); + public static float2 operator +(float2 left, float2 right) => new(left.x + right.x, left.y + right.y); + public static float2 operator -(float2 left, float2 right) => new(left.x - right.x, left.y - right.y); + public static float2 operator *(float2 left, float2 right) => new(left.x * right.x, left.y * right.y); + public static float2 operator /(float2 left, float2 right) => new(left.x / right.x, left.y / right.y); + public static float2 operator %(float2 left, float2 right) => new(left.x % right.x, left.y % right.y); +} diff --git a/src/CultMath/float3.cs b/src/CultMath/float3.cs new file mode 100644 index 00000000..037e8838 --- /dev/null +++ b/src/CultMath/float3.cs @@ -0,0 +1,31 @@ +namespace CultMath; + +public readonly record struct float3(float x, float y, float z) +{ + public static readonly float3 zero = new(0.0f, 0.0f, 0.0f); + public static readonly float3 one = new(1.0f, 1.0f, 1.0f); + + public float2 xy => new(x, y); + public float2 xz => new(x, z); + public float2 yz => new(y, z); + + public float this[int index] => index switch + { + 0 => x, + 1 => y, + 2 => z, + _ => throw new ArgumentOutOfRangeException(nameof(index)), + }; + + public static implicit operator float3(float value) => new(value, value, value); + public static explicit operator System.Numerics.Vector3(float3 value) => new(value.x, value.y, value.z); + public static explicit operator float3(System.Numerics.Vector3 value) => new(value.X, value.Y, value.Z); + + public static float3 operator +(float3 value) => value; + public static float3 operator -(float3 value) => new(-value.x, -value.y, -value.z); + public static float3 operator +(float3 left, float3 right) => new(left.x + right.x, left.y + right.y, left.z + right.z); + public static float3 operator -(float3 left, float3 right) => new(left.x - right.x, left.y - right.y, left.z - right.z); + public static float3 operator *(float3 left, float3 right) => new(left.x * right.x, left.y * right.y, left.z * right.z); + public static float3 operator /(float3 left, float3 right) => new(left.x / right.x, left.y / right.y, left.z / right.z); + public static float3 operator %(float3 left, float3 right) => new(left.x % right.x, left.y % right.y, left.z % right.z); +} diff --git a/src/CultMath/float4.cs b/src/CultMath/float4.cs new file mode 100644 index 00000000..d9ec0982 --- /dev/null +++ b/src/CultMath/float4.cs @@ -0,0 +1,31 @@ +namespace CultMath; + +public readonly record struct float4(float x, float y, float z, float w) +{ + public static readonly float4 zero = new(0.0f, 0.0f, 0.0f, 0.0f); + public static readonly float4 one = new(1.0f, 1.0f, 1.0f, 1.0f); + + public float2 xy => new(x, y); + public float3 xyz => new(x, y, z); + + public float this[int index] => index switch + { + 0 => x, + 1 => y, + 2 => z, + 3 => w, + _ => throw new ArgumentOutOfRangeException(nameof(index)), + }; + + public static implicit operator float4(float value) => new(value, value, value, value); + public static explicit operator System.Numerics.Vector4(float4 value) => new(value.x, value.y, value.z, value.w); + public static explicit operator float4(System.Numerics.Vector4 value) => new(value.X, value.Y, value.Z, value.W); + + public static float4 operator +(float4 value) => value; + public static float4 operator -(float4 value) => new(-value.x, -value.y, -value.z, -value.w); + public static float4 operator +(float4 left, float4 right) => new(left.x + right.x, left.y + right.y, left.z + right.z, left.w + right.w); + public static float4 operator -(float4 left, float4 right) => new(left.x - right.x, left.y - right.y, left.z - right.z, left.w - right.w); + public static float4 operator *(float4 left, float4 right) => new(left.x * right.x, left.y * right.y, left.z * right.z, left.w * right.w); + public static float4 operator /(float4 left, float4 right) => new(left.x / right.x, left.y / right.y, left.z / right.z, left.w / right.w); + public static float4 operator %(float4 left, float4 right) => new(left.x % right.x, left.y % right.y, left.z % right.z, left.w % right.w); +} diff --git a/src/CultMath/math.cs b/src/CultMath/math.cs new file mode 100644 index 00000000..6b0cf455 --- /dev/null +++ b/src/CultMath/math.cs @@ -0,0 +1,114 @@ +namespace CultMath; + +public static class math +{ + public const float PI = MathF.PI; + public const float TAU = MathF.PI * 2.0f; + public const float HALF_PI = MathF.PI * 0.5f; + + public static float radians(float degrees) => degrees * (PI / 180.0f); + public static float degrees(float radians) => radians * (180.0f / PI); + + public static float abs(float value) => MathF.Abs(value); + public static float2 abs(float2 value) => new(abs(value.x), abs(value.y)); + public static float3 abs(float3 value) => new(abs(value.x), abs(value.y), abs(value.z)); + public static float4 abs(float4 value) => new(abs(value.x), abs(value.y), abs(value.z), abs(value.w)); + + public static float floor(float value) => MathF.Floor(value); + public static float2 floor(float2 value) => new(floor(value.x), floor(value.y)); + public static float3 floor(float3 value) => new(floor(value.x), floor(value.y), floor(value.z)); + public static float4 floor(float4 value) => new(floor(value.x), floor(value.y), floor(value.z), floor(value.w)); + + public static float ceil(float value) => MathF.Ceiling(value); + public static float2 ceil(float2 value) => new(ceil(value.x), ceil(value.y)); + public static float3 ceil(float3 value) => new(ceil(value.x), ceil(value.y), ceil(value.z)); + public static float4 ceil(float4 value) => new(ceil(value.x), ceil(value.y), ceil(value.z), ceil(value.w)); + + public static float frac(float value) => value - floor(value); + public static float2 frac(float2 value) => value - floor(value); + public static float3 frac(float3 value) => value - floor(value); + public static float4 frac(float4 value) => value - floor(value); + + public static float min(float left, float right) => MathF.Min(left, right); + public static float2 min(float2 left, float2 right) => new(min(left.x, right.x), min(left.y, right.y)); + public static float3 min(float3 left, float3 right) => new(min(left.x, right.x), min(left.y, right.y), min(left.z, right.z)); + public static float4 min(float4 left, float4 right) => new(min(left.x, right.x), min(left.y, right.y), min(left.z, right.z), min(left.w, right.w)); + + public static float max(float left, float right) => MathF.Max(left, right); + public static float2 max(float2 left, float2 right) => new(max(left.x, right.x), max(left.y, right.y)); + public static float3 max(float3 left, float3 right) => new(max(left.x, right.x), max(left.y, right.y), max(left.z, right.z)); + public static float4 max(float4 left, float4 right) => new(max(left.x, right.x), max(left.y, right.y), max(left.z, right.z), max(left.w, right.w)); + + public static float clamp(float value, float minimum, float maximum) => min(max(value, minimum), maximum); + public static float2 clamp(float2 value, float2 minimum, float2 maximum) => min(max(value, minimum), maximum); + public static float3 clamp(float3 value, float3 minimum, float3 maximum) => min(max(value, minimum), maximum); + public static float4 clamp(float4 value, float4 minimum, float4 maximum) => min(max(value, minimum), maximum); + + public static float saturate(float value) => clamp(value, 0.0f, 1.0f); + public static float2 saturate(float2 value) => clamp(value, 0.0f, 1.0f); + public static float3 saturate(float3 value) => clamp(value, 0.0f, 1.0f); + public static float4 saturate(float4 value) => clamp(value, 0.0f, 1.0f); + + public static float lerp(float start, float end, float amount) => start + (end - start) * amount; + public static float2 lerp(float2 start, float2 end, float2 amount) => start + (end - start) * amount; + public static float3 lerp(float3 start, float3 end, float3 amount) => start + (end - start) * amount; + public static float4 lerp(float4 start, float4 end, float4 amount) => start + (end - start) * amount; + + public static float step(float edge, float value) => value < edge ? 0.0f : 1.0f; + public static float2 step(float2 edge, float2 value) => new(step(edge.x, value.x), step(edge.y, value.y)); + public static float3 step(float3 edge, float3 value) => new(step(edge.x, value.x), step(edge.y, value.y), step(edge.z, value.z)); + public static float4 step(float4 edge, float4 value) => new(step(edge.x, value.x), step(edge.y, value.y), step(edge.z, value.z), step(edge.w, value.w)); + + public static float smoothstep(float minimum, float maximum, float value) + { + var t = saturate((value - minimum) / (maximum - minimum)); + return t * t * (3.0f - 2.0f * t); + } + + public static float2 smoothstep(float2 minimum, float2 maximum, float2 value) + { + var t = saturate((value - minimum) / (maximum - minimum)); + return t * t * (3.0f - 2.0f * t); + } + + public static float3 smoothstep(float3 minimum, float3 maximum, float3 value) + { + var t = saturate((value - minimum) / (maximum - minimum)); + return t * t * (3.0f - 2.0f * t); + } + + public static float4 smoothstep(float4 minimum, float4 maximum, float4 value) + { + var t = saturate((value - minimum) / (maximum - minimum)); + return t * t * (3.0f - 2.0f * t); + } + + public static float dot(float2 left, float2 right) => left.x * right.x + left.y * right.y; + public static float dot(float3 left, float3 right) => left.x * right.x + left.y * right.y + left.z * right.z; + public static float dot(float4 left, float4 right) => left.x * right.x + left.y * right.y + left.z * right.z + left.w * right.w; + + public static float3 cross(float3 left, float3 right) => + new( + left.y * right.z - left.z * right.y, + left.z * right.x - left.x * right.z, + left.x * right.y - left.y * right.x); + + public static float lengthsq(float2 value) => dot(value, value); + public static float lengthsq(float3 value) => dot(value, value); + public static float lengthsq(float4 value) => dot(value, value); + + public static float length(float2 value) => MathF.Sqrt(lengthsq(value)); + public static float length(float3 value) => MathF.Sqrt(lengthsq(value)); + public static float length(float4 value) => MathF.Sqrt(lengthsq(value)); + + public static float distance(float2 left, float2 right) => length(left - right); + public static float distance(float3 left, float3 right) => length(left - right); + public static float distance(float4 left, float4 right) => length(left - right); + + public static float2 normalize(float2 value) => value / MathF.Max(length(value), 1.0e-20f); + public static float3 normalize(float3 value) => value / MathF.Max(length(value), 1.0e-20f); + public static float4 normalize(float4 value) => value / MathF.Max(length(value), 1.0e-20f); + + public static float2 reflect(float2 incident, float2 normal) => incident - 2.0f * dot(normal, incident) * normal; + public static float3 reflect(float3 incident, float3 normal) => incident - 2.0f * dot(normal, incident) * normal; +} diff --git a/tests/CultMath.Tests/CultMath.Tests.csproj b/tests/CultMath.Tests/CultMath.Tests.csproj new file mode 100644 index 00000000..1e77eba1 --- /dev/null +++ b/tests/CultMath.Tests/CultMath.Tests.csproj @@ -0,0 +1,20 @@ + + + + net10.0 + enable + enable + false + + + + + + + + + + + + + diff --git a/tests/CultMath.Tests/MathTests.cs b/tests/CultMath.Tests/MathTests.cs new file mode 100644 index 00000000..80b0ed95 --- /dev/null +++ b/tests/CultMath.Tests/MathTests.cs @@ -0,0 +1,38 @@ +using CultMath; +using Xunit; + +namespace CultMath.Tests; + +public sealed class MathTests +{ + [Fact] + public void FracMatchesShaderStylePositiveAndNegativeValues() + { + Assert.Equal(0.25f, math.frac(1.25f)); + Assert.Equal(0.75f, math.frac(-1.25f)); + } + + [Fact] + public void VectorOperationsAreComponentWise() + { + var value = new float3(1.0f, 2.0f, 3.0f) * new float3(4.0f, 5.0f, 6.0f); + + Assert.Equal(new float3(4.0f, 10.0f, 18.0f), value); + } + + [Fact] + public void NormalizeProducesUnitLength() + { + var value = math.normalize(new float3(3.0f, 4.0f, 0.0f)); + + Assert.Equal(1.0f, math.length(value), precision: 5); + } + + [Fact] + public void SmoothstepUsesHermiteRamp() + { + Assert.Equal(0.0f, math.smoothstep(0.0f, 1.0f, -1.0f)); + Assert.Equal(0.5f, math.smoothstep(0.0f, 1.0f, 0.5f), precision: 5); + Assert.Equal(1.0f, math.smoothstep(0.0f, 1.0f, 2.0f)); + } +} From 5cef6d951e3bf8bf49c89d81675a88605b5aa599 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 25 May 2026 20:33:04 +0100 Subject: [PATCH 002/283] Add shader-shaped vector constructors and trig intrinsics --- src/CultMath/float3.cs | 5 +++++ src/CultMath/float4.cs | 10 ++++++++++ src/CultMath/math.cs | 8 ++++++++ tests/CultMath.Tests/MathTests.cs | 17 +++++++++++++++++ 4 files changed, 40 insertions(+) diff --git a/src/CultMath/float3.cs b/src/CultMath/float3.cs index 037e8838..70cfa02b 100644 --- a/src/CultMath/float3.cs +++ b/src/CultMath/float3.cs @@ -5,6 +5,11 @@ public readonly record struct float3(float x, float y, float z) public static readonly float3 zero = new(0.0f, 0.0f, 0.0f); public static readonly float3 one = new(1.0f, 1.0f, 1.0f); + public float3(float2 xy, float z) + : this(xy.x, xy.y, z) + { + } + public float2 xy => new(x, y); public float2 xz => new(x, z); public float2 yz => new(y, z); diff --git a/src/CultMath/float4.cs b/src/CultMath/float4.cs index d9ec0982..c7bfb404 100644 --- a/src/CultMath/float4.cs +++ b/src/CultMath/float4.cs @@ -5,6 +5,16 @@ public readonly record struct float4(float x, float y, float z, float w) public static readonly float4 zero = new(0.0f, 0.0f, 0.0f, 0.0f); public static readonly float4 one = new(1.0f, 1.0f, 1.0f, 1.0f); + public float4(float2 xy, float z, float w) + : this(xy.x, xy.y, z, w) + { + } + + public float4(float3 xyz, float w) + : this(xyz.x, xyz.y, xyz.z, w) + { + } + public float2 xy => new(x, y); public float3 xyz => new(x, y, z); diff --git a/src/CultMath/math.cs b/src/CultMath/math.cs index 6b0cf455..6d44f900 100644 --- a/src/CultMath/math.cs +++ b/src/CultMath/math.cs @@ -8,6 +8,14 @@ public static class math public static float radians(float degrees) => degrees * (PI / 180.0f); public static float degrees(float radians) => radians * (180.0f / PI); + public static float sin(float value) => MathF.Sin(value); + public static float cos(float value) => MathF.Cos(value); + public static float tan(float value) => MathF.Tan(value); + public static float asin(float value) => MathF.Asin(value); + public static float acos(float value) => MathF.Acos(value); + public static float atan(float value) => MathF.Atan(value); + public static float atan2(float y, float x) => MathF.Atan2(y, x); + public static float sqrt(float value) => MathF.Sqrt(value); public static float abs(float value) => MathF.Abs(value); public static float2 abs(float2 value) => new(abs(value.x), abs(value.y)); diff --git a/tests/CultMath.Tests/MathTests.cs b/tests/CultMath.Tests/MathTests.cs index 80b0ed95..8576a770 100644 --- a/tests/CultMath.Tests/MathTests.cs +++ b/tests/CultMath.Tests/MathTests.cs @@ -20,6 +20,14 @@ public sealed class MathTests Assert.Equal(new float3(4.0f, 10.0f, 18.0f), value); } + [Fact] + public void VectorConstructorsAcceptLowerDimensionVectors() + { + Assert.Equal(new float3(1.0f, 2.0f, 3.0f), new float3(new float2(1.0f, 2.0f), 3.0f)); + Assert.Equal(new float4(1.0f, 2.0f, 3.0f, 4.0f), new float4(new float2(1.0f, 2.0f), 3.0f, 4.0f)); + Assert.Equal(new float4(1.0f, 2.0f, 3.0f, 4.0f), new float4(new float3(1.0f, 2.0f, 3.0f), 4.0f)); + } + [Fact] public void NormalizeProducesUnitLength() { @@ -35,4 +43,13 @@ public sealed class MathTests Assert.Equal(0.5f, math.smoothstep(0.0f, 1.0f, 0.5f), precision: 5); Assert.Equal(1.0f, math.smoothstep(0.0f, 1.0f, 2.0f)); } + + [Fact] + public void TrigIntrinsicsUseRadians() + { + Assert.Equal(1.0f, math.sin(math.HALF_PI), precision: 5); + Assert.Equal(-1.0f, math.cos(math.PI), precision: 5); + Assert.Equal(1.0f, math.tan(math.PI * 0.25f), precision: 5); + Assert.Equal(math.HALF_PI, math.atan2(1.0f, 0.0f), precision: 5); + } } From bfe356fe92e26a641d4db0ba592f23d7ee00396b Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 3 Jun 2026 02:58:56 +0100 Subject: [PATCH 003/283] Add Rust-backed Voronoi batch kernel --- .gitignore | 9 +- README.md | 32 +++-- docs/design.md | 7 +- native/cultmath-core/Cargo.lock | 7 ++ native/cultmath-core/Cargo.toml | 13 ++ native/cultmath-core/src/lib.rs | 188 +++++++++++++++++++++++++++++ src/CultMath/Color32.cs | 4 + src/CultMath/CultMath.csproj | 1 + src/CultMath/CultMathTone.cs | 10 ++ src/CultMath/Voronoi.cs | 190 ++++++++++++++++++++++++++++++ tests/CultMath.Tests/MathTests.cs | 16 +++ 11 files changed, 461 insertions(+), 16 deletions(-) create mode 100644 native/cultmath-core/Cargo.lock create mode 100644 native/cultmath-core/Cargo.toml create mode 100644 native/cultmath-core/src/lib.rs create mode 100644 src/CultMath/Color32.cs create mode 100644 src/CultMath/CultMathTone.cs create mode 100644 src/CultMath/Voronoi.cs diff --git a/.gitignore b/.gitignore index 59e67361..6eae4393 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ +bin/ +obj/ **/bin/ **/obj/ -artifacts/ -*.user -*.suo -.vs/ -.idea/ +target/ +**/target/ diff --git a/README.md b/README.md index c3b1809d..b693d258 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,12 @@ # CultMath -Clean-room C# math shaped for people who think in HLSL. +Clean-room math shaped for people who think in HLSL. -CultMath provides lowercase vector types and shader-style intrinsics so -math-heavy renderer code can move between C# and HLSL without turning every -line into a translation exercise. It is not a Unity.Mathematics clone. It is a -small, Aquarium-born library built from public shader semantics and plain .NET. +CultMath provides lowercase vector types, shader-style intrinsics, and native +hot-path kernels so math-heavy renderer code can move between C#, Rust, and HLSL +without turning every line into a translation exercise. It is not a +Unity.Mathematics clone. It is a small, Aquarium-born library built from public +shader semantics. ## Current Surface @@ -17,6 +18,17 @@ small, Aquarium-born library built from public shader semantics and plain .NET. - `math` intrinsics: `radians`, `degrees`, `abs`, `floor`, `ceil`, `frac`, `min`, `max`, `clamp`, `saturate`, `lerp`, `step`, `smoothstep`, `dot`, `cross`, `length`, `distance`, `normalize`, and `reflect` +- `Voronoi.SampleTones`, a C# batch surface that calls the Rust + `cultmath-core` native kernel when `cultmath_core` is available and falls back + to the managed parity path otherwise. + +## Native Core + +The canonical hot-path body lives in `native/cultmath-core`. It exports a C ABI +for batch kernels such as `cultmath_apollonian_voronoi_tones`. + +Runtime wrappers own syntax and integration. Rust owns optimized primitive +kernel behavior and parity fixtures. ## Example @@ -33,11 +45,13 @@ float glow = math.smoothstep(0.2f, 1.0f, rim); ```powershell dotnet build CultMath.slnx dotnet test CultMath.slnx +cargo test --manifest-path native/cultmath-core/Cargo.toml +cargo build --release --manifest-path native/cultmath-core/Cargo.toml ``` ## Doctrine -The goal is mechanical sympathy between CPU-side authoring and GPU-side shader -math. If an intrinsic exists here, it should behave like the shader concept -unless .NET numeric rules make that impossible. Weird deviations get tests and -documentation, not folklore. +The goal is mechanical sympathy between CPU-side authoring, native kernels, and +GPU-side shader math. If an intrinsic exists here, it should behave like the +shader concept unless a runtime's numeric rules make that impossible. Weird +deviations get tests and documentation, not folklore. diff --git a/docs/design.md b/docs/design.md index 62102739..3c87fb51 100644 --- a/docs/design.md +++ b/docs/design.md @@ -1,11 +1,14 @@ # Design -CultMath exists to make renderer math readable in both places it needs to live: -C# host code and HLSL shader code. +CultMath exists to make renderer math readable in every place it needs to live: +Rust hot kernels, C# host code, and HLSL shader code. ## Rules - Keep type names HLSL-shaped: `float2`, `float3`, `float4`, and `math`. +- Keep Rust as the owner of native hot-path kernels and parity fixtures. +- Keep C#, shader, and scripting surfaces as runtime wrappers, not competing + math authorities. - Implement public shader semantics directly; do not copy Unity.Mathematics. - Prefer small immutable value types. - Prefer component-wise overloads over clever generic machinery until the API diff --git a/native/cultmath-core/Cargo.lock b/native/cultmath-core/Cargo.lock new file mode 100644 index 00000000..09598b97 --- /dev/null +++ b/native/cultmath-core/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "cultmath-core" +version = "0.1.0" diff --git a/native/cultmath-core/Cargo.toml b/native/cultmath-core/Cargo.toml new file mode 100644 index 00000000..cf7819a0 --- /dev/null +++ b/native/cultmath-core/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "cultmath-core" +version = "0.1.0" +edition = "2021" + +[lib] +name = "cultmath_core" +crate-type = ["cdylib", "staticlib"] + +[profile.release] +lto = "thin" +codegen-units = 1 +panic = "abort" diff --git a/native/cultmath-core/src/lib.rs b/native/cultmath-core/src/lib.rs new file mode 100644 index 00000000..5a484608 --- /dev/null +++ b/native/cultmath-core/src/lib.rs @@ -0,0 +1,188 @@ +#[repr(C)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +pub struct CultMathColor32 { + pub r: u8, + pub g: u8, + pub b: u8, + pub a: u8, +} + +#[no_mangle] +pub unsafe extern "C" fn cultmath_apollonian_voronoi_tones( + xs: *const f32, + ys: *const f32, + tones: *const u8, + spans: *const f32, + count: usize, + resolution_y: f32, + frame_index: i32, + out_colors: *mut CultMathColor32, +) -> i32 { + if xs.is_null() || ys.is_null() || tones.is_null() || spans.is_null() || out_colors.is_null() { + return -1; + } + + let xs = unsafe { std::slice::from_raw_parts(xs, count) }; + let ys = unsafe { std::slice::from_raw_parts(ys, count) }; + let tones = unsafe { std::slice::from_raw_parts(tones, count) }; + let spans = unsafe { std::slice::from_raw_parts(spans, count) }; + let out_colors = unsafe { std::slice::from_raw_parts_mut(out_colors, count) }; + for index in 0..count { + out_colors[index] = tone_color( + xs[index], + ys[index], + resolution_y, + frame_index, + tones[index], + spans[index], + ); + } + + 0 +} + +fn tone_color(px: f32, py: f32, resolution_y: f32, frame_index: i32, tone: u8, span: f32) -> CultMathColor32 { + let sample = stable_sample(px, py, resolution_y, frame_index, tone, span); + let luminance = saturate(sample.0 * 0.299 + sample.1 * 0.587 + sample.2 * 0.114); + match tone { + 3 => { + let glow = 0.62 + luminance * 0.38; + color(255.0 * glow, 96.0 * glow, 14.0 * glow) + } + 4 => { + let glow = 0.68 + luminance * 0.32; + color(245.0 * glow, 248.0 * glow, 252.0 * glow) + } + _ => { + let (gain, lift) = match tone { + 1 => (0.25, 6.0), + 2 => (0.95, 20.0), + _ => (0.16, 2.0), + }; + color( + lift + sample.0 * 255.0 * gain, + lift + sample.1 * 255.0 * gain, + lift + sample.2 * 255.0 * gain, + ) + } + } +} + +fn stable_sample(px: f32, py: f32, resolution_y: f32, frame_index: i32, tone: u8, span: f32) -> (f32, f32, f32) { + let seed = px * 12.9898 + py * 78.233 + hash1((tone as f32 + 1.0) * 19.19); + let jitter_x = (hash1(seed) - 0.5) * span; + let jitter_y = (hash1(seed + 37.17) - 0.5) * span; + voronoi(px + jitter_x, py + jitter_y, resolution_y, frame_index) +} + +fn voronoi(px: f32, py: f32, resolution_y: f32, frame_index: i32) -> (f32, f32, f32) { + let time = frame_index as f32 / 120.0; + let scale = 6.0; + let x = scale * px / resolution_y.max(1.0); + let y = scale * py / resolution_y.max(1.0); + let nx = x.floor(); + let ny = y.floor(); + let fx = frac(x); + let fy = frac(y); + let mut distance = 8.0; + let mut red = 0.0; + let mut green = 0.0; + let mut blue = 0.0; + let smoothness = 0.005; + + for j in -2..=2 { + for i in -2..=2 { + let gx = i as f32; + let gy = j as f32; + let (mut ox, mut oy) = hash2(nx + gx, ny + gy); + let weight = ox * 0.5 + 0.5; + ox = 0.5 + 0.5 * (time + 6.2831 * ox).sin(); + oy = 0.5 + 0.5 * (time + 6.2831 * oy).sin(); + let dx = (gx - fx + ox).abs(); + let dy = (gy - fy + oy).abs(); + let d = dx.max(dy) * weight; + let seed = hash1((nx + gx) * 7.0 + (ny + gy) * 113.0); + let candidate_red = 0.5 + 0.5 * (seed * 2.5 + 3.5 + 2.0).sin(); + let candidate_green = 0.5 + 0.5 * (seed * 2.5 + 3.5 + 3.0).sin(); + let candidate_blue = 0.5 + 0.5 * (seed * 2.5 + 3.5 + 2.0).sin(); + let h = smoothstep(0.0, 1.0, 0.5 + 0.5 * (distance - d) / smoothness); + let correction = h * (1.0 - h) * smoothness / (1.0 + 3.0 * smoothness); + distance = lerp(distance, d, h) - correction; + red = lerp(red, candidate_red, h) - correction; + green = lerp(green, candidate_green, h) - correction; + blue = lerp(blue, candidate_blue, h) - correction; + } + } + + let edge_dimming = 1.0 - 0.1 * smoothstep(0.04, 0.05, distance); + ( + (red * edge_dimming).max(0.0), + (green * edge_dimming).max(0.0), + (blue * edge_dimming).max(0.0), + ) +} + +fn hash1(value: f32) -> f32 { + frac(value.sin() * 43758.5453) +} + +fn hash2(x: f32, y: f32) -> (f32, f32) { + ( + frac((x * 127.1 + y * 311.7).sin() * 43758.5453), + frac((x * 269.5 + y * 183.3).sin() * 43758.5453), + ) +} + +fn frac(value: f32) -> f32 { + value - value.floor() +} + +fn saturate(value: f32) -> f32 { + value.clamp(0.0, 1.0) +} + +fn smoothstep(edge0: f32, edge1: f32, value: f32) -> f32 { + let t = saturate((value - edge0) / (edge1 - edge0)); + t * t * (3.0 - 2.0 * t) +} + +fn lerp(start: f32, end: f32, amount: f32) -> f32 { + start + (end - start) * amount +} + +fn color(r: f32, g: f32, b: f32) -> CultMathColor32 { + CultMathColor32 { + r: r.clamp(0.0, 255.0) as u8, + g: g.clamp(0.0, 255.0) as u8, + b: b.clamp(0.0, 255.0) as u8, + a: 255, + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn batch_sampler_writes_colors() { + let xs = [0.0, 20.0, 100.0]; + let ys = [0.0, 30.0, 140.0]; + let tones = [0, 3, 4]; + let spans = [1920.0, 8.0, 8.0]; + let mut out = [CultMathColor32::default(); 3]; + let rc = unsafe { + cultmath_apollonian_voronoi_tones( + xs.as_ptr(), + ys.as_ptr(), + tones.as_ptr(), + spans.as_ptr(), + xs.len(), + 1080.0, + 12, + out.as_mut_ptr(), + ) + }; + assert_eq!(rc, 0); + assert!(out.iter().any(|color| color.r != 0 || color.g != 0 || color.b != 0)); + } +} diff --git a/src/CultMath/Color32.cs b/src/CultMath/Color32.cs new file mode 100644 index 00000000..e9a2b481 --- /dev/null +++ b/src/CultMath/Color32.cs @@ -0,0 +1,4 @@ +namespace CultMath; + +[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)] +public readonly record struct Color32(byte r, byte g, byte b, byte a = 255); diff --git a/src/CultMath/CultMath.csproj b/src/CultMath/CultMath.csproj index f06b8bed..83f6fb9d 100644 --- a/src/CultMath/CultMath.csproj +++ b/src/CultMath/CultMath.csproj @@ -12,6 +12,7 @@ https://github.com/GameCult/CultMath README.md $(NoWarn);CS8981 + true diff --git a/src/CultMath/CultMathTone.cs b/src/CultMath/CultMathTone.cs new file mode 100644 index 00000000..25dfffeb --- /dev/null +++ b/src/CultMath/CultMathTone.cs @@ -0,0 +1,10 @@ +namespace CultMath; + +public enum CultMathTone : byte +{ + Background = 0, + Panel = 1, + Edge = 2, + Header = 3, + Body = 4, +} diff --git a/src/CultMath/Voronoi.cs b/src/CultMath/Voronoi.cs new file mode 100644 index 00000000..52e6acb6 --- /dev/null +++ b/src/CultMath/Voronoi.cs @@ -0,0 +1,190 @@ +using System.Runtime.InteropServices; + +namespace CultMath; + +public static class Voronoi +{ + public static bool NativeAvailable { get; private set; } = true; + + public static Color32 SampleTone(float x, float y, float resolutionY, int frameIndex, CultMathTone tone, float span) + { + Span xs = stackalloc[] { x }; + Span ys = stackalloc[] { y }; + Span tones = stackalloc[] { tone }; + Span spans = stackalloc[] { span }; + Span colors = stackalloc Color32[1]; + SampleTones(xs, ys, tones, spans, resolutionY, frameIndex, colors); + return colors[0]; + } + + public static void SampleTones( + ReadOnlySpan xs, + ReadOnlySpan ys, + ReadOnlySpan tones, + ReadOnlySpan spans, + float resolutionY, + int frameIndex, + Span colors) + { + if (xs.Length != ys.Length || xs.Length != tones.Length || xs.Length != spans.Length || xs.Length != colors.Length) + { + throw new ArgumentException("CultMath Voronoi batch spans must have equal length."); + } + + if (xs.IsEmpty) + { + return; + } + + if (NativeAvailable && TrySampleNative(xs, ys, tones, spans, resolutionY, frameIndex, colors)) + { + return; + } + + for (var index = 0; index < xs.Length; index++) + { + colors[index] = SampleManaged(xs[index], ys[index], resolutionY, frameIndex, tones[index], spans[index]); + } + } + + private static unsafe bool TrySampleNative( + ReadOnlySpan xs, + ReadOnlySpan ys, + ReadOnlySpan tones, + ReadOnlySpan spans, + float resolutionY, + int frameIndex, + Span colors) + { + try + { + fixed (float* xPtr = xs) + fixed (float* yPtr = ys) + fixed (CultMathTone* tonePtr = tones) + fixed (float* spanPtr = spans) + fixed (Color32* colorPtr = colors) + { + var result = Native.cultmath_apollonian_voronoi_tones( + xPtr, + yPtr, + (byte*)tonePtr, + spanPtr, + (nuint)xs.Length, + resolutionY, + frameIndex, + colorPtr); + if (result == 0) + { + return true; + } + } + } + catch (DllNotFoundException) + { + NativeAvailable = false; + } + catch (EntryPointNotFoundException) + { + NativeAvailable = false; + } + + return false; + } + + private static Color32 SampleManaged(float x, float y, float resolutionY, int frameIndex, CultMathTone tone, float span) + { + var sample = StableSample(x, y, resolutionY, frameIndex, tone, span); + var luminance = math.saturate(sample.x * 0.299f + sample.y * 0.587f + sample.z * 0.114f); + if (tone == CultMathTone.Header) + { + var glow = 0.62f + luminance * 0.38f; + return new Color32((byte)(255 * glow), (byte)(96 * glow), (byte)(14 * glow)); + } + + if (tone == CultMathTone.Body) + { + var glow = 0.68f + luminance * 0.32f; + return new Color32((byte)(245 * glow), (byte)(248 * glow), (byte)(252 * glow)); + } + + var gain = tone switch + { + CultMathTone.Panel => 0.25f, + CultMathTone.Edge => 0.95f, + _ => 0.16f, + }; + var lift = tone switch + { + CultMathTone.Panel => 6.0f, + CultMathTone.Edge => 20.0f, + _ => 2.0f, + }; + return new Color32( + (byte)Math.Clamp(lift + sample.x * 255.0f * gain, 0, 255), + (byte)Math.Clamp(lift + sample.y * 255.0f * gain, 0, 255), + (byte)Math.Clamp(lift + sample.z * 255.0f * gain, 0, 255)); + } + + private static float3 StableSample(float x, float y, float resolutionY, int frameIndex, CultMathTone tone, float span) + { + var seed = x * 12.9898f + y * 78.233f + Hash1(((byte)tone + 1.0f) * 19.19f); + var jitter = new float2((Hash1(seed) - 0.5f) * span, (Hash1(seed + 37.17f) - 0.5f) * span); + return SampleField(x + jitter.x, y + jitter.y, resolutionY, frameIndex); + } + + private static float3 SampleField(float px, float py, float resolutionY, int frameIndex) + { + var time = frameIndex / 120.0f; + var p = new float2(6.0f * px / Math.Max(1.0f, resolutionY), 6.0f * py / Math.Max(1.0f, resolutionY)); + var n = math.floor(p); + var f = math.frac(p); + var distance = 8.0f; + var color = float3.zero; + const float smoothness = 0.005f; + for (var j = -2; j <= 2; j++) + { + for (var i = -2; i <= 2; i++) + { + var g = new float2(i, j); + var o = Hash2(n + g); + var weight = o.x * 0.5f + 0.5f; + o = 0.5f + 0.5f * new float2(math.sin(time + 6.2831f * o.x), math.sin(time + 6.2831f * o.y)); + var d2 = math.abs(g - f + o); + var d = Math.Max(d2.x, d2.y) * weight; + var seed = Hash1(math.dot(n + g, new float2(7.0f, 113.0f))); + var candidate = 0.5f + 0.5f * new float3( + math.sin(seed * 2.5f + 3.5f + 2.0f), + math.sin(seed * 2.5f + 3.5f + 3.0f), + math.sin(seed * 2.5f + 3.5f + 2.0f)); + var h = math.smoothstep(0.0f, 1.0f, 0.5f + 0.5f * (distance - d) / smoothness); + var correction = h * (1.0f - h) * smoothness / (1.0f + 3.0f * smoothness); + distance = math.lerp(distance, d, h) - correction; + color = math.lerp(color, candidate, h) - correction; + } + } + + return math.max(float3.zero, color * (1.0f - 0.1f * math.smoothstep(0.04f, 0.05f, distance))); + } + + private static float Hash1(float value) => math.frac(math.sin(value) * 43758.5453f); + + private static float2 Hash2(float2 value) + { + var p = new float2(math.dot(value, new float2(127.1f, 311.7f)), math.dot(value, new float2(269.5f, 183.3f))); + return math.frac(new float2(math.sin(p.x) * 43758.5453f, math.sin(p.y) * 43758.5453f)); + } + + private static unsafe partial class Native + { + [DllImport("cultmath_core", CallingConvention = CallingConvention.Cdecl)] + public static extern int cultmath_apollonian_voronoi_tones( + float* xs, + float* ys, + byte* tones, + float* spans, + nuint count, + float resolutionY, + int frameIndex, + Color32* outColors); + } +} diff --git a/tests/CultMath.Tests/MathTests.cs b/tests/CultMath.Tests/MathTests.cs index 8576a770..2e0cea93 100644 --- a/tests/CultMath.Tests/MathTests.cs +++ b/tests/CultMath.Tests/MathTests.cs @@ -52,4 +52,20 @@ public sealed class MathTests Assert.Equal(1.0f, math.tan(math.PI * 0.25f), precision: 5); Assert.Equal(math.HALF_PI, math.atan2(1.0f, 0.0f), precision: 5); } + + [Fact] + public void VoronoiBatchProducesToneMappedColors() + { + var xs = new[] { 0.0f, 24.0f, 96.0f }; + var ys = new[] { 0.0f, 36.0f, 144.0f }; + var tones = new[] { CultMathTone.Background, CultMathTone.Header, CultMathTone.Body }; + var spans = new[] { 1920.0f, 8.0f, 8.0f }; + var colors = new Color32[xs.Length]; + + Voronoi.SampleTones(xs, ys, tones, spans, 1080.0f, 12, colors); + + Assert.NotEqual(new Color32(), colors[0]); + Assert.True(colors[1].r > colors[1].g); + Assert.True(colors[2].r > 120 && colors[2].g > 120 && colors[2].b > 120); + } } From b79b6d047fc850fa7ed38e0f4cc673b25ab50b23 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 3 Jun 2026 04:08:48 +0100 Subject: [PATCH 004/283] Broaden Voronoi color spectrum --- native/cultmath-core/src/lib.rs | 37 +++++++++++++++++---- src/CultMath/Voronoi.cs | 58 +++++++++++++++++++++++++++------ 2 files changed, 79 insertions(+), 16 deletions(-) diff --git a/native/cultmath-core/src/lib.rs b/native/cultmath-core/src/lib.rs index 5a484608..46e7ced6 100644 --- a/native/cultmath-core/src/lib.rs +++ b/native/cultmath-core/src/lib.rs @@ -55,9 +55,9 @@ fn tone_color(px: f32, py: f32, resolution_y: f32, frame_index: i32, tone: u8, s } _ => { let (gain, lift) = match tone { - 1 => (0.25, 6.0), - 2 => (0.95, 20.0), - _ => (0.16, 2.0), + 1 => (0.42, 14.0), + 2 => (1.05, 24.0), + _ => (0.24, 4.0), }; color( lift + sample.0 * 255.0 * gain, @@ -102,9 +102,8 @@ fn voronoi(px: f32, py: f32, resolution_y: f32, frame_index: i32) -> (f32, f32, let dy = (gy - fy + oy).abs(); let d = dx.max(dy) * weight; let seed = hash1((nx + gx) * 7.0 + (ny + gy) * 113.0); - let candidate_red = 0.5 + 0.5 * (seed * 2.5 + 3.5 + 2.0).sin(); - let candidate_green = 0.5 + 0.5 * (seed * 2.5 + 3.5 + 3.0).sin(); - let candidate_blue = 0.5 + 0.5 * (seed * 2.5 + 3.5 + 2.0).sin(); + let hue = frac((nx + gx) * 0.173 + (ny + gy) * 0.379 + seed * 0.431); + let (candidate_red, candidate_green, candidate_blue) = pastel_spectrum(hue); let h = smoothstep(0.0, 1.0, 0.5 + 0.5 * (distance - d) / smoothness); let correction = h * (1.0 - h) * smoothness / (1.0 + 3.0 * smoothness); distance = lerp(distance, d, h) - correction; @@ -150,6 +149,32 @@ fn lerp(start: f32, end: f32, amount: f32) -> f32 { start + (end - start) * amount } +fn pastel_spectrum(hue: f32) -> (f32, f32, f32) { + hsv_to_rgb(hue, 0.52, 0.98) +} + +fn hsv_to_rgb(hue: f32, saturation: f32, value: f32) -> (f32, f32, f32) { + let h = frac(hue) * 6.0; + let c = value * saturation; + let x = c * (1.0 - ((h % 2.0) - 1.0).abs()); + let m = value - c; + let (r, g, b) = if h < 1.0 { + (c, x, 0.0) + } else if h < 2.0 { + (x, c, 0.0) + } else if h < 3.0 { + (0.0, c, x) + } else if h < 4.0 { + (0.0, x, c) + } else if h < 5.0 { + (x, 0.0, c) + } else { + (c, 0.0, x) + }; + + (r + m, g + m, b + m) +} + fn color(r: f32, g: f32, b: f32) -> CultMathColor32 { CultMathColor32 { r: r.clamp(0.0, 255.0) as u8, diff --git a/src/CultMath/Voronoi.cs b/src/CultMath/Voronoi.cs index 52e6acb6..9791a8e0 100644 --- a/src/CultMath/Voronoi.cs +++ b/src/CultMath/Voronoi.cs @@ -109,15 +109,15 @@ public static class Voronoi var gain = tone switch { - CultMathTone.Panel => 0.25f, - CultMathTone.Edge => 0.95f, - _ => 0.16f, + CultMathTone.Panel => 0.42f, + CultMathTone.Edge => 1.05f, + _ => 0.24f, }; var lift = tone switch { - CultMathTone.Panel => 6.0f, - CultMathTone.Edge => 20.0f, - _ => 2.0f, + CultMathTone.Panel => 14.0f, + CultMathTone.Edge => 24.0f, + _ => 4.0f, }; return new Color32( (byte)Math.Clamp(lift + sample.x * 255.0f * gain, 0, 255), @@ -152,10 +152,8 @@ public static class Voronoi var d2 = math.abs(g - f + o); var d = Math.Max(d2.x, d2.y) * weight; var seed = Hash1(math.dot(n + g, new float2(7.0f, 113.0f))); - var candidate = 0.5f + 0.5f * new float3( - math.sin(seed * 2.5f + 3.5f + 2.0f), - math.sin(seed * 2.5f + 3.5f + 3.0f), - math.sin(seed * 2.5f + 3.5f + 2.0f)); + var hue = math.frac((n.x + g.x) * 0.173f + (n.y + g.y) * 0.379f + seed * 0.431f); + var candidate = PastelSpectrum(hue); var h = math.smoothstep(0.0f, 1.0f, 0.5f + 0.5f * (distance - d) / smoothness); var correction = h * (1.0f - h) * smoothness / (1.0f + 3.0f * smoothness); distance = math.lerp(distance, d, h) - correction; @@ -168,6 +166,46 @@ public static class Voronoi private static float Hash1(float value) => math.frac(math.sin(value) * 43758.5453f); + private static float3 PastelSpectrum(float hue) + { + return HsvToRgb(hue, 0.52f, 0.98f); + } + + private static float3 HsvToRgb(float hue, float saturation, float value) + { + var h = math.frac(hue) * 6.0f; + var c = value * saturation; + var x = c * (1.0f - Math.Abs(h % 2.0f - 1.0f)); + var m = value - c; + float3 rgb; + if (h < 1.0f) + { + rgb = new float3(c, x, 0.0f); + } + else if (h < 2.0f) + { + rgb = new float3(x, c, 0.0f); + } + else if (h < 3.0f) + { + rgb = new float3(0.0f, c, x); + } + else if (h < 4.0f) + { + rgb = new float3(0.0f, x, c); + } + else if (h < 5.0f) + { + rgb = new float3(x, 0.0f, c); + } + else + { + rgb = new float3(c, 0.0f, x); + } + + return rgb + m; + } + private static float2 Hash2(float2 value) { var p = new float2(math.dot(value, new float2(127.1f, 311.7f)), math.dot(value, new float2(269.5f, 183.3f))); From f535801cd0ceb273fabb96a9bd8ad508489ef28c Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 10 Jun 2026 21:22:43 +0100 Subject: [PATCH 005/283] Promote shader math primitives --- README.md | 30 ++- docs/design.md | 9 +- shaders/CultMath.hlsl | 254 ++++++++++++++++++++++++ src/CultMath/CultMath.csproj | 1 + src/CultMath/math.cs | 202 +++++++++++++++++++ tests/CultMath.Tests/HlslMirrorTests.cs | 63 ++++++ tests/CultMath.Tests/MathTests.cs | 48 +++++ 7 files changed, 604 insertions(+), 3 deletions(-) create mode 100644 shaders/CultMath.hlsl create mode 100644 tests/CultMath.Tests/HlslMirrorTests.cs diff --git a/README.md b/README.md index b693d258..ef69df80 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,13 @@ shader semantics. - conversions to and from `System.Numerics` - `math` intrinsics: `radians`, `degrees`, `abs`, `floor`, `ceil`, `frac`, `min`, `max`, `clamp`, `saturate`, `lerp`, `step`, `smoothstep`, `dot`, - `cross`, `length`, `distance`, `normalize`, and `reflect` + `cross`, `length`, `distance`, `normalize`, `reflect`, `csum`, exponential + `decay`/`damp`, intercept/segment helpers, Catmull-Rom, Bezier curves, and + deterministic value-noise primitives +- `shaders/CultMath.hlsl`, a canonical HLSL mirror include for shader-side + parity. HLSL already owns `float2`, `float3`, and `float4`; the include + exposes `cultmath_*` functions for shared semantics, including CultMath's + safe `normalize` contract. - `Voronoi.SampleTones`, a C# batch surface that calls the Rust `cultmath-core` native kernel when `cultmath_core` is available and falls back to the managed parity path otherwise. @@ -38,8 +44,25 @@ using CultMath; float3 normal = math.normalize(new float3(0.25f, 1.0f, -0.1f)); float rim = math.saturate(1.0f - math.dot(normal, new float3(0.0f, 0.0f, -1.0f))); float glow = math.smoothstep(0.2f, 1.0f, rim); +float grain = math.value_noise_bicubic(math.float2(12.0f, 3.5f)); ``` +```hlsl +#include "CultMath.hlsl" + +float3 normal = cultmath_normalize(float3(0.25, 1.0, -0.1)); +float rim = cultmath_saturate(1.0 - dot(normal, float3(0.0, 0.0, -1.0))); +float glow = cultmath_smoothstep(0.2, 1.0, rim); +float grain = cultmath_value_noise_bicubic(float2(12.0, 3.5)); +``` + +## Provenance + +The small spline, damping, and pursuit helpers were promoted from Aetheria's +local `AetheriaMath` surface. The value-noise family follows public shader +literature from Inigo Quilez's noise and mini-spline articles, expressed in +CultMath names with tests instead of copied project-local helper drift. + ## Build ```powershell @@ -55,3 +78,8 @@ The goal is mechanical sympathy between CPU-side authoring, native kernels, and GPU-side shader math. If an intrinsic exists here, it should behave like the shader concept unless a runtime's numeric rules make that impossible. Weird deviations get tests and documentation, not folklore. + +CultMath is still not a shader generator. Projects should include +`shaders/CultMath.hlsl` directly or add that directory to their shader include +path. If a shared operation needs CPU/GPU parity, put the primitive here and +test it here before copying local math helpers into a renderer or daemon. diff --git a/docs/design.md b/docs/design.md index 3c87fb51..8250ba78 100644 --- a/docs/design.md +++ b/docs/design.md @@ -9,16 +9,21 @@ Rust hot kernels, C# host code, and HLSL shader code. - Keep Rust as the owner of native hot-path kernels and parity fixtures. - Keep C#, shader, and scripting surfaces as runtime wrappers, not competing math authorities. +- Keep `shaders/CultMath.hlsl` as the canonical shader mirror for shared + intrinsics. Project-local shader helpers should move here once more than one + organ needs them or once CPU/GPU parity matters. - Implement public shader semantics directly; do not copy Unity.Mathematics. - Prefer small immutable value types. - Prefer component-wise overloads over clever generic machinery until the API earns that complexity. -- Keep the first surface boring and exact. Noise, matrices, quaternions, and - packing helpers come later. +- Keep the surface boring and exact. Noise primitives are allowed when they are + source-grounded, shader-shaped, and shared by more than one project. Matrices, + quaternions, and packing helpers still need an owner before they enter. ## Non-Goals - Compiling C# to shaders. +- Generating HLSL from Rust or Rust from HLSL. - Replacing `System.Numerics` for general .NET work. - Recreating every Unity.Mathematics type because a spreadsheet somewhere says “coverage.” That way lies decorative obesity. diff --git a/shaders/CultMath.hlsl b/shaders/CultMath.hlsl new file mode 100644 index 00000000..3cbb3fdd --- /dev/null +++ b/shaders/CultMath.hlsl @@ -0,0 +1,254 @@ +#ifndef CULTMATH_HLSL +#define CULTMATH_HLSL + +// CultMath HLSL mirror. +// +// HLSL already owns the float2/float3/float4 type names and most primitive +// intrinsics. This include names the CultMath semantic surface explicitly so +// shader code, C# wrappers, and Rust/native parity fixtures can share the same +// small vocabulary without local helper drift. + +static const float CULTMATH_PI = 3.14159265358979323846; +static const float CULTMATH_TAU = 6.28318530717958647692; +static const float CULTMATH_HALF_PI = 1.57079632679489661923; +static const float CULTMATH_NORMALIZE_EPSILON = 1.0e-20; + +float cultmath_radians(float degrees_value) { return degrees_value * (CULTMATH_PI / 180.0); } +float cultmath_degrees(float radians_value) { return radians_value * (180.0 / CULTMATH_PI); } + +float cultmath_frac(float value) { return value - floor(value); } +float2 cultmath_frac(float2 value) { return value - floor(value); } +float3 cultmath_frac(float3 value) { return value - floor(value); } +float4 cultmath_frac(float4 value) { return value - floor(value); } + +float cultmath_clamp(float value, float minimum, float maximum) { return min(max(value, minimum), maximum); } +float2 cultmath_clamp(float2 value, float2 minimum, float2 maximum) { return min(max(value, minimum), maximum); } +float3 cultmath_clamp(float3 value, float3 minimum, float3 maximum) { return min(max(value, minimum), maximum); } +float4 cultmath_clamp(float4 value, float4 minimum, float4 maximum) { return min(max(value, minimum), maximum); } + +float cultmath_saturate(float value) { return cultmath_clamp(value, 0.0, 1.0); } +float2 cultmath_saturate(float2 value) { return cultmath_clamp(value, float2(0.0, 0.0), float2(1.0, 1.0)); } +float3 cultmath_saturate(float3 value) { return cultmath_clamp(value, float3(0.0, 0.0, 0.0), float3(1.0, 1.0, 1.0)); } +float4 cultmath_saturate(float4 value) { return cultmath_clamp(value, float4(0.0, 0.0, 0.0, 0.0), float4(1.0, 1.0, 1.0, 1.0)); } + +float cultmath_lerp(float start, float end, float amount) { return start + (end - start) * amount; } +float2 cultmath_lerp(float2 start, float2 end, float2 amount) { return start + (end - start) * amount; } +float3 cultmath_lerp(float3 start, float3 end, float3 amount) { return start + (end - start) * amount; } +float4 cultmath_lerp(float4 start, float4 end, float4 amount) { return start + (end - start) * amount; } + +float cultmath_step(float edge, float value) { return value < edge ? 0.0 : 1.0; } +float2 cultmath_step(float2 edge, float2 value) { return float2(cultmath_step(edge.x, value.x), cultmath_step(edge.y, value.y)); } +float3 cultmath_step(float3 edge, float3 value) { return float3(cultmath_step(edge.x, value.x), cultmath_step(edge.y, value.y), cultmath_step(edge.z, value.z)); } +float4 cultmath_step(float4 edge, float4 value) { return float4(cultmath_step(edge.x, value.x), cultmath_step(edge.y, value.y), cultmath_step(edge.z, value.z), cultmath_step(edge.w, value.w)); } + +float cultmath_smoothstep(float minimum, float maximum, float value) +{ + float t = cultmath_saturate((value - minimum) / (maximum - minimum)); + return t * t * (3.0 - 2.0 * t); +} + +float2 cultmath_smoothstep(float2 minimum, float2 maximum, float2 value) +{ + float2 t = cultmath_saturate((value - minimum) / (maximum - minimum)); + return t * t * (float2(3.0, 3.0) - float2(2.0, 2.0) * t); +} + +float3 cultmath_smoothstep(float3 minimum, float3 maximum, float3 value) +{ + float3 t = cultmath_saturate((value - minimum) / (maximum - minimum)); + return t * t * (float3(3.0, 3.0, 3.0) - float3(2.0, 2.0, 2.0) * t); +} + +float4 cultmath_smoothstep(float4 minimum, float4 maximum, float4 value) +{ + float4 t = cultmath_saturate((value - minimum) / (maximum - minimum)); + return t * t * (float4(3.0, 3.0, 3.0, 3.0) - float4(2.0, 2.0, 2.0, 2.0) * t); +} + +float cultmath_smoothstep01(float value) { return cultmath_smoothstep(0.0, 1.0, value); } + +float cultmath_smootherstep(float value) +{ + value = cultmath_saturate(value); + return value * value * value * (value * (value * 6.0 - 15.0) + 10.0); +} + +float cultmath_lengthsq(float2 value) { return dot(value, value); } +float cultmath_lengthsq(float3 value) { return dot(value, value); } +float cultmath_lengthsq(float4 value) { return dot(value, value); } + +float cultmath_distance(float2 left, float2 right) { return length(left - right); } +float cultmath_distance(float3 left, float3 right) { return length(left - right); } +float cultmath_distance(float4 left, float4 right) { return length(left - right); } + +float2 cultmath_normalize(float2 value) { return value / max(length(value), CULTMATH_NORMALIZE_EPSILON); } +float3 cultmath_normalize(float3 value) { return value / max(length(value), CULTMATH_NORMALIZE_EPSILON); } +float4 cultmath_normalize(float4 value) { return value / max(length(value), CULTMATH_NORMALIZE_EPSILON); } + +float2 cultmath_reflect(float2 incident, float2 normal_value) +{ + return incident - 2.0 * dot(normal_value, incident) * normal_value; +} + +float3 cultmath_reflect(float3 incident, float3 normal_value) +{ + return incident - 2.0 * dot(normal_value, incident) * normal_value; +} + +float cultmath_csum(float2 value) { return value.x + value.y; } +float cultmath_csum(float3 value) { return value.x + value.y + value.z; } +float cultmath_csum(float4 value) { return value.x + value.y + value.z + value.w; } + +float cultmath_decay(float source, float lambda_value, float dt) { return source * exp(-lambda_value * dt); } +float2 cultmath_decay(float2 source, float lambda_value, float dt) { return source * exp(-lambda_value * dt); } +float3 cultmath_decay(float3 source, float lambda_value, float dt) { return source * exp(-lambda_value * dt); } +float4 cultmath_decay(float4 source, float lambda_value, float dt) { return source * exp(-lambda_value * dt); } + +float cultmath_damp(float start, float end, float lambda_value, float dt) +{ + return cultmath_lerp(start, end, 1.0 - exp(-lambda_value * dt)); +} + +float2 cultmath_damp(float2 start, float2 end, float lambda_value, float dt) +{ + return cultmath_lerp(start, end, 1.0 - exp(-lambda_value * dt)); +} + +float3 cultmath_damp(float3 start, float3 end, float lambda_value, float dt) +{ + return cultmath_lerp(start, end, 1.0 - exp(-lambda_value * dt)); +} + +float4 cultmath_damp(float4 start, float4 end, float lambda_value, float dt) +{ + return cultmath_lerp(start, end, 1.0 - exp(-lambda_value * dt)); +} + +float cultmath_catmullrom(float p0, float p1, float p2, float p3, float t) +{ + float t2 = t * t; + float t3 = t2 * t; + return 0.5 * ((2.0 * p1) + (p2 - p0) * t + (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) * t2 + (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3); +} + +float2 cultmath_catmullrom(float2 p0, float2 p1, float2 p2, float2 p3, float t) +{ + float t2 = t * t; + float t3 = t2 * t; + return 0.5 * ((2.0 * p1) + (p2 - p0) * t + (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) * t2 + (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3); +} + +float3 cultmath_catmullrom(float3 p0, float3 p1, float3 p2, float3 p3, float t) +{ + float t2 = t * t; + float t3 = t2 * t; + return 0.5 * ((2.0 * p1) + (p2 - p0) * t + (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) * t2 + (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3); +} + +float4 cultmath_catmullrom(float4 p0, float4 p1, float4 p2, float4 p3, float t) +{ + float t2 = t * t; + float t3 = t2 * t; + return 0.5 * ((2.0 * p1) + (p2 - p0) * t + (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) * t2 + (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3); +} + +float cultmath_quadratic_bezier(float p0, float p1, float p2, float t) +{ + t = cultmath_saturate(t); + float inv = 1.0 - t; + return inv * inv * p0 + 2.0 * inv * t * p1 + t * t * p2; +} + +float3 cultmath_quadratic_bezier(float3 p0, float3 p1, float3 p2, float t) +{ + t = cultmath_saturate(t); + float inv = 1.0 - t; + return inv * inv * p0 + 2.0 * inv * t * p1 + t * t * p2; +} + +float cultmath_cubic_bezier(float p0, float p1, float p2, float p3, float t) +{ + t = cultmath_saturate(t); + float inv = 1.0 - t; + return inv * inv * inv * p0 + 3.0 * inv * inv * t * p1 + 3.0 * inv * t * t * p2 + t * t * t * p3; +} + +float3 cultmath_cubic_bezier(float3 p0, float3 p1, float3 p2, float3 p3, float t) +{ + t = cultmath_saturate(t); + float inv = 1.0 - t; + return inv * inv * inv * p0 + 3.0 * inv * inv * t * p1 + 3.0 * inv * t * t * p2 + t * t * t * p3; +} + +float cultmath_hash(float value) { return cultmath_frac(sin(value) * 43758.5453); } +float cultmath_hash(float2 value) { return cultmath_hash(dot(value, float2(127.1, 311.7))); } +float cultmath_hash(float3 value) { return cultmath_hash(dot(value, float3(127.1, 311.7, 74.7))); } + +float cultmath_value_noise(float2 position) +{ + float2 cell = floor(position); + float2 local = cultmath_frac(position); + float2 u = local * local * (float2(3.0, 3.0) - float2(2.0, 2.0) * local); + + float a = cultmath_hash(cell); + float b = cultmath_hash(cell + float2(1.0, 0.0)); + float c = cultmath_hash(cell + float2(0.0, 1.0)); + float d = cultmath_hash(cell + float2(1.0, 1.0)); + + return cultmath_lerp(cultmath_lerp(a, b, u.x), cultmath_lerp(c, d, u.x), u.y); +} + +float cultmath_value_noise_bicubic(float2 position) +{ + float2 cell = floor(position); + float2 local = cultmath_frac(position); + + float y0 = cultmath_catmullrom(cultmath_hash(cell + float2(-1.0, -1.0)), cultmath_hash(cell + float2(0.0, -1.0)), cultmath_hash(cell + float2(1.0, -1.0)), cultmath_hash(cell + float2(2.0, -1.0)), local.x); + float y1 = cultmath_catmullrom(cultmath_hash(cell + float2(-1.0, 0.0)), cultmath_hash(cell + float2(0.0, 0.0)), cultmath_hash(cell + float2(1.0, 0.0)), cultmath_hash(cell + float2(2.0, 0.0)), local.x); + float y2 = cultmath_catmullrom(cultmath_hash(cell + float2(-1.0, 1.0)), cultmath_hash(cell + float2(0.0, 1.0)), cultmath_hash(cell + float2(1.0, 1.0)), cultmath_hash(cell + float2(2.0, 1.0)), local.x); + float y3 = cultmath_catmullrom(cultmath_hash(cell + float2(-1.0, 2.0)), cultmath_hash(cell + float2(0.0, 2.0)), cultmath_hash(cell + float2(1.0, 2.0)), cultmath_hash(cell + float2(2.0, 2.0)), local.x); + + return cultmath_catmullrom(y0, y1, y2, y3, local.y); +} + +float cultmath_value_noise_texture(Texture2D noise_texture, SamplerState noise_sampler, float2 uv, float scale) +{ + return noise_texture.SampleLevel(noise_sampler, uv * scale, 0.0).r; +} + +float cultmath_value_noise_texture_bicubic(Texture2D noise_texture, SamplerState noise_sampler, float2 uv, float scale, float2 texel_size) +{ + float2 position = uv * scale; + float2 cell = floor(position); + float2 local = cultmath_frac(position); + float2 base_uv = cell / scale; + + float row0 = cultmath_catmullrom( + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(-1.0, -1.0), 0.0).r, + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(0.0, -1.0), 0.0).r, + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(1.0, -1.0), 0.0).r, + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(2.0, -1.0), 0.0).r, + local.x); + float row1 = cultmath_catmullrom( + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(-1.0, 0.0), 0.0).r, + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(0.0, 0.0), 0.0).r, + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(1.0, 0.0), 0.0).r, + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(2.0, 0.0), 0.0).r, + local.x); + float row2 = cultmath_catmullrom( + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(-1.0, 1.0), 0.0).r, + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(0.0, 1.0), 0.0).r, + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(1.0, 1.0), 0.0).r, + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(2.0, 1.0), 0.0).r, + local.x); + float row3 = cultmath_catmullrom( + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(-1.0, 2.0), 0.0).r, + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(0.0, 2.0), 0.0).r, + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(1.0, 2.0), 0.0).r, + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(2.0, 2.0), 0.0).r, + local.x); + + return cultmath_catmullrom(row0, row1, row2, row3, local.y); +} + +#endif diff --git a/src/CultMath/CultMath.csproj b/src/CultMath/CultMath.csproj index 83f6fb9d..f43adce3 100644 --- a/src/CultMath/CultMath.csproj +++ b/src/CultMath/CultMath.csproj @@ -17,6 +17,7 @@ + diff --git a/src/CultMath/math.cs b/src/CultMath/math.cs index 6d44f900..817aa7fd 100644 --- a/src/CultMath/math.cs +++ b/src/CultMath/math.cs @@ -6,6 +6,16 @@ public static class math public const float TAU = MathF.PI * 2.0f; public const float HALF_PI = MathF.PI * 0.5f; + public static float2 float2(float x, float y) => new(x, y); + public static float2 float2(float value) => new(value, value); + public static float3 float3(float x, float y, float z) => new(x, y, z); + public static float3 float3(float2 xy, float z) => new(xy, z); + public static float3 float3(float value) => new(value, value, value); + public static float4 float4(float x, float y, float z, float w) => new(x, y, z, w); + public static float4 float4(float2 xy, float z, float w) => new(xy, z, w); + public static float4 float4(float3 xyz, float w) => new(xyz, w); + public static float4 float4(float value) => new(value, value, value, value); + public static float radians(float degrees) => degrees * (PI / 180.0f); public static float degrees(float radians) => radians * (180.0f / PI); public static float sin(float value) => MathF.Sin(value); @@ -16,6 +26,10 @@ public static class math public static float atan(float value) => MathF.Atan(value); public static float atan2(float y, float x) => MathF.Atan2(y, x); public static float sqrt(float value) => MathF.Sqrt(value); + public static float exp(float value) => MathF.Exp(value); + public static float2 exp(float2 value) => new(exp(value.x), exp(value.y)); + public static float3 exp(float3 value) => new(exp(value.x), exp(value.y), exp(value.z)); + public static float4 exp(float4 value) => new(exp(value.x), exp(value.y), exp(value.z), exp(value.w)); public static float abs(float value) => MathF.Abs(value); public static float2 abs(float2 value) => new(abs(value.x), abs(value.y)); @@ -119,4 +133,192 @@ public static class math public static float2 reflect(float2 incident, float2 normal) => incident - 2.0f * dot(normal, incident) * normal; public static float3 reflect(float3 incident, float3 normal) => incident - 2.0f * dot(normal, incident) * normal; + + public static float csum(float2 value) => value.x + value.y; + public static float csum(float3 value) => value.x + value.y + value.z; + public static float csum(float4 value) => value.x + value.y + value.z + value.w; + + public static float decay(float source, float lambda, float dt) => source * exp(-lambda * dt); + public static float2 decay(float2 source, float lambda, float dt) => source * exp(-lambda * dt); + public static float3 decay(float3 source, float lambda, float dt) => source * exp(-lambda * dt); + public static float4 decay(float4 source, float lambda, float dt) => source * exp(-lambda * dt); + public static float2 decay(float2 source, float2 lambda, float dt) => source * exp(-lambda * dt); + public static float3 decay(float3 source, float3 lambda, float dt) => source * exp(-lambda * dt); + public static float4 decay(float4 source, float4 lambda, float dt) => source * exp(-lambda * dt); + + public static float damp(float start, float end, float lambda, float dt) => lerp(start, end, 1.0f - exp(-lambda * dt)); + public static float2 damp(float2 start, float2 end, float lambda, float dt) => lerp(start, end, 1.0f - exp(-lambda * dt)); + public static float3 damp(float3 start, float3 end, float lambda, float dt) => lerp(start, end, 1.0f - exp(-lambda * dt)); + public static float4 damp(float4 start, float4 end, float lambda, float dt) => lerp(start, end, 1.0f - exp(-lambda * dt)); + + public static float first_order_intercept_time(float shotSpeed, float3 targetRelativePosition, float3 targetRelativeVelocity) + { + var velocitySquared = lengthsq(targetRelativeVelocity); + if (velocitySquared < 0.001f) + { + return 0.0f; + } + + var a = velocitySquared - shotSpeed * shotSpeed; + if (abs(a) < 0.001f) + { + var time = -lengthsq(targetRelativePosition) / (2.0f * dot(targetRelativeVelocity, targetRelativePosition)); + return max(time, 0.0f); + } + + var b = 2.0f * dot(targetRelativeVelocity, targetRelativePosition); + var c = lengthsq(targetRelativePosition); + var determinant = b * b - 4.0f * a * c; + + if (determinant > 0.0f) + { + var root = sqrt(determinant); + var t1 = (-b + root) / (2.0f * a); + var t2 = (-b - root) / (2.0f * a); + if (t1 > 0.0f) + { + return t2 > 0.0f ? min(t1, t2) : t1; + } + + return max(t2, 0.0f); + } + + if (determinant < 0.0f) + { + return 0.0f; + } + + return max(-b / (2.0f * a), 0.0f); + } + + public static float3 first_order_intercept( + float3 shooterPosition, + float3 shooterVelocity, + float shotSpeed, + float3 targetPosition, + float3 targetVelocity) + { + var targetRelativePosition = targetPosition - shooterPosition; + var targetRelativeVelocity = targetVelocity - shooterVelocity; + var time = first_order_intercept_time(shotSpeed, targetRelativePosition, targetRelativeVelocity); + return targetPosition + time * targetRelativeVelocity; + } + + public static float distance_to_segment(float2 point, float2 start, float2 end, out float2 closest) + { + var segment = end - start; + var segmentLengthSq = lengthsq(segment); + if (segmentLengthSq <= 0.0f) + { + closest = start; + return distance(point, start); + } + + var t = saturate(dot(point - start, segment) / segmentLengthSq); + closest = start + segment * t; + return distance(point, closest); + } + + public static float catmullrom(float p0, float p1, float p2, float p3, float t) + { + var t2 = t * t; + var t3 = t2 * t; + return 0.5f * ((2.0f * p1) + (p2 - p0) * t + (2.0f * p0 - 5.0f * p1 + 4.0f * p2 - p3) * t2 + (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * t3); + } + + public static float2 catmullrom(float2 p0, float2 p1, float2 p2, float2 p3, float t) => + 0.5f * ((2.0f * p1) + (p2 - p0) * t + (2.0f * p0 - 5.0f * p1 + 4.0f * p2 - p3) * (t * t) + (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * (t * t * t)); + + public static float3 catmullrom(float3 p0, float3 p1, float3 p2, float3 p3, float t) => + 0.5f * ((2.0f * p1) + (p2 - p0) * t + (2.0f * p0 - 5.0f * p1 + 4.0f * p2 - p3) * (t * t) + (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * (t * t * t)); + + public static float4 catmullrom(float4 p0, float4 p1, float4 p2, float4 p3, float t) => + 0.5f * ((2.0f * p1) + (p2 - p0) * t + (2.0f * p0 - 5.0f * p1 + 4.0f * p2 - p3) * (t * t) + (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * (t * t * t)); + + public static float quadratic_bezier(float p0, float p1, float p2, float t) + { + t = saturate(t); + var inv = 1.0f - t; + return inv * inv * p0 + 2.0f * inv * t * p1 + t * t * p2; + } + + public static float3 quadratic_bezier(float3 p0, float3 p1, float3 p2, float t) + { + t = saturate(t); + var inv = 1.0f - t; + return inv * inv * p0 + 2.0f * inv * t * p1 + t * t * p2; + } + + public static float cubic_bezier(float p0, float p1, float p2, float p3, float t) + { + t = saturate(t); + var inv = 1.0f - t; + return inv * inv * inv * p0 + 3.0f * inv * inv * t * p1 + 3.0f * inv * t * t * p2 + t * t * t * p3; + } + + public static float3 cubic_bezier(float3 p0, float3 p1, float3 p2, float3 p3, float t) + { + t = saturate(t); + var inv = 1.0f - t; + return inv * inv * inv * p0 + 3.0f * inv * inv * t * p1 + 3.0f * inv * t * t * p2 + t * t * t * p3; + } + + public static float smoothstep01(float value) => smoothstep(0.0f, 1.0f, value); + + public static float smootherstep(float value) + { + value = saturate(value); + return value * value * value * (value * (value * 6.0f - 15.0f) + 10.0f); + } + + public static float hash(float value) => frac(sin(value) * 43758.5453f); + public static float hash(float2 value) => hash(dot(value, new float2(127.1f, 311.7f))); + public static float hash(float3 value) => hash(dot(value, new float3(127.1f, 311.7f, 74.7f))); + + public static float value_noise(float2 position) + { + var cell = floor(position); + var local = frac(position); + var u = local * local * (3.0f - 2.0f * local); + + var a = hash(cell); + var b = hash(cell + new float2(1.0f, 0.0f)); + var c = hash(cell + new float2(0.0f, 1.0f)); + var d = hash(cell + new float2(1.0f, 1.0f)); + + return lerp(lerp(a, b, u.x), lerp(c, d, u.x), u.y); + } + + public static float value_noise_bicubic(float2 position) + { + var cell = floor(position); + var local = frac(position); + + var y0 = catmullrom( + hash(cell + new float2(-1.0f, -1.0f)), + hash(cell + new float2(0.0f, -1.0f)), + hash(cell + new float2(1.0f, -1.0f)), + hash(cell + new float2(2.0f, -1.0f)), + local.x); + var y1 = catmullrom( + hash(cell + new float2(-1.0f, 0.0f)), + hash(cell + new float2(0.0f, 0.0f)), + hash(cell + new float2(1.0f, 0.0f)), + hash(cell + new float2(2.0f, 0.0f)), + local.x); + var y2 = catmullrom( + hash(cell + new float2(-1.0f, 1.0f)), + hash(cell + new float2(0.0f, 1.0f)), + hash(cell + new float2(1.0f, 1.0f)), + hash(cell + new float2(2.0f, 1.0f)), + local.x); + var y3 = catmullrom( + hash(cell + new float2(-1.0f, 2.0f)), + hash(cell + new float2(0.0f, 2.0f)), + hash(cell + new float2(1.0f, 2.0f)), + hash(cell + new float2(2.0f, 2.0f)), + local.x); + + return catmullrom(y0, y1, y2, y3, local.y); + } } diff --git a/tests/CultMath.Tests/HlslMirrorTests.cs b/tests/CultMath.Tests/HlslMirrorTests.cs new file mode 100644 index 00000000..91a95f4d --- /dev/null +++ b/tests/CultMath.Tests/HlslMirrorTests.cs @@ -0,0 +1,63 @@ +using Xunit; + +namespace CultMath.Tests; + +public sealed class HlslMirrorTests +{ + [Fact] + public void HlslMirrorPublishesCultMathPrimitives() + { + var include = File.ReadAllText(Path.Combine(GetRepositoryRoot(), "shaders", "CultMath.hlsl")); + var requiredSymbols = new[] + { + "cultmath_radians", + "cultmath_degrees", + "cultmath_frac", + "cultmath_clamp", + "cultmath_saturate", + "cultmath_lerp", + "cultmath_step", + "cultmath_smoothstep", + "cultmath_smootherstep", + "cultmath_lengthsq", + "cultmath_distance", + "cultmath_normalize", + "cultmath_reflect", + "cultmath_csum", + "cultmath_decay", + "cultmath_damp", + "cultmath_catmullrom", + "cultmath_quadratic_bezier", + "cultmath_cubic_bezier", + "cultmath_hash", + "cultmath_value_noise", + "cultmath_value_noise_bicubic", + "cultmath_value_noise_texture", + "cultmath_value_noise_texture_bicubic", + }; + + foreach (var symbol in requiredSymbols) + { + Assert.Contains(symbol, include); + } + + Assert.Contains("CULTMATH_NORMALIZE_EPSILON", include); + Assert.Contains("max(length(value), CULTMATH_NORMALIZE_EPSILON)", include); + } + + private static string GetRepositoryRoot() + { + var directory = new DirectoryInfo(AppContext.BaseDirectory); + while (directory is not null) + { + if (File.Exists(Path.Combine(directory.FullName, "CultMath.slnx"))) + { + return directory.FullName; + } + + directory = directory.Parent; + } + + throw new InvalidOperationException("Could not locate CultMath repository root."); + } +} diff --git a/tests/CultMath.Tests/MathTests.cs b/tests/CultMath.Tests/MathTests.cs index 2e0cea93..18fa203a 100644 --- a/tests/CultMath.Tests/MathTests.cs +++ b/tests/CultMath.Tests/MathTests.cs @@ -23,6 +23,9 @@ public sealed class MathTests [Fact] public void VectorConstructorsAcceptLowerDimensionVectors() { + Assert.Equal(new float2(1.0f, 2.0f), math.float2(1.0f, 2.0f)); + Assert.Equal(new float3(1.0f, 1.0f, 1.0f), math.float3(1.0f)); + Assert.Equal(new float4(1.0f, 2.0f, 3.0f, 4.0f), math.float4(new float3(1.0f, 2.0f, 3.0f), 4.0f)); Assert.Equal(new float3(1.0f, 2.0f, 3.0f), new float3(new float2(1.0f, 2.0f), 3.0f)); Assert.Equal(new float4(1.0f, 2.0f, 3.0f, 4.0f), new float4(new float2(1.0f, 2.0f), 3.0f, 4.0f)); Assert.Equal(new float4(1.0f, 2.0f, 3.0f, 4.0f), new float4(new float3(1.0f, 2.0f, 3.0f), 4.0f)); @@ -42,6 +45,7 @@ public sealed class MathTests Assert.Equal(0.0f, math.smoothstep(0.0f, 1.0f, -1.0f)); Assert.Equal(0.5f, math.smoothstep(0.0f, 1.0f, 0.5f), precision: 5); Assert.Equal(1.0f, math.smoothstep(0.0f, 1.0f, 2.0f)); + Assert.Equal(0.5f, math.smootherstep(0.5f), precision: 5); } [Fact] @@ -53,6 +57,50 @@ public sealed class MathTests Assert.Equal(math.HALF_PI, math.atan2(1.0f, 0.0f), precision: 5); } + [Fact] + public void AetheriaPrimitivesRemainSmallAndDeterministic() + { + Assert.Equal(6.0f, math.csum(new float3(1.0f, 2.0f, 3.0f))); + Assert.Equal(MathF.Exp(-2.0f), math.decay(1.0f, 2.0f, 1.0f), precision: 5); + Assert.Equal(1.0f - MathF.Exp(-2.0f), math.damp(0.0f, 1.0f, 2.0f, 1.0f), precision: 5); + + Assert.Equal(15.0f, math.catmullrom(0.0f, 10.0f, 20.0f, 30.0f, 0.5f), precision: 5); + Assert.Equal(0.25f, math.quadratic_bezier(0.0f, 0.0f, 1.0f, 0.5f), precision: 5); + Assert.Equal(0.5f, math.cubic_bezier(0.0f, 0.0f, 1.0f, 1.0f, 0.5f), precision: 5); + } + + [Fact] + public void SegmentDistanceReportsClosestPoint() + { + var distance = math.distance_to_segment(new float2(2.0f, 3.0f), new float2(0.0f, 0.0f), new float2(4.0f, 0.0f), out var closest); + + Assert.Equal(3.0f, distance, precision: 5); + Assert.Equal(new float2(2.0f, 0.0f), closest); + } + + [Fact] + public void FirstOrderInterceptSolvesSimpleClosingTarget() + { + var time = math.first_order_intercept_time( + 2.0f, + new float3(10.0f, 0.0f, 0.0f), + new float3(-1.0f, 0.0f, 0.0f)); + + Assert.Equal(10.0f / 3.0f, time, precision: 5); + } + + [Fact] + public void ValueNoiseIsDeterministicAndSmoothAtCellCorners() + { + var position = new float2(12.25f, -4.5f); + + Assert.Equal(math.value_noise(position), math.value_noise(position)); + Assert.Equal(math.hash(new float2(3.0f, 5.0f)), math.value_noise(new float2(3.0f, 5.0f)), precision: 5); + + var bicubic = math.value_noise_bicubic(position); + Assert.True(bicubic > -0.25f && bicubic < 1.25f); + } + [Fact] public void VoronoiBatchProducesToneMappedColors() { From 2c9f81fbf1abec2228569bb5d672aad76b5f1d8e Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 10 Jun 2026 21:30:49 +0100 Subject: [PATCH 006/283] Add HLSL SPIR-V tool scripts --- .gitignore | 1 + README.md | 16 ++++++++++ tools/compile-hlsl-spirv.ps1 | 58 ++++++++++++++++++++++++++++++++++++ tools/get-dxc.ps1 | 42 ++++++++++++++++++++++++++ 4 files changed, 117 insertions(+) create mode 100644 tools/compile-hlsl-spirv.ps1 create mode 100644 tools/get-dxc.ps1 diff --git a/.gitignore b/.gitignore index 6eae4393..5ae20c8e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ obj/ **/obj/ target/ **/target/ +.tools/ diff --git a/README.md b/README.md index ef69df80..7627b773 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,22 @@ cargo test --manifest-path native/cultmath-core/Cargo.toml cargo build --release --manifest-path native/cultmath-core/Cargo.toml ``` +## Shader Tooling + +CultMath keeps portable DXC outside git under `.tools/`: + +```powershell +.\tools\get-dxc.ps1 +.\tools\compile-hlsl-spirv.ps1 ` + -ShaderPath E:\Projects\Odin\crates\muninn-move-tracker\shaders\MoveSphereCandidate.comp.hlsl ` + -OutputPath E:\Projects\Odin\crates\muninn-move-tracker\artifacts\shader\MoveSphereCandidate.comp.spv ` + -IncludePath E:\Projects\CultMath\shaders +``` + +DXC emits Vulkan SPIR-V with `-spirv`. `-TargetEnv vulkan1.2` is exposed by the +script, but the current Windows DXC release compiled this shader successfully +with DXC's default Vulkan target while rejecting the dotted target-env value. + ## Doctrine The goal is mechanical sympathy between CPU-side authoring, native kernels, and diff --git a/tools/compile-hlsl-spirv.ps1 b/tools/compile-hlsl-spirv.ps1 new file mode 100644 index 00000000..98270cb0 --- /dev/null +++ b/tools/compile-hlsl-spirv.ps1 @@ -0,0 +1,58 @@ +param( + [Parameter(Mandatory = $true)] + [string]$ShaderPath, + + [Parameter(Mandatory = $true)] + [string]$OutputPath, + + [string]$EntryPoint = "main", + [string]$Profile = "cs_6_0", + [string[]]$IncludePath = @(), + [string]$TargetEnv = "", + [string]$DxcPath = "" +) + +$ErrorActionPreference = "Stop" + +$repoRoot = Resolve-Path (Join-Path $PSScriptRoot "..") +if (-not $DxcPath) { + $DxcPath = Join-Path $repoRoot ".tools\dxc\current\bin\x64\dxc.exe" +} + +if (-not (Test-Path $DxcPath)) { + throw "DXC not found at '$DxcPath'. Run tools\get-dxc.ps1 first or pass -DxcPath." +} + +$resolvedShader = Resolve-Path $ShaderPath +$resolvedIncludes = @((Join-Path $repoRoot "shaders")) +foreach ($path in $IncludePath) { + $resolvedIncludes += (Resolve-Path $path) +} + +$outputDirectory = Split-Path -Parent $OutputPath +if ($outputDirectory) { + New-Item -ItemType Directory -Force -Path $outputDirectory | Out-Null +} + +$arguments = @( + "-T", $Profile, + "-E", $EntryPoint, + "-spirv" +) + +if ($TargetEnv) { + $arguments += "-fspv-target-env=$TargetEnv" +} + +foreach ($include in $resolvedIncludes) { + $arguments += @("-I", $include) +} + +$arguments += @($resolvedShader, "-Fo", $OutputPath) + +& $DxcPath @arguments +if ($LASTEXITCODE -ne 0) { + throw "dxc.exe failed with exit code $LASTEXITCODE." +} + +Get-Item -LiteralPath $OutputPath diff --git a/tools/get-dxc.ps1 b/tools/get-dxc.ps1 new file mode 100644 index 00000000..2f3363f3 --- /dev/null +++ b/tools/get-dxc.ps1 @@ -0,0 +1,42 @@ +param( + [string]$InstallRoot = ".tools\dxc" +) + +$ErrorActionPreference = "Stop" + +$repoRoot = Resolve-Path (Join-Path $PSScriptRoot "..") +$installPath = Join-Path $repoRoot $InstallRoot +New-Item -ItemType Directory -Force -Path $installPath | Out-Null + +$release = Invoke-RestMethod ` + -Uri "https://api.github.com/repos/microsoft/DirectXShaderCompiler/releases/latest" ` + -Headers @{ "User-Agent" = "CultMath-DXC-Bootstrap" } + +$asset = $release.assets | + Where-Object { $_.name -like "dxc_*.zip" } | + Select-Object -First 1 + +if (-not $asset) { + throw "No Windows dxc_*.zip asset found on the latest DirectXShaderCompiler release." +} + +$zipPath = Join-Path $installPath $asset.name +Remove-Item -LiteralPath $zipPath -Force -ErrorAction SilentlyContinue + +& curl.exe -L --retry 5 --retry-delay 2 --fail -o $zipPath $asset.browser_download_url +if ($LASTEXITCODE -ne 0) { + throw "curl.exe failed with exit code $LASTEXITCODE." +} + +$currentPath = Join-Path $installPath "current" +Remove-Item -LiteralPath $currentPath -Recurse -Force -ErrorAction SilentlyContinue +New-Item -ItemType Directory -Force -Path $currentPath | Out-Null +Expand-Archive -LiteralPath $zipPath -DestinationPath $currentPath -Force + +$dxcPath = Join-Path $currentPath "bin\x64\dxc.exe" +if (-not (Test-Path $dxcPath)) { + throw "DXC x64 executable was not found after extraction." +} + +& $dxcPath --version +Write-Host "DXC installed at $dxcPath" From 788a75dba537be7b475e3b240a5189363272eb1d Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 11 Jun 2026 06:57:22 +0100 Subject: [PATCH 007/283] Add SPIR-V to Metal tooling --- README.md | 9 +++++++++ tools/compile-hlsl-spirv.ps1 | 11 +++++++++++ tools/compile-spirv-metal.ps1 | 34 ++++++++++++++++++++++++++++++++++ tools/get-spirv-cross.ps1 | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+) create mode 100644 tools/compile-spirv-metal.ps1 create mode 100644 tools/get-spirv-cross.ps1 diff --git a/README.md b/README.md index 7627b773..d6623e46 100644 --- a/README.md +++ b/README.md @@ -78,15 +78,24 @@ CultMath keeps portable DXC outside git under `.tools/`: ```powershell .\tools\get-dxc.ps1 +.\tools\get-spirv-cross.ps1 .\tools\compile-hlsl-spirv.ps1 ` -ShaderPath E:\Projects\Odin\crates\muninn-move-tracker\shaders\MoveSphereCandidate.comp.hlsl ` -OutputPath E:\Projects\Odin\crates\muninn-move-tracker\artifacts\shader\MoveSphereCandidate.comp.spv ` -IncludePath E:\Projects\CultMath\shaders +.\tools\compile-spirv-metal.ps1 ` + -SpirvPath E:\Projects\Odin\crates\muninn-move-tracker\artifacts\shader\MoveSphereCandidate.comp.spv ` + -OutputPath E:\Projects\Odin\crates\muninn-move-tracker\artifacts\shader\MoveSphereCandidate.comp.metal ``` DXC emits Vulkan SPIR-V with `-spirv`. `-TargetEnv vulkan1.2` is exposed by the script, but the current Windows DXC release compiled this shader successfully with DXC's default Vulkan target while rejecting the dotted target-env value. +The SPIR-V script applies default Vulkan register shifts for cbuffers, textures, +UAVs, and samplers so cross-compiled Metal buffers do not alias by resource +class. SPIRV-Cross emits Metal Shading Language from SPIR-V on Windows; building +an iPad-ready `.metallib` still belongs to Apple's Metal compiler on an Apple +toolchain. ## Doctrine diff --git a/tools/compile-hlsl-spirv.ps1 b/tools/compile-hlsl-spirv.ps1 index 98270cb0..280e08d5 100644 --- a/tools/compile-hlsl-spirv.ps1 +++ b/tools/compile-hlsl-spirv.ps1 @@ -9,6 +9,10 @@ param( [string]$Profile = "cs_6_0", [string[]]$IncludePath = @(), [string]$TargetEnv = "", + [int]$VulkanCBufferShift = 0, + [int]$VulkanTextureShift = 10, + [int]$VulkanUavShift = 20, + [int]$VulkanSamplerShift = 30, [string]$DxcPath = "" ) @@ -44,6 +48,13 @@ if ($TargetEnv) { $arguments += "-fspv-target-env=$TargetEnv" } +$arguments += @( + "-fvk-b-shift", $VulkanCBufferShift.ToString(), "0", + "-fvk-t-shift", $VulkanTextureShift.ToString(), "0", + "-fvk-u-shift", $VulkanUavShift.ToString(), "0", + "-fvk-s-shift", $VulkanSamplerShift.ToString(), "0" +) + foreach ($include in $resolvedIncludes) { $arguments += @("-I", $include) } diff --git a/tools/compile-spirv-metal.ps1 b/tools/compile-spirv-metal.ps1 new file mode 100644 index 00000000..490e6331 --- /dev/null +++ b/tools/compile-spirv-metal.ps1 @@ -0,0 +1,34 @@ +param( + [Parameter(Mandatory = $true)] + [string]$SpirvPath, + + [Parameter(Mandatory = $true)] + [string]$OutputPath, + + [int]$MslVersion = 23000, + [string]$SpirvCrossPath = "" +) + +$ErrorActionPreference = "Stop" + +$repoRoot = Resolve-Path (Join-Path $PSScriptRoot "..") +if (-not $SpirvCrossPath) { + $SpirvCrossPath = Join-Path $repoRoot ".tools\spirv-cross\build\spirv-cross.exe" +} + +if (-not (Test-Path $SpirvCrossPath)) { + throw "SPIRV-Cross not found at '$SpirvCrossPath'. Run tools\get-spirv-cross.ps1 first or pass -SpirvCrossPath." +} + +$resolvedSpirv = Resolve-Path $SpirvPath +$outputDirectory = Split-Path -Parent $OutputPath +if ($outputDirectory) { + New-Item -ItemType Directory -Force -Path $outputDirectory | Out-Null +} + +& $SpirvCrossPath $resolvedSpirv --msl --msl-version $MslVersion --output $OutputPath +if ($LASTEXITCODE -ne 0) { + throw "spirv-cross failed with exit code $LASTEXITCODE." +} + +Get-Item -LiteralPath $OutputPath diff --git a/tools/get-spirv-cross.ps1 b/tools/get-spirv-cross.ps1 new file mode 100644 index 00000000..f5105b9a --- /dev/null +++ b/tools/get-spirv-cross.ps1 @@ -0,0 +1,34 @@ +param( + [string]$InstallRoot = ".tools\spirv-cross" +) + +$ErrorActionPreference = "Stop" + +$repoRoot = Resolve-Path (Join-Path $PSScriptRoot "..") +$installPath = Join-Path $repoRoot $InstallRoot +$sourcePath = Join-Path $installPath "src" +$buildPath = Join-Path $installPath "build" + +New-Item -ItemType Directory -Force -Path $installPath | Out-Null + +if (-not (Test-Path $sourcePath)) { + git clone --depth 1 https://github.com/KhronosGroup/SPIRV-Cross.git $sourcePath +} + +cmake ` + -S $sourcePath ` + -B $buildPath ` + -G Ninja ` + -DSPIRV_CROSS_CLI=ON ` + -DSPIRV_CROSS_ENABLE_TESTS=OFF ` + -DSPIRV_CROSS_ENABLE_C_API=OFF + +cmake --build $buildPath --target spirv-cross --config Release + +$spirvCrossPath = Join-Path $buildPath "spirv-cross.exe" +if (-not (Test-Path $spirvCrossPath)) { + throw "SPIRV-Cross executable was not found after build." +} + +& $spirvCrossPath --version +Write-Host "SPIRV-Cross installed at $spirvCrossPath" From 26d9996d7b41e9fae09ba47976137e58259a4be9 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 17 Jun 2026 02:53:02 +0100 Subject: [PATCH 008/283] Add SIMD SoA batch math kernels --- README.md | 3 + src/CultMath/BatchMath.cs | 147 ++++++++++++++++++++++++++++++ tests/CultMath.Tests/MathTests.cs | 37 ++++++++ 3 files changed, 187 insertions(+) create mode 100644 src/CultMath/BatchMath.cs diff --git a/README.md b/README.md index d6623e46..1050e4ec 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,9 @@ shader semantics. - scalar-to-vector splats - swizzles for common lanes - conversions to and from `System.Numerics` +- `BatchMath` SoA kernels over `Span` / `ReadOnlySpan` using + `System.Numerics.Vector` when available, including radial falloff + acceleration and semi-implicit Euler integration - `math` intrinsics: `radians`, `degrees`, `abs`, `floor`, `ceil`, `frac`, `min`, `max`, `clamp`, `saturate`, `lerp`, `step`, `smoothstep`, `dot`, `cross`, `length`, `distance`, `normalize`, `reflect`, `csum`, exponential diff --git a/src/CultMath/BatchMath.cs b/src/CultMath/BatchMath.cs new file mode 100644 index 00000000..df62e07c --- /dev/null +++ b/src/CultMath/BatchMath.cs @@ -0,0 +1,147 @@ +using System.Numerics; + +namespace CultMath; + +public static class BatchMath +{ + private const float MinimumDistanceSquared = 1.0e-8f; + + public static int LaneCount => Vector.Count; + + public static bool IsHardwareAccelerated => Vector.IsHardwareAccelerated; + + public static void Clear(Span values) => values.Clear(); + + public static void AddRadialFalloffAcceleration2D( + ReadOnlySpan positionX, + ReadOnlySpan positionY, + float centerX, + float centerY, + float strength, + float radius, + Span accelerationX, + Span accelerationY) + { + ValidateEqualLengths(positionX.Length, positionY.Length, accelerationX.Length, accelerationY.Length); + + if (radius <= 0.0f || strength == 0.0f || positionX.Length == 0) + { + return; + } + + var radiusVector = new Vector(radius); + var centerXVector = new Vector(centerX); + var centerYVector = new Vector(centerY); + var strengthVector = new Vector(strength); + var one = Vector.One; + var zero = Vector.Zero; + var minimumDistanceSquared = new Vector(MinimumDistanceSquared); + + var i = 0; + var lanes = Vector.Count; + for (; i <= positionX.Length - lanes; i += lanes) + { + var px = new Vector(positionX.Slice(i, lanes)); + var py = new Vector(positionY.Slice(i, lanes)); + var dx = centerXVector - px; + var dy = centerYVector - py; + var distanceSquared = Vector.Max(dx * dx + dy * dy, minimumDistanceSquared); + var distance = Vector.SquareRoot(distanceSquared); + var inRange = Vector.LessThanOrEqual(distance, radiusVector); + var falloff = Vector.Max(zero, one - distance / radiusVector); + var magnitude = strengthVector * falloff; + var ax = Vector.ConditionalSelect(inRange, dx / distance * magnitude, zero); + var ay = Vector.ConditionalSelect(inRange, dy / distance * magnitude, zero); + + (new Vector(accelerationX.Slice(i, lanes)) + ax).CopyTo(accelerationX.Slice(i, lanes)); + (new Vector(accelerationY.Slice(i, lanes)) + ay).CopyTo(accelerationY.Slice(i, lanes)); + } + + for (; i < positionX.Length; i++) + { + var dx = centerX - positionX[i]; + var dy = centerY - positionY[i]; + var distanceSquared = MathF.Max(dx * dx + dy * dy, MinimumDistanceSquared); + var distance = MathF.Sqrt(distanceSquared); + if (distance > radius) + { + continue; + } + + var falloff = MathF.Max(0.0f, 1.0f - distance / radius); + var magnitude = strength * falloff; + accelerationX[i] += dx / distance * magnitude; + accelerationY[i] += dy / distance * magnitude; + } + } + + public static void IntegrateSemiImplicitEuler2D( + float deltaTime, + ReadOnlySpan dynamicMask, + Span positionX, + Span positionY, + Span velocityX, + Span velocityY, + ReadOnlySpan accelerationX, + ReadOnlySpan accelerationY) + { + if (deltaTime <= 0.0f) + { + throw new ArgumentOutOfRangeException(nameof(deltaTime), "Delta time must be positive."); + } + + ValidateEqualLengths( + dynamicMask.Length, + positionX.Length, + positionY.Length, + velocityX.Length, + velocityY.Length, + accelerationX.Length, + accelerationY.Length); + + var delta = new Vector(deltaTime); + var i = 0; + var lanes = Vector.Count; + for (; i <= positionX.Length - lanes; i += lanes) + { + var mask = new Vector(dynamicMask.Slice(i, lanes)); + var vx = new Vector(velocityX.Slice(i, lanes)); + var vy = new Vector(velocityY.Slice(i, lanes)); + var px = new Vector(positionX.Slice(i, lanes)); + var py = new Vector(positionY.Slice(i, lanes)); + var ax = new Vector(accelerationX.Slice(i, lanes)); + var ay = new Vector(accelerationY.Slice(i, lanes)); + + vx += ax * delta * mask; + vy += ay * delta * mask; + px += vx * delta * mask; + py += vy * delta * mask; + + vx.CopyTo(velocityX.Slice(i, lanes)); + vy.CopyTo(velocityY.Slice(i, lanes)); + px.CopyTo(positionX.Slice(i, lanes)); + py.CopyTo(positionY.Slice(i, lanes)); + } + + for (; i < positionX.Length; i++) + { + var mask = dynamicMask[i]; + velocityX[i] += accelerationX[i] * deltaTime * mask; + velocityY[i] += accelerationY[i] * deltaTime * mask; + positionX[i] += velocityX[i] * deltaTime * mask; + positionY[i] += velocityY[i] * deltaTime * mask; + } + } + + private static void ValidateEqualLengths(params int[] lengths) + { + var length = lengths[0]; + for (var i = 1; i < lengths.Length; i++) + { + if (lengths[i] != length) + { + throw new ArgumentException("CultMath batch spans must have equal length."); + } + } + } +} diff --git a/tests/CultMath.Tests/MathTests.cs b/tests/CultMath.Tests/MathTests.cs index 18fa203a..44dd1290 100644 --- a/tests/CultMath.Tests/MathTests.cs +++ b/tests/CultMath.Tests/MathTests.cs @@ -116,4 +116,41 @@ public sealed class MathTests Assert.True(colors[1].r > colors[1].g); Assert.True(colors[2].r > 120 && colors[2].g > 120 && colors[2].b > 120); } + + [Fact] + public void BatchRadialFalloffAccelerationMatchesScalarContract() + { + var xs = new[] { 0.0f, 5.0f, 10.0f }; + var ys = new[] { 0.0f, 0.0f, 0.0f }; + var ax = new float[xs.Length]; + var ay = new float[xs.Length]; + + BatchMath.AddRadialFalloffAcceleration2D(xs, ys, 10.0f, 0.0f, 10.0f, 20.0f, ax, ay); + + Assert.True(BatchMath.LaneCount >= 4); + Assert.Equal(5.0f, ax[0], precision: 5); + Assert.Equal(7.5f, ax[1], precision: 5); + Assert.Equal(0.0f, ax[2], precision: 5); + Assert.Equal(0.0f, ay[0], precision: 5); + } + + [Fact] + public void BatchEulerIntegrationHonorsDynamicMask() + { + var dynamicMask = new[] { 1.0f, 0.0f }; + var px = new[] { 0.0f, 0.0f }; + var py = new[] { 0.0f, 0.0f }; + var vx = new[] { 1.0f, 1.0f }; + var vy = new[] { 0.0f, 0.0f }; + var ax = new[] { 2.0f, 2.0f }; + var ay = new[] { 0.0f, 4.0f }; + + BatchMath.IntegrateSemiImplicitEuler2D(0.5f, dynamicMask, px, py, vx, vy, ax, ay); + + Assert.Equal(2.0f, vx[0], precision: 5); + Assert.Equal(1.0f, px[0], precision: 5); + Assert.Equal(1.0f, vx[1], precision: 5); + Assert.Equal(0.0f, px[1], precision: 5); + Assert.Equal(0.0f, py[1], precision: 5); + } } From ab6a2c6456ec4b48311857daf24494f76cd1ca78 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 12 Jul 2026 19:33:59 +0100 Subject: [PATCH 009/283] Complete portable CultMath runtime surface --- CultMath.slnx.meta | 7 + Directory.Build.props | 6 + Directory.Build.props.meta | 7 + README.md.meta | 7 + docs.meta | 8 ++ docs/design.md.meta | 7 + global.json.meta | 7 + native.meta | 8 ++ native/cultmath-core.meta | 8 ++ native/cultmath-core/Cargo.lock.meta | 7 + native/cultmath-core/Cargo.toml.meta | 7 + native/cultmath-core/src.meta | 8 ++ native/cultmath-core/src/lib.rs.meta | 7 + package.json | 14 ++ package.json.meta | 7 + shaders.meta | 8 ++ shaders/CultMath.hlsl | 84 +++++++++++ shaders/CultMath.hlsl.meta | 7 + src.meta | 8 ++ src/CultMath.meta | 8 ++ src/CultMath/BatchMath.cs | 128 +++++++++++++++-- src/CultMath/BatchMath.cs.meta | 2 + src/CultMath/Color32.cs.meta | 2 + src/CultMath/CultMath.asmdef | 14 ++ src/CultMath/CultMath.asmdef.meta | 7 + src/CultMath/CultMath.csproj | 3 +- src/CultMath/CultMath.csproj.meta | 7 + src/CultMath/CultMathTone.cs.meta | 2 + src/CultMath/IsExternalInit.cs | 5 + src/CultMath/IsExternalInit.cs.meta | 2 + src/CultMath/Random.cs | 62 ++++++++ src/CultMath/Random.cs.meta | 2 + src/CultMath/SphericalErosion.cs | 108 ++++++++++++++ src/CultMath/Voronoi.cs | 1 + src/CultMath/Voronoi.cs.meta | 2 + src/CultMath/bool2.cs | 18 +++ src/CultMath/bool2.cs.meta | 2 + src/CultMath/double2.cs | 25 ++++ src/CultMath/double2.cs.meta | 2 + src/CultMath/double3.cs | 36 +++++ src/CultMath/double3.cs.meta | 2 + src/CultMath/float2.cs | 4 +- src/CultMath/float2.cs.meta | 2 + src/CultMath/float3.cs | 49 ++++++- src/CultMath/float3.cs.meta | 2 + src/CultMath/float4.cs | 21 ++- src/CultMath/float4.cs.meta | 2 + src/CultMath/int2.cs | 29 ++++ src/CultMath/int2.cs.meta | 2 + src/CultMath/math.cs | 52 +++++++ src/CultMath/math.cs.meta | 2 + src/CultMath/quaternion.cs | 68 +++++++++ src/CultMath/quaternion.cs.meta | 2 + src/CultMath/rect.cs | 21 +++ src/CultMath/rect.cs.meta | 2 + tests.meta | 8 ++ tests/CultMath.Tests.meta | 8 ++ .../CultMath.Tests/CultMath.Tests.csproj.meta | 7 + tests/CultMath.Tests/HlslMirrorTests.cs | 9 ++ tests/CultMath.Tests/HlslMirrorTests.cs.meta | 2 + tests/CultMath.Tests/MathTests.cs | 134 ++++++++++++++++++ tests/CultMath.Tests/MathTests.cs.meta | 2 + tests/CultMath.Tests/SphericalErosionTests.cs | 27 ++++ tools.meta | 8 ++ tools/compile-hlsl-spirv.ps1.meta | 7 + tools/compile-spirv-metal.ps1.meta | 7 + tools/get-dxc.ps1.meta | 7 + tools/get-spirv-cross.ps1.meta | 7 + 68 files changed, 1130 insertions(+), 23 deletions(-) create mode 100644 CultMath.slnx.meta create mode 100644 Directory.Build.props create mode 100644 Directory.Build.props.meta create mode 100644 README.md.meta create mode 100644 docs.meta create mode 100644 docs/design.md.meta create mode 100644 global.json.meta create mode 100644 native.meta create mode 100644 native/cultmath-core.meta create mode 100644 native/cultmath-core/Cargo.lock.meta create mode 100644 native/cultmath-core/Cargo.toml.meta create mode 100644 native/cultmath-core/src.meta create mode 100644 native/cultmath-core/src/lib.rs.meta create mode 100644 package.json create mode 100644 package.json.meta create mode 100644 shaders.meta create mode 100644 shaders/CultMath.hlsl.meta create mode 100644 src.meta create mode 100644 src/CultMath.meta create mode 100644 src/CultMath/BatchMath.cs.meta create mode 100644 src/CultMath/Color32.cs.meta create mode 100644 src/CultMath/CultMath.asmdef create mode 100644 src/CultMath/CultMath.asmdef.meta create mode 100644 src/CultMath/CultMath.csproj.meta create mode 100644 src/CultMath/CultMathTone.cs.meta create mode 100644 src/CultMath/IsExternalInit.cs create mode 100644 src/CultMath/IsExternalInit.cs.meta create mode 100644 src/CultMath/Random.cs create mode 100644 src/CultMath/Random.cs.meta create mode 100644 src/CultMath/SphericalErosion.cs create mode 100644 src/CultMath/Voronoi.cs.meta create mode 100644 src/CultMath/bool2.cs create mode 100644 src/CultMath/bool2.cs.meta create mode 100644 src/CultMath/double2.cs create mode 100644 src/CultMath/double2.cs.meta create mode 100644 src/CultMath/double3.cs create mode 100644 src/CultMath/double3.cs.meta create mode 100644 src/CultMath/float2.cs.meta create mode 100644 src/CultMath/float3.cs.meta create mode 100644 src/CultMath/float4.cs.meta create mode 100644 src/CultMath/int2.cs create mode 100644 src/CultMath/int2.cs.meta create mode 100644 src/CultMath/math.cs.meta create mode 100644 src/CultMath/quaternion.cs create mode 100644 src/CultMath/quaternion.cs.meta create mode 100644 src/CultMath/rect.cs create mode 100644 src/CultMath/rect.cs.meta create mode 100644 tests.meta create mode 100644 tests/CultMath.Tests.meta create mode 100644 tests/CultMath.Tests/CultMath.Tests.csproj.meta create mode 100644 tests/CultMath.Tests/HlslMirrorTests.cs.meta create mode 100644 tests/CultMath.Tests/MathTests.cs.meta create mode 100644 tests/CultMath.Tests/SphericalErosionTests.cs create mode 100644 tools.meta create mode 100644 tools/compile-hlsl-spirv.ps1.meta create mode 100644 tools/compile-spirv-metal.ps1.meta create mode 100644 tools/get-dxc.ps1.meta create mode 100644 tools/get-spirv-cross.ps1.meta diff --git a/CultMath.slnx.meta b/CultMath.slnx.meta new file mode 100644 index 00000000..a33f7974 --- /dev/null +++ b/CultMath.slnx.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d310c959fd7a1d24a981ea6766ee3c59 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 00000000..4df13bd3 --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,6 @@ + + + $(MSBuildThisFileDirectory).tools\dotnet\bin\$(MSBuildProjectName)\ + $(MSBuildThisFileDirectory).tools\dotnet\obj\$(MSBuildProjectName)\ + + diff --git a/Directory.Build.props.meta b/Directory.Build.props.meta new file mode 100644 index 00000000..f41d119d --- /dev/null +++ b/Directory.Build.props.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e041df73afea0094cae9b8d5dcc5e4eb +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/README.md.meta b/README.md.meta new file mode 100644 index 00000000..4411da72 --- /dev/null +++ b/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 867daebafe0ce48479cf043461ee6bdf +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs.meta b/docs.meta new file mode 100644 index 00000000..ee5fab29 --- /dev/null +++ b/docs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: de535b89253410b41b5989f712b80af4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs/design.md.meta b/docs/design.md.meta new file mode 100644 index 00000000..0d31ca6a --- /dev/null +++ b/docs/design.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 07021a8be816e3448a9490c10845b0aa +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/global.json.meta b/global.json.meta new file mode 100644 index 00000000..6c2c0eec --- /dev/null +++ b/global.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 28e4ce693c46cbd4b990c5790745d62f +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/native.meta b/native.meta new file mode 100644 index 00000000..f4135336 --- /dev/null +++ b/native.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9d1cb2ac88c530b4d9da456523115e12 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/native/cultmath-core.meta b/native/cultmath-core.meta new file mode 100644 index 00000000..48a2ef76 --- /dev/null +++ b/native/cultmath-core.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a42d65478346c354c8b4f353c5581b49 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/native/cultmath-core/Cargo.lock.meta b/native/cultmath-core/Cargo.lock.meta new file mode 100644 index 00000000..9ca3ec60 --- /dev/null +++ b/native/cultmath-core/Cargo.lock.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f1c365f7eead2684ba621124e653bdab +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/native/cultmath-core/Cargo.toml.meta b/native/cultmath-core/Cargo.toml.meta new file mode 100644 index 00000000..8875de09 --- /dev/null +++ b/native/cultmath-core/Cargo.toml.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: cdd2d4eab053b764b9a06d36b080e43e +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/native/cultmath-core/src.meta b/native/cultmath-core/src.meta new file mode 100644 index 00000000..8e5232db --- /dev/null +++ b/native/cultmath-core/src.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7de448b7e258d2c448bb7391051cc628 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/native/cultmath-core/src/lib.rs.meta b/native/cultmath-core/src/lib.rs.meta new file mode 100644 index 00000000..2fa8aee8 --- /dev/null +++ b/native/cultmath-core/src/lib.rs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b06c69c432a633f4584830d6b28d4473 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/package.json b/package.json new file mode 100644 index 00000000..6da2a17a --- /dev/null +++ b/package.json @@ -0,0 +1,14 @@ +{ + "name": "org.gamecult.cultmath", + "displayName": "CultMath", + "version": "0.1.0", + "unity": "2021.3", + "description": "Clean-room C# math primitives shaped for HLSL-style renderer and simulation code.", + "keywords": [ + "GameCult", + "Math", + "Simulation" + ], + "license": "MPL-2.0", + "category": "Scripting" +} diff --git a/package.json.meta b/package.json.meta new file mode 100644 index 00000000..23ed71cf --- /dev/null +++ b/package.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1abf066549a826c4ba7a30d6676735c0 +PackageManifestImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/shaders.meta b/shaders.meta new file mode 100644 index 00000000..46f9d445 --- /dev/null +++ b/shaders.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3bed74ebcba445543800218dbe185034 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/shaders/CultMath.hlsl b/shaders/CultMath.hlsl index 3cbb3fdd..07b2b8a9 100644 --- a/shaders/CultMath.hlsl +++ b/shaders/CultMath.hlsl @@ -95,6 +95,18 @@ float3 cultmath_reflect(float3 incident, float3 normal_value) return incident - 2.0 * dot(normal_value, incident) * normal_value; } +float2 cultmath_rotate(float2 value, float radians_value) +{ + float s = sin(radians_value); + float c = cos(radians_value); + return float2(value.x * c - value.y * s, value.x * s + value.y * c); +} + +float2 cultmath_rotate_degrees(float2 value, float degrees_value) +{ + return cultmath_rotate(value, cultmath_radians(degrees_value)); +} + float cultmath_csum(float2 value) { return value.x + value.y; } float cultmath_csum(float3 value) { return value.x + value.y + value.z; } float cultmath_csum(float4 value) { return value.x + value.y + value.z + value.w; } @@ -251,4 +263,76 @@ float cultmath_value_noise_texture_bicubic(Texture2D noise_texture, Sampl return cultmath_catmullrom(row0, row1, row2, row3, local.y); } +struct CultMathSphericalErosionParameters +{ + float frequency; float amplitude; float lacunarity; float gain; + float slope_strength; float detail; float seed; int octaves; +}; + +struct CultMathSphericalErosionSample +{ + float height_offset; float ridge; float gully; float3 gradient; +}; + +float cultmath_spherical_cell_wave(float3 position, float3 flow, float3 cell, float seed) +{ + float3 pivot = cell + float3(cultmath_hash(cell + seed + 11.7), cultmath_hash(cell.yzx + seed + 37.1), cultmath_hash(cell.zyx + seed + 73.9)); + return dot(position - pivot, flow) * 6.28318530718 + cultmath_hash(cell + seed + 101.3) * 6.28318530718; +} + +float cultmath_spherical_directional_wave(float3 position, float3 flow, float seed) +{ + float3 cell = floor(position); + float3 local = cultmath_frac(position); + float3 weights = local * local * (3.0 - 2.0 * local); + float z0 = cultmath_lerp( + cultmath_lerp(cultmath_spherical_cell_wave(position, flow, cell + float3(0,0,0), seed), cultmath_spherical_cell_wave(position, flow, cell + float3(1,0,0), seed), weights.x), + cultmath_lerp(cultmath_spherical_cell_wave(position, flow, cell + float3(0,1,0), seed), cultmath_spherical_cell_wave(position, flow, cell + float3(1,1,0), seed), weights.x), weights.y); + float z1 = cultmath_lerp( + cultmath_lerp(cultmath_spherical_cell_wave(position, flow, cell + float3(0,0,1), seed), cultmath_spherical_cell_wave(position, flow, cell + float3(1,0,1), seed), weights.x), + cultmath_lerp(cultmath_spherical_cell_wave(position, flow, cell + float3(0,1,1), seed), cultmath_spherical_cell_wave(position, flow, cell + float3(1,1,1), seed), weights.x), weights.y); + return cultmath_lerp(z0, z1, weights.z); +} + +float3 cultmath_spherical_stable_tangent(float3 position) +{ + float3 axis = abs(position.z) < 0.8 ? float3(0,0,1) : float3(0,1,0); + return cultmath_normalize(cross(axis, position)); +} + +CultMathSphericalErosionSample cultmath_spherical_erosion(float3 unit_position, float base_height, float3 base_gradient, CultMathSphericalErosionParameters p) +{ + float3 position = cultmath_normalize(unit_position); + float3 gradient = base_gradient - position * dot(base_gradient, position); + float slope = length(gradient); + float3 flow = slope > 1.0e-6 ? -gradient / slope : cultmath_spherical_stable_tangent(position); + float frequency = max(p.frequency, 0.001); + float amplitude = p.amplitude; + float combi_mask = 1.0 - pow(1.0 - cultmath_saturate(slope * p.slope_strength), 2.0); + float fade_target = cultmath_saturate(base_height * 0.5 + 0.5) * 2.0 - 1.0; + CultMathSphericalErosionSample result = (CultMathSphericalErosionSample)0; + [loop] for (int octave = 0; octave < min(max(p.octaves, 0), 8); octave++) + { + float phase = cultmath_spherical_directional_wave(position * frequency, flow, p.seed + octave * 19.19); + float wave = cos(phase); + float wave_slope = sin(phase); + float faded = cultmath_lerp(fade_target, wave, combi_mask); + result.height_offset += faded * amplitude; + result.ridge = max(result.ridge, cultmath_saturate(faded)); + result.gully = max(result.gully, cultmath_saturate(-faded)); + float3 across = cultmath_normalize(cross(position, flow)); + gradient += across * (sign(wave_slope) * amplitude * frequency * combi_mask); + gradient -= position * dot(gradient, position); + slope = length(gradient); + flow = slope > 1.0e-6 ? -gradient / slope : cultmath_spherical_stable_tangent(position); + float new_mask = 1.0 - pow(1.0 - cultmath_saturate(abs(wave_slope) * 1.35), 2.0); + combi_mask = (1.0 - pow(1.0 - cultmath_saturate(combi_mask), max(p.detail, 0.001))) * new_mask; + fade_target = faded; + frequency *= max(p.lacunarity, 1.01); + amplitude *= cultmath_saturate(p.gain); + } + result.gradient = gradient; + return result; +} + #endif diff --git a/shaders/CultMath.hlsl.meta b/shaders/CultMath.hlsl.meta new file mode 100644 index 00000000..d6b8542e --- /dev/null +++ b/shaders/CultMath.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 33174674795143c4a905408718f956f8 +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src.meta b/src.meta new file mode 100644 index 00000000..3e88fcb9 --- /dev/null +++ b/src.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 64f48d0cae0810e4ba9903e9094fe4c6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/CultMath.meta b/src/CultMath.meta new file mode 100644 index 00000000..381b726d --- /dev/null +++ b/src/CultMath.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e857b457b93397d4fb4ad8481cb72e4c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/CultMath/BatchMath.cs b/src/CultMath/BatchMath.cs index df62e07c..04c042d9 100644 --- a/src/CultMath/BatchMath.cs +++ b/src/CultMath/BatchMath.cs @@ -1,3 +1,4 @@ +using System; using System.Numerics; namespace CultMath; @@ -39,10 +40,19 @@ public static class BatchMath var i = 0; var lanes = Vector.Count; + var pxBuffer = new float[lanes]; + var pyBuffer = new float[lanes]; + var axBuffer = new float[lanes]; + var ayBuffer = new float[lanes]; for (; i <= positionX.Length - lanes; i += lanes) { - var px = new Vector(positionX.Slice(i, lanes)); - var py = new Vector(positionY.Slice(i, lanes)); + CopySpanToArray(positionX.Slice(i, lanes), pxBuffer); + CopySpanToArray(positionY.Slice(i, lanes), pyBuffer); + CopySpanToArray(accelerationX.Slice(i, lanes), axBuffer); + CopySpanToArray(accelerationY.Slice(i, lanes), ayBuffer); + + var px = new Vector(pxBuffer); + var py = new Vector(pyBuffer); var dx = centerXVector - px; var dy = centerYVector - py; var distanceSquared = Vector.Max(dx * dx + dy * dy, minimumDistanceSquared); @@ -53,8 +63,10 @@ public static class BatchMath var ax = Vector.ConditionalSelect(inRange, dx / distance * magnitude, zero); var ay = Vector.ConditionalSelect(inRange, dy / distance * magnitude, zero); - (new Vector(accelerationX.Slice(i, lanes)) + ax).CopyTo(accelerationX.Slice(i, lanes)); - (new Vector(accelerationY.Slice(i, lanes)) + ay).CopyTo(accelerationY.Slice(i, lanes)); + (new Vector(axBuffer) + ax).CopyTo(axBuffer); + (new Vector(ayBuffer) + ay).CopyTo(ayBuffer); + CopyArrayToSpan(axBuffer, accelerationX.Slice(i, lanes)); + CopyArrayToSpan(ayBuffer, accelerationY.Slice(i, lanes)); } for (; i < positionX.Length; i++) @@ -75,6 +87,35 @@ public static class BatchMath } } + public static void AddRadialFalloffAcceleration2D( + ReadOnlySpan positions, + float2 center, + float strength, + float radius, + Span acceleration) + { + ValidateEqualLengths(positions.Length, acceleration.Length); + + if (radius <= 0.0f || strength == 0.0f || positions.Length == 0) + { + return; + } + + for (var i = 0; i < positions.Length; i++) + { + var delta = center - positions[i]; + var distanceSquared = MathF.Max(delta.x * delta.x + delta.y * delta.y, MinimumDistanceSquared); + var distance = MathF.Sqrt(distanceSquared); + if (distance > radius) + { + continue; + } + + var falloff = MathF.Max(0.0f, 1.0f - distance / radius); + acceleration[i] += delta / distance * (strength * falloff); + } + } + public static void IntegrateSemiImplicitEuler2D( float deltaTime, ReadOnlySpan dynamicMask, @@ -102,25 +143,44 @@ public static class BatchMath var delta = new Vector(deltaTime); var i = 0; var lanes = Vector.Count; + var maskBuffer = new float[lanes]; + var pxBuffer = new float[lanes]; + var pyBuffer = new float[lanes]; + var vxBuffer = new float[lanes]; + var vyBuffer = new float[lanes]; + var axBuffer = new float[lanes]; + var ayBuffer = new float[lanes]; for (; i <= positionX.Length - lanes; i += lanes) { - var mask = new Vector(dynamicMask.Slice(i, lanes)); - var vx = new Vector(velocityX.Slice(i, lanes)); - var vy = new Vector(velocityY.Slice(i, lanes)); - var px = new Vector(positionX.Slice(i, lanes)); - var py = new Vector(positionY.Slice(i, lanes)); - var ax = new Vector(accelerationX.Slice(i, lanes)); - var ay = new Vector(accelerationY.Slice(i, lanes)); + CopySpanToArray(dynamicMask.Slice(i, lanes), maskBuffer); + CopySpanToArray(velocityX.Slice(i, lanes), vxBuffer); + CopySpanToArray(velocityY.Slice(i, lanes), vyBuffer); + CopySpanToArray(positionX.Slice(i, lanes), pxBuffer); + CopySpanToArray(positionY.Slice(i, lanes), pyBuffer); + CopySpanToArray(accelerationX.Slice(i, lanes), axBuffer); + CopySpanToArray(accelerationY.Slice(i, lanes), ayBuffer); + + var mask = new Vector(maskBuffer); + var vx = new Vector(vxBuffer); + var vy = new Vector(vyBuffer); + var px = new Vector(pxBuffer); + var py = new Vector(pyBuffer); + var ax = new Vector(axBuffer); + var ay = new Vector(ayBuffer); vx += ax * delta * mask; vy += ay * delta * mask; px += vx * delta * mask; py += vy * delta * mask; - vx.CopyTo(velocityX.Slice(i, lanes)); - vy.CopyTo(velocityY.Slice(i, lanes)); - px.CopyTo(positionX.Slice(i, lanes)); - py.CopyTo(positionY.Slice(i, lanes)); + vx.CopyTo(vxBuffer); + vy.CopyTo(vyBuffer); + px.CopyTo(pxBuffer); + py.CopyTo(pyBuffer); + CopyArrayToSpan(vxBuffer, velocityX.Slice(i, lanes)); + CopyArrayToSpan(vyBuffer, velocityY.Slice(i, lanes)); + CopyArrayToSpan(pxBuffer, positionX.Slice(i, lanes)); + CopyArrayToSpan(pyBuffer, positionY.Slice(i, lanes)); } for (; i < positionX.Length; i++) @@ -133,6 +193,28 @@ public static class BatchMath } } + public static void IntegrateSemiImplicitEuler2D( + float deltaTime, + ReadOnlySpan dynamicMask, + Span position, + Span velocity, + ReadOnlySpan acceleration) + { + if (deltaTime <= 0.0f) + { + throw new ArgumentOutOfRangeException(nameof(deltaTime), "Delta time must be positive."); + } + + ValidateEqualLengths(dynamicMask.Length, position.Length, velocity.Length, acceleration.Length); + + for (var i = 0; i < position.Length; i++) + { + var mask = dynamicMask[i]; + velocity[i] += acceleration[i] * deltaTime * mask; + position[i] += velocity[i] * deltaTime * mask; + } + } + private static void ValidateEqualLengths(params int[] lengths) { var length = lengths[0]; @@ -144,4 +226,20 @@ public static class BatchMath } } } + + private static void CopySpanToArray(ReadOnlySpan source, float[] destination) + { + for (var i = 0; i < source.Length; i++) + { + destination[i] = source[i]; + } + } + + private static void CopyArrayToSpan(float[] source, Span destination) + { + for (var i = 0; i < destination.Length; i++) + { + destination[i] = source[i]; + } + } } diff --git a/src/CultMath/BatchMath.cs.meta b/src/CultMath/BatchMath.cs.meta new file mode 100644 index 00000000..fe7c6033 --- /dev/null +++ b/src/CultMath/BatchMath.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d4771320e190bdd408dd296c293a9d0e \ No newline at end of file diff --git a/src/CultMath/Color32.cs.meta b/src/CultMath/Color32.cs.meta new file mode 100644 index 00000000..71e1ba55 --- /dev/null +++ b/src/CultMath/Color32.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: bfa14a9aacb8ac4448761568643f2bc6 \ No newline at end of file diff --git a/src/CultMath/CultMath.asmdef b/src/CultMath/CultMath.asmdef new file mode 100644 index 00000000..449549f6 --- /dev/null +++ b/src/CultMath/CultMath.asmdef @@ -0,0 +1,14 @@ +{ + "name": "CultMath", + "rootNamespace": "CultMath", + "references": [], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": true, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": true +} diff --git a/src/CultMath/CultMath.asmdef.meta b/src/CultMath/CultMath.asmdef.meta new file mode 100644 index 00000000..5a26d2c5 --- /dev/null +++ b/src/CultMath/CultMath.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f0b66b909d13e18468f7aa56221531e9 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/CultMath/CultMath.csproj b/src/CultMath/CultMath.csproj index f43adce3..01901b6b 100644 --- a/src/CultMath/CultMath.csproj +++ b/src/CultMath/CultMath.csproj @@ -1,9 +1,10 @@ - net8.0 + net8.0;netstandard2.1 enable enable + latest CultMath CultMath CultMath diff --git a/src/CultMath/CultMath.csproj.meta b/src/CultMath/CultMath.csproj.meta new file mode 100644 index 00000000..78fc304d --- /dev/null +++ b/src/CultMath/CultMath.csproj.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 77e1a0a2512910f41885650a7d0d6f60 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/CultMath/CultMathTone.cs.meta b/src/CultMath/CultMathTone.cs.meta new file mode 100644 index 00000000..f41d1475 --- /dev/null +++ b/src/CultMath/CultMathTone.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d4bfc66f9f7e992448f884c2c338d50a \ No newline at end of file diff --git a/src/CultMath/IsExternalInit.cs b/src/CultMath/IsExternalInit.cs new file mode 100644 index 00000000..b05eb4a1 --- /dev/null +++ b/src/CultMath/IsExternalInit.cs @@ -0,0 +1,5 @@ +namespace System.Runtime.CompilerServices; + +internal static class IsExternalInit +{ +} diff --git a/src/CultMath/IsExternalInit.cs.meta b/src/CultMath/IsExternalInit.cs.meta new file mode 100644 index 00000000..ca761bcb --- /dev/null +++ b/src/CultMath/IsExternalInit.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: de2b3c3e7f03c354aa2b84fbbc55b497 \ No newline at end of file diff --git a/src/CultMath/Random.cs b/src/CultMath/Random.cs new file mode 100644 index 00000000..9931a87f --- /dev/null +++ b/src/CultMath/Random.cs @@ -0,0 +1,62 @@ +namespace CultMath; + +public struct Random +{ + private const uint DefaultSeed = 0x6E624EB7u; + + public uint state; + + public Random(uint seed) + { + state = seed == 0 ? DefaultSeed : seed; + } + + public static Random CreateFromIndex(uint index) => new(index + DefaultSeed); + + public void InitState(uint seed) + { + state = seed == 0 ? DefaultSeed : seed; + } + + public uint NextUInt() + { + var x = state == 0 ? DefaultSeed : state; + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + state = x == 0 ? DefaultSeed : x; + return state; + } + + public int NextInt(int max) => NextInt(0, max); + + public int NextInt(int min, int max) + { + if (max <= min) + { + return min; + } + + return min + (int)(NextUInt() % (uint)(max - min)); + } + + public float NextFloat() => (NextUInt() >> 8) * (1.0f / 16777216.0f); + + public float NextFloat(float max) => NextFloat() * max; + + public float NextFloat(float min, float max) => min + NextFloat() * (max - min); + + public float2 NextFloat2() => new(NextFloat(), NextFloat()); + + public float2 NextFloat2(float min, float max) => new(NextFloat(min, max), NextFloat(min, max)); + + public float2 NextFloat2(float2 min, float2 max) => min + NextFloat2() * (max - min); + + public float2 NextFloat2Direction() + { + var angle = NextFloat(0.0f, math.TAU); + return new float2(math.cos(angle), math.sin(angle)); + } + + public float3 NextFloat3(float3 min, float3 max) => min + new float3(NextFloat(), NextFloat(), NextFloat()) * (max - min); +} diff --git a/src/CultMath/Random.cs.meta b/src/CultMath/Random.cs.meta new file mode 100644 index 00000000..55032ded --- /dev/null +++ b/src/CultMath/Random.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7c1a557259026da4ca20b54264852c13 \ No newline at end of file diff --git a/src/CultMath/SphericalErosion.cs b/src/CultMath/SphericalErosion.cs new file mode 100644 index 00000000..93ddb0ec --- /dev/null +++ b/src/CultMath/SphericalErosion.cs @@ -0,0 +1,108 @@ +namespace CultMath; + +public readonly record struct SphericalErosionParameters( + float Frequency, + float Amplitude, + float Lacunarity, + float Gain, + float SlopeStrength, + float Detail, + float Seed, + int Octaves) +{ + public static SphericalErosionParameters Default => new(18.0f, 0.035f, 2.03f, 0.52f, 6.0f, 1.35f, 0.0f, 5); +} + +public readonly record struct SphericalErosionSample(float HeightOffset, float Ridge, float Gully, float3 Gradient); + +/// +/// Stateless, point-evaluable erosion-like synthesis on a unit sphere. +/// The matching shader body is cultmath_spherical_erosion in CultMath.hlsl. +/// Position and gradient are planet-space; the gradient is projected tangent +/// internally so cube faces and tile request order never enter the result. +/// +public static class SphericalErosion +{ + public static SphericalErosionSample Sample( + float3 unitPosition, + float baseHeight, + float3 baseGradient, + SphericalErosionParameters parameters) + { + var position = math.normalize(unitPosition); + var gradient = baseGradient - position * math.dot(baseGradient, position); + var slope = math.length(gradient); + var flow = slope > 1.0e-6f ? -gradient / slope : StableTangent(position); + var frequency = math.max(parameters.Frequency, 0.001f); + var amplitude = parameters.Amplitude; + var combiMask = EaseOut(math.saturate(slope * parameters.SlopeStrength)); + var fadeTarget = math.saturate(baseHeight * 0.5f + 0.5f) * 2.0f - 1.0f; + var heightOffset = 0.0f; + var ridge = 0.0f; + var gully = 0.0f; + + var octaveCount = math.min(math.max(parameters.Octaves, 0), 8); + for (var octave = 0; octave < octaveCount; octave++) + { + var phase = DirectionalCellWave(position * frequency, flow, parameters.Seed + octave * 19.19f); + var wave = math.cos(phase); + var waveSlope = math.sin(phase); + var faded = math.lerp(fadeTarget, wave, combiMask); + heightOffset += faded * amplitude; + ridge = math.max(ridge, math.saturate(faded)); + gully = math.max(gully, math.saturate(-faded)); + + var across = math.normalize(math.cross(position, flow)); + gradient += across * (math.sign(waveSlope) * amplitude * frequency * combiMask); + gradient -= position * math.dot(gradient, position); + slope = math.length(gradient); + flow = slope > 1.0e-6f ? -gradient / slope : StableTangent(position); + + var newMask = EaseOut(math.saturate(math.abs(waveSlope) * 1.35f)); + combiMask = PowInverse(combiMask, parameters.Detail) * newMask; + fadeTarget = faded; + frequency *= math.max(parameters.Lacunarity, 1.01f); + amplitude *= math.saturate(parameters.Gain); + } + + return new SphericalErosionSample(heightOffset, ridge, gully, gradient); + } + + private static float DirectionalCellWave(float3 position, float3 flow, float seed) + { + var cell = math.floor(position); + var local = math.frac(position); + var weights = local * local * (3.0f - 2.0f * local); + var x00 = CellWave(position, flow, cell + new float3(0, 0, 0), seed); + var x10 = CellWave(position, flow, cell + new float3(1, 0, 0), seed); + var x01 = CellWave(position, flow, cell + new float3(0, 1, 0), seed); + var x11 = CellWave(position, flow, cell + new float3(1, 1, 0), seed); + var y00 = math.lerp(x00, x10, weights.x); + var y10 = math.lerp(x01, x11, weights.x); + var z0 = math.lerp(y00, y10, weights.y); + var x00z = CellWave(position, flow, cell + new float3(0, 0, 1), seed); + var x10z = CellWave(position, flow, cell + new float3(1, 0, 1), seed); + var x01z = CellWave(position, flow, cell + new float3(0, 1, 1), seed); + var x11z = CellWave(position, flow, cell + new float3(1, 1, 1), seed); + var z1 = math.lerp(math.lerp(x00z, x10z, weights.x), math.lerp(x01z, x11z, weights.x), weights.y); + return math.lerp(z0, z1, weights.z); + } + + private static float CellWave(float3 position, float3 flow, float3 cell, float seed) + { + var pivot = cell + new float3( + math.hash(cell + seed + 11.7f), + math.hash(cell.yzx + seed + 37.1f), + math.hash(cell.zyx + seed + 73.9f)); + return math.dot(position - pivot, flow) * math.TAU + math.hash(cell + seed + 101.3f) * math.TAU; + } + + private static float3 StableTangent(float3 position) + { + var axis = math.abs(position.z) < 0.8f ? new float3(0, 0, 1) : new float3(0, 1, 0); + return math.normalize(math.cross(axis, position)); + } + + private static float EaseOut(float value) => 1.0f - (1.0f - value) * (1.0f - value); + private static float PowInverse(float value, float power) => 1.0f - math.pow(1.0f - math.saturate(value), math.max(power, 0.001f)); +} diff --git a/src/CultMath/Voronoi.cs b/src/CultMath/Voronoi.cs index 9791a8e0..38b52d81 100644 --- a/src/CultMath/Voronoi.cs +++ b/src/CultMath/Voronoi.cs @@ -1,3 +1,4 @@ +using System; using System.Runtime.InteropServices; namespace CultMath; diff --git a/src/CultMath/Voronoi.cs.meta b/src/CultMath/Voronoi.cs.meta new file mode 100644 index 00000000..6c738085 --- /dev/null +++ b/src/CultMath/Voronoi.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: cb530f1428ac8ff43939b986986ae959 \ No newline at end of file diff --git a/src/CultMath/bool2.cs b/src/CultMath/bool2.cs new file mode 100644 index 00000000..95ab29eb --- /dev/null +++ b/src/CultMath/bool2.cs @@ -0,0 +1,18 @@ +using System; + +namespace CultMath; + +public record struct bool2(bool x, bool y) +{ + public static readonly bool2 @false = new(false, false); + public static readonly bool2 @true = new(true, true); + + public bool this[int index] => index switch + { + 0 => x, + 1 => y, + _ => throw new ArgumentOutOfRangeException(nameof(index)), + }; + + public static implicit operator bool2(bool value) => new(value, value); +} diff --git a/src/CultMath/bool2.cs.meta b/src/CultMath/bool2.cs.meta new file mode 100644 index 00000000..477ff144 --- /dev/null +++ b/src/CultMath/bool2.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 725efb2725e987449a3782452f5a95e0 \ No newline at end of file diff --git a/src/CultMath/double2.cs b/src/CultMath/double2.cs new file mode 100644 index 00000000..000c3cb0 --- /dev/null +++ b/src/CultMath/double2.cs @@ -0,0 +1,25 @@ +using System; + +namespace CultMath; + +public record struct double2(double x, double y) +{ + public static readonly double2 zero = new(0.0, 0.0); + public static readonly double2 one = new(1.0, 1.0); + + public double this[int index] => index switch + { + 0 => x, + 1 => y, + _ => throw new ArgumentOutOfRangeException(nameof(index)), + }; + + public static implicit operator double2(double value) => new(value, value); + + public static double2 operator +(double2 value) => value; + public static double2 operator -(double2 value) => new(-value.x, -value.y); + public static double2 operator +(double2 left, double2 right) => new(left.x + right.x, left.y + right.y); + public static double2 operator -(double2 left, double2 right) => new(left.x - right.x, left.y - right.y); + public static double2 operator *(double2 left, double2 right) => new(left.x * right.x, left.y * right.y); + public static double2 operator /(double2 left, double2 right) => new(left.x / right.x, left.y / right.y); +} diff --git a/src/CultMath/double2.cs.meta b/src/CultMath/double2.cs.meta new file mode 100644 index 00000000..61243b2a --- /dev/null +++ b/src/CultMath/double2.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: bbe739a5f0216c3459762d2b5ee7401a \ No newline at end of file diff --git a/src/CultMath/double3.cs b/src/CultMath/double3.cs new file mode 100644 index 00000000..b1427505 --- /dev/null +++ b/src/CultMath/double3.cs @@ -0,0 +1,36 @@ +using System; + +namespace CultMath; + +public record struct double3(double x, double y, double z) +{ + public static readonly double3 zero = new(0.0, 0.0, 0.0); + public static readonly double3 one = new(1.0, 1.0, 1.0); + + public double2 xy + { + get => new(x, y); + set + { + x = value.x; + y = value.y; + } + } + + public double this[int index] => index switch + { + 0 => x, + 1 => y, + 2 => z, + _ => throw new ArgumentOutOfRangeException(nameof(index)), + }; + + public static implicit operator double3(double value) => new(value, value, value); + + public static double3 operator +(double3 value) => value; + public static double3 operator -(double3 value) => new(-value.x, -value.y, -value.z); + public static double3 operator +(double3 left, double3 right) => new(left.x + right.x, left.y + right.y, left.z + right.z); + public static double3 operator -(double3 left, double3 right) => new(left.x - right.x, left.y - right.y, left.z - right.z); + public static double3 operator *(double3 left, double3 right) => new(left.x * right.x, left.y * right.y, left.z * right.z); + public static double3 operator /(double3 left, double3 right) => new(left.x / right.x, left.y / right.y, left.z / right.z); +} diff --git a/src/CultMath/double3.cs.meta b/src/CultMath/double3.cs.meta new file mode 100644 index 00000000..302d13d8 --- /dev/null +++ b/src/CultMath/double3.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 1cbaafd219703ee43ae279aa5cbf407f \ No newline at end of file diff --git a/src/CultMath/float2.cs b/src/CultMath/float2.cs index 1f1d66b1..5298494b 100644 --- a/src/CultMath/float2.cs +++ b/src/CultMath/float2.cs @@ -1,6 +1,8 @@ +using System; + namespace CultMath; -public readonly record struct float2(float x, float y) +public record struct float2(float x, float y) { public static readonly float2 zero = new(0.0f, 0.0f); public static readonly float2 one = new(1.0f, 1.0f); diff --git a/src/CultMath/float2.cs.meta b/src/CultMath/float2.cs.meta new file mode 100644 index 00000000..c82f69ae --- /dev/null +++ b/src/CultMath/float2.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: fa066a0aed5494f499d462a2ebc51e50 \ No newline at end of file diff --git a/src/CultMath/float3.cs b/src/CultMath/float3.cs index 70cfa02b..e9833ae4 100644 --- a/src/CultMath/float3.cs +++ b/src/CultMath/float3.cs @@ -1,6 +1,8 @@ +using System; + namespace CultMath; -public readonly record struct float3(float x, float y, float z) +public record struct float3(float x, float y, float z) { public static readonly float3 zero = new(0.0f, 0.0f, 0.0f); public static readonly float3 one = new(1.0f, 1.0f, 1.0f); @@ -10,9 +12,48 @@ public readonly record struct float3(float x, float y, float z) { } - public float2 xy => new(x, y); - public float2 xz => new(x, z); - public float2 yz => new(y, z); + public float2 xy + { + get => new(x, y); + set + { + x = value.x; + y = value.y; + } + } + + public float2 xz + { + get => new(x, z); + set + { + x = value.x; + z = value.y; + } + } + + public float2 yz + { + get => new(y, z); + set + { + y = value.x; + z = value.y; + } + } + + public float2 zy + { + get => new(z, y); + set + { + z = value.x; + y = value.y; + } + } + + public float3 yzx => new(y, z, x); + public float3 zyx => new(z, y, x); public float this[int index] => index switch { diff --git a/src/CultMath/float3.cs.meta b/src/CultMath/float3.cs.meta new file mode 100644 index 00000000..3c649c4a --- /dev/null +++ b/src/CultMath/float3.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 58a355dd1cf6b9f48a7595eea0c0e1f2 \ No newline at end of file diff --git a/src/CultMath/float4.cs b/src/CultMath/float4.cs index c7bfb404..b6eed097 100644 --- a/src/CultMath/float4.cs +++ b/src/CultMath/float4.cs @@ -1,6 +1,8 @@ +using System; + namespace CultMath; -public readonly record struct float4(float x, float y, float z, float w) +public record struct float4(float x, float y, float z, float w) { public static readonly float4 zero = new(0.0f, 0.0f, 0.0f, 0.0f); public static readonly float4 one = new(1.0f, 1.0f, 1.0f, 1.0f); @@ -15,7 +17,22 @@ public readonly record struct float4(float x, float y, float z, float w) { } - public float2 xy => new(x, y); + public float4(float x, float3 yzw) + : this(x, yzw.x, yzw.y, yzw.z) + { + } + + public float2 xy + { + get => new(x, y); + set + { + x = value.x; + y = value.y; + } + } + public float3 xyw => new(x, y, w); + public float3 yzx => new(y, z, x); public float3 xyz => new(x, y, z); public float this[int index] => index switch diff --git a/src/CultMath/float4.cs.meta b/src/CultMath/float4.cs.meta new file mode 100644 index 00000000..206444e0 --- /dev/null +++ b/src/CultMath/float4.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: fe24fbdab33538849bc6be0afbb0a692 \ No newline at end of file diff --git a/src/CultMath/int2.cs b/src/CultMath/int2.cs new file mode 100644 index 00000000..7c2f350b --- /dev/null +++ b/src/CultMath/int2.cs @@ -0,0 +1,29 @@ +using System; + +namespace CultMath; + +public record struct int2(int x, int y) +{ + public static readonly int2 zero = new(0, 0); + public static readonly int2 one = new(1, 1); + + public int this[int index] => index switch + { + 0 => x, + 1 => y, + _ => throw new ArgumentOutOfRangeException(nameof(index)), + }; + + public static implicit operator int2(int value) => new(value, value); + public static implicit operator float2(int2 value) => new(value.x, value.y); + public static explicit operator System.Numerics.Vector2(int2 value) => new(value.x, value.y); + public static explicit operator int2(System.Numerics.Vector2 value) => new((int)value.X, (int)value.Y); + + public static int2 operator +(int2 value) => value; + public static int2 operator -(int2 value) => new(-value.x, -value.y); + public static int2 operator +(int2 left, int2 right) => new(left.x + right.x, left.y + right.y); + public static int2 operator -(int2 left, int2 right) => new(left.x - right.x, left.y - right.y); + public static int2 operator *(int2 left, int2 right) => new(left.x * right.x, left.y * right.y); + public static int2 operator /(int2 left, int2 right) => new(left.x / right.x, left.y / right.y); + public static int2 operator %(int2 left, int2 right) => new(left.x % right.x, left.y % right.y); +} diff --git a/src/CultMath/int2.cs.meta b/src/CultMath/int2.cs.meta new file mode 100644 index 00000000..5920328a --- /dev/null +++ b/src/CultMath/int2.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 577b174a998aaa4478ec26e7a6782f46 \ No newline at end of file diff --git a/src/CultMath/math.cs b/src/CultMath/math.cs index 817aa7fd..874554ad 100644 --- a/src/CultMath/math.cs +++ b/src/CultMath/math.cs @@ -1,3 +1,5 @@ +using System; + namespace CultMath; public static class math @@ -8,13 +10,20 @@ public static class math public static float2 float2(float x, float y) => new(x, y); public static float2 float2(float value) => new(value, value); + public static bool2 bool2(bool x, bool y) => new(x, y); + public static bool2 bool2(bool value) => new(value, value); + public static int2 int2(int x, int y) => new(x, y); + public static int2 int2(int value) => new(value, value); public static float3 float3(float x, float y, float z) => new(x, y, z); public static float3 float3(float2 xy, float z) => new(xy, z); public static float3 float3(float value) => new(value, value, value); public static float4 float4(float x, float y, float z, float w) => new(x, y, z, w); public static float4 float4(float2 xy, float z, float w) => new(xy, z, w); public static float4 float4(float3 xyz, float w) => new(xyz, w); + public static float4 float4(float x, float3 yzw) => new(x, yzw); public static float4 float4(float value) => new(value, value, value, value); + public static rect rect(float2 min, float2 max) => new(min, max); + public static rect rect(float minX, float minY, float maxX, float maxY) => new(minX, minY, maxX, maxY); public static float radians(float degrees) => degrees * (PI / 180.0f); public static float degrees(float radians) => radians * (180.0f / PI); @@ -26,16 +35,26 @@ public static class math public static float atan(float value) => MathF.Atan(value); public static float atan2(float y, float x) => MathF.Atan2(y, x); public static float sqrt(float value) => MathF.Sqrt(value); + public static float pow(float value, float power) => MathF.Pow(value, power); + public static bool isinf(float value) => float.IsInfinity(value); public static float exp(float value) => MathF.Exp(value); + public static double exp(double value) => Math.Exp(value); public static float2 exp(float2 value) => new(exp(value.x), exp(value.y)); public static float3 exp(float3 value) => new(exp(value.x), exp(value.y), exp(value.z)); public static float4 exp(float4 value) => new(exp(value.x), exp(value.y), exp(value.z), exp(value.w)); + public static double2 exp(double2 value) => new(exp(value.x), exp(value.y)); + public static double3 exp(double3 value) => new(exp(value.x), exp(value.y), exp(value.z)); public static float abs(float value) => MathF.Abs(value); public static float2 abs(float2 value) => new(abs(value.x), abs(value.y)); public static float3 abs(float3 value) => new(abs(value.x), abs(value.y), abs(value.z)); public static float4 abs(float4 value) => new(abs(value.x), abs(value.y), abs(value.z), abs(value.w)); + public static float sign(float value) => MathF.Sign(value); + public static float2 sign(float2 value) => new(sign(value.x), sign(value.y)); + public static float3 sign(float3 value) => new(sign(value.x), sign(value.y), sign(value.z)); + public static float4 sign(float4 value) => new(sign(value.x), sign(value.y), sign(value.z), sign(value.w)); + public static float floor(float value) => MathF.Floor(value); public static float2 floor(float2 value) => new(floor(value.x), floor(value.y)); public static float3 floor(float3 value) => new(floor(value.x), floor(value.y), floor(value.z)); @@ -52,11 +71,13 @@ public static class math public static float4 frac(float4 value) => value - floor(value); public static float min(float left, float right) => MathF.Min(left, right); + public static int min(int left, int right) => Math.Min(left, right); public static float2 min(float2 left, float2 right) => new(min(left.x, right.x), min(left.y, right.y)); public static float3 min(float3 left, float3 right) => new(min(left.x, right.x), min(left.y, right.y), min(left.z, right.z)); public static float4 min(float4 left, float4 right) => new(min(left.x, right.x), min(left.y, right.y), min(left.z, right.z), min(left.w, right.w)); public static float max(float left, float right) => MathF.Max(left, right); + public static int max(int left, int right) => Math.Max(left, right); public static float2 max(float2 left, float2 right) => new(max(left.x, right.x), max(left.y, right.y)); public static float3 max(float3 left, float3 right) => new(max(left.x, right.x), max(left.y, right.y), max(left.z, right.z)); public static float4 max(float4 left, float4 right) => new(max(left.x, right.x), max(left.y, right.y), max(left.z, right.z), max(left.w, right.w)); @@ -72,9 +93,20 @@ public static class math public static float4 saturate(float4 value) => clamp(value, 0.0f, 1.0f); public static float lerp(float start, float end, float amount) => start + (end - start) * amount; + public static double lerp(double start, double end, double amount) => start + (end - start) * amount; public static float2 lerp(float2 start, float2 end, float2 amount) => start + (end - start) * amount; public static float3 lerp(float3 start, float3 end, float3 amount) => start + (end - start) * amount; public static float4 lerp(float4 start, float4 end, float4 amount) => start + (end - start) * amount; + public static double2 lerp(double2 start, double2 end, double2 amount) => start + (end - start) * amount; + public static double3 lerp(double3 start, double3 end, double3 amount) => start + (end - start) * amount; + + public static float unlerp(float start, float end, float value) => (value - start) / (end - start); + public static double unlerp(double start, double end, double value) => (value - start) / (end - start); + public static float2 unlerp(float2 start, float2 end, float2 value) => (value - start) / (end - start); + public static float3 unlerp(float3 start, float3 end, float3 value) => (value - start) / (end - start); + public static float4 unlerp(float4 start, float4 end, float4 value) => (value - start) / (end - start); + public static double2 unlerp(double2 start, double2 end, double2 value) => (value - start) / (end - start); + public static double3 unlerp(double3 start, double3 end, double3 value) => (value - start) / (end - start); public static float step(float edge, float value) => value < edge ? 0.0f : 1.0f; public static float2 step(float2 edge, float2 value) => new(step(edge.x, value.x), step(edge.y, value.y)); @@ -130,10 +162,30 @@ public static class math public static float2 normalize(float2 value) => value / MathF.Max(length(value), 1.0e-20f); public static float3 normalize(float3 value) => value / MathF.Max(length(value), 1.0e-20f); public static float4 normalize(float4 value) => value / MathF.Max(length(value), 1.0e-20f); + public static quaternion normalize(quaternion value) + { + var length = MathF.Sqrt(value.x * value.x + value.y * value.y + value.z * value.z + value.w * value.w); + if (length <= 1.0e-20f) + { + return quaternion.identity; + } + + var invLength = 1.0f / length; + return new quaternion(value.x * invLength, value.y * invLength, value.z * invLength, value.w * invLength); + } public static float2 reflect(float2 incident, float2 normal) => incident - 2.0f * dot(normal, incident) * normal; public static float3 reflect(float3 incident, float3 normal) => incident - 2.0f * dot(normal, incident) * normal; + public static float2 rotate(float2 value, float radians) + { + var s = sin(radians); + var c = cos(radians); + return new float2(value.x * c - value.y * s, value.x * s + value.y * c); + } + + public static float2 rotate_degrees(float2 value, float degrees) => rotate(value, radians(degrees)); + public static float csum(float2 value) => value.x + value.y; public static float csum(float3 value) => value.x + value.y + value.z; public static float csum(float4 value) => value.x + value.y + value.z + value.w; diff --git a/src/CultMath/math.cs.meta b/src/CultMath/math.cs.meta new file mode 100644 index 00000000..9222af7d --- /dev/null +++ b/src/CultMath/math.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 0d9b4cacc40d169429ee743d19577cb7 \ No newline at end of file diff --git a/src/CultMath/quaternion.cs b/src/CultMath/quaternion.cs new file mode 100644 index 00000000..fe8dda8e --- /dev/null +++ b/src/CultMath/quaternion.cs @@ -0,0 +1,68 @@ +namespace CultMath; + +public record struct quaternion(float x, float y, float z, float w) +{ + public static readonly quaternion identity = new(0.0f, 0.0f, 0.0f, 1.0f); + + public static quaternion LookRotation(float3 forward, float3 up) + { + forward = math.normalize(forward); + up = math.normalize(up); + + var right = math.normalize(math.cross(up, forward)); + up = math.cross(forward, right); + + var m00 = right.x; + var m01 = up.x; + var m02 = forward.x; + var m10 = right.y; + var m11 = up.y; + var m12 = forward.y; + var m20 = right.z; + var m21 = up.z; + var m22 = forward.z; + + var trace = m00 + m11 + m22; + if (trace > 0.0f) + { + var s = math.sqrt(trace + 1.0f) * 2.0f; + return math.normalize(new quaternion( + (m21 - m12) / s, + (m02 - m20) / s, + (m10 - m01) / s, + 0.25f * s)); + } + + if (m00 > m11 && m00 > m22) + { + var s = math.sqrt(1.0f + m00 - m11 - m22) * 2.0f; + return math.normalize(new quaternion( + 0.25f * s, + (m01 + m10) / s, + (m02 + m20) / s, + (m21 - m12) / s)); + } + + if (m11 > m22) + { + var s = math.sqrt(1.0f + m11 - m00 - m22) * 2.0f; + return math.normalize(new quaternion( + (m01 + m10) / s, + 0.25f * s, + (m12 + m21) / s, + (m02 - m20) / s)); + } + + { + var s = math.sqrt(1.0f + m22 - m00 - m11) * 2.0f; + return math.normalize(new quaternion( + (m02 + m20) / s, + (m12 + m21) / s, + 0.25f * s, + (m10 - m01) / s)); + } + } + + public static implicit operator quaternion(float4 value) => new(value.x, value.y, value.z, value.w); + public static implicit operator float4(quaternion value) => new(value.x, value.y, value.z, value.w); +} diff --git a/src/CultMath/quaternion.cs.meta b/src/CultMath/quaternion.cs.meta new file mode 100644 index 00000000..ae6e8a11 --- /dev/null +++ b/src/CultMath/quaternion.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 12f3627d9250dc348be9c1a1056ec7d0 \ No newline at end of file diff --git a/src/CultMath/rect.cs b/src/CultMath/rect.cs new file mode 100644 index 00000000..67b210b9 --- /dev/null +++ b/src/CultMath/rect.cs @@ -0,0 +1,21 @@ +namespace CultMath; + +public readonly record struct rect(float2 min, float2 max) +{ + public rect(float minX, float minY, float maxX, float maxY) + : this(math.float2(math.min(minX, maxX), math.min(minY, maxY)), + math.float2(math.max(minX, maxX), math.max(minY, maxY))) + { + } + + public float2 size => max - min; + public float2 center => (min + max) * 0.5f; + + public bool Contains(float2 point) + { + return point.x >= min.x && + point.x <= max.x && + point.y >= min.y && + point.y <= max.y; + } +} diff --git a/src/CultMath/rect.cs.meta b/src/CultMath/rect.cs.meta new file mode 100644 index 00000000..9f7598ed --- /dev/null +++ b/src/CultMath/rect.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: b00dc5f108967db47ac2f54a47033e33 \ No newline at end of file diff --git a/tests.meta b/tests.meta new file mode 100644 index 00000000..a35356c4 --- /dev/null +++ b/tests.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4ca61dedbfb3c5d46b0acaf23202b5c2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/tests/CultMath.Tests.meta b/tests/CultMath.Tests.meta new file mode 100644 index 00000000..3f1451c6 --- /dev/null +++ b/tests/CultMath.Tests.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bcee65f13f85daa45b0cf3fdaa901779 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/tests/CultMath.Tests/CultMath.Tests.csproj.meta b/tests/CultMath.Tests/CultMath.Tests.csproj.meta new file mode 100644 index 00000000..709184bb --- /dev/null +++ b/tests/CultMath.Tests/CultMath.Tests.csproj.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 636051db121e19146a0baf92b790415c +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/tests/CultMath.Tests/HlslMirrorTests.cs b/tests/CultMath.Tests/HlslMirrorTests.cs index 91a95f4d..ed9119b7 100644 --- a/tests/CultMath.Tests/HlslMirrorTests.cs +++ b/tests/CultMath.Tests/HlslMirrorTests.cs @@ -4,6 +4,14 @@ namespace CultMath.Tests; public sealed class HlslMirrorTests { + [Fact] + public void HlslMirrorPublishesSphericalErosionKernel() + { + var source = File.ReadAllText(FindHlslMirror()); + Assert.Contains("cultmath_spherical_erosion", source); + Assert.Contains("CultMathSphericalErosionParameters", source); + } + [Fact] public void HlslMirrorPublishesCultMathPrimitives() { @@ -23,6 +31,7 @@ public sealed class HlslMirrorTests "cultmath_distance", "cultmath_normalize", "cultmath_reflect", + "cultmath_rotate", "cultmath_csum", "cultmath_decay", "cultmath_damp", diff --git a/tests/CultMath.Tests/HlslMirrorTests.cs.meta b/tests/CultMath.Tests/HlslMirrorTests.cs.meta new file mode 100644 index 00000000..1fcf44b3 --- /dev/null +++ b/tests/CultMath.Tests/HlslMirrorTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 3d7eb9df849ea0148a71419bbfe2352c \ No newline at end of file diff --git a/tests/CultMath.Tests/MathTests.cs b/tests/CultMath.Tests/MathTests.cs index 44dd1290..bb816d47 100644 --- a/tests/CultMath.Tests/MathTests.cs +++ b/tests/CultMath.Tests/MathTests.cs @@ -23,6 +23,7 @@ public sealed class MathTests [Fact] public void VectorConstructorsAcceptLowerDimensionVectors() { + Assert.Equal(new int2(1, 2), math.int2(1, 2)); Assert.Equal(new float2(1.0f, 2.0f), math.float2(1.0f, 2.0f)); Assert.Equal(new float3(1.0f, 1.0f, 1.0f), math.float3(1.0f)); Assert.Equal(new float4(1.0f, 2.0f, 3.0f, 4.0f), math.float4(new float3(1.0f, 2.0f, 3.0f), 4.0f)); @@ -31,6 +32,112 @@ public sealed class MathTests Assert.Equal(new float4(1.0f, 2.0f, 3.0f, 4.0f), new float4(new float3(1.0f, 2.0f, 3.0f), 4.0f)); } + [Fact] + public void RectNormalizesBoundsAndContainsPoints() + { + var viewport = math.rect(10.0f, 20.0f, -5.0f, -2.0f); + + Assert.Equal(new float2(-5.0f, -2.0f), viewport.min); + Assert.Equal(new float2(10.0f, 20.0f), viewport.max); + Assert.Equal(new float2(15.0f, 22.0f), viewport.size); + Assert.Equal(new float2(2.5f, 9.0f), viewport.center); + Assert.True(viewport.Contains(new float2(0.0f, 0.0f))); + Assert.False(viewport.Contains(new float2(11.0f, 0.0f))); + } + + [Fact] + public void VectorsExposeCommonReadOnlySwizzles() + { + Assert.Equal(new float3(2.0f, 3.0f, 1.0f), new float3(1.0f, 2.0f, 3.0f).yzx); + Assert.Equal(new float3(3.0f, 2.0f, 1.0f), new float3(1.0f, 2.0f, 3.0f).zyx); + Assert.Equal(new float2(3.0f, 2.0f), new float3(1.0f, 2.0f, 3.0f).zy); + Assert.Equal(new float3(1.0f, 2.0f, 4.0f), new float4(1.0f, 2.0f, 3.0f, 4.0f).xyw); + Assert.Equal(new float3(2.0f, 3.0f, 1.0f), new float4(1.0f, 2.0f, 3.0f, 4.0f).yzx); + Assert.Equal(new float4(1.0f, 2.0f, 3.0f, 4.0f), new float4(1.0f, new float3(2.0f, 3.0f, 4.0f))); + Assert.Equal(new float4(1.0f, 2.0f, 3.0f, 4.0f), math.float4(1.0f, new float3(2.0f, 3.0f, 4.0f))); + } + + [Fact] + public void VectorsSupportUnityStyleFieldAndSwizzleMutation() + { + var position = new float3(1.0f, 2.0f, 3.0f); + position.y = 5.0f; + position.xz = new float2(8.0f, 13.0f); + + Assert.Equal(new float3(8.0f, 5.0f, 13.0f), position); + + var bounds = new float4(1.0f, 2.0f, 3.0f, 4.0f); + bounds.xy = new float2(-1.0f, -2.0f); + + Assert.Equal(new float4(-1.0f, -2.0f, 3.0f, 4.0f), bounds); + } + + [Fact] + public void DoubleVectorsSupportDampedMath() + { + var value = new double3(1.0, 2.0, 3.0); + value.xy = new double2(5.0, 8.0); + + Assert.Equal(new double3(5.0, 8.0, 3.0), value); + Assert.Equal(new double2(Math.Exp(-2.0), Math.Exp(-4.0)), math.exp(new double2(-2.0, -4.0))); + Assert.Equal(new double3(2.0, 4.0, 6.0), math.lerp(new double3(0.0, 0.0, 0.0), new double3(4.0, 8.0, 12.0), new double3(0.5, 0.5, 0.5))); + } + + [Fact] + public void Int2SupportsGridArithmeticAndFloatPromotion() + { + var cell = new int2(2, 3); + + Assert.Equal(new int2(3, 5), cell + new int2(1, 2)); + Assert.Equal(new int2(4, 6), cell * new int2(2, 2)); + Assert.Equal(3, cell[1]); + + float2 promoted = cell; + Assert.Equal(new float2(2.0f, 3.0f), promoted); + } + + [Fact] + public void Bool2SupportsHullGridStyleStorage() + { + bool2 conductivity = true; + + conductivity.y = false; + + Assert.True(conductivity.x); + Assert.False(conductivity[1]); + Assert.Equal(new bool2(false, true), math.bool2(false, true)); + } + + [Fact] + public void QuaternionLookRotationProducesUnitOrientation() + { + var rotation = quaternion.LookRotation(new float3(0.0f, 0.0f, 1.0f), new float3(0.0f, 1.0f, 0.0f)); + + Assert.Equal(quaternion.identity, rotation); + Assert.Equal(1.0f, math.length((float4)quaternion.LookRotation(new float3(1.0f, 0.0f, 0.0f), new float3(0.0f, 1.0f, 0.0f))), precision: 5); + } + + [Fact] + public void RandomIsDeterministicAndUnityShaped() + { + var a = new Random(1234); + var b = new Random(1234); + + Assert.Equal(a.NextUInt(), b.NextUInt()); + Assert.Equal(a.NextFloat(), b.NextFloat()); + + var bounded = a.NextFloat(-2.0f, 4.0f); + Assert.True(bounded >= -2.0f && bounded < 4.0f); + + var direction = a.NextFloat2Direction(); + Assert.Equal(1.0f, math.length(direction), precision: 5); + + var point = a.NextFloat3(new float3(-1.0f, -2.0f, -3.0f), new float3(1.0f, 2.0f, 3.0f)); + Assert.True(point.x >= -1.0f && point.x < 1.0f); + Assert.True(point.y >= -2.0f && point.y < 2.0f); + Assert.True(point.z >= -3.0f && point.z < 3.0f); + } + [Fact] public void NormalizeProducesUnitLength() { @@ -55,12 +162,39 @@ public sealed class MathTests Assert.Equal(-1.0f, math.cos(math.PI), precision: 5); Assert.Equal(1.0f, math.tan(math.PI * 0.25f), precision: 5); Assert.Equal(math.HALF_PI, math.atan2(1.0f, 0.0f), precision: 5); + Assert.Equal(2, math.min(2, 5)); + Assert.Equal(5, math.max(2, 5)); + Assert.True(math.isinf(float.PositiveInfinity)); + } + + [Fact] + public void SignIsComponentWiseForSimulationVectors() + { + Assert.Equal(-1.0f, math.sign(-12.0f)); + Assert.Equal(0.0f, math.sign(0.0f)); + Assert.Equal(1.0f, math.sign(12.0f)); + Assert.Equal(new float3(-1.0f, 0.0f, 1.0f), math.sign(new float3(-2.0f, 0.0f, 4.0f))); + } + + [Fact] + public void RotateTurnsFloat2CounterClockwiseInRadians() + { + var rotated = math.rotate(new float2(1.0f, 0.0f), math.HALF_PI); + + Assert.Equal(0.0f, rotated.x, precision: 5); + Assert.Equal(1.0f, rotated.y, precision: 5); + + var rotatedDegrees = math.rotate_degrees(new float2(0.0f, 1.0f), 90.0f); + Assert.Equal(-1.0f, rotatedDegrees.x, precision: 5); + Assert.Equal(0.0f, rotatedDegrees.y, precision: 5); } [Fact] public void AetheriaPrimitivesRemainSmallAndDeterministic() { Assert.Equal(6.0f, math.csum(new float3(1.0f, 2.0f, 3.0f))); + Assert.Equal(0.25f, math.unlerp(10.0f, 30.0f, 15.0f)); + Assert.Equal(new float2(0.25f, 0.75f), math.unlerp(new float2(10.0f, 10.0f), new float2(30.0f, 30.0f), new float2(15.0f, 25.0f))); Assert.Equal(MathF.Exp(-2.0f), math.decay(1.0f, 2.0f, 1.0f), precision: 5); Assert.Equal(1.0f - MathF.Exp(-2.0f), math.damp(0.0f, 1.0f, 2.0f, 1.0f), precision: 5); diff --git a/tests/CultMath.Tests/MathTests.cs.meta b/tests/CultMath.Tests/MathTests.cs.meta new file mode 100644 index 00000000..277df5a3 --- /dev/null +++ b/tests/CultMath.Tests/MathTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c7a709e5345da214aa650e8c796fcaff \ No newline at end of file diff --git a/tests/CultMath.Tests/SphericalErosionTests.cs b/tests/CultMath.Tests/SphericalErosionTests.cs new file mode 100644 index 00000000..8ae04859 --- /dev/null +++ b/tests/CultMath.Tests/SphericalErosionTests.cs @@ -0,0 +1,27 @@ +namespace CultMath.Tests; + +public sealed class SphericalErosionTests +{ + [Fact] + public void SampleIsDeterministicAndScaleInvariant() + { + var parameters = SphericalErosionParameters.Default with { Seed = 42.0f }; + var a = SphericalErosion.Sample(new float3(0.31f, -0.74f, 0.59f), 0.2f, new float3(0.4f, -0.1f, 0.2f), parameters); + var b = SphericalErosion.Sample(new float3(3.1f, -7.4f, 5.9f), 0.2f, new float3(0.4f, -0.1f, 0.2f), parameters); + + Assert.Equal(a, b); + Assert.InRange(a.HeightOffset, -0.08f, 0.08f); + Assert.InRange(a.Ridge, 0.0f, 1.0f); + Assert.InRange(a.Gully, 0.0f, 1.0f); + } + + [Fact] + public void NearbySamplesRemainContinuousAcrossAChartBoundary() + { + var parameters = SphericalErosionParameters.Default; + var left = SphericalErosion.Sample(math.normalize(new float3(1.0f, 0.99999f, 0.2f)), 0.1f, new float3(0.2f, -0.1f, 0.05f), parameters); + var right = SphericalErosion.Sample(math.normalize(new float3(0.99999f, 1.0f, 0.2f)), 0.1f, new float3(0.2f, -0.1f, 0.05f), parameters); + + Assert.InRange(math.abs(left.HeightOffset - right.HeightOffset), 0.0f, 0.0002f); + } +} diff --git a/tools.meta b/tools.meta new file mode 100644 index 00000000..3594fa6a --- /dev/null +++ b/tools.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 697162910ffd9614ba9655d31af9afa4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/tools/compile-hlsl-spirv.ps1.meta b/tools/compile-hlsl-spirv.ps1.meta new file mode 100644 index 00000000..31e7948a --- /dev/null +++ b/tools/compile-hlsl-spirv.ps1.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b47e7016a99a5d148bc44c399c13c4d3 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/tools/compile-spirv-metal.ps1.meta b/tools/compile-spirv-metal.ps1.meta new file mode 100644 index 00000000..2e7e74c2 --- /dev/null +++ b/tools/compile-spirv-metal.ps1.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6150c8f461e471b4c8641fd32d1984ef +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/tools/get-dxc.ps1.meta b/tools/get-dxc.ps1.meta new file mode 100644 index 00000000..c9ab0d82 --- /dev/null +++ b/tools/get-dxc.ps1.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 86d0b9a1006042745b7fff523831049c +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/tools/get-spirv-cross.ps1.meta b/tools/get-spirv-cross.ps1.meta new file mode 100644 index 00000000..12ccdd8e --- /dev/null +++ b/tools/get-spirv-cross.ps1.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: dcf41da07502f4b439f8fc5ad25d16c9 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From 430cbc9695aba7a03f1f87c82ed84d1eba61a9e5 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 12 Jul 2026 19:49:33 +0100 Subject: [PATCH 010/283] Add faithful advanced erosion filter core --- README.md | 5 + THIRD-PARTY-NOTICES.md | 21 +++ shaders/AdvancedErosionFilter.hlsl | 112 +++++++++++++++ shaders/CultMath.hlsl | 2 + src/CultMath/AdvancedErosionFilter.cs | 129 ++++++++++++++++++ .../AdvancedErosionFilterTests.cs | 44 ++++++ tests/CultMath.Tests/HlslMirrorTests.cs | 13 +- tests/CultMath.Tests/SphericalErosionTests.cs | 2 + 8 files changed, 327 insertions(+), 1 deletion(-) create mode 100644 THIRD-PARTY-NOTICES.md create mode 100644 shaders/AdvancedErosionFilter.hlsl create mode 100644 src/CultMath/AdvancedErosionFilter.cs create mode 100644 tests/CultMath.Tests/AdvancedErosionFilterTests.cs diff --git a/README.md b/README.md index 1050e4ec..1228736a 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,11 @@ local `AetheriaMath` surface. The value-noise family follows public shader literature from Inigo Quilez's noise and mini-spline articles, expressed in CultMath names with tests instead of copied project-local helper drift. +The advanced erosion filter is an MPL-2.0 adaptation of Rune Skovbo Johansen's +published filter. Its faithful planar core is isolated in +`AdvancedErosionFilter.cs` and `AdvancedErosionFilter.hlsl`; spherical mapping +is a separate CultMath concern. See `THIRD-PARTY-NOTICES.md`. + ## Build ```powershell diff --git a/THIRD-PARTY-NOTICES.md b/THIRD-PARTY-NOTICES.md new file mode 100644 index 00000000..c8976207 --- /dev/null +++ b/THIRD-PARTY-NOTICES.md @@ -0,0 +1,21 @@ +# Third-Party Notices + +## Advanced Terrain Erosion Filter + +`src/CultMath/AdvancedErosionFilter.cs` and +`shaders/AdvancedErosionFilter.hlsl` adapt the mathematical procedure from +Rune Skovbo Johansen's **Advanced Terrain Erosion Filter**: + +- Copyright 2025 Rune Skovbo Johansen. +- Upstream: +- Explanation: +- License: Mozilla Public License 2.0, + + +The CultMath files retain the MPL notice and separate the faithful planar +filter from CultMath's spherical adaptation. Modifications include C#/HLSL +type lowering, explicit bounded octave counts, finite zero-rounding behavior, +and CultMath naming. + +The technique builds on earlier work credited by the upstream author to Fewes +and Clay John. The hash form follows the public shader math of Inigo Quilez. diff --git a/shaders/AdvancedErosionFilter.hlsl b/shaders/AdvancedErosionFilter.hlsl new file mode 100644 index 00000000..6c35dd47 --- /dev/null +++ b/shaders/AdvancedErosionFilter.hlsl @@ -0,0 +1,112 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. +// Mathematical procedure adapted from Rune Skovbo Johansen's Advanced Terrain +// Erosion Filter (2025): https://www.shadertoy.com/view/wXcfWn + +#ifndef CULTMATH_ADVANCED_EROSION_FILTER_HLSL +#define CULTMATH_ADVANCED_EROSION_FILTER_HLSL + +struct CultMathAdvancedErosionParameters +{ + float scale; float strength; float gully_weight; float detail; + float4 rounding; float4 onset; float2 assumed_slope; + float cell_scale; float normalization; int octaves; float lacunarity; float gain; +}; + +struct CultMathAdvancedErosionResult +{ + float3 delta; float magnitude; float ridge_map; float fade_target; +}; + +float2 cultmath_erosion_hash2(float2 input) +{ + float2 k = float2(0.3183099, 0.3678794); + float2 x = input * k + k.yx; + return -1.0 + 2.0 * frac(16.0 * k * frac(x.x * x.y * (x.x + x.y))); +} + +float4 cultmath_phacelle_noise(float2 position, float2 normal_direction, float frequency, float offset_cycles, float normalization) +{ + float2 side_direction = float2(-normal_direction.y, normal_direction.x) * frequency * 6.28318530718; + float offset = offset_cycles * 6.28318530718; + float2 cell = floor(position); + float2 local = frac(position); + float2 phase = 0.0; + float weight_sum = 0.0; + [unroll] for (int x = -1; x <= 2; x++) + [unroll] for (int y = -1; y <= 2; y++) + { + float2 grid_offset = float2(x, y); + float2 grid_point = cell + grid_offset; + float2 random_offset = cultmath_erosion_hash2(grid_point) * 0.5; + float2 delta = local - grid_offset - random_offset; + float weight = max(0.0, exp(-dot(delta, delta) * 2.0) - 0.01111); + weight_sum += weight; + float wave = dot(delta, side_direction) + offset; + phase += float2(cos(wave), sin(wave)) * weight; + } + float2 interpolated = phase / max(weight_sum, 1.0e-20); + float magnitude = max(1.0 - saturate(normalization), length(interpolated)); + return float4(interpolated / max(magnitude, 1.0e-20), side_direction); +} + +float cultmath_erosion_pow_inverse(float value, float power) { return 1.0 - pow(1.0 - saturate(value), power); } +float cultmath_erosion_ease_out(float value) { float inverse = 1.0 - saturate(value); return 1.0 - inverse * inverse; } +float cultmath_erosion_smooth_start(float value, float smoothing) +{ + return smoothing <= 1.0e-10 || value >= smoothing ? value - 0.5 * smoothing : 0.5 * value * value / smoothing; +} +float2 cultmath_erosion_safe_normalize(float2 value) +{ + float value_length = length(value); + return abs(value_length) > 1.0e-10 ? value / value_length : value; +} + +CultMathAdvancedErosionResult cultmath_advanced_erosion_filter(float2 position, float3 base_height_and_slope, float fade_target, CultMathAdvancedErosionParameters p) +{ + float strength = p.strength * p.scale; + fade_target = clamp(fade_target, -1.0, 1.0); + float3 input_value = base_height_and_slope; + float3 height_and_slope = input_value; + float frequency = 1.0 / max(p.scale * p.cell_scale, 1.0e-10); + float2 slope = height_and_slope.yz; + float slope_length = max(length(slope), 1.0e-10); + float magnitude = 0.0; + float rounding_multiplier = 1.0; + float input_rounding = lerp(p.rounding.y, p.rounding.x, saturate(fade_target + 0.5)) * p.rounding.z; + float combined_mask = cultmath_erosion_ease_out(cultmath_erosion_smooth_start(slope_length * p.onset.x, input_rounding * p.onset.x)); + float ridge_mask = cultmath_erosion_ease_out(slope_length * p.onset.z); + float ridge_fade = fade_target; + float2 gully_slope = lerp(slope, slope / slope_length * p.assumed_slope.x, p.assumed_slope.y); + + [loop] for (int octave = 0; octave < min(max(p.octaves, 0), 8); octave++) + { + float4 phacelle = cultmath_phacelle_noise(position * frequency, cultmath_erosion_safe_normalize(gully_slope), p.cell_scale, 0.25, p.normalization); + float2 derivative_direction = phacelle.zw * -frequency; + float sloping = abs(phacelle.y); + gully_slope += sign(phacelle.y) * derivative_direction * strength * p.gully_weight; + float3 gullies = float3(phacelle.x, phacelle.y * derivative_direction.x, phacelle.y * derivative_direction.y); + float3 faded = lerp(float3(fade_target, 0.0, 0.0), gullies * p.gully_weight, combined_mask); + height_and_slope += faded * strength; + magnitude += strength; + fade_target = faded.x; + float octave_rounding = lerp(p.rounding.y, p.rounding.x, saturate(phacelle.x + 0.5)) * rounding_multiplier; + float new_mask = cultmath_erosion_ease_out(cultmath_erosion_smooth_start(sloping * p.onset.y, octave_rounding * p.onset.y)); + combined_mask = cultmath_erosion_pow_inverse(combined_mask, p.detail) * new_mask; + ridge_fade = lerp(ridge_fade, gullies.x, ridge_mask); + ridge_mask *= cultmath_erosion_ease_out(sloping * p.onset.w); + strength *= p.gain; + frequency *= p.lacunarity; + rounding_multiplier *= p.rounding.w; + } + + CultMathAdvancedErosionResult result; + result.delta = height_and_slope - input_value; + result.magnitude = magnitude; + result.ridge_map = ridge_fade * (1.0 - ridge_mask); + result.fade_target = fade_target; + return result; +} + +#endif diff --git a/shaders/CultMath.hlsl b/shaders/CultMath.hlsl index 07b2b8a9..c55a1790 100644 --- a/shaders/CultMath.hlsl +++ b/shaders/CultMath.hlsl @@ -263,6 +263,8 @@ float cultmath_value_noise_texture_bicubic(Texture2D noise_texture, Sampl return cultmath_catmullrom(row0, row1, row2, row3, local.y); } +#include "AdvancedErosionFilter.hlsl" + struct CultMathSphericalErosionParameters { float frequency; float amplitude; float lacunarity; float gain; diff --git a/src/CultMath/AdvancedErosionFilter.cs b/src/CultMath/AdvancedErosionFilter.cs new file mode 100644 index 00000000..f004c327 --- /dev/null +++ b/src/CultMath/AdvancedErosionFilter.cs @@ -0,0 +1,129 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. +// +// Mathematical procedure adapted from Rune Skovbo Johansen's Advanced Terrain +// Erosion Filter (2025): https://www.shadertoy.com/view/wXcfWn + +namespace CultMath; + +public readonly record struct AdvancedErosionParameters( + float Scale, + float Strength, + float GullyWeight, + float Detail, + float4 Rounding, + float4 Onset, + float2 AssumedSlope, + float CellScale, + float Normalization, + int Octaves, + float Lacunarity, + float Gain) +{ + public static AdvancedErosionParameters Default => new( + 0.15f, 0.22f, 0.5f, 1.5f, + new float4(0.1f, 0.0f, 0.1f, 2.0f), + new float4(1.25f, 1.25f, 2.8f, 1.5f), + new float2(0.7f, 1.0f), + 0.7f, 0.5f, 5, 2.0f, 0.5f); +} + +public readonly record struct AdvancedErosionResult(float3 Delta, float Magnitude, float RidgeMap, float FadeTarget); + +public static class AdvancedErosionFilter +{ + public static AdvancedErosionResult Sample(float2 position, float3 baseHeightAndSlope, float fadeTarget, AdvancedErosionParameters p) + { + var strength = p.Strength * p.Scale; + fadeTarget = math.clamp(fadeTarget, -1.0f, 1.0f); + var input = baseHeightAndSlope; + var heightAndSlope = input; + var frequency = 1.0f / math.max(p.Scale * p.CellScale, 1.0e-10f); + var slope = new float2(heightAndSlope.y, heightAndSlope.z); + var slopeLength = math.max(math.length(slope), 1.0e-10f); + var magnitude = 0.0f; + var roundingMultiplier = 1.0f; + + var inputRounding = math.lerp(p.Rounding.y, p.Rounding.x, math.saturate(fadeTarget + 0.5f)) * p.Rounding.z; + var combinedMask = EaseOut(SmoothStart(slopeLength * p.Onset.x, inputRounding * p.Onset.x)); + var ridgeMask = EaseOut(slopeLength * p.Onset.z); + var ridgeFade = fadeTarget; + var gullySlope = math.lerp(slope, slope / slopeLength * p.AssumedSlope.x, p.AssumedSlope.y); + + var octaves = math.min(math.max(p.Octaves, 0), 8); + for (var octave = 0; octave < octaves; octave++) + { + var phacelle = Phacelle(position * frequency, SafeNormalize(gullySlope), p.CellScale, 0.25f, p.Normalization); + var derivativeDirection = new float2(phacelle.z, phacelle.w) * -frequency; + var sloping = math.abs(phacelle.y); + gullySlope += math.sign(phacelle.y) * derivativeDirection * strength * p.GullyWeight; + + var gullies = new float3(phacelle.x, phacelle.y * derivativeDirection.x, phacelle.y * derivativeDirection.y); + var faded = math.lerp(new float3(fadeTarget, 0.0f, 0.0f), gullies * p.GullyWeight, combinedMask); + heightAndSlope += faded * strength; + magnitude += strength; + fadeTarget = faded.x; + + var octaveRounding = math.lerp(p.Rounding.y, p.Rounding.x, math.saturate(phacelle.x + 0.5f)) * roundingMultiplier; + var newMask = EaseOut(SmoothStart(sloping * p.Onset.y, octaveRounding * p.Onset.y)); + combinedMask = PowInverse(combinedMask, p.Detail) * newMask; + + ridgeFade = math.lerp(ridgeFade, gullies.x, ridgeMask); + ridgeMask *= EaseOut(sloping * p.Onset.w); + strength *= p.Gain; + frequency *= p.Lacunarity; + roundingMultiplier *= p.Rounding.w; + } + + return new AdvancedErosionResult(heightAndSlope - input, magnitude, ridgeFade * (1.0f - ridgeMask), fadeTarget); + } + + public static float4 Phacelle(float2 position, float2 normalDirection, float frequency, float offsetCycles, float normalization) + { + var sideDirection = new float2(-normalDirection.y, normalDirection.x) * frequency * math.TAU; + var offset = offsetCycles * math.TAU; + var cell = math.floor(position); + var local = math.frac(position); + var phase = float2.zero; + var weightSum = 0.0f; + + for (var x = -1; x <= 2; x++) + for (var y = -1; y <= 2; y++) + { + var gridOffset = new float2(x, y); + var gridPoint = cell + gridOffset; + var randomOffset = Hash2(gridPoint) * 0.5f; + var delta = local - gridOffset - randomOffset; + var weight = math.max(0.0f, math.exp(-math.dot(delta, delta) * 2.0f) - 0.01111f); + weightSum += weight; + var wave = math.dot(delta, sideDirection) + offset; + phase += new float2(math.cos(wave), math.sin(wave)) * weight; + } + + var interpolated = phase / math.max(weightSum, 1.0e-20f); + var magnitude = math.max(1.0f - math.saturate(normalization), math.length(interpolated)); + var normalized = interpolated / math.max(magnitude, 1.0e-20f); + return new float4(normalized, sideDirection.x, sideDirection.y); + } + + private static float2 Hash2(float2 input) + { + var k = new float2(0.3183099f, 0.3678794f); + var x = input * k + new float2(k.y, k.x); + var scalar = math.frac(x.x * x.y * (x.x + x.y)); + return -float2.one + 2.0f * math.frac(16.0f * k * scalar); + } + + private static float2 SafeNormalize(float2 value) + { + var length = math.length(value); + return math.abs(length) > 1.0e-10f ? value / length : value; + } + + private static float PowInverse(float value, float power) => 1.0f - math.pow(1.0f - math.saturate(value), power); + private static float EaseOut(float value) { var inverse = 1.0f - math.saturate(value); return 1.0f - inverse * inverse; } + private static float SmoothStart(float value, float smoothing) => smoothing <= 1.0e-10f || value >= smoothing + ? value - 0.5f * smoothing + : 0.5f * value * value / smoothing; +} diff --git a/tests/CultMath.Tests/AdvancedErosionFilterTests.cs b/tests/CultMath.Tests/AdvancedErosionFilterTests.cs new file mode 100644 index 00000000..cccebd64 --- /dev/null +++ b/tests/CultMath.Tests/AdvancedErosionFilterTests.cs @@ -0,0 +1,44 @@ +using Xunit; + +namespace CultMath.Tests; + +public sealed class AdvancedErosionFilterTests +{ + [Fact] + public void DefaultReferenceFixtureIsStable() + { + var result = AdvancedErosionFilter.Sample( + new float2(0.42f, 0.31f), + new float3(0.5f, 0.1f, -0.2f), + 0.0f, + AdvancedErosionParameters.Default); + + Assert.Equal(0.0639375f, result.Magnitude, precision: 7); + Assert.True(float.IsFinite(result.Delta.x)); + Assert.True(float.IsFinite(result.Delta.y)); + Assert.True(float.IsFinite(result.Delta.z)); + Assert.InRange(result.RidgeMap, -1.0f, 1.0f); + } + + [Fact] + public void FlatInputAndZeroRoundingRemainFinite() + { + var parameters = AdvancedErosionParameters.Default with { Rounding = float4.zero }; + var result = AdvancedErosionFilter.Sample(new float2(0.25f, 0.75f), float3.zero, 0.0f, parameters); + + Assert.True(float.IsFinite(result.Delta.x)); + Assert.True(float.IsFinite(result.RidgeMap)); + Assert.True(float.IsFinite(result.FadeTarget)); + } + + [Fact] + public void PhacellePartialNormalizationIsFiniteAtEndpoints() + { + foreach (var normalization in new[] { 0.0f, 0.5f, 1.0f }) + { + var sample = AdvancedErosionFilter.Phacelle(new float2(1.7f, -3.2f), new float2(0.6f, -0.8f), 0.7f, 0.25f, normalization); + Assert.True(float.IsFinite(sample.x)); + Assert.True(float.IsFinite(sample.y)); + } + } +} diff --git a/tests/CultMath.Tests/HlslMirrorTests.cs b/tests/CultMath.Tests/HlslMirrorTests.cs index ed9119b7..0e904a32 100644 --- a/tests/CultMath.Tests/HlslMirrorTests.cs +++ b/tests/CultMath.Tests/HlslMirrorTests.cs @@ -7,11 +7,22 @@ public sealed class HlslMirrorTests [Fact] public void HlslMirrorPublishesSphericalErosionKernel() { - var source = File.ReadAllText(FindHlslMirror()); + var source = File.ReadAllText(Path.Combine(GetRepositoryRoot(), "shaders", "CultMath.hlsl")); Assert.Contains("cultmath_spherical_erosion", source); Assert.Contains("CultMathSphericalErosionParameters", source); } + [Fact] + public void HlslMirrorPublishesFaithfulAdvancedErosionKernel() + { + var mirror = Path.Combine(GetRepositoryRoot(), "shaders", "CultMath.hlsl"); + var source = File.ReadAllText(mirror); + Assert.Contains("AdvancedErosionFilter.hlsl", source); + var advanced = File.ReadAllText(Path.Combine(Path.GetDirectoryName(mirror)!, "AdvancedErosionFilter.hlsl")); + Assert.Contains("cultmath_phacelle_noise", advanced); + Assert.Contains("cultmath_advanced_erosion_filter", advanced); + } + [Fact] public void HlslMirrorPublishesCultMathPrimitives() { diff --git a/tests/CultMath.Tests/SphericalErosionTests.cs b/tests/CultMath.Tests/SphericalErosionTests.cs index 8ae04859..53d37bce 100644 --- a/tests/CultMath.Tests/SphericalErosionTests.cs +++ b/tests/CultMath.Tests/SphericalErosionTests.cs @@ -1,3 +1,5 @@ +using Xunit; + namespace CultMath.Tests; public sealed class SphericalErosionTests From 33c017b284c11a0b54e54dc8aefef2a920a90a55 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 12 Jul 2026 19:57:24 +0100 Subject: [PATCH 011/283] Make erosion cell hashing cross-device deterministic --- THIRD-PARTY-NOTICES.md | 5 ++++- shaders/AdvancedErosionFilter.hlsl | 11 ++++++++--- src/CultMath/AdvancedErosionFilter.cs | 14 ++++++++++---- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/THIRD-PARTY-NOTICES.md b/THIRD-PARTY-NOTICES.md index c8976207..8339c5fe 100644 --- a/THIRD-PARTY-NOTICES.md +++ b/THIRD-PARTY-NOTICES.md @@ -15,7 +15,10 @@ Rune Skovbo Johansen's **Advanced Terrain Erosion Filter**: The CultMath files retain the MPL notice and separate the faithful planar filter from CultMath's spherical adaptation. Modifications include C#/HLSL type lowering, explicit bounded octave counts, finite zero-rounding behavior, -and CultMath naming. +and CultMath naming. CultMath replaces the reference floating hash with a +shared integer avalanche hash so C# and GPU evaluation select identical cell +pivots across devices; this changes the stochastic pattern, not the filter +mechanics. The technique builds on earlier work credited by the upstream author to Fewes and Clay John. The hash form follows the public shader math of Inigo Quilez. diff --git a/shaders/AdvancedErosionFilter.hlsl b/shaders/AdvancedErosionFilter.hlsl index 6c35dd47..38c3ef19 100644 --- a/shaders/AdvancedErosionFilter.hlsl +++ b/shaders/AdvancedErosionFilter.hlsl @@ -19,11 +19,16 @@ struct CultMathAdvancedErosionResult float3 delta; float magnitude; float ridge_map; float fade_target; }; +float cultmath_erosion_hash_unit(int2 cell, uint salt) +{ + uint value = (uint)cell.x * 0x8da6b343u ^ (uint)cell.y * 0xd8163841u ^ salt; + value ^= value >> 16; value *= 0x7feb352du; value ^= value >> 15; value *= 0x846ca68bu; value ^= value >> 16; + return (value & 0x00ffffffu) * (1.0 / 16777216.0); +} float2 cultmath_erosion_hash2(float2 input) { - float2 k = float2(0.3183099, 0.3678794); - float2 x = input * k + k.yx; - return -1.0 + 2.0 * frac(16.0 * k * frac(x.x * x.y * (x.x + x.y))); + int2 cell = (int2)input; + return float2(cultmath_erosion_hash_unit(cell, 0x68bc21ebu), cultmath_erosion_hash_unit(cell, 0x02e5be93u)) * 2.0 - 1.0; } float4 cultmath_phacelle_noise(float2 position, float2 normal_direction, float frequency, float offset_cycles, float normalization) diff --git a/src/CultMath/AdvancedErosionFilter.cs b/src/CultMath/AdvancedErosionFilter.cs index f004c327..6780223f 100644 --- a/src/CultMath/AdvancedErosionFilter.cs +++ b/src/CultMath/AdvancedErosionFilter.cs @@ -109,10 +109,16 @@ public static class AdvancedErosionFilter private static float2 Hash2(float2 input) { - var k = new float2(0.3183099f, 0.3678794f); - var x = input * k + new float2(k.y, k.x); - var scalar = math.frac(x.x * x.y * (x.x + x.y)); - return -float2.one + 2.0f * math.frac(16.0f * k * scalar); + var x = (int)input.x; + var y = (int)input.y; + return new float2(HashUnit(x, y, 0x68bc21ebu), HashUnit(x, y, 0x02e5be93u)) * 2.0f - float2.one; + } + + private static float HashUnit(int x, int y, uint salt) + { + var value = unchecked((uint)x * 0x8da6b343u ^ (uint)y * 0xd8163841u ^ salt); + value ^= value >> 16; value *= 0x7feb352du; value ^= value >> 15; value *= 0x846ca68bu; value ^= value >> 16; + return (value & 0x00ffffffu) * (1.0f / 16777216.0f); } private static float2 SafeNormalize(float2 value) From ddeac557cb2dbc9b47e14010ce5e4b9ce1252c98 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 12 Jul 2026 20:02:45 +0100 Subject: [PATCH 012/283] Add physical erosion frequency bands --- shaders/AdvancedErosionFilter.hlsl | 42 ++++++++++++-- src/CultMath/AdvancedErosionFilter.cs | 14 +++-- src/CultMath/ErosionFrequencyBands.cs | 57 +++++++++++++++++++ .../ErosionFrequencyBandsTests.cs | 34 +++++++++++ 4 files changed, 136 insertions(+), 11 deletions(-) create mode 100644 src/CultMath/ErosionFrequencyBands.cs create mode 100644 tests/CultMath.Tests/ErosionFrequencyBandsTests.cs diff --git a/shaders/AdvancedErosionFilter.hlsl b/shaders/AdvancedErosionFilter.hlsl index 38c3ef19..a0a350e5 100644 --- a/shaders/AdvancedErosionFilter.hlsl +++ b/shaders/AdvancedErosionFilter.hlsl @@ -19,6 +19,28 @@ struct CultMathAdvancedErosionResult float3 delta; float magnitude; float ridge_map; float fade_target; }; +struct CultMathErosionBandSelection +{ + int active_octaves; float final_octave_weight; float finest_included_wavelength; float unresolved_height_bound; +}; + +CultMathErosionBandSelection cultmath_select_erosion_bands(float base_wavelength, float sample_spacing, int maximum_octaves, float lacunarity, float base_amplitude, float gain, float transition_ratio) +{ + base_wavelength=max(base_wavelength,1.0e-6); sample_spacing=max(sample_spacing,0.0); lacunarity=max(lacunarity,1.01); transition_ratio=max(transition_ratio,1.01); maximum_octaves=min(max(maximum_octaves,0),16); + float nyquist=sample_spacing*2.0, wavelength=base_wavelength, final_weight=0.0, finest=0.0; int active=0; + [loop] for(int octave=0; octave=active) omitted+=amplitude; else if(index==active-1) omitted+=amplitude*(1.0-final_weight); amplitude*=abs(gain); + } + CultMathErosionBandSelection result; result.active_octaves=active; result.final_octave_weight=active>0?final_weight:0.0; result.finest_included_wavelength=finest; result.unresolved_height_bound=omitted; return result; +} + float cultmath_erosion_hash_unit(int2 cell, uint salt) { uint value = (uint)cell.x * 0x8da6b343u ^ (uint)cell.y * 0xd8163841u ^ salt; @@ -68,7 +90,7 @@ float2 cultmath_erosion_safe_normalize(float2 value) return abs(value_length) > 1.0e-10 ? value / value_length : value; } -CultMathAdvancedErosionResult cultmath_advanced_erosion_filter(float2 position, float3 base_height_and_slope, float fade_target, CultMathAdvancedErosionParameters p) +CultMathAdvancedErosionResult cultmath_advanced_erosion_filter_banded(float2 position, float3 base_height_and_slope, float fade_target, CultMathAdvancedErosionParameters p, CultMathErosionBandSelection band) { float strength = p.strength * p.scale; fade_target = clamp(fade_target, -1.0, 1.0); @@ -85,7 +107,8 @@ CultMathAdvancedErosionResult cultmath_advanced_erosion_filter(float2 position, float ridge_fade = fade_target; float2 gully_slope = lerp(slope, slope / slope_length * p.assumed_slope.x, p.assumed_slope.y); - [loop] for (int octave = 0; octave < min(max(p.octaves, 0), 8); octave++) + int octave_count=min(min(max(p.octaves,0),8),max(band.active_octaves,0)); + [loop] for (int octave = 0; octave < octave_count; octave++) { float4 phacelle = cultmath_phacelle_noise(position * frequency, cultmath_erosion_safe_normalize(gully_slope), p.cell_scale, 0.25, p.normalization); float2 derivative_direction = phacelle.zw * -frequency; @@ -93,14 +116,15 @@ CultMathAdvancedErosionResult cultmath_advanced_erosion_filter(float2 position, gully_slope += sign(phacelle.y) * derivative_direction * strength * p.gully_weight; float3 gullies = float3(phacelle.x, phacelle.y * derivative_direction.x, phacelle.y * derivative_direction.y); float3 faded = lerp(float3(fade_target, 0.0, 0.0), gullies * p.gully_weight, combined_mask); - height_and_slope += faded * strength; - magnitude += strength; + float octave_weight=octave==octave_count-1?saturate(band.final_octave_weight):1.0; + height_and_slope += faded * strength * octave_weight; + magnitude += strength * octave_weight; fade_target = faded.x; float octave_rounding = lerp(p.rounding.y, p.rounding.x, saturate(phacelle.x + 0.5)) * rounding_multiplier; float new_mask = cultmath_erosion_ease_out(cultmath_erosion_smooth_start(sloping * p.onset.y, octave_rounding * p.onset.y)); combined_mask = cultmath_erosion_pow_inverse(combined_mask, p.detail) * new_mask; - ridge_fade = lerp(ridge_fade, gullies.x, ridge_mask); - ridge_mask *= cultmath_erosion_ease_out(sloping * p.onset.w); + ridge_fade = lerp(ridge_fade, lerp(ridge_fade, gullies.x, ridge_mask), octave_weight); + ridge_mask *= lerp(1.0, cultmath_erosion_ease_out(sloping * p.onset.w), octave_weight); strength *= p.gain; frequency *= p.lacunarity; rounding_multiplier *= p.rounding.w; @@ -114,4 +138,10 @@ CultMathAdvancedErosionResult cultmath_advanced_erosion_filter(float2 position, return result; } +CultMathAdvancedErosionResult cultmath_advanced_erosion_filter(float2 position, float3 base_height_and_slope, float fade_target, CultMathAdvancedErosionParameters p) +{ + CultMathErosionBandSelection band; band.active_octaves=p.octaves; band.final_octave_weight=1.0; band.finest_included_wavelength=0.0; band.unresolved_height_bound=0.0; + return cultmath_advanced_erosion_filter_banded(position, base_height_and_slope, fade_target, p, band); +} + #endif diff --git a/src/CultMath/AdvancedErosionFilter.cs b/src/CultMath/AdvancedErosionFilter.cs index 6780223f..65db3671 100644 --- a/src/CultMath/AdvancedErosionFilter.cs +++ b/src/CultMath/AdvancedErosionFilter.cs @@ -34,6 +34,9 @@ public readonly record struct AdvancedErosionResult(float3 Delta, float Magnitud public static class AdvancedErosionFilter { public static AdvancedErosionResult Sample(float2 position, float3 baseHeightAndSlope, float fadeTarget, AdvancedErosionParameters p) + => Sample(position, baseHeightAndSlope, fadeTarget, p, new ErosionBandSelection(p.Octaves, 1.0f, 0.0f, 0.0f)); + + public static AdvancedErosionResult Sample(float2 position, float3 baseHeightAndSlope, float fadeTarget, AdvancedErosionParameters p, ErosionBandSelection band) { var strength = p.Strength * p.Scale; fadeTarget = math.clamp(fadeTarget, -1.0f, 1.0f); @@ -51,7 +54,7 @@ public static class AdvancedErosionFilter var ridgeFade = fadeTarget; var gullySlope = math.lerp(slope, slope / slopeLength * p.AssumedSlope.x, p.AssumedSlope.y); - var octaves = math.min(math.max(p.Octaves, 0), 8); + var octaves = math.min(math.min(math.max(p.Octaves, 0), 8), math.max(band.ActiveOctaves, 0)); for (var octave = 0; octave < octaves; octave++) { var phacelle = Phacelle(position * frequency, SafeNormalize(gullySlope), p.CellScale, 0.25f, p.Normalization); @@ -61,16 +64,17 @@ public static class AdvancedErosionFilter var gullies = new float3(phacelle.x, phacelle.y * derivativeDirection.x, phacelle.y * derivativeDirection.y); var faded = math.lerp(new float3(fadeTarget, 0.0f, 0.0f), gullies * p.GullyWeight, combinedMask); - heightAndSlope += faded * strength; - magnitude += strength; + var octaveWeight = octave == octaves - 1 ? math.saturate(band.FinalOctaveWeight) : 1.0f; + heightAndSlope += faded * strength * octaveWeight; + magnitude += strength * octaveWeight; fadeTarget = faded.x; var octaveRounding = math.lerp(p.Rounding.y, p.Rounding.x, math.saturate(phacelle.x + 0.5f)) * roundingMultiplier; var newMask = EaseOut(SmoothStart(sloping * p.Onset.y, octaveRounding * p.Onset.y)); combinedMask = PowInverse(combinedMask, p.Detail) * newMask; - ridgeFade = math.lerp(ridgeFade, gullies.x, ridgeMask); - ridgeMask *= EaseOut(sloping * p.Onset.w); + ridgeFade = math.lerp(ridgeFade, math.lerp(ridgeFade, gullies.x, ridgeMask), octaveWeight); + ridgeMask *= math.lerp(1.0f, EaseOut(sloping * p.Onset.w), octaveWeight); strength *= p.Gain; frequency *= p.Lacunarity; roundingMultiplier *= p.Rounding.w; diff --git a/src/CultMath/ErosionFrequencyBands.cs b/src/CultMath/ErosionFrequencyBands.cs new file mode 100644 index 00000000..3c63eb62 --- /dev/null +++ b/src/CultMath/ErosionFrequencyBands.cs @@ -0,0 +1,57 @@ +namespace CultMath; + +public readonly record struct ErosionBandSelection( + int ActiveOctaves, + float FinalOctaveWeight, + float FinestIncludedWavelength, + float UnresolvedHeightBound) +{ + public bool HasSamples => ActiveOctaves > 0; +} + +public static class ErosionFrequencyBands +{ + public static ErosionBandSelection Select( + float baseWavelength, + float sampleSpacing, + int maximumOctaves, + float lacunarity, + float baseAmplitude, + float gain, + float transitionRatio = 2.0f) + { + baseWavelength = math.max(baseWavelength, 1.0e-6f); + sampleSpacing = math.max(sampleSpacing, 0.0f); + lacunarity = math.max(lacunarity, 1.01f); + transitionRatio = math.max(transitionRatio, 1.01f); + maximumOctaves = math.min(math.max(maximumOctaves, 0), 16); + var nyquistWavelength = sampleSpacing * 2.0f; + var wavelength = baseWavelength; + var active = 0; + var finalWeight = 0.0f; + var finest = 0.0f; + + for (var octave = 0; octave < maximumOctaves; octave++) + { + var weight = nyquistWavelength <= 0.0f + ? 1.0f + : math.smoothstep(nyquistWavelength, nyquistWavelength * transitionRatio, wavelength); + if (weight <= 0.0f) break; + active++; + finalWeight = weight; + finest = wavelength; + wavelength /= lacunarity; + } + + var omittedAmplitude = 0.0f; + var amplitude = math.abs(baseAmplitude); + for (var octave = 0; octave < maximumOctaves; octave++) + { + if (octave >= active) omittedAmplitude += amplitude; + else if (octave == active - 1) omittedAmplitude += amplitude * (1.0f - finalWeight); + amplitude *= math.abs(gain); + } + + return new ErosionBandSelection(active, active > 0 ? finalWeight : 0.0f, finest, omittedAmplitude); + } +} diff --git a/tests/CultMath.Tests/ErosionFrequencyBandsTests.cs b/tests/CultMath.Tests/ErosionFrequencyBandsTests.cs new file mode 100644 index 00000000..f57213a4 --- /dev/null +++ b/tests/CultMath.Tests/ErosionFrequencyBandsTests.cs @@ -0,0 +1,34 @@ +using Xunit; + +namespace CultMath.Tests; + +public sealed class ErosionFrequencyBandsTests +{ + [Fact] + public void RadiusIndependentWorldWavelengthSelectsSameBands() + { + var small = ErosionFrequencyBands.Select(1_000.0f, 100.0f, 8, 2.0f, 20.0f, 0.5f); + var large = ErosionFrequencyBands.Select(1_000.0f, 100.0f, 8, 2.0f, 20.0f, 0.5f); + Assert.Equal(small, large); + Assert.Equal(3, small.ActiveOctaves); + } + + [Fact] + public void TransitionPartiallyWeightsLastResolvableOctave() + { + var selection = ErosionFrequencyBands.Select(1_000.0f, 50.0f, 8, 2.0f, 1.0f, 0.5f); + Assert.Equal(4, selection.ActiveOctaves); + Assert.InRange(selection.FinalOctaveWeight, 0.0f, 1.0f); + Assert.True(selection.UnresolvedHeightBound > 0.0f); + } + + [Fact] + public void BandedFilterPreservesLowOctaveResultExactly() + { + var p = AdvancedErosionParameters.Default; + var band = new ErosionBandSelection(2, 1.0f, 0.0f, 0.0f); + var banded = AdvancedErosionFilter.Sample(new float2(0.42f, 0.31f), new float3(0.5f, 0.1f, -0.2f), 0.0f, p, band); + var truncated = AdvancedErosionFilter.Sample(new float2(0.42f, 0.31f), new float3(0.5f, 0.1f, -0.2f), 0.0f, p with { Octaves = 2 }); + Assert.Equal(truncated, banded); + } +} From e870663fe038d5ed532a48243b93bb376796ab2d Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 13 Jul 2026 00:41:25 +0100 Subject: [PATCH 013/283] Make spherical erosion diagnostics finite --- src/CultMath/float3.cs | 2 ++ tests/CultMath.Tests/SphericalErosionTests.cs | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/CultMath/float3.cs b/src/CultMath/float3.cs index e9833ae4..4a4efeba 100644 --- a/src/CultMath/float3.cs +++ b/src/CultMath/float3.cs @@ -67,6 +67,8 @@ public record struct float3(float x, float y, float z) public static explicit operator System.Numerics.Vector3(float3 value) => new(value.x, value.y, value.z); public static explicit operator float3(System.Numerics.Vector3 value) => new(value.X, value.Y, value.Z); + public override readonly string ToString() => $"float3({x:R}, {y:R}, {z:R})"; + public static float3 operator +(float3 value) => value; public static float3 operator -(float3 value) => new(-value.x, -value.y, -value.z); public static float3 operator +(float3 left, float3 right) => new(left.x + right.x, left.y + right.y, left.z + right.z); diff --git a/tests/CultMath.Tests/SphericalErosionTests.cs b/tests/CultMath.Tests/SphericalErosionTests.cs index 53d37bce..f634ba6d 100644 --- a/tests/CultMath.Tests/SphericalErosionTests.cs +++ b/tests/CultMath.Tests/SphericalErosionTests.cs @@ -9,9 +9,14 @@ public sealed class SphericalErosionTests { var parameters = SphericalErosionParameters.Default with { Seed = 42.0f }; var a = SphericalErosion.Sample(new float3(0.31f, -0.74f, 0.59f), 0.2f, new float3(0.4f, -0.1f, 0.2f), parameters); + var repeated = SphericalErosion.Sample(new float3(0.31f, -0.74f, 0.59f), 0.2f, new float3(0.4f, -0.1f, 0.2f), parameters); var b = SphericalErosion.Sample(new float3(3.1f, -7.4f, 5.9f), 0.2f, new float3(0.4f, -0.1f, 0.2f), parameters); - Assert.Equal(a, b); + Assert.Equal(a, repeated); + Assert.InRange(math.abs(a.HeightOffset-b.HeightOffset),0.0f,1.0e-6f); + Assert.InRange(math.abs(a.Ridge-b.Ridge),0.0f,1.0e-6f); + Assert.InRange(math.abs(a.Gully-b.Gully),0.0f,5.0e-5f); + Assert.InRange(math.length(a.Gradient-b.Gradient),0.0f,5.0e-6f); Assert.InRange(a.HeightOffset, -0.08f, 0.08f); Assert.InRange(a.Ridge, 0.0f, 1.0f); Assert.InRange(a.Gully, 0.0f, 1.0f); From 15f27173ddf4bf6d5d0380b0d79cd644ce42f6e8 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 13 Jul 2026 00:45:25 +0100 Subject: [PATCH 014/283] Share planetary radial refinement semantics --- shaders/CultMath.hlsl | 19 ++++++++++++ src/CultMath/PlanetaryRadialRefinement.cs | 28 ++++++++++++++++++ .../PlanetaryRadialRefinementTests.cs | 29 +++++++++++++++++++ 3 files changed, 76 insertions(+) create mode 100644 src/CultMath/PlanetaryRadialRefinement.cs create mode 100644 tests/CultMath.Tests/PlanetaryRadialRefinementTests.cs diff --git a/shaders/CultMath.hlsl b/shaders/CultMath.hlsl index c55a1790..e7281c99 100644 --- a/shaders/CultMath.hlsl +++ b/shaders/CultMath.hlsl @@ -337,4 +337,23 @@ CultMathSphericalErosionSample cultmath_spherical_erosion(float3 unit_position, return result; } +float3 cultmath_planetary_radial_refinement_step( + float3 position, + float3 ray_direction, + float3 center, + float target_radius, + float minimum_derivative, + float maximum_correction) +{ + float3 local=position-center; + float radius=length(local); + float3 radial=local/max(radius,0.0001); + float error=radius-target_radius; + float derivative=dot(ray_direction,radial); + float safe_minimum=max(minimum_derivative,0.0001); + float safe_derivative=abs(derivative)>safe_minimum?derivative:(derivative<0?-safe_minimum:safe_minimum); + float correction=clamp(-error/safe_derivative,-abs(maximum_correction),abs(maximum_correction)); + return position+ray_direction*correction; +} + #endif diff --git a/src/CultMath/PlanetaryRadialRefinement.cs b/src/CultMath/PlanetaryRadialRefinement.cs new file mode 100644 index 00000000..7188a513 --- /dev/null +++ b/src/CultMath/PlanetaryRadialRefinement.cs @@ -0,0 +1,28 @@ +namespace CultMath; + +public static class PlanetaryRadialRefinement +{ + public static float3 Step( + float3 position, + float3 rayDirection, + float3 center, + float targetRadius, + float minimumDerivative = 0.2f, + float maximumCorrection = 0.08f) + { + var local = position - center; + var radius = math.length(local); + var radial = local / math.max(radius, 0.0001f); + var error = radius - targetRadius; + var derivative = math.dot(rayDirection, radial); + var safeMinimum = math.max(minimumDerivative, 0.0001f); + var safeDerivative = math.abs(derivative) > safeMinimum + ? derivative + : derivative < 0.0f ? -safeMinimum : safeMinimum; + var correction = math.clamp( + -error / safeDerivative, + -math.abs(maximumCorrection), + math.abs(maximumCorrection)); + return position + rayDirection * correction; + } +} diff --git a/tests/CultMath.Tests/PlanetaryRadialRefinementTests.cs b/tests/CultMath.Tests/PlanetaryRadialRefinementTests.cs new file mode 100644 index 00000000..d0263b67 --- /dev/null +++ b/tests/CultMath.Tests/PlanetaryRadialRefinementTests.cs @@ -0,0 +1,29 @@ +using Xunit; + +namespace CultMath.Tests; + +public sealed class PlanetaryRadialRefinementTests +{ + [Fact] + public void FourBoundedStepsConvergeFromTheRasterCaptureShell() + { + var center=new float3(0.3f,-0.2f,0.7f); + var radial=math.normalize(new float3(0.2f,-0.4f,0.9f)); + var targetRadius=3.85f; + var target=center+radial*targetRadius; + var origin=target+math.normalize(radial+new float3(0.12f,-0.05f,0.02f))*6.0f; + var position=center+radial*(targetRadius+0.30f); + var ray=math.normalize(position-origin); + for(var step=0;step<4;step++) + position=PlanetaryRadialRefinement.Step(position,ray,center,targetRadius); + Assert.InRange(math.abs(math.length(position-center)-targetRadius),0.0f,1.0e-4f); + } + + [Fact] + public void StepClampsWeakDerivativeCorrections() + { + var position=new float3(0,0,4.1f); + var result=PlanetaryRadialRefinement.Step(position,new float3(1,0,0),float3.zero,3.8f); + Assert.InRange(math.length(result-position),0.07999f,0.08001f); + } +} From 42fef7cdd70e8d8b98fab56a58cfd1a361120db7 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 13 Jul 2026 02:14:11 +0100 Subject: [PATCH 015/283] Build portable planetary field runtime --- README.md | 6 + docs/design.md | 6 + docs/planetary.md | 117 +++++++ shaders/CultMath.hlsl | 1 + shaders/Planetary.hlsl | 260 ++++++++++++++ src/CultMath/CultMath.csproj | 2 + src/CultMath/PlanetaryField.cs | 213 ++++++++++++ src/CultMath/PlanetaryPages.cs | 185 ++++++++++ src/CultMath/PlanetaryPatch.cs | 42 +++ src/CultMath/PlanetaryProjection.cs | 320 ++++++++++++++++++ src/CultMath/PlanetaryQueries.cs | 191 +++++++++++ src/CultMath/PlanetaryResidency.cs | 144 ++++++++ src/CultMath/PlanetaryTopology.cs | 170 ++++++++++ tests/CultMath.Tests/HlslMirrorTests.cs | 16 + tests/CultMath.Tests/PlanetaryFieldTests.cs | 80 +++++ tests/CultMath.Tests/PlanetaryPageTests.cs | 57 ++++ tests/CultMath.Tests/PlanetaryPatchTests.cs | 40 +++ .../PlanetaryProjectionTests.cs | 73 ++++ tests/CultMath.Tests/PlanetaryQueryTests.cs | 46 +++ .../CultMath.Tests/PlanetaryResidencyTests.cs | 57 ++++ .../CultMath.Tests/PlanetaryTopologyTests.cs | 55 +++ unity/Runtime/CultMath.Unity.asmdef | 16 + unity/Runtime/PlanetaryPageUpload.cs | 81 +++++ unity/Runtime/PlanetaryPatchMeshAdapter.cs | 36 ++ 24 files changed, 2214 insertions(+) create mode 100644 docs/planetary.md create mode 100644 shaders/Planetary.hlsl create mode 100644 src/CultMath/PlanetaryField.cs create mode 100644 src/CultMath/PlanetaryPages.cs create mode 100644 src/CultMath/PlanetaryPatch.cs create mode 100644 src/CultMath/PlanetaryProjection.cs create mode 100644 src/CultMath/PlanetaryQueries.cs create mode 100644 src/CultMath/PlanetaryResidency.cs create mode 100644 src/CultMath/PlanetaryTopology.cs create mode 100644 tests/CultMath.Tests/PlanetaryFieldTests.cs create mode 100644 tests/CultMath.Tests/PlanetaryPageTests.cs create mode 100644 tests/CultMath.Tests/PlanetaryPatchTests.cs create mode 100644 tests/CultMath.Tests/PlanetaryProjectionTests.cs create mode 100644 tests/CultMath.Tests/PlanetaryQueryTests.cs create mode 100644 tests/CultMath.Tests/PlanetaryResidencyTests.cs create mode 100644 tests/CultMath.Tests/PlanetaryTopologyTests.cs create mode 100644 unity/Runtime/CultMath.Unity.asmdef create mode 100644 unity/Runtime/PlanetaryPageUpload.cs create mode 100644 unity/Runtime/PlanetaryPatchMeshAdapter.cs diff --git a/README.md b/README.md index 1228736a..29eb115f 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,12 @@ shader semantics. - `Voronoi.SampleTones`, a C# batch surface that calls the Rust `cultmath-core` native kernel when `cultmath_core` is available and falls back to the managed parity path otherwise. +- `PlanetaryField`, a scale-aware CPU/HLSL spherical field contract with + deterministic identity, cube-sphere topology, residual pages, LOD residency, + ray/path/region queries, coarse patches, and projected map-tile baking. See + `docs/planetary.md`. +- `CultMath.Unity`, an engine-facing assembly containing only Unity mesh and + page-upload adapters for the canonical planetary contracts. ## Native Core diff --git a/docs/design.md b/docs/design.md index 8250ba78..f4ca5b49 100644 --- a/docs/design.md +++ b/docs/design.md @@ -19,6 +19,12 @@ Rust hot kernels, C# host code, and HLSL shader code. - Keep the surface boring and exact. Noise primitives are allowed when they are source-grounded, shader-shaped, and shared by more than one project. Matrices, quaternions, and packing helpers still need an owner before they enter. +- Planetary geometry is a scale-aware field query, not a renderer asset. CPU + simulation is the reference consumer; pages, patches, and maps are derived + lowerings carrying field identity and unresolved error. +- Application base fields and gameplay meaning enter through narrow inputs. + CultMath does not own biomes, resources, traversability, render materials, or + committed game consequences. ## Non-Goals diff --git a/docs/planetary.md b/docs/planetary.md new file mode 100644 index 00000000..8196c1c7 --- /dev/null +++ b/docs/planetary.md @@ -0,0 +1,117 @@ +# Planetary Field Runtime + +CultMath owns the deterministic, renderer-independent planetary field. The same +definition can be queried by a CPU simulation, baked into residual pages, +sampled through a map projection, or evaluated by HLSL. Render resources and +gameplay interpretation remain consumer responsibilities. + +## Authority + +- `PlanetaryFieldDefinition` identifies radius, seed, erosion parameters, and a + version that includes the consumer-owned base-field version. +- `IPlanetaryBaseField` supplies deterministic application-authored base + evidence without making CultMath depend on an application. +- `PlanetaryQueryScale` makes the physical footprint and accepted unresolved + error explicit. There is deliberately no scale-free authoritative + `HeightAt` call. +- `PlanetarySurfaceSample` carries displacement, tangent gradient, normal, + slope, ridge/gully evidence, resolved wavelength, and unresolved bound. +- pages, residency, patches, and map tiles are disposable lowerings of that + contract. + +The C# surface targets .NET and Unity-compatible `netstandard2.1`. The matching +HLSL lives in `shaders/Planetary.hlsl` and is included by `CultMath.hlsl`. + +## Point and batch queries + +```csharp +var erosion = AdvancedErosionParameters.Default with +{ + Scale = radius * 0.075f, + Strength = 0.12f, + Octaves = 7, +}; +var field = PlanetaryFieldDefinition.Create( + baseFieldVersion: 17, + radius, + seed: 42, + erosion); +var scale = PlanetaryQueryScale.AtFootprint( + footprintMeters: 10, + maximumUnresolvedHeight: 0.5f); + +PlanetaryBaseFieldSample basis = source.Sample(direction); +PlanetarySurfaceSample sample = PlanetaryField.Sample( + field, direction, basis, scale); +``` + +`PlanetaryField.SampleBatch` writes into a caller-owned span. `SamplePosition` +accepts `double3`, reduces the astronomical position to a stable unit direction, +and then evaluates the same float field contract. + +Higher-level CPU queries include bounded ray intersection, segment clearance, +great-circle profiles, and region summaries. Their answers remain field queries; +only a consuming simulation can turn them into committed game consequences. + +## Cube-sphere topology and pages + +`PlanetaryTopology` owns the tangent/QSC cube-sphere mapping, inverse face +coordinates, tile selection, local page coordinates, and radial-graph surface +normal. `PlanetaryPageSampling` owns bordered directions, nominal spacing, +bilinear sampling, and summaries. + +`PlanetaryPageBaker` evaluates a root page at its physical sample spacing. A +child stores `child filtered field - parent filtered field`. A +`PlanetaryPageSetSampling` query adds every containing ancestor contribution +and applies transition weights only to residuals. + +`PlanetaryLodSelector` selects six roots plus one camera-facing ancestor chain +from the unresolved-height error. `PlanetaryResidualResidency` owns arrival and +departure presentation weights, content and presentation versions, and nothing +about field truth. + +## Patches + +`PlanetaryPatch.CreateFace` and `CreateCubeSphere` produce renderer-neutral +coarse meshes from the canonical topology. HLSL calls +`cultmath_planetary_face_direction` for procedural vertices and +`cultmath_planetary_radial_refinement_step` for bounded pixel refinement. + +Renderers still own cameras, clip space, depth, materials, buffers, dispatch, +and draw submission. + +The optional `CultMath.Unity` assembly converts a canonical face patch into a +Unity `Mesh` and converts a residency snapshot into Unity-native page input and +metadata payloads. It owns no field parameters, page selection, or simulation +state. Unity render code remains responsible for allocating/binding graphics +buffers and dispatching application-specific base-field entry points. + +## Maps + +`PlanetaryProjection` supplies forward and inverse transforms for: + +- equirectangular; +- Web Mercator with an explicit polar cutoff; +- Equal Earth; +- orthographic; +- azimuthal equidistant and equal-area; +- cube atlas; +- local tangent/gnomonic views. + +`PlanetaryMapTileBaker` maps each valid tile sample through the inverse +projection and canonical field query. `PlanetaryMapTileKey` includes field, +projection, layer, layout, and query-scale identity. Palettes, contours, labels, +and strategic overlays do not enter CultMath. + +## Numeric contract + +Integer hashes and published field versions are exact. Basic arithmetic follows +CultMath's matched C#/HLSL semantics. Hardware transcendental functions such as +`atan` and `tan` use measured tolerances rather than fictional bit identity. +Every filtered terrain query carries an unresolved-height bound so consumers can +reject insufficient fidelity explicitly. + +Current D3D12 parity evidence covers the advanced erosion kernel and the QSC +forward/inverse topology. The remaining production page and patch shaders use +the common functions and retain their seam, residual, summary, and radial-hit +integration probes in Fensalir. diff --git a/shaders/CultMath.hlsl b/shaders/CultMath.hlsl index e7281c99..cf76c8c2 100644 --- a/shaders/CultMath.hlsl +++ b/shaders/CultMath.hlsl @@ -264,6 +264,7 @@ float cultmath_value_noise_texture_bicubic(Texture2D noise_texture, Sampl } #include "AdvancedErosionFilter.hlsl" +#include "Planetary.hlsl" struct CultMathSphericalErosionParameters { diff --git a/shaders/Planetary.hlsl b/shaders/Planetary.hlsl new file mode 100644 index 00000000..729c6332 --- /dev/null +++ b/shaders/Planetary.hlsl @@ -0,0 +1,260 @@ +#ifndef CULTMATH_PLANETARY_HLSL +#define CULTMATH_PLANETARY_HLSL + +static const float CULTMATH_PLANETARY_QUARTER_PI = 0.78539816339744830962; + +float3 cultmath_planetary_face_direction(int face, float2 coordinate) +{ + float2 tangent = tan(coordinate * CULTMATH_PLANETARY_QUARTER_PI); + float3 cube = face == 0 ? float3(1.0, tangent.y, -tangent.x) + : face == 1 ? float3(-1.0, tangent.y, tangent.x) + : face == 2 ? float3(tangent.x, 1.0, -tangent.y) + : face == 3 ? float3(tangent.x, -1.0, tangent.y) + : face == 4 ? float3(tangent.x, tangent.y, 1.0) + : float3(-tangent.x, tangent.y, -1.0); + return cultmath_normalize(cube); +} + +float2 cultmath_planetary_face_coordinate(float3 direction, out int face) +{ + float3 d = cultmath_normalize(direction); + float3 a = abs(d); + float2 cube_uv; + if (a.x >= a.y && a.x >= a.z) + { + if (d.x >= 0.0) { face = 0; cube_uv = float2(-d.z, d.y) / a.x; } + else { face = 1; cube_uv = float2(d.z, d.y) / a.x; } + } + else if (a.y >= a.z) + { + if (d.y >= 0.0) { face = 2; cube_uv = float2(d.x, -d.z) / a.y; } + else { face = 3; cube_uv = float2(d.x, d.z) / a.y; } + } + else + { + if (d.z >= 0.0) { face = 4; cube_uv = d.xy / a.z; } + else { face = 5; cube_uv = float2(-d.x, d.y) / a.z; } + } + return atan(cube_uv) / CULTMATH_PLANETARY_QUARTER_PI; +} + +bool cultmath_planetary_page_local(float3 direction, float4 tile_address, float active, out float2 local) +{ + int face; + float2 uv = cultmath_planetary_face_coordinate(direction, face); + local = 0.0; + if (active < 0.5 || abs((float)face - tile_address.x) > 0.25) return false; + float axis_tiles = exp2(tile_address.y); + float2 scaled = (uv * 0.5 + 0.5) * axis_tiles; + float2 canonical = floor(min(scaled, axis_tiles - 1.0e-5)); + if (any(abs(canonical - tile_address.zw) > 0.25)) return false; + local = scaled - tile_address.zw; + return all(local >= 0.0) && all(local <= 1.0); +} + +float3 cultmath_planetary_surface_normal(float3 direction, float3 world_distance_tangent_gradient) +{ + direction = cultmath_normalize(direction); + float3 tangent_gradient = world_distance_tangent_gradient - direction * dot(world_distance_tangent_gradient, direction); + return cultmath_normalize(direction - tangent_gradient); +} + +float2 cultmath_planetary_equirectangular_forward(float3 direction) +{ + direction = cultmath_normalize(direction); + return float2(atan2(direction.y, direction.x) / CULTMATH_PI, asin(clamp(direction.z, -1.0, 1.0)) / CULTMATH_HALF_PI); +} + +float3 cultmath_planetary_equirectangular_inverse(float2 coordinate) +{ + float longitude = coordinate.x * CULTMATH_PI; + float latitude = coordinate.y * CULTMATH_HALF_PI; + float cos_latitude = cos(latitude); + return cultmath_normalize(float3(cos_latitude * cos(longitude), cos_latitude * sin(longitude), sin(latitude))); +} + +static const float CULTMATH_EQUAL_EARTH_A1 = 1.340264; +static const float CULTMATH_EQUAL_EARTH_A2 = -0.081106; +static const float CULTMATH_EQUAL_EARTH_A3 = 0.000893; +static const float CULTMATH_EQUAL_EARTH_A4 = 0.003796; +static const float CULTMATH_EQUAL_EARTH_M = 0.8660254037844386; +static const float CULTMATH_EQUAL_EARTH_X_MAX = 2.706629; +static const float CULTMATH_EQUAL_EARTH_Y_MAX = 1.3173628; + +float cultmath_equal_earth_y(float theta) +{ + float theta2 = theta * theta; + float theta6 = theta2 * theta2 * theta2; + return theta * (CULTMATH_EQUAL_EARTH_A1 + CULTMATH_EQUAL_EARTH_A2 * theta2 + theta6 * (CULTMATH_EQUAL_EARTH_A3 + CULTMATH_EQUAL_EARTH_A4 * theta2)); +} + +float2 cultmath_planetary_equal_earth_forward(float3 direction) +{ + direction = cultmath_normalize(direction); + float longitude = atan2(direction.y, direction.x); + float latitude = asin(clamp(direction.z, -1.0, 1.0)); + float theta = asin(CULTMATH_EQUAL_EARTH_M * sin(latitude)); + float theta2 = theta * theta; + float theta6 = theta2 * theta2 * theta2; + float denominator = CULTMATH_EQUAL_EARTH_M * (CULTMATH_EQUAL_EARTH_A1 + 3.0 * CULTMATH_EQUAL_EARTH_A2 * theta2 + theta6 * (7.0 * CULTMATH_EQUAL_EARTH_A3 + 9.0 * CULTMATH_EQUAL_EARTH_A4 * theta2)); + return float2(longitude * cos(theta) / denominator / CULTMATH_EQUAL_EARTH_X_MAX, cultmath_equal_earth_y(theta) / CULTMATH_EQUAL_EARTH_Y_MAX); +} + +float3 cultmath_planetary_equal_earth_inverse(float2 coordinate) +{ + float target_y = coordinate.y * CULTMATH_EQUAL_EARTH_Y_MAX; + float theta = target_y / CULTMATH_EQUAL_EARTH_A1; + [unroll] for (int iteration = 0; iteration < 8; iteration++) + { + float theta2 = theta * theta; + float theta6 = theta2 * theta2 * theta2; + float derivative = CULTMATH_EQUAL_EARTH_A1 + 3.0 * CULTMATH_EQUAL_EARTH_A2 * theta2 + theta6 * (7.0 * CULTMATH_EQUAL_EARTH_A3 + 9.0 * CULTMATH_EQUAL_EARTH_A4 * theta2); + theta -= (cultmath_equal_earth_y(theta) - target_y) / derivative; + } + float latitude = asin(clamp(sin(theta) / CULTMATH_EQUAL_EARTH_M, -1.0, 1.0)); + float theta2 = theta * theta; + float theta6 = theta2 * theta2 * theta2; + float denominator = CULTMATH_EQUAL_EARTH_M * (CULTMATH_EQUAL_EARTH_A1 + 3.0 * CULTMATH_EQUAL_EARTH_A2 * theta2 + theta6 * (7.0 * CULTMATH_EQUAL_EARTH_A3 + 9.0 * CULTMATH_EQUAL_EARTH_A4 * theta2)); + float longitude = coordinate.x * CULTMATH_EQUAL_EARTH_X_MAX * denominator / cos(theta); + float cos_latitude = cos(latitude); + return cultmath_normalize(float3(cos_latitude * cos(longitude), cos_latitude * sin(longitude), sin(latitude))); +} + +struct CultMathPlanetaryFieldDefinition +{ + float radius; + int seed; + CultMathAdvancedErosionParameters erosion; +}; + +struct CultMathPlanetaryBaseFieldSample +{ + float radial_displacement; + float3 radial_gradient; + float field_value; + float3 field_gradient; + float fade_target; +}; + +struct CultMathPlanetarySurfaceSample +{ + float radial_displacement; + float3 tangent_gradient; + float3 surface_normal; + float slope; + float ridge; + float gully; + float finest_resolved_wavelength; + float unresolved_height_bound; +}; + +struct CultMathPlanetaryPageSample +{ + float4 height_gradient; + float2 masks; +}; + +CultMathPlanetaryPageSample cultmath_planetary_page_lerp( + CultMathPlanetaryPageSample a, + CultMathPlanetaryPageSample b, + CultMathPlanetaryPageSample c, + CultMathPlanetaryPageSample d, + float2 fraction) +{ + CultMathPlanetaryPageSample result; + result.height_gradient = lerp(lerp(a.height_gradient, b.height_gradient, fraction.x), lerp(c.height_gradient, d.height_gradient, fraction.x), fraction.y); + result.masks = lerp(lerp(a.masks, b.masks, fraction.x), lerp(c.masks, d.masks, fraction.x), fraction.y); + return result; +} + +CultMathPlanetaryPageSample cultmath_planetary_residual_sample( + CultMathPlanetarySurfaceSample child, + CultMathPlanetarySurfaceSample parent, + bool has_parent) +{ + CultMathPlanetaryPageSample result; + result.height_gradient = float4(child.radial_displacement, child.tangent_gradient); + if (has_parent) result.height_gradient -= float4(parent.radial_displacement, parent.tangent_gradient); + result.masks = float2(child.ridge, child.gully); + return result; +} + +float4 cultmath_planetary_summary_empty() +{ + return float4(3.402823466e+38, -3.402823466e+38, 0.0, 0.0); +} + +float4 cultmath_planetary_summary_accumulate(float4 summary, float4 height_gradient, float unresolved_height) +{ + summary.x = min(summary.x, height_gradient.x); + summary.y = max(summary.y, height_gradient.x); + summary.z = max(summary.z, length(height_gradient.yzw)); + summary.w = max(summary.w, max(unresolved_height, 0.0)); + return summary; +} + +float cultmath_planetary_pow4(float value) { float square = value * value; return square * square; } + +CultMathPlanetarySurfaceSample cultmath_planetary_field_sample( + CultMathPlanetaryFieldDefinition definition, + float3 unit_direction, + CultMathPlanetaryBaseFieldSample base_sample, + float footprint_meters) +{ + float3 direction = cultmath_normalize(unit_direction); + float3 radial_gradient = base_sample.radial_gradient - direction * dot(base_sample.radial_gradient, direction); + float3 field_gradient = base_sample.field_gradient - direction * dot(base_sample.field_gradient, direction); + CultMathAdvancedErosionParameters p = definition.erosion; + CultMathErosionBandSelection band = cultmath_select_erosion_bands( + p.scale * p.cell_scale, footprint_meters, p.octaves, p.lacunarity, + p.strength * p.scale, p.gain, 2.0); + float3 powers = float3( + cultmath_planetary_pow4(abs(direction.x)), + cultmath_planetary_pow4(abs(direction.y)), + cultmath_planetary_pow4(abs(direction.z))); + float power_sum = max(powers.x + powers.y + powers.z, 1.0e-6); + float3 weights = powers / power_sum; + float3 world = direction * definition.radius; + float seed = (float)definition.seed; + CultMathAdvancedErosionResult xy = cultmath_advanced_erosion_filter_banded( + world.xy + float2(713.0 + seed * 0.754877666, -291.0 + seed * 0.569840296), + float3(base_sample.field_value, field_gradient.x, field_gradient.y), base_sample.fade_target, p, band); + CultMathAdvancedErosionResult yz = cultmath_advanced_erosion_filter_banded( + world.yz + float2(-431.0 + seed * 0.438289027, 887.0 + seed * 0.328438163), + float3(base_sample.field_value, field_gradient.y, field_gradient.z), base_sample.fade_target, p, band); + CultMathAdvancedErosionResult zx = cultmath_advanced_erosion_filter_banded( + world.zx + float2(197.0 + seed * 0.219783071, 557.0 + seed * 0.145898034), + float3(base_sample.field_value, field_gradient.z, field_gradient.x), base_sample.fade_target, p, band); + float erosion_height = xy.delta.x * weights.z + yz.delta.x * weights.x + zx.delta.x * weights.y; + float3 erosion_gradient = float3( + xy.delta.y * weights.z + zx.delta.z * weights.y, + xy.delta.z * weights.z + yz.delta.y * weights.x, + yz.delta.z * weights.x + zx.delta.y * weights.y); + float3 power_gradient_x = float3(4.0 * direction.x * direction.x * direction.x / definition.radius, 0.0, 0.0); + float3 power_gradient_y = float3(0.0, 4.0 * direction.y * direction.y * direction.y / definition.radius, 0.0); + float3 power_gradient_z = float3(0.0, 0.0, 4.0 * direction.z * direction.z * direction.z / definition.radius); + power_gradient_x -= direction * dot(power_gradient_x, direction); + power_gradient_y -= direction * dot(power_gradient_y, direction); + power_gradient_z -= direction * dot(power_gradient_z, direction); + float3 power_sum_gradient = power_gradient_x + power_gradient_y + power_gradient_z; + float inverse_power_sum_squared = 1.0 / (power_sum * power_sum); + float3 weight_gradient_x = (power_gradient_x * power_sum - power_sum_gradient * powers.x) * inverse_power_sum_squared; + float3 weight_gradient_y = (power_gradient_y * power_sum - power_sum_gradient * powers.y) * inverse_power_sum_squared; + float3 weight_gradient_z = (power_gradient_z * power_sum - power_sum_gradient * powers.z) * inverse_power_sum_squared; + erosion_gradient += yz.delta.x * weight_gradient_x + zx.delta.x * weight_gradient_y + xy.delta.x * weight_gradient_z; + float3 gradient = radial_gradient + erosion_gradient; + gradient -= direction * dot(gradient, direction); + float ridge_evidence = xy.ridge_map * weights.z + yz.ridge_map * weights.x + zx.ridge_map * weights.y; + CultMathPlanetarySurfaceSample result; + result.radial_displacement = base_sample.radial_displacement + erosion_height; + result.tangent_gradient = gradient; + result.surface_normal = cultmath_planetary_surface_normal(direction, gradient); + result.slope = length(gradient); + result.ridge = saturate(ridge_evidence * 0.5 + 0.5); + result.gully = saturate(0.5 - ridge_evidence * 0.5); + result.finest_resolved_wavelength = band.finest_included_wavelength; + result.unresolved_height_bound = band.unresolved_height_bound; + return result; +} + +#endif diff --git a/src/CultMath/CultMath.csproj b/src/CultMath/CultMath.csproj index 01901b6b..61b57c98 100644 --- a/src/CultMath/CultMath.csproj +++ b/src/CultMath/CultMath.csproj @@ -19,6 +19,8 @@ + + diff --git a/src/CultMath/PlanetaryField.cs b/src/CultMath/PlanetaryField.cs new file mode 100644 index 00000000..13f36c0a --- /dev/null +++ b/src/CultMath/PlanetaryField.cs @@ -0,0 +1,213 @@ +namespace CultMath; + +public readonly record struct PlanetaryQueryScale(float FootprintMeters, float MaximumUnresolvedHeight) +{ + public static PlanetaryQueryScale AtFootprint(float footprintMeters, float maximumUnresolvedHeight = float.PositiveInfinity) + => new PlanetaryQueryScale(footprintMeters, maximumUnresolvedHeight).Validate(); + + public PlanetaryQueryScale Validate() + { + if (!float.IsFinite(FootprintMeters) || FootprintMeters < 0) throw new ArgumentOutOfRangeException(nameof(FootprintMeters)); + if (float.IsNaN(MaximumUnresolvedHeight) || MaximumUnresolvedHeight < 0) throw new ArgumentOutOfRangeException(nameof(MaximumUnresolvedHeight)); + return this; + } +} + +public readonly record struct PlanetaryFieldDefinition( + ulong FieldVersion, + float Radius, + int Seed, + AdvancedErosionParameters Erosion) +{ + public static PlanetaryFieldDefinition Create( + ulong baseFieldVersion, + float radius, + int seed, + AdvancedErosionParameters erosion) + => new PlanetaryFieldDefinition(PlanetaryFieldIdentity.Compute(baseFieldVersion, radius, seed, erosion), radius, seed, erosion).Validate(); + + public PlanetaryFieldDefinition Validate() + { + if (FieldVersion == 0) throw new ArgumentOutOfRangeException(nameof(FieldVersion)); + if (!float.IsFinite(Radius) || Radius <= 0) throw new ArgumentOutOfRangeException(nameof(Radius)); + if (!float.IsFinite(Erosion.Scale) || Erosion.Scale <= 0) throw new ArgumentOutOfRangeException(nameof(Erosion)); + return this; + } +} + +public static class PlanetaryFieldIdentity +{ + public static ulong Compute(ulong baseFieldVersion, float radius, int seed, in AdvancedErosionParameters erosion) + { + if (baseFieldVersion == 0) throw new ArgumentOutOfRangeException(nameof(baseFieldVersion)); + const ulong offset = 14695981039346656037UL; + const ulong prime = 1099511628211UL; + var hash = offset; + Add(baseFieldVersion); + Add((uint)BitConverter.SingleToInt32Bits(radius)); Add((uint)seed); + Add((uint)BitConverter.SingleToInt32Bits(erosion.Scale)); Add((uint)BitConverter.SingleToInt32Bits(erosion.Strength)); + Add((uint)BitConverter.SingleToInt32Bits(erosion.GullyWeight)); Add((uint)BitConverter.SingleToInt32Bits(erosion.Detail)); + AddFloat4(erosion.Rounding); AddFloat4(erosion.Onset); + Add((uint)BitConverter.SingleToInt32Bits(erosion.AssumedSlope.x)); Add((uint)BitConverter.SingleToInt32Bits(erosion.AssumedSlope.y)); + Add((uint)BitConverter.SingleToInt32Bits(erosion.CellScale)); Add((uint)BitConverter.SingleToInt32Bits(erosion.Normalization)); + Add((uint)erosion.Octaves); Add((uint)BitConverter.SingleToInt32Bits(erosion.Lacunarity)); Add((uint)BitConverter.SingleToInt32Bits(erosion.Gain)); + return hash == 0 ? 1 : hash; + + void Add(ulong value) => hash = unchecked((hash ^ value) * prime); + void AddFloat4(float4 value) + { + Add((uint)BitConverter.SingleToInt32Bits(value.x)); Add((uint)BitConverter.SingleToInt32Bits(value.y)); + Add((uint)BitConverter.SingleToInt32Bits(value.z)); Add((uint)BitConverter.SingleToInt32Bits(value.w)); + } + } +} + +/// +/// Application-supplied base evidence at one unit spherical direction. +/// FieldValue and FieldGradient drive erosion. RadialDisplacement and +/// RadialGradient describe the uneroded surface in metres. +/// +public readonly record struct PlanetaryBaseFieldSample( + float RadialDisplacement, + float3 RadialGradient, + float FieldValue, + float3 FieldGradient, + float FadeTarget); + +public readonly record struct PlanetarySurfaceSample( + ulong FieldVersion, + float3 UnitDirection, + float Radius, + float RadialDisplacement, + float3 TangentGradient, + float3 SurfaceNormal, + float Slope, + float Ridge, + float Gully, + float FinestResolvedWavelength, + float UnresolvedHeightBound) +{ + public float SurfaceRadius => Radius + RadialDisplacement; + public float3 PlanetLocalPosition => UnitDirection * SurfaceRadius; + public bool Meets(PlanetaryQueryScale scale) => UnresolvedHeightBound <= scale.MaximumUnresolvedHeight; +} + +public static class PlanetaryField +{ + public static PlanetarySurfaceSample Sample( + in PlanetaryFieldDefinition definition, + float3 unitDirection, + in PlanetaryBaseFieldSample baseSample, + in PlanetaryQueryScale scale) + { + definition.Validate(); + scale.Validate(); + PlanetaryTopology.ValidateDirection(unitDirection); + PlanetaryTopology.ValidateFinite(baseSample.RadialGradient, nameof(baseSample)); + PlanetaryTopology.ValidateFinite(baseSample.FieldGradient, nameof(baseSample)); + if (!float.IsFinite(baseSample.RadialDisplacement) || !float.IsFinite(baseSample.FieldValue) || !float.IsFinite(baseSample.FadeTarget)) + throw new ArgumentOutOfRangeException(nameof(baseSample)); + + var direction = math.normalize(unitDirection); + var radialGradient = Tangent(direction, baseSample.RadialGradient); + var fieldGradient = Tangent(direction, baseSample.FieldGradient); + var p = definition.Erosion; + var band = ErosionFrequencyBands.Select( + p.Scale * p.CellScale, + scale.FootprintMeters, + p.Octaves, + p.Lacunarity, + p.Strength * p.Scale, + p.Gain); + + var powers = new float3( + Pow4(MathF.Abs(direction.x)), + Pow4(MathF.Abs(direction.y)), + Pow4(MathF.Abs(direction.z))); + var powerSum = math.max(powers.x + powers.y + powers.z, 1.0e-6f); + var weights = powers / powerSum; + var world = direction * definition.Radius; + var seed = definition.Seed; + var xy = AdvancedErosionFilter.Sample( + world.xy + new float2(713 + seed * 0.754877666f, -291 + seed * 0.569840296f), + new float3(baseSample.FieldValue, fieldGradient.x, fieldGradient.y), baseSample.FadeTarget, p, band); + var yz = AdvancedErosionFilter.Sample( + world.yz + new float2(-431 + seed * 0.438289027f, 887 + seed * 0.328438163f), + new float3(baseSample.FieldValue, fieldGradient.y, fieldGradient.z), baseSample.FadeTarget, p, band); + var zx = AdvancedErosionFilter.Sample( + new float2(world.z, world.x) + new float2(197 + seed * 0.219783071f, 557 + seed * 0.145898034f), + new float3(baseSample.FieldValue, fieldGradient.z, fieldGradient.x), baseSample.FadeTarget, p, band); + + var erosionHeight = xy.Delta.x * weights.z + yz.Delta.x * weights.x + zx.Delta.x * weights.y; + var erosionGradient = new float3( + xy.Delta.y * weights.z + zx.Delta.z * weights.y, + xy.Delta.z * weights.z + yz.Delta.y * weights.x, + yz.Delta.z * weights.x + zx.Delta.y * weights.y); + var powerGradientX = Tangent(direction, new float3(4 * direction.x * direction.x * direction.x / definition.Radius, 0, 0)); + var powerGradientY = Tangent(direction, new float3(0, 4 * direction.y * direction.y * direction.y / definition.Radius, 0)); + var powerGradientZ = Tangent(direction, new float3(0, 0, 4 * direction.z * direction.z * direction.z / definition.Radius)); + var sumGradient = powerGradientX + powerGradientY + powerGradientZ; + var weightGradientX = (powerGradientX * powerSum - sumGradient * powers.x) / (powerSum * powerSum); + var weightGradientY = (powerGradientY * powerSum - sumGradient * powers.y) / (powerSum * powerSum); + var weightGradientZ = (powerGradientZ * powerSum - sumGradient * powers.z) / (powerSum * powerSum); + erosionGradient += yz.Delta.x * weightGradientX + zx.Delta.x * weightGradientY + xy.Delta.x * weightGradientZ; + var gradient = Tangent(direction, radialGradient + erosionGradient); + var ridgeEvidence = xy.RidgeMap * weights.z + yz.RidgeMap * weights.x + zx.RidgeMap * weights.y; + var ridge = math.saturate(ridgeEvidence * 0.5f + 0.5f); + var gully = math.saturate(0.5f - ridgeEvidence * 0.5f); + var displacement = baseSample.RadialDisplacement + erosionHeight; + + return new( + definition.FieldVersion, + direction, + definition.Radius, + displacement, + gradient, + PlanetaryTopology.SurfaceNormal(direction, gradient), + math.length(gradient), + ridge, + gully, + band.FinestIncludedWavelength, + band.UnresolvedHeightBound); + } + + public static void SampleBatch( + in PlanetaryFieldDefinition definition, + ReadOnlySpan directions, + in PlanetaryQueryScale scale, + TSource source, + Span destination) + where TSource : IPlanetaryBaseField + { + if (destination.Length < directions.Length) throw new ArgumentException("Destination is shorter than directions.", nameof(destination)); + for (var i = 0; i < directions.Length; i++) + { + var direction = math.normalize(directions[i]); + var baseSample = source.Sample(direction); + destination[i] = Sample(definition, direction, baseSample, scale); + } + } + + public static PlanetarySurfaceSample SamplePosition( + in PlanetaryFieldDefinition definition, + double3 planetLocalPosition, + in PlanetaryQueryScale scale, + TSource source) + where TSource : IPlanetaryBaseField + { + if (!double.IsFinite(planetLocalPosition.x) || !double.IsFinite(planetLocalPosition.y) || !double.IsFinite(planetLocalPosition.z)) + throw new ArgumentOutOfRangeException(nameof(planetLocalPosition)); + var length = Math.Sqrt(planetLocalPosition.x * planetLocalPosition.x + planetLocalPosition.y * planetLocalPosition.y + planetLocalPosition.z * planetLocalPosition.z); + if (length < 1.0e-12) throw new ArgumentOutOfRangeException(nameof(planetLocalPosition)); + var direction = new float3((float)(planetLocalPosition.x / length), (float)(planetLocalPosition.y / length), (float)(planetLocalPosition.z / length)); + return Sample(definition, direction, source.Sample(direction), scale); + } + + private static float3 Tangent(float3 direction, float3 gradient) => gradient - direction * math.dot(gradient, direction); + private static float Pow4(float value) { var square = value * value; return square * square; } +} + +public interface IPlanetaryBaseField +{ + PlanetaryBaseFieldSample Sample(float3 unitDirection); +} diff --git a/src/CultMath/PlanetaryPages.cs b/src/CultMath/PlanetaryPages.cs new file mode 100644 index 00000000..c9cff51f --- /dev/null +++ b/src/CultMath/PlanetaryPages.cs @@ -0,0 +1,185 @@ +namespace CultMath; + +public readonly record struct PlanetaryPageLayout(PlanetaryTileAddress Tile, int InteriorSize, int BorderSize) +{ + public int StorageSize => checked(InteriorSize + BorderSize * 2); + + public PlanetaryPageLayout Validate() + { + if (InteriorSize < 2) throw new ArgumentOutOfRangeException(nameof(InteriorSize)); + if (BorderSize < 0 || BorderSize >= InteriorSize) throw new ArgumentOutOfRangeException(nameof(BorderSize)); + return this; + } +} + +public readonly record struct PlanetaryPageSummary( + float MinimumHeight, + float MaximumHeight, + float MaximumSlope, + float UnresolvedHeightBound, + float AngularTexelSize); + +public readonly record struct PlanetaryPageSample(float Height, float3 TangentGradient, float Ridge, float Gully); + +public static class PlanetaryPageSampling +{ + public static float3 Direction(PlanetaryPageLayout page, int storageX, int storageY) + { + page.Validate(); + if ((uint)storageX >= (uint)page.StorageSize || (uint)storageY >= (uint)page.StorageSize) + throw new ArgumentOutOfRangeException(nameof(storageX)); + var localU = (storageX - page.BorderSize) / (double)(page.InteriorSize - 1); + var localV = (storageY - page.BorderSize) / (double)(page.InteriorSize - 1); + return DirectionAtLocal(page, localU, localV); + } + + public static float3 DirectionAtLocal(PlanetaryPageLayout page, double localU, double localV) + { + page.Validate(); + if (!double.IsFinite(localU) || !double.IsFinite(localV)) throw new ArgumentOutOfRangeException(nameof(localU)); + var count = page.Tile.AxisTileCount; + return PlanetaryTopology.Direction(new( + page.Tile.Face, + -1.0 + 2.0 * (page.Tile.X + localU) / count, + -1.0 + 2.0 * (page.Tile.Y + localV) / count)); + } + + public static float AngularTexelSize(PlanetaryPageLayout page) + { + var center = page.BorderSize + (page.InteriorSize - 1) / 2; + var a = Direction(page, center, center); + var b = Direction(page, Math.Min(center + 1, page.StorageSize - 1), center); + return MathF.Acos(math.clamp(math.dot(a, b), -1.0f, 1.0f)); + } + + public static float NominalAngularTexelSize(PlanetaryPageLayout page) + { + page.Validate(); + return MathF.PI * 0.5f / (page.Tile.AxisTileCount * (page.InteriorSize - 1)); + } + + public static PlanetaryPageSample Bilinear( + ReadOnlySpan samples, + PlanetaryPageLayout page, + float2 local) + { + page.Validate(); + if (samples.Length != page.StorageSize * page.StorageSize) throw new ArgumentException("Page sample count does not match layout.", nameof(samples)); + var texel = local * (page.InteriorSize - 1) + page.BorderSize; + var x0 = Math.Clamp((int)MathF.Floor(texel.x), 0, page.StorageSize - 1); + var y0 = Math.Clamp((int)MathF.Floor(texel.y), 0, page.StorageSize - 1); + var x1 = Math.Min(x0 + 1, page.StorageSize - 1); + var y1 = Math.Min(y0 + 1, page.StorageSize - 1); + var tx = math.frac(texel.x); + var ty = math.frac(texel.y); + var a = Lerp(samples[y0 * page.StorageSize + x0], samples[y0 * page.StorageSize + x1], tx); + var b = Lerp(samples[y1 * page.StorageSize + x0], samples[y1 * page.StorageSize + x1], tx); + return Lerp(a, b, ty); + } + + public static PlanetaryPageSummary Summarize(ReadOnlySpan samples, PlanetaryPageLayout page, float unresolvedHeightBound) + { + page.Validate(); + if (samples.Length != page.StorageSize * page.StorageSize) throw new ArgumentException("Page sample count does not match layout.", nameof(samples)); + var min = float.PositiveInfinity; + var max = float.NegativeInfinity; + var maxSlope = 0.0f; + foreach (var sample in samples) + { + min = MathF.Min(min, sample.Height); + max = MathF.Max(max, sample.Height); + maxSlope = MathF.Max(maxSlope, math.length(sample.TangentGradient)); + } + return new(min, max, maxSlope, MathF.Max(unresolvedHeightBound, 0), AngularTexelSize(page)); + } + + private static PlanetaryPageSample Lerp(PlanetaryPageSample a, PlanetaryPageSample b, float t) => new( + math.lerp(a.Height, b.Height, t), + math.lerp(a.TangentGradient, b.TangentGradient, t), + math.lerp(a.Ridge, b.Ridge, t), + math.lerp(a.Gully, b.Gully, t)); +} + +public readonly record struct PlanetaryBakedPage( + PlanetaryPageLayout Layout, + PlanetaryPageSample[] Samples, + PlanetaryPageSummary Summary); + +public static class PlanetaryPageBaker +{ + public static PlanetaryBakedPage Bake( + in PlanetaryFieldDefinition field, + PlanetaryPageLayout layout, + TSource source) + where TSource : IPlanetaryBaseField + { + layout.Validate(); field.Validate(); + var spacing = PlanetaryPageSampling.NominalAngularTexelSize(layout) * field.Radius; + var parentSpacing = layout.Tile.Level == 0 + ? 0 + : PlanetaryPageSampling.NominalAngularTexelSize(new(layout.Tile.Parent(), layout.InteriorSize, layout.BorderSize)) * field.Radius; + var samples = new PlanetaryPageSample[layout.StorageSize * layout.StorageSize]; + var unresolved = 0.0f; + for (var y = 0; y < layout.StorageSize; y++) + for (var x = 0; x < layout.StorageSize; x++) + { + var direction = PlanetaryPageSampling.Direction(layout, x, y); + var baseSample = source.Sample(direction); + var child = PlanetaryField.Sample(field, direction, baseSample, PlanetaryQueryScale.AtFootprint(spacing)); + var height = child.RadialDisplacement; + var gradient = child.TangentGradient; + if (parentSpacing > 0) + { + var parent = PlanetaryField.Sample(field, direction, baseSample, PlanetaryQueryScale.AtFootprint(parentSpacing)); + height -= parent.RadialDisplacement; + gradient -= parent.TangentGradient; + } + samples[y * layout.StorageSize + x] = new(height, gradient, child.Ridge, child.Gully); + unresolved = MathF.Max(unresolved, child.UnresolvedHeightBound); + } + return new(layout, samples, PlanetaryPageSampling.Summarize(samples, layout, unresolved)); + } +} + +public readonly record struct PlanetaryResidentPage(PlanetaryBakedPage Page, float Blend) +{ + public PlanetaryResidentPage Validate() + { + if (!float.IsFinite(Blend) || Blend is < 0 or > 1) throw new ArgumentOutOfRangeException(nameof(Blend)); + Page.Layout.Validate(); + if (Page.Samples.Length != Page.Layout.StorageSize * Page.Layout.StorageSize) throw new ArgumentException("Page payload does not match layout."); + return this; + } +} + +public static class PlanetaryPageSetSampling +{ + public static bool TrySample(ReadOnlySpan pages, float3 direction, out PlanetaryPageSample sample) + { + PlanetaryTopology.ValidateDirection(direction); + var height = 0.0f; + var gradient = float3.zero; + var ridge = 0.0f; + var gully = 0.0f; + var found = false; + var deepestLevel = -1; + foreach (var resident in pages) + { + resident.Validate(); + if (!PlanetaryTopology.TryLocalCoordinate(direction, resident.Page.Layout.Tile, out var local)) continue; + var contribution = PlanetaryPageSampling.Bilinear(resident.Page.Samples, resident.Page.Layout, local); + var blend = math.saturate(resident.Blend); + height += contribution.Height * blend; + gradient += contribution.TangentGradient * blend; + if (resident.Page.Layout.Tile.Level >= deepestLevel) + { + ridge = found ? math.lerp(ridge, contribution.Ridge, blend) : contribution.Ridge; + gully = found ? math.lerp(gully, contribution.Gully, blend) : contribution.Gully; + deepestLevel = resident.Page.Layout.Tile.Level; + } + found = true; + } + sample = new(height, gradient, ridge, gully); + return found; + } +} diff --git a/src/CultMath/PlanetaryPatch.cs b/src/CultMath/PlanetaryPatch.cs new file mode 100644 index 00000000..0fd3cbb6 --- /dev/null +++ b/src/CultMath/PlanetaryPatch.cs @@ -0,0 +1,42 @@ +namespace CultMath; + +public readonly record struct PlanetaryPatchVertex(float2 LocalCoordinate, float3 UnitDirection); + +public readonly record struct PlanetaryPatchMesh( + PlanetaryCubeFace Face, + int CellsPerAxis, + PlanetaryPatchVertex[] Vertices, + int[] Indices); + +public static class PlanetaryPatch +{ + public static PlanetaryPatchMesh CreateFace(PlanetaryCubeFace face, int cellsPerAxis) + { + if (!Enum.IsDefined(typeof(PlanetaryCubeFace), face)) throw new ArgumentOutOfRangeException(nameof(face)); + if (cellsPerAxis < 1 || cellsPerAxis > 4096) throw new ArgumentOutOfRangeException(nameof(cellsPerAxis)); + var axisVertices = cellsPerAxis + 1; + var vertices = new PlanetaryPatchVertex[checked(axisVertices * axisVertices)]; + for (var y = 0; y < axisVertices; y++) + for (var x = 0; x < axisVertices; x++) + { + var local = new float2(x / (float)cellsPerAxis, y / (float)cellsPerAxis); + vertices[y * axisVertices + x] = new(local, PlanetaryTopology.Direction(new(face, local.x * 2 - 1, local.y * 2 - 1))); + } + var indices = new int[checked(cellsPerAxis * cellsPerAxis * 6)]; + var write = 0; + for (var y = 0; y < cellsPerAxis; y++) + for (var x = 0; x < cellsPerAxis; x++) + { + var lowerLeft = y * axisVertices + x; + var lowerRight = lowerLeft + 1; + var upperLeft = lowerLeft + axisVertices; + var upperRight = upperLeft + 1; + indices[write++] = lowerLeft; indices[write++] = lowerRight; indices[write++] = upperRight; + indices[write++] = lowerLeft; indices[write++] = upperRight; indices[write++] = upperLeft; + } + return new(face, cellsPerAxis, vertices, indices); + } + + public static PlanetaryPatchMesh[] CreateCubeSphere(int cellsPerAxis) + => ((PlanetaryCubeFace[])Enum.GetValues(typeof(PlanetaryCubeFace))).Select(face => CreateFace(face, cellsPerAxis)).ToArray(); +} diff --git a/src/CultMath/PlanetaryProjection.cs b/src/CultMath/PlanetaryProjection.cs new file mode 100644 index 00000000..f849fe20 --- /dev/null +++ b/src/CultMath/PlanetaryProjection.cs @@ -0,0 +1,320 @@ +namespace CultMath; + +public enum PlanetaryProjectionKind +{ + Equirectangular, + WebMercator, + EqualEarth, + Orthographic, + AzimuthalEquidistant, + AzimuthalEqualArea, + CubeAtlas, + LocalTangent, +} + +public readonly record struct PlanetaryProjectionParameters( + PlanetaryProjectionKind Kind, + double CenterLongitude = 0, + double CenterLatitude = 0, + double Scale = 1) +{ + public PlanetaryProjectionParameters Validate() + { + if (!double.IsFinite(CenterLongitude) || !double.IsFinite(CenterLatitude) || !double.IsFinite(Scale) || Scale <= 0) + throw new ArgumentOutOfRangeException(nameof(Scale)); + if (CenterLatitude is < -Math.PI / 2 or > Math.PI / 2) throw new ArgumentOutOfRangeException(nameof(CenterLatitude)); + return this; + } +} + +public static class PlanetaryProjection +{ + private const double EqualEarthA1 = 1.340264; + private const double EqualEarthA2 = -0.081106; + private const double EqualEarthA3 = 0.000893; + private const double EqualEarthA4 = 0.003796; + private static readonly double EqualEarthM = Math.Sqrt(3) / 2; + private static readonly double EqualEarthXMax = Math.PI / (EqualEarthM * EqualEarthA1); + private static readonly double EqualEarthYMax = EqualEarthY(Math.Asin(EqualEarthM)); + public static readonly double WebMercatorMaximumLatitude = Math.Atan(Math.Sinh(Math.PI)); + + public static bool TryForward(float3 direction, PlanetaryProjectionParameters parameters, out double2 coordinate) + { + parameters.Validate(); + PlanetaryTopology.ValidateDirection(direction); + var d = math.normalize(direction); + if (parameters.Kind == PlanetaryProjectionKind.CubeAtlas) + { + var face = PlanetaryTopology.FaceCoordinate(d); + var index = (int)face.Face; + var column = index % 3; + var row = index / 3; + coordinate = new( + (-1 + (column + (face.U + 1) * 0.5) * (2.0 / 3.0)) / parameters.Scale, + (1 - (row + (face.V + 1) * 0.5)) / parameters.Scale); + return true; + } + + var longitude = Math.Atan2(d.y, d.x); + var latitude = Math.Asin(Math.Clamp(d.z, -1, 1)); + var deltaLongitude = WrapLongitude(longitude - parameters.CenterLongitude); + var centered = CenteredForward(deltaLongitude, latitude, parameters, out coordinate); + coordinate /= parameters.Scale; + return centered; + } + + public static bool TryInverse(double2 coordinate, PlanetaryProjectionParameters parameters, out float3 direction) + { + parameters.Validate(); + if (!double.IsFinite(coordinate.x) || !double.IsFinite(coordinate.y)) + { + direction = float3.zero; + return false; + } + coordinate *= parameters.Scale; + if (parameters.Kind == PlanetaryProjectionKind.CubeAtlas) + return TryInverseCubeAtlas(coordinate, out direction); + + if (!CenteredInverse(coordinate, parameters, out var deltaLongitude, out var latitude)) + { + direction = float3.zero; + return false; + } + var longitude = WrapLongitude(deltaLongitude + parameters.CenterLongitude); + var cosLatitude = Math.Cos(latitude); + direction = math.normalize(new float3( + (float)(cosLatitude * Math.Cos(longitude)), + (float)(cosLatitude * Math.Sin(longitude)), + (float)Math.Sin(latitude))); + return true; + } + + private static bool CenteredForward(double longitude, double latitude, PlanetaryProjectionParameters p, out double2 coordinate) + { + switch (p.Kind) + { + case PlanetaryProjectionKind.Equirectangular: + coordinate = new(longitude / Math.PI, latitude / (Math.PI * 0.5)); + return true; + case PlanetaryProjectionKind.WebMercator: + if (Math.Abs(latitude) > WebMercatorMaximumLatitude) { coordinate = double2.zero; return false; } + coordinate = new(longitude / Math.PI, Math.Asinh(Math.Tan(latitude)) / Math.PI); + return true; + case PlanetaryProjectionKind.EqualEarth: + { + var theta = Math.Asin(EqualEarthM * Math.Sin(latitude)); + var theta2 = theta * theta; + var theta6 = theta2 * theta2 * theta2; + var denominator = EqualEarthM * (EqualEarthA1 + 3 * EqualEarthA2 * theta2 + theta6 * (7 * EqualEarthA3 + 9 * EqualEarthA4 * theta2)); + coordinate = new(longitude * Math.Cos(theta) / denominator / EqualEarthXMax, EqualEarthY(theta) / EqualEarthYMax); + return true; + } + case PlanetaryProjectionKind.Orthographic: + case PlanetaryProjectionKind.AzimuthalEquidistant: + case PlanetaryProjectionKind.AzimuthalEqualArea: + case PlanetaryProjectionKind.LocalTangent: + return ForwardAzimuthal(longitude, latitude, p, out coordinate); + default: + throw new ArgumentOutOfRangeException(nameof(p)); + } + } + + private static bool CenteredInverse(double2 coordinate, PlanetaryProjectionParameters p, out double longitude, out double latitude) + { + longitude = latitude = 0; + switch (p.Kind) + { + case PlanetaryProjectionKind.Equirectangular: + if (Math.Abs(coordinate.y) > 1) return false; + longitude = coordinate.x * Math.PI; latitude = coordinate.y * Math.PI * 0.5; return Math.Abs(coordinate.x) <= 1; + case PlanetaryProjectionKind.WebMercator: + if (Math.Abs(coordinate.x) > 1 || Math.Abs(coordinate.y) > 1) return false; + longitude = coordinate.x * Math.PI; latitude = Math.Atan(Math.Sinh(coordinate.y * Math.PI)); return true; + case PlanetaryProjectionKind.EqualEarth: + { + if (Math.Abs(coordinate.x) > 1 || Math.Abs(coordinate.y) > 1) return false; + var targetY = coordinate.y * EqualEarthYMax; + var theta = targetY / EqualEarthA1; + for (var i = 0; i < 8; i++) + { + var theta2 = theta * theta; + var theta6 = theta2 * theta2 * theta2; + var f = EqualEarthY(theta) - targetY; + var derivative = EqualEarthA1 + 3 * EqualEarthA2 * theta2 + theta6 * (7 * EqualEarthA3 + 9 * EqualEarthA4 * theta2); + theta -= f / derivative; + } + var sinLatitude = Math.Sin(theta) / EqualEarthM; + if (Math.Abs(sinLatitude) > 1.0000000001) return false; + latitude = Math.Asin(Math.Clamp(sinLatitude, -1, 1)); + var thetaSquared = theta * theta; + var thetaSixth = thetaSquared * thetaSquared * thetaSquared; + var denominator = EqualEarthM * (EqualEarthA1 + 3 * EqualEarthA2 * thetaSquared + thetaSixth * (7 * EqualEarthA3 + 9 * EqualEarthA4 * thetaSquared)); + longitude = coordinate.x * EqualEarthXMax * denominator / Math.Cos(theta); + return Math.Abs(longitude) <= Math.PI + 1.0e-10; + } + case PlanetaryProjectionKind.Orthographic: + case PlanetaryProjectionKind.AzimuthalEquidistant: + case PlanetaryProjectionKind.AzimuthalEqualArea: + case PlanetaryProjectionKind.LocalTangent: + return InverseAzimuthal(coordinate, p, out longitude, out latitude); + default: + throw new ArgumentOutOfRangeException(nameof(p)); + } + } + + private static bool ForwardAzimuthal(double longitude, double latitude, PlanetaryProjectionParameters p, out double2 coordinate) + { + var sin0 = Math.Sin(p.CenterLatitude); var cos0 = Math.Cos(p.CenterLatitude); + var sin = Math.Sin(latitude); var cos = Math.Cos(latitude); var cosLon = Math.Cos(longitude); + var cosC = Math.Clamp(sin0 * sin + cos0 * cos * cosLon, -1, 1); + var rawX = cos * Math.Sin(longitude); + var rawY = cos0 * sin - sin0 * cos * cosLon; + double factor; + switch (p.Kind) + { + case PlanetaryProjectionKind.Orthographic: + if (cosC < 0) { coordinate = double2.zero; return false; } + factor = 1; break; + case PlanetaryProjectionKind.AzimuthalEquidistant: + { + var c = Math.Acos(cosC); factor = c < 1.0e-12 ? 1 : c / Math.Sin(c); factor /= Math.PI; break; + } + case PlanetaryProjectionKind.AzimuthalEqualArea: + factor = Math.Sqrt(2 / Math.Max(1 + cosC, 1.0e-20)) * 0.5; break; + case PlanetaryProjectionKind.LocalTangent: + if (cosC <= 0) { coordinate = double2.zero; return false; } + factor = 1 / cosC; break; + default: throw new ArgumentOutOfRangeException(nameof(p)); + } + coordinate = new(rawX * factor, rawY * factor); + return true; + } + + private static bool InverseAzimuthal(double2 coordinate, PlanetaryProjectionParameters p, out double longitude, out double latitude) + { + longitude = latitude = 0; + var rho = Math.Sqrt(coordinate.x * coordinate.x + coordinate.y * coordinate.y); + double c; + switch (p.Kind) + { + case PlanetaryProjectionKind.Orthographic: if (rho > 1) return false; c = Math.Asin(Math.Clamp(rho, 0, 1)); break; + case PlanetaryProjectionKind.AzimuthalEquidistant: if (rho > 1) return false; c = rho * Math.PI; break; + case PlanetaryProjectionKind.AzimuthalEqualArea: if (rho > 1) return false; c = 2 * Math.Asin(Math.Clamp(rho, 0, 1)); break; + case PlanetaryProjectionKind.LocalTangent: c = Math.Atan(rho); break; + default: throw new ArgumentOutOfRangeException(nameof(p)); + } + if (rho < 1.0e-12) { latitude = p.CenterLatitude; return true; } + var sinC = Math.Sin(c); var cosC = Math.Cos(c); + var sin0 = Math.Sin(p.CenterLatitude); var cos0 = Math.Cos(p.CenterLatitude); + latitude = Math.Asin(Math.Clamp(cosC * sin0 + coordinate.y * sinC * cos0 / rho, -1, 1)); + longitude = Math.Atan2(coordinate.x * sinC, rho * cos0 * cosC - coordinate.y * sin0 * sinC); + return true; + } + + private static bool TryInverseCubeAtlas(double2 coordinate, out float3 direction) + { + direction = float3.zero; + if (coordinate.x is < -1 or > 1 || coordinate.y is < -1 or > 1) return false; + var column = Math.Min((int)((coordinate.x + 1) * 1.5), 2); + var row = Math.Min((int)((1 - coordinate.y)), 1); + var u = ((coordinate.x + 1) * 1.5 - column) * 2 - 1; + var v = ((1 - coordinate.y) - row) * 2 - 1; + direction = PlanetaryTopology.Direction(new((PlanetaryCubeFace)(row * 3 + column), u, v)); + return true; + } + + private static double EqualEarthY(double theta) + { + var theta2 = theta * theta; + var theta6 = theta2 * theta2 * theta2; + return theta * (EqualEarthA1 + EqualEarthA2 * theta2 + theta6 * (EqualEarthA3 + EqualEarthA4 * theta2)); + } + + private static double WrapLongitude(double longitude) + { + longitude %= Math.PI * 2; + if (longitude > Math.PI) longitude -= Math.PI * 2; + if (longitude < -Math.PI) longitude += Math.PI * 2; + return longitude; + } +} + +public readonly record struct PlanetaryMapTileLayout( + PlanetaryProjectionParameters Projection, + int Level, + int X, + int Y, + int InteriorSize, + int BorderSize) +{ + public int StorageSize => checked(InteriorSize + BorderSize * 2); + + public PlanetaryMapTileLayout Validate() + { + Projection.Validate(); + if (Level is < 0 or > 30) throw new ArgumentOutOfRangeException(nameof(Level)); + var count = 1 << Level; + if ((uint)X >= (uint)count || (uint)Y >= (uint)count) throw new ArgumentOutOfRangeException(nameof(X)); + if (InteriorSize < 2 || BorderSize < 0 || BorderSize >= InteriorSize) throw new ArgumentOutOfRangeException(nameof(InteriorSize)); + return this; + } +} + +public static class PlanetaryMapTileSampling +{ + public static bool TryDirection(PlanetaryMapTileLayout tile, int storageX, int storageY, out float3 direction) + { + tile.Validate(); + if ((uint)storageX >= (uint)tile.StorageSize || (uint)storageY >= (uint)tile.StorageSize) throw new ArgumentOutOfRangeException(nameof(storageX)); + var count = 1 << tile.Level; + var localU = (storageX - tile.BorderSize) / (double)(tile.InteriorSize - 1); + var localV = (storageY - tile.BorderSize) / (double)(tile.InteriorSize - 1); + var map = new double2(-1 + 2 * (tile.X + localU) / count, 1 - 2 * (tile.Y + localV) / count); + return PlanetaryProjection.TryInverse(map, tile.Projection, out direction); + } +} + +public readonly record struct PlanetaryMapTileKey( + ulong FieldVersion, + uint ProjectionVersion, + uint LayerId, + PlanetaryMapTileLayout Layout, + PlanetaryQueryScale QueryScale) +{ + public PlanetaryMapTileKey Validate() + { + if (FieldVersion == 0 || ProjectionVersion == 0) throw new ArgumentOutOfRangeException(nameof(FieldVersion)); + Layout.Validate(); QueryScale.Validate(); + return this; + } +} + +public readonly record struct PlanetarySurfaceMapTile( + PlanetaryMapTileKey Key, + PlanetarySurfaceSample[] Samples, + bool[] Validity); + +public static class PlanetaryMapTileBaker +{ + public static PlanetarySurfaceMapTile Bake( + in PlanetaryFieldDefinition field, + PlanetaryMapTileKey key, + TSource source) + where TSource : IPlanetaryBaseField + { + field.Validate(); key.Validate(); + if (field.FieldVersion != key.FieldVersion) throw new ArgumentException("Tile field version does not match definition.", nameof(key)); + var count = key.Layout.StorageSize * key.Layout.StorageSize; + var samples = new PlanetarySurfaceSample[count]; + var validity = new bool[count]; + for (var y = 0; y < key.Layout.StorageSize; y++) + for (var x = 0; x < key.Layout.StorageSize; x++) + { + var index = y * key.Layout.StorageSize + x; + if (!PlanetaryMapTileSampling.TryDirection(key.Layout, x, y, out var direction)) continue; + samples[index] = PlanetaryField.Sample(field, direction, source.Sample(direction), key.QueryScale); + validity[index] = true; + } + return new(key, samples, validity); + } +} diff --git a/src/CultMath/PlanetaryQueries.cs b/src/CultMath/PlanetaryQueries.cs new file mode 100644 index 00000000..1f11ca77 --- /dev/null +++ b/src/CultMath/PlanetaryQueries.cs @@ -0,0 +1,191 @@ +namespace CultMath; + +public readonly record struct PlanetaryRadialBounds(float MinimumDisplacement, float MaximumDisplacement) +{ + public PlanetaryRadialBounds Validate() + { + if (!float.IsFinite(MinimumDisplacement) || !float.IsFinite(MaximumDisplacement) || MinimumDisplacement > MaximumDisplacement) + throw new ArgumentOutOfRangeException(nameof(MinimumDisplacement)); + return this; + } +} + +public readonly record struct PlanetaryRayHit( + double Distance, + double3 PlanetLocalPosition, + PlanetarySurfaceSample Surface); + +public readonly record struct PlanetaryPathSample(double Distance, PlanetarySurfaceSample Surface); + +public readonly record struct PlanetaryRegionSummary( + float MinimumDisplacement, + float MaximumDisplacement, + float MaximumSlope, + float MaximumUnresolvedHeight); + +public static class PlanetaryQueries +{ + public static bool TryIntersectRay( + in PlanetaryFieldDefinition field, + double3 rayOrigin, + double3 rayDirection, + double maximumDistance, + in PlanetaryQueryScale scale, + in PlanetaryRadialBounds bounds, + TSource source, + out PlanetaryRayHit hit) + where TSource : IPlanetaryBaseField + { + field.Validate(); scale.Validate(); bounds.Validate(); + ValidateFinite(rayOrigin, nameof(rayOrigin)); ValidateFinite(rayDirection, nameof(rayDirection)); + if (!double.IsFinite(maximumDistance) || maximumDistance <= 0) throw new ArgumentOutOfRangeException(nameof(maximumDistance)); + var directionLength = Length(rayDirection); + if (directionLength < 1.0e-15) throw new ArgumentOutOfRangeException(nameof(rayDirection)); + var direction = rayDirection / directionLength; + var outerRadius = field.Radius + bounds.MaximumDisplacement + scale.MaximumUnresolvedHeight; + if (!double.IsFinite(outerRadius)) outerRadius = field.Radius + bounds.MaximumDisplacement; + if (!TrySphereInterval(rayOrigin, direction, outerRadius, out var enter, out var leave)) { hit = default; return false; } + var start = Math.Max(enter, 0); + var end = Math.Min(leave, maximumDistance); + if (start > end) { hit = default; return false; } + + var previousDistance = start; + var previous = SignedSurfaceDistance(field, rayOrigin + direction * previousDistance, scale, source, out var previousSample); + if (previous <= 0) + { + hit = new(previousDistance, rayOrigin + direction * previousDistance, previousSample); + return true; + } + var minimumStep = Math.Max(scale.FootprintMeters * 0.5, field.Radius * 1.0e-7); + for (var iteration = 0; iteration < 512 && previousDistance < end; iteration++) + { + var nextDistance = Math.Min(previousDistance + Math.Max(previous * 0.5, minimumStep), end); + var next = SignedSurfaceDistance(field, rayOrigin + direction * nextDistance, scale, source, out var nextSample); + if (next <= 0) + { + var low = previousDistance; + var high = nextDistance; + var surface = nextSample; + for (var refine = 0; refine < 32; refine++) + { + var middle = (low + high) * 0.5; + var value = SignedSurfaceDistance(field, rayOrigin + direction * middle, scale, source, out var middleSample); + if (value > 0) low = middle; + else { high = middle; surface = middleSample; } + } + var position = rayOrigin + direction * high; + hit = new(high, position, surface); + return true; + } + if (nextDistance >= end) break; + previousDistance = nextDistance; + previous = next; + previousSample = nextSample; + } + hit = default; + return false; + } + + public static double SegmentClearance( + in PlanetaryFieldDefinition field, + double3 start, + double3 end, + double sampleSpacing, + in PlanetaryQueryScale scale, + TSource source) + where TSource : IPlanetaryBaseField + { + ValidateFinite(start, nameof(start)); ValidateFinite(end, nameof(end)); + if (!double.IsFinite(sampleSpacing) || sampleSpacing <= 0) throw new ArgumentOutOfRangeException(nameof(sampleSpacing)); + var delta = end - start; + var distance = Length(delta); + var steps = Math.Max((int)Math.Ceiling(distance / sampleSpacing), 1); + var minimum = double.PositiveInfinity; + for (var i = 0; i <= steps; i++) + { + var position = start + delta * (i / (double)steps); + minimum = Math.Min(minimum, SignedSurfaceDistance(field, position, scale, source, out _)); + } + return minimum; + } + + public static PlanetaryPathSample[] SampleGreatCircle( + in PlanetaryFieldDefinition field, + float3 startDirection, + float3 endDirection, + int segmentCount, + in PlanetaryQueryScale scale, + TSource source) + where TSource : IPlanetaryBaseField + { + if (segmentCount < 1) throw new ArgumentOutOfRangeException(nameof(segmentCount)); + PlanetaryTopology.ValidateDirection(startDirection); PlanetaryTopology.ValidateDirection(endDirection); + var a = math.normalize(startDirection); var b = math.normalize(endDirection); + var angle = MathF.Acos(math.clamp(math.dot(a, b), -1, 1)); + var sinAngle = MathF.Sin(angle); + var result = new PlanetaryPathSample[segmentCount + 1]; + for (var i = 0; i <= segmentCount; i++) + { + var t = i / (float)segmentCount; + var direction = sinAngle < 1.0e-6f + ? math.normalize(math.lerp(a, b, t)) + : math.normalize(a * (MathF.Sin((1 - t) * angle) / sinAngle) + b * (MathF.Sin(t * angle) / sinAngle)); + var sample = PlanetaryField.Sample(field, direction, source.Sample(direction), scale); + result[i] = new(angle * field.Radius * t, sample); + } + return result; + } + + public static PlanetaryRegionSummary Summarize( + in PlanetaryFieldDefinition field, + ReadOnlySpan directions, + in PlanetaryQueryScale scale, + TSource source) + where TSource : IPlanetaryBaseField + { + if (directions.IsEmpty) throw new ArgumentException("At least one direction is required.", nameof(directions)); + var min = float.PositiveInfinity; var max = float.NegativeInfinity; var slope = 0.0f; var unresolved = 0.0f; + foreach (var direction in directions) + { + var normalized = math.normalize(direction); + var sample = PlanetaryField.Sample(field, normalized, source.Sample(normalized), scale); + min = MathF.Min(min, sample.RadialDisplacement); + max = MathF.Max(max, sample.RadialDisplacement); + slope = MathF.Max(slope, sample.Slope); + unresolved = MathF.Max(unresolved, sample.UnresolvedHeightBound); + } + return new(min, max, slope, unresolved); + } + + private static double SignedSurfaceDistance( + in PlanetaryFieldDefinition field, + double3 position, + in PlanetaryQueryScale scale, + TSource source, + out PlanetarySurfaceSample sample) + where TSource : IPlanetaryBaseField + { + var radius = Length(position); + if (radius < 1.0e-15) { sample = default; return double.NegativeInfinity; } + var direction = new float3((float)(position.x / radius), (float)(position.y / radius), (float)(position.z / radius)); + sample = PlanetaryField.Sample(field, direction, source.Sample(direction), scale); + return radius - sample.SurfaceRadius; + } + + private static bool TrySphereInterval(double3 origin, double3 direction, double radius, out double enter, out double leave) + { + var b = Dot(origin, direction); + var c = Dot(origin, origin) - radius * radius; + var discriminant = b * b - c; + if (discriminant < 0) { enter = leave = 0; return false; } + var root = Math.Sqrt(discriminant); + enter = -b - root; leave = -b + root; return leave >= 0; + } + + private static double Dot(double3 a, double3 b) => a.x * b.x + a.y * b.y + a.z * b.z; + private static double Length(double3 value) => Math.Sqrt(Dot(value, value)); + private static void ValidateFinite(double3 value, string name) + { + if (!double.IsFinite(value.x) || !double.IsFinite(value.y) || !double.IsFinite(value.z)) throw new ArgumentOutOfRangeException(name); + } +} diff --git a/src/CultMath/PlanetaryResidency.cs b/src/CultMath/PlanetaryResidency.cs new file mode 100644 index 00000000..e5dca115 --- /dev/null +++ b/src/CultMath/PlanetaryResidency.cs @@ -0,0 +1,144 @@ +namespace CultMath; + +public readonly record struct PlanetaryLodParameters( + int MaximumLevel, + int PageInteriorSize, + int PageBorderSize, + float ViewportHeightPixels, + float MinimumFootprintMeters) +{ + public PlanetaryLodParameters Validate() + { + if (MaximumLevel is < 0 or > PlanetaryTileAddress.MaxLevel) throw new ArgumentOutOfRangeException(nameof(MaximumLevel)); + _ = new PlanetaryPageLayout(new(PlanetaryCubeFace.PositiveX, 0, 0, 0), PageInteriorSize, PageBorderSize).Validate(); + if (!float.IsFinite(ViewportHeightPixels) || ViewportHeightPixels <= 0) throw new ArgumentOutOfRangeException(nameof(ViewportHeightPixels)); + if (!float.IsFinite(MinimumFootprintMeters) || MinimumFootprintMeters < 0) throw new ArgumentOutOfRangeException(nameof(MinimumFootprintMeters)); + return this; + } +} + +public static class PlanetaryLodSelector +{ + public static int SelectLevel( + in PlanetaryFieldDefinition field, + float cameraDistanceFromCenter, + in PlanetaryLodParameters parameters) + { + field.Validate(); parameters.Validate(); + if (!float.IsFinite(cameraDistanceFromCenter) || cameraDistanceFromCenter < 0) throw new ArgumentOutOfRangeException(nameof(cameraDistanceFromCenter)); + var altitude = MathF.Max(cameraDistanceFromCenter - field.Radius, 0.001f); + var footprint = MathF.Max(altitude / parameters.ViewportHeightPixels * 2, parameters.MinimumFootprintMeters); + var erosion = field.Erosion; + for (var level = 0; level <= parameters.MaximumLevel; level++) + { + var page = new PlanetaryPageLayout(new(PlanetaryCubeFace.PositiveX, level, 0, 0), parameters.PageInteriorSize, parameters.PageBorderSize); + var spacing = PlanetaryPageSampling.NominalAngularTexelSize(page) * field.Radius; + var unresolved = ErosionFrequencyBands.Select( + erosion.Scale * erosion.CellScale, spacing, erosion.Octaves, + erosion.Lacunarity, erosion.Strength * erosion.Scale, erosion.Gain).UnresolvedHeightBound; + if (unresolved <= footprint) return level; + } + return parameters.MaximumLevel; + } + + public static PlanetaryTileAddress[] SelectAncestorChain( + in PlanetaryFieldDefinition field, + float3 cameraDirection, + float cameraDistanceFromCenter, + in PlanetaryLodParameters parameters) + { + PlanetaryTopology.ValidateDirection(cameraDirection); + var level = SelectLevel(field, cameraDistanceFromCenter, parameters); + var result = new PlanetaryTileAddress[6 + level]; + for (var face = 0; face < 6; face++) result[face] = new((PlanetaryCubeFace)face, 0, 0, 0); + var leaf = PlanetaryTopology.TileAt(cameraDirection, level); + for (var currentLevel = level; currentLevel >= 1; currentLevel--) + { + result[6 + currentLevel - 1] = leaf; + leaf = leaf.Parent(); + } + return result; + } +} + +public readonly record struct PlanetaryResidentTile(PlanetaryTileAddress Tile, float Blend, bool Departing); + +public readonly record struct PlanetaryResidencySnapshot( + ulong ContentVersion, + ulong PresentationVersion, + PlanetaryResidentTile[] Tiles); + +/// Owns presentation residency only. It never owns field content. +public sealed class PlanetaryResidualResidency +{ + private readonly Dictionary residents = []; + private readonly Dictionary arrivals = []; + private readonly Dictionary departures = []; + private float lastTime = float.NegativeInfinity; + + public void Reset() + { + residents.Clear(); arrivals.Clear(); departures.Clear(); lastTime = float.NegativeInfinity; + } + + public PlanetaryResidencySnapshot Update(ReadOnlySpan desired, float timeSeconds, float transitionSeconds) + { + if (!float.IsFinite(timeSeconds)) throw new ArgumentOutOfRangeException(nameof(timeSeconds)); + if (!float.IsFinite(transitionSeconds) || transitionSeconds < 0) throw new ArgumentOutOfRangeException(nameof(transitionSeconds)); + if (timeSeconds < lastTime) Reset(); + lastTime = timeSeconds; + + var desiredKeys = new HashSet(); + foreach (var tile in desired) + { + var key = tile.StableKey; + desiredKeys.Add(key); + residents[key] = tile; + if (!arrivals.ContainsKey(key)) arrivals[key] = timeSeconds; + departures.Remove(key); + } + + foreach (var pair in residents.ToArray()) + { + if (pair.Value.Level == 0 || desiredKeys.Contains(pair.Key)) continue; + if (!departures.ContainsKey(pair.Key)) + { + var startingBlend = transitionSeconds == 0 + ? 1 + : Math.Clamp((timeSeconds - arrivals[pair.Key]) / transitionSeconds, 0, 1); + departures[pair.Key] = (timeSeconds, startingBlend); + } + if (transitionSeconds > 0 && timeSeconds - departures[pair.Key].Time < transitionSeconds) continue; + residents.Remove(pair.Key); arrivals.Remove(pair.Key); departures.Remove(pair.Key); + } + + var ordered = residents + .OrderBy(pair => pair.Value.Level) + .ThenBy(pair => pair.Value.Face) + .ThenBy(pair => pair.Value.X) + .ThenBy(pair => pair.Value.Y) + .ToArray(); + var tiles = new PlanetaryResidentTile[ordered.Length]; + for (var i = 0; i < ordered.Length; i++) + { + var pair = ordered[i]; + var departing = departures.TryGetValue(pair.Key, out var departure); + var blend = pair.Value.Level == 0 || transitionSeconds == 0 + ? 1 + : departing + ? departure.StartingBlend * Math.Clamp(1 - (timeSeconds - departure.Time) / transitionSeconds, 0, 1) + : Math.Clamp((timeSeconds - arrivals[pair.Key]) / transitionSeconds, 0, 1); + tiles[i] = new(pair.Value, blend, departing); + } + return new(Hash(ordered.Select(pair => pair.Key)), Hash(tiles.Select(tile => tile.Tile.StableKey ^ (uint)BitConverter.SingleToInt32Bits(tile.Blend))), tiles); + } + + private static ulong Hash(IEnumerable values) + { + const ulong offset = 14695981039346656037UL; + const ulong prime = 1099511628211UL; + var hash = offset; + foreach (var value in values) hash = unchecked((hash ^ value) * prime); + return hash == 0 ? 1 : hash; + } +} diff --git a/src/CultMath/PlanetaryTopology.cs b/src/CultMath/PlanetaryTopology.cs new file mode 100644 index 00000000..c8535079 --- /dev/null +++ b/src/CultMath/PlanetaryTopology.cs @@ -0,0 +1,170 @@ +namespace CultMath; + +public enum PlanetaryCubeFace +{ + PositiveX, + NegativeX, + PositiveY, + NegativeY, + PositiveZ, + NegativeZ, +} + +public readonly record struct PlanetaryFaceCoordinate(PlanetaryCubeFace Face, double U, double V) +{ + public PlanetaryFaceCoordinate Validate(bool allowOutsideFace = false) + { + if (!double.IsFinite(U) || !double.IsFinite(V)) throw new ArgumentOutOfRangeException(nameof(U)); + if (!allowOutsideFace && (U is < -1.0 or > 1.0 || V is < -1.0 or > 1.0)) + throw new ArgumentOutOfRangeException(nameof(U), "Face coordinates must be in [-1, 1]."); + if (!Enum.IsDefined(typeof(PlanetaryCubeFace), Face)) throw new ArgumentOutOfRangeException(nameof(Face)); + return this; + } +} + +public readonly record struct PlanetaryTileAddress +{ + public const int MaxLevel = 30; + + public PlanetaryTileAddress(PlanetaryCubeFace face, int level, int x, int y) + { + if (!Enum.IsDefined(typeof(PlanetaryCubeFace), face)) throw new ArgumentOutOfRangeException(nameof(face)); + if (level is < 0 or > MaxLevel) throw new ArgumentOutOfRangeException(nameof(level)); + var count = 1 << level; + if ((uint)x >= (uint)count) throw new ArgumentOutOfRangeException(nameof(x)); + if ((uint)y >= (uint)count) throw new ArgumentOutOfRangeException(nameof(y)); + Face = face; + Level = level; + X = x; + Y = y; + } + + public PlanetaryCubeFace Face { get; } + public int Level { get; } + public int X { get; } + public int Y { get; } + public int AxisTileCount => 1 << Level; + + public PlanetaryTileAddress Parent() => Level == 0 + ? throw new InvalidOperationException("Root cube tile has no parent.") + : new(Face, Level - 1, X >> 1, Y >> 1); + + public PlanetaryTileAddress Child(int childX, int childY) + { + if ((uint)childX > 1) throw new ArgumentOutOfRangeException(nameof(childX)); + if ((uint)childY > 1) throw new ArgumentOutOfRangeException(nameof(childY)); + if (Level == MaxLevel) throw new InvalidOperationException($"Level {MaxLevel} cannot be subdivided."); + return new(Face, Level + 1, (X << 1) | childX, (Y << 1) | childY); + } + + public PlanetaryFaceCoordinate PositionAt(double localU, double localV) + { + if (!double.IsFinite(localU) || localU is < 0.0 or > 1.0) throw new ArgumentOutOfRangeException(nameof(localU)); + if (!double.IsFinite(localV) || localV is < 0.0 or > 1.0) throw new ArgumentOutOfRangeException(nameof(localV)); + var count = AxisTileCount; + return new(Face, -1.0 + 2.0 * (X + localU) / count, -1.0 + 2.0 * (Y + localV) / count); + } + + public ulong StableKey + { + get + { + const ulong offset = 14695981039346656037UL; + const ulong prime = 1099511628211UL; + var hash = offset; + hash = unchecked((hash ^ (uint)Face) * prime); + hash = unchecked((hash ^ (uint)Level) * prime); + hash = unchecked((hash ^ (uint)X) * prime); + hash = unchecked((hash ^ (uint)Y) * prime); + return hash == 0 ? 1 : hash; + } + } + public override string ToString() => $"{Face}/L{Level:D2}/{X}/{Y}"; +} + +public static class PlanetaryTopology +{ + private const float QuarterPi = MathF.PI * 0.25f; + + public static float3 Direction(PlanetaryFaceCoordinate coordinate) + { + coordinate.Validate(allowOutsideFace: true); + var u = MathF.Tan((float)coordinate.U * QuarterPi); + var v = MathF.Tan((float)coordinate.V * QuarterPi); + var cube = coordinate.Face switch + { + PlanetaryCubeFace.PositiveX => new float3(1, v, -u), + PlanetaryCubeFace.NegativeX => new float3(-1, v, u), + PlanetaryCubeFace.PositiveY => new float3(u, 1, -v), + PlanetaryCubeFace.NegativeY => new float3(u, -1, v), + PlanetaryCubeFace.PositiveZ => new float3(u, v, 1), + PlanetaryCubeFace.NegativeZ => new float3(-u, v, -1), + _ => throw new ArgumentOutOfRangeException(nameof(coordinate)), + }; + return math.normalize(cube); + } + + public static PlanetaryFaceCoordinate FaceCoordinate(float3 direction) + { + ValidateDirection(direction); + var d = math.normalize(direction); + var a = math.abs(d); + if (a.x >= a.y && a.x >= a.z) + return d.x >= 0 + ? FromCubeUv(PlanetaryCubeFace.PositiveX, -d.z / a.x, d.y / a.x) + : FromCubeUv(PlanetaryCubeFace.NegativeX, d.z / a.x, d.y / a.x); + if (a.y >= a.z) + return d.y >= 0 + ? FromCubeUv(PlanetaryCubeFace.PositiveY, d.x / a.y, -d.z / a.y) + : FromCubeUv(PlanetaryCubeFace.NegativeY, d.x / a.y, d.z / a.y); + return d.z >= 0 + ? FromCubeUv(PlanetaryCubeFace.PositiveZ, d.x / a.z, d.y / a.z) + : FromCubeUv(PlanetaryCubeFace.NegativeZ, -d.x / a.z, d.y / a.z); + } + + public static PlanetaryTileAddress TileAt(float3 direction, int level) + { + if (level is < 0 or > PlanetaryTileAddress.MaxLevel) throw new ArgumentOutOfRangeException(nameof(level)); + var face = FaceCoordinate(direction); + var count = 1 << level; + var x = Math.Clamp((int)((face.U * 0.5 + 0.5) * count), 0, count - 1); + var y = Math.Clamp((int)((face.V * 0.5 + 0.5) * count), 0, count - 1); + return new(face.Face, level, x, y); + } + + public static bool TryLocalCoordinate(float3 direction, PlanetaryTileAddress tile, out float2 local) + { + var face = FaceCoordinate(direction); + if (face.Face != tile.Face) { local = float2.zero; return false; } + var scaledU = (face.U * 0.5 + 0.5) * tile.AxisTileCount; + var scaledV = (face.V * 0.5 + 0.5) * tile.AxisTileCount; + local = new((float)(scaledU - tile.X), (float)(scaledV - tile.Y)); + return local.x is >= 0 and <= 1 && local.y is >= 0 and <= 1; + } + + public static float3 SurfaceNormal(float3 unitDirection, float3 worldDistanceTangentGradient) + { + ValidateDirection(unitDirection); + ValidateFinite(worldDistanceTangentGradient, nameof(worldDistanceTangentGradient)); + var direction = math.normalize(unitDirection); + var tangent = worldDistanceTangentGradient - direction * math.dot(worldDistanceTangentGradient, direction); + return math.normalize(direction - tangent); + } + + private static PlanetaryFaceCoordinate FromCubeUv(PlanetaryCubeFace face, float cubeU, float cubeV) => new( + face, + MathF.Atan(cubeU) / QuarterPi, + MathF.Atan(cubeV) / QuarterPi); + + internal static void ValidateDirection(float3 direction) + { + ValidateFinite(direction, nameof(direction)); + if (math.length(direction) < 1.0e-12f) throw new ArgumentOutOfRangeException(nameof(direction)); + } + + internal static void ValidateFinite(float3 value, string name) + { + if (!float.IsFinite(value.x) || !float.IsFinite(value.y) || !float.IsFinite(value.z)) + throw new ArgumentOutOfRangeException(name); + } +} diff --git a/tests/CultMath.Tests/HlslMirrorTests.cs b/tests/CultMath.Tests/HlslMirrorTests.cs index 0e904a32..567b038b 100644 --- a/tests/CultMath.Tests/HlslMirrorTests.cs +++ b/tests/CultMath.Tests/HlslMirrorTests.cs @@ -65,6 +65,22 @@ public sealed class HlslMirrorTests Assert.Contains("max(length(value), CULTMATH_NORMALIZE_EPSILON)", include); } + [Fact] + public void HlslMirrorPublishesPlanetaryTopologyAndField() + { + var root = GetRepositoryRoot(); + var include = File.ReadAllText(Path.Combine(root, "shaders", "CultMath.hlsl")); + var planetary = File.ReadAllText(Path.Combine(root, "shaders", "Planetary.hlsl")); + Assert.Contains("Planetary.hlsl", include); + Assert.Contains("cultmath_planetary_face_direction", planetary); + Assert.Contains("cultmath_planetary_face_coordinate", planetary); + Assert.Contains("cultmath_planetary_page_local", planetary); + Assert.Contains("cultmath_planetary_field_sample", planetary); + Assert.Contains("cultmath_planetary_equirectangular_forward", planetary); + Assert.Contains("cultmath_planetary_equal_earth_forward", planetary); + Assert.Contains("CultMathPlanetarySurfaceSample", planetary); + } + private static string GetRepositoryRoot() { var directory = new DirectoryInfo(AppContext.BaseDirectory); diff --git a/tests/CultMath.Tests/PlanetaryFieldTests.cs b/tests/CultMath.Tests/PlanetaryFieldTests.cs new file mode 100644 index 00000000..4dc75325 --- /dev/null +++ b/tests/CultMath.Tests/PlanetaryFieldTests.cs @@ -0,0 +1,80 @@ +using Xunit; + +namespace CultMath.Tests; + +public sealed class PlanetaryFieldTests +{ + private static readonly PlanetaryFieldDefinition Definition = new( + 0x7f59_6d11_02ab_9c31UL, + 8.4f, + 42, + AdvancedErosionParameters.Default with { Scale = 0.63f, Strength = 0.12f, Octaves = 7 }); + + [Fact] + public void SampleIsDeterministicScaleAwareAndTangent() + { + var direction = math.normalize(new float3(0.31f, -0.72f, 0.61f)); + var source = new FixtureField(); + var coarse = PlanetaryField.Sample(Definition, direction, source.Sample(direction), PlanetaryQueryScale.AtFootprint(0.1f)); + var fine = PlanetaryField.Sample(Definition, direction, source.Sample(direction), PlanetaryQueryScale.AtFootprint(0.01f)); + var repeated = PlanetaryField.Sample(Definition, direction, source.Sample(direction), PlanetaryQueryScale.AtFootprint(0.01f)); + + Assert.Equal(fine, repeated); + Assert.Equal(Definition.FieldVersion, fine.FieldVersion); + Assert.True(fine.UnresolvedHeightBound <= coarse.UnresolvedHeightBound); + Assert.True(fine.FinestResolvedWavelength <= coarse.FinestResolvedWavelength); + Assert.InRange(MathF.Abs(math.dot(fine.UnitDirection, fine.TangentGradient)), 0, 2.0e-5f); + Assert.Equal(1, math.length(fine.SurfaceNormal), 5); + } + + [Fact] + public void BatchAndDoublePositionUseThePointContract() + { + var directions = new[] + { + math.normalize(new float3(1, 2, 3)), + math.normalize(new float3(-2, 0.5f, 1)), + math.normalize(new float3(0.1f, -0.2f, -1)), + }; + var output = new PlanetarySurfaceSample[directions.Length]; + var source = new FixtureField(); + var scale = PlanetaryQueryScale.AtFootprint(0.05f); + PlanetaryField.SampleBatch(Definition, directions, scale, source, output); + + for (var i = 0; i < directions.Length; i++) + { + var normalized = math.normalize(directions[i]); + var expected = PlanetaryField.Sample(Definition, normalized, source.Sample(normalized), scale); + Assert.InRange(MathF.Abs(expected.RadialDisplacement - output[i].RadialDisplacement), 0, 1.0e-6f); + Assert.InRange(math.distance(expected.TangentGradient, output[i].TangentGradient), 0, 1.0e-6f); + } + + var d = directions[0]; + var position = new double3(d.x * 8.0e11, d.y * 8.0e11, d.z * 8.0e11); + var positioned = PlanetaryField.SamplePosition(Definition, position, scale, source); + Assert.InRange(math.distance(positioned.UnitDirection, d), 0, 2.0e-6f); + } + + [Fact] + public void FieldIdentityChangesWithEveryLoadBearingInput() + { + var erosion = AdvancedErosionParameters.Default; + var baseline = PlanetaryFieldDefinition.Create(3, 8.4f, 7, erosion); + Assert.Equal(baseline.FieldVersion, PlanetaryFieldDefinition.Create(3, 8.4f, 7, erosion).FieldVersion); + Assert.NotEqual(baseline.FieldVersion, PlanetaryFieldDefinition.Create(4, 8.4f, 7, erosion).FieldVersion); + Assert.NotEqual(baseline.FieldVersion, PlanetaryFieldDefinition.Create(3, 8.5f, 7, erosion).FieldVersion); + Assert.NotEqual(baseline.FieldVersion, PlanetaryFieldDefinition.Create(3, 8.4f, 8, erosion).FieldVersion); + Assert.NotEqual(baseline.FieldVersion, PlanetaryFieldDefinition.Create(3, 8.4f, 7, erosion with { Gain = 0.49f }).FieldVersion); + } + + private readonly struct FixtureField : IPlanetaryBaseField + { + public PlanetaryBaseFieldSample Sample(float3 direction) + { + var value = direction.x * 0.6f + direction.y * direction.z * 0.3f; + var fieldGradient = new float3(0.6f, direction.z * 0.3f, direction.y * 0.3f); + fieldGradient -= direction * math.dot(fieldGradient, direction); + return new(value * 0.1f, fieldGradient * 0.1f, value, fieldGradient, math.clamp(value, -1, 1)); + } + } +} diff --git a/tests/CultMath.Tests/PlanetaryPageTests.cs b/tests/CultMath.Tests/PlanetaryPageTests.cs new file mode 100644 index 00000000..c4e4045b --- /dev/null +++ b/tests/CultMath.Tests/PlanetaryPageTests.cs @@ -0,0 +1,57 @@ +using Xunit; + +namespace CultMath.Tests; + +public sealed class PlanetaryPageTests +{ + [Fact] + public void BilinearSamplingAndSummaryUseOnePageContract() + { + var layout = new PlanetaryPageLayout(new(PlanetaryCubeFace.PositiveZ, 0, 0, 0), 3, 1); + var samples = new PlanetaryPageSample[layout.StorageSize * layout.StorageSize]; + for (var y = 0; y < layout.StorageSize; y++) + for (var x = 0; x < layout.StorageSize; x++) + samples[y * layout.StorageSize + x] = new(x + y * 10, new float3(x, y, 0), x / 10.0f, y / 10.0f); + + var sample = PlanetaryPageSampling.Bilinear(samples, layout, new float2(0.25f, 0.75f)); + Assert.Equal(26.5f, sample.Height, 4); + Assert.Equal(new float3(1.5f, 2.5f, 0), sample.TangentGradient); + var summary = PlanetaryPageSampling.Summarize(samples, layout, 0.125f); + Assert.Equal(0, summary.MinimumHeight); + Assert.Equal(44, summary.MaximumHeight); + Assert.Equal(0.125f, summary.UnresolvedHeightBound); + Assert.True(summary.MaximumSlope > 0); + } + + [Fact] + public void ChildPageStoresOnlyResidualAndComposesBackToDirectField() + { + var field = new PlanetaryFieldDefinition(7, 8.4f, 3, AdvancedErosionParameters.Default with + { + Scale = 0.63f, + Strength = 0.12f, + Octaves = 7, + }); + var source = new FixtureField(); + var root = PlanetaryPageBaker.Bake(field, new(new(PlanetaryCubeFace.PositiveZ, 0, 0, 0), 17, 2), source); + var child = PlanetaryPageBaker.Bake(field, new(new(PlanetaryCubeFace.PositiveZ, 1, 1, 0), 17, 2), source); + var direction = PlanetaryPageSampling.DirectionAtLocal(child.Layout, 0.5, 0.5); + var pages = new[] { new PlanetaryResidentPage(root, 1), new PlanetaryResidentPage(child, 1) }; + Assert.True(PlanetaryPageSetSampling.TrySample(pages, direction, out var composed)); + var spacing = PlanetaryPageSampling.NominalAngularTexelSize(child.Layout) * field.Radius; + var direct = PlanetaryField.Sample(field, direction, source.Sample(direction), PlanetaryQueryScale.AtFootprint(spacing)); + Assert.InRange(MathF.Abs(composed.Height - direct.RadialDisplacement), 0, 2.0e-5f); + Assert.InRange(math.distance(composed.TangentGradient, direct.TangentGradient), 0, 3.0e-5f); + } + + private readonly struct FixtureField : IPlanetaryBaseField + { + public PlanetaryBaseFieldSample Sample(float3 direction) + { + var value = direction.x * 0.4f - direction.y * 0.2f + direction.z * 0.5f; + var gradient = new float3(0.4f, -0.2f, 0.5f); + gradient -= direction * math.dot(gradient, direction); + return new(value * 0.08f, gradient * 0.08f, value, gradient, value); + } + } +} diff --git a/tests/CultMath.Tests/PlanetaryPatchTests.cs b/tests/CultMath.Tests/PlanetaryPatchTests.cs new file mode 100644 index 00000000..6564c773 --- /dev/null +++ b/tests/CultMath.Tests/PlanetaryPatchTests.cs @@ -0,0 +1,40 @@ +using Xunit; + +namespace CultMath.Tests; + +public sealed class PlanetaryPatchTests +{ + [Fact] + public void CubeSpherePatchMeshUsesCanonicalTopology() + { + var meshes = PlanetaryPatch.CreateCubeSphere(8); + Assert.Equal(6, meshes.Length); + foreach (var mesh in meshes) + { + Assert.Equal(81, mesh.Vertices.Length); + Assert.Equal(8 * 8 * 6, mesh.Indices.Length); + Assert.All(mesh.Vertices, vertex => Assert.Equal(1, math.length(vertex.UnitDirection), 5)); + foreach (var index in mesh.Indices) Assert.InRange(index, 0, mesh.Vertices.Length - 1); + } + } + + [Fact] + public void NeighborFaceCornersAreSingleValued() + { + var directions = PlanetaryPatch.CreateCubeSphere(1) + .SelectMany(mesh => mesh.Vertices.Select(vertex => vertex.UnitDirection)) + .ToArray(); + var groups = directions.GroupBy(direction => new + { + X = Math.Sign(direction.x), + Y = Math.Sign(direction.y), + Z = Math.Sign(direction.z), + }); + Assert.Equal(8, groups.Count()); + Assert.All(groups, group => + { + var first = group.First(); + Assert.All(group, direction => Assert.InRange(math.distance(first, direction), 0, 1.0e-6f)); + }); + } +} diff --git a/tests/CultMath.Tests/PlanetaryProjectionTests.cs b/tests/CultMath.Tests/PlanetaryProjectionTests.cs new file mode 100644 index 00000000..ad811d6e --- /dev/null +++ b/tests/CultMath.Tests/PlanetaryProjectionTests.cs @@ -0,0 +1,73 @@ +using Xunit; + +namespace CultMath.Tests; + +public sealed class PlanetaryProjectionTests +{ + [Theory] + [InlineData(PlanetaryProjectionKind.Equirectangular)] + [InlineData(PlanetaryProjectionKind.WebMercator)] + [InlineData(PlanetaryProjectionKind.EqualEarth)] + [InlineData(PlanetaryProjectionKind.Orthographic)] + [InlineData(PlanetaryProjectionKind.AzimuthalEquidistant)] + [InlineData(PlanetaryProjectionKind.AzimuthalEqualArea)] + [InlineData(PlanetaryProjectionKind.LocalTangent)] + public void ProjectionRoundTripsVisibleDirections(PlanetaryProjectionKind kind) + { + var parameters = new PlanetaryProjectionParameters(kind, 0.31, -0.22); + foreach (var longitude in new[] { -0.4, -0.1, 0.2, 0.65 }) + foreach (var latitude in new[] { -0.6, -0.15, 0.3, 0.7 }) + { + var direction = Direction(longitude + parameters.CenterLongitude, latitude); + if (!PlanetaryProjection.TryForward(direction, parameters, out var map)) continue; + Assert.True(PlanetaryProjection.TryInverse(map, parameters, out var roundTrip)); + Assert.InRange(math.distance(direction, roundTrip), 0, 3.0e-5f); + } + } + + [Fact] + public void CubeAtlasRoundTripsEveryFaceInterior() + { + var projection = new PlanetaryProjectionParameters(PlanetaryProjectionKind.CubeAtlas); + foreach (var face in Enum.GetValues()) + { + var direction = PlanetaryTopology.Direction(new(face, 0.23, -0.41)); + Assert.True(PlanetaryProjection.TryForward(direction, projection, out var map)); + Assert.True(PlanetaryProjection.TryInverse(map, projection, out var roundTrip)); + Assert.InRange(math.distance(direction, roundTrip), 0, 2.0e-6f); + } + } + + [Fact] + public void MercatorRejectsPolarSingularity() + { + var northPole = new float3(0, 0, 1); + Assert.False(PlanetaryProjection.TryForward(northPole, new(PlanetaryProjectionKind.WebMercator), out _)); + } + + [Fact] + public void MapTileBakerCarriesFieldIdentityAndProjectionValidity() + { + var field = new PlanetaryFieldDefinition(99, 10, 0, AdvancedErosionParameters.Default); + var layout = new PlanetaryMapTileLayout( + new(PlanetaryProjectionKind.Orthographic), 0, 0, 0, 9, 1); + var key = new PlanetaryMapTileKey(field.FieldVersion, 1, 7, layout, PlanetaryQueryScale.AtFootprint(0.1f)); + var tile = PlanetaryMapTileBaker.Bake(field, key, new FlatField()); + Assert.Equal(key, tile.Key); + Assert.Equal(layout.StorageSize * layout.StorageSize, tile.Samples.Length); + Assert.Contains(tile.Validity, valid => valid); + Assert.Contains(tile.Validity, valid => !valid); + Assert.All(tile.Samples.Where((_, index) => tile.Validity[index]), sample => Assert.Equal(field.FieldVersion, sample.FieldVersion)); + } + + private static float3 Direction(double longitude, double latitude) + { + var cos = Math.Cos(latitude); + return new((float)(cos * Math.Cos(longitude)), (float)(cos * Math.Sin(longitude)), (float)Math.Sin(latitude)); + } + + private readonly struct FlatField : IPlanetaryBaseField + { + public PlanetaryBaseFieldSample Sample(float3 unitDirection) => new(0, float3.zero, 0, float3.zero, 0); + } +} diff --git a/tests/CultMath.Tests/PlanetaryQueryTests.cs b/tests/CultMath.Tests/PlanetaryQueryTests.cs new file mode 100644 index 00000000..48d865f4 --- /dev/null +++ b/tests/CultMath.Tests/PlanetaryQueryTests.cs @@ -0,0 +1,46 @@ +using Xunit; + +namespace CultMath.Tests; + +public sealed class PlanetaryQueryTests +{ + private static readonly PlanetaryFieldDefinition Field = new(12, 10, 0, AdvancedErosionParameters.Default with { Strength = 0, Octaves = 0 }); + private static readonly PlanetaryQueryScale Scale = PlanetaryQueryScale.AtFootprint(0.1f, 0); + + [Fact] + public void RayIntersectionAndClearanceUseTheCpuSurfaceContract() + { + var source = new BulgedSphere(); + Assert.True(PlanetaryQueries.TryIntersectRay( + Field, new double3(0, 0, 20), new double3(0, 0, -1), 30, + Scale, new PlanetaryRadialBounds(-1, 1), source, out var hit)); + Assert.InRange(hit.Distance, 8.99999, 9.00001); + Assert.InRange(hit.PlanetLocalPosition.z, 10.99999, 11.00001); + var clearance = PlanetaryQueries.SegmentClearance( + Field, new double3(-2, 0, 12), new double3(2, 0, 12), 0.1, Scale, source); + Assert.True(clearance > 0.8); + } + + [Fact] + public void GreatCircleAndRegionQueriesReturnVersionedSamples() + { + var source = new BulgedSphere(); + var path = PlanetaryQueries.SampleGreatCircle(Field, new float3(1, 0, 0), new float3(0, 1, 0), 8, Scale, source); + Assert.Equal(9, path.Length); + Assert.Equal(MathF.PI * 5, path[^1].Distance, 4); + Assert.All(path, point => Assert.Equal(Field.FieldVersion, point.Surface.FieldVersion)); + var summary = PlanetaryQueries.Summarize(Field, path.Select(point => point.Surface.UnitDirection).ToArray(), Scale, source); + Assert.True(summary.MaximumDisplacement >= summary.MinimumDisplacement); + Assert.True(summary.MaximumSlope >= 0); + } + + private readonly struct BulgedSphere : IPlanetaryBaseField + { + public PlanetaryBaseFieldSample Sample(float3 direction) + { + var displacement = direction.z; + var gradient = new float3(0, 0, 1) - direction * direction.z; + return new(displacement, gradient, 0, float3.zero, 0); + } + } +} diff --git a/tests/CultMath.Tests/PlanetaryResidencyTests.cs b/tests/CultMath.Tests/PlanetaryResidencyTests.cs new file mode 100644 index 00000000..d2b89b7a --- /dev/null +++ b/tests/CultMath.Tests/PlanetaryResidencyTests.cs @@ -0,0 +1,57 @@ +using Xunit; + +namespace CultMath.Tests; + +public sealed class PlanetaryResidencyTests +{ + private static readonly PlanetaryFieldDefinition Field = new( + 1, 8.4f, 0, AdvancedErosionParameters.Default with { Scale = 0.63f, Strength = 0.12f, Octaves = 7 }); + private static readonly PlanetaryLodParameters Lod = new(5, 17, 2, 720, 8.4f / 65536); + + [Fact] + public void SelectorReturnsSixRootsAndOneAncestorChain() + { + var direction = math.normalize(new float3(-0.2f, 0.91f, 0.37f)); + var selected = PlanetaryLodSelector.SelectAncestorChain(Field, direction, 8.45f, Lod); + Assert.Equal(6, selected.Count(tile => tile.Level == 0)); + var descendants = selected.Where(tile => tile.Level > 0).OrderBy(tile => tile.Level).ToArray(); + for (var i = 1; i < descendants.Length; i++) Assert.Equal(descendants[i - 1], descendants[i].Parent()); + if (descendants.Length > 0) Assert.Equal(PlanetaryTopology.TileAt(direction, descendants[^1].Level), descendants[^1]); + } + + [Fact] + public void ResidencyFadesResidualsWithoutChangingContentDuringPresentation() + { + var root = new PlanetaryTileAddress(PlanetaryCubeFace.PositiveX, 0, 0, 0); + var child = root.Child(1, 0); + var residency = new PlanetaryResidualResidency(); + var arrival = residency.Update(new[] { root, child }, 0, 1); + var midpoint = residency.Update(new[] { root, child }, 0.5f, 1); + var settled = residency.Update(new[] { root, child }, 1, 1); + Assert.Equal(arrival.ContentVersion, midpoint.ContentVersion); + Assert.Equal(midpoint.ContentVersion, settled.ContentVersion); + Assert.Equal(0, arrival.Tiles.Single(tile => tile.Tile == child).Blend); + Assert.Equal(0.5f, midpoint.Tiles.Single(tile => tile.Tile == child).Blend); + Assert.Equal(1, settled.Tiles.Single(tile => tile.Tile == child).Blend); + + var leaving = residency.Update(new[] { root }, 1.25f, 1); + Assert.True(leaving.Tiles.Single(tile => tile.Tile == child).Departing); + Assert.Equal(1, leaving.Tiles.Single(tile => tile.Tile == child).Blend); + var gone = residency.Update(new[] { root }, 2.25f, 1); + Assert.DoesNotContain(gone.Tiles, tile => tile.Tile == child); + } + + [Fact] + public void ReversingAnArrivalDepartsFromItsCurrentWeightWithoutJumping() + { + var root = new PlanetaryTileAddress(PlanetaryCubeFace.PositiveX, 0, 0, 0); + var child = root.Child(0, 1); + var residency = new PlanetaryResidualResidency(); + _ = residency.Update(new[] { root, child }, 0, 1); + var arriving = residency.Update(new[] { root, child }, 0.25f, 1); + var departing = residency.Update(new[] { root }, 0.25f, 1); + Assert.Equal(0.25f, arriving.Tiles.Single(tile => tile.Tile == child).Blend); + Assert.Equal(0.25f, departing.Tiles.Single(tile => tile.Tile == child).Blend); + Assert.True(departing.Tiles.Single(tile => tile.Tile == child).Departing); + } +} diff --git a/tests/CultMath.Tests/PlanetaryTopologyTests.cs b/tests/CultMath.Tests/PlanetaryTopologyTests.cs new file mode 100644 index 00000000..6e6b0838 --- /dev/null +++ b/tests/CultMath.Tests/PlanetaryTopologyTests.cs @@ -0,0 +1,55 @@ +using Xunit; + +namespace CultMath.Tests; + +public sealed class PlanetaryTopologyTests +{ + [Fact] + public void FaceDirectionRoundTripsAcrossEveryFace() + { + foreach (var face in Enum.GetValues()) + foreach (var u in new[] { -0.9, -0.25, 0.0, 0.4, 0.9 }) + foreach (var v in new[] { -0.85, -0.1, 0.3, 0.88 }) + { + var direction = PlanetaryTopology.Direction(new(face, u, v)); + var roundTrip = PlanetaryTopology.FaceCoordinate(direction); + Assert.Equal(face, roundTrip.Face); + Assert.Equal(u, roundTrip.U, 5); + Assert.Equal(v, roundTrip.V, 5); + } + } + + [Fact] + public void SiblingPagesShareBitStableBoundaryDirections() + { + var left = new PlanetaryPageLayout(new(PlanetaryCubeFace.PositiveZ, 1, 0, 0), 17, 2); + var right = new PlanetaryPageLayout(new(PlanetaryCubeFace.PositiveZ, 1, 1, 0), 17, 2); + for (var y = 0; y < left.InteriorSize; y++) + { + var a = PlanetaryPageSampling.Direction(left, left.BorderSize + left.InteriorSize - 1, left.BorderSize + y); + var b = PlanetaryPageSampling.Direction(right, right.BorderSize, right.BorderSize + y); + Assert.Equal(a, b); + } + } + + [Fact] + public void DirectionSelectsContainingTileAndLocalCoordinate() + { + var expected = new PlanetaryTileAddress(PlanetaryCubeFace.NegativeY, 5, 19, 7); + var direction = PlanetaryPageSampling.DirectionAtLocal(new(expected, 17, 2), 0.37, 0.61); + Assert.Equal(expected, PlanetaryTopology.TileAt(direction, expected.Level)); + Assert.True(PlanetaryTopology.TryLocalCoordinate(direction, expected, out var local)); + Assert.Equal(0.37f, local.x, 4); + Assert.Equal(0.61f, local.y, 4); + } + + [Fact] + public void BorderSamplesDoNotRequireNeighborResidency() + { + var page = new PlanetaryPageLayout(new(PlanetaryCubeFace.PositiveX, 0, 0, 0), 17, 3); + var edge = PlanetaryPageSampling.Direction(page, page.BorderSize + page.InteriorSize - 1, page.BorderSize + 8); + var border = PlanetaryPageSampling.Direction(page, page.StorageSize - 1, page.BorderSize + 8); + Assert.NotEqual(edge, border); + Assert.Equal(1, math.length(border), 5); + } +} diff --git a/unity/Runtime/CultMath.Unity.asmdef b/unity/Runtime/CultMath.Unity.asmdef new file mode 100644 index 00000000..632c4e4c --- /dev/null +++ b/unity/Runtime/CultMath.Unity.asmdef @@ -0,0 +1,16 @@ +{ + "name": "CultMath.Unity", + "rootNamespace": "CultMath.Unity", + "references": [ + "CultMath" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} diff --git a/unity/Runtime/PlanetaryPageUpload.cs b/unity/Runtime/PlanetaryPageUpload.cs new file mode 100644 index 00000000..f0b168cd --- /dev/null +++ b/unity/Runtime/PlanetaryPageUpload.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using UnityEngine; + +namespace CultMath.Unity; + +[StructLayout(LayoutKind.Sequential)] +public readonly struct PlanetaryPageInputGpu +{ + public PlanetaryPageInputGpu(Vector4 directionRadius, Vector4 sampling) + { + DirectionRadius = directionRadius; + Sampling = sampling; + } + + public readonly Vector4 DirectionRadius; + public readonly Vector4 Sampling; +} + +[StructLayout(LayoutKind.Sequential)] +public readonly struct PlanetaryPageMetadataGpu +{ + public PlanetaryPageMetadataGpu(Vector4 address, Vector4 layout, Vector4 bounds, Vector4 state) + { + Address = address; + Layout = layout; + Bounds = bounds; + State = state; + } + + public readonly Vector4 Address; + public readonly Vector4 Layout; + public readonly Vector4 Bounds; + public readonly Vector4 State; +} + +public readonly record struct PlanetaryPageUpload( + PlanetaryPageInputGpu[] Inputs, + PlanetaryPageMetadataGpu[] Metadata, + int OutputSampleCount, + ulong ContentVersion, + ulong PresentationVersion); + +public static class PlanetaryPageUploadBuilder +{ + public static PlanetaryPageUpload Build( + in PlanetaryResidencySnapshot snapshot, + int interiorSize, + int borderSize, + float radius) + { + if (!float.IsFinite(radius) || radius <= 0) throw new ArgumentOutOfRangeException(nameof(radius)); + var inputs = new List(); + var metadata = new PlanetaryPageMetadataGpu[snapshot.Tiles.Length]; + foreach (var (resident, pageIndex) in snapshot.Tiles.Select((resident, index) => (resident, index))) + { + var layout = new PlanetaryPageLayout(resident.Tile, interiorSize, borderSize).Validate(); + var spacing = PlanetaryPageSampling.NominalAngularTexelSize(layout) * radius; + var parentSpacing = resident.Tile.Level == 0 + ? 0 + : PlanetaryPageSampling.NominalAngularTexelSize(new(resident.Tile.Parent(), interiorSize, borderSize)) * radius; + var outputOffset = inputs.Count; + for (var y = 0; y < layout.StorageSize; y++) + for (var x = 0; x < layout.StorageSize; x++) + { + var direction = PlanetaryPageSampling.Direction(layout, x, y); + inputs.Add(new( + new Vector4(direction.x, direction.y, direction.z, radius), + new Vector4(spacing, parentSpacing, 0, 0))); + } + metadata[pageIndex] = new( + new Vector4((int)resident.Tile.Face, resident.Tile.Level, resident.Tile.X, resident.Tile.Y), + new Vector4(outputOffset, layout.StorageSize, layout.InteriorSize, layout.BorderSize), + Vector4.zero, + new Vector4(1, resident.Blend, PlanetaryPageSampling.NominalAngularTexelSize(layout), spacing)); + } + return new(inputs.ToArray(), metadata, inputs.Count, snapshot.ContentVersion, snapshot.PresentationVersion); + } +} diff --git a/unity/Runtime/PlanetaryPatchMeshAdapter.cs b/unity/Runtime/PlanetaryPatchMeshAdapter.cs new file mode 100644 index 00000000..69a72a2a --- /dev/null +++ b/unity/Runtime/PlanetaryPatchMeshAdapter.cs @@ -0,0 +1,36 @@ +using System; +using UnityEngine; +using UnityEngine.Rendering; + +namespace CultMath.Unity; + +public static class PlanetaryPatchMeshAdapter +{ + public static Mesh CreateFaceMesh(PlanetaryCubeFace face, int cellsPerAxis, float radius = 1) + { + if (!float.IsFinite(radius) || radius <= 0) throw new ArgumentOutOfRangeException(nameof(radius)); + var source = PlanetaryPatch.CreateFace(face, cellsPerAxis); + var vertices = new Vector3[source.Vertices.Length]; + var normals = new Vector3[source.Vertices.Length]; + var uv = new Vector2[source.Vertices.Length]; + for (var i = 0; i < source.Vertices.Length; i++) + { + var direction = source.Vertices[i].UnitDirection; + var normal = new Vector3(direction.x, direction.y, direction.z); + vertices[i] = normal * radius; + normals[i] = normal; + uv[i] = new Vector2(source.Vertices[i].LocalCoordinate.x, source.Vertices[i].LocalCoordinate.y); + } + var mesh = new Mesh + { + name = $"CultMath Planetary {face} {cellsPerAxis}x{cellsPerAxis}", + indexFormat = vertices.Length > ushort.MaxValue ? IndexFormat.UInt32 : IndexFormat.UInt16, + vertices = vertices, + normals = normals, + uv = uv, + triangles = source.Indices, + }; + mesh.RecalculateBounds(); + return mesh; + } +} From 102403efac25efea5986c1f114c11437ae1a6b03 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 13 Jul 2026 02:52:13 +0100 Subject: [PATCH 016/283] Complete portable planetary presentation contracts --- .gitignore | 1 + CultMath.slnx | 3 + README.md | 14 ++ .../CultMath.PlanetaryViewer.Editor.asmdef | 18 +++ .../Editor/CultMathPlanetaryViewerMenu.cs | 26 ++++ Samples~/PlanetaryViewer/README.md | 16 ++ .../Runtime/CultMath.PlanetaryViewer.asmdef | 17 +++ .../Runtime/CultMathPlanetaryViewer.cs | 139 ++++++++++++++++++ .../Runtime/CultMathPlanetaryViewer.shader | 90 ++++++++++++ THIRD-PARTY-NOTICES.md.meta | 7 + .../CultMath.PlanetaryTileFixture.csproj | 11 ++ .../CultMath.PlanetaryTileFixture/Program.cs | 22 +++ docs/planetary.md | 29 +++- docs/planetary.md.meta | 7 + package.json | 9 +- scripts.meta | 8 + scripts/test-web-planetary-tile.ps1 | 9 ++ scripts/test-web-planetary-tile.ps1.meta | 7 + shaders/AdvancedErosionFilter.hlsl.meta | 7 + shaders/Planetary.hlsl | 132 +++++++++++++++++ shaders/Planetary.hlsl.meta | 7 + src/CultMath/AdvancedErosionFilter.cs.meta | 2 + src/CultMath/ErosionFrequencyBands.cs.meta | 2 + src/CultMath/PlanetaryField.cs | 2 + src/CultMath/PlanetaryField.cs.meta | 2 + src/CultMath/PlanetaryGpuPages.cs | 55 +++++++ src/CultMath/PlanetaryGpuPages.cs.meta | 2 + src/CultMath/PlanetaryMapTileEncoding.cs | 117 +++++++++++++++ src/CultMath/PlanetaryMapTileEncoding.cs.meta | 2 + src/CultMath/PlanetaryPages.cs | 2 + src/CultMath/PlanetaryPages.cs.meta | 2 + src/CultMath/PlanetaryPatch.cs | 3 + src/CultMath/PlanetaryPatch.cs.meta | 2 + src/CultMath/PlanetaryProjection.cs | 2 + src/CultMath/PlanetaryProjection.cs.meta | 2 + src/CultMath/PlanetaryQueries.cs | 2 + src/CultMath/PlanetaryQueries.cs.meta | 2 + .../PlanetaryRadialRefinement.cs.meta | 2 + src/CultMath/PlanetaryResidency.cs | 10 +- src/CultMath/PlanetaryResidency.cs.meta | 2 + src/CultMath/PlanetaryTopology.cs | 21 +++ src/CultMath/PlanetaryTopology.cs.meta | 2 + src/CultMath/SphericalErosion.cs.meta | 2 + .../AdvancedErosionFilterTests.cs.meta | 2 + .../ErosionFrequencyBandsTests.cs.meta | 2 + tests/CultMath.Tests/HlslMirrorTests.cs | 2 + .../PlanetaryFieldTests.cs.meta | 2 + tests/CultMath.Tests/PlanetaryGpuPageTests.cs | 25 ++++ .../PlanetaryGpuPageTests.cs.meta | 2 + .../PlanetaryMapTileEncodingTests.cs | 52 +++++++ .../PlanetaryMapTileEncodingTests.cs.meta | 2 + .../CultMath.Tests/PlanetaryPageTests.cs.meta | 2 + .../PlanetaryPatchTests.cs.meta | 2 + .../PlanetaryProjectionTests.cs.meta | 2 + .../PlanetaryQueryTests.cs.meta | 2 + .../PlanetaryRadialRefinementTests.cs.meta | 2 + .../PlanetaryResidencyTests.cs.meta | 2 + .../CultMath.Tests/PlanetaryTopologyTests.cs | 8 + .../PlanetaryTopologyTests.cs.meta | 2 + .../SphericalErosionTests.cs.meta | 2 + tools/CultMath.PlanetaryTileFixture.meta | 8 + unity.meta | 8 + unity/Runtime.meta | 8 + unity/Runtime/CultMath.Unity.asmdef.meta | 7 + unity/Runtime/PlanetaryPageUpload.cs | 52 ++++--- unity/Runtime/PlanetaryPageUpload.cs.meta | 2 + .../Runtime/PlanetaryPatchMeshAdapter.cs.meta | 2 + web.meta | 8 + web/planetary-tile.cross-runtime.test.mjs | 21 +++ ...planetary-tile.cross-runtime.test.mjs.meta | 7 + web/planetary-tile.test.mjs | 39 +++++ web/planetary-tile.test.mjs.meta | 7 + web/planetary-tile.ts | 89 +++++++++++ web/planetary-tile.ts.meta | 7 + 74 files changed, 1166 insertions(+), 31 deletions(-) create mode 100644 Samples~/PlanetaryViewer/Editor/CultMath.PlanetaryViewer.Editor.asmdef create mode 100644 Samples~/PlanetaryViewer/Editor/CultMathPlanetaryViewerMenu.cs create mode 100644 Samples~/PlanetaryViewer/README.md create mode 100644 Samples~/PlanetaryViewer/Runtime/CultMath.PlanetaryViewer.asmdef create mode 100644 Samples~/PlanetaryViewer/Runtime/CultMathPlanetaryViewer.cs create mode 100644 Samples~/PlanetaryViewer/Runtime/CultMathPlanetaryViewer.shader create mode 100644 THIRD-PARTY-NOTICES.md.meta create mode 100644 Tools~/CultMath.PlanetaryTileFixture/CultMath.PlanetaryTileFixture.csproj create mode 100644 Tools~/CultMath.PlanetaryTileFixture/Program.cs create mode 100644 docs/planetary.md.meta create mode 100644 scripts.meta create mode 100644 scripts/test-web-planetary-tile.ps1 create mode 100644 scripts/test-web-planetary-tile.ps1.meta create mode 100644 shaders/AdvancedErosionFilter.hlsl.meta create mode 100644 shaders/Planetary.hlsl.meta create mode 100644 src/CultMath/AdvancedErosionFilter.cs.meta create mode 100644 src/CultMath/ErosionFrequencyBands.cs.meta create mode 100644 src/CultMath/PlanetaryField.cs.meta create mode 100644 src/CultMath/PlanetaryGpuPages.cs create mode 100644 src/CultMath/PlanetaryGpuPages.cs.meta create mode 100644 src/CultMath/PlanetaryMapTileEncoding.cs create mode 100644 src/CultMath/PlanetaryMapTileEncoding.cs.meta create mode 100644 src/CultMath/PlanetaryPages.cs.meta create mode 100644 src/CultMath/PlanetaryPatch.cs.meta create mode 100644 src/CultMath/PlanetaryProjection.cs.meta create mode 100644 src/CultMath/PlanetaryQueries.cs.meta create mode 100644 src/CultMath/PlanetaryRadialRefinement.cs.meta create mode 100644 src/CultMath/PlanetaryResidency.cs.meta create mode 100644 src/CultMath/PlanetaryTopology.cs.meta create mode 100644 src/CultMath/SphericalErosion.cs.meta create mode 100644 tests/CultMath.Tests/AdvancedErosionFilterTests.cs.meta create mode 100644 tests/CultMath.Tests/ErosionFrequencyBandsTests.cs.meta create mode 100644 tests/CultMath.Tests/PlanetaryFieldTests.cs.meta create mode 100644 tests/CultMath.Tests/PlanetaryGpuPageTests.cs create mode 100644 tests/CultMath.Tests/PlanetaryGpuPageTests.cs.meta create mode 100644 tests/CultMath.Tests/PlanetaryMapTileEncodingTests.cs create mode 100644 tests/CultMath.Tests/PlanetaryMapTileEncodingTests.cs.meta create mode 100644 tests/CultMath.Tests/PlanetaryPageTests.cs.meta create mode 100644 tests/CultMath.Tests/PlanetaryPatchTests.cs.meta create mode 100644 tests/CultMath.Tests/PlanetaryProjectionTests.cs.meta create mode 100644 tests/CultMath.Tests/PlanetaryQueryTests.cs.meta create mode 100644 tests/CultMath.Tests/PlanetaryRadialRefinementTests.cs.meta create mode 100644 tests/CultMath.Tests/PlanetaryResidencyTests.cs.meta create mode 100644 tests/CultMath.Tests/PlanetaryTopologyTests.cs.meta create mode 100644 tests/CultMath.Tests/SphericalErosionTests.cs.meta create mode 100644 tools/CultMath.PlanetaryTileFixture.meta create mode 100644 unity.meta create mode 100644 unity/Runtime.meta create mode 100644 unity/Runtime/CultMath.Unity.asmdef.meta create mode 100644 unity/Runtime/PlanetaryPageUpload.cs.meta create mode 100644 unity/Runtime/PlanetaryPatchMeshAdapter.cs.meta create mode 100644 web.meta create mode 100644 web/planetary-tile.cross-runtime.test.mjs create mode 100644 web/planetary-tile.cross-runtime.test.mjs.meta create mode 100644 web/planetary-tile.test.mjs create mode 100644 web/planetary-tile.test.mjs.meta create mode 100644 web/planetary-tile.ts create mode 100644 web/planetary-tile.ts.meta diff --git a/.gitignore b/.gitignore index 5ae20c8e..3779002b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ obj/ **/obj/ target/ **/target/ +/native/cultmath-core/target.meta .tools/ diff --git a/CultMath.slnx b/CultMath.slnx index 95834573..05d17886 100644 --- a/CultMath.slnx +++ b/CultMath.slnx @@ -5,4 +5,7 @@ + + + diff --git a/README.md b/README.md index 29eb115f..c60a9912 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,20 @@ cargo test --manifest-path native/cultmath-core/Cargo.toml cargo build --release --manifest-path native/cultmath-core/Cargo.toml ``` +## Unity compiler + +CultMath uses C# 10 record structs and file-scoped namespaces. Unity projects +must select the compiler's latest language mode with an `Assets/csc.rsp` file: + +```text +-langversion:latest +``` + +The package's Unity smoke project verifies this contract against Unity 6. The +setting is already present in current GameCult Unity clients; it belongs to the +consumer project because Unity only reads compiler response files from its +`Assets` root. + ## Shader Tooling CultMath keeps portable DXC outside git under `.tools/`: diff --git a/Samples~/PlanetaryViewer/Editor/CultMath.PlanetaryViewer.Editor.asmdef b/Samples~/PlanetaryViewer/Editor/CultMath.PlanetaryViewer.Editor.asmdef new file mode 100644 index 00000000..10512326 --- /dev/null +++ b/Samples~/PlanetaryViewer/Editor/CultMath.PlanetaryViewer.Editor.asmdef @@ -0,0 +1,18 @@ +{ + "name": "CultMath.PlanetaryViewer.Editor", + "rootNamespace": "CultMath.Unity.Samples.Editor", + "references": [ + "CultMath.PlanetaryViewer" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} diff --git a/Samples~/PlanetaryViewer/Editor/CultMathPlanetaryViewerMenu.cs b/Samples~/PlanetaryViewer/Editor/CultMathPlanetaryViewerMenu.cs new file mode 100644 index 00000000..ade28c30 --- /dev/null +++ b/Samples~/PlanetaryViewer/Editor/CultMathPlanetaryViewerMenu.cs @@ -0,0 +1,26 @@ +using UnityEditor; +using UnityEngine; + +namespace CultMath.Unity.Samples.Editor; + +public static class CultMathPlanetaryViewerMenu +{ + [MenuItem("GameObject/CultMath/Planetary Field Viewer", false, 10)] + public static void CreateViewer() + { + var root = new GameObject("CultMath Planetary Field Viewer"); + Undo.RegisterCreatedObjectUndo(root, "Create CultMath Planetary Viewer"); + root.AddComponent(); + Selection.activeGameObject = root; + + if (Camera.main != null) return; + var cameraObject = new GameObject("Planetary Viewer Camera"); + Undo.RegisterCreatedObjectUndo(cameraObject, "Create Planetary Viewer Camera"); + cameraObject.tag = "MainCamera"; + cameraObject.transform.position = new Vector3(0, 0, -24); + cameraObject.transform.LookAt(root.transform); + var camera = cameraObject.AddComponent(); + camera.nearClipPlane = 0.01f; + camera.farClipPlane = 1000; + } +} diff --git a/Samples~/PlanetaryViewer/README.md b/Samples~/PlanetaryViewer/README.md new file mode 100644 index 00000000..ec4dcc3a --- /dev/null +++ b/Samples~/PlanetaryViewer/README.md @@ -0,0 +1,16 @@ +# Planetary Field Viewer + +Import this sample through Unity's Package Manager, then choose +`GameObject > CultMath > Planetary Field Viewer`. + +The host project must contain `Assets/csc.rsp` with +`-langversion:latest`, as documented in the CultMath package README. + +The generated six-face mesh uses `PlanetaryPatch`. Its shader calls +`cultmath_planetary_field_sample` from the packaged CultMath HLSL, while the +component exposes the matching CPU `Sample` method. Seed, radius, physical +sample footprint, erosion settings, and base-field equations are shared between +the two bodies. + +This is a renderer integration fixture, not a gameplay owner. It deliberately +contains no Aetheria state, biomes, resources, or simulation decisions. diff --git a/Samples~/PlanetaryViewer/Runtime/CultMath.PlanetaryViewer.asmdef b/Samples~/PlanetaryViewer/Runtime/CultMath.PlanetaryViewer.asmdef new file mode 100644 index 00000000..2d3676f4 --- /dev/null +++ b/Samples~/PlanetaryViewer/Runtime/CultMath.PlanetaryViewer.asmdef @@ -0,0 +1,17 @@ +{ + "name": "CultMath.PlanetaryViewer", + "rootNamespace": "CultMath.Unity.Samples", + "references": [ + "CultMath", + "CultMath.Unity" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} diff --git a/Samples~/PlanetaryViewer/Runtime/CultMathPlanetaryViewer.cs b/Samples~/PlanetaryViewer/Runtime/CultMathPlanetaryViewer.cs new file mode 100644 index 00000000..06113728 --- /dev/null +++ b/Samples~/PlanetaryViewer/Runtime/CultMathPlanetaryViewer.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace CultMath.Unity.Samples; + +[ExecuteAlways] +public sealed class CultMathPlanetaryViewer : MonoBehaviour +{ + [Min(0.001f)] public float Radius = 8.4f; + [Range(1, 256)] public int CellsPerFace = 64; + public int Seed = 42; + [Min(0.0001f)] public float SampleFootprint = 0.01f; + public Shader? PlanetShader; + public Vector3 LightDirection = new(-0.4f, 0.7f, -0.6f); + public Color LowColor = new(0.055f, 0.16f, 0.09f, 1); + public Color HighColor = new(0.62f, 0.48f, 0.28f, 1); + public Color RidgeColor = new(0.88f, 0.83f, 0.7f, 1); + + private readonly List meshes = new(); + private Material? material; + private int builtCells; + + public PlanetaryFieldDefinition Definition => PlanetaryFieldDefinition.Create( + 1, + Radius, + Seed, + ViewerErosion(Radius)); + + public PlanetarySurfaceSample Sample(float3 direction) + { + var source = new ViewerBaseField(Radius); + var normalized = math.normalize(direction); + return PlanetaryField.Sample(Definition, normalized, source.Sample(normalized), PlanetaryQueryScale.AtFootprint(SampleFootprint)); + } + + private void OnEnable() => Rebuild(); + + private void OnValidate() + { + Radius = Mathf.Max(Radius, 0.001f); + CellsPerFace = Mathf.Clamp(CellsPerFace, 1, 256); + SampleFootprint = Mathf.Max(SampleFootprint, 0.0001f); + if (isActiveAndEnabled) Rebuild(); + } + + private void Update() + { + if (builtCells != CellsPerFace || material == null) Rebuild(); + ApplyMaterial(); + } + + private void Rebuild() + { + ClearGenerated(); + PlanetShader ??= Shader.Find("CultMath/Planetary Field Viewer"); + if (PlanetShader == null) return; + material = new Material(PlanetShader) { name = "CultMath Planetary Viewer Material", hideFlags = HideFlags.HideAndDontSave }; + foreach (var face in (PlanetaryCubeFace[])Enum.GetValues(typeof(PlanetaryCubeFace))) + { + var mesh = PlanetaryPatchMeshAdapter.CreateFaceMesh(face, CellsPerFace); + mesh.hideFlags = HideFlags.HideAndDontSave; + meshes.Add(mesh); + var child = new GameObject(face.ToString()) { hideFlags = HideFlags.DontSave }; + child.transform.SetParent(transform, false); + child.AddComponent().sharedMesh = mesh; + child.AddComponent().sharedMaterial = material; + } + builtCells = CellsPerFace; + ApplyMaterial(); + } + + private void ApplyMaterial() + { + if (material == null) return; + var p = ViewerErosion(Radius); + material.SetFloat("_Radius", Radius); + material.SetFloat("_SampleFootprint", SampleFootprint); + material.SetInt("_Seed", Seed); + material.SetFloat("_ErosionScale", p.Scale); + material.SetFloat("_ErosionStrength", p.Strength); + material.SetFloat("_GullyWeight", p.GullyWeight); + material.SetFloat("_Detail", p.Detail); + material.SetVector("_Rounding", new(p.Rounding.x, p.Rounding.y, p.Rounding.z, p.Rounding.w)); + material.SetVector("_Onset", new(p.Onset.x, p.Onset.y, p.Onset.z, p.Onset.w)); + material.SetVector("_AssumedSlope", new(p.AssumedSlope.x, p.AssumedSlope.y, 0, 0)); + material.SetFloat("_CellScale", p.CellScale); + material.SetFloat("_Normalization", p.Normalization); + material.SetInt("_Octaves", p.Octaves); + material.SetFloat("_Lacunarity", p.Lacunarity); + material.SetFloat("_Gain", p.Gain); + material.SetVector("_LightDirection", LightDirection.normalized); + material.SetColor("_LowColor", LowColor); + material.SetColor("_HighColor", HighColor); + material.SetColor("_RidgeColor", RidgeColor); + } + + private void OnDisable() => ClearGenerated(); + private void OnDestroy() => ClearGenerated(); + + private void ClearGenerated() + { + for (var i = transform.childCount - 1; i >= 0; i--) DestroyGenerated(transform.GetChild(i).gameObject); + foreach (var mesh in meshes) DestroyGenerated(mesh); + meshes.Clear(); + if (material != null) DestroyGenerated(material); + material = null; + builtCells = 0; + } + + private static void DestroyGenerated(UnityEngine.Object value) + { + if (Application.isPlaying) Destroy(value); + else DestroyImmediate(value); + } + + private static AdvancedErosionParameters ViewerErosion(float radius) => new( + radius * 0.075f, 0.12f, 0.58f, 1.45f, + new float4(0.1f, 0.015f, 0.1f, 2), + new float4(1.25f, 1.25f, 2.8f, 1.5f), + new float2(0.7f, 0.85f), 0.7f, 0.5f, 7, 2, 0.5f); + + private readonly struct ViewerBaseField : IPlanetaryBaseField + { + private readonly float radius; + public ViewerBaseField(float radius) => this.radius = radius; + + public PlanetaryBaseFieldSample Sample(float3 direction) + { + var value = direction.x * 0.6f + direction.y * direction.z * 0.3f; + var angularGradient = new float3(0.6f, direction.z * 0.3f, direction.y * 0.3f); + angularGradient -= direction * math.dot(angularGradient, direction); + var fieldGradient = angularGradient / radius; + var radialDisplacement = value * radius * 0.035f; + var radialGradient = angularGradient * 0.035f; + return new(radialDisplacement, radialGradient, value, fieldGradient, math.clamp(value, -1, 1)); + } + } +} diff --git a/Samples~/PlanetaryViewer/Runtime/CultMathPlanetaryViewer.shader b/Samples~/PlanetaryViewer/Runtime/CultMathPlanetaryViewer.shader new file mode 100644 index 00000000..b5f7274f --- /dev/null +++ b/Samples~/PlanetaryViewer/Runtime/CultMathPlanetaryViewer.shader @@ -0,0 +1,90 @@ +Shader "CultMath/Planetary Field Viewer" +{ + Properties + { + _LowColor ("Low Color", Color) = (0.055, 0.16, 0.09, 1) + _HighColor ("High Color", Color) = (0.62, 0.48, 0.28, 1) + _RidgeColor ("Ridge Color", Color) = (0.88, 0.83, 0.7, 1) + } + SubShader + { + Tags { "RenderType"="Opaque" "Queue"="Geometry" } + Pass + { + Cull Back + ZWrite On + HLSLPROGRAM + #pragma target 5.0 + #pragma vertex vert + #pragma fragment frag + #include "UnityCG.cginc" + #include "Packages/org.gamecult.cultmath/shaders/CultMath.hlsl" + + float _Radius; + float _SampleFootprint; + int _Seed; + float _ErosionScale, _ErosionStrength, _GullyWeight, _Detail; + float4 _Rounding, _Onset, _AssumedSlope; + float _CellScale, _Normalization, _Lacunarity, _Gain; + int _Octaves; + float3 _LightDirection; + float4 _LowColor, _HighColor, _RidgeColor; + + struct Attributes { float4 vertex : POSITION; }; + struct Varyings + { + float4 position : SV_POSITION; + float3 worldNormal : TEXCOORD0; + float height : TEXCOORD1; + float ridge : TEXCOORD2; + }; + + CultMathPlanetarySurfaceSample viewer_sample(float3 direction) + { + direction = normalize(direction); + float value = direction.x * 0.6 + direction.y * direction.z * 0.3; + float3 angular_gradient = float3(0.6, direction.z * 0.3, direction.y * 0.3); + angular_gradient -= direction * dot(angular_gradient, direction); + CultMathPlanetaryBaseFieldSample base_sample; + base_sample.radial_displacement = value * _Radius * 0.035; + base_sample.radial_gradient = angular_gradient * 0.035; + base_sample.field_value = value; + base_sample.field_gradient = angular_gradient / _Radius; + base_sample.fade_target = clamp(value, -1.0, 1.0); + CultMathAdvancedErosionParameters erosion; + erosion.scale = _ErosionScale; erosion.strength = _ErosionStrength; + erosion.gully_weight = _GullyWeight; erosion.detail = _Detail; + erosion.rounding = _Rounding; erosion.onset = _Onset; + erosion.assumed_slope = _AssumedSlope.xy; erosion.cell_scale = _CellScale; + erosion.normalization = _Normalization; erosion.octaves = _Octaves; + erosion.lacunarity = _Lacunarity; erosion.gain = _Gain; + CultMathPlanetaryFieldDefinition definition; + definition.radius = _Radius; definition.seed = _Seed; definition.erosion = erosion; + return cultmath_planetary_field_sample(definition, direction, base_sample, _SampleFootprint); + } + + Varyings vert(Attributes input) + { + float3 direction = normalize(input.vertex.xyz); + CultMathPlanetarySurfaceSample sample = viewer_sample(direction); + float3 local = direction * (_Radius + sample.radial_displacement); + Varyings output; + output.position = UnityObjectToClipPos(float4(local, 1)); + output.worldNormal = UnityObjectToWorldNormal(sample.surface_normal); + output.height = sample.radial_displacement / max(_Radius * 0.1, 1.0e-5); + output.ridge = sample.ridge; + return output; + } + + float4 frag(Varyings input) : SV_Target + { + float height = saturate(input.height * 0.5 + 0.5); + float3 albedo = lerp(_LowColor.rgb, _HighColor.rgb, height); + albedo = lerp(albedo, _RidgeColor.rgb, saturate((input.ridge - 0.55) * 2.5)); + float diffuse = saturate(dot(normalize(input.worldNormal), normalize(-_LightDirection))) * 0.82 + 0.08; + return float4(albedo * diffuse, 1); + } + ENDHLSL + } + } +} diff --git a/THIRD-PARTY-NOTICES.md.meta b/THIRD-PARTY-NOTICES.md.meta new file mode 100644 index 00000000..4b43ddaa --- /dev/null +++ b/THIRD-PARTY-NOTICES.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7c28c8631c7d4054eb751d7ce952df33 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tools~/CultMath.PlanetaryTileFixture/CultMath.PlanetaryTileFixture.csproj b/Tools~/CultMath.PlanetaryTileFixture/CultMath.PlanetaryTileFixture.csproj new file mode 100644 index 00000000..9a6f8bdd --- /dev/null +++ b/Tools~/CultMath.PlanetaryTileFixture/CultMath.PlanetaryTileFixture.csproj @@ -0,0 +1,11 @@ + + + Exe + net10.0 + enable + enable + + + + + diff --git a/Tools~/CultMath.PlanetaryTileFixture/Program.cs b/Tools~/CultMath.PlanetaryTileFixture/Program.cs new file mode 100644 index 00000000..1952fa2d --- /dev/null +++ b/Tools~/CultMath.PlanetaryTileFixture/Program.cs @@ -0,0 +1,22 @@ +using CultMath; + +if (args.Length != 1) throw new ArgumentException("Expected one output path."); +var field = PlanetaryFieldDefinition.Create(0x55aa, 10, 7, AdvancedErosionParameters.Default); +var layout = new PlanetaryMapTileLayout(new(PlanetaryProjectionKind.EqualEarth), 0, 0, 0, 5, 1); +var key = new PlanetaryMapTileKey(field.FieldVersion, 3, 29, layout, PlanetaryQueryScale.AtFootprint(0.25f, 0.125f)); +var tile = PlanetaryMapTileBaker.Bake(field, key, new FixtureField()); +var path = Path.GetFullPath(args[0]); +Directory.CreateDirectory(Path.GetDirectoryName(path)!); +using var stream = File.Create(path); +PlanetaryMapTileEncoding.Write(stream, tile); + +readonly struct FixtureField : IPlanetaryBaseField +{ + public PlanetaryBaseFieldSample Sample(float3 direction) + { + var value = direction.x * 0.2f + direction.z * 0.4f; + var gradient = new float3(0.2f, 0, 0.4f); + gradient -= direction * math.dot(gradient, direction); + return new(value, gradient, value, gradient * 0.1f, value); + } +} diff --git a/docs/planetary.md b/docs/planetary.md index 8196c1c7..3503429b 100644 --- a/docs/planetary.md +++ b/docs/planetary.md @@ -80,11 +80,17 @@ coarse meshes from the canonical topology. HLSL calls Renderers still own cameras, clip space, depth, materials, buffers, dispatch, and draw submission. +`PlanetaryGpuPageBuilder` owns the renderer-neutral page input and metadata +payload. Host adapters may convert its `float4` values to native vector types, +but do not recalculate directions, spacing, addressing, or transition state. + The optional `CultMath.Unity` assembly converts a canonical face patch into a -Unity `Mesh` and converts a residency snapshot into Unity-native page input and -metadata payloads. It owns no field parameters, page selection, or simulation -state. Unity render code remains responsible for allocating/binding graphics -buffers and dispatching application-specific base-field entry points. +Unity `Mesh` and converts the shared GPU payload into Unity-native structs. It +owns no field parameters, page selection, or simulation state. The package's +Planetary Field Viewer sample renders the shared HLSL field and reports matching +CPU queries. Unity render code remains responsible for allocating/binding +graphics buffers and dispatching application-specific base-field entry points. +The host Unity project must set `-langversion:latest` in `Assets/csc.rsp`. ## Maps @@ -103,6 +109,12 @@ projection and canonical field query. `PlanetaryMapTileKey` includes field, projection, layer, layout, and query-scale identity. Palettes, contours, labels, and strategic overlays do not enter CultMath. +`PlanetaryMapTileEncoding` writes the resulting evidence as a versioned +little-endian `CMPT` binary asset. `web/planetary-tile.ts` decodes that exact +format into browser-native values without defining another terrain generator. +Typed CultMesh documents should carry the tile key and asset reference; the +binary payload is derived CDN/cache data, not committed game state. + ## Numeric contract Integer hashes and published field versions are exact. Basic arithmetic follows @@ -111,7 +123,8 @@ CultMath's matched C#/HLSL semantics. Hardware transcendental functions such as Every filtered terrain query carries an unresolved-height bound so consumers can reject insufficient fidelity explicitly. -Current D3D12 parity evidence covers the advanced erosion kernel and the QSC -forward/inverse topology. The remaining production page and patch shaders use -the common functions and retain their seam, residual, summary, and radial-hit -integration probes in Fensalir. +Current D3D12 parity evidence covers the advanced erosion kernel, QSC topology, +and forward/inverse transforms for every supported map projection, including +center and scale parameters. Production page and patch shaders use the common +functions and retain their seam, residual, summary, and radial-hit integration +probes in Fensalir. diff --git a/docs/planetary.md.meta b/docs/planetary.md.meta new file mode 100644 index 00000000..af364c25 --- /dev/null +++ b/docs/planetary.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 23a5751e4cececc4e99e024058d69add +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/package.json b/package.json index 6da2a17a..25643608 100644 --- a/package.json +++ b/package.json @@ -10,5 +10,12 @@ "Simulation" ], "license": "MPL-2.0", - "category": "Scripting" + "category": "Scripting", + "samples": [ + { + "displayName": "Planetary Field Viewer", + "description": "Runnable Unity viewer using the canonical CultMath CPU and HLSL planetary field.", + "path": "Samples~/PlanetaryViewer" + } + ] } diff --git a/scripts.meta b/scripts.meta new file mode 100644 index 00000000..6f03c566 --- /dev/null +++ b/scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0ddff5b782cf14e43ae5cda048e040d8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/scripts/test-web-planetary-tile.ps1 b/scripts/test-web-planetary-tile.ps1 new file mode 100644 index 00000000..5221fb36 --- /dev/null +++ b/scripts/test-web-planetary-tile.ps1 @@ -0,0 +1,9 @@ +$ErrorActionPreference = "Stop" +$root = Split-Path -Parent $PSScriptRoot +$fixture = Join-Path $root ".tools\planetary-tile\fixture.cmpt" +dotnet run --project (Join-Path $root "Tools~\CultMath.PlanetaryTileFixture\CultMath.PlanetaryTileFixture.csproj") -- $fixture +if ($LASTEXITCODE -ne 0) { throw "Planetary tile fixture generation failed." } +node --no-warnings --experimental-strip-types (Join-Path $root "web\planetary-tile.cross-runtime.test.mjs") $fixture +if ($LASTEXITCODE -ne 0) { throw "Planetary tile web decoding failed." } +node --no-warnings --experimental-strip-types (Join-Path $root "web\planetary-tile.test.mjs") +if ($LASTEXITCODE -ne 0) { throw "Planetary tile decoder unit test failed." } diff --git a/scripts/test-web-planetary-tile.ps1.meta b/scripts/test-web-planetary-tile.ps1.meta new file mode 100644 index 00000000..ffd73234 --- /dev/null +++ b/scripts/test-web-planetary-tile.ps1.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 235e8f203bd1c4d40a8fa211273106ba +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/shaders/AdvancedErosionFilter.hlsl.meta b/shaders/AdvancedErosionFilter.hlsl.meta new file mode 100644 index 00000000..a354e330 --- /dev/null +++ b/shaders/AdvancedErosionFilter.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3252ac02e8853ef4b9d1fbc5204b5c6b +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/shaders/Planetary.hlsl b/shaders/Planetary.hlsl index 729c6332..81e312b7 100644 --- a/shaders/Planetary.hlsl +++ b/shaders/Planetary.hlsl @@ -120,6 +120,138 @@ float3 cultmath_planetary_equal_earth_inverse(float2 coordinate) return cultmath_normalize(float3(cos_latitude * cos(longitude), cos_latitude * sin(longitude), sin(latitude))); } +float cultmath_planetary_wrap_longitude(float longitude) +{ + longitude = fmod(longitude, CULTMATH_TAU); + if (longitude > CULTMATH_PI) longitude -= CULTMATH_TAU; + if (longitude < -CULTMATH_PI) longitude += CULTMATH_TAU; + return longitude; +} + +float3 cultmath_planetary_lon_lat_direction(float longitude, float latitude) +{ + float cos_latitude = cos(latitude); + return cultmath_normalize(float3(cos_latitude * cos(longitude), cos_latitude * sin(longitude), sin(latitude))); +} + +float cultmath_planetary_asinh(float value) { return log(value + sqrt(value * value + 1.0)); } +float cultmath_planetary_sinh(float value) { return 0.5 * (exp(value) - exp(-value)); } + +bool cultmath_planetary_azimuthal_forward(float3 direction, float2 center_lon_lat, int kind, out float2 coordinate) +{ + direction = cultmath_normalize(direction); + float longitude = cultmath_planetary_wrap_longitude(atan2(direction.y, direction.x) - center_lon_lat.x); + float latitude = asin(clamp(direction.z, -1.0, 1.0)); + float sin0 = sin(center_lon_lat.y), cos0 = cos(center_lon_lat.y); + float sin_latitude = sin(latitude), cos_latitude = cos(latitude), cos_longitude = cos(longitude); + float cos_c = clamp(sin0 * sin_latitude + cos0 * cos_latitude * cos_longitude, -1.0, 1.0); + float2 raw = float2(cos_latitude * sin(longitude), cos0 * sin_latitude - sin0 * cos_latitude * cos_longitude); + float factor = 1.0; + if (kind == 3) + { + if (cos_c < 0.0) { coordinate = 0.0; return false; } + } + else if (kind == 4) + { + float c = acos(cos_c); factor = (c < 1.0e-6 ? 1.0 : c / sin(c)) / CULTMATH_PI; + } + else if (kind == 5) factor = sqrt(2.0 / max(1.0 + cos_c, 1.0e-20)) * 0.5; + else + { + if (cos_c <= 0.0) { coordinate = 0.0; return false; } + factor = 1.0 / cos_c; + } + coordinate = raw * factor; + return true; +} + +bool cultmath_planetary_azimuthal_inverse(float2 coordinate, float2 center_lon_lat, int kind, out float3 direction) +{ + float rho = length(coordinate); + float c; + if (kind == 3) { if (rho > 1.0) { direction = 0.0; return false; } c = asin(clamp(rho, 0.0, 1.0)); } + else if (kind == 4) { if (rho > 1.0) { direction = 0.0; return false; } c = rho * CULTMATH_PI; } + else if (kind == 5) { if (rho > 1.0) { direction = 0.0; return false; } c = 2.0 * asin(clamp(rho, 0.0, 1.0)); } + else c = atan(rho); + if (rho < 1.0e-6) { direction = cultmath_planetary_lon_lat_direction(center_lon_lat.x, center_lon_lat.y); return true; } + float sin_c = sin(c), cos_c = cos(c), sin0 = sin(center_lon_lat.y), cos0 = cos(center_lon_lat.y); + float latitude = asin(clamp(cos_c * sin0 + coordinate.y * sin_c * cos0 / rho, -1.0, 1.0)); + float delta_longitude = atan2(coordinate.x * sin_c, rho * cos0 * cos_c - coordinate.y * sin0 * sin_c); + direction = cultmath_planetary_lon_lat_direction(cultmath_planetary_wrap_longitude(delta_longitude + center_lon_lat.x), latitude); + return true; +} + +bool cultmath_planetary_cube_atlas_forward(float3 direction, out float2 coordinate) +{ + int face; + float2 face_coordinate = cultmath_planetary_face_coordinate(direction, face); + int column = face % 3; + int row = face / 3; + coordinate = float2(-1.0 + (column + (face_coordinate.x + 1.0) * 0.5) * (2.0 / 3.0), 1.0 - (row + (face_coordinate.y + 1.0) * 0.5)); + return true; +} + +bool cultmath_planetary_cube_atlas_inverse(float2 coordinate, out float3 direction) +{ + if (any(coordinate < -1.0) || any(coordinate > 1.0)) { direction = 0.0; return false; } + int column = min((int)((coordinate.x + 1.0) * 1.5), 2); + int row = min((int)(1.0 - coordinate.y), 1); + float u = ((coordinate.x + 1.0) * 1.5 - column) * 2.0 - 1.0; + float v = ((1.0 - coordinate.y) - row) * 2.0 - 1.0; + direction = cultmath_planetary_face_direction(row * 3 + column, float2(u, v)); + return true; +} + +bool cultmath_planetary_projection_forward(float3 direction, int kind, float3 center_lon_lat_scale, out float2 coordinate) +{ + float scale = max(center_lon_lat_scale.z, 1.0e-20); + if (kind == 6) + { + bool valid = cultmath_planetary_cube_atlas_forward(direction, coordinate); + coordinate /= scale; return valid; + } + if (kind >= 3) + { + bool valid = cultmath_planetary_azimuthal_forward(direction, center_lon_lat_scale.xy, kind, coordinate); + coordinate /= scale; return valid; + } + direction = cultmath_normalize(direction); + float longitude = cultmath_planetary_wrap_longitude(atan2(direction.y, direction.x) - center_lon_lat_scale.x); + float latitude = asin(clamp(direction.z, -1.0, 1.0)); + if (kind == 0) coordinate = float2(longitude / CULTMATH_PI, latitude / CULTMATH_HALF_PI); + else if (kind == 1) + { + const float maximum_latitude = 1.4844222297453324; + if (abs(latitude) > maximum_latitude) { coordinate = 0.0; return false; } + coordinate = float2(longitude / CULTMATH_PI, cultmath_planetary_asinh(tan(latitude)) / CULTMATH_PI); + } + else + { + float3 centered = cultmath_planetary_lon_lat_direction(longitude, latitude); + coordinate = cultmath_planetary_equal_earth_forward(centered); + } + coordinate /= scale; + return true; +} + +bool cultmath_planetary_projection_inverse(float2 coordinate, int kind, float3 center_lon_lat_scale, out float3 direction) +{ + coordinate *= max(center_lon_lat_scale.z, 1.0e-20); + if (kind == 6) return cultmath_planetary_cube_atlas_inverse(coordinate, direction); + if (kind >= 3) return cultmath_planetary_azimuthal_inverse(coordinate, center_lon_lat_scale.xy, kind, direction); + if (any(abs(coordinate) > 1.0)) { direction = 0.0; return false; } + float longitude, latitude; + if (kind == 0) { longitude = coordinate.x * CULTMATH_PI; latitude = coordinate.y * CULTMATH_HALF_PI; } + else if (kind == 1) { longitude = coordinate.x * CULTMATH_PI; latitude = atan(cultmath_planetary_sinh(coordinate.y * CULTMATH_PI)); } + else + { + float3 centered = cultmath_planetary_equal_earth_inverse(coordinate); + longitude = atan2(centered.y, centered.x); latitude = asin(clamp(centered.z, -1.0, 1.0)); + } + direction = cultmath_planetary_lon_lat_direction(cultmath_planetary_wrap_longitude(longitude + center_lon_lat_scale.x), latitude); + return true; +} + struct CultMathPlanetaryFieldDefinition { float radius; diff --git a/shaders/Planetary.hlsl.meta b/shaders/Planetary.hlsl.meta new file mode 100644 index 00000000..f7771355 --- /dev/null +++ b/shaders/Planetary.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: bb055ad5328888e479e90ae3fe62c3fe +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/CultMath/AdvancedErosionFilter.cs.meta b/src/CultMath/AdvancedErosionFilter.cs.meta new file mode 100644 index 00000000..52f7ca19 --- /dev/null +++ b/src/CultMath/AdvancedErosionFilter.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: bec15fdcbe97a7f44a24bdb3ff79e1e7 \ No newline at end of file diff --git a/src/CultMath/ErosionFrequencyBands.cs.meta b/src/CultMath/ErosionFrequencyBands.cs.meta new file mode 100644 index 00000000..cae99643 --- /dev/null +++ b/src/CultMath/ErosionFrequencyBands.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 05e7969589dd09b43bd0fda672d25a0b \ No newline at end of file diff --git a/src/CultMath/PlanetaryField.cs b/src/CultMath/PlanetaryField.cs index 13f36c0a..4d5596e5 100644 --- a/src/CultMath/PlanetaryField.cs +++ b/src/CultMath/PlanetaryField.cs @@ -1,3 +1,5 @@ +using System; + namespace CultMath; public readonly record struct PlanetaryQueryScale(float FootprintMeters, float MaximumUnresolvedHeight) diff --git a/src/CultMath/PlanetaryField.cs.meta b/src/CultMath/PlanetaryField.cs.meta new file mode 100644 index 00000000..3e83f637 --- /dev/null +++ b/src/CultMath/PlanetaryField.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: b61d6354e3aab054e94721e77e619bfa \ No newline at end of file diff --git a/src/CultMath/PlanetaryGpuPages.cs b/src/CultMath/PlanetaryGpuPages.cs new file mode 100644 index 00000000..024d26b0 --- /dev/null +++ b/src/CultMath/PlanetaryGpuPages.cs @@ -0,0 +1,55 @@ +using System; + +namespace CultMath; + +public readonly record struct PlanetaryGpuPageInput(float4 DirectionRadius, float4 Sampling); + +public readonly record struct PlanetaryGpuPageMetadata(float4 Address, float4 Layout, float4 Bounds, float4 State); + +public readonly record struct PlanetaryGpuPageContent( + PlanetaryPageLayout Layout, + PlanetaryGpuPageInput[] Inputs, + float SampleSpacing, + float ParentSampleSpacing); + +public static class PlanetaryGpuPageBuilder +{ + public static PlanetaryGpuPageContent BuildContent(PlanetaryPageLayout layout, float radius) + { + layout.Validate(); + if (!float.IsFinite(radius) || radius <= 0) throw new ArgumentOutOfRangeException(nameof(radius)); + var spacing = PlanetaryPageSampling.NominalAngularTexelSize(layout) * radius; + var parentSpacing = layout.Tile.Level == 0 + ? 0 + : PlanetaryPageSampling.NominalAngularTexelSize(new(layout.Tile.Parent(), layout.InteriorSize, layout.BorderSize)) * radius; + var inputs = new PlanetaryGpuPageInput[layout.StorageSize * layout.StorageSize]; + for (var y = 0; y < layout.StorageSize; y++) + for (var x = 0; x < layout.StorageSize; x++) + { + var direction = PlanetaryPageSampling.Direction(layout, x, y); + inputs[y * layout.StorageSize + x] = new( + new float4(direction, radius), + new float4(spacing, parentSpacing, 0, 0)); + } + return new(layout, inputs, spacing, parentSpacing); + } + + public static PlanetaryGpuPageMetadata Metadata( + in PlanetaryGpuPageContent content, + int outputOffset, + float blend, + float4 bounds = default) + { + content.Layout.Validate(); + if (content.Inputs == null || content.Inputs.Length != content.Layout.StorageSize * content.Layout.StorageSize) + throw new ArgumentException("GPU page content does not match its layout.", nameof(content)); + if (outputOffset < 0) throw new ArgumentOutOfRangeException(nameof(outputOffset)); + if (!float.IsFinite(blend) || blend is < 0 or > 1) throw new ArgumentOutOfRangeException(nameof(blend)); + var tile = content.Layout.Tile; + return new( + new float4((int)tile.Face, tile.Level, tile.X, tile.Y), + new float4(outputOffset, content.Layout.StorageSize, content.Layout.InteriorSize, content.Layout.BorderSize), + bounds, + new float4(1, blend, PlanetaryPageSampling.NominalAngularTexelSize(content.Layout), content.SampleSpacing)); + } +} diff --git a/src/CultMath/PlanetaryGpuPages.cs.meta b/src/CultMath/PlanetaryGpuPages.cs.meta new file mode 100644 index 00000000..7afe847c --- /dev/null +++ b/src/CultMath/PlanetaryGpuPages.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 42173c60766948a4e8c376687033532e \ No newline at end of file diff --git a/src/CultMath/PlanetaryMapTileEncoding.cs b/src/CultMath/PlanetaryMapTileEncoding.cs new file mode 100644 index 00000000..ec556617 --- /dev/null +++ b/src/CultMath/PlanetaryMapTileEncoding.cs @@ -0,0 +1,117 @@ +using System; +using System.IO; +using System.Text; + +namespace CultMath; + +public static class PlanetaryMapTileEncoding +{ + public const uint FormatVersion = 1; + private static readonly byte[] Magic = Encoding.ASCII.GetBytes("CMPT"); + + public static void Write(Stream stream, in PlanetarySurfaceMapTile tile, bool leaveOpen = false) + { + if (stream == null || !stream.CanWrite) throw new ArgumentException("A writable stream is required.", nameof(stream)); + tile.Key.Validate(); + if (tile.Samples == null || tile.Validity == null || tile.Samples.Length != tile.Validity.Length) + throw new ArgumentException("Tile samples and validity must have equal lengths.", nameof(tile)); + var expectedCount = tile.Key.Layout.StorageSize * tile.Key.Layout.StorageSize; + if (tile.Samples.Length != expectedCount) throw new ArgumentException("Tile payload does not match its layout.", nameof(tile)); + + using var writer = new BinaryWriter(stream, Encoding.UTF8, leaveOpen); + writer.Write(Magic); + writer.Write(FormatVersion); + writer.Write(tile.Key.FieldVersion); + writer.Write(tile.Key.ProjectionVersion); + writer.Write(tile.Key.LayerId); + var projection = tile.Key.Layout.Projection; + writer.Write((int)projection.Kind); + writer.Write(projection.CenterLongitude); + writer.Write(projection.CenterLatitude); + writer.Write(projection.Scale); + writer.Write(tile.Key.Layout.Level); + writer.Write(tile.Key.Layout.X); + writer.Write(tile.Key.Layout.Y); + writer.Write(tile.Key.Layout.InteriorSize); + writer.Write(tile.Key.Layout.BorderSize); + writer.Write(tile.Key.QueryScale.FootprintMeters); + writer.Write(tile.Key.QueryScale.MaximumUnresolvedHeight); + writer.Write(tile.Samples.Length); + for (var i = 0; i < tile.Samples.Length; i++) + { + writer.Write(tile.Validity[i]); + if (!tile.Validity[i]) continue; + WriteSample(writer, tile.Samples[i], tile.Key.FieldVersion); + } + } + + public static PlanetarySurfaceMapTile Read(Stream stream, bool leaveOpen = false) + { + if (stream == null || !stream.CanRead) throw new ArgumentException("A readable stream is required.", nameof(stream)); + using var reader = new BinaryReader(stream, Encoding.UTF8, leaveOpen); + var magic = reader.ReadBytes(Magic.Length); + if (magic.Length != Magic.Length || !magic.AsSpan().SequenceEqual(Magic)) throw new InvalidDataException("Not a CultMath planetary tile."); + var version = reader.ReadUInt32(); + if (version != FormatVersion) throw new InvalidDataException($"Unsupported planetary tile version {version}."); + var fieldVersion = reader.ReadUInt64(); + var projectionVersion = reader.ReadUInt32(); + var layerId = reader.ReadUInt32(); + var kindValue = reader.ReadInt32(); + if (!Enum.IsDefined(typeof(PlanetaryProjectionKind), kindValue)) throw new InvalidDataException("Unknown planetary projection kind."); + var projection = new PlanetaryProjectionParameters( + (PlanetaryProjectionKind)kindValue, + reader.ReadDouble(), reader.ReadDouble(), reader.ReadDouble()).Validate(); + var layout = new PlanetaryMapTileLayout( + projection, + reader.ReadInt32(), reader.ReadInt32(), reader.ReadInt32(), + reader.ReadInt32(), reader.ReadInt32()).Validate(); + var scale = new PlanetaryQueryScale(reader.ReadSingle(), reader.ReadSingle()).Validate(); + var key = new PlanetaryMapTileKey(fieldVersion, projectionVersion, layerId, layout, scale).Validate(); + var count = reader.ReadInt32(); + if (count != layout.StorageSize * layout.StorageSize) throw new InvalidDataException("Planetary tile sample count does not match layout."); + var samples = new PlanetarySurfaceSample[count]; + var validity = new bool[count]; + for (var i = 0; i < count; i++) + { + validity[i] = reader.ReadBoolean(); + if (validity[i]) samples[i] = ReadSample(reader, fieldVersion); + } + if (stream.CanSeek && stream.Position != stream.Length) throw new InvalidDataException("Planetary tile has trailing bytes."); + return new(key, samples, validity); + } + + private static void WriteSample(BinaryWriter writer, PlanetarySurfaceSample sample, ulong fieldVersion) + { + if (sample.FieldVersion != fieldVersion) throw new ArgumentException("Sample field version does not match tile identity."); + Write(writer, sample.UnitDirection); + writer.Write(sample.Radius); + writer.Write(sample.RadialDisplacement); + Write(writer, sample.TangentGradient); + Write(writer, sample.SurfaceNormal); + writer.Write(sample.Slope); + writer.Write(sample.Ridge); + writer.Write(sample.Gully); + writer.Write(sample.FinestResolvedWavelength); + writer.Write(sample.UnresolvedHeightBound); + } + + private static PlanetarySurfaceSample ReadSample(BinaryReader reader, ulong fieldVersion) + { + var direction = ReadFloat3(reader); + var radius = reader.ReadSingle(); + var displacement = reader.ReadSingle(); + var gradient = ReadFloat3(reader); + var normal = ReadFloat3(reader); + return new( + fieldVersion, direction, radius, displacement, gradient, normal, + reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), + reader.ReadSingle(), reader.ReadSingle()); + } + + private static void Write(BinaryWriter writer, float3 value) + { + writer.Write(value.x); writer.Write(value.y); writer.Write(value.z); + } + + private static float3 ReadFloat3(BinaryReader reader) => new(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); +} diff --git a/src/CultMath/PlanetaryMapTileEncoding.cs.meta b/src/CultMath/PlanetaryMapTileEncoding.cs.meta new file mode 100644 index 00000000..76484f65 --- /dev/null +++ b/src/CultMath/PlanetaryMapTileEncoding.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 6898f6de57df20646a0b9077bb923592 \ No newline at end of file diff --git a/src/CultMath/PlanetaryPages.cs b/src/CultMath/PlanetaryPages.cs index c9cff51f..699a5c1d 100644 --- a/src/CultMath/PlanetaryPages.cs +++ b/src/CultMath/PlanetaryPages.cs @@ -1,3 +1,5 @@ +using System; + namespace CultMath; public readonly record struct PlanetaryPageLayout(PlanetaryTileAddress Tile, int InteriorSize, int BorderSize) diff --git a/src/CultMath/PlanetaryPages.cs.meta b/src/CultMath/PlanetaryPages.cs.meta new file mode 100644 index 00000000..91fdc27d --- /dev/null +++ b/src/CultMath/PlanetaryPages.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7af9a0354faa56348a2e07188739a0ae \ No newline at end of file diff --git a/src/CultMath/PlanetaryPatch.cs b/src/CultMath/PlanetaryPatch.cs index 0fd3cbb6..30c852ff 100644 --- a/src/CultMath/PlanetaryPatch.cs +++ b/src/CultMath/PlanetaryPatch.cs @@ -1,3 +1,6 @@ +using System; +using System.Linq; + namespace CultMath; public readonly record struct PlanetaryPatchVertex(float2 LocalCoordinate, float3 UnitDirection); diff --git a/src/CultMath/PlanetaryPatch.cs.meta b/src/CultMath/PlanetaryPatch.cs.meta new file mode 100644 index 00000000..efd8156a --- /dev/null +++ b/src/CultMath/PlanetaryPatch.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 04651571f7d240a418c1f6aafa217fa6 \ No newline at end of file diff --git a/src/CultMath/PlanetaryProjection.cs b/src/CultMath/PlanetaryProjection.cs index f849fe20..a82ebfdb 100644 --- a/src/CultMath/PlanetaryProjection.cs +++ b/src/CultMath/PlanetaryProjection.cs @@ -1,3 +1,5 @@ +using System; + namespace CultMath; public enum PlanetaryProjectionKind diff --git a/src/CultMath/PlanetaryProjection.cs.meta b/src/CultMath/PlanetaryProjection.cs.meta new file mode 100644 index 00000000..7b1e6654 --- /dev/null +++ b/src/CultMath/PlanetaryProjection.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 5021202cf626f7442a57961255a8a217 \ No newline at end of file diff --git a/src/CultMath/PlanetaryQueries.cs b/src/CultMath/PlanetaryQueries.cs index 1f11ca77..54a9a3e9 100644 --- a/src/CultMath/PlanetaryQueries.cs +++ b/src/CultMath/PlanetaryQueries.cs @@ -1,3 +1,5 @@ +using System; + namespace CultMath; public readonly record struct PlanetaryRadialBounds(float MinimumDisplacement, float MaximumDisplacement) diff --git a/src/CultMath/PlanetaryQueries.cs.meta b/src/CultMath/PlanetaryQueries.cs.meta new file mode 100644 index 00000000..6fd11413 --- /dev/null +++ b/src/CultMath/PlanetaryQueries.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 2ec43c567214b8247bda19b5c120c200 \ No newline at end of file diff --git a/src/CultMath/PlanetaryRadialRefinement.cs.meta b/src/CultMath/PlanetaryRadialRefinement.cs.meta new file mode 100644 index 00000000..32af2655 --- /dev/null +++ b/src/CultMath/PlanetaryRadialRefinement.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 82e4db521edc253499220458b417fd1e \ No newline at end of file diff --git a/src/CultMath/PlanetaryResidency.cs b/src/CultMath/PlanetaryResidency.cs index e5dca115..6918ac57 100644 --- a/src/CultMath/PlanetaryResidency.cs +++ b/src/CultMath/PlanetaryResidency.cs @@ -1,3 +1,7 @@ +using System; +using System.Collections.Generic; +using System.Linq; + namespace CultMath; public readonly record struct PlanetaryLodParameters( @@ -71,9 +75,9 @@ public readonly record struct PlanetaryResidencySnapshot( /// Owns presentation residency only. It never owns field content. public sealed class PlanetaryResidualResidency { - private readonly Dictionary residents = []; - private readonly Dictionary arrivals = []; - private readonly Dictionary departures = []; + private readonly Dictionary residents = new(); + private readonly Dictionary arrivals = new(); + private readonly Dictionary departures = new(); private float lastTime = float.NegativeInfinity; public void Reset() diff --git a/src/CultMath/PlanetaryResidency.cs.meta b/src/CultMath/PlanetaryResidency.cs.meta new file mode 100644 index 00000000..24347624 --- /dev/null +++ b/src/CultMath/PlanetaryResidency.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 0585ea15edd7f1c4fa272df4911a8d6f \ No newline at end of file diff --git a/src/CultMath/PlanetaryTopology.cs b/src/CultMath/PlanetaryTopology.cs index c8535079..57d562cc 100644 --- a/src/CultMath/PlanetaryTopology.cs +++ b/src/CultMath/PlanetaryTopology.cs @@ -1,3 +1,5 @@ +using System; + namespace CultMath; public enum PlanetaryCubeFace @@ -104,6 +106,14 @@ public static class PlanetaryTopology return math.normalize(cube); } + public static float3 NormalizedCubeDirection(PlanetaryFaceCoordinate coordinate) + { + coordinate.Validate(allowOutsideFace: true); + var u = (float)coordinate.U; + var v = (float)coordinate.V; + return math.normalize(CubeVector(coordinate.Face, u, v)); + } + public static PlanetaryFaceCoordinate FaceCoordinate(float3 direction) { ValidateDirection(direction); @@ -156,6 +166,17 @@ public static class PlanetaryTopology MathF.Atan(cubeU) / QuarterPi, MathF.Atan(cubeV) / QuarterPi); + private static float3 CubeVector(PlanetaryCubeFace face, float u, float v) => face switch + { + PlanetaryCubeFace.PositiveX => new float3(1, v, -u), + PlanetaryCubeFace.NegativeX => new float3(-1, v, u), + PlanetaryCubeFace.PositiveY => new float3(u, 1, -v), + PlanetaryCubeFace.NegativeY => new float3(u, -1, v), + PlanetaryCubeFace.PositiveZ => new float3(u, v, 1), + PlanetaryCubeFace.NegativeZ => new float3(-u, v, -1), + _ => throw new ArgumentOutOfRangeException(nameof(face)), + }; + internal static void ValidateDirection(float3 direction) { ValidateFinite(direction, nameof(direction)); diff --git a/src/CultMath/PlanetaryTopology.cs.meta b/src/CultMath/PlanetaryTopology.cs.meta new file mode 100644 index 00000000..411a8bdb --- /dev/null +++ b/src/CultMath/PlanetaryTopology.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 88f6789c4384f7846ac4be37613fe5ed \ No newline at end of file diff --git a/src/CultMath/SphericalErosion.cs.meta b/src/CultMath/SphericalErosion.cs.meta new file mode 100644 index 00000000..82db7730 --- /dev/null +++ b/src/CultMath/SphericalErosion.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 59ec2db73065f6c4483ad90f5e17850e \ No newline at end of file diff --git a/tests/CultMath.Tests/AdvancedErosionFilterTests.cs.meta b/tests/CultMath.Tests/AdvancedErosionFilterTests.cs.meta new file mode 100644 index 00000000..253ee425 --- /dev/null +++ b/tests/CultMath.Tests/AdvancedErosionFilterTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a7c85309318ae3f4ba75ac28a4f661cf \ No newline at end of file diff --git a/tests/CultMath.Tests/ErosionFrequencyBandsTests.cs.meta b/tests/CultMath.Tests/ErosionFrequencyBandsTests.cs.meta new file mode 100644 index 00000000..ef15b7ee --- /dev/null +++ b/tests/CultMath.Tests/ErosionFrequencyBandsTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 095f8ed13d2f2f74baefd23310395256 \ No newline at end of file diff --git a/tests/CultMath.Tests/HlslMirrorTests.cs b/tests/CultMath.Tests/HlslMirrorTests.cs index 567b038b..5e1451cd 100644 --- a/tests/CultMath.Tests/HlslMirrorTests.cs +++ b/tests/CultMath.Tests/HlslMirrorTests.cs @@ -78,6 +78,8 @@ public sealed class HlslMirrorTests Assert.Contains("cultmath_planetary_field_sample", planetary); Assert.Contains("cultmath_planetary_equirectangular_forward", planetary); Assert.Contains("cultmath_planetary_equal_earth_forward", planetary); + Assert.Contains("cultmath_planetary_projection_forward", planetary); + Assert.Contains("cultmath_planetary_projection_inverse", planetary); Assert.Contains("CultMathPlanetarySurfaceSample", planetary); } diff --git a/tests/CultMath.Tests/PlanetaryFieldTests.cs.meta b/tests/CultMath.Tests/PlanetaryFieldTests.cs.meta new file mode 100644 index 00000000..1710b5ff --- /dev/null +++ b/tests/CultMath.Tests/PlanetaryFieldTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c747cfda80df21d41a57412d8d07c08a \ No newline at end of file diff --git a/tests/CultMath.Tests/PlanetaryGpuPageTests.cs b/tests/CultMath.Tests/PlanetaryGpuPageTests.cs new file mode 100644 index 00000000..ea17b4b9 --- /dev/null +++ b/tests/CultMath.Tests/PlanetaryGpuPageTests.cs @@ -0,0 +1,25 @@ +using Xunit; + +namespace CultMath.Tests; + +public sealed class PlanetaryGpuPageTests +{ + [Fact] + public void UploadContentUsesCanonicalDirectionsSpacingAndMetadata() + { + var layout = new PlanetaryPageLayout(new(PlanetaryCubeFace.NegativeY, 3, 4, 2), 9, 2); + var content = PlanetaryGpuPageBuilder.BuildContent(layout, 8.4f); + Assert.Equal(layout.StorageSize * layout.StorageSize, content.Inputs.Length); + Assert.True(content.ParentSampleSpacing > content.SampleSpacing); + var first = content.Inputs[0]; + Assert.Equal(PlanetaryPageSampling.Direction(layout, 0, 0), first.DirectionRadius.xyz); + Assert.Equal(8.4f, first.DirectionRadius.w); + Assert.Equal(content.SampleSpacing, first.Sampling.x); + Assert.Equal(content.ParentSampleSpacing, first.Sampling.y); + + var metadata = PlanetaryGpuPageBuilder.Metadata(content, 37, 0.25f); + Assert.Equal(new float4((int)layout.Tile.Face, layout.Tile.Level, layout.Tile.X, layout.Tile.Y), metadata.Address); + Assert.Equal(new float4(37, layout.StorageSize, layout.InteriorSize, layout.BorderSize), metadata.Layout); + Assert.Equal(0.25f, metadata.State.y); + } +} diff --git a/tests/CultMath.Tests/PlanetaryGpuPageTests.cs.meta b/tests/CultMath.Tests/PlanetaryGpuPageTests.cs.meta new file mode 100644 index 00000000..00f4a3a5 --- /dev/null +++ b/tests/CultMath.Tests/PlanetaryGpuPageTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 87266638e8010f546ab6c430a712868b \ No newline at end of file diff --git a/tests/CultMath.Tests/PlanetaryMapTileEncodingTests.cs b/tests/CultMath.Tests/PlanetaryMapTileEncodingTests.cs new file mode 100644 index 00000000..112cb31f --- /dev/null +++ b/tests/CultMath.Tests/PlanetaryMapTileEncodingTests.cs @@ -0,0 +1,52 @@ +using System.IO; +using Xunit; + +namespace CultMath.Tests; + +public sealed class PlanetaryMapTileEncodingTests +{ + [Fact] + public void BinaryTileRoundTripsIdentityValidityAndSurfaceEvidence() + { + var field = PlanetaryFieldDefinition.Create(5, 10, 3, AdvancedErosionParameters.Default); + var layout = new PlanetaryMapTileLayout(new(PlanetaryProjectionKind.EqualEarth), 1, 1, 0, 5, 1); + var key = new PlanetaryMapTileKey(field.FieldVersion, 2, 17, layout, PlanetaryQueryScale.AtFootprint(0.25f, 0.1f)); + var tile = PlanetaryMapTileBaker.Bake(field, key, new FlatField()); + using var bytes = new MemoryStream(); + PlanetaryMapTileEncoding.Write(bytes, tile, leaveOpen: true); + bytes.Position = 0; + var decoded = PlanetaryMapTileEncoding.Read(bytes); + + Assert.Equal(tile.Key, decoded.Key); + Assert.Equal(tile.Validity, decoded.Validity); + for (var i = 0; i < tile.Samples.Length; i++) + if (tile.Validity[i]) Assert.Equal(tile.Samples[i], decoded.Samples[i]); + } + + [Fact] + public void DecoderRejectsForeignMagicAndVersions() + { + Assert.Throws(() => PlanetaryMapTileEncoding.Read(new MemoryStream(new byte[] { 1, 2, 3, 4, 1, 0, 0, 0 }))); + var bytes = new byte[] { (byte)'C', (byte)'M', (byte)'P', (byte)'T', 99, 0, 0, 0 }; + Assert.Throws(() => PlanetaryMapTileEncoding.Read(new MemoryStream(bytes))); + } + + [Fact] + public void DecoderRejectsTrailingBytes() + { + var field = PlanetaryFieldDefinition.Create(2, 1, 0, AdvancedErosionParameters.Default); + var layout = new PlanetaryMapTileLayout(new(PlanetaryProjectionKind.Equirectangular), 0, 0, 0, 2, 0); + var key = new PlanetaryMapTileKey(field.FieldVersion, 1, 0, layout, PlanetaryQueryScale.AtFootprint(1)); + var tile = PlanetaryMapTileBaker.Bake(field, key, new FlatField()); + using var bytes = new MemoryStream(); + PlanetaryMapTileEncoding.Write(bytes, tile, leaveOpen: true); + bytes.WriteByte(0xff); + bytes.Position = 0; + Assert.Throws(() => PlanetaryMapTileEncoding.Read(bytes)); + } + + private readonly struct FlatField : IPlanetaryBaseField + { + public PlanetaryBaseFieldSample Sample(float3 direction) => new(0, float3.zero, 0, float3.zero, 0); + } +} diff --git a/tests/CultMath.Tests/PlanetaryMapTileEncodingTests.cs.meta b/tests/CultMath.Tests/PlanetaryMapTileEncodingTests.cs.meta new file mode 100644 index 00000000..027754e8 --- /dev/null +++ b/tests/CultMath.Tests/PlanetaryMapTileEncodingTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e916ef83478d48b43ac99777f5e0f731 \ No newline at end of file diff --git a/tests/CultMath.Tests/PlanetaryPageTests.cs.meta b/tests/CultMath.Tests/PlanetaryPageTests.cs.meta new file mode 100644 index 00000000..70a43864 --- /dev/null +++ b/tests/CultMath.Tests/PlanetaryPageTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7c3ae5598d3b9164a9bd3a736a22ba9a \ No newline at end of file diff --git a/tests/CultMath.Tests/PlanetaryPatchTests.cs.meta b/tests/CultMath.Tests/PlanetaryPatchTests.cs.meta new file mode 100644 index 00000000..85990473 --- /dev/null +++ b/tests/CultMath.Tests/PlanetaryPatchTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 36840ef44326f84409f850163b00e1f7 \ No newline at end of file diff --git a/tests/CultMath.Tests/PlanetaryProjectionTests.cs.meta b/tests/CultMath.Tests/PlanetaryProjectionTests.cs.meta new file mode 100644 index 00000000..7f37f78f --- /dev/null +++ b/tests/CultMath.Tests/PlanetaryProjectionTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f370036bb1663524fb4a4d47dfd50401 \ No newline at end of file diff --git a/tests/CultMath.Tests/PlanetaryQueryTests.cs.meta b/tests/CultMath.Tests/PlanetaryQueryTests.cs.meta new file mode 100644 index 00000000..d72b2cb6 --- /dev/null +++ b/tests/CultMath.Tests/PlanetaryQueryTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 93cf8771fdd520b41a4e931a6566a80a \ No newline at end of file diff --git a/tests/CultMath.Tests/PlanetaryRadialRefinementTests.cs.meta b/tests/CultMath.Tests/PlanetaryRadialRefinementTests.cs.meta new file mode 100644 index 00000000..b9f3bea9 --- /dev/null +++ b/tests/CultMath.Tests/PlanetaryRadialRefinementTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d34c0018ee2b700448b16540eca8ebcf \ No newline at end of file diff --git a/tests/CultMath.Tests/PlanetaryResidencyTests.cs.meta b/tests/CultMath.Tests/PlanetaryResidencyTests.cs.meta new file mode 100644 index 00000000..be7de2b4 --- /dev/null +++ b/tests/CultMath.Tests/PlanetaryResidencyTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9ece3b02dbd3d7448baabee7f1fba0ab \ No newline at end of file diff --git a/tests/CultMath.Tests/PlanetaryTopologyTests.cs b/tests/CultMath.Tests/PlanetaryTopologyTests.cs index 6e6b0838..759928d8 100644 --- a/tests/CultMath.Tests/PlanetaryTopologyTests.cs +++ b/tests/CultMath.Tests/PlanetaryTopologyTests.cs @@ -52,4 +52,12 @@ public sealed class PlanetaryTopologyTests Assert.NotEqual(edge, border); Assert.Equal(1, math.length(border), 5); } + + [Fact] + public void NormalizedCubeBaselineSharesFaceEdges() + { + var a = PlanetaryTopology.NormalizedCubeDirection(new(PlanetaryCubeFace.PositiveZ, 1, -0.4)); + var b = PlanetaryTopology.NormalizedCubeDirection(new(PlanetaryCubeFace.PositiveX, -1, -0.4)); + Assert.InRange(math.distance(a, b), 0, 1.0e-6f); + } } diff --git a/tests/CultMath.Tests/PlanetaryTopologyTests.cs.meta b/tests/CultMath.Tests/PlanetaryTopologyTests.cs.meta new file mode 100644 index 00000000..b6930142 --- /dev/null +++ b/tests/CultMath.Tests/PlanetaryTopologyTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: be3b0ec07fe65344db889d1e98448113 \ No newline at end of file diff --git a/tests/CultMath.Tests/SphericalErosionTests.cs.meta b/tests/CultMath.Tests/SphericalErosionTests.cs.meta new file mode 100644 index 00000000..00ff1de0 --- /dev/null +++ b/tests/CultMath.Tests/SphericalErosionTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 60eb9e9e9f8ae2948b13403f5080168e \ No newline at end of file diff --git a/tools/CultMath.PlanetaryTileFixture.meta b/tools/CultMath.PlanetaryTileFixture.meta new file mode 100644 index 00000000..7f40b6ae --- /dev/null +++ b/tools/CultMath.PlanetaryTileFixture.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7197a2202273a9445b974bdd69109b1a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/unity.meta b/unity.meta new file mode 100644 index 00000000..de47a618 --- /dev/null +++ b/unity.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 366efeaef9f68224b80229332c7ecfc6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/unity/Runtime.meta b/unity/Runtime.meta new file mode 100644 index 00000000..8e0678f8 --- /dev/null +++ b/unity/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8226365c03c5e1a438408b7e42b98740 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/unity/Runtime/CultMath.Unity.asmdef.meta b/unity/Runtime/CultMath.Unity.asmdef.meta new file mode 100644 index 00000000..2dd3a36a --- /dev/null +++ b/unity/Runtime/CultMath.Unity.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d1906c397c420ae4eb222a3f09f36843 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/unity/Runtime/PlanetaryPageUpload.cs b/unity/Runtime/PlanetaryPageUpload.cs index f0b168cd..1a61a707 100644 --- a/unity/Runtime/PlanetaryPageUpload.cs +++ b/unity/Runtime/PlanetaryPageUpload.cs @@ -36,12 +36,28 @@ public readonly struct PlanetaryPageMetadataGpu public readonly Vector4 State; } -public readonly record struct PlanetaryPageUpload( - PlanetaryPageInputGpu[] Inputs, - PlanetaryPageMetadataGpu[] Metadata, - int OutputSampleCount, - ulong ContentVersion, - ulong PresentationVersion); +public readonly struct PlanetaryPageUpload +{ + public PlanetaryPageUpload( + PlanetaryPageInputGpu[] inputs, + PlanetaryPageMetadataGpu[] metadata, + int outputSampleCount, + ulong contentVersion, + ulong presentationVersion) + { + Inputs = inputs; + Metadata = metadata; + OutputSampleCount = outputSampleCount; + ContentVersion = contentVersion; + PresentationVersion = presentationVersion; + } + + public PlanetaryPageInputGpu[] Inputs { get; } + public PlanetaryPageMetadataGpu[] Metadata { get; } + public int OutputSampleCount { get; } + public ulong ContentVersion { get; } + public ulong PresentationVersion { get; } +} public static class PlanetaryPageUploadBuilder { @@ -57,25 +73,23 @@ public static class PlanetaryPageUploadBuilder foreach (var (resident, pageIndex) in snapshot.Tiles.Select((resident, index) => (resident, index))) { var layout = new PlanetaryPageLayout(resident.Tile, interiorSize, borderSize).Validate(); - var spacing = PlanetaryPageSampling.NominalAngularTexelSize(layout) * radius; - var parentSpacing = resident.Tile.Level == 0 - ? 0 - : PlanetaryPageSampling.NominalAngularTexelSize(new(resident.Tile.Parent(), interiorSize, borderSize)) * radius; + var content = PlanetaryGpuPageBuilder.BuildContent(layout, radius); var outputOffset = inputs.Count; - for (var y = 0; y < layout.StorageSize; y++) - for (var x = 0; x < layout.StorageSize; x++) + foreach (var input in content.Inputs) { - var direction = PlanetaryPageSampling.Direction(layout, x, y); inputs.Add(new( - new Vector4(direction.x, direction.y, direction.z, radius), - new Vector4(spacing, parentSpacing, 0, 0))); + ToUnity(input.DirectionRadius), + ToUnity(input.Sampling))); } + var commonMetadata = PlanetaryGpuPageBuilder.Metadata(content, outputOffset, resident.Blend); metadata[pageIndex] = new( - new Vector4((int)resident.Tile.Face, resident.Tile.Level, resident.Tile.X, resident.Tile.Y), - new Vector4(outputOffset, layout.StorageSize, layout.InteriorSize, layout.BorderSize), - Vector4.zero, - new Vector4(1, resident.Blend, PlanetaryPageSampling.NominalAngularTexelSize(layout), spacing)); + ToUnity(commonMetadata.Address), + ToUnity(commonMetadata.Layout), + ToUnity(commonMetadata.Bounds), + ToUnity(commonMetadata.State)); } return new(inputs.ToArray(), metadata, inputs.Count, snapshot.ContentVersion, snapshot.PresentationVersion); } + + private static Vector4 ToUnity(float4 value) => new(value.x, value.y, value.z, value.w); } diff --git a/unity/Runtime/PlanetaryPageUpload.cs.meta b/unity/Runtime/PlanetaryPageUpload.cs.meta new file mode 100644 index 00000000..87bcb61a --- /dev/null +++ b/unity/Runtime/PlanetaryPageUpload.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7edd3bb2edb2e6448a2d54fc082c27dc \ No newline at end of file diff --git a/unity/Runtime/PlanetaryPatchMeshAdapter.cs.meta b/unity/Runtime/PlanetaryPatchMeshAdapter.cs.meta new file mode 100644 index 00000000..69af0abc --- /dev/null +++ b/unity/Runtime/PlanetaryPatchMeshAdapter.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9ad7b581e14ef774d8435069bb77ca6a \ No newline at end of file diff --git a/web.meta b/web.meta new file mode 100644 index 00000000..d65ff3e6 --- /dev/null +++ b/web.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: daf45471f8b5f4f44a2cb86e77e010db +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/web/planetary-tile.cross-runtime.test.mjs b/web/planetary-tile.cross-runtime.test.mjs new file mode 100644 index 00000000..2b457219 --- /dev/null +++ b/web/planetary-tile.cross-runtime.test.mjs @@ -0,0 +1,21 @@ +import assert from "node:assert/strict"; +import { readFile } from "node:fs/promises"; +import { decodePlanetarySurfaceTile } from "./planetary-tile.ts"; + +if (process.argv.length !== 3) throw new Error("Expected a generated CMPT fixture path"); +const bytes = await readFile(process.argv[2]); +const arrayBuffer = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength); +const tile = decodePlanetarySurfaceTile(arrayBuffer); +assert.equal(tile.header.projectionVersion, 3); +assert.equal(tile.header.layerId, 29); +assert.equal(tile.header.projectionKind, 2); +assert.equal(tile.header.interiorSize, 5); +assert.equal(tile.header.borderSize, 1); +assert.equal(tile.storageSize, 7); +assert.equal(tile.samples.length, 49); +assert.ok(tile.samples.some(sample => sample !== null)); +for (const sample of tile.samples) { + if (sample === null) continue; + assert.ok(Number.isFinite(sample.radialDisplacement)); + assert.ok(Number.isFinite(sample.unresolvedHeightBound)); +} diff --git a/web/planetary-tile.cross-runtime.test.mjs.meta b/web/planetary-tile.cross-runtime.test.mjs.meta new file mode 100644 index 00000000..3c38da54 --- /dev/null +++ b/web/planetary-tile.cross-runtime.test.mjs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7bc397e5660d2b6448919c41983d35e8 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/web/planetary-tile.test.mjs b/web/planetary-tile.test.mjs new file mode 100644 index 00000000..cb054f28 --- /dev/null +++ b/web/planetary-tile.test.mjs @@ -0,0 +1,39 @@ +import assert from "node:assert/strict"; +import { decodePlanetarySurfaceTile } from "./planetary-tile.ts"; + +const bytes = new ArrayBuffer(152); +const view = new DataView(bytes); +let offset = 0; +const u8 = value => view.setUint8(offset++, value); +const u32 = value => { view.setUint32(offset, value, true); offset += 4; }; +const i32 = value => { view.setInt32(offset, value, true); offset += 4; }; +const u64 = value => { view.setBigUint64(offset, value, true); offset += 8; }; +const f32 = value => { view.setFloat32(offset, value, true); offset += 4; }; +const f64 = value => { view.setFloat64(offset, value, true); offset += 8; }; + +for (const character of "CMPT") u8(character.charCodeAt(0)); +u32(1); u64(0x1234n); u32(2); u32(17); i32(0); +f64(0); f64(0); f64(1); +i32(0); i32(0); i32(0); i32(2); i32(0); +f32(10); f32(0.5); i32(4); +u8(1); +for (const value of [1, 0, 0]) f32(value); +f32(8.4); f32(0.25); +for (const value of [0, 0.1, 0]) f32(value); +for (const value of [0.99, -0.1, 0]) f32(value); +for (const value of [0.1, 0.8, 0.2, 2.5, 0.05]) f32(value); +u8(0); u8(0); u8(0); +assert.equal(offset, bytes.byteLength); + +const tile = decodePlanetarySurfaceTile(bytes); +assert.equal(tile.header.fieldVersion, 0x1234n); +assert.equal(tile.header.layerId, 17); +assert.equal(tile.storageSize, 2); +assert.equal(tile.samples.length, 4); +assert.equal(tile.samples[0]?.radialDisplacement, 0.25); +assert.equal(tile.samples[1], null); + +assert.throws(() => decodePlanetarySurfaceTile(bytes.slice(0, bytes.byteLength - 1)), /Truncated/); +const trailing = new Uint8Array(bytes.byteLength + 1); +trailing.set(new Uint8Array(bytes)); +assert.throws(() => decodePlanetarySurfaceTile(trailing.buffer), /trailing/); diff --git a/web/planetary-tile.test.mjs.meta b/web/planetary-tile.test.mjs.meta new file mode 100644 index 00000000..d622095b --- /dev/null +++ b/web/planetary-tile.test.mjs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 04c93ecab90d465499aa3d60722e6fc3 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/web/planetary-tile.ts b/web/planetary-tile.ts new file mode 100644 index 00000000..e68d70fa --- /dev/null +++ b/web/planetary-tile.ts @@ -0,0 +1,89 @@ +export const CULTMATH_PLANETARY_TILE_VERSION = 1; + +export interface PlanetaryTileHeader { + fieldVersion: bigint; + projectionVersion: number; + layerId: number; + projectionKind: number; + centerLongitude: number; + centerLatitude: number; + projectionScale: number; + level: number; + x: number; + y: number; + interiorSize: number; + borderSize: number; + footprintMeters: number; + maximumUnresolvedHeight: number; +} + +export interface PlanetaryTileSample { + direction: readonly [number, number, number]; + radius: number; + radialDisplacement: number; + tangentGradient: readonly [number, number, number]; + surfaceNormal: readonly [number, number, number]; + slope: number; + ridge: number; + gully: number; + finestResolvedWavelength: number; + unresolvedHeightBound: number; +} + +export interface PlanetarySurfaceTile { + header: PlanetaryTileHeader; + storageSize: number; + samples: readonly (PlanetaryTileSample | null)[]; +} + +export function decodePlanetarySurfaceTile(bytes: ArrayBuffer): PlanetarySurfaceTile { + const view = new DataView(bytes); + let offset = 0; + const u8 = () => view.getUint8(offset++); + const u32 = () => { const value = view.getUint32(offset, true); offset += 4; return value; }; + const i32 = () => { const value = view.getInt32(offset, true); offset += 4; return value; }; + const f32 = () => { const value = view.getFloat32(offset, true); offset += 4; return value; }; + const f64 = () => { const value = view.getFloat64(offset, true); offset += 8; return value; }; + const u64 = () => { const value = view.getBigUint64(offset, true); offset += 8; return value; }; + const vector3 = (): [number, number, number] => [f32(), f32(), f32()]; + const requireRemaining = (count: number) => { + if (offset + count > view.byteLength) throw new Error("Truncated CultMath planetary tile"); + }; + + requireRemaining(8); + if (String.fromCharCode(u8(), u8(), u8(), u8()) !== "CMPT") throw new Error("Not a CultMath planetary tile"); + const version = u32(); + if (version !== CULTMATH_PLANETARY_TILE_VERSION) throw new Error(`Unsupported CultMath planetary tile version ${version}`); + requireRemaining(76); + const header: PlanetaryTileHeader = { + fieldVersion: u64(), + projectionVersion: u32(), + layerId: u32(), + projectionKind: i32(), + centerLongitude: f64(), + centerLatitude: f64(), + projectionScale: f64(), + level: i32(), x: i32(), y: i32(), interiorSize: i32(), borderSize: i32(), + footprintMeters: f32(), maximumUnresolvedHeight: f32(), + }; + const count = i32(); + const storageSize = header.interiorSize + header.borderSize * 2; + if (count !== storageSize * storageSize) throw new Error("CultMath planetary tile sample count does not match layout"); + const samples: (PlanetaryTileSample | null)[] = new Array(count); + for (let index = 0; index < count; index++) { + requireRemaining(1); + if (u8() === 0) { samples[index] = null; continue; } + requireRemaining(64); + samples[index] = { + direction: vector3(), + radius: f32(), + radialDisplacement: f32(), + tangentGradient: vector3(), + surfaceNormal: vector3(), + slope: f32(), ridge: f32(), gully: f32(), + finestResolvedWavelength: f32(), unresolvedHeightBound: f32(), + }; + } + if (offset !== view.byteLength) throw new Error("CultMath planetary tile has trailing bytes"); + return { header, storageSize, samples }; +} diff --git a/web/planetary-tile.ts.meta b/web/planetary-tile.ts.meta new file mode 100644 index 00000000..337da3bd --- /dev/null +++ b/web/planetary-tile.ts.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f284e64628320844196b7aaea76475a4 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From 929527853113b01bd7404910510fd435f79f5cd6 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 13 Jul 2026 17:30:08 +0100 Subject: [PATCH 017/283] Return RUDP application receipts --- packages/cultmesh-ts/src/index.ts | 63 +++++++++++++++++++++- packages/cultmesh-ts/test/cultmesh.test.ts | 30 +++++++++++ 2 files changed, 91 insertions(+), 2 deletions(-) diff --git a/packages/cultmesh-ts/src/index.ts b/packages/cultmesh-ts/src/index.ts index c61dfee1..687f9b8a 100644 --- a/packages/cultmesh-ts/src/index.ts +++ b/packages/cultmesh-ts/src/index.ts @@ -4088,11 +4088,25 @@ export interface CultMeshRudpDocumentPut { }; } +export interface CultMeshRudpDocumentReceipt { + binding: CultNetDocumentBinding; + recordKey: string; + value: CultCacheDocumentValue; + messageId?: string; + sourceRuntimeId?: string; + sourceAgentId?: string; + sourceRole?: string; + tags?: string[]; +} + export interface CultMeshRudpDocumentServerOptions extends CultMeshRudpSocketOptions { documents: CultNetDocumentRegistry; getCache?: () => Promise | CultCache; onError?: (error: Error) => void; - onDocumentPutRaw?: (document: CultMeshRudpDocumentPut) => void | Promise; + onDocumentPutRaw?: (document: CultMeshRudpDocumentPut) => + | CultMeshRudpDocumentReceipt + | void + | Promise; wireContract?: CultNetWireContract; sessionTimeoutMs?: number; } @@ -4112,6 +4126,10 @@ export interface CultMeshRudpDocumentPublishOptions extends CultMeshRudpPeerOpti flushTimeoutMs?: number; } +export interface CultMeshRudpDocumentReceiptOptions extends CultMeshRudpDocumentPublishOptions { + receiptTimeoutMs?: number; +} + export interface CultMeshRudpEndpoint { host: string; port: number; @@ -5638,7 +5656,18 @@ export class CultMesh { return; case "cultnet.document_put_raw.v0": if (options.onDocumentPutRaw) { - await options.onDocumentPutRaw(normalizeRudpDocumentPut(message, record.remote)); + const receipt = await options.onDocumentPutRaw(normalizeRudpDocumentPut(message, record.remote)); + if (receipt) { + sendSchemaMessage(record, options.documents.createRawDocumentPutMessage( + receipt.binding, receipt.messageId ?? message.messageId, receipt.recordKey, receipt.value, + { + sourceRuntimeId: receipt.sourceRuntimeId ?? runtimeId, + sourceAgentId: receipt.sourceAgentId, + sourceRole: receipt.sourceRole ?? "provider", + tags: receipt.tags ?? ["receipt"], + }, + )); + } } return; default: @@ -5753,6 +5782,36 @@ export class CultMesh { } } + public static async publishRudpDocumentAndWaitForReceipt( + runtimeId: string, connectionId: number, endpoint: string | CultMeshRudpEndpoint, + binding: CultNetDocumentBinding, recordKey: string, value: CultCacheDocumentValue, + receiptBinding: CultNetDocumentBinding, options: CultMeshRudpDocumentReceiptOptions = {}, + ): Promise> { + requireNonEmpty(runtimeId, "runtimeId"); + requireNonEmpty(recordKey, "recordKey"); + const messageId = options.messageId ?? `${runtimeId}:${binding.definition.type}:${recordKey}`; + const peer = await CultMesh.createRudpPeer(runtimeId, connectionId, endpoint, options); + try { + const receipt = new Promise>((resolve, reject) => { + const timeout = setTimeout(() => { cleanup(); reject(new Error(`Timed out waiting for RUDP application receipt for ${recordKey}.`)); }, options.receiptTimeoutMs ?? 5_000); + const onMessage = (message: CultNetMessage): void => { + if (message.schemaVersion !== "cultnet.document_put_raw.v0" || message.messageId !== messageId || message.document.schemaId !== receiptBinding.definition.schemaId) return; + try { + const decoded = decode(new Uint8Array(message.document.payload)); + cleanup(); + resolve(receiptBinding.definition.schema.parse(decoded) as CultCacheDocumentValue); + } catch (error) { cleanup(); reject(error); } + }; + const cleanup = (): void => { clearTimeout(timeout); peer.off("message", onMessage); }; + peer.on("message", onMessage); + }); + peer.send(new CultNetDocumentRegistry([binding]).createRawDocumentPutMessage(binding, messageId, recordKey, value, { + sourceRuntimeId: options.sourceRuntimeId ?? runtimeId, sourceAgentId: options.sourceAgentId, sourceRole: options.sourceRole, tags: options.tags, + })); + return await receipt; + } finally { peer.close(); } + } + public static async createRudpServer( runtimeId: string, connectionId: number, diff --git a/packages/cultmesh-ts/test/cultmesh.test.ts b/packages/cultmesh-ts/test/cultmesh.test.ts index f4e8f9cc..285ee09d 100644 --- a/packages/cultmesh-ts/test/cultmesh.test.ts +++ b/packages/cultmesh-ts/test/cultmesh.test.ts @@ -34,6 +34,13 @@ const noteAliasDocument = defineDocumentType({ name: "noteId", }); +const noteReceiptDocument = defineDocumentType({ + type: "cultmesh.note_receipt", + schemaId: "cultmesh.note_receipt.v0", + schema: z.object({ commandId: z.string(), state: z.literal("applied"), body: z.string() }), + name: "commandId", +}); + const foreignNoteDocument = defineDocumentType({ type: "runtime.generated.cultmesh.note", schemaId: "runtime.generated.cultmesh.note.ui.42", @@ -2568,6 +2575,29 @@ test("CultMesh TS publishes one registered document to a RUDP catalog", async () } }); +test("CultMesh TS returns a correlated provider receipt after a RUDP document mutation", async () => { + const connectionId = 0x10203050; + const commandBinding = defineCultNetDocumentBinding({ definition: noteDocument }); + const receiptBinding = defineCultNetDocumentBinding({ definition: noteReceiptDocument }); + const server = CultMesh.createRudpDocumentServer("cultmesh-ts-receipt-server", connectionId, { + documents: new CultNetDocumentRegistry([commandBinding, receiptBinding]), bindHost: "127.0.0.1", bindPort: 0, + resendDelayMs: 25, resendPollMs: 5, + onDocumentPutRaw: async (document) => ({ + binding: receiptBinding, recordKey: document.recordKey, + value: { commandId: document.recordKey, state: "applied", body: (document.payload as { body: string }).body }, + }), + }); + try { + await server.start(); + const receipt = await CultMesh.publishRudpDocumentAndWaitForReceipt( + "cultmesh-ts-receipt-client", connectionId, `rudp://127.0.0.1:${server.bind.port}`, + commandBinding, "command:note", { noteId: "command:note", body: "provider applied this" }, receiptBinding, + { messageId: "command:note", receiptTimeoutMs: 1_000, resendPollMs: 5 }, + ); + assert.deepEqual(receipt, { commandId: "command:note", state: "applied", body: "provider applied this" }); + } finally { server.close(); } +}); + test("CultMesh TS reads remote RUDP snapshots through document handles", async () => { const connectionId = 0x10203048; const node = await CultMesh.startNode( From cb481b4c75444426a693781a0e5b35ade08a8938 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Fri, 17 Jul 2026 07:45:28 +0100 Subject: [PATCH 018/283] Add Unity-compatible simplex noise semantics --- THIRD-PARTY-NOTICES.md | 10 ++++++ shaders/CultMath.hlsl | 36 ++++++++++++++++++++ src/CultMath/math.cs | 44 +++++++++++++++++++++++++ tests/CultMath.Tests/HlslMirrorTests.cs | 1 + tests/CultMath.Tests/MathTests.cs | 10 ++++++ 5 files changed, 101 insertions(+) diff --git a/THIRD-PARTY-NOTICES.md b/THIRD-PARTY-NOTICES.md index 8339c5fe..54e280f6 100644 --- a/THIRD-PARTY-NOTICES.md +++ b/THIRD-PARTY-NOTICES.md @@ -1,5 +1,15 @@ # Third-Party Notices +## 2D Simplex Noise + +`math.simplex_noise` and `cultmath_simplex_noise` port the textureless 2D +simplex-noise function by Ian McEwan and Ashima Arts, as distributed by Stefan +Gustavson's `webgl-noise` project and Unity Mathematics. + +- Copyright 2011 Ashima Arts. +- Upstream: +- License: MIT. + ## Advanced Terrain Erosion Filter `src/CultMath/AdvancedErosionFilter.cs` and diff --git a/shaders/CultMath.hlsl b/shaders/CultMath.hlsl index cf76c8c2..84d244bb 100644 --- a/shaders/CultMath.hlsl +++ b/shaders/CultMath.hlsl @@ -73,6 +73,42 @@ float cultmath_smootherstep(float value) return value * value * value * (value * (value * 6.0 - 15.0) + 10.0); } +float2 cultmath_simplex_mod289(float2 value) { return value - floor(value * (1.0 / 289.0)) * 289.0; } +float3 cultmath_simplex_mod289(float3 value) { return value - floor(value * (1.0 / 289.0)) * 289.0; } +float3 cultmath_simplex_permute(float3 value) { return cultmath_simplex_mod289(((value * 34.0) + 1.0) * value); } + +float cultmath_simplex_noise(float2 value) +{ + const float4 c = float4( + 0.211324865405187, + 0.366025403784439, + -0.577350269189626, + 0.024390243902439); + float2 i = floor(value + dot(value, c.yy)); + float2 x0 = value - i + dot(i, c.xx); + float2 i1 = x0.x > x0.y ? float2(1.0, 0.0) : float2(0.0, 1.0); + float4 x12 = float4(x0.x + c.x - i1.x, x0.y + c.x - i1.y, x0.x + c.z, x0.y + c.z); + + i = cultmath_simplex_mod289(i); + float3 p = cultmath_simplex_permute( + cultmath_simplex_permute(i.y + float3(0.0, i1.y, 1.0)) + i.x + float3(0.0, i1.x, 1.0)); + float3 m = max(0.5 - float3(dot(x0, x0), dot(x12.xy, x12.xy), dot(x12.zw, x12.zw)), 0.0); + m *= m; + m *= m; + + float3 x = 2.0 * frac(p * c.w) - 1.0; + float3 h = abs(x) - 0.5; + float3 ox = floor(x + 0.5); + float3 a0 = x - ox; + m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h); + + float3 g = float3( + a0.x * x0.x + h.x * x0.y, + a0.y * x12.x + h.y * x12.y, + a0.z * x12.z + h.z * x12.w); + return 130.0 * dot(m, g); +} + float cultmath_lengthsq(float2 value) { return dot(value, value); } float cultmath_lengthsq(float3 value) { return dot(value, value); } float cultmath_lengthsq(float4 value) { return dot(value, value); } diff --git a/src/CultMath/math.cs b/src/CultMath/math.cs index 874554ad..e15fbf08 100644 --- a/src/CultMath/math.cs +++ b/src/CultMath/math.cs @@ -327,6 +327,50 @@ public static class math public static float hash(float2 value) => hash(dot(value, new float2(127.1f, 311.7f))); public static float hash(float3 value) => hash(dot(value, new float3(127.1f, 311.7f, 74.7f))); + // Ashima Arts / Ian McEwan 2D simplex noise, kept component-explicit so + // the C# and HLSL mirrors preserve the same float32 evaluation order. + public static float simplex_noise(float2 value) + { + var c = new float4( + 0.211324865405187f, + 0.366025403784439f, + -0.577350269189626f, + 0.024390243902439f); + var i = floor(value + dot(value, new float2(c.y, c.y))); + var x0 = value - i + dot(i, new float2(c.x, c.x)); + var i1 = x0.x > x0.y ? new float2(1.0f, 0.0f) : new float2(0.0f, 1.0f); + var x12 = new float4( + x0.x + c.x - i1.x, + x0.y + c.x - i1.y, + x0.x + c.z, + x0.y + c.z); + + i = simplex_mod289(i); + var p = simplex_permute(simplex_permute(i.y + new float3(0.0f, i1.y, 1.0f)) + i.x + new float3(0.0f, i1.x, 1.0f)); + var m = max(0.5f - new float3( + dot(x0, x0), + x12.x * x12.x + x12.y * x12.y, + x12.z * x12.z + x12.w * x12.w), 0.0f); + m = m * m; + m = m * m; + + var x = 2.0f * frac(p * c.w) - 1.0f; + var h = abs(x) - 0.5f; + var ox = floor(x + 0.5f); + var a0 = x - ox; + m *= 1.79284291400159f - 0.85373472095314f * (a0 * a0 + h * h); + + var g = new float3( + a0.x * x0.x + h.x * x0.y, + a0.y * x12.x + h.y * x12.y, + a0.z * x12.z + h.z * x12.w); + return 130.0f * dot(m, g); + } + + private static float2 simplex_mod289(float2 value) => value - floor(value * (1.0f / 289.0f)) * 289.0f; + private static float3 simplex_mod289(float3 value) => value - floor(value * (1.0f / 289.0f)) * 289.0f; + private static float3 simplex_permute(float3 value) => simplex_mod289(((value * 34.0f) + 1.0f) * value); + public static float value_noise(float2 position) { var cell = floor(position); diff --git a/tests/CultMath.Tests/HlslMirrorTests.cs b/tests/CultMath.Tests/HlslMirrorTests.cs index 5e1451cd..47f58971 100644 --- a/tests/CultMath.Tests/HlslMirrorTests.cs +++ b/tests/CultMath.Tests/HlslMirrorTests.cs @@ -51,6 +51,7 @@ public sealed class HlslMirrorTests "cultmath_cubic_bezier", "cultmath_hash", "cultmath_value_noise", + "cultmath_simplex_noise", "cultmath_value_noise_bicubic", "cultmath_value_noise_texture", "cultmath_value_noise_texture_bicubic", diff --git a/tests/CultMath.Tests/MathTests.cs b/tests/CultMath.Tests/MathTests.cs index bb816d47..6979bdd6 100644 --- a/tests/CultMath.Tests/MathTests.cs +++ b/tests/CultMath.Tests/MathTests.cs @@ -235,6 +235,16 @@ public sealed class MathTests Assert.True(bicubic > -0.25f && bicubic < 1.25f); } + [Theory] + [InlineData(0.0f, 0.0f, 0.0f)] + [InlineData(0.25f, -0.5f, -0.425866783f)] + [InlineData(12.25f, -4.5f, 0.258312f)] + [InlineData(536.5106f, 536.5106f, -0.6901103f)] + public void SimplexNoiseMatchesUnityMathematics(float x, float y, float expected) + { + Assert.Equal(expected, math.simplex_noise(new float2(x, y)), precision: 6); + } + [Fact] public void VoronoiBatchProducesToneMappedColors() { From 13e8c56f5f9cdda892752695ebbc54ba36e06a29 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 02:26:02 +0100 Subject: [PATCH 019/283] Plan geometry ownership migration --- ...ltmath-gamecult-geometry-migration-plan.md | 552 ++++++++++++++++++ 1 file changed, 552 insertions(+) create mode 100644 docs/cultmath-gamecult-geometry-migration-plan.md diff --git a/docs/cultmath-gamecult-geometry-migration-plan.md b/docs/cultmath-gamecult-geometry-migration-plan.md new file mode 100644 index 00000000..e8e961c4 --- /dev/null +++ b/docs/cultmath-gamecult-geometry-migration-plan.md @@ -0,0 +1,552 @@ +# CultMath and GameCult.Geometry Staged Migration Plan + +Status: proposed for execution + +Date: 2026-07-22 + +## Decision + +`GameCult.Geometry` is the sole owner of geometric meaning and geometry +machinery. It builds on CultMath numeric primitives and participates in +CultCache, CultNet, and CultMesh through the normal CultLib integration paths. + +CultMath owns the HLSL-shaped numeric substrate: scalar operations, vectors, +quaternions, and general numeric kernels that have no spatial domain authority. +It does not own regions, topology, projections, surfaces, planetary fields, +patches, geometry residency, meshes, or geometry workflow state. + +VibeGeometry and `vg-csg` are sources to mine. They are not surviving owners or +dependencies. + +Source transfer does not erase provenance. CultMath is MPL-2.0 and CultLib is +MIT-licensed; moved files require an explicit licensing decision and preserved +notices before they enter a differently licensed package. + +## Objective + +Produce one coherent geometry stack in which: + +- consumers use `CultMath.float2`, `float3`, and `float4` as the canonical + floating-point vector primitives; +- `GameCult.Geometry` owns reusable geometry, planetary geometry, CSG, mesh + production, spatial queries, and the typed documents that coordinate those + systems; +- CultMath no longer publishes planetary or other geometry-owned APIs; +- `CultVec2` and `CultVec3` no longer exist; +- VibeGeometry can be archived after its useful implementation, evidence, and + doctrine have been absorbed; +- persisted geometry remains readable through an explicit migration path when + a live persisted corpus requires one. + +## Authority Map + +| Organ | Owns | Does not own | +| --- | --- | --- | +| CultMath | `float2`, `float3`, `float4`, integer/double/bool vector primitives, quaternion algebra, scalar and component-wise intrinsics, coordinate-agnostic numeric kernels, CPU/HLSL parity for those primitives | Rectangles, spheres, topology, projections, planetary fields, geometry pages, meshes, CSG, persistence schemas, worker commands | +| GameCult.Geometry | Spatial value types built from CultMath primitives, spatial queries, topology and projection, planetary field and page machinery, mesh and CSG implementation, geometry schema documents, stable geometry identities, geometry-specific HLSL and cross-runtime fixtures | Competing vector types, generic storage/network ownership, application gameplay consequences | +| CultCache/CultNet/CultMesh | Typed persistence, schema resolution, transport, discovery, publication, commands, and interface projection | Geometry semantics or geometry algorithm ownership | +| VibeGeometry / `vg-csg` | Nothing after migration | Any live runtime, schema, package, or compatibility authority | + +Authority sentence: + +> CultMath owns how numeric primitives behave; GameCult.Geometry owns what those +> primitives mean in space. + +## Current Mechanism + +The live body is split across three places: + +1. CultMath publishes the canonical HLSL-shaped vector types, but also contains + `rect`, planetary topology/projection/field/page/residency systems, spherical + erosion, planetary HLSL, Unity adapters, web fixtures, and planetary tools. +2. `GameCult.Geometry` contains duplicate `CultVec2` and `CultVec3` values, + geometric primitives, and four CultCache document roots. Its document + members still encode many vectors, bounds, transforms, vertices, normals, + and UVs as anonymous `float[]` values. +3. VibeGeometry wraps the `vg-csg` Rust implementation for domain-tree intent, + LOD-aware selected cuts, CSG lowering, and triangle/collider output. + +CultCache's current managed SoA projection only admits primitive scalar members. +It neither preserves arbitrary unmanaged structs as columns nor recursively +splits them. A `float2` or `float3` member is therefore omitted from the SoA +until that storage seam is repaired. + +## Invariants + +The migration must preserve these statements at every published boundary: + +1. There is one canonical vector vocabulary: CultMath's HLSL-shaped primitive + types. +2. Geometry algorithms and geometry state have one owner: `GameCult.Geometry`. +3. CultMath never depends on CultLib, CultCache, MessagePack, or + `GameCult.Geometry`. +4. `GameCult.Geometry` may depend on CultMath and CultLib. +5. Persistence decoration and formatters do not contaminate CultMath primitive + definitions. +6. A geometry schema has one active writer. Legacy readers or offline + migrators may exist temporarily, but they cannot decide live behavior. +7. Record keys and stable fingerprints are identical across supported runtimes + for the same semantic geometry value. +8. SoA storage preserves each authored unmanaged member as one column of its + exact type. It never decomposes `float2`, `float3`, quaternion, or another + value type by reflection. +9. CPU, HLSL, Unity, web, and Rust fixtures compare the same claimed layer of + geometry behavior. +10. VibeGeometry is not retained as a wrapper, submodule, compatibility crate, + or second source of truth. + +## Target Package Shape + +The exact directory names may follow existing CultLib conventions, but the +ownership should lower into these runtime surfaces: + +```text +CultMath + C# and Unity numeric primitives + CultMath.hlsl numeric mirror + coordinate-agnostic native numeric kernels + +CultLib + src/GameCult.Geometry/ + C# geometry API + planetary geometry + CultCache document contracts and formatters + geometry-specific HLSL packaged as content + packages/gamecult-geometry-rs/ + Rust geometry, CSG, and cross-runtime fixtures + packages/gamecult-geometry-ts/ # only if the web runtime remains earned + web projection/tile helpers and parity fixtures + src/GameCult.Unity/Assets/Geometry/ # Unity-owned lowering/adapters + mesh/page upload and presentation adapters + Packages/org.gamecult.geometry/ # final location follows packaging audit + Unity package depending on CultMath and CultLib +``` + +The runtime directories are projections of one geometry authority. They are not +independent products allowed to invent their own vector, topology, schema, or +fingerprint semantics. + +Each stage is a commit/review boundary. Do not begin the next stage until the +current gate passes, and never publish a state in which both repositories claim +the same geometry authority. + +## Source Classification + +### Keep in CultMath + +- HLSL-shaped primitive types such as `float2`, `float3`, and `float4`. +- Integer, double, and boolean vector primitives. +- Quaternion algebra. +- `math` scalar/component-wise operations and the core `CultMath.hlsl` mirror. +- Numeric batch kernels whose contracts are independent of regions, topology, + surfaces, planets, meshes, CSG, rendering policy, and persistence. + +### Move from CultMath to GameCult.Geometry + +The initial move set is: + +- `rect` and other spatial-region values; +- `PlanetaryTopology`; +- `PlanetaryProjection`; +- `PlanetaryQueries`; +- `PlanetaryPatch`; +- `PlanetaryPages`; +- `PlanetaryGpuPages`; +- `PlanetaryResidency`; +- `PlanetaryRadialRefinement`; +- `PlanetaryMapTileEncoding`; +- `PlanetaryField`; +- `AdvancedErosionFilter`; +- `ErosionFrequencyBands`; +- `SphericalErosion`; +- `AdvancedErosionFilter.hlsl`; +- `Planetary.hlsl`; +- spherical-erosion and planetary-radial-refinement shader bodies currently + embedded in `CultMath.hlsl`; +- the versioned `CMPT` planetary tile format and its TypeScript decoder; +- planetary tests, docs, tools, Unity adapters, web fixtures, and samples. + +`AdvancedErosionFilter` and `ErosionFrequencyBands` move with planetary +geometry. Their public contracts encode terrain-field policy, they are direct +dependencies of the planetary field definition, and their HLSL is coupled to +that field. Voronoi tone rendering and `native/cultmath-core` are outside this +migration: the native crate currently owns only that tone kernel and has no +planetary implementation. Audit those separately rather than dragging them +across this boundary because their names look spatial. + +### Rebuild inside GameCult.Geometry + +- Make `CultRect`, `CultCircle`, and `CultSphere` the GameCult.Geometry-owned + spatial values, implemented over CultMath primitives, and delete + `CultMath.rect` at cutover. +- Replace `CultVec2` and `CultVec3` with `float2` and `float3` at every typed + boundary. +- Replace vector-shaped `float[]` document members with typed CultMath values or + intentional packed buffers. +- Keep packed mesh buffers packed when they are genuinely bulk artifact storage; + do not turn every vertex buffer into a forest of object wrappers. +- Put MessagePack/CultCache formatters for CultMath values in the integration + package or generated formatter output, not on the CultMath types. + +### Mine from VibeGeometry and `vg-csg` + +Evaluate and extract, in dependency order: + +- convex plane splitting and brush operations; +- CSG tree and ordered operation semantics; +- domain-tree DSL and lowering; +- dirty-frontier and prefix-checkpoint work; +- selected-cut and LOD planning; +- triangle/collider assembly; +- performance fixtures and parity evidence; +- useful RealtimeCSG-derived behavioral fixtures; +- runtime doctrine that still describes the adopted machine. + +Rewrite extracted code under GameCult.Geometry ownership. Preserve third-party +license notices and source provenance. Do not retain a `vg-csg` forwarding +crate or a VibeGeometry submodule after consumers have moved. + +## Staged Migration + +### Stage 0: Freeze and Baseline + +Purpose: establish the evidence needed to move authority without guessing. + +Work: + +- Freeze new planetary and geometry API additions in CultMath, VibeGeometry, + and the current duplicate primitive surface. +- Do not publish an intermediate release containing duplicate live planetary + implementations. A coordinated working branch may hold source temporarily + for comparison, but only one owner may enter a package feed. +- Inventory public symbols, package versions, HLSL entrypoints, Unity samples, + web fixtures, native exports, persisted schema IDs, record-key algorithms, + and known consumers. +- Inventory exact contract constants: `FieldVersion`, enum ordinals, tile stable + keys, `CMPT` versions and bytes, MessagePack slots, GPU buffer layouts, + integer hashes, topology face/seam/corner rules, and shader include paths. +- Search deployed and checked-in `.cc` stores for the four + `gamecult.geometry.*.v1` schemas. +- Record whether any external consumer relies on CultMath planetary namespaces, + `CultVec*`, `CultMath.rect`, `vg-csg`, or the current HLSL function names. +- Capture passing baselines for CultMath tests, GameCult.Geometry tests, + `vg-csg` tests/clippy, cross-runtime planetary fixtures, and package builds. +- Add representative fixture hashes for projection, topology, field sampling, + patch selection, page encoding, CSG output, and geometry record keys. +- Resolve licensing and provenance for MPL-2.0 CultMath sources and any + third-party-derived `vg-csg` behavior before copying source into CultLib. + +Gate: + +- Every published surface has a named consumer or is marked for deletion. +- The persisted v1 corpus is known rather than assumed. +- Baseline fixtures can be run without booting an entire daemon. + +### Stage 1: Establish the Destination and Dependency Direction + +Purpose: make `GameCult.Geometry` capable of receiving geometry without growing +a second primitive vocabulary. + +Work: + +- Add the explicit `GameCult.Geometry -> CultMath` dependency. +- Define the target namespaces and package content layout for C#, Rust, HLSL, + Unity, and any retained web surface. +- Establish distribution before source transfer: an explicit NuGet dependency + and a dedicated `org.gamecult.geometry` Unity package depending on + `org.gamecult.cultmath` and `org.gamecult.cultlib`, unless package inspection + proves an existing surface already owns that role. +- Retain `net8.0` and `netstandard2.1` targets and Unity 2021.3 compatibility. + The geometry asmdef references CultMath; the Unity lowering assembly + references both. CultMath's asmdef remains reference-free with + `noEngineReferences: true`. +- Add GameCult.Geometry-owned MessagePack formatters for `float2`, `float3`, + `float4`, and quaternion with fixed positional layouts. +- Add cross-runtime byte fixtures for those value encodings. +- Repair CultCache's SoA member discovery so any direct unmanaged member is one + exact typed column. Add `Column` and `Column` tests and a + negative test proving no scalar decomposition occurs. +- Ensure generated schema metadata describes the authored vector member rather + than synthetic x/y/z members. + +Gate: + +- CultMath has no new dependency. +- `GameCult.Geometry` can serialize, deserialize, index, and expose intact + CultMath vectors. +- CultCache hot-path access returns intact vector spans. +- Built NuGet and UPM artifacts contain the expected dependency metadata, + formatters, shaders, and owned runtime assets. + +### Stage 2: Replace Duplicate Primitives and Repair Geometry Schemas + +Purpose: remove the duplicate vocabulary before moving larger geometry systems. + +Work: + +- Rewrite `CultRect`, `CultCircle`, and `CultSphere` with CultMath primitives. +- Delete `CultVec2` and `CultVec3`; do not add aliases or conversion wrappers. +- Replace typed references and opaque native-slice metadata using the obsolete + names. +- Classify every vector-shaped `float[]` in `CultGeometryDocuments.cs`: + - `Translation`, `SupportCenter`, `SupportSize`, `CameraPosition`, + `FrustumMin`, `FrustumMax`, `BoundsMin`, and `BoundsMax` become `float3`; + - `RotationXyzw` becomes quaternion; + - mesh `Positions` and `Normals` become `float3[]`; + - mesh `Uvs` becomes `float2[]`; + - scalar and index buffers remain packed arrays; + - use a named geometry value when bounds/topology carries an invariant. +- Define v2 schemas for every document whose field types change. CultCache + includes CLR type identity in the canonical schema and must reject an in-place + slot type mutation even when no durable v1 corpus is found. +- If live v1 documents exist, add bounded v1 reader DTOs and an offline + v1-to-v2 migrator. Stop all v1 writers at cutover. If no live persisted corpus + exists, omit the migrator and delete v1 runtime support, but still publish the + corrected contract under v2 identity. +- Reject malformed legacy vectors: fixed vectors must have the exact expected + component count, while packed mesh streams must be divisible by their element + width before conversion. +- Recompute and cross-check stable fingerprints and record keys against Rust + fixtures before accepting the new schemas. Preserve an old record key only + when the typed representation reproduces the prior IEEE-bit canonicalization + exactly; otherwise version the identity deliberately. +- Use CultMath's lowercase component names in v2 JSON inspection projections. + JSON is not the runtime transport, and uppercase `X/Y/Z` aliases must not keep + the deleted vector vocabulary alive. Any xenos-facing alternate casing is an + explicit boundary projection. + +Gate: + +- Repository-wide searches find no `CultVec2` or `CultVec3` outside historical + evidence. +- Repository and package searches find no `CultMath.rect`. +- No live writer emits vector-shaped anonymous arrays for semantic single + values. +- The old schema cannot overwrite, repair, or become a second owner of v2 + state. + +### Stage 3: Transfer Planetary Geometry out of CultMath + +Purpose: move planetary authority as one coherent vertical slice. + +Work: + +- Move the classified planetary C# implementation and tests into + `GameCult.Geometry`. +- Move `Planetary.hlsl` and rename its include ownership and public entrypoints + to GameCult.Geometry. It may include CultMath numeric HLSL; CultMath must no + longer include planetary geometry. Remove the current implicit planetary + include from `CultMath.hlsl` only after consumers include the new owner. +- Move `AdvancedErosionFilter.hlsl` plus the spherical-erosion and + planetary-radial-refinement bodies embedded in `CultMath.hlsl`. Publish one + geometry-owned umbrella include that imports CultMath first and geometry + organs afterward. +- Move planetary documentation, fixture tools, web tile code, Unity page/mesh + adapters, and the planetary viewer sample to their consumer-owned runtime + locations. +- Move ownership of the `CMPT` little-endian tile format and TypeScript decoder. + Preserve v1 bytes exactly or introduce a new format version; never reuse a + wire version after changing its bytes. +- Rename public namespaces and symbols to their GameCult.Geometry authority. + Prefer a coordinated breaking release over permanent forwarding types. +- Move spherical/terrain erosion components classified as geometry. Keep only + genuinely coordinate-agnostic numeric kernels in CultMath. +- Run CPU/HLSL and cross-runtime fixtures from the new owner before deleting + the old files. +- Preserve exact fixtures for field versions, enum ordinals, integer hashes, + tile keys/bytes, GPU buffer packing, MessagePack slots, topology seams and + corners, and record hashes. Use explicit tolerances only for floating + CPU/HLSL comparisons. +- Delete the corresponding CultMath sources, package entries, and implicit + includes in the same authority-transfer stage after the destination passes. + Do not defer the actual ownership cut to consumer cleanup. + +Gate: + +- GameCult.Geometry passes the captured planetary baseline and owns the fixture + commands. +- CultMath packages no `Planetary.hlsl`, planetary sample, planetary tool, or + planetary public namespace. +- No source or shader include can select an old CultMath planetary path. +- Package inspection finds no planetary API, Unity adapter, sample, tile + decoder, documentation claim, or implicit shader include in CultMath. + +### Stage 4: Mine and Absorb `vg-csg` + +Purpose: preserve useful CSG machinery without preserving the defunct owner. + +Work: + +- Import the earned Rust implementation into the GameCult.Geometry runtime + surface with source provenance and applicable license notices. +- Replace `bevy_math`-shaped public contracts where they conflict with the + canonical cross-runtime primitive/layout contract. Internal use may remain + where it protects a measured invariant and does not leak a second public + vocabulary. +- Connect domain trees, selected cuts, build requests, and emitted artifacts to + the GameCult.Geometry schema definitions. +- Port useful fixtures before refactoring algorithms so observable behavior has + a witness. +- Preserve the existing Rust v1 tuple MessagePack and stable-hash fixtures as + migration witnesses, then make the GameCult.Geometry-owned Rust package emit + the v2 contract. +- Re-run performance fixtures and retain thresholds only where the fixture + represents a real workload. +- Move surviving doctrine into GameCult.Geometry docs and discard historical + instructions that would recreate VibeGeometry ownership. + +Gate: + +- No production build or test depends on the VibeGeometry repository or + `vg-csg` submodule. +- CSG output satisfies the adopted correctness and performance fixtures from + its new package. +- The Rust runtime speaks the same schema IDs, vector layouts, fingerprints, + and record keys as C#. + +### Stage 5: Integrate Geometry Through CultCache, CultNet, and CultMesh + +Purpose: prove the new owner through the real typed-state path. + +Work: + +- Register the adopted geometry schemas and formatters through the generated + registry path. +- Prove raw envelope interchange for geometry documents across C# and Rust, + adding TypeScript only if an actual web consumer remains. +- Publish geometry worker state and commands through the provider-owned + CultMesh surface. +- Ensure geometry build requests, selected cuts, chunk artifacts, and planetary + page state share one commit/derivation path for direct and programmatic use. +- Add a development probe exposing schema version, owner, source record key, + selected cut/page, content hash, and served package version. + +Gate: + +- A pipeline smoke proves typed handoff from domain input through selected cut + or planetary page selection to a persisted and republished artifact. +- The visible/debug projection and persisted state identify the same owner and + version. +- No ad hoc JSON or parallel status model becomes load-bearing geometry truth. + +### Stage 6: Consumer Cutover and Coordinated Release + +Purpose: switch consumers without maintaining two live authorities. + +Release order: + +1. Build an unpublished CultMath candidate that contains the stable primitive + contract and removes geometry-owned APIs. +2. Build an unpublished GameCult.Geometry candidate against that exact CultMath + version, containing adopted schemas, planetary geometry, and runtime packages. +3. Update and test GameCult services, Unity projects, web consumers, and tools + against a local candidate feed. +4. Publish the CultMath and GameCult.Geometry candidates in one coordinated + release window, with the primitives-only CultMath dependency entering the + feed first. +5. Publish consumer updates after both owning packages are available. +6. Convert persisted v1 geometry stores, if any, and remove migration tooling + after the retained-corpus policy is satisfied. + +Work: + +- Pin compatible package versions across the coordinated release. +- Update examples and developer-facing entrypoints to use + `GameCult.Geometry` plus CultMath primitives directly. +- Cut Fensalir's Engine/Contracts public planetary types and shader includes to + the new assembly before removing CultMath geometry. Its CPU/GPU parity tests + are release gates. +- Add the geometry package to Aetheria/Unity, move its directly compiled + planetary sources to the new assembly, preserve moved Unity `.meta` GUIDs, + and regenerate Unity project files. +- Verify served package, shader, schema, and migration versions in at least one + real consumer for each retained runtime. +- Run the preserved parity corpus through known consumers including Fensalir, + Zyphos, Aetheria/Unity, the web tile decoder when retained, C#, Rust, and HLSL. +- Refuse mixed old/new geometry writers rather than reconciling them later. + +Gate: + +- Every known consumer runs on the new owner. +- No published package graph has `CultMath -> CultLib` or + `CultMath -> GameCult.Geometry`. +- Old and new writers cannot target the same state surface. + +### Stage 7: Delete Obsolete Authorities + +Purpose: make the old ownership structurally unable to return. + +Work: + +- Confirm deletion of all CultMath planetary/geometry sources, tests, shaders, + samples, docs, tools, web surfaces, package content entries, and Unity + adapters; remove any residue found after consumer cutover. +- Delete obsolete GameCult.Geometry duplicate primitive code and stale schema + paths. +- Delete VibeGeometry workspace wiring and the `vg-csg` submodule dependency; + archive the repositories after provenance links and release tags are + recorded. +- Remove compatibility aliases, forwarding namespaces, dual registries, and + temporary migration flags. +- Update source indexes and repository memory so future agents retrieve the new + authority first. + +Gate: + +- Negative searches and package inspection prove the old paths are absent. +- Building CultMath alone cannot access planetary or geometry APIs. +- Building GameCult.Geometry cannot access `CultVec*` or VibeGeometry. +- The old persisted schema path cannot write or override current geometry. + +## Schema Migration Policy + +Do not create a permanent compatibility model pre-emptively. + +- If no durable v1 corpus exists, change the schema once, update fixtures, and + publish the corrected contract as v2, then delete the old form without + building a migrator. +- If a durable v1 corpus exists, create an offline migrator with explicit input + and output schema IDs, content hashes, counts, and a dry-run report. +- A v1 reader may exist only inside migration/inspection tooling. +- The runtime writes only the current schema after cutover. +- Migration completes only when retained stores have receipts and no active + service advertises or writes v1. + +## Verification Matrix + +| Layer | Required evidence | +| --- | --- | +| CultMath primitives | C#/HLSL parity, unmanaged layout/size checks, package inspection | +| Geometry values | Exact `float2`/`float3` field ownership, intersection/query unit tests, MessagePack byte fixtures | +| CultCache SoA | Intact vector columns, no recursive flattening, add/update/remove/snapshot behavior | +| Geometry schemas | Catalog IDs and slots, v1 inventory or migration receipts, stable record-key parity | +| Planetary geometry | Projection round trips, topology adjacency, field/normal samples, radial refinement, page encoding/residency, CPU/HLSL parity | +| CSG | Boolean/convex fixtures, dirty rebuild behavior, selected-cut correctness, triangle/collider receipts, performance fixtures | +| Cross-runtime | C#/Rust payload and fingerprint parity; web parity only for retained web consumers | +| Packaging | CultMath contains no geometry assets; GameCult.Geometry includes its owned HLSL/docs/runtime assets | +| End to end | Domain or planetary input to persisted artifact through CultMesh with visible owner/version evidence | + +## Negative Completion Checks + +The migration is not complete until all are true: + +- `CultVec2` and `CultVec3` cannot appear in newly generated schemas or native + slice metadata. +- CultMath cannot publish or execute planetary geometry through an old entrypoint. +- VibeGeometry and `vg-csg` cannot influence a build, runtime, fixture, or + generated artifact. +- VibeGeometry is absent from project references, package manifests, + submodules, CI, runtime identifiers, and authoritative documentation. +- Legacy v1 state cannot override or repair current geometry after the fact. +- CultCache cannot decompose a vector into independently owned scalar columns. +- Manual, programmatic, imported, persisted, and network-received geometry use + the same schema and commit paths. +- Passing unit tests are accompanied by package inspection and cross-runtime + evidence at the layer users actually consume. + +## Definition of Done + +The work is complete when `GameCult.Geometry` is the only geometry authority, +CultMath is a clean numeric substrate, all retained runtime projections agree on +typed layouts and stable identities, VibeGeometry has no live dependency path, +and the old owners are structurally unable to emit current geometry state. From c83ce2e7e6a91388f2801bf560a46b9a5896773f Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 02:47:08 +0100 Subject: [PATCH 020/283] Record geometry migration baseline --- ...th-gamecult-geometry-migration-progress.md | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 docs/cultmath-gamecult-geometry-migration-progress.md diff --git a/docs/cultmath-gamecult-geometry-migration-progress.md b/docs/cultmath-gamecult-geometry-migration-progress.md new file mode 100644 index 00000000..834a64c8 --- /dev/null +++ b/docs/cultmath-gamecult-geometry-migration-progress.md @@ -0,0 +1,115 @@ +# CultMath and GameCult.Geometry Migration Progress + +Plan: `docs/cultmath-gamecult-geometry-migration-plan.md` (locked) + +Started: 2026-07-22 + +Status: Stage 0 complete; Stage 1 in progress + +## Objective + +Implement the locked migration so `GameCult.Geometry` becomes the sole owner of +geometry, planetary geometry, CSG, geometry schemas, and runtime projections, +while CultMath remains the HLSL-shaped numeric substrate and VibeGeometry loses +all live authority. + +## Execution Authority Map + +- Owner: `GameCult.Geometry` owns geometry decisions and geometry state. +- Inputs: CultMath numeric primitives, mined `vg-csg` implementation/evidence, + current geometry v1 documents, and named downstream consumer contracts. +- Outputs: GameCult.Geometry C#/Rust/HLSL/Unity/web surfaces, v2 typed schemas, + persisted artifacts, and CultMesh projections. +- Derived state: JSON inspection, UI/debug projections, caches, migration + receipts, and compatibility reads are non-authoritative. +- Forbidden writers: CultMath planetary APIs, v1 geometry runtime writers, + `CultVec*`, VibeGeometry/`vg-csg`, legacy shader entrypoints, and anonymous + fixed-vector arrays. +- Shared paths: direct API calls, persisted reloads, imports, network envelopes, + worker commands, Unity consumption, web tile reads, and Rust emitters must use + the same current schema/layout/fingerprint rules. +- Deletion line: `CultVec2`, `CultVec3`, `CultMath.rect`, CultMath planetary and + erosion ownership, v1 writers, VibeGeometry wiring/submodule authority, and + stale package/docs/schema paths. + +Demotions: + +- Geometry v1 DTOs are no longer owners; when a durable corpus requires them, + they are bounded read-only migration inputs to v2. +- JSON is no longer an owner; it is an inspection or xenos-boundary projection. +- VibeGeometry is no longer an owner; it is a provenance-bearing source quarry. +- CultMath planetary state is no longer an owner; it is source material pending + transfer and deletion in the same unpublished migration cut. + +## Worktree Safety + +- CultLib began with unrelated modified `.voidbot`, CultMesh, CultCache TS, + CultNet Rust, README, and test files plus scratch PID files. These changes are + outside the migration unless an exact overlap is required and reviewed. +- CultMath began clean on `codex/rust-cultmath-core` at `cb481b4`. +- VibeGeometry began clean on `main` at `85ac60a`. +- The locked plan is not edited during implementation. + +## Stage Ledger + +| Stage | State | Evidence / next gate | +| --- | --- | --- | +| 0. Freeze and baseline | Complete | Source bodies, contracts, consumers, licenses, fixtures, and focused baselines mapped | +| 1. Destination/dependency/formatters/SoA | In progress | Resolver ownership and exact unmanaged-column support are the first cuts | +| 2. Primitive deletion and v2 schemas | Pending | Requires intact CultMath vector serialization and SoA | +| 3. Planetary transfer | Pending | Requires destination packaging and preserved parity corpus | +| 4. Mine `vg-csg` | Pending | Requires v1 fixture capture and target Rust package seam | +| 5. CultCache/CultNet/CultMesh integration | Pending | Requires current schemas and runtime packages | +| 6. Consumer cutover/release | Pending | Requires local candidate feed and downstream passes | +| 7. Delete obsolete authorities/audit | Pending | Requires every prior stage gate | + +## Verification Receipts + +Receipts will be appended here with command, repository, commit, result, and +relevant artifact/version. A passing narrow test is not accepted as evidence for +a broader stage gate. + +### Stage 0 receipts + +- CultLib: `dotnet test tests/GameCult.Geometry.Tests/GameCult.Geometry.Tests.csproj --no-build --no-restore --disable-build-servers` passed 13/13. A full rebuild remains a Stage 1 gate; shared .NET build contention made attached build attempts exceed 60 seconds. +- CultMath: `dotnet test CultMath.slnx --no-restore` passed 72/72. +- CultMath native: `cargo test --locked` passed 1/1. +- CultMath web tile unit: `node --test web/planetary-tile.test.mjs` passed 1/1. +- CultMath pack and the combined web/C# cross-runtime script exceeded the + baseline time window and remain required package-transfer gates. +- VibeGeometry: `cargo test` passed 56 unit and 9 integration tests; doc tests + passed; `cargo clippy --all-targets --all-features` passed. +- Authoritative Rust quarry: VibeGeometry-pinned `vg-csg` submodule `a3197f4`. + Standalone `E:\Projects\vg-csg` is stale and excluded. +- v1 witnesses: current C#/Rust slots and hash algorithms match; Rust expected + record keys include domain `02c9...ed95` and chunk `b94d...21af5`. Exact + checked-in MessagePack byte witnesses still need to be generated before v2. +- Persisted corpus: targeted file inventory covered CultLib, CultMath, + VibeGeometry, Fensalir, and Aetheria. CultLib contains only the two checked-in + `vg-csg-ragnarok` payload fixtures. Binary scanning of Aetheria `.cc`, + `.msgpack`, and `.mpack` artifacts found no `gamecult.geometry.*.v1` catalog + identity. Indexed-source retrieval found definitions/tests/docs but no durable + geometry store. Execution therefore uses v2 plus retained test witnesses, + with no live v1 runtime migrator. + +## Decisions and Deviations + +- Licensing: no relicensing is assumed. Moved CultMath files retain MPL-2.0 + notices and provenance; the GameCult.Geometry package will carry explicit + mixed-license package documentation rather than falsely stamping those files + MIT. `AdvancedErosionFilter` source and shader notices remain verbatim. +- Serialization: Geometry-owned external value formatters require a declarative + per-document-assembly resolver seam in `GameCult.Caching.MessagePack`. + CultMath remains annotation-free and core caching does not reference Geometry. +- v1 persistence: no durable corpus was found in the named repositories and + artifacts. v1 remains fixture evidence only; it will not survive as a runtime + writer or general compatibility model. +- No deviations from the locked target architecture. + +## Next Actions + +1. Implement the owner-assembly MessagePack resolver seam and its isolation tests. +2. Establish the Geometry -> CultMath dependency and exact vector formatter + fixtures. +3. Cut the scalar-only SoA whitelist so intact unmanaged vectors can exist as + columns before v2 document fields adopt them. From 9698805588059244e00b2decd45921405f26e0ac Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 02:53:29 +0100 Subject: [PATCH 021/283] Add geometry serialization and SoA foundations --- ...th-gamecult-geometry-migration-progress.md | 29 ++++- .../CultDocumentMessagePackGenerator.cs | 4 +- .../CultDocumentMessagePackSerialization.cs | 83 +++++++++++++- src/GameCult.Caching/CultManagedDocument.cs | 36 ++++-- .../DocumentAssemblyResolverTests.cs | 88 +++++++++++++++ .../SoaValueColumnTests.cs | 104 ++++++++++++++++++ 6 files changed, 321 insertions(+), 23 deletions(-) create mode 100644 tests/GameCult.Caching.Tests/DocumentAssemblyResolverTests.cs create mode 100644 tests/GameCult.Caching.Tests/SoaValueColumnTests.cs diff --git a/docs/cultmath-gamecult-geometry-migration-progress.md b/docs/cultmath-gamecult-geometry-migration-progress.md index 834a64c8..0d6db0e6 100644 --- a/docs/cultmath-gamecult-geometry-migration-progress.md +++ b/docs/cultmath-gamecult-geometry-migration-progress.md @@ -92,6 +92,25 @@ a broader stage gate. geometry store. Execution therefore uses v2 plus retained test witnesses, with no live v1 runtime migrator. +### Stage 1 receipts + +- CultCache MessagePack now resolves external member values through a + document-owner assembly declaration. Resolver precedence is core CultCache, + owner-declared resolvers, then MessagePack standard fallback; the options are + cached per owner assembly and generated document codecs use that same path. + CultCache does not reference Geometry or CultMath. +- CultCache SoA discovery now admits direct reference-free value types as one + exact typed column. It rejects managed-reference and byref-like values and + does not synthesize component columns from nested struct fields. +- `dotnet test tests/GameCult.Caching.Tests/GameCult.Caching.Tests.csproj + --no-restore --filter + "FullyQualifiedName~DocumentAssemblyResolverTests|FullyQualifiedName~SoaValueColumnTests" + --verbosity minimal -m:1 -nodeReuse:false` passed 4/4 after a full rebuild. +- The initial SoA reflection probe used `Type.IsFunctionPointer`, which is not + available on the library's `netstandard2.1` target. It was removed rather + than papered over; structural managed-reference inspection is the owning + eligibility rule. + ## Decisions and Deviations - Licensing: no relicensing is assumed. Moved CultMath files retain MPL-2.0 @@ -108,8 +127,8 @@ a broader stage gate. ## Next Actions -1. Implement the owner-assembly MessagePack resolver seam and its isolation tests. -2. Establish the Geometry -> CultMath dependency and exact vector formatter - fixtures. -3. Cut the scalar-only SoA whitelist so intact unmanaged vectors can exist as - columns before v2 document fields adopt them. +1. Establish the Geometry -> CultMath dependency through an explicit candidate + package/local-feed workflow rather than an implicit sibling checkout. +2. Add Geometry-owned exact vector/quaternion formatters and byte fixtures. +3. Prove actual `Column` and `Column` access from Geometry, then + inspect the NuGet and UPM artifacts before adopting vectors in v2 schemas. diff --git a/src/GameCult.Caching.MessagePack.Generator/CultDocumentMessagePackGenerator.cs b/src/GameCult.Caching.MessagePack.Generator/CultDocumentMessagePackGenerator.cs index eeb09475..2948837b 100644 --- a/src/GameCult.Caching.MessagePack.Generator/CultDocumentMessagePackGenerator.cs +++ b/src/GameCult.Caching.MessagePack.Generator/CultDocumentMessagePackGenerator.cs @@ -274,7 +274,7 @@ public sealed class CultDocumentMessagePackGenerator : IIncrementalGenerator builder.AppendLine($" private static byte[] {document.PayloadSerializerMethodName}(object document)"); builder.AppendLine(" {"); builder.AppendLine($" var typed = ({document.DocumentTypeName})document;"); - builder.AppendLine(" var options = global::GameCult.Caching.MessagePack.CultDocumentMessagePackSerialization.Options;"); + builder.AppendLine($" var options = global::GameCult.Caching.MessagePack.CultDocumentMessagePackSerialization.OptionsFor(typeof({document.DocumentTypeName}));"); builder.AppendLine(" var buffer = new global::System.Buffers.ArrayBufferWriter();"); builder.AppendLine(" var writer = new global::MessagePack.MessagePackWriter(buffer);"); builder.AppendLine($" writer.WriteArrayHeader({document.Members.Length});"); @@ -292,7 +292,7 @@ public sealed class CultDocumentMessagePackGenerator : IIncrementalGenerator { builder.AppendLine($" private static object {document.PayloadDeserializerMethodName}(byte[] payload)"); builder.AppendLine(" {"); - builder.AppendLine(" var options = global::GameCult.Caching.MessagePack.CultDocumentMessagePackSerialization.Options;"); + builder.AppendLine($" var options = global::GameCult.Caching.MessagePack.CultDocumentMessagePackSerialization.OptionsFor(typeof({document.DocumentTypeName}));"); builder.AppendLine(" var reader = new global::MessagePack.MessagePackReader(payload);"); builder.AppendLine(" var count = reader.ReadArrayHeader();"); builder.AppendLine($" var value = new {document.DocumentTypeName}();"); diff --git a/src/GameCult.Caching.MessagePack/CultDocumentMessagePackSerialization.cs b/src/GameCult.Caching.MessagePack/CultDocumentMessagePackSerialization.cs index 21278fa8..688d23f6 100644 --- a/src/GameCult.Caching.MessagePack/CultDocumentMessagePackSerialization.cs +++ b/src/GameCult.Caching.MessagePack/CultDocumentMessagePackSerialization.cs @@ -1,5 +1,8 @@ using System; using System.Buffers; +using System.Collections.Concurrent; +using System.Linq; +using System.Reflection; using GameCult.Caching; using MessagePack; using MessagePack.Formatters; @@ -7,6 +10,27 @@ using MessagePack.Resolvers; namespace GameCult.Caching.MessagePack; +/// +/// Declares MessagePack resolvers owned by the assembly that defines a Cult document. +/// +[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +public sealed class CultDocumentMessagePackResolversAttribute : Attribute +{ + /// Creates a resolver declaration in precedence order. + public CultDocumentMessagePackResolversAttribute(params Type[] resolverTypes) + { + if (resolverTypes == null || resolverTypes.Length == 0) + { + throw new ArgumentException("At least one resolver type is required.", nameof(resolverTypes)); + } + + ResolverTypes = resolverTypes; + } + + /// Gets the declared resolver types in precedence order. + public Type[] ResolverTypes { get; } +} + /// /// MessagePack resolver for CultCache-specific value types. /// @@ -43,6 +67,7 @@ public static class CultDocumentMessagePackSerialization private const int SchemaCatalogEntryFieldCount = 7; private const int SchemaCatalogMemberFieldCount = 8; private const int StoreSnapshotFieldCount = 3; + private static readonly ConcurrentDictionary DocumentAssemblyOptions = new(); /// /// Gets the shared MessagePack serializer options for CultCache payloads. @@ -54,12 +79,29 @@ public static class CultDocumentMessagePackSerialization StandardResolver.Instance)) .WithSecurity(MessagePackSecurity.UntrustedData); + /// + /// Gets serializer options for documents owned by an assembly. CultCache formatters + /// take precedence, followed by assembly-declared resolvers and the standard resolver. + /// + public static MessagePackSerializerOptions OptionsFor(Assembly documentAssembly) + { + if (documentAssembly == null) throw new ArgumentNullException(nameof(documentAssembly)); + return DocumentAssemblyOptions.GetOrAdd(documentAssembly, CreateDocumentAssemblyOptions); + } + + /// Gets serializer options for the assembly that owns a document type. + public static MessagePackSerializerOptions OptionsFor(Type documentType) + { + if (documentType == null) throw new ArgumentNullException(nameof(documentType)); + return OptionsFor(documentType.Assembly); + } + /// /// Serializes a typed value with the CultCache MessagePack options. /// public static byte[] Serialize(T value) { - return MessagePackSerializer.Serialize(value, Options); + return MessagePackSerializer.Serialize(value, OptionsFor(typeof(T))); } /// @@ -67,7 +109,7 @@ public static class CultDocumentMessagePackSerialization /// public static T Deserialize(byte[] payload) { - return MessagePackSerializer.Deserialize(payload, Options); + return MessagePackSerializer.Deserialize(payload, OptionsFor(typeof(T))); } /// @@ -84,7 +126,7 @@ public static class CultDocumentMessagePackSerialization } } - return MessagePackSerializer.Serialize(type, value, Options); + return MessagePackSerializer.Serialize(type, value, OptionsFor(type)); } /// @@ -98,10 +140,43 @@ public static class CultDocumentMessagePackSerialization return descriptor.GeneratedPayloadDeserializer(payload); } - return MessagePackSerializer.Deserialize(type, payload, Options) + return MessagePackSerializer.Deserialize(type, payload, OptionsFor(type)) ?? throw new InvalidOperationException($"MessagePack returned null for Cult document type {type.FullName}."); } + private static MessagePackSerializerOptions CreateDocumentAssemblyOptions(Assembly documentAssembly) + { + var ownerResolvers = documentAssembly + .GetCustomAttributes() + .SelectMany(attribute => attribute.ResolverTypes) + .Select(CreateOwnerResolver) + .ToArray(); + + if (ownerResolvers.Length == 0) + { + return Options; + } + + var resolvers = new IFormatterResolver[ownerResolvers.Length + 2]; + resolvers[0] = CultDocumentResolver.Instance; + Array.Copy(ownerResolvers, 0, resolvers, 1, ownerResolvers.Length); + resolvers[resolvers.Length - 1] = StandardResolver.Instance; + return Options.WithResolver(CompositeResolver.Create(resolvers)); + } + + private static IFormatterResolver CreateOwnerResolver(Type resolverType) + { + if (resolverType == null || !typeof(IFormatterResolver).IsAssignableFrom(resolverType)) + { + throw new InvalidOperationException( + $"Cult document MessagePack resolver '{resolverType?.FullName ?? ""}' must implement {typeof(IFormatterResolver).FullName}."); + } + + return Activator.CreateInstance(resolverType) as IFormatterResolver + ?? throw new InvalidOperationException( + $"Cult document MessagePack resolver '{resolverType.FullName}' must have a public parameterless constructor."); + } + /// /// Serializes one persisted store record. /// diff --git a/src/GameCult.Caching/CultManagedDocument.cs b/src/GameCult.Caching/CultManagedDocument.cs index 100cb628..1919ea88 100644 --- a/src/GameCult.Caching/CultManagedDocument.cs +++ b/src/GameCult.Caching/CultManagedDocument.cs @@ -398,18 +398,30 @@ namespace GameCult.Caching private static bool IsColumnType(Type type) { - return type.IsEnum || - type == typeof(byte) || - type == typeof(sbyte) || - type == typeof(short) || - type == typeof(ushort) || - type == typeof(int) || - type == typeof(uint) || - type == typeof(long) || - type == typeof(ulong) || - type == typeof(float) || - type == typeof(double) || - type == typeof(bool); + return type.IsValueType && + !type.IsByRefLike && + !ContainsManagedReferences(type, new HashSet()); + } + + private static bool ContainsManagedReferences(Type type, HashSet visited) + { + if (type.IsPointer) + { + return false; + } + + if (!type.IsValueType) + { + return true; + } + + if (type.IsPrimitive || type.IsEnum || !visited.Add(type)) + { + return false; + } + + const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; + return type.GetFields(flags).Any(field => ContainsManagedReferences(field.FieldType, visited)); } } } diff --git a/tests/GameCult.Caching.Tests/DocumentAssemblyResolverTests.cs b/tests/GameCult.Caching.Tests/DocumentAssemblyResolverTests.cs new file mode 100644 index 00000000..02db2c14 --- /dev/null +++ b/tests/GameCult.Caching.Tests/DocumentAssemblyResolverTests.cs @@ -0,0 +1,88 @@ +#nullable enable +using System; +using System.Buffers; +using GameCult.Caching.MessagePack; +using MessagePack; +using MessagePack.Formatters; +using NUnit.Framework; + +[assembly: CultDocumentMessagePackResolvers(typeof(GameCult.Caching.Tests.FirstOwnerResolver), typeof(GameCult.Caching.Tests.SecondOwnerResolver))] + +namespace GameCult.Caching.Tests; + +public sealed class DocumentAssemblyResolverTests +{ + [Test] + public void OptionsFor_CachesOptionsByDocumentAssembly() + { + var first = CultDocumentMessagePackSerialization.OptionsFor(typeof(ResolverDocument)); + var second = CultDocumentMessagePackSerialization.OptionsFor(typeof(ResolverDocument).Assembly); + + Assert.That(second, Is.SameAs(first)); + Assert.That(first, Is.Not.SameAs(CultDocumentMessagePackSerialization.Options)); + } + + [Test] + public void GeneratedDocumentSerialization_UsesOwnerResolversInDeclaredOrder() + { + FirstOwnerResolver.SerializeCount = 0; + SecondOwnerResolver.FormatterRequestCount = 0; + var original = new ResolverDocument { Name = "probe", Value = new ExternalValue(41) }; + + var payload = CultDocumentMessagePackSerialization.SerializeUntyped(original, typeof(ResolverDocument)); + var decoded = (ResolverDocument)CultDocumentMessagePackSerialization.DeserializeUntyped(typeof(ResolverDocument), payload); + + Assert.That(decoded.Name, Is.EqualTo("probe")); + Assert.That(decoded.Value.Number, Is.EqualTo(42)); + Assert.That(FirstOwnerResolver.SerializeCount, Is.EqualTo(1)); + Assert.That(SecondOwnerResolver.FormatterRequestCount, Is.Zero); + } +} + +[CultDocument("tests.assembly_resolver", "tests.assembly_resolver.v1")] +public sealed class ResolverDocument +{ + [Key(0)] public string Name { get; set; } = string.Empty; + [Key(1)] public ExternalValue Value { get; set; } +} + +public readonly struct ExternalValue +{ + public ExternalValue(int number) => Number = number; + public int Number { get; } +} + +public sealed class FirstOwnerResolver : IFormatterResolver +{ + public static int SerializeCount; + + public IMessagePackFormatter? GetFormatter() + { + return typeof(T) == typeof(ExternalValue) + ? (IMessagePackFormatter)(object)new FirstExternalValueFormatter() + : null; + } + + public sealed class FirstExternalValueFormatter : IMessagePackFormatter + { + public void Serialize(ref MessagePackWriter writer, ExternalValue value, MessagePackSerializerOptions options) + { + SerializeCount++; + writer.Write(value.Number + 1); + } + + public ExternalValue Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + => new(reader.ReadInt32()); + } +} + +public sealed class SecondOwnerResolver : IFormatterResolver +{ + public static int FormatterRequestCount; + + public IMessagePackFormatter? GetFormatter() + { + if (typeof(T) == typeof(ExternalValue)) FormatterRequestCount++; + return null; + } +} diff --git a/tests/GameCult.Caching.Tests/SoaValueColumnTests.cs b/tests/GameCult.Caching.Tests/SoaValueColumnTests.cs new file mode 100644 index 00000000..e64310a6 --- /dev/null +++ b/tests/GameCult.Caching.Tests/SoaValueColumnTests.cs @@ -0,0 +1,104 @@ +#nullable enable +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using GameCult.Caching; +using MessagePack; +using NUnit.Framework; + +namespace GameCult.Caching.Tests +{ + public sealed class SoaValueColumnTests + { + [Test] + public async Task Soa_Preserves_Unmanaged_Value_Members_As_Intact_Columns() + { + var cache = new CultCache(); + var first = new CultRecordHandle(new CultRecordKey("vector:first")); + var second = new CultRecordHandle(new CultRecordKey("vector:second")); + + await cache.UpsertAsync(new VectorDocument + { + Name = "first", + Position = new TestFloat3(1, 2, 3), + Health = 10, + }, first); + await cache.UpsertAsync(new VectorDocument + { + Name = "second", + Position = new TestFloat3(4, 5, 6), + Health = 20, + }, second); + await cache.UpsertAsync(new VectorDocument + { + Name = "first-updated", + Position = new TestFloat3(7, 8, 9), + Health = 30, + }, first); + + var table = cache.Soa(); + + Assert.That(table.Column(nameof(VectorDocument.Position)).Span.ToArray(), Is.EqualTo(new[] + { + new TestFloat3(7, 8, 9), + new TestFloat3(4, 5, 6), + })); + Assert.That(table.Column(nameof(VectorDocument.Health)).Span.ToArray(), Is.EqualTo(new[] { 30, 20 })); + Assert.That(() => table.Column("Position.x"), Throws.TypeOf()); + Assert.That(() => table.Column("x"), Throws.TypeOf()); + + Assert.That(cache.Remove(first.Key), Is.True); + var afterRemoval = cache.Soa(); + Assert.That(afterRemoval.Keys.Select(key => key.Value).ToArray(), Is.EqualTo(new[] { "vector:second" })); + Assert.That( + afterRemoval.Column(nameof(VectorDocument.Position)).Span.ToArray(), + Is.EqualTo(new[] { new TestFloat3(4, 5, 6) })); + } + + [Test] + public async Task Soa_Rejects_Value_Members_Containing_Managed_References() + { + var cache = new CultCache(); + await cache.UpsertAsync(new VectorDocument + { + Name = "managed", + Position = new TestFloat3(1, 2, 3), + ManagedValue = new ManagedValue(42, "not a column"), + }); + + var table = cache.Soa(); + + Assert.That( + () => table.Column(nameof(VectorDocument.ManagedValue)), + Throws.TypeOf()); + } + + [MessagePackObject] + public readonly record struct TestFloat3( + [property: Key(0)] float x, + [property: Key(1)] float y, + [property: Key(2)] float z); + + [MessagePackObject] + public readonly record struct ManagedValue( + [property: Key(0)] int Code, + [property: Key(1)] string Label); + + [CultDocument("tests.soa_value_column", "tests.soa_value_column.v1")] + internal sealed class VectorDocument + { + [Key(0)] + [CultName] + public string Name = string.Empty; + + [Key(1)] + public TestFloat3 Position; + + [Key(2)] + public int Health; + + [Key(3)] + public ManagedValue ManagedValue; + } + } +} From 364c9cdf48d3bb604d341a4dc1803d83aa13e8c0 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 02:58:42 +0100 Subject: [PATCH 022/283] Integrate CultMath vectors into geometry --- ...th-gamecult-geometry-migration-progress.md | 29 ++++- .../CultMathMessagePackResolver.cs | 106 ++++++++++++++++++ .../GameCult.Geometry.csproj | 5 + .../CultMathValueIntegrationTests.cs | 76 +++++++++++++ 4 files changed, 211 insertions(+), 5 deletions(-) create mode 100644 src/GameCult.Geometry/CultMathMessagePackResolver.cs create mode 100644 tests/GameCult.Geometry.Tests/CultMathValueIntegrationTests.cs diff --git a/docs/cultmath-gamecult-geometry-migration-progress.md b/docs/cultmath-gamecult-geometry-migration-progress.md index 0d6db0e6..481b360f 100644 --- a/docs/cultmath-gamecult-geometry-migration-progress.md +++ b/docs/cultmath-gamecult-geometry-migration-progress.md @@ -110,6 +110,26 @@ a broader stage gate. available on the library's `netstandard2.1` target. It was removed rather than papered over; structural managed-reference inspection is the owning eligibility rule. +- CultMath candidate `0.1.0-geometry-migration.1` was packed from commit + `cb481b4c75444426a693781a0e5b35ade08a8938` with build servers disabled. The + 123,307-byte package SHA-256 is + `07C0CE79453AF9BA29910809F8779916E7B8F92DCA7ACEB5E2B8F9D3EBED3E93`; + a local-feed consumer restored, compiled, and executed `CultMath.float3`. +- GameCult.Geometry consumes that candidate as an explicit NuGet dependency; + its sibling `.tools/local-feed` is only an optional restore source, not a + project-reference authority. Geometry owns strict positional formatters for + `float2`, `float3`, `float4`, and `quaternion`. +- `dotnet test tests/GameCult.Geometry.Tests/GameCult.Geometry.Tests.csproj + --no-restore --filter FullyQualifiedName~CultMathValueIntegrationTests + --verbosity minimal --disable-build-servers -p:UseSharedCompilation=false + -m:1` + passed 6/6. Evidence covers exact bytes, round trips, malformed-width + rejection, actual `Column`/`Column` access, and absence of + synthetic component columns. +- GameCult.Geometry candidate `0.1.0-geometry-migration.1` packed successfully; + its nuspec declares exact candidate dependencies on CultMath, CultCache, and + CultCache.MessagePack. The dedicated UPM artifact remains the open Stage 1 + gate. ## Decisions and Deviations @@ -127,8 +147,7 @@ a broader stage gate. ## Next Actions -1. Establish the Geometry -> CultMath dependency through an explicit candidate - package/local-feed workflow rather than an implicit sibling checkout. -2. Add Geometry-owned exact vector/quaternion formatters and byte fixtures. -3. Prove actual `Column` and `Column` access from Geometry, then - inspect the NuGet and UPM artifacts before adopting vectors in v2 schemas. +1. Establish and inspect the dedicated `org.gamecult.geometry` UPM artifact. +2. Record the newly pinned Rust v1 byte/key witnesses and commit their + authoritative submodule change. +3. Begin Stage 2 only after the Unity dependency/layout gate is proven. diff --git a/src/GameCult.Geometry/CultMathMessagePackResolver.cs b/src/GameCult.Geometry/CultMathMessagePackResolver.cs new file mode 100644 index 00000000..6e0075cf --- /dev/null +++ b/src/GameCult.Geometry/CultMathMessagePackResolver.cs @@ -0,0 +1,106 @@ +using CultMath; +using GameCult.Caching.MessagePack; +using MessagePack; +using MessagePack.Formatters; + +[assembly: CultDocumentMessagePackResolvers(typeof(GameCult.Geometry.CultMathMessagePackResolver))] + +namespace GameCult.Geometry; + +/// +/// Owns the persisted positional representation of CultMath values used by +/// GameCult.Geometry documents. CultMath remains serialization-agnostic. +/// +public sealed class CultMathMessagePackResolver : IFormatterResolver +{ + public IMessagePackFormatter? GetFormatter() + { + if (typeof(T) == typeof(float2)) return (IMessagePackFormatter)(object)Float2Formatter.Instance; + if (typeof(T) == typeof(float3)) return (IMessagePackFormatter)(object)Float3Formatter.Instance; + if (typeof(T) == typeof(float4)) return (IMessagePackFormatter)(object)Float4Formatter.Instance; + if (typeof(T) == typeof(quaternion)) return (IMessagePackFormatter)(object)QuaternionFormatter.Instance; + return null; + } + + private static void RequireComponents(ref MessagePackReader reader, int expected, string typeName) + { + var actual = reader.ReadArrayHeader(); + if (actual != expected) + { + throw new MessagePackSerializationException($"{typeName} requires exactly {expected} components; payload contained {actual}."); + } + } + + internal sealed class Float2Formatter : IMessagePackFormatter + { + public static readonly Float2Formatter Instance = new(); + public void Serialize(ref MessagePackWriter writer, float2 value, MessagePackSerializerOptions options) + { + writer.WriteArrayHeader(2); + writer.Write(value.x); + writer.Write(value.y); + } + + public float2 Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + { + RequireComponents(ref reader, 2, nameof(float2)); + return new float2(reader.ReadSingle(), reader.ReadSingle()); + } + } + + internal sealed class Float3Formatter : IMessagePackFormatter + { + public static readonly Float3Formatter Instance = new(); + public void Serialize(ref MessagePackWriter writer, float3 value, MessagePackSerializerOptions options) + { + writer.WriteArrayHeader(3); + writer.Write(value.x); + writer.Write(value.y); + writer.Write(value.z); + } + + public float3 Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + { + RequireComponents(ref reader, 3, nameof(float3)); + return new float3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); + } + } + + internal sealed class Float4Formatter : IMessagePackFormatter + { + public static readonly Float4Formatter Instance = new(); + public void Serialize(ref MessagePackWriter writer, float4 value, MessagePackSerializerOptions options) + { + writer.WriteArrayHeader(4); + writer.Write(value.x); + writer.Write(value.y); + writer.Write(value.z); + writer.Write(value.w); + } + + public float4 Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + { + RequireComponents(ref reader, 4, nameof(float4)); + return new float4(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); + } + } + + internal sealed class QuaternionFormatter : IMessagePackFormatter + { + public static readonly QuaternionFormatter Instance = new(); + public void Serialize(ref MessagePackWriter writer, quaternion value, MessagePackSerializerOptions options) + { + writer.WriteArrayHeader(4); + writer.Write(value.x); + writer.Write(value.y); + writer.Write(value.z); + writer.Write(value.w); + } + + public quaternion Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + { + RequireComponents(ref reader, 4, nameof(quaternion)); + return new quaternion(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); + } + } +} diff --git a/src/GameCult.Geometry/GameCult.Geometry.csproj b/src/GameCult.Geometry/GameCult.Geometry.csproj index a0192f69..22c991ab 100644 --- a/src/GameCult.Geometry/GameCult.Geometry.csproj +++ b/src/GameCult.Geometry/GameCult.Geometry.csproj @@ -5,10 +5,15 @@ game;geometry;csg;lod;cultcache;cultmesh;vibegeometry;fensalir README.md $(NoWarn);1591 + 0.1.0-geometry-migration.1 + $(MSBuildThisFileDirectory)..\..\..\CultMath\.tools\local-feed + $(RestoreAdditionalProjectSources);$(CultMathCandidateFeed) + + diff --git a/tests/GameCult.Geometry.Tests/CultMathValueIntegrationTests.cs b/tests/GameCult.Geometry.Tests/CultMathValueIntegrationTests.cs new file mode 100644 index 00000000..b76248c0 --- /dev/null +++ b/tests/GameCult.Geometry.Tests/CultMathValueIntegrationTests.cs @@ -0,0 +1,76 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using CultMath; +using GameCult.Caching; +using GameCult.Caching.MessagePack; +using MessagePack; +using NUnit.Framework; + +namespace GameCult.Geometry.Tests; + +public sealed class CultMathValueIntegrationTests +{ + private static readonly MessagePackSerializerOptions GeometryOptions = + CultDocumentMessagePackSerialization.OptionsFor(typeof(CultGeometryDomainDocument)); + + [TestCaseSource(nameof(ValueEncodingCases))] + public void GeometryResolver_UsesExactPositionalVectorEncoding(object value, Type type, string expectedHex) + { + var payload = MessagePackSerializer.Serialize(type, value, GeometryOptions); + + Assert.That(Convert.ToHexString(payload), Is.EqualTo(expectedHex)); + Assert.That(MessagePackSerializer.Deserialize(type, payload, GeometryOptions), Is.EqualTo(value)); + } + + [Test] + public void GeometryResolver_RejectsWrongVectorWidth() + { + var twoComponents = Convert.FromHexString("92CA3F800000CA40000000"); + + Assert.That( + () => MessagePackSerializer.Deserialize(twoComponents, GeometryOptions), + Throws.TypeOf()); + } + + [Test] + public async Task GeometrySoa_ExposesCultMathVectorsAsIntactColumns() + { + var cache = new CultCache(); + await cache.UpsertAsync(new VectorColumnDocument + { + Name = "probe", + Uv = new float2(0.25f, 0.75f), + Position = new float3(1f, 2f, 3f), + }); + + var table = cache.Soa(); + + Assert.That(table.Column(nameof(VectorColumnDocument.Uv)).Span.ToArray(), + Is.EqualTo(new[] { new float2(0.25f, 0.75f) })); + Assert.That(table.Column(nameof(VectorColumnDocument.Position)).Span.ToArray(), + Is.EqualTo(new[] { new float3(1f, 2f, 3f) })); + Assert.That(() => table.Column("Position.x"), Throws.TypeOf()); + } + + private static object[] ValueEncodingCases => + [ + new object[] { new float2(1f, -2.5f), typeof(float2), "92CA3F800000CAC0200000" }, + new object[] { new float3(1f, -2.5f, 0.5f), typeof(float3), "93CA3F800000CAC0200000CA3F000000" }, + new object[] { new float4(1f, -2.5f, 0.5f, 4f), typeof(float4), "94CA3F800000CAC0200000CA3F000000CA40800000" }, + new object[] { new quaternion(1f, -2.5f, 0.5f, 4f), typeof(quaternion), "94CA3F800000CAC0200000CA3F000000CA40800000" }, + ]; + + [CultDocument("tests.geometry_vector_column", "tests.geometry_vector_column.v1")] + private sealed class VectorColumnDocument + { + [Key(0), CultName] + public string Name { get; set; } = string.Empty; + + [Key(1)] + public float2 Uv { get; set; } + + [Key(2)] + public float3 Position { get; set; } + } +} From 343e03d8a2276a5020b81f7304b5ad5595fd7e7f Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 02:59:20 +0100 Subject: [PATCH 023/283] Record geometry wire witnesses --- docs/cultmath-gamecult-geometry-migration-progress.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/cultmath-gamecult-geometry-migration-progress.md b/docs/cultmath-gamecult-geometry-migration-progress.md index 481b360f..d872a6c2 100644 --- a/docs/cultmath-gamecult-geometry-migration-progress.md +++ b/docs/cultmath-gamecult-geometry-migration-progress.md @@ -130,6 +130,11 @@ a broader stage gate. its nuspec declares exact candidate dependencies on CultMath, CultCache, and CultCache.MessagePack. The dedicated UPM artifact remains the open Stage 1 gate. +- Authoritative `vg-csg` commit `8f070f4` now pins exact v1 MessagePack bytes + for representative domain/chunk tuples plus complete domain, request, + selected-cut, and chunk record keys. Focused Rust tests passed 4/4; formatting + and clippy passed. VibeGeometry commit `82b56db` advances its submodule to + that witness commit. Both migration branches are pushed. ## Decisions and Deviations @@ -148,6 +153,4 @@ a broader stage gate. ## Next Actions 1. Establish and inspect the dedicated `org.gamecult.geometry` UPM artifact. -2. Record the newly pinned Rust v1 byte/key witnesses and commit their - authoritative submodule change. -3. Begin Stage 2 only after the Unity dependency/layout gate is proven. +2. Begin Stage 2 only after the Unity dependency/layout gate is proven. From 0f16f1441517252ff0e1455d0567f1206eaa97a0 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 03:01:08 +0100 Subject: [PATCH 024/283] Add dedicated Geometry Unity package --- ...th-gamecult-geometry-migration-progress.md | 19 +++-- scripts/build-geometry-unity-package.ps1 | 70 +++++++++++++++++++ unity/org.gamecult.geometry/README.md | 12 ++++ .../Runtime/GameCult.Geometry.asmdef | 19 +++++ unity/org.gamecult.geometry/package.json | 15 ++++ 5 files changed, 130 insertions(+), 5 deletions(-) create mode 100644 scripts/build-geometry-unity-package.ps1 create mode 100644 unity/org.gamecult.geometry/README.md create mode 100644 unity/org.gamecult.geometry/Runtime/GameCult.Geometry.asmdef create mode 100644 unity/org.gamecult.geometry/package.json diff --git a/docs/cultmath-gamecult-geometry-migration-progress.md b/docs/cultmath-gamecult-geometry-migration-progress.md index d872a6c2..ab9b8455 100644 --- a/docs/cultmath-gamecult-geometry-migration-progress.md +++ b/docs/cultmath-gamecult-geometry-migration-progress.md @@ -4,7 +4,7 @@ Plan: `docs/cultmath-gamecult-geometry-migration-plan.md` (locked) Started: 2026-07-22 -Status: Stage 0 complete; Stage 1 in progress +Status: Stages 0-1 complete; Stage 2 in progress ## Objective @@ -55,8 +55,8 @@ Demotions: | Stage | State | Evidence / next gate | | --- | --- | --- | | 0. Freeze and baseline | Complete | Source bodies, contracts, consumers, licenses, fixtures, and focused baselines mapped | -| 1. Destination/dependency/formatters/SoA | In progress | Resolver ownership and exact unmanaged-column support are the first cuts | -| 2. Primitive deletion and v2 schemas | Pending | Requires intact CultMath vector serialization and SoA | +| 1. Destination/dependency/formatters/SoA | Complete | NuGet and dedicated UPM artifacts prove dependency direction and owned vector integration | +| 2. Primitive deletion and v2 schemas | In progress | Delete duplicate vectors first, then publish corrected v2 contracts | | 3. Planetary transfer | Pending | Requires destination packaging and preserved parity corpus | | 4. Mine `vg-csg` | Pending | Requires v1 fixture capture and target Rust package seam | | 5. CultCache/CultNet/CultMesh integration | Pending | Requires current schemas and runtime packages | @@ -135,6 +135,12 @@ a broader stage gate. selected-cut, and chunk record keys. Focused Rust tests passed 4/4; formatting and clippy passed. VibeGeometry commit `82b56db` advances its submodule to that witness commit. Both migration branches are pushed. +- `scripts/build-geometry-unity-package.ps1` staged + `org.gamecult.geometry@0.1.0` successfully. Its manifest depends explicitly + on `org.gamecult.cultmath@0.1.0` and `org.gamecult.cultlib@1.0.7`; the package + contains only its owned `GameCult.Geometry.dll`/symbols plus its asmdef and + documentation. It neither duplicates CultMath nor buries Geometry inside the + CultLib Unity package. ## Decisions and Deviations @@ -152,5 +158,8 @@ a broader stage gate. ## Next Actions -1. Establish and inspect the dedicated `org.gamecult.geometry` UPM artifact. -2. Begin Stage 2 only after the Unity dependency/layout gate is proven. +1. Rewrite Geometry primitives over CultMath and delete `CultVec2`/`CultVec3` + without aliases or forwarding types. +2. Publish v2 geometry documents with typed vectors/quaternion and deliberate + stable-key fixtures; keep v1 only as test evidence. +3. Run repository/package negative searches before beginning planetary transfer. diff --git a/scripts/build-geometry-unity-package.ps1 b/scripts/build-geometry-unity-package.ps1 new file mode 100644 index 00000000..c5665b1e --- /dev/null +++ b/scripts/build-geometry-unity-package.ps1 @@ -0,0 +1,70 @@ +param( + [string] $Configuration = "Release", + [string] $OutputDirectory = "artifacts\unity\org.gamecult.geometry", + [string] $CultMathCandidateFeed = "..\CultMath\.tools\local-feed" +) + +$ErrorActionPreference = "Stop" + +$repoRoot = Split-Path -Parent $PSScriptRoot +$projectPath = Join-Path $repoRoot "src\GameCult.Geometry\GameCult.Geometry.csproj" +$templateRoot = Join-Path $repoRoot "unity\org.gamecult.geometry" +$publishRoot = Join-Path $repoRoot "artifacts\geometry-unity-publish" +$outputRoot = if ([System.IO.Path]::IsPathRooted($OutputDirectory)) { + $OutputDirectory +} else { + Join-Path $repoRoot $OutputDirectory +} +$candidateFeed = if ([System.IO.Path]::IsPathRooted($CultMathCandidateFeed)) { + $CultMathCandidateFeed +} else { + Join-Path $repoRoot $CultMathCandidateFeed +} +$pluginRoot = Join-Path $outputRoot "Runtime\Plugins" + +if (-not (Test-Path -LiteralPath (Join-Path $candidateFeed "CultMath.0.1.0-geometry-migration.1.nupkg"))) { + throw "CultMath migration candidate is missing from $candidateFeed. Pack CultMath before staging Geometry." +} + +if (Test-Path -LiteralPath $publishRoot) { + Remove-Item -LiteralPath $publishRoot -Recurse -Force +} +if (Test-Path -LiteralPath $outputRoot) { + Remove-Item -LiteralPath $outputRoot -Recurse -Force +} + +dotnet restore $projectPath --disable-build-servers -p:CultMathCandidateFeed=$candidateFeed -p:UseSharedCompilation=false -m:1 +if ($LASTEXITCODE -ne 0) { + throw "GameCult.Geometry restore failed with exit code $LASTEXITCODE" +} + +dotnet publish $projectPath -c $Configuration -o $publishRoot --no-restore --disable-build-servers -p:UseSharedCompilation=false -m:1 +if ($LASTEXITCODE -ne 0) { + throw "GameCult.Geometry publish failed with exit code $LASTEXITCODE" +} + +New-Item -ItemType Directory -Force -Path $pluginRoot | Out-Null +Copy-Item -LiteralPath (Join-Path $templateRoot "package.json") -Destination $outputRoot +Copy-Item -LiteralPath (Join-Path $templateRoot "README.md") -Destination $outputRoot +Copy-Item -LiteralPath (Join-Path $templateRoot "Runtime\GameCult.Geometry.asmdef") -Destination (Join-Path $outputRoot "Runtime") + +$geometryAssembly = Join-Path $publishRoot "GameCult.Geometry.dll" +if (-not (Test-Path -LiteralPath $geometryAssembly)) { + throw "Geometry Unity package is missing GameCult.Geometry.dll" +} +Copy-Item -LiteralPath $geometryAssembly -Destination $pluginRoot +$geometrySymbols = [System.IO.Path]::ChangeExtension($geometryAssembly, ".pdb") +if (Test-Path -LiteralPath $geometrySymbols) { + Copy-Item -LiteralPath $geometrySymbols -Destination $pluginRoot +} + +$manifest = Get-Content -LiteralPath (Join-Path $outputRoot "package.json") -Raw | ConvertFrom-Json +$stagedAssemblies = @(Get-ChildItem -LiteralPath $pluginRoot -Filter "*.dll") +if ($stagedAssemblies.Count -ne 1 -or $stagedAssemblies[0].Name -ne "GameCult.Geometry.dll") { + throw "Geometry package must stage only its owned assembly; found: $($stagedAssemblies.Name -join ', ')" +} + +Write-Host "GameCult.Geometry Unity package: $outputRoot" +Write-Host "Package: $($manifest.name)@$($manifest.version)" +Write-Host "Dependencies: $($manifest.dependencies.PSObject.Properties.Name -join ', ')" +Write-Host "Managed assemblies: $($stagedAssemblies.Count)" diff --git a/unity/org.gamecult.geometry/README.md b/unity/org.gamecult.geometry/README.md new file mode 100644 index 00000000..7a6e0823 --- /dev/null +++ b/unity/org.gamecult.geometry/README.md @@ -0,0 +1,12 @@ +# GameCult.Geometry for Unity + +This package is the Unity projection of the GameCult.Geometry authority. It +depends on `org.gamecult.cultmath` for numeric primitives and +`org.gamecult.cultlib` for CultCache/CultNet/CultMesh integration. + +Build it with `scripts/build-geometry-unity-package.ps1`. Do not edit generated +plugin assemblies in the package output. + +CultLib-authored files are MIT licensed. Geometry sources transferred from +CultMath retain their MPL-2.0 notices and provenance; those files will be listed +here as they enter this package. No transferred CultMath source is relicensed. diff --git a/unity/org.gamecult.geometry/Runtime/GameCult.Geometry.asmdef b/unity/org.gamecult.geometry/Runtime/GameCult.Geometry.asmdef new file mode 100644 index 00000000..ea9a8c9f --- /dev/null +++ b/unity/org.gamecult.geometry/Runtime/GameCult.Geometry.asmdef @@ -0,0 +1,19 @@ +{ + "name": "GameCult.Geometry", + "rootNamespace": "GameCult.Geometry", + "references": [ + "CultMath", + "GameCult.CultLib" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": true, + "precompiledReferences": [ + "GameCult.Geometry.dll" + ], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": true +} diff --git a/unity/org.gamecult.geometry/package.json b/unity/org.gamecult.geometry/package.json new file mode 100644 index 00000000..023fed98 --- /dev/null +++ b/unity/org.gamecult.geometry/package.json @@ -0,0 +1,15 @@ +{ + "name": "org.gamecult.geometry", + "displayName": "GameCult.Geometry", + "version": "0.1.0", + "unity": "2021.3", + "description": "GameCult geometry values, typed state contracts, and runtime algorithms built on CultMath primitives.", + "license": "SEE LICENSES IN README.md", + "author": { + "name": "GameCult" + }, + "dependencies": { + "org.gamecult.cultmath": "0.1.0", + "org.gamecult.cultlib": "1.0.7" + } +} From 317b7d538e07bec7b0ee790e3594259b83a9374d Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 03:07:31 +0100 Subject: [PATCH 025/283] Delete duplicate geometry vectors --- ...th-gamecult-geometry-migration-progress.md | 20 ++ packages/cultmesh-ts/test/cultmesh.test.ts | 6 +- .../CultGeometryPrimitives.cs | 184 ++++-------------- src/GameCult.Geometry/README.md | 4 +- .../docs/cross-runtime-primitives-roadmap.md | 4 +- src/GameCult.Mesh/docs/public-api.md | 4 +- .../GeometryDocumentTests.cs | 51 ++--- 7 files changed, 91 insertions(+), 182 deletions(-) diff --git a/docs/cultmath-gamecult-geometry-migration-progress.md b/docs/cultmath-gamecult-geometry-migration-progress.md index ab9b8455..678d98c6 100644 --- a/docs/cultmath-gamecult-geometry-migration-progress.md +++ b/docs/cultmath-gamecult-geometry-migration-progress.md @@ -155,6 +155,26 @@ a broader stage gate. artifacts. v1 remains fixture evidence only; it will not survive as a runtime writer or general compatibility model. - No deviations from the locked target architecture. +- Stage 2 versions all four root geometry documents as one v2 cohort. Domain's + nested CLR layout changes are invisible to the current root-only schema + fingerprint, and leaving SelectedCut as the lone live v1 writer would retain + a split cohort even though its direct fields are unchanged. +- Typed vectors preserve existing record keys by flattening components in the + same authored order into the existing IEEE-754 bit canonicalization. Wire + payloads still change—especially typed mesh arrays—so byte fixtures and v2 + identities remain mandatory. + +### Stage 2 receipts + +- `CultVec2` and `CultVec3` definitions were deleted; `CultRect`, `CultCircle`, + and `CultSphere` now expose CultMath `float2`/`float3` directly. No alias or + conversion owner remains. +- `dotnet test tests/GameCult.Geometry.Tests/GameCult.Geometry.Tests.csproj + --no-restore --verbosity minimal --disable-build-servers + -p:UseSharedCompilation=false -m:1` passed 19/19 for the primitive cut. +- CultMesh native-slice metadata fixtures now name `CultMath.float2` and + `CultMath.float3` while retaining 8/12-byte element widths. Only those three + overlapping lines were staged from the already-dirty TypeScript test file. ## Next Actions diff --git a/packages/cultmesh-ts/test/cultmesh.test.ts b/packages/cultmesh-ts/test/cultmesh.test.ts index 285ee09d..d7f5e267 100644 --- a/packages/cultmesh-ts/test/cultmesh.test.ts +++ b/packages/cultmesh-ts/test/cultmesh.test.ts @@ -1454,7 +1454,7 @@ test("CultMesh TS describes typed surface catalogs for tools and generated bindi "aetheria.zone.render", "gamecult.aetheria.render_body.v1", 128, - [CultMesh.nativeSliceColumn("position", "CultVec2", 8)], + [CultMesh.nativeSliceColumn("position", "CultMath.float2", 8)], { route: routeHint }, ); @@ -2150,7 +2150,7 @@ test("CultMesh TS exposes native slice descriptors", () => { "gamecult.aetheria.zone_render.v1", 12, [ - CultMesh.nativeSliceColumn("position", "CultVec3", 12), + CultMesh.nativeSliceColumn("position", "CultMath.float3", 12), CultMesh.nativeSliceColumn("rotationRadians", "float32", 4), CultMesh.nativeSliceColumn("renderGroupId", "uint32", 4), ], @@ -2163,7 +2163,7 @@ test("CultMesh TS exposes native slice descriptors", () => { assert.equal(CultMesh.denseRowStrideBytes(view), 20); assert.deepEqual(CultMesh.findNativeSliceColumn(view, "position"), { name: "position", - valueType: "CultVec3", + valueType: "CultMath.float3", elementSizeBytes: 12, }); assert.equal(CultMesh.findNativeSliceColumn(view, "missing"), undefined); diff --git a/src/GameCult.Geometry/CultGeometryPrimitives.cs b/src/GameCult.Geometry/CultGeometryPrimitives.cs index 99587b8e..4636a3bc 100644 --- a/src/GameCult.Geometry/CultGeometryPrimitives.cs +++ b/src/GameCult.Geometry/CultGeometryPrimitives.cs @@ -1,126 +1,10 @@ using System; using System.Text.Json.Serialization; +using CultMath; using MessagePack; namespace GameCult.Geometry { - /// - /// Deterministic two-dimensional float vector for cross-runtime geometry and query contracts. - /// - [MessagePackObject] - public readonly struct CultVec2 : IEquatable - { - /// Creates a two-dimensional vector. - public CultVec2(float x, float y) - { - X = x; - Y = y; - } - - /// Gets the x component. - [Key(0)] - public float X { get; } - - /// Gets the y component. - [Key(1)] - public float Y { get; } - - /// Gets the zero vector. - [IgnoreMember] - [JsonIgnore] - public static CultVec2 Zero => new(0f, 0f); - - /// Gets the squared vector length. - [IgnoreMember] - [JsonIgnore] - public float LengthSquared => (X * X) + (Y * Y); - - /// Returns whether this vector is equal to another vector. - public bool Equals(CultVec2 other) => X.Equals(other.X) && Y.Equals(other.Y); - - /// - public override bool Equals(object? obj) => obj is CultVec2 other && Equals(other); - - /// - public override int GetHashCode() => HashCode.Combine(X, Y); - - /// - public override string ToString() => $"({X}, {Y})"; - - public static CultVec2 operator +(CultVec2 left, CultVec2 right) => new(left.X + right.X, left.Y + right.Y); - public static CultVec2 operator -(CultVec2 left, CultVec2 right) => new(left.X - right.X, left.Y - right.Y); - public static CultVec2 operator *(CultVec2 value, float scalar) => new(value.X * scalar, value.Y * scalar); - public static CultVec2 operator /(CultVec2 value, float scalar) => new(value.X / scalar, value.Y / scalar); - public static bool operator ==(CultVec2 left, CultVec2 right) => left.Equals(right); - public static bool operator !=(CultVec2 left, CultVec2 right) => !left.Equals(right); - } - - /// - /// Deterministic three-dimensional float vector for cross-runtime geometry and query contracts. - /// - [MessagePackObject] - public readonly struct CultVec3 : IEquatable - { - /// Creates a three-dimensional vector. - public CultVec3(float x, float y, float z) - { - X = x; - Y = y; - Z = z; - } - - /// Gets the x component. - [Key(0)] - public float X { get; } - - /// Gets the y component. - [Key(1)] - public float Y { get; } - - /// Gets the z component. - [Key(2)] - public float Z { get; } - - /// Gets the zero vector. - [IgnoreMember] - [JsonIgnore] - public static CultVec3 Zero => new(0f, 0f, 0f); - - /// Gets the XY plane projection. - [IgnoreMember] - [JsonIgnore] - public CultVec2 Xy => new(X, Y); - - /// Gets the XZ plane projection for Unity compatibility adapters. - [IgnoreMember] - [JsonIgnore] - public CultVec2 Xz => new(X, Z); - - /// Gets the squared vector length. - [IgnoreMember] - [JsonIgnore] - public float LengthSquared => (X * X) + (Y * Y) + (Z * Z); - - /// Returns whether this vector is equal to another vector. - public bool Equals(CultVec3 other) => X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z); - - /// - public override bool Equals(object? obj) => obj is CultVec3 other && Equals(other); - - /// - public override int GetHashCode() => HashCode.Combine(X, Y, Z); - - /// - public override string ToString() => $"({X}, {Y}, {Z})"; - - public static CultVec3 operator +(CultVec3 left, CultVec3 right) => new(left.X + right.X, left.Y + right.Y, left.Z + right.Z); - public static CultVec3 operator -(CultVec3 left, CultVec3 right) => new(left.X - right.X, left.Y - right.Y, left.Z - right.Z); - public static CultVec3 operator *(CultVec3 value, float scalar) => new(value.X * scalar, value.Y * scalar, value.Z * scalar); - public static CultVec3 operator /(CultVec3 value, float scalar) => new(value.X / scalar, value.Y / scalar, value.Z / scalar); - public static bool operator ==(CultVec3 left, CultVec3 right) => left.Equals(right); - public static bool operator !=(CultVec3 left, CultVec3 right) => !left.Equals(right); - } - /// /// Axis-aligned two-dimensional rectangle represented by canonical min and max corners. /// @@ -128,52 +12,52 @@ namespace GameCult.Geometry public readonly struct CultRect : IEquatable { /// Creates a rectangle and canonicalizes min/max corners. - public CultRect(CultVec2 min, CultVec2 max) + public CultRect(float2 min, float2 max) { - Min = new CultVec2(Math.Min(min.X, max.X), Math.Min(min.Y, max.Y)); - Max = new CultVec2(Math.Max(min.X, max.X), Math.Max(min.Y, max.Y)); + Min = new float2(Math.Min(min.x, max.x), Math.Min(min.y, max.y)); + Max = new float2(Math.Max(min.x, max.x), Math.Max(min.y, max.y)); } /// Creates a rectangle and canonicalizes min/max corners. public CultRect(float minX, float minY, float maxX, float maxY) - : this(new CultVec2(minX, minY), new CultVec2(maxX, maxY)) + : this(new float2(minX, minY), new float2(maxX, maxY)) { } /// Gets the canonical minimum corner. [Key(0)] - public CultVec2 Min { get; } + public float2 Min { get; } /// Gets the canonical maximum corner. [Key(1)] - public CultVec2 Max { get; } + public float2 Max { get; } /// Gets the rectangle size. [IgnoreMember] [JsonIgnore] - public CultVec2 Size => Max - Min; + public float2 Size => Max - Min; /// Gets the rectangle center. [IgnoreMember] [JsonIgnore] - public CultVec2 Center => (Min + Max) * 0.5f; + public float2 Center => (Min + Max) * 0.5f; /// Returns whether the point lies inside or on the rectangle edge. - public bool Contains(CultVec2 point) + public bool Contains(float2 point) { - return point.X >= Min.X && - point.X <= Max.X && - point.Y >= Min.Y && - point.Y <= Max.Y; + return point.x >= Min.x && + point.x <= Max.x && + point.y >= Min.y && + point.y <= Max.y; } /// Returns whether this rectangle intersects another rectangle. public bool Intersects(CultRect other) { - return Min.X <= other.Max.X && - Max.X >= other.Min.X && - Min.Y <= other.Max.Y && - Max.Y >= other.Min.Y; + return Min.x <= other.Max.x && + Max.x >= other.Min.x && + Min.y <= other.Max.y && + Max.y >= other.Min.y; } /// Returns whether this rectangle is equal to another rectangle. @@ -199,7 +83,7 @@ namespace GameCult.Geometry public readonly struct CultCircle : IEquatable { /// Creates a circle. - public CultCircle(CultVec2 center, float radius) + public CultCircle(float2 center, float radius) { if (radius < 0f) { @@ -212,7 +96,7 @@ namespace GameCult.Geometry /// Gets the circle center. [Key(0)] - public CultVec2 Center { get; } + public float2 Center { get; } /// Gets the circle radius. [Key(1)] @@ -222,24 +106,24 @@ namespace GameCult.Geometry [IgnoreMember] [JsonIgnore] public CultRect Bounds => new( - Center.X - Radius, - Center.Y - Radius, - Center.X + Radius, - Center.Y + Radius); + Center.x - Radius, + Center.y - Radius, + Center.x + Radius, + Center.y + Radius); /// Returns whether the point lies inside or on the circle edge. - public bool Contains(CultVec2 point) + public bool Contains(float2 point) { var delta = point - Center; - return delta.LengthSquared <= Radius * Radius; + return ((delta.x * delta.x) + (delta.y * delta.y)) <= Radius * Radius; } /// Returns whether this circle intersects a rectangle. public bool Intersects(CultRect rect) { - var clampedX = Math.Max(rect.Min.X, Math.Min(Center.X, rect.Max.X)); - var clampedY = Math.Max(rect.Min.Y, Math.Min(Center.Y, rect.Max.Y)); - return Contains(new CultVec2(clampedX, clampedY)); + var clampedX = Math.Max(rect.Min.x, Math.Min(Center.x, rect.Max.x)); + var clampedY = Math.Max(rect.Min.y, Math.Min(Center.y, rect.Max.y)); + return Contains(new float2(clampedX, clampedY)); } /// Returns whether this circle is equal to another circle. @@ -262,7 +146,7 @@ namespace GameCult.Geometry public readonly struct CultSphere : IEquatable { /// Creates a sphere. - public CultSphere(CultVec3 center, float radius) + public CultSphere(float3 center, float radius) { if (radius < 0f) { @@ -275,7 +159,7 @@ namespace GameCult.Geometry /// Gets the sphere center. [Key(0)] - public CultVec3 Center { get; } + public float3 Center { get; } /// Gets the sphere radius. [Key(1)] @@ -284,13 +168,13 @@ namespace GameCult.Geometry /// Gets the XY circle projection. [IgnoreMember] [JsonIgnore] - public CultCircle XyCircle => new(Center.Xy, Radius); + public CultCircle XyCircle => new(Center.xy, Radius); /// Returns whether the point lies inside or on the sphere surface. - public bool Contains(CultVec3 point) + public bool Contains(float3 point) { var delta = point - Center; - return delta.LengthSquared <= Radius * Radius; + return ((delta.x * delta.x) + (delta.y * delta.y) + (delta.z * delta.z)) <= Radius * Radius; } /// Returns whether this sphere is equal to another sphere. diff --git a/src/GameCult.Geometry/README.md b/src/GameCult.Geometry/README.md index 200f14ed..4fb881bc 100644 --- a/src/GameCult.Geometry/README.md +++ b/src/GameCult.Geometry/README.md @@ -20,7 +20,7 @@ The package is deliberately substrate-shaped: The small value layer is for cross-runtime query contracts, physics probes, native slices, and UI surfaces: -- `CultVec2` and `CultVec3`: whole-vector values for positions, velocities, +- `CultMath.float2` and `CultMath.float3`: whole-vector values for positions, velocities, accelerations, and query inputs. SoA layouts may store them efficiently, but the semantic API does not force callers to split x/y/z into unrelated fields. - `CultRect`: canonical XY viewport/query rectangle stored as min/max corners. @@ -72,7 +72,7 @@ cache miss; that is split-brain geometry. ## Documents -- `CultVec2`, `CultVec3`, `CultRect`, `CultCircle`, `CultSphere`: shared value +- `CultMath.float2`, `CultMath.float3`, `CultRect`, `CultCircle`, `CultSphere`: shared value primitives for query and view contracts. - `CultGeometryDomainDocument`: one hierarchical domain tree, suitable for Ragnarok/Fensalir-style feature DSL output. diff --git a/src/GameCult.Mesh/docs/cross-runtime-primitives-roadmap.md b/src/GameCult.Mesh/docs/cross-runtime-primitives-roadmap.md index 93fb3f3c..53db8c7b 100644 --- a/src/GameCult.Mesh/docs/cross-runtime-primitives-roadmap.md +++ b/src/GameCult.Mesh/docs/cross-runtime-primitives-roadmap.md @@ -121,7 +121,7 @@ var viewport = await aetheria.Zone(zoneId) await aetheria.Entity(ravenId) .Pilot() - .MoveAsync(CultVec2.Right, claim: "pilot-control"); + .MoveAsync(new CultMath.float2(1f, 0f), claim: "pilot-control"); ``` Current seed: @@ -134,7 +134,7 @@ var verse = await CultMesh.ConnectVerseAsync( new[] { new CultMeshAuthorityClaim("pilot-control", shardId: "zone:raven") }); var aetheria = verse.Use(context => new AetheriaGeneratedFacade(context)); -await aetheria.Entity(ravenId).Pilot.MoveAsync(CultVec2.Right); +await aetheria.Entity(ravenId).Pilot.MoveAsync(new CultMath.float2(1f, 0f)); ``` ```ts diff --git a/src/GameCult.Mesh/docs/public-api.md b/src/GameCult.Mesh/docs/public-api.md index 512b3e30..ff00e515 100644 --- a/src/GameCult.Mesh/docs/public-api.md +++ b/src/GameCult.Mesh/docs/public-api.md @@ -393,8 +393,8 @@ var view = new CultMeshNativeSliceViewDescriptor( rowCount, new[] { - CultMeshNativeSliceColumn.For("position"), - CultMeshNativeSliceColumn.For("velocity") + CultMeshNativeSliceColumn.For("position"), + CultMeshNativeSliceColumn.For("velocity") }, new CultMeshRouteHint(CultMeshLocalityKind.SharedMemory)); ``` diff --git a/tests/GameCult.Geometry.Tests/GeometryDocumentTests.cs b/tests/GameCult.Geometry.Tests/GeometryDocumentTests.cs index b39b5182..1c50ab80 100644 --- a/tests/GameCult.Geometry.Tests/GeometryDocumentTests.cs +++ b/tests/GameCult.Geometry.Tests/GeometryDocumentTests.cs @@ -3,6 +3,7 @@ using GameCult.Caching; using GameCult.Caching.MessagePack; using GameCult.Mesh; using GameCult.Networking; +using CultMath; using MessagePack; using NUnit.Framework; using R3; @@ -21,52 +22,56 @@ namespace GameCult.Geometry.Tests { var viewport = new CultRect(8f, 4f, -8f, -4f); - viewport.Min.Should().Be(new CultVec2(-8f, -4f)); - viewport.Max.Should().Be(new CultVec2(8f, 4f)); - viewport.Center.Should().Be(CultVec2.Zero); - viewport.Contains(new CultVec2(2f, 3f)).Should().BeTrue(); + viewport.Min.Should().Be(new float2(-8f, -4f)); + viewport.Max.Should().Be(new float2(8f, 4f)); + viewport.Center.Should().Be(float2.zero); + viewport.Contains(new float2(2f, 3f)).Should().BeTrue(); viewport.Intersects(new CultRect(7f, 3f, 10f, 5f)).Should().BeTrue(); viewport.Intersects(new CultRect(9f, 5f, 10f, 6f)).Should().BeFalse(); - var gravityBrush = new CultCircle(new CultVec2(10f, 0f), 3f); + var gravityBrush = new CultCircle(new float2(10f, 0f), 3f); gravityBrush.Intersects(viewport).Should().BeTrue(); - gravityBrush.Contains(new CultVec2(12f, 0f)).Should().BeTrue(); - gravityBrush.Contains(new CultVec2(14f, 0f)).Should().BeFalse(); + gravityBrush.Contains(new float2(12f, 0f)).Should().BeTrue(); + gravityBrush.Contains(new float2(14f, 0f)).Should().BeFalse(); } [Test] public void GeometryPrimitives_PreserveWholeVectorsForSoaAndPhysicsQueries() { - var sphere = new CultSphere(new CultVec3(1f, 2f, 3f), 5f); + var sphere = new CultSphere(new float3(1f, 2f, 3f), 5f); - sphere.Contains(new CultVec3(1f, 6f, 3f)).Should().BeTrue(); - sphere.Contains(new CultVec3(1f, 8f, 3f)).Should().BeFalse(); - sphere.Center.Xy.Should().Be(new CultVec2(1f, 2f)); - sphere.Center.Xz.Should().Be(new CultVec2(1f, 3f)); + sphere.Contains(new float3(1f, 6f, 3f)).Should().BeTrue(); + sphere.Contains(new float3(1f, 8f, 3f)).Should().BeFalse(); + sphere.Center.xy.Should().Be(new float2(1f, 2f)); + sphere.Center.xz.Should().Be(new float2(1f, 3f)); sphere.XyCircle.Bounds.Should().Be(new CultRect(-4f, -3f, 6f, 7f)); } [Test] public void GeometryPrimitives_RoundTripThroughMessagePack() { - var rect = new CultRect(new CultVec2(5f, -2f), new CultVec2(-1f, 7f)); - var payload = MessagePackSerializer.Serialize(rect); - var decoded = MessagePackSerializer.Deserialize(payload); + var rect = new CultRect(new float2(5f, -2f), new float2(-1f, 7f)); + var options = CultDocumentMessagePackSerialization.OptionsFor(typeof(CultRect)); + var payload = MessagePackSerializer.Serialize(rect, options); + var decoded = MessagePackSerializer.Deserialize(payload, options); decoded.Should().Be(rect); - decoded.Min.Should().Be(new CultVec2(-1f, -2f)); - decoded.Max.Should().Be(new CultVec2(5f, 7f)); + decoded.Min.Should().Be(new float2(-1f, -2f)); + decoded.Max.Should().Be(new float2(5f, 7f)); } [Test] - public void GeometryPrimitives_JsonOmitsComputedConvenienceProperties() + public void GeometryPrimitive_JsonInspectionProjection_UsesLowercaseComponents() { - var json = JsonSerializer.Serialize(new CultVec3(1f, 2f, 3f)); + var value = new float3(1f, 2f, 3f); + var json = JsonSerializer.Serialize(new { value.x, value.y, value.z }); - json.Should().Be("""{"X":1,"Y":2,"Z":3}"""); - json.Should().NotContain("LengthSquared"); - json.Should().NotContain("Xy"); - json.Should().NotContain("Xz"); + json.Should().Contain("\"x\":1"); + json.Should().Contain("\"y\":2"); + json.Should().Contain("\"z\":3"); + json.Should().NotContain("\"X\""); + json.Should().NotContain("\"Y\""); + json.Should().NotContain("\"Z\""); } [Test] From 8a219a479a6ffc4df17f1900fb7f335672a18801 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 03:12:55 +0100 Subject: [PATCH 026/283] Publish typed geometry v2 contracts --- ...th-gamecult-geometry-migration-progress.md | 11 +++ .../CultGeometryDocuments.cs | 59 +++++++----- .../GeometryDocumentTests.cs | 91 +++++++++++-------- 3 files changed, 97 insertions(+), 64 deletions(-) diff --git a/docs/cultmath-gamecult-geometry-migration-progress.md b/docs/cultmath-gamecult-geometry-migration-progress.md index 678d98c6..4f964208 100644 --- a/docs/cultmath-gamecult-geometry-migration-progress.md +++ b/docs/cultmath-gamecult-geometry-migration-progress.md @@ -175,6 +175,17 @@ a broader stage gate. - CultMesh native-slice metadata fixtures now name `CultMath.float2` and `CultMath.float3` while retaining 8/12-byte element widths. Only those three overlapping lines were staged from the already-dirty TypeScript test file. +- All four root geometry schemas now form a v2 cohort with their original slot + numbers. Semantic single vectors use `float3`/`quaternion`; mesh vertices, + normals, and UVs use `float3[]`/`float2[]`. The runtime contains no v1 DTO, + reader, writer, or conversion authority. +- Live v2 semantic SchemaIds are pinned as domain `sha256:e335...421d`, build + request `sha256:2de3...21d3`, selected cut `sha256:8644...9ff8`, and chunk + artifact `sha256:2d28...6156`. Full values live in the executable tests. +- Typed stable fingerprints flatten components into the prior ordered IEEE-bit + stream. Domain/chunk round trips preserve record identity, while the checked- + in flat-mesh v1 payload is retained as negative evidence and rejected by the + v2 decoder. The Geometry suite passes 19/19 after the cohort cut. ## Next Actions diff --git a/src/GameCult.Geometry/CultGeometryDocuments.cs b/src/GameCult.Geometry/CultGeometryDocuments.cs index 306b5849..68fc5514 100644 --- a/src/GameCult.Geometry/CultGeometryDocuments.cs +++ b/src/GameCult.Geometry/CultGeometryDocuments.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Security.Cryptography; using System.Text; using GameCult.Caching; +using CultMath; using MessagePack; using static GameCult.Geometry.CultGeometryDocuments; @@ -14,10 +15,10 @@ namespace GameCult.Geometry /// 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"; + public const string Domain = "gamecult.geometry.domain.v2"; + public const string BuildRequest = "gamecult.geometry.build_request.v2"; + public const string SelectedCut = "gamecult.geometry.selected_cut.v2"; + public const string ChunkArtifact = "gamecult.geometry.chunk_artifact.v2"; } /// @@ -67,10 +68,10 @@ namespace GameCult.Geometry public string Kind { get; set; } = string.Empty; [Key(2)] - public float[] Translation { get; set; } = Array.Empty(); + public float3 Translation { get; set; } [Key(3)] - public float[] RotationXyzw { get; set; } = Array.Empty(); + public quaternion Rotation { get; set; } = quaternion.identity; [Key(4)] public ulong Seed { get; set; } @@ -88,7 +89,7 @@ namespace GameCult.Geometry Name, Kind, StableVector(Translation), - StableVector(RotationXyzw), + StableVector(Rotation), Seed.ToString(CultureInfo.InvariantCulture) } .Concat(Claims.Select(claim => claim.StableFingerprint())) @@ -109,16 +110,16 @@ namespace GameCult.Geometry public string Name { get; set; } = string.Empty; [Key(1)] - public float[] Translation { get; set; } = Array.Empty(); + public float3 Translation { get; set; } [Key(2)] - public float[] RotationXyzw { get; set; } = Array.Empty(); + public quaternion Rotation { get; set; } = quaternion.identity; [Key(3)] - public float[] SupportCenter { get; set; } = Array.Empty(); + public float3 SupportCenter { get; set; } [Key(4)] - public float[] SupportSize { get; set; } = Array.Empty(); + public float3 SupportSize { get; set; } [Key(5)] public string Kind { get; set; } = string.Empty; @@ -132,7 +133,7 @@ namespace GameCult.Geometry public string StableFingerprint() => StableArray([ Name, StableVector(Translation), - StableVector(RotationXyzw), + StableVector(Rotation), StableVector(SupportCenter), StableVector(SupportSize), Kind, @@ -161,13 +162,13 @@ namespace GameCult.Geometry public string WorkerGroup { get; set; } = string.Empty; [Key(3)] - public float[] CameraPosition { get; set; } = Array.Empty(); + public float3 CameraPosition { get; set; } [Key(4)] - public float[] FrustumMin { get; set; } = Array.Empty(); + public float3 FrustumMin { get; set; } [Key(5)] - public float[] FrustumMax { get; set; } = Array.Empty(); + public float3 FrustumMax { get; set; } [Key(6)] public float ViewportHeightPixels { get; set; } @@ -321,10 +322,10 @@ namespace GameCult.Geometry public string SelectedCutId { get; set; } = string.Empty; [Key(3)] - public float[] BoundsMin { get; set; } = Array.Empty(); + public float3 BoundsMin { get; set; } [Key(4)] - public float[] BoundsMax { get; set; } = Array.Empty(); + public float3 BoundsMax { get; set; } [Key(5)] public string[] SourceDomainKeys { get; set; } = Array.Empty(); @@ -374,13 +375,13 @@ namespace GameCult.Geometry public sealed class CultGeometryTriangleMesh { [Key(0)] - public float[] Positions { get; set; } = Array.Empty(); + public float3[] Positions { get; set; } = Array.Empty(); [Key(1)] - public float[] Normals { get; set; } = Array.Empty(); + public float3[] Normals { get; set; } = Array.Empty(); [Key(2)] - public float[] Uvs { get; set; } = Array.Empty(); + public float2[] Uvs { get; set; } = Array.Empty(); [Key(3)] public uint[] Indices { get; set; } = Array.Empty(); @@ -409,10 +410,20 @@ namespace GameCult.Geometry return string.Concat(bytes.Select(value => value.ToString("x2"))); } - public static string StableVector(float[] values) - { - return string.Join(",", values.Select(StableFloat)); - } + public static string StableVector(float2 value) => + string.Join(",", StableFloat(value.x), StableFloat(value.y)); + + public static string StableVector(float3 value) => + string.Join(",", StableFloat(value.x), StableFloat(value.y), StableFloat(value.z)); + + public static string StableVector(quaternion value) => + string.Join(",", StableFloat(value.x), StableFloat(value.y), StableFloat(value.z), StableFloat(value.w)); + + public static string StableVector(float2[] values) => + string.Join(",", values.SelectMany(value => new[] { value.x, value.y }).Select(StableFloat)); + + public static string StableVector(float3[] values) => + string.Join(",", values.SelectMany(value => new[] { value.x, value.y, value.z }).Select(StableFloat)); public static string StableFloat(float value) { diff --git a/tests/GameCult.Geometry.Tests/GeometryDocumentTests.cs b/tests/GameCult.Geometry.Tests/GeometryDocumentTests.cs index 1c50ab80..345c270e 100644 --- a/tests/GameCult.Geometry.Tests/GeometryDocumentTests.cs +++ b/tests/GameCult.Geometry.Tests/GeometryDocumentTests.cs @@ -87,6 +87,15 @@ namespace GameCult.Geometry.Tests .Should().Be(CultGeometrySchemaVersions.SelectedCut); cache.Registry.GetRequired().SchemaVersion .Should().Be(CultGeometrySchemaVersions.ChunkArtifact); + + cache.Registry.GetRequired().SchemaId + .Should().Be("sha256:e3358436f8a07c84cc66b5196380cdfcd6920fa15f15d052d30b42b73762421d"); + cache.Registry.GetRequired().SchemaId + .Should().Be("sha256:2de3162db128fc2c5cc2ea3dae46d0196110a9e5f969997002309e636a3721d3"); + cache.Registry.GetRequired().SchemaId + .Should().Be("sha256:864412d3cf0f6b079ceb0bbd3b36232f11380e63cdf0bfd64d505a710fb49ff8"); + cache.Registry.GetRequired().SchemaId + .Should().Be("sha256:2d28046b7c76244ced70ee6de09bcbb5c64d364aa578e5a4c903d397a7a56156"); } [Test] @@ -98,9 +107,9 @@ namespace GameCult.Geometry.Tests { DomainKey = domainKey.Value, WorkerGroup = "ragnarok-column-workers", - CameraPosition = [36f, -42f, 30f], - FrustumMin = [-75f, -75f, -30f], - FrustumMax = [75f, 75f, 120f], + CameraPosition = new float3(36f, -42f, 30f), + FrustumMin = new float3(-75f, -75f, -30f), + FrustumMax = new float3(75f, 75f, 120f), ViewportHeightPixels = 1080f, VerticalFovRadians = 1.0471976f, TargetError = 0.01f, @@ -131,6 +140,11 @@ namespace GameCult.Geometry.Tests decoded.ChunkId.Should().Be(chunk.ChunkId); decoded.RenderMesh.TriangleCount.Should().Be(1); + decoded.BoundsMin.Should().Be(new float3(-1f, -1f, 0f)); + decoded.RenderMesh.Positions.Should().Equal(chunk.RenderMesh.Positions); + decoded.RenderMesh.Normals.Should().HaveCount(decoded.RenderMesh.Positions.Length); + decoded.RenderMesh.Uvs.Should().HaveCount(decoded.RenderMesh.Positions.Length); + decoded.RenderMesh.Indices.Length.Should().Be(decoded.RenderMesh.TriangleMaterials.Length * 3); CultGeometryChunkArtifact.CreateRecordKey(decoded) .Should().Be(CultGeometryChunkArtifact.CreateRecordKey(chunk)); } @@ -152,29 +166,26 @@ namespace GameCult.Geometry.Tests } [Test] - public void RustExportedDomainDocument_DecodesWithStableCultCacheKey() + public void TypedV2Domain_RoundTripsAndPreservesTheV1RecordKey() { - var payload = File.ReadAllBytes(FixturePath("ragnarok-domain.msgpack")); - var domain = CultDocumentMessagePackSerialization.Deserialize(payload); + var domain = SampleDomain(); + var payload = CultDocumentMessagePackSerialization.Serialize(domain); + var decoded = CultDocumentMessagePackSerialization.Deserialize(payload); - domain.DomainId.Should().Be("ragnarok-column"); - domain.Root.Children.Should().NotBeEmpty(); - domain.Root.Children[0].Name.Should().Be("stellarator-column-00"); - CultGeometryDomainDocument.CreateRecordKey(domain).Value - .Should().Be("geometry:domain:02c9b5810977406b0c206f3a3494327a423abb9448192be1b9a1863cd0f2ed95"); + decoded.Root.Rotation.Should().Be(quaternion.identity); + decoded.Root.Children[0].Claims[0].SupportCenter.Should().Be(new float3(0f, 0f, 45f)); + CultGeometryDomainDocument.CreateRecordKey(decoded).Value.Should().Be( + "geometry:domain:175899ea97548da0599e12bcaccd07fa1d6009ed450fadb3de229d47bab04431"); } [Test] - public void RustExportedChunkArtifact_DecodesWithStableCultCacheKey() + public void V2Chunk_DoesNotAcceptTheLegacyFlatMeshPayload() { var payload = File.ReadAllBytes(FixturePath("ragnarok-first-chunk.msgpack")); - var chunk = CultDocumentMessagePackSerialization.Deserialize(payload); - chunk.ChunkId.Should().StartWith("chunk/"); - chunk.RenderMesh.TriangleCount.Should().BeGreaterThan(0); - chunk.SourceDomainKeys.Should().NotBeEmpty(); - CultGeometryChunkArtifact.CreateRecordKey(chunk).Value - .Should().Be("geometry:chunk:b94dcd7d6776df15d0fa5fcf7f4b24f1384876b13b2d38cc57c4468136521af5"); + FluentActions.Invoking(() => + CultDocumentMessagePackSerialization.Deserialize(payload)) + .Should().Throw(); } [Test] @@ -325,8 +336,8 @@ namespace GameCult.Geometry.Tests { Name = "ragnarok-column", Kind = "Root", - Translation = [0f, 0f, 0f], - RotationXyzw = [0f, 0f, 0f, 1f], + Translation = float3.zero, + Rotation = quaternion.identity, Seed = 0x5EED, Claims = [], Children = @@ -335,18 +346,18 @@ namespace GameCult.Geometry.Tests { Name = "stellarator-column-00", Kind = "Column", - Translation = [0f, 0f, 0f], - RotationXyzw = [0f, 0f, 0f, 1f], + Translation = float3.zero, + Rotation = quaternion.identity, 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], + Translation = float3.zero, + Rotation = quaternion.identity, + SupportCenter = new float3(0f, 0f, 45f), + SupportSize = new float3(18f, 18f, 96f), Kind = "SupportShell", Material = 10, LoweringPolicy = "RenderAndCollider" @@ -359,15 +370,6 @@ namespace GameCult.Geometry.Tests }; } - private static string FixturePath(string fileName) - { - return Path.Combine( - TestContext.CurrentContext.TestDirectory, - "Fixtures", - "vg-csg-ragnarok", - fileName); - } - private static CultGeometryChunkArtifact SampleChunk() { return new CultGeometryChunkArtifact @@ -375,15 +377,15 @@ namespace GameCult.Geometry.Tests ChunkId = "chunk/ragnarok-column/column-00", CutKey = "geometry:cut:test", SelectedCutId = "cut-test", - BoundsMin = [-1f, -1f, 0f], - BoundsMax = [1f, 1f, 1f], + BoundsMin = new float3(-1f, -1f, 0f), + BoundsMax = new float3(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], + Positions = [new float3(0f, 0f, 0f), new float3(1f, 0f, 0f), new float3(0f, 1f, 0f)], + Normals = [new float3(0f, 0f, 1f), new float3(0f, 0f, 1f), new float3(0f, 0f, 1f)], + Uvs = [new float2(0f, 0f), new float2(1f, 0f), new float2(0f, 1f)], Indices = [0u, 1u, 2u], TriangleMaterials = [20u] }, @@ -393,5 +395,14 @@ namespace GameCult.Geometry.Tests SupportsParentChildCoexistence = true }; } + + private static string FixturePath(string fileName) + { + return Path.Combine( + TestContext.CurrentContext.TestDirectory, + "Fixtures", + "vg-csg-ragnarok", + fileName); + } } } From 92934716307f1b78ce9b51c057be04000a7212ee Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 03:25:46 +0100 Subject: [PATCH 027/283] Add cross-runtime geometry v2 contract --- .gitignore | 3 + ...th-gamecult-geometry-migration-progress.md | 27 +- packages/gamecult-geometry-rs/Cargo.lock | 194 ++++++ packages/gamecult-geometry-rs/Cargo.toml | 14 + packages/gamecult-geometry-rs/LICENSE | 22 + packages/gamecult-geometry-rs/README.md | 11 + packages/gamecult-geometry-rs/src/lib.rs | 578 ++++++++++++++++++ .../CultGeometryDocuments.cs | 6 +- .../GeometryV2WireParityTests.cs | 153 +++++ 9 files changed, 998 insertions(+), 10 deletions(-) create mode 100644 packages/gamecult-geometry-rs/Cargo.lock create mode 100644 packages/gamecult-geometry-rs/Cargo.toml create mode 100644 packages/gamecult-geometry-rs/LICENSE create mode 100644 packages/gamecult-geometry-rs/README.md create mode 100644 packages/gamecult-geometry-rs/src/lib.rs create mode 100644 tests/GameCult.Geometry.Tests/GeometryV2WireParityTests.cs diff --git a/.gitignore b/.gitignore index d639c709..2e7fdf6c 100644 --- a/.gitignore +++ b/.gitignore @@ -206,6 +206,9 @@ PublishScripts/ *.snupkg # The packages folder can be ignored because of Package Restore **/[Pp]ackages/* +!/packages/gamecult-geometry-rs/ +!/packages/gamecult-geometry-rs/** +packages/gamecult-geometry-rs/target/ # except build/, which is used as an MSBuild target. !**/[Pp]ackages/build/ # Uncomment if necessary however generally it will be regenerated when needed diff --git a/docs/cultmath-gamecult-geometry-migration-progress.md b/docs/cultmath-gamecult-geometry-migration-progress.md index 4f964208..3fefd608 100644 --- a/docs/cultmath-gamecult-geometry-migration-progress.md +++ b/docs/cultmath-gamecult-geometry-migration-progress.md @@ -56,8 +56,8 @@ Demotions: | --- | --- | --- | | 0. Freeze and baseline | Complete | Source bodies, contracts, consumers, licenses, fixtures, and focused baselines mapped | | 1. Destination/dependency/formatters/SoA | Complete | NuGet and dedicated UPM artifacts prove dependency direction and owned vector integration | -| 2. Primitive deletion and v2 schemas | In progress | Delete duplicate vectors first, then publish corrected v2 contracts | -| 3. Planetary transfer | Pending | Requires destination packaging and preserved parity corpus | +| 2. Primitive deletion and v2 schemas | Complete | C# and Geometry-owned Rust emit identical v2 bytes and record keys for all four roots | +| 3. Planetary transfer | In progress | Transfer C#/tests first, then shaders and runtime projections; delete CultMath owners in the same stage | | 4. Mine `vg-csg` | Pending | Requires v1 fixture capture and target Rust package seam | | 5. CultCache/CultNet/CultMesh integration | Pending | Requires current schemas and runtime packages | | 6. Consumer cutover/release | Pending | Requires local candidate feed and downstream passes | @@ -186,11 +186,24 @@ a broader stage gate. stream. Domain/chunk round trips preserve record identity, while the checked- in flat-mesh v1 payload is retained as negative evidence and rejected by the v2 decoder. The Geometry suite passes 19/19 after the cohort cut. +- `packages/gamecult-geometry-rs` is the Geometry-owned Rust v2 destination. + It has no VibeGeometry, `vg-csg`, `bevy_math`, CultCache, or CultNet + dependency and preserves the MIT provenance of the mined `vg-csg` contract. +- C# and Rust pin identical exact MessagePack bytes and record keys for domain, + build request, selected cut, and chunk roots. C# decodes the Rust witnesses + and re-emits the same bytes. The Geometry suite passes 24/24; Rust passes 4/4, + doc tests, rustfmt, and warning-denied clippy. +- The parity pass exposed an old split identity: C# request scalar floats used + round-trip decimal text while `vg-csg` used IEEE-bit hex. v2 deliberately + standardizes every float on IEEE bits. The request key therefore changes at + the v2 boundary; signed zero, a chosen NaN payload, and infinity are pinned + across MessagePack so this cannot quietly diverge again. ## Next Actions -1. Rewrite Geometry primitives over CultMath and delete `CultVec2`/`CultVec3` - without aliases or forwarding types. -2. Publish v2 geometry documents with typed vectors/quaternion and deliberate - stable-key fixtures; keep v1 only as test evidence. -3. Run repository/package negative searches before beginning planetary transfer. +1. Establish the Geometry-owned planetary parity harness and move the 13 C# + source/test files while deleting the matching CultMath owners and `rect`. +2. Transfer and rename planetary/erosion HLSL ownership, then remove the + implicit geometry includes and bodies from `CultMath.hlsl`. +3. Transfer the CMPT tool/web decoder, Unity adapters/sample, docs, and license + notices; inspect both packages and run the complete negative gate. diff --git a/packages/gamecult-geometry-rs/Cargo.lock b/packages/gamecult-geometry-rs/Cargo.lock new file mode 100644 index 00000000..ba7661a8 --- /dev/null +++ b/packages/gamecult-geometry-rs/Cargo.lock @@ -0,0 +1,194 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "gamecult-geometry" +version = "0.1.0" +dependencies = [ + "rmp-serde", + "serde", + "sha2", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rmp" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ba8be72d372b2c9b35542551678538b562e7cf86c3315773cae48dfbfe7790c" +dependencies = [ + "num-traits", +] + +[[package]] +name = "rmp-serde" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f81bee8c8ef9b577d1681a70ebbc962c232461e397b22c208c43c04b67a155" +dependencies = [ + "rmp", + "serde", +] + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "syn" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" diff --git a/packages/gamecult-geometry-rs/Cargo.toml b/packages/gamecult-geometry-rs/Cargo.toml new file mode 100644 index 00000000..4cabb87a --- /dev/null +++ b/packages/gamecult-geometry-rs/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "gamecult-geometry" +version = "0.1.0" +edition = "2024" +description = "GameCult.Geometry typed contracts and geometry runtime for Rust" +license = "MIT" +repository = "https://github.com/GameCult/CultLib" +readme = "README.md" + +[dependencies] +rmp-serde = "1" +serde = { version = "1", features = ["derive"] } +sha2 = "0.10" + diff --git a/packages/gamecult-geometry-rs/LICENSE b/packages/gamecult-geometry-rs/LICENSE new file mode 100644 index 00000000..a431c3ab --- /dev/null +++ b/packages/gamecult-geometry-rs/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2026 GameCult + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/packages/gamecult-geometry-rs/README.md b/packages/gamecult-geometry-rs/README.md new file mode 100644 index 00000000..0b3ec053 --- /dev/null +++ b/packages/gamecult-geometry-rs/README.md @@ -0,0 +1,11 @@ +# GameCult.Geometry for Rust + +Rust projection of the GameCult.Geometry v2 document contract. It owns the +typed MessagePack layouts and stable geometry record identities used at the +Rust boundary; it does not depend on VibeGeometry or `vg-csg`. + +The initial contract and stable-hash implementation were mined from the +MIT-licensed GameCult `vg-csg` crate at commit `8f070f4`. The implementation +was rewritten here under GameCult.Geometry ownership. The original copyright +and MIT terms are preserved in [LICENSE](LICENSE). + diff --git a/packages/gamecult-geometry-rs/src/lib.rs b/packages/gamecult-geometry-rs/src/lib.rs new file mode 100644 index 00000000..7882c457 --- /dev/null +++ b/packages/gamecult-geometry-rs/src/lib.rs @@ -0,0 +1,578 @@ +//! GameCult.Geometry's Rust contract and runtime surface. +//! +//! The v2 contract was mined from the MIT-licensed GameCult `vg-csg` crate at +//! commit `8f070f4`, then rewritten around typed vector values. This crate has +//! no runtime or build dependency on VibeGeometry or `vg-csg`. + +use std::fmt::Write; + +use serde::{Deserialize, Serialize, de::DeserializeOwned}; +use sha2::{Digest, Sha256}; + +pub const GEOMETRY_DOMAIN_SCHEMA: &str = "gamecult.geometry.domain.v2"; +pub const GEOMETRY_BUILD_REQUEST_SCHEMA: &str = "gamecult.geometry.build_request.v2"; +pub const GEOMETRY_SELECTED_CUT_SCHEMA: &str = "gamecult.geometry.selected_cut.v2"; +pub const GEOMETRY_CHUNK_ARTIFACT_SCHEMA: &str = "gamecult.geometry.chunk_artifact.v2"; + +#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)] +pub struct Float2(pub f32, pub f32); + +#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)] +pub struct Float3(pub f32, pub f32, pub f32); + +#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] +pub struct Quaternion(pub f32, pub f32, pub f32, pub f32); + +impl Default for Quaternion { + fn default() -> Self { + Self(0.0, 0.0, 0.0, 1.0) + } +} + +pub trait GeometryDocument: Serialize + DeserializeOwned + Sized { + const SCHEMA_VERSION: &'static str; + fn record_key(&self) -> String; + fn to_msgpack(&self) -> Result, rmp_serde::encode::Error> { + rmp_serde::to_vec(self) + } + fn from_msgpack(payload: &[u8]) -> Result { + rmp_serde::from_slice(payload) + } +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct GeometryDomainDocument( + pub String, + pub String, + pub String, + pub GeometryDomainNode, + pub String, +); + +impl GeometryDocument for GeometryDomainDocument { + const SCHEMA_VERSION: &'static str = GEOMETRY_DOMAIN_SCHEMA; + fn record_key(&self) -> String { + format!( + "geometry:domain:{}", + stable_hash(&[&self.1, &self.2, &self.3.stable_fingerprint()]) + ) + } +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct GeometryDomainNode( + pub String, + pub String, + pub Float3, + pub Quaternion, + pub u64, + pub Vec, + pub Vec, +); + +impl GeometryDomainNode { + pub fn stable_fingerprint(&self) -> String { + let mut parts = vec![ + self.0.clone(), + self.1.clone(), + stable_float3(self.2), + stable_quaternion(self.3), + self.4.to_string(), + ]; + parts.extend(self.5.iter().map(GeometryFeatureClaim::stable_fingerprint)); + parts.extend(self.6.iter().map(GeometryDomainNode::stable_fingerprint)); + stable_join(&parts) + } +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct GeometryFeatureClaim( + pub String, + pub Float3, + pub Quaternion, + pub Float3, + pub Float3, + pub String, + pub u32, + pub String, +); + +impl GeometryFeatureClaim { + pub fn stable_fingerprint(&self) -> String { + stable_join(&[ + self.0.clone(), + stable_float3(self.1), + stable_quaternion(self.2), + stable_float3(self.3), + stable_float3(self.4), + self.5.clone(), + self.6.to_string(), + self.7.clone(), + ]) + } +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct GeometryBuildRequest( + pub String, + pub String, + pub String, + pub Float3, + pub Float3, + pub Float3, + pub f32, + pub f32, + pub f32, + pub i32, + pub i32, + pub Vec, + pub Vec, + pub Vec, + pub String, +); + +impl GeometryDocument for GeometryBuildRequest { + const SCHEMA_VERSION: &'static str = GEOMETRY_BUILD_REQUEST_SCHEMA; + fn record_key(&self) -> String { + format!( + "geometry:request:{}", + stable_hash(&[ + &self.1, + &self.2, + &stable_float3(self.3), + &stable_float3(self.4), + &stable_float3(self.5), + &stable_f32(self.6), + &stable_f32(self.7), + &stable_f32(self.8), + &self.9.to_string(), + &self.10.to_string(), + &stable_join(&self.11), + &stable_join(&self.12), + &stable_join(&self.13), + ]) + ) + } +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct GeometrySelectedCutManifest( + pub String, + pub String, + pub Vec, + pub Vec, + pub Vec, + pub Vec, +); + +impl GeometryDocument for GeometrySelectedCutManifest { + const SCHEMA_VERSION: &'static str = GEOMETRY_SELECTED_CUT_SCHEMA; + fn record_key(&self) -> String { + format!( + "geometry:cut:{}", + stable_hash(&[ + &self.1, + &self.0, + &stable_join(&self.2), + &stable_join(&self.3), + &stable_join(&self.4), + ]) + ) + } +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct GeometryContributionRow( + pub String, + pub String, + pub f32, + pub f32, + pub f32, + pub i32, + pub i32, + pub i32, + pub bool, + pub bool, + pub bool, + pub bool, + pub bool, +); + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct GeometryChunkArtifact( + pub String, + pub String, + pub String, + pub Float3, + pub Float3, + pub Vec, + pub Vec, + pub GeometryTriangleMesh, + pub Option, + pub i32, + pub i32, + pub i32, + pub u64, + pub bool, +); + +impl GeometryDocument for GeometryChunkArtifact { + const SCHEMA_VERSION: &'static str = GEOMETRY_CHUNK_ARTIFACT_SCHEMA; + fn record_key(&self) -> String { + format!( + "geometry:chunk:{}", + stable_hash(&[ + &self.1, + &self.0, + &self.2, + &stable_join(&self.5), + &stable_join(&self.6), + &self.7.stable_fingerprint(), + self.8 + .as_ref() + .map(GeometryTriangleMesh::stable_fingerprint) + .as_deref() + .unwrap_or(""), + ]) + ) + } +} + +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] +pub struct GeometryTriangleMesh( + pub Vec, + pub Vec, + pub Vec, + pub Vec, + pub Vec, +); + +impl GeometryTriangleMesh { + pub fn triangle_count(&self) -> usize { + self.3.len() / 3 + } + pub fn stable_fingerprint(&self) -> String { + stable_hash(&[ + &stable_float3_array(&self.0), + &stable_float3_array(&self.1), + &stable_float2_array(&self.2), + &stable_u32_array(&self.3), + &stable_u32_array(&self.4), + ]) + } +} + +fn stable_hash(parts: &[&str]) -> String { + let mut hasher = Sha256::new(); + hasher.update(parts.join("\u{1f}").as_bytes()); + let mut output = String::with_capacity(64); + for byte in hasher.finalize() { + write!(&mut output, "{byte:02x}").expect("string write"); + } + output +} + +fn stable_join(parts: &[String]) -> String { + parts.join("\u{1e}") +} +fn stable_f32(value: f32) -> String { + format!("{:08x}", value.to_bits()) +} +fn stable_float2(value: Float2) -> String { + format!("{},{}", stable_f32(value.0), stable_f32(value.1)) +} +fn stable_float3(value: Float3) -> String { + format!( + "{},{},{}", + stable_f32(value.0), + stable_f32(value.1), + stable_f32(value.2) + ) +} +fn stable_quaternion(value: Quaternion) -> String { + format!( + "{},{},{},{}", + stable_f32(value.0), + stable_f32(value.1), + stable_f32(value.2), + stable_f32(value.3) + ) +} +fn stable_float2_array(values: &[Float2]) -> String { + values + .iter() + .map(|v| stable_float2(*v)) + .collect::>() + .join(",") +} +fn stable_float3_array(values: &[Float3]) -> String { + values + .iter() + .map(|v| stable_float3(*v)) + .collect::>() + .join(",") +} +fn stable_u32_array(values: &[u32]) -> String { + values + .iter() + .map(u32::to_string) + .collect::>() + .join(",") +} + +#[cfg(test)] +mod tests { + use super::*; + + fn domain() -> GeometryDomainDocument { + GeometryDomainDocument( + "fixture-domain".into(), + "fixture/root".into(), + "gamecult-geometry-rs".into(), + GeometryDomainNode( + "root".into(), + "Root".into(), + Float3(1.0, -2.5, 0.0), + Quaternion::default(), + 42, + vec![], + vec![], + ), + "2026-07-22T00:00:00Z".into(), + ) + } + + fn chunk() -> GeometryChunkArtifact { + GeometryChunkArtifact( + "fixture/chunk".into(), + "geometry:cut:fixture".into(), + "cut-fixture".into(), + Float3(-1.0, -2.0, -3.0), + Float3(1.0, 2.0, 3.0), + vec!["fixture/root".into()], + vec!["fixture/root/claim".into()], + GeometryTriangleMesh( + vec![ + Float3(0.0, 0.0, 0.0), + Float3(1.0, 0.0, 0.0), + Float3(0.0, 1.0, 0.0), + ], + vec![Float3(0.0, 0.0, 1.0); 3], + vec![Float2(0.0, 0.0), Float2(1.0, 0.0), Float2(0.0, 1.0)], + vec![0, 1, 2], + vec![7], + ), + None, + 1, + 0, + 0, + 0x0123_4567_89ab_cdef, + true, + ) + } + + fn request() -> GeometryBuildRequest { + GeometryBuildRequest( + "request-fixture".into(), + domain().record_key(), + "workers".into(), + Float3(1.0, 2.0, 3.0), + Float3(-4.0, -5.0, -6.0), + Float3(4.0, 5.0, 6.0), + 1080.0, + 1.0, + 0.25, + 100, + 50, + vec!["Root".into()], + vec![], + vec![], + "2026-07-22T00:00:01Z".into(), + ) + } + + fn cut() -> GeometrySelectedCutManifest { + GeometrySelectedCutManifest( + "cut-fixture".into(), + "geometry:request:fixture".into(), + vec!["fixture/root".into()], + vec![], + vec![], + vec![], + ) + } + + #[test] + fn schema_versions_are_v2() { + assert_eq!( + GeometryDomainDocument::SCHEMA_VERSION, + "gamecult.geometry.domain.v2" + ); + assert_eq!( + GeometryBuildRequest::SCHEMA_VERSION, + "gamecult.geometry.build_request.v2" + ); + assert_eq!( + GeometrySelectedCutManifest::SCHEMA_VERSION, + "gamecult.geometry.selected_cut.v2" + ); + assert_eq!( + GeometryChunkArtifact::SCHEMA_VERSION, + "gamecult.geometry.chunk_artifact.v2" + ); + } + + #[test] + fn domain_record_key_matches_csharp_v2_fixture() { + let document = GeometryDomainDocument( + "ragnarok-column".into(), + "ragnarok-column".into(), + "vg-csg".into(), + GeometryDomainNode( + "ragnarok-column".into(), + "Root".into(), + Float3::default(), + Quaternion::default(), + 0x5eed, + vec![], + vec![GeometryDomainNode( + "stellarator-column-00".into(), + "Column".into(), + Float3::default(), + Quaternion::default(), + 0xc011_0000, + vec![GeometryFeatureClaim( + "column-support-shell".into(), + Float3::default(), + Quaternion::default(), + Float3(0.0, 0.0, 45.0), + Float3(18.0, 18.0, 96.0), + "SupportShell".into(), + 10, + "RenderAndCollider".into(), + )], + vec![], + )], + ), + "2026-05-29T00:00:00.0000000Z".into(), + ); + + assert_eq!( + document.record_key(), + "geometry:domain:175899ea97548da0599e12bcaccd07fa1d6009ed450fadb3de229d47bab04431" + ); + } + + #[test] + fn exact_v2_messagepack_and_record_key_witnesses() { + let domain = domain(); + let chunk = chunk(); + let request = request(); + let cut = cut(); + assert_eq!( + domain.record_key(), + "geometry:domain:505c94e7393580a4e5b048b169aa4da955da606ffd28c054b766a4b94e50502e" + ); + assert_eq!( + request.record_key(), + "geometry:request:36e25b80c04a6c54c8b3137abb4a8c961468a9b1c0e7dd4d5632cf5a6f847966" + ); + assert_eq!( + cut.record_key(), + "geometry:cut:5614eae3fe2a17dca651d1e32f401c50e1c3b9cf941f5789655990325da64fb3" + ); + assert_eq!( + chunk.record_key(), + "geometry:chunk:ca2874d3638800179c906087ec817ea715c43b70b99ead04edccce2a1b3d6ebb" + ); + assert_eq!( + domain.to_msgpack().unwrap(), + [ + 149, 174, 102, 105, 120, 116, 117, 114, 101, 45, 100, 111, 109, 97, 105, 110, 172, + 102, 105, 120, 116, 117, 114, 101, 47, 114, 111, 111, 116, 180, 103, 97, 109, 101, + 99, 117, 108, 116, 45, 103, 101, 111, 109, 101, 116, 114, 121, 45, 114, 115, 151, + 164, 114, 111, 111, 116, 164, 82, 111, 111, 116, 147, 202, 63, 128, 0, 0, 202, 192, + 32, 0, 0, 202, 0, 0, 0, 0, 148, 202, 0, 0, 0, 0, 202, 0, 0, 0, 0, 202, 0, 0, 0, 0, + 202, 63, 128, 0, 0, 42, 144, 144, 180, 50, 48, 50, 54, 45, 48, 55, 45, 50, 50, 84, + 48, 48, 58, 48, 48, 58, 48, 48, 90 + ] + ); + assert_eq!( + request.to_msgpack().unwrap(), + [ + 159, 175, 114, 101, 113, 117, 101, 115, 116, 45, 102, 105, 120, 116, 117, 114, 101, + 217, 80, 103, 101, 111, 109, 101, 116, 114, 121, 58, 100, 111, 109, 97, 105, 110, + 58, 53, 48, 53, 99, 57, 52, 101, 55, 51, 57, 51, 53, 56, 48, 97, 52, 101, 53, 98, + 48, 52, 56, 98, 49, 54, 57, 97, 97, 52, 100, 97, 57, 53, 53, 100, 97, 54, 48, 54, + 102, 102, 100, 50, 56, 99, 48, 53, 52, 98, 55, 54, 54, 97, 52, 98, 57, 52, 101, 53, + 48, 53, 48, 50, 101, 167, 119, 111, 114, 107, 101, 114, 115, 147, 202, 63, 128, 0, + 0, 202, 64, 0, 0, 0, 202, 64, 64, 0, 0, 147, 202, 192, 128, 0, 0, 202, 192, 160, 0, + 0, 202, 192, 192, 0, 0, 147, 202, 64, 128, 0, 0, 202, 64, 160, 0, 0, 202, 64, 192, + 0, 0, 202, 68, 135, 0, 0, 202, 63, 128, 0, 0, 202, 62, 128, 0, 0, 100, 50, 145, + 164, 82, 111, 111, 116, 144, 144, 180, 50, 48, 50, 54, 45, 48, 55, 45, 50, 50, 84, + 48, 48, 58, 48, 48, 58, 48, 49, 90 + ] + ); + assert_eq!( + cut.to_msgpack().unwrap(), + [ + 150, 171, 99, 117, 116, 45, 102, 105, 120, 116, 117, 114, 101, 184, 103, 101, 111, + 109, 101, 116, 114, 121, 58, 114, 101, 113, 117, 101, 115, 116, 58, 102, 105, 120, + 116, 117, 114, 101, 145, 172, 102, 105, 120, 116, 117, 114, 101, 47, 114, 111, 111, + 116, 144, 144, 144 + ] + ); + assert_eq!( + chunk.to_msgpack().unwrap(), + [ + 158, 173, 102, 105, 120, 116, 117, 114, 101, 47, 99, 104, 117, 110, 107, 180, 103, + 101, 111, 109, 101, 116, 114, 121, 58, 99, 117, 116, 58, 102, 105, 120, 116, 117, + 114, 101, 171, 99, 117, 116, 45, 102, 105, 120, 116, 117, 114, 101, 147, 202, 191, + 128, 0, 0, 202, 192, 0, 0, 0, 202, 192, 64, 0, 0, 147, 202, 63, 128, 0, 0, 202, 64, + 0, 0, 0, 202, 64, 64, 0, 0, 145, 172, 102, 105, 120, 116, 117, 114, 101, 47, 114, + 111, 111, 116, 145, 178, 102, 105, 120, 116, 117, 114, 101, 47, 114, 111, 111, 116, + 47, 99, 108, 97, 105, 109, 149, 147, 147, 202, 0, 0, 0, 0, 202, 0, 0, 0, 0, 202, 0, + 0, 0, 0, 147, 202, 63, 128, 0, 0, 202, 0, 0, 0, 0, 202, 0, 0, 0, 0, 147, 202, 0, 0, + 0, 0, 202, 63, 128, 0, 0, 202, 0, 0, 0, 0, 147, 147, 202, 0, 0, 0, 0, 202, 0, 0, 0, + 0, 202, 63, 128, 0, 0, 147, 202, 0, 0, 0, 0, 202, 0, 0, 0, 0, 202, 63, 128, 0, 0, + 147, 202, 0, 0, 0, 0, 202, 0, 0, 0, 0, 202, 63, 128, 0, 0, 147, 146, 202, 0, 0, 0, + 0, 202, 0, 0, 0, 0, 146, 202, 63, 128, 0, 0, 202, 0, 0, 0, 0, 146, 202, 0, 0, 0, 0, + 202, 63, 128, 0, 0, 147, 0, 1, 2, 145, 7, 192, 1, 0, 0, 207, 1, 35, 69, 103, 137, + 171, 205, 239, 195 + ] + ); + assert_eq!( + GeometryDomainDocument::from_msgpack(&domain.to_msgpack().unwrap()).unwrap(), + domain + ); + assert_eq!( + GeometryChunkArtifact::from_msgpack(&chunk.to_msgpack().unwrap()).unwrap(), + chunk + ); + assert_eq!( + GeometryBuildRequest::from_msgpack(&request.to_msgpack().unwrap()).unwrap(), + request + ); + assert_eq!( + GeometrySelectedCutManifest::from_msgpack(&cut.to_msgpack().unwrap()).unwrap(), + cut + ); + } + + #[test] + fn scalar_bit_identity_is_stable_through_messagepack() { + let mut signed_zero = request(); + signed_zero.6 = -0.0; + signed_zero.7 = f32::from_bits(0x7fc0_1234); + signed_zero.8 = f32::NEG_INFINITY; + assert_eq!( + signed_zero.record_key(), + "geometry:request:978dd0913fc3e12c04766e065320d485d172d60d61be920a9a32637d1c439c81" + ); + let decoded = + GeometryBuildRequest::from_msgpack(&signed_zero.to_msgpack().unwrap()).unwrap(); + assert_eq!(decoded.6.to_bits(), 0x8000_0000); + assert_eq!(decoded.7.to_bits(), 0x7fc0_1234); + assert_eq!(decoded.8.to_bits(), f32::NEG_INFINITY.to_bits()); + } +} diff --git a/src/GameCult.Geometry/CultGeometryDocuments.cs b/src/GameCult.Geometry/CultGeometryDocuments.cs index 68fc5514..afb6d305 100644 --- a/src/GameCult.Geometry/CultGeometryDocuments.cs +++ b/src/GameCult.Geometry/CultGeometryDocuments.cs @@ -206,9 +206,9 @@ namespace GameCult.Geometry 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), + StableFloat(request.ViewportHeightPixels), + StableFloat(request.VerticalFovRadians), + StableFloat(request.TargetError), request.TriangleBudget.ToString(CultureInfo.InvariantCulture), request.ColliderBudget.ToString(CultureInfo.InvariantCulture), StableArray(request.SemanticFilter), diff --git a/tests/GameCult.Geometry.Tests/GeometryV2WireParityTests.cs b/tests/GameCult.Geometry.Tests/GeometryV2WireParityTests.cs new file mode 100644 index 00000000..4c475683 --- /dev/null +++ b/tests/GameCult.Geometry.Tests/GeometryV2WireParityTests.cs @@ -0,0 +1,153 @@ +using System; +using CultMath; +using FluentAssertions; +using GameCult.Caching.MessagePack; +using NUnit.Framework; + +namespace GameCult.Geometry.Tests; + +public sealed class GeometryV2WireParityTests +{ + private const string DomainHex = "95AE666978747572652D646F6D61696EAC666978747572652F726F6F74B467616D6563756C742D67656F6D657472792D727397A4726F6F74A4526F6F7493CA3F800000CAC0200000CA0000000094CA00000000CA00000000CA00000000CA3F8000002A9090B4323032362D30372D32325430303A30303A30305A"; + private const string RequestHex = "9FAF726571756573742D66697874757265D95067656F6D657472793A646F6D61696E3A35303563393465373339333538306134653562303438623136396161346461393535646136303666666432386330353462373636613462393465353035303265A7776F726B65727393CA3F800000CA40000000CA4040000093CAC0800000CAC0A00000CAC0C0000093CA40800000CA40A00000CA40C00000CA44870000CA3F800000CA3E800000643291A4526F6F749090B4323032362D30372D32325430303A30303A30315A"; + private const string CutHex = "96AB6375742D66697874757265B867656F6D657472793A726571756573743A6669787475726591AC666978747572652F726F6F74909090"; + private const string ChunkHex = "9EAD666978747572652F6368756E6BB467656F6D657472793A6375743A66697874757265AB6375742D6669787475726593CABF800000CAC0000000CAC040000093CA3F800000CA40000000CA4040000091AC666978747572652F726F6F7491B2666978747572652F726F6F742F636C61696D959393CA00000000CA00000000CA0000000093CA3F800000CA00000000CA0000000093CA00000000CA3F800000CA000000009393CA00000000CA00000000CA3F80000093CA00000000CA00000000CA3F80000093CA00000000CA00000000CA3F8000009392CA00000000CA0000000092CA3F800000CA0000000092CA00000000CA3F800000930001029107C0010000CF0123456789ABCDEFC3"; + + [Test] + public void Domain_MatchesRustV2BytesAndKey() + { + var document = Domain(); + AssertWire(document, DomainHex); + CultGeometryDomainDocument.CreateRecordKey(document).Value.Should().Be( + "geometry:domain:505c94e7393580a4e5b048b169aa4da955da606ffd28c054b766a4b94e50502e"); + } + + [Test] + public void BuildRequest_MatchesRustV2BytesAndKey() + { + var document = Request(); + AssertWire(document, RequestHex); + CultGeometryBuildRequest.CreateRecordKey(document).Value.Should().Be( + "geometry:request:36e25b80c04a6c54c8b3137abb4a8c961468a9b1c0e7dd4d5632cf5a6f847966"); + } + + [Test] + public void SelectedCut_MatchesRustV2BytesAndKey() + { + var document = Cut(); + AssertWire(document, CutHex); + CultGeometrySelectedCutManifest.CreateRecordKey(document).Value.Should().Be( + "geometry:cut:5614eae3fe2a17dca651d1e32f401c50e1c3b9cf941f5789655990325da64fb3"); + } + + [Test] + public void Chunk_MatchesRustV2BytesAndKey() + { + var document = Chunk(); + AssertWire(document, ChunkHex); + CultGeometryChunkArtifact.CreateRecordKey(document).Value.Should().Be( + "geometry:chunk:ca2874d3638800179c906087ec817ea715c43b70b99ead04edccce2a1b3d6ebb"); + } + + [Test] + public void BuildRequest_ScalarIdentityUsesExactIeeeBits() + { + var document = Request(); + document.ViewportHeightPixels = -0f; + document.VerticalFovRadians = BitConverter.Int32BitsToSingle(unchecked((int)0x7fc01234)); + document.TargetError = float.NegativeInfinity; + + CultGeometryBuildRequest.CreateRecordKey(document).Value.Should().Be( + "geometry:request:978dd0913fc3e12c04766e065320d485d172d60d61be920a9a32637d1c439c81"); + + var payload = CultDocumentMessagePackSerialization.Serialize(document); + var decoded = CultDocumentMessagePackSerialization.Deserialize(payload); + BitConverter.SingleToInt32Bits(decoded.ViewportHeightPixels).Should().Be(unchecked((int)0x80000000)); + BitConverter.SingleToInt32Bits(decoded.VerticalFovRadians).Should().Be(unchecked((int)0x7fc01234)); + BitConverter.SingleToInt32Bits(decoded.TargetError).Should().Be(unchecked((int)0xff800000)); + } + + private static void AssertWire(T document, string expectedHex) + { + var payload = CultDocumentMessagePackSerialization.Serialize(document); + Convert.ToHexString(payload).Should().Be(expectedHex); + var decoded = CultDocumentMessagePackSerialization.Deserialize(payload); + Convert.ToHexString(CultDocumentMessagePackSerialization.Serialize(decoded)).Should().Be(expectedHex); + + var rustPayload = Convert.FromHexString(expectedHex); + var decodedFromRust = CultDocumentMessagePackSerialization.Deserialize(rustPayload); + Convert.ToHexString(CultDocumentMessagePackSerialization.Serialize(decodedFromRust)).Should().Be(expectedHex); + } + + private static CultGeometryDomainDocument Domain() => new() + { + DomainId = "fixture-domain", + RootKey = "fixture/root", + SourceRuntime = "gamecult-geometry-rs", + Root = new CultGeometryDomainNode + { + Name = "root", + Kind = "Root", + Translation = new float3(1f, -2.5f, 0f), + Rotation = quaternion.identity, + Seed = 42, + Claims = [], + Children = [], + }, + CreatedAt = "2026-07-22T00:00:00Z", + }; + + private static CultGeometryBuildRequest Request() => new() + { + RequestId = "request-fixture", + DomainKey = CultGeometryDomainDocument.CreateRecordKey(Domain()).Value, + WorkerGroup = "workers", + CameraPosition = new float3(1f, 2f, 3f), + FrustumMin = new float3(-4f, -5f, -6f), + FrustumMax = new float3(4f, 5f, 6f), + ViewportHeightPixels = 1080f, + VerticalFovRadians = 1f, + TargetError = 0.25f, + TriangleBudget = 100, + ColliderBudget = 50, + SemanticFilter = ["Root"], + RequestedChunkKeys = [], + DirtyDomainKeys = [], + CreatedAt = "2026-07-22T00:00:01Z", + }; + + private static CultGeometrySelectedCutManifest Cut() => new() + { + CutId = "cut-fixture", + RequestKey = "geometry:request:fixture", + SelectedNodes = ["fixture/root"], + DeferredChildRequests = [], + ParentFallbackNodes = [], + Diagnostics = [], + }; + + private static CultGeometryChunkArtifact Chunk() => new() + { + ChunkId = "fixture/chunk", + CutKey = "geometry:cut:fixture", + SelectedCutId = "cut-fixture", + BoundsMin = new float3(-1f, -2f, -3f), + BoundsMax = new float3(1f, 2f, 3f), + SourceDomainKeys = ["fixture/root"], + SourceClaimKeys = ["fixture/root/claim"], + RenderMesh = new CultGeometryTriangleMesh + { + Positions = [new float3(0f, 0f, 0f), new float3(1f, 0f, 0f), new float3(0f, 1f, 0f)], + Normals = [new float3(0f, 0f, 1f), new float3(0f, 0f, 1f), new float3(0f, 0f, 1f)], + Uvs = [new float2(0f, 0f), new float2(1f, 0f), new float2(0f, 1f)], + Indices = [0, 1, 2], + TriangleMaterials = [7], + }, + ColliderMesh = null, + InputBrushes = 1, + CandidatePairs = 0, + RejectedPairs = 0, + StableClipSeed = 0x0123_4567_89ab_cdef, + SupportsParentChildCoexistence = true, + }; +} From 6a162606e4bed08de8b3250d708db9b841c92d1b Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 03:47:38 +0100 Subject: [PATCH 028/283] Transfer planetary geometry to GameCult.Geometry --- CultMath.slnx | 3 - README.md | 11 - .../CultMath.PlanetaryViewer.Editor.asmdef | 18 - .../Editor/CultMathPlanetaryViewerMenu.cs | 26 -- Samples~/PlanetaryViewer/README.md | 16 - .../Runtime/CultMath.PlanetaryViewer.asmdef | 17 - .../Runtime/CultMathPlanetaryViewer.cs | 139 ------- .../Runtime/CultMathPlanetaryViewer.shader | 90 ---- THIRD-PARTY-NOTICES.md | 23 - .../CultMath.PlanetaryTileFixture.csproj | 11 - .../CultMath.PlanetaryTileFixture/Program.cs | 22 - docs/design.md | 6 - docs/planetary.md | 130 ------ docs/planetary.md.meta | 7 - package.json | 9 +- scripts/test-web-planetary-tile.ps1 | 9 - scripts/test-web-planetary-tile.ps1.meta | 7 - shaders/AdvancedErosionFilter.hlsl | 147 ------- shaders/AdvancedErosionFilter.hlsl.meta | 7 - shaders/CultMath.hlsl | 94 ----- shaders/Planetary.hlsl | 392 ------------------ shaders/Planetary.hlsl.meta | 7 - src/CultMath/AdvancedErosionFilter.cs | 139 ------- src/CultMath/AdvancedErosionFilter.cs.meta | 2 - src/CultMath/CultMath.csproj | 2 - src/CultMath/ErosionFrequencyBands.cs | 57 --- src/CultMath/ErosionFrequencyBands.cs.meta | 2 - src/CultMath/PlanetaryField.cs | 215 ---------- src/CultMath/PlanetaryField.cs.meta | 2 - src/CultMath/PlanetaryGpuPages.cs | 55 --- src/CultMath/PlanetaryGpuPages.cs.meta | 2 - src/CultMath/PlanetaryMapTileEncoding.cs | 117 ------ src/CultMath/PlanetaryMapTileEncoding.cs.meta | 2 - src/CultMath/PlanetaryPages.cs | 187 --------- src/CultMath/PlanetaryPages.cs.meta | 2 - src/CultMath/PlanetaryPatch.cs | 45 -- src/CultMath/PlanetaryPatch.cs.meta | 2 - src/CultMath/PlanetaryProjection.cs | 322 -------------- src/CultMath/PlanetaryProjection.cs.meta | 2 - src/CultMath/PlanetaryQueries.cs | 193 --------- src/CultMath/PlanetaryQueries.cs.meta | 2 - src/CultMath/PlanetaryRadialRefinement.cs | 28 -- .../PlanetaryRadialRefinement.cs.meta | 2 - src/CultMath/PlanetaryResidency.cs | 148 ------- src/CultMath/PlanetaryResidency.cs.meta | 2 - src/CultMath/PlanetaryTopology.cs | 191 --------- src/CultMath/PlanetaryTopology.cs.meta | 2 - src/CultMath/SphericalErosion.cs | 108 ----- src/CultMath/SphericalErosion.cs.meta | 2 - src/CultMath/math.cs | 3 - src/CultMath/rect.cs | 21 - src/CultMath/rect.cs.meta | 2 - .../AdvancedErosionFilterTests.cs | 44 -- .../AdvancedErosionFilterTests.cs.meta | 2 - .../ErosionFrequencyBandsTests.cs | 34 -- .../ErosionFrequencyBandsTests.cs.meta | 2 - tests/CultMath.Tests/HlslMirrorTests.cs | 37 +- tests/CultMath.Tests/MathTests.cs | 13 - tests/CultMath.Tests/PlanetaryFieldTests.cs | 80 ---- .../PlanetaryFieldTests.cs.meta | 2 - tests/CultMath.Tests/PlanetaryGpuPageTests.cs | 25 -- .../PlanetaryGpuPageTests.cs.meta | 2 - .../PlanetaryMapTileEncodingTests.cs | 52 --- .../PlanetaryMapTileEncodingTests.cs.meta | 2 - tests/CultMath.Tests/PlanetaryPageTests.cs | 57 --- .../CultMath.Tests/PlanetaryPageTests.cs.meta | 2 - tests/CultMath.Tests/PlanetaryPatchTests.cs | 40 -- .../PlanetaryPatchTests.cs.meta | 2 - .../PlanetaryProjectionTests.cs | 73 ---- .../PlanetaryProjectionTests.cs.meta | 2 - tests/CultMath.Tests/PlanetaryQueryTests.cs | 46 -- .../PlanetaryQueryTests.cs.meta | 2 - .../PlanetaryRadialRefinementTests.cs | 29 -- .../PlanetaryRadialRefinementTests.cs.meta | 2 - .../CultMath.Tests/PlanetaryResidencyTests.cs | 57 --- .../PlanetaryResidencyTests.cs.meta | 2 - .../CultMath.Tests/PlanetaryTopologyTests.cs | 63 --- .../PlanetaryTopologyTests.cs.meta | 2 - tests/CultMath.Tests/SphericalErosionTests.cs | 34 -- .../SphericalErosionTests.cs.meta | 2 - tools/CultMath.PlanetaryTileFixture.meta | 8 - unity/Runtime/PlanetaryPageUpload.cs | 95 ----- unity/Runtime/PlanetaryPageUpload.cs.meta | 2 - unity/Runtime/PlanetaryPatchMeshAdapter.cs | 36 -- .../Runtime/PlanetaryPatchMeshAdapter.cs.meta | 2 - web/planetary-tile.cross-runtime.test.mjs | 21 - ...planetary-tile.cross-runtime.test.mjs.meta | 7 - web/planetary-tile.test.mjs | 39 -- web/planetary-tile.test.mjs.meta | 7 - web/planetary-tile.ts | 89 ---- web/planetary-tile.ts.meta | 7 - 91 files changed, 6 insertions(+), 4067 deletions(-) delete mode 100644 Samples~/PlanetaryViewer/Editor/CultMath.PlanetaryViewer.Editor.asmdef delete mode 100644 Samples~/PlanetaryViewer/Editor/CultMathPlanetaryViewerMenu.cs delete mode 100644 Samples~/PlanetaryViewer/README.md delete mode 100644 Samples~/PlanetaryViewer/Runtime/CultMath.PlanetaryViewer.asmdef delete mode 100644 Samples~/PlanetaryViewer/Runtime/CultMathPlanetaryViewer.cs delete mode 100644 Samples~/PlanetaryViewer/Runtime/CultMathPlanetaryViewer.shader delete mode 100644 Tools~/CultMath.PlanetaryTileFixture/CultMath.PlanetaryTileFixture.csproj delete mode 100644 Tools~/CultMath.PlanetaryTileFixture/Program.cs delete mode 100644 docs/planetary.md delete mode 100644 docs/planetary.md.meta delete mode 100644 scripts/test-web-planetary-tile.ps1 delete mode 100644 scripts/test-web-planetary-tile.ps1.meta delete mode 100644 shaders/AdvancedErosionFilter.hlsl delete mode 100644 shaders/AdvancedErosionFilter.hlsl.meta delete mode 100644 shaders/Planetary.hlsl delete mode 100644 shaders/Planetary.hlsl.meta delete mode 100644 src/CultMath/AdvancedErosionFilter.cs delete mode 100644 src/CultMath/AdvancedErosionFilter.cs.meta delete mode 100644 src/CultMath/ErosionFrequencyBands.cs delete mode 100644 src/CultMath/ErosionFrequencyBands.cs.meta delete mode 100644 src/CultMath/PlanetaryField.cs delete mode 100644 src/CultMath/PlanetaryField.cs.meta delete mode 100644 src/CultMath/PlanetaryGpuPages.cs delete mode 100644 src/CultMath/PlanetaryGpuPages.cs.meta delete mode 100644 src/CultMath/PlanetaryMapTileEncoding.cs delete mode 100644 src/CultMath/PlanetaryMapTileEncoding.cs.meta delete mode 100644 src/CultMath/PlanetaryPages.cs delete mode 100644 src/CultMath/PlanetaryPages.cs.meta delete mode 100644 src/CultMath/PlanetaryPatch.cs delete mode 100644 src/CultMath/PlanetaryPatch.cs.meta delete mode 100644 src/CultMath/PlanetaryProjection.cs delete mode 100644 src/CultMath/PlanetaryProjection.cs.meta delete mode 100644 src/CultMath/PlanetaryQueries.cs delete mode 100644 src/CultMath/PlanetaryQueries.cs.meta delete mode 100644 src/CultMath/PlanetaryRadialRefinement.cs delete mode 100644 src/CultMath/PlanetaryRadialRefinement.cs.meta delete mode 100644 src/CultMath/PlanetaryResidency.cs delete mode 100644 src/CultMath/PlanetaryResidency.cs.meta delete mode 100644 src/CultMath/PlanetaryTopology.cs delete mode 100644 src/CultMath/PlanetaryTopology.cs.meta delete mode 100644 src/CultMath/SphericalErosion.cs delete mode 100644 src/CultMath/SphericalErosion.cs.meta delete mode 100644 src/CultMath/rect.cs delete mode 100644 src/CultMath/rect.cs.meta delete mode 100644 tests/CultMath.Tests/AdvancedErosionFilterTests.cs delete mode 100644 tests/CultMath.Tests/AdvancedErosionFilterTests.cs.meta delete mode 100644 tests/CultMath.Tests/ErosionFrequencyBandsTests.cs delete mode 100644 tests/CultMath.Tests/ErosionFrequencyBandsTests.cs.meta delete mode 100644 tests/CultMath.Tests/PlanetaryFieldTests.cs delete mode 100644 tests/CultMath.Tests/PlanetaryFieldTests.cs.meta delete mode 100644 tests/CultMath.Tests/PlanetaryGpuPageTests.cs delete mode 100644 tests/CultMath.Tests/PlanetaryGpuPageTests.cs.meta delete mode 100644 tests/CultMath.Tests/PlanetaryMapTileEncodingTests.cs delete mode 100644 tests/CultMath.Tests/PlanetaryMapTileEncodingTests.cs.meta delete mode 100644 tests/CultMath.Tests/PlanetaryPageTests.cs delete mode 100644 tests/CultMath.Tests/PlanetaryPageTests.cs.meta delete mode 100644 tests/CultMath.Tests/PlanetaryPatchTests.cs delete mode 100644 tests/CultMath.Tests/PlanetaryPatchTests.cs.meta delete mode 100644 tests/CultMath.Tests/PlanetaryProjectionTests.cs delete mode 100644 tests/CultMath.Tests/PlanetaryProjectionTests.cs.meta delete mode 100644 tests/CultMath.Tests/PlanetaryQueryTests.cs delete mode 100644 tests/CultMath.Tests/PlanetaryQueryTests.cs.meta delete mode 100644 tests/CultMath.Tests/PlanetaryRadialRefinementTests.cs delete mode 100644 tests/CultMath.Tests/PlanetaryRadialRefinementTests.cs.meta delete mode 100644 tests/CultMath.Tests/PlanetaryResidencyTests.cs delete mode 100644 tests/CultMath.Tests/PlanetaryResidencyTests.cs.meta delete mode 100644 tests/CultMath.Tests/PlanetaryTopologyTests.cs delete mode 100644 tests/CultMath.Tests/PlanetaryTopologyTests.cs.meta delete mode 100644 tests/CultMath.Tests/SphericalErosionTests.cs delete mode 100644 tests/CultMath.Tests/SphericalErosionTests.cs.meta delete mode 100644 tools/CultMath.PlanetaryTileFixture.meta delete mode 100644 unity/Runtime/PlanetaryPageUpload.cs delete mode 100644 unity/Runtime/PlanetaryPageUpload.cs.meta delete mode 100644 unity/Runtime/PlanetaryPatchMeshAdapter.cs delete mode 100644 unity/Runtime/PlanetaryPatchMeshAdapter.cs.meta delete mode 100644 web/planetary-tile.cross-runtime.test.mjs delete mode 100644 web/planetary-tile.cross-runtime.test.mjs.meta delete mode 100644 web/planetary-tile.test.mjs delete mode 100644 web/planetary-tile.test.mjs.meta delete mode 100644 web/planetary-tile.ts delete mode 100644 web/planetary-tile.ts.meta diff --git a/CultMath.slnx b/CultMath.slnx index 05d17886..95834573 100644 --- a/CultMath.slnx +++ b/CultMath.slnx @@ -5,7 +5,4 @@ - - - diff --git a/README.md b/README.md index c60a9912..b471c7fd 100644 --- a/README.md +++ b/README.md @@ -30,12 +30,6 @@ shader semantics. - `Voronoi.SampleTones`, a C# batch surface that calls the Rust `cultmath-core` native kernel when `cultmath_core` is available and falls back to the managed parity path otherwise. -- `PlanetaryField`, a scale-aware CPU/HLSL spherical field contract with - deterministic identity, cube-sphere topology, residual pages, LOD residency, - ray/path/region queries, coarse patches, and projected map-tile baking. See - `docs/planetary.md`. -- `CultMath.Unity`, an engine-facing assembly containing only Unity mesh and - page-upload adapters for the canonical planetary contracts. ## Native Core @@ -72,11 +66,6 @@ local `AetheriaMath` surface. The value-noise family follows public shader literature from Inigo Quilez's noise and mini-spline articles, expressed in CultMath names with tests instead of copied project-local helper drift. -The advanced erosion filter is an MPL-2.0 adaptation of Rune Skovbo Johansen's -published filter. Its faithful planar core is isolated in -`AdvancedErosionFilter.cs` and `AdvancedErosionFilter.hlsl`; spherical mapping -is a separate CultMath concern. See `THIRD-PARTY-NOTICES.md`. - ## Build ```powershell diff --git a/Samples~/PlanetaryViewer/Editor/CultMath.PlanetaryViewer.Editor.asmdef b/Samples~/PlanetaryViewer/Editor/CultMath.PlanetaryViewer.Editor.asmdef deleted file mode 100644 index 10512326..00000000 --- a/Samples~/PlanetaryViewer/Editor/CultMath.PlanetaryViewer.Editor.asmdef +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "CultMath.PlanetaryViewer.Editor", - "rootNamespace": "CultMath.Unity.Samples.Editor", - "references": [ - "CultMath.PlanetaryViewer" - ], - "includePlatforms": [ - "Editor" - ], - "excludePlatforms": [], - "allowUnsafeCode": false, - "overrideReferences": false, - "precompiledReferences": [], - "autoReferenced": true, - "defineConstraints": [], - "versionDefines": [], - "noEngineReferences": false -} diff --git a/Samples~/PlanetaryViewer/Editor/CultMathPlanetaryViewerMenu.cs b/Samples~/PlanetaryViewer/Editor/CultMathPlanetaryViewerMenu.cs deleted file mode 100644 index ade28c30..00000000 --- a/Samples~/PlanetaryViewer/Editor/CultMathPlanetaryViewerMenu.cs +++ /dev/null @@ -1,26 +0,0 @@ -using UnityEditor; -using UnityEngine; - -namespace CultMath.Unity.Samples.Editor; - -public static class CultMathPlanetaryViewerMenu -{ - [MenuItem("GameObject/CultMath/Planetary Field Viewer", false, 10)] - public static void CreateViewer() - { - var root = new GameObject("CultMath Planetary Field Viewer"); - Undo.RegisterCreatedObjectUndo(root, "Create CultMath Planetary Viewer"); - root.AddComponent(); - Selection.activeGameObject = root; - - if (Camera.main != null) return; - var cameraObject = new GameObject("Planetary Viewer Camera"); - Undo.RegisterCreatedObjectUndo(cameraObject, "Create Planetary Viewer Camera"); - cameraObject.tag = "MainCamera"; - cameraObject.transform.position = new Vector3(0, 0, -24); - cameraObject.transform.LookAt(root.transform); - var camera = cameraObject.AddComponent(); - camera.nearClipPlane = 0.01f; - camera.farClipPlane = 1000; - } -} diff --git a/Samples~/PlanetaryViewer/README.md b/Samples~/PlanetaryViewer/README.md deleted file mode 100644 index ec4dcc3a..00000000 --- a/Samples~/PlanetaryViewer/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Planetary Field Viewer - -Import this sample through Unity's Package Manager, then choose -`GameObject > CultMath > Planetary Field Viewer`. - -The host project must contain `Assets/csc.rsp` with -`-langversion:latest`, as documented in the CultMath package README. - -The generated six-face mesh uses `PlanetaryPatch`. Its shader calls -`cultmath_planetary_field_sample` from the packaged CultMath HLSL, while the -component exposes the matching CPU `Sample` method. Seed, radius, physical -sample footprint, erosion settings, and base-field equations are shared between -the two bodies. - -This is a renderer integration fixture, not a gameplay owner. It deliberately -contains no Aetheria state, biomes, resources, or simulation decisions. diff --git a/Samples~/PlanetaryViewer/Runtime/CultMath.PlanetaryViewer.asmdef b/Samples~/PlanetaryViewer/Runtime/CultMath.PlanetaryViewer.asmdef deleted file mode 100644 index 2d3676f4..00000000 --- a/Samples~/PlanetaryViewer/Runtime/CultMath.PlanetaryViewer.asmdef +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "CultMath.PlanetaryViewer", - "rootNamespace": "CultMath.Unity.Samples", - "references": [ - "CultMath", - "CultMath.Unity" - ], - "includePlatforms": [], - "excludePlatforms": [], - "allowUnsafeCode": false, - "overrideReferences": false, - "precompiledReferences": [], - "autoReferenced": true, - "defineConstraints": [], - "versionDefines": [], - "noEngineReferences": false -} diff --git a/Samples~/PlanetaryViewer/Runtime/CultMathPlanetaryViewer.cs b/Samples~/PlanetaryViewer/Runtime/CultMathPlanetaryViewer.cs deleted file mode 100644 index 06113728..00000000 --- a/Samples~/PlanetaryViewer/Runtime/CultMathPlanetaryViewer.cs +++ /dev/null @@ -1,139 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace CultMath.Unity.Samples; - -[ExecuteAlways] -public sealed class CultMathPlanetaryViewer : MonoBehaviour -{ - [Min(0.001f)] public float Radius = 8.4f; - [Range(1, 256)] public int CellsPerFace = 64; - public int Seed = 42; - [Min(0.0001f)] public float SampleFootprint = 0.01f; - public Shader? PlanetShader; - public Vector3 LightDirection = new(-0.4f, 0.7f, -0.6f); - public Color LowColor = new(0.055f, 0.16f, 0.09f, 1); - public Color HighColor = new(0.62f, 0.48f, 0.28f, 1); - public Color RidgeColor = new(0.88f, 0.83f, 0.7f, 1); - - private readonly List meshes = new(); - private Material? material; - private int builtCells; - - public PlanetaryFieldDefinition Definition => PlanetaryFieldDefinition.Create( - 1, - Radius, - Seed, - ViewerErosion(Radius)); - - public PlanetarySurfaceSample Sample(float3 direction) - { - var source = new ViewerBaseField(Radius); - var normalized = math.normalize(direction); - return PlanetaryField.Sample(Definition, normalized, source.Sample(normalized), PlanetaryQueryScale.AtFootprint(SampleFootprint)); - } - - private void OnEnable() => Rebuild(); - - private void OnValidate() - { - Radius = Mathf.Max(Radius, 0.001f); - CellsPerFace = Mathf.Clamp(CellsPerFace, 1, 256); - SampleFootprint = Mathf.Max(SampleFootprint, 0.0001f); - if (isActiveAndEnabled) Rebuild(); - } - - private void Update() - { - if (builtCells != CellsPerFace || material == null) Rebuild(); - ApplyMaterial(); - } - - private void Rebuild() - { - ClearGenerated(); - PlanetShader ??= Shader.Find("CultMath/Planetary Field Viewer"); - if (PlanetShader == null) return; - material = new Material(PlanetShader) { name = "CultMath Planetary Viewer Material", hideFlags = HideFlags.HideAndDontSave }; - foreach (var face in (PlanetaryCubeFace[])Enum.GetValues(typeof(PlanetaryCubeFace))) - { - var mesh = PlanetaryPatchMeshAdapter.CreateFaceMesh(face, CellsPerFace); - mesh.hideFlags = HideFlags.HideAndDontSave; - meshes.Add(mesh); - var child = new GameObject(face.ToString()) { hideFlags = HideFlags.DontSave }; - child.transform.SetParent(transform, false); - child.AddComponent().sharedMesh = mesh; - child.AddComponent().sharedMaterial = material; - } - builtCells = CellsPerFace; - ApplyMaterial(); - } - - private void ApplyMaterial() - { - if (material == null) return; - var p = ViewerErosion(Radius); - material.SetFloat("_Radius", Radius); - material.SetFloat("_SampleFootprint", SampleFootprint); - material.SetInt("_Seed", Seed); - material.SetFloat("_ErosionScale", p.Scale); - material.SetFloat("_ErosionStrength", p.Strength); - material.SetFloat("_GullyWeight", p.GullyWeight); - material.SetFloat("_Detail", p.Detail); - material.SetVector("_Rounding", new(p.Rounding.x, p.Rounding.y, p.Rounding.z, p.Rounding.w)); - material.SetVector("_Onset", new(p.Onset.x, p.Onset.y, p.Onset.z, p.Onset.w)); - material.SetVector("_AssumedSlope", new(p.AssumedSlope.x, p.AssumedSlope.y, 0, 0)); - material.SetFloat("_CellScale", p.CellScale); - material.SetFloat("_Normalization", p.Normalization); - material.SetInt("_Octaves", p.Octaves); - material.SetFloat("_Lacunarity", p.Lacunarity); - material.SetFloat("_Gain", p.Gain); - material.SetVector("_LightDirection", LightDirection.normalized); - material.SetColor("_LowColor", LowColor); - material.SetColor("_HighColor", HighColor); - material.SetColor("_RidgeColor", RidgeColor); - } - - private void OnDisable() => ClearGenerated(); - private void OnDestroy() => ClearGenerated(); - - private void ClearGenerated() - { - for (var i = transform.childCount - 1; i >= 0; i--) DestroyGenerated(transform.GetChild(i).gameObject); - foreach (var mesh in meshes) DestroyGenerated(mesh); - meshes.Clear(); - if (material != null) DestroyGenerated(material); - material = null; - builtCells = 0; - } - - private static void DestroyGenerated(UnityEngine.Object value) - { - if (Application.isPlaying) Destroy(value); - else DestroyImmediate(value); - } - - private static AdvancedErosionParameters ViewerErosion(float radius) => new( - radius * 0.075f, 0.12f, 0.58f, 1.45f, - new float4(0.1f, 0.015f, 0.1f, 2), - new float4(1.25f, 1.25f, 2.8f, 1.5f), - new float2(0.7f, 0.85f), 0.7f, 0.5f, 7, 2, 0.5f); - - private readonly struct ViewerBaseField : IPlanetaryBaseField - { - private readonly float radius; - public ViewerBaseField(float radius) => this.radius = radius; - - public PlanetaryBaseFieldSample Sample(float3 direction) - { - var value = direction.x * 0.6f + direction.y * direction.z * 0.3f; - var angularGradient = new float3(0.6f, direction.z * 0.3f, direction.y * 0.3f); - angularGradient -= direction * math.dot(angularGradient, direction); - var fieldGradient = angularGradient / radius; - var radialDisplacement = value * radius * 0.035f; - var radialGradient = angularGradient * 0.035f; - return new(radialDisplacement, radialGradient, value, fieldGradient, math.clamp(value, -1, 1)); - } - } -} diff --git a/Samples~/PlanetaryViewer/Runtime/CultMathPlanetaryViewer.shader b/Samples~/PlanetaryViewer/Runtime/CultMathPlanetaryViewer.shader deleted file mode 100644 index b5f7274f..00000000 --- a/Samples~/PlanetaryViewer/Runtime/CultMathPlanetaryViewer.shader +++ /dev/null @@ -1,90 +0,0 @@ -Shader "CultMath/Planetary Field Viewer" -{ - Properties - { - _LowColor ("Low Color", Color) = (0.055, 0.16, 0.09, 1) - _HighColor ("High Color", Color) = (0.62, 0.48, 0.28, 1) - _RidgeColor ("Ridge Color", Color) = (0.88, 0.83, 0.7, 1) - } - SubShader - { - Tags { "RenderType"="Opaque" "Queue"="Geometry" } - Pass - { - Cull Back - ZWrite On - HLSLPROGRAM - #pragma target 5.0 - #pragma vertex vert - #pragma fragment frag - #include "UnityCG.cginc" - #include "Packages/org.gamecult.cultmath/shaders/CultMath.hlsl" - - float _Radius; - float _SampleFootprint; - int _Seed; - float _ErosionScale, _ErosionStrength, _GullyWeight, _Detail; - float4 _Rounding, _Onset, _AssumedSlope; - float _CellScale, _Normalization, _Lacunarity, _Gain; - int _Octaves; - float3 _LightDirection; - float4 _LowColor, _HighColor, _RidgeColor; - - struct Attributes { float4 vertex : POSITION; }; - struct Varyings - { - float4 position : SV_POSITION; - float3 worldNormal : TEXCOORD0; - float height : TEXCOORD1; - float ridge : TEXCOORD2; - }; - - CultMathPlanetarySurfaceSample viewer_sample(float3 direction) - { - direction = normalize(direction); - float value = direction.x * 0.6 + direction.y * direction.z * 0.3; - float3 angular_gradient = float3(0.6, direction.z * 0.3, direction.y * 0.3); - angular_gradient -= direction * dot(angular_gradient, direction); - CultMathPlanetaryBaseFieldSample base_sample; - base_sample.radial_displacement = value * _Radius * 0.035; - base_sample.radial_gradient = angular_gradient * 0.035; - base_sample.field_value = value; - base_sample.field_gradient = angular_gradient / _Radius; - base_sample.fade_target = clamp(value, -1.0, 1.0); - CultMathAdvancedErosionParameters erosion; - erosion.scale = _ErosionScale; erosion.strength = _ErosionStrength; - erosion.gully_weight = _GullyWeight; erosion.detail = _Detail; - erosion.rounding = _Rounding; erosion.onset = _Onset; - erosion.assumed_slope = _AssumedSlope.xy; erosion.cell_scale = _CellScale; - erosion.normalization = _Normalization; erosion.octaves = _Octaves; - erosion.lacunarity = _Lacunarity; erosion.gain = _Gain; - CultMathPlanetaryFieldDefinition definition; - definition.radius = _Radius; definition.seed = _Seed; definition.erosion = erosion; - return cultmath_planetary_field_sample(definition, direction, base_sample, _SampleFootprint); - } - - Varyings vert(Attributes input) - { - float3 direction = normalize(input.vertex.xyz); - CultMathPlanetarySurfaceSample sample = viewer_sample(direction); - float3 local = direction * (_Radius + sample.radial_displacement); - Varyings output; - output.position = UnityObjectToClipPos(float4(local, 1)); - output.worldNormal = UnityObjectToWorldNormal(sample.surface_normal); - output.height = sample.radial_displacement / max(_Radius * 0.1, 1.0e-5); - output.ridge = sample.ridge; - return output; - } - - float4 frag(Varyings input) : SV_Target - { - float height = saturate(input.height * 0.5 + 0.5); - float3 albedo = lerp(_LowColor.rgb, _HighColor.rgb, height); - albedo = lerp(albedo, _RidgeColor.rgb, saturate((input.ridge - 0.55) * 2.5)); - float diffuse = saturate(dot(normalize(input.worldNormal), normalize(-_LightDirection))) * 0.82 + 0.08; - return float4(albedo * diffuse, 1); - } - ENDHLSL - } - } -} diff --git a/THIRD-PARTY-NOTICES.md b/THIRD-PARTY-NOTICES.md index 54e280f6..c283df2b 100644 --- a/THIRD-PARTY-NOTICES.md +++ b/THIRD-PARTY-NOTICES.md @@ -9,26 +9,3 @@ Gustavson's `webgl-noise` project and Unity Mathematics. - Copyright 2011 Ashima Arts. - Upstream: - License: MIT. - -## Advanced Terrain Erosion Filter - -`src/CultMath/AdvancedErosionFilter.cs` and -`shaders/AdvancedErosionFilter.hlsl` adapt the mathematical procedure from -Rune Skovbo Johansen's **Advanced Terrain Erosion Filter**: - -- Copyright 2025 Rune Skovbo Johansen. -- Upstream: -- Explanation: -- License: Mozilla Public License 2.0, - - -The CultMath files retain the MPL notice and separate the faithful planar -filter from CultMath's spherical adaptation. Modifications include C#/HLSL -type lowering, explicit bounded octave counts, finite zero-rounding behavior, -and CultMath naming. CultMath replaces the reference floating hash with a -shared integer avalanche hash so C# and GPU evaluation select identical cell -pivots across devices; this changes the stochastic pattern, not the filter -mechanics. - -The technique builds on earlier work credited by the upstream author to Fewes -and Clay John. The hash form follows the public shader math of Inigo Quilez. diff --git a/Tools~/CultMath.PlanetaryTileFixture/CultMath.PlanetaryTileFixture.csproj b/Tools~/CultMath.PlanetaryTileFixture/CultMath.PlanetaryTileFixture.csproj deleted file mode 100644 index 9a6f8bdd..00000000 --- a/Tools~/CultMath.PlanetaryTileFixture/CultMath.PlanetaryTileFixture.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - Exe - net10.0 - enable - enable - - - - - diff --git a/Tools~/CultMath.PlanetaryTileFixture/Program.cs b/Tools~/CultMath.PlanetaryTileFixture/Program.cs deleted file mode 100644 index 1952fa2d..00000000 --- a/Tools~/CultMath.PlanetaryTileFixture/Program.cs +++ /dev/null @@ -1,22 +0,0 @@ -using CultMath; - -if (args.Length != 1) throw new ArgumentException("Expected one output path."); -var field = PlanetaryFieldDefinition.Create(0x55aa, 10, 7, AdvancedErosionParameters.Default); -var layout = new PlanetaryMapTileLayout(new(PlanetaryProjectionKind.EqualEarth), 0, 0, 0, 5, 1); -var key = new PlanetaryMapTileKey(field.FieldVersion, 3, 29, layout, PlanetaryQueryScale.AtFootprint(0.25f, 0.125f)); -var tile = PlanetaryMapTileBaker.Bake(field, key, new FixtureField()); -var path = Path.GetFullPath(args[0]); -Directory.CreateDirectory(Path.GetDirectoryName(path)!); -using var stream = File.Create(path); -PlanetaryMapTileEncoding.Write(stream, tile); - -readonly struct FixtureField : IPlanetaryBaseField -{ - public PlanetaryBaseFieldSample Sample(float3 direction) - { - var value = direction.x * 0.2f + direction.z * 0.4f; - var gradient = new float3(0.2f, 0, 0.4f); - gradient -= direction * math.dot(gradient, direction); - return new(value, gradient, value, gradient * 0.1f, value); - } -} diff --git a/docs/design.md b/docs/design.md index f4ca5b49..8250ba78 100644 --- a/docs/design.md +++ b/docs/design.md @@ -19,12 +19,6 @@ Rust hot kernels, C# host code, and HLSL shader code. - Keep the surface boring and exact. Noise primitives are allowed when they are source-grounded, shader-shaped, and shared by more than one project. Matrices, quaternions, and packing helpers still need an owner before they enter. -- Planetary geometry is a scale-aware field query, not a renderer asset. CPU - simulation is the reference consumer; pages, patches, and maps are derived - lowerings carrying field identity and unresolved error. -- Application base fields and gameplay meaning enter through narrow inputs. - CultMath does not own biomes, resources, traversability, render materials, or - committed game consequences. ## Non-Goals diff --git a/docs/planetary.md b/docs/planetary.md deleted file mode 100644 index 3503429b..00000000 --- a/docs/planetary.md +++ /dev/null @@ -1,130 +0,0 @@ -# Planetary Field Runtime - -CultMath owns the deterministic, renderer-independent planetary field. The same -definition can be queried by a CPU simulation, baked into residual pages, -sampled through a map projection, or evaluated by HLSL. Render resources and -gameplay interpretation remain consumer responsibilities. - -## Authority - -- `PlanetaryFieldDefinition` identifies radius, seed, erosion parameters, and a - version that includes the consumer-owned base-field version. -- `IPlanetaryBaseField` supplies deterministic application-authored base - evidence without making CultMath depend on an application. -- `PlanetaryQueryScale` makes the physical footprint and accepted unresolved - error explicit. There is deliberately no scale-free authoritative - `HeightAt` call. -- `PlanetarySurfaceSample` carries displacement, tangent gradient, normal, - slope, ridge/gully evidence, resolved wavelength, and unresolved bound. -- pages, residency, patches, and map tiles are disposable lowerings of that - contract. - -The C# surface targets .NET and Unity-compatible `netstandard2.1`. The matching -HLSL lives in `shaders/Planetary.hlsl` and is included by `CultMath.hlsl`. - -## Point and batch queries - -```csharp -var erosion = AdvancedErosionParameters.Default with -{ - Scale = radius * 0.075f, - Strength = 0.12f, - Octaves = 7, -}; -var field = PlanetaryFieldDefinition.Create( - baseFieldVersion: 17, - radius, - seed: 42, - erosion); -var scale = PlanetaryQueryScale.AtFootprint( - footprintMeters: 10, - maximumUnresolvedHeight: 0.5f); - -PlanetaryBaseFieldSample basis = source.Sample(direction); -PlanetarySurfaceSample sample = PlanetaryField.Sample( - field, direction, basis, scale); -``` - -`PlanetaryField.SampleBatch` writes into a caller-owned span. `SamplePosition` -accepts `double3`, reduces the astronomical position to a stable unit direction, -and then evaluates the same float field contract. - -Higher-level CPU queries include bounded ray intersection, segment clearance, -great-circle profiles, and region summaries. Their answers remain field queries; -only a consuming simulation can turn them into committed game consequences. - -## Cube-sphere topology and pages - -`PlanetaryTopology` owns the tangent/QSC cube-sphere mapping, inverse face -coordinates, tile selection, local page coordinates, and radial-graph surface -normal. `PlanetaryPageSampling` owns bordered directions, nominal spacing, -bilinear sampling, and summaries. - -`PlanetaryPageBaker` evaluates a root page at its physical sample spacing. A -child stores `child filtered field - parent filtered field`. A -`PlanetaryPageSetSampling` query adds every containing ancestor contribution -and applies transition weights only to residuals. - -`PlanetaryLodSelector` selects six roots plus one camera-facing ancestor chain -from the unresolved-height error. `PlanetaryResidualResidency` owns arrival and -departure presentation weights, content and presentation versions, and nothing -about field truth. - -## Patches - -`PlanetaryPatch.CreateFace` and `CreateCubeSphere` produce renderer-neutral -coarse meshes from the canonical topology. HLSL calls -`cultmath_planetary_face_direction` for procedural vertices and -`cultmath_planetary_radial_refinement_step` for bounded pixel refinement. - -Renderers still own cameras, clip space, depth, materials, buffers, dispatch, -and draw submission. - -`PlanetaryGpuPageBuilder` owns the renderer-neutral page input and metadata -payload. Host adapters may convert its `float4` values to native vector types, -but do not recalculate directions, spacing, addressing, or transition state. - -The optional `CultMath.Unity` assembly converts a canonical face patch into a -Unity `Mesh` and converts the shared GPU payload into Unity-native structs. It -owns no field parameters, page selection, or simulation state. The package's -Planetary Field Viewer sample renders the shared HLSL field and reports matching -CPU queries. Unity render code remains responsible for allocating/binding -graphics buffers and dispatching application-specific base-field entry points. -The host Unity project must set `-langversion:latest` in `Assets/csc.rsp`. - -## Maps - -`PlanetaryProjection` supplies forward and inverse transforms for: - -- equirectangular; -- Web Mercator with an explicit polar cutoff; -- Equal Earth; -- orthographic; -- azimuthal equidistant and equal-area; -- cube atlas; -- local tangent/gnomonic views. - -`PlanetaryMapTileBaker` maps each valid tile sample through the inverse -projection and canonical field query. `PlanetaryMapTileKey` includes field, -projection, layer, layout, and query-scale identity. Palettes, contours, labels, -and strategic overlays do not enter CultMath. - -`PlanetaryMapTileEncoding` writes the resulting evidence as a versioned -little-endian `CMPT` binary asset. `web/planetary-tile.ts` decodes that exact -format into browser-native values without defining another terrain generator. -Typed CultMesh documents should carry the tile key and asset reference; the -binary payload is derived CDN/cache data, not committed game state. - -## Numeric contract - -Integer hashes and published field versions are exact. Basic arithmetic follows -CultMath's matched C#/HLSL semantics. Hardware transcendental functions such as -`atan` and `tan` use measured tolerances rather than fictional bit identity. -Every filtered terrain query carries an unresolved-height bound so consumers can -reject insufficient fidelity explicitly. - -Current D3D12 parity evidence covers the advanced erosion kernel, QSC topology, -and forward/inverse transforms for every supported map projection, including -center and scale parameters. Production page and patch shaders use the common -functions and retain their seam, residual, summary, and radial-hit integration -probes in Fensalir. diff --git a/docs/planetary.md.meta b/docs/planetary.md.meta deleted file mode 100644 index af364c25..00000000 --- a/docs/planetary.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 23a5751e4cececc4e99e024058d69add -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/package.json b/package.json index 25643608..6da2a17a 100644 --- a/package.json +++ b/package.json @@ -10,12 +10,5 @@ "Simulation" ], "license": "MPL-2.0", - "category": "Scripting", - "samples": [ - { - "displayName": "Planetary Field Viewer", - "description": "Runnable Unity viewer using the canonical CultMath CPU and HLSL planetary field.", - "path": "Samples~/PlanetaryViewer" - } - ] + "category": "Scripting" } diff --git a/scripts/test-web-planetary-tile.ps1 b/scripts/test-web-planetary-tile.ps1 deleted file mode 100644 index 5221fb36..00000000 --- a/scripts/test-web-planetary-tile.ps1 +++ /dev/null @@ -1,9 +0,0 @@ -$ErrorActionPreference = "Stop" -$root = Split-Path -Parent $PSScriptRoot -$fixture = Join-Path $root ".tools\planetary-tile\fixture.cmpt" -dotnet run --project (Join-Path $root "Tools~\CultMath.PlanetaryTileFixture\CultMath.PlanetaryTileFixture.csproj") -- $fixture -if ($LASTEXITCODE -ne 0) { throw "Planetary tile fixture generation failed." } -node --no-warnings --experimental-strip-types (Join-Path $root "web\planetary-tile.cross-runtime.test.mjs") $fixture -if ($LASTEXITCODE -ne 0) { throw "Planetary tile web decoding failed." } -node --no-warnings --experimental-strip-types (Join-Path $root "web\planetary-tile.test.mjs") -if ($LASTEXITCODE -ne 0) { throw "Planetary tile decoder unit test failed." } diff --git a/scripts/test-web-planetary-tile.ps1.meta b/scripts/test-web-planetary-tile.ps1.meta deleted file mode 100644 index ffd73234..00000000 --- a/scripts/test-web-planetary-tile.ps1.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 235e8f203bd1c4d40a8fa211273106ba -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/shaders/AdvancedErosionFilter.hlsl b/shaders/AdvancedErosionFilter.hlsl deleted file mode 100644 index a0a350e5..00000000 --- a/shaders/AdvancedErosionFilter.hlsl +++ /dev/null @@ -1,147 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at https://mozilla.org/MPL/2.0/. -// Mathematical procedure adapted from Rune Skovbo Johansen's Advanced Terrain -// Erosion Filter (2025): https://www.shadertoy.com/view/wXcfWn - -#ifndef CULTMATH_ADVANCED_EROSION_FILTER_HLSL -#define CULTMATH_ADVANCED_EROSION_FILTER_HLSL - -struct CultMathAdvancedErosionParameters -{ - float scale; float strength; float gully_weight; float detail; - float4 rounding; float4 onset; float2 assumed_slope; - float cell_scale; float normalization; int octaves; float lacunarity; float gain; -}; - -struct CultMathAdvancedErosionResult -{ - float3 delta; float magnitude; float ridge_map; float fade_target; -}; - -struct CultMathErosionBandSelection -{ - int active_octaves; float final_octave_weight; float finest_included_wavelength; float unresolved_height_bound; -}; - -CultMathErosionBandSelection cultmath_select_erosion_bands(float base_wavelength, float sample_spacing, int maximum_octaves, float lacunarity, float base_amplitude, float gain, float transition_ratio) -{ - base_wavelength=max(base_wavelength,1.0e-6); sample_spacing=max(sample_spacing,0.0); lacunarity=max(lacunarity,1.01); transition_ratio=max(transition_ratio,1.01); maximum_octaves=min(max(maximum_octaves,0),16); - float nyquist=sample_spacing*2.0, wavelength=base_wavelength, final_weight=0.0, finest=0.0; int active=0; - [loop] for(int octave=0; octave=active) omitted+=amplitude; else if(index==active-1) omitted+=amplitude*(1.0-final_weight); amplitude*=abs(gain); - } - CultMathErosionBandSelection result; result.active_octaves=active; result.final_octave_weight=active>0?final_weight:0.0; result.finest_included_wavelength=finest; result.unresolved_height_bound=omitted; return result; -} - -float cultmath_erosion_hash_unit(int2 cell, uint salt) -{ - uint value = (uint)cell.x * 0x8da6b343u ^ (uint)cell.y * 0xd8163841u ^ salt; - value ^= value >> 16; value *= 0x7feb352du; value ^= value >> 15; value *= 0x846ca68bu; value ^= value >> 16; - return (value & 0x00ffffffu) * (1.0 / 16777216.0); -} -float2 cultmath_erosion_hash2(float2 input) -{ - int2 cell = (int2)input; - return float2(cultmath_erosion_hash_unit(cell, 0x68bc21ebu), cultmath_erosion_hash_unit(cell, 0x02e5be93u)) * 2.0 - 1.0; -} - -float4 cultmath_phacelle_noise(float2 position, float2 normal_direction, float frequency, float offset_cycles, float normalization) -{ - float2 side_direction = float2(-normal_direction.y, normal_direction.x) * frequency * 6.28318530718; - float offset = offset_cycles * 6.28318530718; - float2 cell = floor(position); - float2 local = frac(position); - float2 phase = 0.0; - float weight_sum = 0.0; - [unroll] for (int x = -1; x <= 2; x++) - [unroll] for (int y = -1; y <= 2; y++) - { - float2 grid_offset = float2(x, y); - float2 grid_point = cell + grid_offset; - float2 random_offset = cultmath_erosion_hash2(grid_point) * 0.5; - float2 delta = local - grid_offset - random_offset; - float weight = max(0.0, exp(-dot(delta, delta) * 2.0) - 0.01111); - weight_sum += weight; - float wave = dot(delta, side_direction) + offset; - phase += float2(cos(wave), sin(wave)) * weight; - } - float2 interpolated = phase / max(weight_sum, 1.0e-20); - float magnitude = max(1.0 - saturate(normalization), length(interpolated)); - return float4(interpolated / max(magnitude, 1.0e-20), side_direction); -} - -float cultmath_erosion_pow_inverse(float value, float power) { return 1.0 - pow(1.0 - saturate(value), power); } -float cultmath_erosion_ease_out(float value) { float inverse = 1.0 - saturate(value); return 1.0 - inverse * inverse; } -float cultmath_erosion_smooth_start(float value, float smoothing) -{ - return smoothing <= 1.0e-10 || value >= smoothing ? value - 0.5 * smoothing : 0.5 * value * value / smoothing; -} -float2 cultmath_erosion_safe_normalize(float2 value) -{ - float value_length = length(value); - return abs(value_length) > 1.0e-10 ? value / value_length : value; -} - -CultMathAdvancedErosionResult cultmath_advanced_erosion_filter_banded(float2 position, float3 base_height_and_slope, float fade_target, CultMathAdvancedErosionParameters p, CultMathErosionBandSelection band) -{ - float strength = p.strength * p.scale; - fade_target = clamp(fade_target, -1.0, 1.0); - float3 input_value = base_height_and_slope; - float3 height_and_slope = input_value; - float frequency = 1.0 / max(p.scale * p.cell_scale, 1.0e-10); - float2 slope = height_and_slope.yz; - float slope_length = max(length(slope), 1.0e-10); - float magnitude = 0.0; - float rounding_multiplier = 1.0; - float input_rounding = lerp(p.rounding.y, p.rounding.x, saturate(fade_target + 0.5)) * p.rounding.z; - float combined_mask = cultmath_erosion_ease_out(cultmath_erosion_smooth_start(slope_length * p.onset.x, input_rounding * p.onset.x)); - float ridge_mask = cultmath_erosion_ease_out(slope_length * p.onset.z); - float ridge_fade = fade_target; - float2 gully_slope = lerp(slope, slope / slope_length * p.assumed_slope.x, p.assumed_slope.y); - - int octave_count=min(min(max(p.octaves,0),8),max(band.active_octaves,0)); - [loop] for (int octave = 0; octave < octave_count; octave++) - { - float4 phacelle = cultmath_phacelle_noise(position * frequency, cultmath_erosion_safe_normalize(gully_slope), p.cell_scale, 0.25, p.normalization); - float2 derivative_direction = phacelle.zw * -frequency; - float sloping = abs(phacelle.y); - gully_slope += sign(phacelle.y) * derivative_direction * strength * p.gully_weight; - float3 gullies = float3(phacelle.x, phacelle.y * derivative_direction.x, phacelle.y * derivative_direction.y); - float3 faded = lerp(float3(fade_target, 0.0, 0.0), gullies * p.gully_weight, combined_mask); - float octave_weight=octave==octave_count-1?saturate(band.final_octave_weight):1.0; - height_and_slope += faded * strength * octave_weight; - magnitude += strength * octave_weight; - fade_target = faded.x; - float octave_rounding = lerp(p.rounding.y, p.rounding.x, saturate(phacelle.x + 0.5)) * rounding_multiplier; - float new_mask = cultmath_erosion_ease_out(cultmath_erosion_smooth_start(sloping * p.onset.y, octave_rounding * p.onset.y)); - combined_mask = cultmath_erosion_pow_inverse(combined_mask, p.detail) * new_mask; - ridge_fade = lerp(ridge_fade, lerp(ridge_fade, gullies.x, ridge_mask), octave_weight); - ridge_mask *= lerp(1.0, cultmath_erosion_ease_out(sloping * p.onset.w), octave_weight); - strength *= p.gain; - frequency *= p.lacunarity; - rounding_multiplier *= p.rounding.w; - } - - CultMathAdvancedErosionResult result; - result.delta = height_and_slope - input_value; - result.magnitude = magnitude; - result.ridge_map = ridge_fade * (1.0 - ridge_mask); - result.fade_target = fade_target; - return result; -} - -CultMathAdvancedErosionResult cultmath_advanced_erosion_filter(float2 position, float3 base_height_and_slope, float fade_target, CultMathAdvancedErosionParameters p) -{ - CultMathErosionBandSelection band; band.active_octaves=p.octaves; band.final_octave_weight=1.0; band.finest_included_wavelength=0.0; band.unresolved_height_bound=0.0; - return cultmath_advanced_erosion_filter_banded(position, base_height_and_slope, fade_target, p, band); -} - -#endif diff --git a/shaders/AdvancedErosionFilter.hlsl.meta b/shaders/AdvancedErosionFilter.hlsl.meta deleted file mode 100644 index a354e330..00000000 --- a/shaders/AdvancedErosionFilter.hlsl.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 3252ac02e8853ef4b9d1fbc5204b5c6b -ShaderIncludeImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/shaders/CultMath.hlsl b/shaders/CultMath.hlsl index 84d244bb..4c00fb69 100644 --- a/shaders/CultMath.hlsl +++ b/shaders/CultMath.hlsl @@ -299,98 +299,4 @@ float cultmath_value_noise_texture_bicubic(Texture2D noise_texture, Sampl return cultmath_catmullrom(row0, row1, row2, row3, local.y); } -#include "AdvancedErosionFilter.hlsl" -#include "Planetary.hlsl" - -struct CultMathSphericalErosionParameters -{ - float frequency; float amplitude; float lacunarity; float gain; - float slope_strength; float detail; float seed; int octaves; -}; - -struct CultMathSphericalErosionSample -{ - float height_offset; float ridge; float gully; float3 gradient; -}; - -float cultmath_spherical_cell_wave(float3 position, float3 flow, float3 cell, float seed) -{ - float3 pivot = cell + float3(cultmath_hash(cell + seed + 11.7), cultmath_hash(cell.yzx + seed + 37.1), cultmath_hash(cell.zyx + seed + 73.9)); - return dot(position - pivot, flow) * 6.28318530718 + cultmath_hash(cell + seed + 101.3) * 6.28318530718; -} - -float cultmath_spherical_directional_wave(float3 position, float3 flow, float seed) -{ - float3 cell = floor(position); - float3 local = cultmath_frac(position); - float3 weights = local * local * (3.0 - 2.0 * local); - float z0 = cultmath_lerp( - cultmath_lerp(cultmath_spherical_cell_wave(position, flow, cell + float3(0,0,0), seed), cultmath_spherical_cell_wave(position, flow, cell + float3(1,0,0), seed), weights.x), - cultmath_lerp(cultmath_spherical_cell_wave(position, flow, cell + float3(0,1,0), seed), cultmath_spherical_cell_wave(position, flow, cell + float3(1,1,0), seed), weights.x), weights.y); - float z1 = cultmath_lerp( - cultmath_lerp(cultmath_spherical_cell_wave(position, flow, cell + float3(0,0,1), seed), cultmath_spherical_cell_wave(position, flow, cell + float3(1,0,1), seed), weights.x), - cultmath_lerp(cultmath_spherical_cell_wave(position, flow, cell + float3(0,1,1), seed), cultmath_spherical_cell_wave(position, flow, cell + float3(1,1,1), seed), weights.x), weights.y); - return cultmath_lerp(z0, z1, weights.z); -} - -float3 cultmath_spherical_stable_tangent(float3 position) -{ - float3 axis = abs(position.z) < 0.8 ? float3(0,0,1) : float3(0,1,0); - return cultmath_normalize(cross(axis, position)); -} - -CultMathSphericalErosionSample cultmath_spherical_erosion(float3 unit_position, float base_height, float3 base_gradient, CultMathSphericalErosionParameters p) -{ - float3 position = cultmath_normalize(unit_position); - float3 gradient = base_gradient - position * dot(base_gradient, position); - float slope = length(gradient); - float3 flow = slope > 1.0e-6 ? -gradient / slope : cultmath_spherical_stable_tangent(position); - float frequency = max(p.frequency, 0.001); - float amplitude = p.amplitude; - float combi_mask = 1.0 - pow(1.0 - cultmath_saturate(slope * p.slope_strength), 2.0); - float fade_target = cultmath_saturate(base_height * 0.5 + 0.5) * 2.0 - 1.0; - CultMathSphericalErosionSample result = (CultMathSphericalErosionSample)0; - [loop] for (int octave = 0; octave < min(max(p.octaves, 0), 8); octave++) - { - float phase = cultmath_spherical_directional_wave(position * frequency, flow, p.seed + octave * 19.19); - float wave = cos(phase); - float wave_slope = sin(phase); - float faded = cultmath_lerp(fade_target, wave, combi_mask); - result.height_offset += faded * amplitude; - result.ridge = max(result.ridge, cultmath_saturate(faded)); - result.gully = max(result.gully, cultmath_saturate(-faded)); - float3 across = cultmath_normalize(cross(position, flow)); - gradient += across * (sign(wave_slope) * amplitude * frequency * combi_mask); - gradient -= position * dot(gradient, position); - slope = length(gradient); - flow = slope > 1.0e-6 ? -gradient / slope : cultmath_spherical_stable_tangent(position); - float new_mask = 1.0 - pow(1.0 - cultmath_saturate(abs(wave_slope) * 1.35), 2.0); - combi_mask = (1.0 - pow(1.0 - cultmath_saturate(combi_mask), max(p.detail, 0.001))) * new_mask; - fade_target = faded; - frequency *= max(p.lacunarity, 1.01); - amplitude *= cultmath_saturate(p.gain); - } - result.gradient = gradient; - return result; -} - -float3 cultmath_planetary_radial_refinement_step( - float3 position, - float3 ray_direction, - float3 center, - float target_radius, - float minimum_derivative, - float maximum_correction) -{ - float3 local=position-center; - float radius=length(local); - float3 radial=local/max(radius,0.0001); - float error=radius-target_radius; - float derivative=dot(ray_direction,radial); - float safe_minimum=max(minimum_derivative,0.0001); - float safe_derivative=abs(derivative)>safe_minimum?derivative:(derivative<0?-safe_minimum:safe_minimum); - float correction=clamp(-error/safe_derivative,-abs(maximum_correction),abs(maximum_correction)); - return position+ray_direction*correction; -} - #endif diff --git a/shaders/Planetary.hlsl b/shaders/Planetary.hlsl deleted file mode 100644 index 81e312b7..00000000 --- a/shaders/Planetary.hlsl +++ /dev/null @@ -1,392 +0,0 @@ -#ifndef CULTMATH_PLANETARY_HLSL -#define CULTMATH_PLANETARY_HLSL - -static const float CULTMATH_PLANETARY_QUARTER_PI = 0.78539816339744830962; - -float3 cultmath_planetary_face_direction(int face, float2 coordinate) -{ - float2 tangent = tan(coordinate * CULTMATH_PLANETARY_QUARTER_PI); - float3 cube = face == 0 ? float3(1.0, tangent.y, -tangent.x) - : face == 1 ? float3(-1.0, tangent.y, tangent.x) - : face == 2 ? float3(tangent.x, 1.0, -tangent.y) - : face == 3 ? float3(tangent.x, -1.0, tangent.y) - : face == 4 ? float3(tangent.x, tangent.y, 1.0) - : float3(-tangent.x, tangent.y, -1.0); - return cultmath_normalize(cube); -} - -float2 cultmath_planetary_face_coordinate(float3 direction, out int face) -{ - float3 d = cultmath_normalize(direction); - float3 a = abs(d); - float2 cube_uv; - if (a.x >= a.y && a.x >= a.z) - { - if (d.x >= 0.0) { face = 0; cube_uv = float2(-d.z, d.y) / a.x; } - else { face = 1; cube_uv = float2(d.z, d.y) / a.x; } - } - else if (a.y >= a.z) - { - if (d.y >= 0.0) { face = 2; cube_uv = float2(d.x, -d.z) / a.y; } - else { face = 3; cube_uv = float2(d.x, d.z) / a.y; } - } - else - { - if (d.z >= 0.0) { face = 4; cube_uv = d.xy / a.z; } - else { face = 5; cube_uv = float2(-d.x, d.y) / a.z; } - } - return atan(cube_uv) / CULTMATH_PLANETARY_QUARTER_PI; -} - -bool cultmath_planetary_page_local(float3 direction, float4 tile_address, float active, out float2 local) -{ - int face; - float2 uv = cultmath_planetary_face_coordinate(direction, face); - local = 0.0; - if (active < 0.5 || abs((float)face - tile_address.x) > 0.25) return false; - float axis_tiles = exp2(tile_address.y); - float2 scaled = (uv * 0.5 + 0.5) * axis_tiles; - float2 canonical = floor(min(scaled, axis_tiles - 1.0e-5)); - if (any(abs(canonical - tile_address.zw) > 0.25)) return false; - local = scaled - tile_address.zw; - return all(local >= 0.0) && all(local <= 1.0); -} - -float3 cultmath_planetary_surface_normal(float3 direction, float3 world_distance_tangent_gradient) -{ - direction = cultmath_normalize(direction); - float3 tangent_gradient = world_distance_tangent_gradient - direction * dot(world_distance_tangent_gradient, direction); - return cultmath_normalize(direction - tangent_gradient); -} - -float2 cultmath_planetary_equirectangular_forward(float3 direction) -{ - direction = cultmath_normalize(direction); - return float2(atan2(direction.y, direction.x) / CULTMATH_PI, asin(clamp(direction.z, -1.0, 1.0)) / CULTMATH_HALF_PI); -} - -float3 cultmath_planetary_equirectangular_inverse(float2 coordinate) -{ - float longitude = coordinate.x * CULTMATH_PI; - float latitude = coordinate.y * CULTMATH_HALF_PI; - float cos_latitude = cos(latitude); - return cultmath_normalize(float3(cos_latitude * cos(longitude), cos_latitude * sin(longitude), sin(latitude))); -} - -static const float CULTMATH_EQUAL_EARTH_A1 = 1.340264; -static const float CULTMATH_EQUAL_EARTH_A2 = -0.081106; -static const float CULTMATH_EQUAL_EARTH_A3 = 0.000893; -static const float CULTMATH_EQUAL_EARTH_A4 = 0.003796; -static const float CULTMATH_EQUAL_EARTH_M = 0.8660254037844386; -static const float CULTMATH_EQUAL_EARTH_X_MAX = 2.706629; -static const float CULTMATH_EQUAL_EARTH_Y_MAX = 1.3173628; - -float cultmath_equal_earth_y(float theta) -{ - float theta2 = theta * theta; - float theta6 = theta2 * theta2 * theta2; - return theta * (CULTMATH_EQUAL_EARTH_A1 + CULTMATH_EQUAL_EARTH_A2 * theta2 + theta6 * (CULTMATH_EQUAL_EARTH_A3 + CULTMATH_EQUAL_EARTH_A4 * theta2)); -} - -float2 cultmath_planetary_equal_earth_forward(float3 direction) -{ - direction = cultmath_normalize(direction); - float longitude = atan2(direction.y, direction.x); - float latitude = asin(clamp(direction.z, -1.0, 1.0)); - float theta = asin(CULTMATH_EQUAL_EARTH_M * sin(latitude)); - float theta2 = theta * theta; - float theta6 = theta2 * theta2 * theta2; - float denominator = CULTMATH_EQUAL_EARTH_M * (CULTMATH_EQUAL_EARTH_A1 + 3.0 * CULTMATH_EQUAL_EARTH_A2 * theta2 + theta6 * (7.0 * CULTMATH_EQUAL_EARTH_A3 + 9.0 * CULTMATH_EQUAL_EARTH_A4 * theta2)); - return float2(longitude * cos(theta) / denominator / CULTMATH_EQUAL_EARTH_X_MAX, cultmath_equal_earth_y(theta) / CULTMATH_EQUAL_EARTH_Y_MAX); -} - -float3 cultmath_planetary_equal_earth_inverse(float2 coordinate) -{ - float target_y = coordinate.y * CULTMATH_EQUAL_EARTH_Y_MAX; - float theta = target_y / CULTMATH_EQUAL_EARTH_A1; - [unroll] for (int iteration = 0; iteration < 8; iteration++) - { - float theta2 = theta * theta; - float theta6 = theta2 * theta2 * theta2; - float derivative = CULTMATH_EQUAL_EARTH_A1 + 3.0 * CULTMATH_EQUAL_EARTH_A2 * theta2 + theta6 * (7.0 * CULTMATH_EQUAL_EARTH_A3 + 9.0 * CULTMATH_EQUAL_EARTH_A4 * theta2); - theta -= (cultmath_equal_earth_y(theta) - target_y) / derivative; - } - float latitude = asin(clamp(sin(theta) / CULTMATH_EQUAL_EARTH_M, -1.0, 1.0)); - float theta2 = theta * theta; - float theta6 = theta2 * theta2 * theta2; - float denominator = CULTMATH_EQUAL_EARTH_M * (CULTMATH_EQUAL_EARTH_A1 + 3.0 * CULTMATH_EQUAL_EARTH_A2 * theta2 + theta6 * (7.0 * CULTMATH_EQUAL_EARTH_A3 + 9.0 * CULTMATH_EQUAL_EARTH_A4 * theta2)); - float longitude = coordinate.x * CULTMATH_EQUAL_EARTH_X_MAX * denominator / cos(theta); - float cos_latitude = cos(latitude); - return cultmath_normalize(float3(cos_latitude * cos(longitude), cos_latitude * sin(longitude), sin(latitude))); -} - -float cultmath_planetary_wrap_longitude(float longitude) -{ - longitude = fmod(longitude, CULTMATH_TAU); - if (longitude > CULTMATH_PI) longitude -= CULTMATH_TAU; - if (longitude < -CULTMATH_PI) longitude += CULTMATH_TAU; - return longitude; -} - -float3 cultmath_planetary_lon_lat_direction(float longitude, float latitude) -{ - float cos_latitude = cos(latitude); - return cultmath_normalize(float3(cos_latitude * cos(longitude), cos_latitude * sin(longitude), sin(latitude))); -} - -float cultmath_planetary_asinh(float value) { return log(value + sqrt(value * value + 1.0)); } -float cultmath_planetary_sinh(float value) { return 0.5 * (exp(value) - exp(-value)); } - -bool cultmath_planetary_azimuthal_forward(float3 direction, float2 center_lon_lat, int kind, out float2 coordinate) -{ - direction = cultmath_normalize(direction); - float longitude = cultmath_planetary_wrap_longitude(atan2(direction.y, direction.x) - center_lon_lat.x); - float latitude = asin(clamp(direction.z, -1.0, 1.0)); - float sin0 = sin(center_lon_lat.y), cos0 = cos(center_lon_lat.y); - float sin_latitude = sin(latitude), cos_latitude = cos(latitude), cos_longitude = cos(longitude); - float cos_c = clamp(sin0 * sin_latitude + cos0 * cos_latitude * cos_longitude, -1.0, 1.0); - float2 raw = float2(cos_latitude * sin(longitude), cos0 * sin_latitude - sin0 * cos_latitude * cos_longitude); - float factor = 1.0; - if (kind == 3) - { - if (cos_c < 0.0) { coordinate = 0.0; return false; } - } - else if (kind == 4) - { - float c = acos(cos_c); factor = (c < 1.0e-6 ? 1.0 : c / sin(c)) / CULTMATH_PI; - } - else if (kind == 5) factor = sqrt(2.0 / max(1.0 + cos_c, 1.0e-20)) * 0.5; - else - { - if (cos_c <= 0.0) { coordinate = 0.0; return false; } - factor = 1.0 / cos_c; - } - coordinate = raw * factor; - return true; -} - -bool cultmath_planetary_azimuthal_inverse(float2 coordinate, float2 center_lon_lat, int kind, out float3 direction) -{ - float rho = length(coordinate); - float c; - if (kind == 3) { if (rho > 1.0) { direction = 0.0; return false; } c = asin(clamp(rho, 0.0, 1.0)); } - else if (kind == 4) { if (rho > 1.0) { direction = 0.0; return false; } c = rho * CULTMATH_PI; } - else if (kind == 5) { if (rho > 1.0) { direction = 0.0; return false; } c = 2.0 * asin(clamp(rho, 0.0, 1.0)); } - else c = atan(rho); - if (rho < 1.0e-6) { direction = cultmath_planetary_lon_lat_direction(center_lon_lat.x, center_lon_lat.y); return true; } - float sin_c = sin(c), cos_c = cos(c), sin0 = sin(center_lon_lat.y), cos0 = cos(center_lon_lat.y); - float latitude = asin(clamp(cos_c * sin0 + coordinate.y * sin_c * cos0 / rho, -1.0, 1.0)); - float delta_longitude = atan2(coordinate.x * sin_c, rho * cos0 * cos_c - coordinate.y * sin0 * sin_c); - direction = cultmath_planetary_lon_lat_direction(cultmath_planetary_wrap_longitude(delta_longitude + center_lon_lat.x), latitude); - return true; -} - -bool cultmath_planetary_cube_atlas_forward(float3 direction, out float2 coordinate) -{ - int face; - float2 face_coordinate = cultmath_planetary_face_coordinate(direction, face); - int column = face % 3; - int row = face / 3; - coordinate = float2(-1.0 + (column + (face_coordinate.x + 1.0) * 0.5) * (2.0 / 3.0), 1.0 - (row + (face_coordinate.y + 1.0) * 0.5)); - return true; -} - -bool cultmath_planetary_cube_atlas_inverse(float2 coordinate, out float3 direction) -{ - if (any(coordinate < -1.0) || any(coordinate > 1.0)) { direction = 0.0; return false; } - int column = min((int)((coordinate.x + 1.0) * 1.5), 2); - int row = min((int)(1.0 - coordinate.y), 1); - float u = ((coordinate.x + 1.0) * 1.5 - column) * 2.0 - 1.0; - float v = ((1.0 - coordinate.y) - row) * 2.0 - 1.0; - direction = cultmath_planetary_face_direction(row * 3 + column, float2(u, v)); - return true; -} - -bool cultmath_planetary_projection_forward(float3 direction, int kind, float3 center_lon_lat_scale, out float2 coordinate) -{ - float scale = max(center_lon_lat_scale.z, 1.0e-20); - if (kind == 6) - { - bool valid = cultmath_planetary_cube_atlas_forward(direction, coordinate); - coordinate /= scale; return valid; - } - if (kind >= 3) - { - bool valid = cultmath_planetary_azimuthal_forward(direction, center_lon_lat_scale.xy, kind, coordinate); - coordinate /= scale; return valid; - } - direction = cultmath_normalize(direction); - float longitude = cultmath_planetary_wrap_longitude(atan2(direction.y, direction.x) - center_lon_lat_scale.x); - float latitude = asin(clamp(direction.z, -1.0, 1.0)); - if (kind == 0) coordinate = float2(longitude / CULTMATH_PI, latitude / CULTMATH_HALF_PI); - else if (kind == 1) - { - const float maximum_latitude = 1.4844222297453324; - if (abs(latitude) > maximum_latitude) { coordinate = 0.0; return false; } - coordinate = float2(longitude / CULTMATH_PI, cultmath_planetary_asinh(tan(latitude)) / CULTMATH_PI); - } - else - { - float3 centered = cultmath_planetary_lon_lat_direction(longitude, latitude); - coordinate = cultmath_planetary_equal_earth_forward(centered); - } - coordinate /= scale; - return true; -} - -bool cultmath_planetary_projection_inverse(float2 coordinate, int kind, float3 center_lon_lat_scale, out float3 direction) -{ - coordinate *= max(center_lon_lat_scale.z, 1.0e-20); - if (kind == 6) return cultmath_planetary_cube_atlas_inverse(coordinate, direction); - if (kind >= 3) return cultmath_planetary_azimuthal_inverse(coordinate, center_lon_lat_scale.xy, kind, direction); - if (any(abs(coordinate) > 1.0)) { direction = 0.0; return false; } - float longitude, latitude; - if (kind == 0) { longitude = coordinate.x * CULTMATH_PI; latitude = coordinate.y * CULTMATH_HALF_PI; } - else if (kind == 1) { longitude = coordinate.x * CULTMATH_PI; latitude = atan(cultmath_planetary_sinh(coordinate.y * CULTMATH_PI)); } - else - { - float3 centered = cultmath_planetary_equal_earth_inverse(coordinate); - longitude = atan2(centered.y, centered.x); latitude = asin(clamp(centered.z, -1.0, 1.0)); - } - direction = cultmath_planetary_lon_lat_direction(cultmath_planetary_wrap_longitude(longitude + center_lon_lat_scale.x), latitude); - return true; -} - -struct CultMathPlanetaryFieldDefinition -{ - float radius; - int seed; - CultMathAdvancedErosionParameters erosion; -}; - -struct CultMathPlanetaryBaseFieldSample -{ - float radial_displacement; - float3 radial_gradient; - float field_value; - float3 field_gradient; - float fade_target; -}; - -struct CultMathPlanetarySurfaceSample -{ - float radial_displacement; - float3 tangent_gradient; - float3 surface_normal; - float slope; - float ridge; - float gully; - float finest_resolved_wavelength; - float unresolved_height_bound; -}; - -struct CultMathPlanetaryPageSample -{ - float4 height_gradient; - float2 masks; -}; - -CultMathPlanetaryPageSample cultmath_planetary_page_lerp( - CultMathPlanetaryPageSample a, - CultMathPlanetaryPageSample b, - CultMathPlanetaryPageSample c, - CultMathPlanetaryPageSample d, - float2 fraction) -{ - CultMathPlanetaryPageSample result; - result.height_gradient = lerp(lerp(a.height_gradient, b.height_gradient, fraction.x), lerp(c.height_gradient, d.height_gradient, fraction.x), fraction.y); - result.masks = lerp(lerp(a.masks, b.masks, fraction.x), lerp(c.masks, d.masks, fraction.x), fraction.y); - return result; -} - -CultMathPlanetaryPageSample cultmath_planetary_residual_sample( - CultMathPlanetarySurfaceSample child, - CultMathPlanetarySurfaceSample parent, - bool has_parent) -{ - CultMathPlanetaryPageSample result; - result.height_gradient = float4(child.radial_displacement, child.tangent_gradient); - if (has_parent) result.height_gradient -= float4(parent.radial_displacement, parent.tangent_gradient); - result.masks = float2(child.ridge, child.gully); - return result; -} - -float4 cultmath_planetary_summary_empty() -{ - return float4(3.402823466e+38, -3.402823466e+38, 0.0, 0.0); -} - -float4 cultmath_planetary_summary_accumulate(float4 summary, float4 height_gradient, float unresolved_height) -{ - summary.x = min(summary.x, height_gradient.x); - summary.y = max(summary.y, height_gradient.x); - summary.z = max(summary.z, length(height_gradient.yzw)); - summary.w = max(summary.w, max(unresolved_height, 0.0)); - return summary; -} - -float cultmath_planetary_pow4(float value) { float square = value * value; return square * square; } - -CultMathPlanetarySurfaceSample cultmath_planetary_field_sample( - CultMathPlanetaryFieldDefinition definition, - float3 unit_direction, - CultMathPlanetaryBaseFieldSample base_sample, - float footprint_meters) -{ - float3 direction = cultmath_normalize(unit_direction); - float3 radial_gradient = base_sample.radial_gradient - direction * dot(base_sample.radial_gradient, direction); - float3 field_gradient = base_sample.field_gradient - direction * dot(base_sample.field_gradient, direction); - CultMathAdvancedErosionParameters p = definition.erosion; - CultMathErosionBandSelection band = cultmath_select_erosion_bands( - p.scale * p.cell_scale, footprint_meters, p.octaves, p.lacunarity, - p.strength * p.scale, p.gain, 2.0); - float3 powers = float3( - cultmath_planetary_pow4(abs(direction.x)), - cultmath_planetary_pow4(abs(direction.y)), - cultmath_planetary_pow4(abs(direction.z))); - float power_sum = max(powers.x + powers.y + powers.z, 1.0e-6); - float3 weights = powers / power_sum; - float3 world = direction * definition.radius; - float seed = (float)definition.seed; - CultMathAdvancedErosionResult xy = cultmath_advanced_erosion_filter_banded( - world.xy + float2(713.0 + seed * 0.754877666, -291.0 + seed * 0.569840296), - float3(base_sample.field_value, field_gradient.x, field_gradient.y), base_sample.fade_target, p, band); - CultMathAdvancedErosionResult yz = cultmath_advanced_erosion_filter_banded( - world.yz + float2(-431.0 + seed * 0.438289027, 887.0 + seed * 0.328438163), - float3(base_sample.field_value, field_gradient.y, field_gradient.z), base_sample.fade_target, p, band); - CultMathAdvancedErosionResult zx = cultmath_advanced_erosion_filter_banded( - world.zx + float2(197.0 + seed * 0.219783071, 557.0 + seed * 0.145898034), - float3(base_sample.field_value, field_gradient.z, field_gradient.x), base_sample.fade_target, p, band); - float erosion_height = xy.delta.x * weights.z + yz.delta.x * weights.x + zx.delta.x * weights.y; - float3 erosion_gradient = float3( - xy.delta.y * weights.z + zx.delta.z * weights.y, - xy.delta.z * weights.z + yz.delta.y * weights.x, - yz.delta.z * weights.x + zx.delta.y * weights.y); - float3 power_gradient_x = float3(4.0 * direction.x * direction.x * direction.x / definition.radius, 0.0, 0.0); - float3 power_gradient_y = float3(0.0, 4.0 * direction.y * direction.y * direction.y / definition.radius, 0.0); - float3 power_gradient_z = float3(0.0, 0.0, 4.0 * direction.z * direction.z * direction.z / definition.radius); - power_gradient_x -= direction * dot(power_gradient_x, direction); - power_gradient_y -= direction * dot(power_gradient_y, direction); - power_gradient_z -= direction * dot(power_gradient_z, direction); - float3 power_sum_gradient = power_gradient_x + power_gradient_y + power_gradient_z; - float inverse_power_sum_squared = 1.0 / (power_sum * power_sum); - float3 weight_gradient_x = (power_gradient_x * power_sum - power_sum_gradient * powers.x) * inverse_power_sum_squared; - float3 weight_gradient_y = (power_gradient_y * power_sum - power_sum_gradient * powers.y) * inverse_power_sum_squared; - float3 weight_gradient_z = (power_gradient_z * power_sum - power_sum_gradient * powers.z) * inverse_power_sum_squared; - erosion_gradient += yz.delta.x * weight_gradient_x + zx.delta.x * weight_gradient_y + xy.delta.x * weight_gradient_z; - float3 gradient = radial_gradient + erosion_gradient; - gradient -= direction * dot(gradient, direction); - float ridge_evidence = xy.ridge_map * weights.z + yz.ridge_map * weights.x + zx.ridge_map * weights.y; - CultMathPlanetarySurfaceSample result; - result.radial_displacement = base_sample.radial_displacement + erosion_height; - result.tangent_gradient = gradient; - result.surface_normal = cultmath_planetary_surface_normal(direction, gradient); - result.slope = length(gradient); - result.ridge = saturate(ridge_evidence * 0.5 + 0.5); - result.gully = saturate(0.5 - ridge_evidence * 0.5); - result.finest_resolved_wavelength = band.finest_included_wavelength; - result.unresolved_height_bound = band.unresolved_height_bound; - return result; -} - -#endif diff --git a/shaders/Planetary.hlsl.meta b/shaders/Planetary.hlsl.meta deleted file mode 100644 index f7771355..00000000 --- a/shaders/Planetary.hlsl.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: bb055ad5328888e479e90ae3fe62c3fe -ShaderIncludeImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/src/CultMath/AdvancedErosionFilter.cs b/src/CultMath/AdvancedErosionFilter.cs deleted file mode 100644 index 65db3671..00000000 --- a/src/CultMath/AdvancedErosionFilter.cs +++ /dev/null @@ -1,139 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at https://mozilla.org/MPL/2.0/. -// -// Mathematical procedure adapted from Rune Skovbo Johansen's Advanced Terrain -// Erosion Filter (2025): https://www.shadertoy.com/view/wXcfWn - -namespace CultMath; - -public readonly record struct AdvancedErosionParameters( - float Scale, - float Strength, - float GullyWeight, - float Detail, - float4 Rounding, - float4 Onset, - float2 AssumedSlope, - float CellScale, - float Normalization, - int Octaves, - float Lacunarity, - float Gain) -{ - public static AdvancedErosionParameters Default => new( - 0.15f, 0.22f, 0.5f, 1.5f, - new float4(0.1f, 0.0f, 0.1f, 2.0f), - new float4(1.25f, 1.25f, 2.8f, 1.5f), - new float2(0.7f, 1.0f), - 0.7f, 0.5f, 5, 2.0f, 0.5f); -} - -public readonly record struct AdvancedErosionResult(float3 Delta, float Magnitude, float RidgeMap, float FadeTarget); - -public static class AdvancedErosionFilter -{ - public static AdvancedErosionResult Sample(float2 position, float3 baseHeightAndSlope, float fadeTarget, AdvancedErosionParameters p) - => Sample(position, baseHeightAndSlope, fadeTarget, p, new ErosionBandSelection(p.Octaves, 1.0f, 0.0f, 0.0f)); - - public static AdvancedErosionResult Sample(float2 position, float3 baseHeightAndSlope, float fadeTarget, AdvancedErosionParameters p, ErosionBandSelection band) - { - var strength = p.Strength * p.Scale; - fadeTarget = math.clamp(fadeTarget, -1.0f, 1.0f); - var input = baseHeightAndSlope; - var heightAndSlope = input; - var frequency = 1.0f / math.max(p.Scale * p.CellScale, 1.0e-10f); - var slope = new float2(heightAndSlope.y, heightAndSlope.z); - var slopeLength = math.max(math.length(slope), 1.0e-10f); - var magnitude = 0.0f; - var roundingMultiplier = 1.0f; - - var inputRounding = math.lerp(p.Rounding.y, p.Rounding.x, math.saturate(fadeTarget + 0.5f)) * p.Rounding.z; - var combinedMask = EaseOut(SmoothStart(slopeLength * p.Onset.x, inputRounding * p.Onset.x)); - var ridgeMask = EaseOut(slopeLength * p.Onset.z); - var ridgeFade = fadeTarget; - var gullySlope = math.lerp(slope, slope / slopeLength * p.AssumedSlope.x, p.AssumedSlope.y); - - var octaves = math.min(math.min(math.max(p.Octaves, 0), 8), math.max(band.ActiveOctaves, 0)); - for (var octave = 0; octave < octaves; octave++) - { - var phacelle = Phacelle(position * frequency, SafeNormalize(gullySlope), p.CellScale, 0.25f, p.Normalization); - var derivativeDirection = new float2(phacelle.z, phacelle.w) * -frequency; - var sloping = math.abs(phacelle.y); - gullySlope += math.sign(phacelle.y) * derivativeDirection * strength * p.GullyWeight; - - var gullies = new float3(phacelle.x, phacelle.y * derivativeDirection.x, phacelle.y * derivativeDirection.y); - var faded = math.lerp(new float3(fadeTarget, 0.0f, 0.0f), gullies * p.GullyWeight, combinedMask); - var octaveWeight = octave == octaves - 1 ? math.saturate(band.FinalOctaveWeight) : 1.0f; - heightAndSlope += faded * strength * octaveWeight; - magnitude += strength * octaveWeight; - fadeTarget = faded.x; - - var octaveRounding = math.lerp(p.Rounding.y, p.Rounding.x, math.saturate(phacelle.x + 0.5f)) * roundingMultiplier; - var newMask = EaseOut(SmoothStart(sloping * p.Onset.y, octaveRounding * p.Onset.y)); - combinedMask = PowInverse(combinedMask, p.Detail) * newMask; - - ridgeFade = math.lerp(ridgeFade, math.lerp(ridgeFade, gullies.x, ridgeMask), octaveWeight); - ridgeMask *= math.lerp(1.0f, EaseOut(sloping * p.Onset.w), octaveWeight); - strength *= p.Gain; - frequency *= p.Lacunarity; - roundingMultiplier *= p.Rounding.w; - } - - return new AdvancedErosionResult(heightAndSlope - input, magnitude, ridgeFade * (1.0f - ridgeMask), fadeTarget); - } - - public static float4 Phacelle(float2 position, float2 normalDirection, float frequency, float offsetCycles, float normalization) - { - var sideDirection = new float2(-normalDirection.y, normalDirection.x) * frequency * math.TAU; - var offset = offsetCycles * math.TAU; - var cell = math.floor(position); - var local = math.frac(position); - var phase = float2.zero; - var weightSum = 0.0f; - - for (var x = -1; x <= 2; x++) - for (var y = -1; y <= 2; y++) - { - var gridOffset = new float2(x, y); - var gridPoint = cell + gridOffset; - var randomOffset = Hash2(gridPoint) * 0.5f; - var delta = local - gridOffset - randomOffset; - var weight = math.max(0.0f, math.exp(-math.dot(delta, delta) * 2.0f) - 0.01111f); - weightSum += weight; - var wave = math.dot(delta, sideDirection) + offset; - phase += new float2(math.cos(wave), math.sin(wave)) * weight; - } - - var interpolated = phase / math.max(weightSum, 1.0e-20f); - var magnitude = math.max(1.0f - math.saturate(normalization), math.length(interpolated)); - var normalized = interpolated / math.max(magnitude, 1.0e-20f); - return new float4(normalized, sideDirection.x, sideDirection.y); - } - - private static float2 Hash2(float2 input) - { - var x = (int)input.x; - var y = (int)input.y; - return new float2(HashUnit(x, y, 0x68bc21ebu), HashUnit(x, y, 0x02e5be93u)) * 2.0f - float2.one; - } - - private static float HashUnit(int x, int y, uint salt) - { - var value = unchecked((uint)x * 0x8da6b343u ^ (uint)y * 0xd8163841u ^ salt); - value ^= value >> 16; value *= 0x7feb352du; value ^= value >> 15; value *= 0x846ca68bu; value ^= value >> 16; - return (value & 0x00ffffffu) * (1.0f / 16777216.0f); - } - - private static float2 SafeNormalize(float2 value) - { - var length = math.length(value); - return math.abs(length) > 1.0e-10f ? value / length : value; - } - - private static float PowInverse(float value, float power) => 1.0f - math.pow(1.0f - math.saturate(value), power); - private static float EaseOut(float value) { var inverse = 1.0f - math.saturate(value); return 1.0f - inverse * inverse; } - private static float SmoothStart(float value, float smoothing) => smoothing <= 1.0e-10f || value >= smoothing - ? value - 0.5f * smoothing - : 0.5f * value * value / smoothing; -} diff --git a/src/CultMath/AdvancedErosionFilter.cs.meta b/src/CultMath/AdvancedErosionFilter.cs.meta deleted file mode 100644 index 52f7ca19..00000000 --- a/src/CultMath/AdvancedErosionFilter.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: bec15fdcbe97a7f44a24bdb3ff79e1e7 \ No newline at end of file diff --git a/src/CultMath/CultMath.csproj b/src/CultMath/CultMath.csproj index 61b57c98..01901b6b 100644 --- a/src/CultMath/CultMath.csproj +++ b/src/CultMath/CultMath.csproj @@ -19,8 +19,6 @@ - - diff --git a/src/CultMath/ErosionFrequencyBands.cs b/src/CultMath/ErosionFrequencyBands.cs deleted file mode 100644 index 3c63eb62..00000000 --- a/src/CultMath/ErosionFrequencyBands.cs +++ /dev/null @@ -1,57 +0,0 @@ -namespace CultMath; - -public readonly record struct ErosionBandSelection( - int ActiveOctaves, - float FinalOctaveWeight, - float FinestIncludedWavelength, - float UnresolvedHeightBound) -{ - public bool HasSamples => ActiveOctaves > 0; -} - -public static class ErosionFrequencyBands -{ - public static ErosionBandSelection Select( - float baseWavelength, - float sampleSpacing, - int maximumOctaves, - float lacunarity, - float baseAmplitude, - float gain, - float transitionRatio = 2.0f) - { - baseWavelength = math.max(baseWavelength, 1.0e-6f); - sampleSpacing = math.max(sampleSpacing, 0.0f); - lacunarity = math.max(lacunarity, 1.01f); - transitionRatio = math.max(transitionRatio, 1.01f); - maximumOctaves = math.min(math.max(maximumOctaves, 0), 16); - var nyquistWavelength = sampleSpacing * 2.0f; - var wavelength = baseWavelength; - var active = 0; - var finalWeight = 0.0f; - var finest = 0.0f; - - for (var octave = 0; octave < maximumOctaves; octave++) - { - var weight = nyquistWavelength <= 0.0f - ? 1.0f - : math.smoothstep(nyquistWavelength, nyquistWavelength * transitionRatio, wavelength); - if (weight <= 0.0f) break; - active++; - finalWeight = weight; - finest = wavelength; - wavelength /= lacunarity; - } - - var omittedAmplitude = 0.0f; - var amplitude = math.abs(baseAmplitude); - for (var octave = 0; octave < maximumOctaves; octave++) - { - if (octave >= active) omittedAmplitude += amplitude; - else if (octave == active - 1) omittedAmplitude += amplitude * (1.0f - finalWeight); - amplitude *= math.abs(gain); - } - - return new ErosionBandSelection(active, active > 0 ? finalWeight : 0.0f, finest, omittedAmplitude); - } -} diff --git a/src/CultMath/ErosionFrequencyBands.cs.meta b/src/CultMath/ErosionFrequencyBands.cs.meta deleted file mode 100644 index cae99643..00000000 --- a/src/CultMath/ErosionFrequencyBands.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 05e7969589dd09b43bd0fda672d25a0b \ No newline at end of file diff --git a/src/CultMath/PlanetaryField.cs b/src/CultMath/PlanetaryField.cs deleted file mode 100644 index 4d5596e5..00000000 --- a/src/CultMath/PlanetaryField.cs +++ /dev/null @@ -1,215 +0,0 @@ -using System; - -namespace CultMath; - -public readonly record struct PlanetaryQueryScale(float FootprintMeters, float MaximumUnresolvedHeight) -{ - public static PlanetaryQueryScale AtFootprint(float footprintMeters, float maximumUnresolvedHeight = float.PositiveInfinity) - => new PlanetaryQueryScale(footprintMeters, maximumUnresolvedHeight).Validate(); - - public PlanetaryQueryScale Validate() - { - if (!float.IsFinite(FootprintMeters) || FootprintMeters < 0) throw new ArgumentOutOfRangeException(nameof(FootprintMeters)); - if (float.IsNaN(MaximumUnresolvedHeight) || MaximumUnresolvedHeight < 0) throw new ArgumentOutOfRangeException(nameof(MaximumUnresolvedHeight)); - return this; - } -} - -public readonly record struct PlanetaryFieldDefinition( - ulong FieldVersion, - float Radius, - int Seed, - AdvancedErosionParameters Erosion) -{ - public static PlanetaryFieldDefinition Create( - ulong baseFieldVersion, - float radius, - int seed, - AdvancedErosionParameters erosion) - => new PlanetaryFieldDefinition(PlanetaryFieldIdentity.Compute(baseFieldVersion, radius, seed, erosion), radius, seed, erosion).Validate(); - - public PlanetaryFieldDefinition Validate() - { - if (FieldVersion == 0) throw new ArgumentOutOfRangeException(nameof(FieldVersion)); - if (!float.IsFinite(Radius) || Radius <= 0) throw new ArgumentOutOfRangeException(nameof(Radius)); - if (!float.IsFinite(Erosion.Scale) || Erosion.Scale <= 0) throw new ArgumentOutOfRangeException(nameof(Erosion)); - return this; - } -} - -public static class PlanetaryFieldIdentity -{ - public static ulong Compute(ulong baseFieldVersion, float radius, int seed, in AdvancedErosionParameters erosion) - { - if (baseFieldVersion == 0) throw new ArgumentOutOfRangeException(nameof(baseFieldVersion)); - const ulong offset = 14695981039346656037UL; - const ulong prime = 1099511628211UL; - var hash = offset; - Add(baseFieldVersion); - Add((uint)BitConverter.SingleToInt32Bits(radius)); Add((uint)seed); - Add((uint)BitConverter.SingleToInt32Bits(erosion.Scale)); Add((uint)BitConverter.SingleToInt32Bits(erosion.Strength)); - Add((uint)BitConverter.SingleToInt32Bits(erosion.GullyWeight)); Add((uint)BitConverter.SingleToInt32Bits(erosion.Detail)); - AddFloat4(erosion.Rounding); AddFloat4(erosion.Onset); - Add((uint)BitConverter.SingleToInt32Bits(erosion.AssumedSlope.x)); Add((uint)BitConverter.SingleToInt32Bits(erosion.AssumedSlope.y)); - Add((uint)BitConverter.SingleToInt32Bits(erosion.CellScale)); Add((uint)BitConverter.SingleToInt32Bits(erosion.Normalization)); - Add((uint)erosion.Octaves); Add((uint)BitConverter.SingleToInt32Bits(erosion.Lacunarity)); Add((uint)BitConverter.SingleToInt32Bits(erosion.Gain)); - return hash == 0 ? 1 : hash; - - void Add(ulong value) => hash = unchecked((hash ^ value) * prime); - void AddFloat4(float4 value) - { - Add((uint)BitConverter.SingleToInt32Bits(value.x)); Add((uint)BitConverter.SingleToInt32Bits(value.y)); - Add((uint)BitConverter.SingleToInt32Bits(value.z)); Add((uint)BitConverter.SingleToInt32Bits(value.w)); - } - } -} - -/// -/// Application-supplied base evidence at one unit spherical direction. -/// FieldValue and FieldGradient drive erosion. RadialDisplacement and -/// RadialGradient describe the uneroded surface in metres. -/// -public readonly record struct PlanetaryBaseFieldSample( - float RadialDisplacement, - float3 RadialGradient, - float FieldValue, - float3 FieldGradient, - float FadeTarget); - -public readonly record struct PlanetarySurfaceSample( - ulong FieldVersion, - float3 UnitDirection, - float Radius, - float RadialDisplacement, - float3 TangentGradient, - float3 SurfaceNormal, - float Slope, - float Ridge, - float Gully, - float FinestResolvedWavelength, - float UnresolvedHeightBound) -{ - public float SurfaceRadius => Radius + RadialDisplacement; - public float3 PlanetLocalPosition => UnitDirection * SurfaceRadius; - public bool Meets(PlanetaryQueryScale scale) => UnresolvedHeightBound <= scale.MaximumUnresolvedHeight; -} - -public static class PlanetaryField -{ - public static PlanetarySurfaceSample Sample( - in PlanetaryFieldDefinition definition, - float3 unitDirection, - in PlanetaryBaseFieldSample baseSample, - in PlanetaryQueryScale scale) - { - definition.Validate(); - scale.Validate(); - PlanetaryTopology.ValidateDirection(unitDirection); - PlanetaryTopology.ValidateFinite(baseSample.RadialGradient, nameof(baseSample)); - PlanetaryTopology.ValidateFinite(baseSample.FieldGradient, nameof(baseSample)); - if (!float.IsFinite(baseSample.RadialDisplacement) || !float.IsFinite(baseSample.FieldValue) || !float.IsFinite(baseSample.FadeTarget)) - throw new ArgumentOutOfRangeException(nameof(baseSample)); - - var direction = math.normalize(unitDirection); - var radialGradient = Tangent(direction, baseSample.RadialGradient); - var fieldGradient = Tangent(direction, baseSample.FieldGradient); - var p = definition.Erosion; - var band = ErosionFrequencyBands.Select( - p.Scale * p.CellScale, - scale.FootprintMeters, - p.Octaves, - p.Lacunarity, - p.Strength * p.Scale, - p.Gain); - - var powers = new float3( - Pow4(MathF.Abs(direction.x)), - Pow4(MathF.Abs(direction.y)), - Pow4(MathF.Abs(direction.z))); - var powerSum = math.max(powers.x + powers.y + powers.z, 1.0e-6f); - var weights = powers / powerSum; - var world = direction * definition.Radius; - var seed = definition.Seed; - var xy = AdvancedErosionFilter.Sample( - world.xy + new float2(713 + seed * 0.754877666f, -291 + seed * 0.569840296f), - new float3(baseSample.FieldValue, fieldGradient.x, fieldGradient.y), baseSample.FadeTarget, p, band); - var yz = AdvancedErosionFilter.Sample( - world.yz + new float2(-431 + seed * 0.438289027f, 887 + seed * 0.328438163f), - new float3(baseSample.FieldValue, fieldGradient.y, fieldGradient.z), baseSample.FadeTarget, p, band); - var zx = AdvancedErosionFilter.Sample( - new float2(world.z, world.x) + new float2(197 + seed * 0.219783071f, 557 + seed * 0.145898034f), - new float3(baseSample.FieldValue, fieldGradient.z, fieldGradient.x), baseSample.FadeTarget, p, band); - - var erosionHeight = xy.Delta.x * weights.z + yz.Delta.x * weights.x + zx.Delta.x * weights.y; - var erosionGradient = new float3( - xy.Delta.y * weights.z + zx.Delta.z * weights.y, - xy.Delta.z * weights.z + yz.Delta.y * weights.x, - yz.Delta.z * weights.x + zx.Delta.y * weights.y); - var powerGradientX = Tangent(direction, new float3(4 * direction.x * direction.x * direction.x / definition.Radius, 0, 0)); - var powerGradientY = Tangent(direction, new float3(0, 4 * direction.y * direction.y * direction.y / definition.Radius, 0)); - var powerGradientZ = Tangent(direction, new float3(0, 0, 4 * direction.z * direction.z * direction.z / definition.Radius)); - var sumGradient = powerGradientX + powerGradientY + powerGradientZ; - var weightGradientX = (powerGradientX * powerSum - sumGradient * powers.x) / (powerSum * powerSum); - var weightGradientY = (powerGradientY * powerSum - sumGradient * powers.y) / (powerSum * powerSum); - var weightGradientZ = (powerGradientZ * powerSum - sumGradient * powers.z) / (powerSum * powerSum); - erosionGradient += yz.Delta.x * weightGradientX + zx.Delta.x * weightGradientY + xy.Delta.x * weightGradientZ; - var gradient = Tangent(direction, radialGradient + erosionGradient); - var ridgeEvidence = xy.RidgeMap * weights.z + yz.RidgeMap * weights.x + zx.RidgeMap * weights.y; - var ridge = math.saturate(ridgeEvidence * 0.5f + 0.5f); - var gully = math.saturate(0.5f - ridgeEvidence * 0.5f); - var displacement = baseSample.RadialDisplacement + erosionHeight; - - return new( - definition.FieldVersion, - direction, - definition.Radius, - displacement, - gradient, - PlanetaryTopology.SurfaceNormal(direction, gradient), - math.length(gradient), - ridge, - gully, - band.FinestIncludedWavelength, - band.UnresolvedHeightBound); - } - - public static void SampleBatch( - in PlanetaryFieldDefinition definition, - ReadOnlySpan directions, - in PlanetaryQueryScale scale, - TSource source, - Span destination) - where TSource : IPlanetaryBaseField - { - if (destination.Length < directions.Length) throw new ArgumentException("Destination is shorter than directions.", nameof(destination)); - for (var i = 0; i < directions.Length; i++) - { - var direction = math.normalize(directions[i]); - var baseSample = source.Sample(direction); - destination[i] = Sample(definition, direction, baseSample, scale); - } - } - - public static PlanetarySurfaceSample SamplePosition( - in PlanetaryFieldDefinition definition, - double3 planetLocalPosition, - in PlanetaryQueryScale scale, - TSource source) - where TSource : IPlanetaryBaseField - { - if (!double.IsFinite(planetLocalPosition.x) || !double.IsFinite(planetLocalPosition.y) || !double.IsFinite(planetLocalPosition.z)) - throw new ArgumentOutOfRangeException(nameof(planetLocalPosition)); - var length = Math.Sqrt(planetLocalPosition.x * planetLocalPosition.x + planetLocalPosition.y * planetLocalPosition.y + planetLocalPosition.z * planetLocalPosition.z); - if (length < 1.0e-12) throw new ArgumentOutOfRangeException(nameof(planetLocalPosition)); - var direction = new float3((float)(planetLocalPosition.x / length), (float)(planetLocalPosition.y / length), (float)(planetLocalPosition.z / length)); - return Sample(definition, direction, source.Sample(direction), scale); - } - - private static float3 Tangent(float3 direction, float3 gradient) => gradient - direction * math.dot(gradient, direction); - private static float Pow4(float value) { var square = value * value; return square * square; } -} - -public interface IPlanetaryBaseField -{ - PlanetaryBaseFieldSample Sample(float3 unitDirection); -} diff --git a/src/CultMath/PlanetaryField.cs.meta b/src/CultMath/PlanetaryField.cs.meta deleted file mode 100644 index 3e83f637..00000000 --- a/src/CultMath/PlanetaryField.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: b61d6354e3aab054e94721e77e619bfa \ No newline at end of file diff --git a/src/CultMath/PlanetaryGpuPages.cs b/src/CultMath/PlanetaryGpuPages.cs deleted file mode 100644 index 024d26b0..00000000 --- a/src/CultMath/PlanetaryGpuPages.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; - -namespace CultMath; - -public readonly record struct PlanetaryGpuPageInput(float4 DirectionRadius, float4 Sampling); - -public readonly record struct PlanetaryGpuPageMetadata(float4 Address, float4 Layout, float4 Bounds, float4 State); - -public readonly record struct PlanetaryGpuPageContent( - PlanetaryPageLayout Layout, - PlanetaryGpuPageInput[] Inputs, - float SampleSpacing, - float ParentSampleSpacing); - -public static class PlanetaryGpuPageBuilder -{ - public static PlanetaryGpuPageContent BuildContent(PlanetaryPageLayout layout, float radius) - { - layout.Validate(); - if (!float.IsFinite(radius) || radius <= 0) throw new ArgumentOutOfRangeException(nameof(radius)); - var spacing = PlanetaryPageSampling.NominalAngularTexelSize(layout) * radius; - var parentSpacing = layout.Tile.Level == 0 - ? 0 - : PlanetaryPageSampling.NominalAngularTexelSize(new(layout.Tile.Parent(), layout.InteriorSize, layout.BorderSize)) * radius; - var inputs = new PlanetaryGpuPageInput[layout.StorageSize * layout.StorageSize]; - for (var y = 0; y < layout.StorageSize; y++) - for (var x = 0; x < layout.StorageSize; x++) - { - var direction = PlanetaryPageSampling.Direction(layout, x, y); - inputs[y * layout.StorageSize + x] = new( - new float4(direction, radius), - new float4(spacing, parentSpacing, 0, 0)); - } - return new(layout, inputs, spacing, parentSpacing); - } - - public static PlanetaryGpuPageMetadata Metadata( - in PlanetaryGpuPageContent content, - int outputOffset, - float blend, - float4 bounds = default) - { - content.Layout.Validate(); - if (content.Inputs == null || content.Inputs.Length != content.Layout.StorageSize * content.Layout.StorageSize) - throw new ArgumentException("GPU page content does not match its layout.", nameof(content)); - if (outputOffset < 0) throw new ArgumentOutOfRangeException(nameof(outputOffset)); - if (!float.IsFinite(blend) || blend is < 0 or > 1) throw new ArgumentOutOfRangeException(nameof(blend)); - var tile = content.Layout.Tile; - return new( - new float4((int)tile.Face, tile.Level, tile.X, tile.Y), - new float4(outputOffset, content.Layout.StorageSize, content.Layout.InteriorSize, content.Layout.BorderSize), - bounds, - new float4(1, blend, PlanetaryPageSampling.NominalAngularTexelSize(content.Layout), content.SampleSpacing)); - } -} diff --git a/src/CultMath/PlanetaryGpuPages.cs.meta b/src/CultMath/PlanetaryGpuPages.cs.meta deleted file mode 100644 index 7afe847c..00000000 --- a/src/CultMath/PlanetaryGpuPages.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 42173c60766948a4e8c376687033532e \ No newline at end of file diff --git a/src/CultMath/PlanetaryMapTileEncoding.cs b/src/CultMath/PlanetaryMapTileEncoding.cs deleted file mode 100644 index ec556617..00000000 --- a/src/CultMath/PlanetaryMapTileEncoding.cs +++ /dev/null @@ -1,117 +0,0 @@ -using System; -using System.IO; -using System.Text; - -namespace CultMath; - -public static class PlanetaryMapTileEncoding -{ - public const uint FormatVersion = 1; - private static readonly byte[] Magic = Encoding.ASCII.GetBytes("CMPT"); - - public static void Write(Stream stream, in PlanetarySurfaceMapTile tile, bool leaveOpen = false) - { - if (stream == null || !stream.CanWrite) throw new ArgumentException("A writable stream is required.", nameof(stream)); - tile.Key.Validate(); - if (tile.Samples == null || tile.Validity == null || tile.Samples.Length != tile.Validity.Length) - throw new ArgumentException("Tile samples and validity must have equal lengths.", nameof(tile)); - var expectedCount = tile.Key.Layout.StorageSize * tile.Key.Layout.StorageSize; - if (tile.Samples.Length != expectedCount) throw new ArgumentException("Tile payload does not match its layout.", nameof(tile)); - - using var writer = new BinaryWriter(stream, Encoding.UTF8, leaveOpen); - writer.Write(Magic); - writer.Write(FormatVersion); - writer.Write(tile.Key.FieldVersion); - writer.Write(tile.Key.ProjectionVersion); - writer.Write(tile.Key.LayerId); - var projection = tile.Key.Layout.Projection; - writer.Write((int)projection.Kind); - writer.Write(projection.CenterLongitude); - writer.Write(projection.CenterLatitude); - writer.Write(projection.Scale); - writer.Write(tile.Key.Layout.Level); - writer.Write(tile.Key.Layout.X); - writer.Write(tile.Key.Layout.Y); - writer.Write(tile.Key.Layout.InteriorSize); - writer.Write(tile.Key.Layout.BorderSize); - writer.Write(tile.Key.QueryScale.FootprintMeters); - writer.Write(tile.Key.QueryScale.MaximumUnresolvedHeight); - writer.Write(tile.Samples.Length); - for (var i = 0; i < tile.Samples.Length; i++) - { - writer.Write(tile.Validity[i]); - if (!tile.Validity[i]) continue; - WriteSample(writer, tile.Samples[i], tile.Key.FieldVersion); - } - } - - public static PlanetarySurfaceMapTile Read(Stream stream, bool leaveOpen = false) - { - if (stream == null || !stream.CanRead) throw new ArgumentException("A readable stream is required.", nameof(stream)); - using var reader = new BinaryReader(stream, Encoding.UTF8, leaveOpen); - var magic = reader.ReadBytes(Magic.Length); - if (magic.Length != Magic.Length || !magic.AsSpan().SequenceEqual(Magic)) throw new InvalidDataException("Not a CultMath planetary tile."); - var version = reader.ReadUInt32(); - if (version != FormatVersion) throw new InvalidDataException($"Unsupported planetary tile version {version}."); - var fieldVersion = reader.ReadUInt64(); - var projectionVersion = reader.ReadUInt32(); - var layerId = reader.ReadUInt32(); - var kindValue = reader.ReadInt32(); - if (!Enum.IsDefined(typeof(PlanetaryProjectionKind), kindValue)) throw new InvalidDataException("Unknown planetary projection kind."); - var projection = new PlanetaryProjectionParameters( - (PlanetaryProjectionKind)kindValue, - reader.ReadDouble(), reader.ReadDouble(), reader.ReadDouble()).Validate(); - var layout = new PlanetaryMapTileLayout( - projection, - reader.ReadInt32(), reader.ReadInt32(), reader.ReadInt32(), - reader.ReadInt32(), reader.ReadInt32()).Validate(); - var scale = new PlanetaryQueryScale(reader.ReadSingle(), reader.ReadSingle()).Validate(); - var key = new PlanetaryMapTileKey(fieldVersion, projectionVersion, layerId, layout, scale).Validate(); - var count = reader.ReadInt32(); - if (count != layout.StorageSize * layout.StorageSize) throw new InvalidDataException("Planetary tile sample count does not match layout."); - var samples = new PlanetarySurfaceSample[count]; - var validity = new bool[count]; - for (var i = 0; i < count; i++) - { - validity[i] = reader.ReadBoolean(); - if (validity[i]) samples[i] = ReadSample(reader, fieldVersion); - } - if (stream.CanSeek && stream.Position != stream.Length) throw new InvalidDataException("Planetary tile has trailing bytes."); - return new(key, samples, validity); - } - - private static void WriteSample(BinaryWriter writer, PlanetarySurfaceSample sample, ulong fieldVersion) - { - if (sample.FieldVersion != fieldVersion) throw new ArgumentException("Sample field version does not match tile identity."); - Write(writer, sample.UnitDirection); - writer.Write(sample.Radius); - writer.Write(sample.RadialDisplacement); - Write(writer, sample.TangentGradient); - Write(writer, sample.SurfaceNormal); - writer.Write(sample.Slope); - writer.Write(sample.Ridge); - writer.Write(sample.Gully); - writer.Write(sample.FinestResolvedWavelength); - writer.Write(sample.UnresolvedHeightBound); - } - - private static PlanetarySurfaceSample ReadSample(BinaryReader reader, ulong fieldVersion) - { - var direction = ReadFloat3(reader); - var radius = reader.ReadSingle(); - var displacement = reader.ReadSingle(); - var gradient = ReadFloat3(reader); - var normal = ReadFloat3(reader); - return new( - fieldVersion, direction, radius, displacement, gradient, normal, - reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), - reader.ReadSingle(), reader.ReadSingle()); - } - - private static void Write(BinaryWriter writer, float3 value) - { - writer.Write(value.x); writer.Write(value.y); writer.Write(value.z); - } - - private static float3 ReadFloat3(BinaryReader reader) => new(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); -} diff --git a/src/CultMath/PlanetaryMapTileEncoding.cs.meta b/src/CultMath/PlanetaryMapTileEncoding.cs.meta deleted file mode 100644 index 76484f65..00000000 --- a/src/CultMath/PlanetaryMapTileEncoding.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 6898f6de57df20646a0b9077bb923592 \ No newline at end of file diff --git a/src/CultMath/PlanetaryPages.cs b/src/CultMath/PlanetaryPages.cs deleted file mode 100644 index 699a5c1d..00000000 --- a/src/CultMath/PlanetaryPages.cs +++ /dev/null @@ -1,187 +0,0 @@ -using System; - -namespace CultMath; - -public readonly record struct PlanetaryPageLayout(PlanetaryTileAddress Tile, int InteriorSize, int BorderSize) -{ - public int StorageSize => checked(InteriorSize + BorderSize * 2); - - public PlanetaryPageLayout Validate() - { - if (InteriorSize < 2) throw new ArgumentOutOfRangeException(nameof(InteriorSize)); - if (BorderSize < 0 || BorderSize >= InteriorSize) throw new ArgumentOutOfRangeException(nameof(BorderSize)); - return this; - } -} - -public readonly record struct PlanetaryPageSummary( - float MinimumHeight, - float MaximumHeight, - float MaximumSlope, - float UnresolvedHeightBound, - float AngularTexelSize); - -public readonly record struct PlanetaryPageSample(float Height, float3 TangentGradient, float Ridge, float Gully); - -public static class PlanetaryPageSampling -{ - public static float3 Direction(PlanetaryPageLayout page, int storageX, int storageY) - { - page.Validate(); - if ((uint)storageX >= (uint)page.StorageSize || (uint)storageY >= (uint)page.StorageSize) - throw new ArgumentOutOfRangeException(nameof(storageX)); - var localU = (storageX - page.BorderSize) / (double)(page.InteriorSize - 1); - var localV = (storageY - page.BorderSize) / (double)(page.InteriorSize - 1); - return DirectionAtLocal(page, localU, localV); - } - - public static float3 DirectionAtLocal(PlanetaryPageLayout page, double localU, double localV) - { - page.Validate(); - if (!double.IsFinite(localU) || !double.IsFinite(localV)) throw new ArgumentOutOfRangeException(nameof(localU)); - var count = page.Tile.AxisTileCount; - return PlanetaryTopology.Direction(new( - page.Tile.Face, - -1.0 + 2.0 * (page.Tile.X + localU) / count, - -1.0 + 2.0 * (page.Tile.Y + localV) / count)); - } - - public static float AngularTexelSize(PlanetaryPageLayout page) - { - var center = page.BorderSize + (page.InteriorSize - 1) / 2; - var a = Direction(page, center, center); - var b = Direction(page, Math.Min(center + 1, page.StorageSize - 1), center); - return MathF.Acos(math.clamp(math.dot(a, b), -1.0f, 1.0f)); - } - - public static float NominalAngularTexelSize(PlanetaryPageLayout page) - { - page.Validate(); - return MathF.PI * 0.5f / (page.Tile.AxisTileCount * (page.InteriorSize - 1)); - } - - public static PlanetaryPageSample Bilinear( - ReadOnlySpan samples, - PlanetaryPageLayout page, - float2 local) - { - page.Validate(); - if (samples.Length != page.StorageSize * page.StorageSize) throw new ArgumentException("Page sample count does not match layout.", nameof(samples)); - var texel = local * (page.InteriorSize - 1) + page.BorderSize; - var x0 = Math.Clamp((int)MathF.Floor(texel.x), 0, page.StorageSize - 1); - var y0 = Math.Clamp((int)MathF.Floor(texel.y), 0, page.StorageSize - 1); - var x1 = Math.Min(x0 + 1, page.StorageSize - 1); - var y1 = Math.Min(y0 + 1, page.StorageSize - 1); - var tx = math.frac(texel.x); - var ty = math.frac(texel.y); - var a = Lerp(samples[y0 * page.StorageSize + x0], samples[y0 * page.StorageSize + x1], tx); - var b = Lerp(samples[y1 * page.StorageSize + x0], samples[y1 * page.StorageSize + x1], tx); - return Lerp(a, b, ty); - } - - public static PlanetaryPageSummary Summarize(ReadOnlySpan samples, PlanetaryPageLayout page, float unresolvedHeightBound) - { - page.Validate(); - if (samples.Length != page.StorageSize * page.StorageSize) throw new ArgumentException("Page sample count does not match layout.", nameof(samples)); - var min = float.PositiveInfinity; - var max = float.NegativeInfinity; - var maxSlope = 0.0f; - foreach (var sample in samples) - { - min = MathF.Min(min, sample.Height); - max = MathF.Max(max, sample.Height); - maxSlope = MathF.Max(maxSlope, math.length(sample.TangentGradient)); - } - return new(min, max, maxSlope, MathF.Max(unresolvedHeightBound, 0), AngularTexelSize(page)); - } - - private static PlanetaryPageSample Lerp(PlanetaryPageSample a, PlanetaryPageSample b, float t) => new( - math.lerp(a.Height, b.Height, t), - math.lerp(a.TangentGradient, b.TangentGradient, t), - math.lerp(a.Ridge, b.Ridge, t), - math.lerp(a.Gully, b.Gully, t)); -} - -public readonly record struct PlanetaryBakedPage( - PlanetaryPageLayout Layout, - PlanetaryPageSample[] Samples, - PlanetaryPageSummary Summary); - -public static class PlanetaryPageBaker -{ - public static PlanetaryBakedPage Bake( - in PlanetaryFieldDefinition field, - PlanetaryPageLayout layout, - TSource source) - where TSource : IPlanetaryBaseField - { - layout.Validate(); field.Validate(); - var spacing = PlanetaryPageSampling.NominalAngularTexelSize(layout) * field.Radius; - var parentSpacing = layout.Tile.Level == 0 - ? 0 - : PlanetaryPageSampling.NominalAngularTexelSize(new(layout.Tile.Parent(), layout.InteriorSize, layout.BorderSize)) * field.Radius; - var samples = new PlanetaryPageSample[layout.StorageSize * layout.StorageSize]; - var unresolved = 0.0f; - for (var y = 0; y < layout.StorageSize; y++) - for (var x = 0; x < layout.StorageSize; x++) - { - var direction = PlanetaryPageSampling.Direction(layout, x, y); - var baseSample = source.Sample(direction); - var child = PlanetaryField.Sample(field, direction, baseSample, PlanetaryQueryScale.AtFootprint(spacing)); - var height = child.RadialDisplacement; - var gradient = child.TangentGradient; - if (parentSpacing > 0) - { - var parent = PlanetaryField.Sample(field, direction, baseSample, PlanetaryQueryScale.AtFootprint(parentSpacing)); - height -= parent.RadialDisplacement; - gradient -= parent.TangentGradient; - } - samples[y * layout.StorageSize + x] = new(height, gradient, child.Ridge, child.Gully); - unresolved = MathF.Max(unresolved, child.UnresolvedHeightBound); - } - return new(layout, samples, PlanetaryPageSampling.Summarize(samples, layout, unresolved)); - } -} - -public readonly record struct PlanetaryResidentPage(PlanetaryBakedPage Page, float Blend) -{ - public PlanetaryResidentPage Validate() - { - if (!float.IsFinite(Blend) || Blend is < 0 or > 1) throw new ArgumentOutOfRangeException(nameof(Blend)); - Page.Layout.Validate(); - if (Page.Samples.Length != Page.Layout.StorageSize * Page.Layout.StorageSize) throw new ArgumentException("Page payload does not match layout."); - return this; - } -} - -public static class PlanetaryPageSetSampling -{ - public static bool TrySample(ReadOnlySpan pages, float3 direction, out PlanetaryPageSample sample) - { - PlanetaryTopology.ValidateDirection(direction); - var height = 0.0f; - var gradient = float3.zero; - var ridge = 0.0f; - var gully = 0.0f; - var found = false; - var deepestLevel = -1; - foreach (var resident in pages) - { - resident.Validate(); - if (!PlanetaryTopology.TryLocalCoordinate(direction, resident.Page.Layout.Tile, out var local)) continue; - var contribution = PlanetaryPageSampling.Bilinear(resident.Page.Samples, resident.Page.Layout, local); - var blend = math.saturate(resident.Blend); - height += contribution.Height * blend; - gradient += contribution.TangentGradient * blend; - if (resident.Page.Layout.Tile.Level >= deepestLevel) - { - ridge = found ? math.lerp(ridge, contribution.Ridge, blend) : contribution.Ridge; - gully = found ? math.lerp(gully, contribution.Gully, blend) : contribution.Gully; - deepestLevel = resident.Page.Layout.Tile.Level; - } - found = true; - } - sample = new(height, gradient, ridge, gully); - return found; - } -} diff --git a/src/CultMath/PlanetaryPages.cs.meta b/src/CultMath/PlanetaryPages.cs.meta deleted file mode 100644 index 91fdc27d..00000000 --- a/src/CultMath/PlanetaryPages.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 7af9a0354faa56348a2e07188739a0ae \ No newline at end of file diff --git a/src/CultMath/PlanetaryPatch.cs b/src/CultMath/PlanetaryPatch.cs deleted file mode 100644 index 30c852ff..00000000 --- a/src/CultMath/PlanetaryPatch.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Linq; - -namespace CultMath; - -public readonly record struct PlanetaryPatchVertex(float2 LocalCoordinate, float3 UnitDirection); - -public readonly record struct PlanetaryPatchMesh( - PlanetaryCubeFace Face, - int CellsPerAxis, - PlanetaryPatchVertex[] Vertices, - int[] Indices); - -public static class PlanetaryPatch -{ - public static PlanetaryPatchMesh CreateFace(PlanetaryCubeFace face, int cellsPerAxis) - { - if (!Enum.IsDefined(typeof(PlanetaryCubeFace), face)) throw new ArgumentOutOfRangeException(nameof(face)); - if (cellsPerAxis < 1 || cellsPerAxis > 4096) throw new ArgumentOutOfRangeException(nameof(cellsPerAxis)); - var axisVertices = cellsPerAxis + 1; - var vertices = new PlanetaryPatchVertex[checked(axisVertices * axisVertices)]; - for (var y = 0; y < axisVertices; y++) - for (var x = 0; x < axisVertices; x++) - { - var local = new float2(x / (float)cellsPerAxis, y / (float)cellsPerAxis); - vertices[y * axisVertices + x] = new(local, PlanetaryTopology.Direction(new(face, local.x * 2 - 1, local.y * 2 - 1))); - } - var indices = new int[checked(cellsPerAxis * cellsPerAxis * 6)]; - var write = 0; - for (var y = 0; y < cellsPerAxis; y++) - for (var x = 0; x < cellsPerAxis; x++) - { - var lowerLeft = y * axisVertices + x; - var lowerRight = lowerLeft + 1; - var upperLeft = lowerLeft + axisVertices; - var upperRight = upperLeft + 1; - indices[write++] = lowerLeft; indices[write++] = lowerRight; indices[write++] = upperRight; - indices[write++] = lowerLeft; indices[write++] = upperRight; indices[write++] = upperLeft; - } - return new(face, cellsPerAxis, vertices, indices); - } - - public static PlanetaryPatchMesh[] CreateCubeSphere(int cellsPerAxis) - => ((PlanetaryCubeFace[])Enum.GetValues(typeof(PlanetaryCubeFace))).Select(face => CreateFace(face, cellsPerAxis)).ToArray(); -} diff --git a/src/CultMath/PlanetaryPatch.cs.meta b/src/CultMath/PlanetaryPatch.cs.meta deleted file mode 100644 index efd8156a..00000000 --- a/src/CultMath/PlanetaryPatch.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 04651571f7d240a418c1f6aafa217fa6 \ No newline at end of file diff --git a/src/CultMath/PlanetaryProjection.cs b/src/CultMath/PlanetaryProjection.cs deleted file mode 100644 index a82ebfdb..00000000 --- a/src/CultMath/PlanetaryProjection.cs +++ /dev/null @@ -1,322 +0,0 @@ -using System; - -namespace CultMath; - -public enum PlanetaryProjectionKind -{ - Equirectangular, - WebMercator, - EqualEarth, - Orthographic, - AzimuthalEquidistant, - AzimuthalEqualArea, - CubeAtlas, - LocalTangent, -} - -public readonly record struct PlanetaryProjectionParameters( - PlanetaryProjectionKind Kind, - double CenterLongitude = 0, - double CenterLatitude = 0, - double Scale = 1) -{ - public PlanetaryProjectionParameters Validate() - { - if (!double.IsFinite(CenterLongitude) || !double.IsFinite(CenterLatitude) || !double.IsFinite(Scale) || Scale <= 0) - throw new ArgumentOutOfRangeException(nameof(Scale)); - if (CenterLatitude is < -Math.PI / 2 or > Math.PI / 2) throw new ArgumentOutOfRangeException(nameof(CenterLatitude)); - return this; - } -} - -public static class PlanetaryProjection -{ - private const double EqualEarthA1 = 1.340264; - private const double EqualEarthA2 = -0.081106; - private const double EqualEarthA3 = 0.000893; - private const double EqualEarthA4 = 0.003796; - private static readonly double EqualEarthM = Math.Sqrt(3) / 2; - private static readonly double EqualEarthXMax = Math.PI / (EqualEarthM * EqualEarthA1); - private static readonly double EqualEarthYMax = EqualEarthY(Math.Asin(EqualEarthM)); - public static readonly double WebMercatorMaximumLatitude = Math.Atan(Math.Sinh(Math.PI)); - - public static bool TryForward(float3 direction, PlanetaryProjectionParameters parameters, out double2 coordinate) - { - parameters.Validate(); - PlanetaryTopology.ValidateDirection(direction); - var d = math.normalize(direction); - if (parameters.Kind == PlanetaryProjectionKind.CubeAtlas) - { - var face = PlanetaryTopology.FaceCoordinate(d); - var index = (int)face.Face; - var column = index % 3; - var row = index / 3; - coordinate = new( - (-1 + (column + (face.U + 1) * 0.5) * (2.0 / 3.0)) / parameters.Scale, - (1 - (row + (face.V + 1) * 0.5)) / parameters.Scale); - return true; - } - - var longitude = Math.Atan2(d.y, d.x); - var latitude = Math.Asin(Math.Clamp(d.z, -1, 1)); - var deltaLongitude = WrapLongitude(longitude - parameters.CenterLongitude); - var centered = CenteredForward(deltaLongitude, latitude, parameters, out coordinate); - coordinate /= parameters.Scale; - return centered; - } - - public static bool TryInverse(double2 coordinate, PlanetaryProjectionParameters parameters, out float3 direction) - { - parameters.Validate(); - if (!double.IsFinite(coordinate.x) || !double.IsFinite(coordinate.y)) - { - direction = float3.zero; - return false; - } - coordinate *= parameters.Scale; - if (parameters.Kind == PlanetaryProjectionKind.CubeAtlas) - return TryInverseCubeAtlas(coordinate, out direction); - - if (!CenteredInverse(coordinate, parameters, out var deltaLongitude, out var latitude)) - { - direction = float3.zero; - return false; - } - var longitude = WrapLongitude(deltaLongitude + parameters.CenterLongitude); - var cosLatitude = Math.Cos(latitude); - direction = math.normalize(new float3( - (float)(cosLatitude * Math.Cos(longitude)), - (float)(cosLatitude * Math.Sin(longitude)), - (float)Math.Sin(latitude))); - return true; - } - - private static bool CenteredForward(double longitude, double latitude, PlanetaryProjectionParameters p, out double2 coordinate) - { - switch (p.Kind) - { - case PlanetaryProjectionKind.Equirectangular: - coordinate = new(longitude / Math.PI, latitude / (Math.PI * 0.5)); - return true; - case PlanetaryProjectionKind.WebMercator: - if (Math.Abs(latitude) > WebMercatorMaximumLatitude) { coordinate = double2.zero; return false; } - coordinate = new(longitude / Math.PI, Math.Asinh(Math.Tan(latitude)) / Math.PI); - return true; - case PlanetaryProjectionKind.EqualEarth: - { - var theta = Math.Asin(EqualEarthM * Math.Sin(latitude)); - var theta2 = theta * theta; - var theta6 = theta2 * theta2 * theta2; - var denominator = EqualEarthM * (EqualEarthA1 + 3 * EqualEarthA2 * theta2 + theta6 * (7 * EqualEarthA3 + 9 * EqualEarthA4 * theta2)); - coordinate = new(longitude * Math.Cos(theta) / denominator / EqualEarthXMax, EqualEarthY(theta) / EqualEarthYMax); - return true; - } - case PlanetaryProjectionKind.Orthographic: - case PlanetaryProjectionKind.AzimuthalEquidistant: - case PlanetaryProjectionKind.AzimuthalEqualArea: - case PlanetaryProjectionKind.LocalTangent: - return ForwardAzimuthal(longitude, latitude, p, out coordinate); - default: - throw new ArgumentOutOfRangeException(nameof(p)); - } - } - - private static bool CenteredInverse(double2 coordinate, PlanetaryProjectionParameters p, out double longitude, out double latitude) - { - longitude = latitude = 0; - switch (p.Kind) - { - case PlanetaryProjectionKind.Equirectangular: - if (Math.Abs(coordinate.y) > 1) return false; - longitude = coordinate.x * Math.PI; latitude = coordinate.y * Math.PI * 0.5; return Math.Abs(coordinate.x) <= 1; - case PlanetaryProjectionKind.WebMercator: - if (Math.Abs(coordinate.x) > 1 || Math.Abs(coordinate.y) > 1) return false; - longitude = coordinate.x * Math.PI; latitude = Math.Atan(Math.Sinh(coordinate.y * Math.PI)); return true; - case PlanetaryProjectionKind.EqualEarth: - { - if (Math.Abs(coordinate.x) > 1 || Math.Abs(coordinate.y) > 1) return false; - var targetY = coordinate.y * EqualEarthYMax; - var theta = targetY / EqualEarthA1; - for (var i = 0; i < 8; i++) - { - var theta2 = theta * theta; - var theta6 = theta2 * theta2 * theta2; - var f = EqualEarthY(theta) - targetY; - var derivative = EqualEarthA1 + 3 * EqualEarthA2 * theta2 + theta6 * (7 * EqualEarthA3 + 9 * EqualEarthA4 * theta2); - theta -= f / derivative; - } - var sinLatitude = Math.Sin(theta) / EqualEarthM; - if (Math.Abs(sinLatitude) > 1.0000000001) return false; - latitude = Math.Asin(Math.Clamp(sinLatitude, -1, 1)); - var thetaSquared = theta * theta; - var thetaSixth = thetaSquared * thetaSquared * thetaSquared; - var denominator = EqualEarthM * (EqualEarthA1 + 3 * EqualEarthA2 * thetaSquared + thetaSixth * (7 * EqualEarthA3 + 9 * EqualEarthA4 * thetaSquared)); - longitude = coordinate.x * EqualEarthXMax * denominator / Math.Cos(theta); - return Math.Abs(longitude) <= Math.PI + 1.0e-10; - } - case PlanetaryProjectionKind.Orthographic: - case PlanetaryProjectionKind.AzimuthalEquidistant: - case PlanetaryProjectionKind.AzimuthalEqualArea: - case PlanetaryProjectionKind.LocalTangent: - return InverseAzimuthal(coordinate, p, out longitude, out latitude); - default: - throw new ArgumentOutOfRangeException(nameof(p)); - } - } - - private static bool ForwardAzimuthal(double longitude, double latitude, PlanetaryProjectionParameters p, out double2 coordinate) - { - var sin0 = Math.Sin(p.CenterLatitude); var cos0 = Math.Cos(p.CenterLatitude); - var sin = Math.Sin(latitude); var cos = Math.Cos(latitude); var cosLon = Math.Cos(longitude); - var cosC = Math.Clamp(sin0 * sin + cos0 * cos * cosLon, -1, 1); - var rawX = cos * Math.Sin(longitude); - var rawY = cos0 * sin - sin0 * cos * cosLon; - double factor; - switch (p.Kind) - { - case PlanetaryProjectionKind.Orthographic: - if (cosC < 0) { coordinate = double2.zero; return false; } - factor = 1; break; - case PlanetaryProjectionKind.AzimuthalEquidistant: - { - var c = Math.Acos(cosC); factor = c < 1.0e-12 ? 1 : c / Math.Sin(c); factor /= Math.PI; break; - } - case PlanetaryProjectionKind.AzimuthalEqualArea: - factor = Math.Sqrt(2 / Math.Max(1 + cosC, 1.0e-20)) * 0.5; break; - case PlanetaryProjectionKind.LocalTangent: - if (cosC <= 0) { coordinate = double2.zero; return false; } - factor = 1 / cosC; break; - default: throw new ArgumentOutOfRangeException(nameof(p)); - } - coordinate = new(rawX * factor, rawY * factor); - return true; - } - - private static bool InverseAzimuthal(double2 coordinate, PlanetaryProjectionParameters p, out double longitude, out double latitude) - { - longitude = latitude = 0; - var rho = Math.Sqrt(coordinate.x * coordinate.x + coordinate.y * coordinate.y); - double c; - switch (p.Kind) - { - case PlanetaryProjectionKind.Orthographic: if (rho > 1) return false; c = Math.Asin(Math.Clamp(rho, 0, 1)); break; - case PlanetaryProjectionKind.AzimuthalEquidistant: if (rho > 1) return false; c = rho * Math.PI; break; - case PlanetaryProjectionKind.AzimuthalEqualArea: if (rho > 1) return false; c = 2 * Math.Asin(Math.Clamp(rho, 0, 1)); break; - case PlanetaryProjectionKind.LocalTangent: c = Math.Atan(rho); break; - default: throw new ArgumentOutOfRangeException(nameof(p)); - } - if (rho < 1.0e-12) { latitude = p.CenterLatitude; return true; } - var sinC = Math.Sin(c); var cosC = Math.Cos(c); - var sin0 = Math.Sin(p.CenterLatitude); var cos0 = Math.Cos(p.CenterLatitude); - latitude = Math.Asin(Math.Clamp(cosC * sin0 + coordinate.y * sinC * cos0 / rho, -1, 1)); - longitude = Math.Atan2(coordinate.x * sinC, rho * cos0 * cosC - coordinate.y * sin0 * sinC); - return true; - } - - private static bool TryInverseCubeAtlas(double2 coordinate, out float3 direction) - { - direction = float3.zero; - if (coordinate.x is < -1 or > 1 || coordinate.y is < -1 or > 1) return false; - var column = Math.Min((int)((coordinate.x + 1) * 1.5), 2); - var row = Math.Min((int)((1 - coordinate.y)), 1); - var u = ((coordinate.x + 1) * 1.5 - column) * 2 - 1; - var v = ((1 - coordinate.y) - row) * 2 - 1; - direction = PlanetaryTopology.Direction(new((PlanetaryCubeFace)(row * 3 + column), u, v)); - return true; - } - - private static double EqualEarthY(double theta) - { - var theta2 = theta * theta; - var theta6 = theta2 * theta2 * theta2; - return theta * (EqualEarthA1 + EqualEarthA2 * theta2 + theta6 * (EqualEarthA3 + EqualEarthA4 * theta2)); - } - - private static double WrapLongitude(double longitude) - { - longitude %= Math.PI * 2; - if (longitude > Math.PI) longitude -= Math.PI * 2; - if (longitude < -Math.PI) longitude += Math.PI * 2; - return longitude; - } -} - -public readonly record struct PlanetaryMapTileLayout( - PlanetaryProjectionParameters Projection, - int Level, - int X, - int Y, - int InteriorSize, - int BorderSize) -{ - public int StorageSize => checked(InteriorSize + BorderSize * 2); - - public PlanetaryMapTileLayout Validate() - { - Projection.Validate(); - if (Level is < 0 or > 30) throw new ArgumentOutOfRangeException(nameof(Level)); - var count = 1 << Level; - if ((uint)X >= (uint)count || (uint)Y >= (uint)count) throw new ArgumentOutOfRangeException(nameof(X)); - if (InteriorSize < 2 || BorderSize < 0 || BorderSize >= InteriorSize) throw new ArgumentOutOfRangeException(nameof(InteriorSize)); - return this; - } -} - -public static class PlanetaryMapTileSampling -{ - public static bool TryDirection(PlanetaryMapTileLayout tile, int storageX, int storageY, out float3 direction) - { - tile.Validate(); - if ((uint)storageX >= (uint)tile.StorageSize || (uint)storageY >= (uint)tile.StorageSize) throw new ArgumentOutOfRangeException(nameof(storageX)); - var count = 1 << tile.Level; - var localU = (storageX - tile.BorderSize) / (double)(tile.InteriorSize - 1); - var localV = (storageY - tile.BorderSize) / (double)(tile.InteriorSize - 1); - var map = new double2(-1 + 2 * (tile.X + localU) / count, 1 - 2 * (tile.Y + localV) / count); - return PlanetaryProjection.TryInverse(map, tile.Projection, out direction); - } -} - -public readonly record struct PlanetaryMapTileKey( - ulong FieldVersion, - uint ProjectionVersion, - uint LayerId, - PlanetaryMapTileLayout Layout, - PlanetaryQueryScale QueryScale) -{ - public PlanetaryMapTileKey Validate() - { - if (FieldVersion == 0 || ProjectionVersion == 0) throw new ArgumentOutOfRangeException(nameof(FieldVersion)); - Layout.Validate(); QueryScale.Validate(); - return this; - } -} - -public readonly record struct PlanetarySurfaceMapTile( - PlanetaryMapTileKey Key, - PlanetarySurfaceSample[] Samples, - bool[] Validity); - -public static class PlanetaryMapTileBaker -{ - public static PlanetarySurfaceMapTile Bake( - in PlanetaryFieldDefinition field, - PlanetaryMapTileKey key, - TSource source) - where TSource : IPlanetaryBaseField - { - field.Validate(); key.Validate(); - if (field.FieldVersion != key.FieldVersion) throw new ArgumentException("Tile field version does not match definition.", nameof(key)); - var count = key.Layout.StorageSize * key.Layout.StorageSize; - var samples = new PlanetarySurfaceSample[count]; - var validity = new bool[count]; - for (var y = 0; y < key.Layout.StorageSize; y++) - for (var x = 0; x < key.Layout.StorageSize; x++) - { - var index = y * key.Layout.StorageSize + x; - if (!PlanetaryMapTileSampling.TryDirection(key.Layout, x, y, out var direction)) continue; - samples[index] = PlanetaryField.Sample(field, direction, source.Sample(direction), key.QueryScale); - validity[index] = true; - } - return new(key, samples, validity); - } -} diff --git a/src/CultMath/PlanetaryProjection.cs.meta b/src/CultMath/PlanetaryProjection.cs.meta deleted file mode 100644 index 7b1e6654..00000000 --- a/src/CultMath/PlanetaryProjection.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 5021202cf626f7442a57961255a8a217 \ No newline at end of file diff --git a/src/CultMath/PlanetaryQueries.cs b/src/CultMath/PlanetaryQueries.cs deleted file mode 100644 index 54a9a3e9..00000000 --- a/src/CultMath/PlanetaryQueries.cs +++ /dev/null @@ -1,193 +0,0 @@ -using System; - -namespace CultMath; - -public readonly record struct PlanetaryRadialBounds(float MinimumDisplacement, float MaximumDisplacement) -{ - public PlanetaryRadialBounds Validate() - { - if (!float.IsFinite(MinimumDisplacement) || !float.IsFinite(MaximumDisplacement) || MinimumDisplacement > MaximumDisplacement) - throw new ArgumentOutOfRangeException(nameof(MinimumDisplacement)); - return this; - } -} - -public readonly record struct PlanetaryRayHit( - double Distance, - double3 PlanetLocalPosition, - PlanetarySurfaceSample Surface); - -public readonly record struct PlanetaryPathSample(double Distance, PlanetarySurfaceSample Surface); - -public readonly record struct PlanetaryRegionSummary( - float MinimumDisplacement, - float MaximumDisplacement, - float MaximumSlope, - float MaximumUnresolvedHeight); - -public static class PlanetaryQueries -{ - public static bool TryIntersectRay( - in PlanetaryFieldDefinition field, - double3 rayOrigin, - double3 rayDirection, - double maximumDistance, - in PlanetaryQueryScale scale, - in PlanetaryRadialBounds bounds, - TSource source, - out PlanetaryRayHit hit) - where TSource : IPlanetaryBaseField - { - field.Validate(); scale.Validate(); bounds.Validate(); - ValidateFinite(rayOrigin, nameof(rayOrigin)); ValidateFinite(rayDirection, nameof(rayDirection)); - if (!double.IsFinite(maximumDistance) || maximumDistance <= 0) throw new ArgumentOutOfRangeException(nameof(maximumDistance)); - var directionLength = Length(rayDirection); - if (directionLength < 1.0e-15) throw new ArgumentOutOfRangeException(nameof(rayDirection)); - var direction = rayDirection / directionLength; - var outerRadius = field.Radius + bounds.MaximumDisplacement + scale.MaximumUnresolvedHeight; - if (!double.IsFinite(outerRadius)) outerRadius = field.Radius + bounds.MaximumDisplacement; - if (!TrySphereInterval(rayOrigin, direction, outerRadius, out var enter, out var leave)) { hit = default; return false; } - var start = Math.Max(enter, 0); - var end = Math.Min(leave, maximumDistance); - if (start > end) { hit = default; return false; } - - var previousDistance = start; - var previous = SignedSurfaceDistance(field, rayOrigin + direction * previousDistance, scale, source, out var previousSample); - if (previous <= 0) - { - hit = new(previousDistance, rayOrigin + direction * previousDistance, previousSample); - return true; - } - var minimumStep = Math.Max(scale.FootprintMeters * 0.5, field.Radius * 1.0e-7); - for (var iteration = 0; iteration < 512 && previousDistance < end; iteration++) - { - var nextDistance = Math.Min(previousDistance + Math.Max(previous * 0.5, minimumStep), end); - var next = SignedSurfaceDistance(field, rayOrigin + direction * nextDistance, scale, source, out var nextSample); - if (next <= 0) - { - var low = previousDistance; - var high = nextDistance; - var surface = nextSample; - for (var refine = 0; refine < 32; refine++) - { - var middle = (low + high) * 0.5; - var value = SignedSurfaceDistance(field, rayOrigin + direction * middle, scale, source, out var middleSample); - if (value > 0) low = middle; - else { high = middle; surface = middleSample; } - } - var position = rayOrigin + direction * high; - hit = new(high, position, surface); - return true; - } - if (nextDistance >= end) break; - previousDistance = nextDistance; - previous = next; - previousSample = nextSample; - } - hit = default; - return false; - } - - public static double SegmentClearance( - in PlanetaryFieldDefinition field, - double3 start, - double3 end, - double sampleSpacing, - in PlanetaryQueryScale scale, - TSource source) - where TSource : IPlanetaryBaseField - { - ValidateFinite(start, nameof(start)); ValidateFinite(end, nameof(end)); - if (!double.IsFinite(sampleSpacing) || sampleSpacing <= 0) throw new ArgumentOutOfRangeException(nameof(sampleSpacing)); - var delta = end - start; - var distance = Length(delta); - var steps = Math.Max((int)Math.Ceiling(distance / sampleSpacing), 1); - var minimum = double.PositiveInfinity; - for (var i = 0; i <= steps; i++) - { - var position = start + delta * (i / (double)steps); - minimum = Math.Min(minimum, SignedSurfaceDistance(field, position, scale, source, out _)); - } - return minimum; - } - - public static PlanetaryPathSample[] SampleGreatCircle( - in PlanetaryFieldDefinition field, - float3 startDirection, - float3 endDirection, - int segmentCount, - in PlanetaryQueryScale scale, - TSource source) - where TSource : IPlanetaryBaseField - { - if (segmentCount < 1) throw new ArgumentOutOfRangeException(nameof(segmentCount)); - PlanetaryTopology.ValidateDirection(startDirection); PlanetaryTopology.ValidateDirection(endDirection); - var a = math.normalize(startDirection); var b = math.normalize(endDirection); - var angle = MathF.Acos(math.clamp(math.dot(a, b), -1, 1)); - var sinAngle = MathF.Sin(angle); - var result = new PlanetaryPathSample[segmentCount + 1]; - for (var i = 0; i <= segmentCount; i++) - { - var t = i / (float)segmentCount; - var direction = sinAngle < 1.0e-6f - ? math.normalize(math.lerp(a, b, t)) - : math.normalize(a * (MathF.Sin((1 - t) * angle) / sinAngle) + b * (MathF.Sin(t * angle) / sinAngle)); - var sample = PlanetaryField.Sample(field, direction, source.Sample(direction), scale); - result[i] = new(angle * field.Radius * t, sample); - } - return result; - } - - public static PlanetaryRegionSummary Summarize( - in PlanetaryFieldDefinition field, - ReadOnlySpan directions, - in PlanetaryQueryScale scale, - TSource source) - where TSource : IPlanetaryBaseField - { - if (directions.IsEmpty) throw new ArgumentException("At least one direction is required.", nameof(directions)); - var min = float.PositiveInfinity; var max = float.NegativeInfinity; var slope = 0.0f; var unresolved = 0.0f; - foreach (var direction in directions) - { - var normalized = math.normalize(direction); - var sample = PlanetaryField.Sample(field, normalized, source.Sample(normalized), scale); - min = MathF.Min(min, sample.RadialDisplacement); - max = MathF.Max(max, sample.RadialDisplacement); - slope = MathF.Max(slope, sample.Slope); - unresolved = MathF.Max(unresolved, sample.UnresolvedHeightBound); - } - return new(min, max, slope, unresolved); - } - - private static double SignedSurfaceDistance( - in PlanetaryFieldDefinition field, - double3 position, - in PlanetaryQueryScale scale, - TSource source, - out PlanetarySurfaceSample sample) - where TSource : IPlanetaryBaseField - { - var radius = Length(position); - if (radius < 1.0e-15) { sample = default; return double.NegativeInfinity; } - var direction = new float3((float)(position.x / radius), (float)(position.y / radius), (float)(position.z / radius)); - sample = PlanetaryField.Sample(field, direction, source.Sample(direction), scale); - return radius - sample.SurfaceRadius; - } - - private static bool TrySphereInterval(double3 origin, double3 direction, double radius, out double enter, out double leave) - { - var b = Dot(origin, direction); - var c = Dot(origin, origin) - radius * radius; - var discriminant = b * b - c; - if (discriminant < 0) { enter = leave = 0; return false; } - var root = Math.Sqrt(discriminant); - enter = -b - root; leave = -b + root; return leave >= 0; - } - - private static double Dot(double3 a, double3 b) => a.x * b.x + a.y * b.y + a.z * b.z; - private static double Length(double3 value) => Math.Sqrt(Dot(value, value)); - private static void ValidateFinite(double3 value, string name) - { - if (!double.IsFinite(value.x) || !double.IsFinite(value.y) || !double.IsFinite(value.z)) throw new ArgumentOutOfRangeException(name); - } -} diff --git a/src/CultMath/PlanetaryQueries.cs.meta b/src/CultMath/PlanetaryQueries.cs.meta deleted file mode 100644 index 6fd11413..00000000 --- a/src/CultMath/PlanetaryQueries.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 2ec43c567214b8247bda19b5c120c200 \ No newline at end of file diff --git a/src/CultMath/PlanetaryRadialRefinement.cs b/src/CultMath/PlanetaryRadialRefinement.cs deleted file mode 100644 index 7188a513..00000000 --- a/src/CultMath/PlanetaryRadialRefinement.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace CultMath; - -public static class PlanetaryRadialRefinement -{ - public static float3 Step( - float3 position, - float3 rayDirection, - float3 center, - float targetRadius, - float minimumDerivative = 0.2f, - float maximumCorrection = 0.08f) - { - var local = position - center; - var radius = math.length(local); - var radial = local / math.max(radius, 0.0001f); - var error = radius - targetRadius; - var derivative = math.dot(rayDirection, radial); - var safeMinimum = math.max(minimumDerivative, 0.0001f); - var safeDerivative = math.abs(derivative) > safeMinimum - ? derivative - : derivative < 0.0f ? -safeMinimum : safeMinimum; - var correction = math.clamp( - -error / safeDerivative, - -math.abs(maximumCorrection), - math.abs(maximumCorrection)); - return position + rayDirection * correction; - } -} diff --git a/src/CultMath/PlanetaryRadialRefinement.cs.meta b/src/CultMath/PlanetaryRadialRefinement.cs.meta deleted file mode 100644 index 32af2655..00000000 --- a/src/CultMath/PlanetaryRadialRefinement.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 82e4db521edc253499220458b417fd1e \ No newline at end of file diff --git a/src/CultMath/PlanetaryResidency.cs b/src/CultMath/PlanetaryResidency.cs deleted file mode 100644 index 6918ac57..00000000 --- a/src/CultMath/PlanetaryResidency.cs +++ /dev/null @@ -1,148 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace CultMath; - -public readonly record struct PlanetaryLodParameters( - int MaximumLevel, - int PageInteriorSize, - int PageBorderSize, - float ViewportHeightPixels, - float MinimumFootprintMeters) -{ - public PlanetaryLodParameters Validate() - { - if (MaximumLevel is < 0 or > PlanetaryTileAddress.MaxLevel) throw new ArgumentOutOfRangeException(nameof(MaximumLevel)); - _ = new PlanetaryPageLayout(new(PlanetaryCubeFace.PositiveX, 0, 0, 0), PageInteriorSize, PageBorderSize).Validate(); - if (!float.IsFinite(ViewportHeightPixels) || ViewportHeightPixels <= 0) throw new ArgumentOutOfRangeException(nameof(ViewportHeightPixels)); - if (!float.IsFinite(MinimumFootprintMeters) || MinimumFootprintMeters < 0) throw new ArgumentOutOfRangeException(nameof(MinimumFootprintMeters)); - return this; - } -} - -public static class PlanetaryLodSelector -{ - public static int SelectLevel( - in PlanetaryFieldDefinition field, - float cameraDistanceFromCenter, - in PlanetaryLodParameters parameters) - { - field.Validate(); parameters.Validate(); - if (!float.IsFinite(cameraDistanceFromCenter) || cameraDistanceFromCenter < 0) throw new ArgumentOutOfRangeException(nameof(cameraDistanceFromCenter)); - var altitude = MathF.Max(cameraDistanceFromCenter - field.Radius, 0.001f); - var footprint = MathF.Max(altitude / parameters.ViewportHeightPixels * 2, parameters.MinimumFootprintMeters); - var erosion = field.Erosion; - for (var level = 0; level <= parameters.MaximumLevel; level++) - { - var page = new PlanetaryPageLayout(new(PlanetaryCubeFace.PositiveX, level, 0, 0), parameters.PageInteriorSize, parameters.PageBorderSize); - var spacing = PlanetaryPageSampling.NominalAngularTexelSize(page) * field.Radius; - var unresolved = ErosionFrequencyBands.Select( - erosion.Scale * erosion.CellScale, spacing, erosion.Octaves, - erosion.Lacunarity, erosion.Strength * erosion.Scale, erosion.Gain).UnresolvedHeightBound; - if (unresolved <= footprint) return level; - } - return parameters.MaximumLevel; - } - - public static PlanetaryTileAddress[] SelectAncestorChain( - in PlanetaryFieldDefinition field, - float3 cameraDirection, - float cameraDistanceFromCenter, - in PlanetaryLodParameters parameters) - { - PlanetaryTopology.ValidateDirection(cameraDirection); - var level = SelectLevel(field, cameraDistanceFromCenter, parameters); - var result = new PlanetaryTileAddress[6 + level]; - for (var face = 0; face < 6; face++) result[face] = new((PlanetaryCubeFace)face, 0, 0, 0); - var leaf = PlanetaryTopology.TileAt(cameraDirection, level); - for (var currentLevel = level; currentLevel >= 1; currentLevel--) - { - result[6 + currentLevel - 1] = leaf; - leaf = leaf.Parent(); - } - return result; - } -} - -public readonly record struct PlanetaryResidentTile(PlanetaryTileAddress Tile, float Blend, bool Departing); - -public readonly record struct PlanetaryResidencySnapshot( - ulong ContentVersion, - ulong PresentationVersion, - PlanetaryResidentTile[] Tiles); - -/// Owns presentation residency only. It never owns field content. -public sealed class PlanetaryResidualResidency -{ - private readonly Dictionary residents = new(); - private readonly Dictionary arrivals = new(); - private readonly Dictionary departures = new(); - private float lastTime = float.NegativeInfinity; - - public void Reset() - { - residents.Clear(); arrivals.Clear(); departures.Clear(); lastTime = float.NegativeInfinity; - } - - public PlanetaryResidencySnapshot Update(ReadOnlySpan desired, float timeSeconds, float transitionSeconds) - { - if (!float.IsFinite(timeSeconds)) throw new ArgumentOutOfRangeException(nameof(timeSeconds)); - if (!float.IsFinite(transitionSeconds) || transitionSeconds < 0) throw new ArgumentOutOfRangeException(nameof(transitionSeconds)); - if (timeSeconds < lastTime) Reset(); - lastTime = timeSeconds; - - var desiredKeys = new HashSet(); - foreach (var tile in desired) - { - var key = tile.StableKey; - desiredKeys.Add(key); - residents[key] = tile; - if (!arrivals.ContainsKey(key)) arrivals[key] = timeSeconds; - departures.Remove(key); - } - - foreach (var pair in residents.ToArray()) - { - if (pair.Value.Level == 0 || desiredKeys.Contains(pair.Key)) continue; - if (!departures.ContainsKey(pair.Key)) - { - var startingBlend = transitionSeconds == 0 - ? 1 - : Math.Clamp((timeSeconds - arrivals[pair.Key]) / transitionSeconds, 0, 1); - departures[pair.Key] = (timeSeconds, startingBlend); - } - if (transitionSeconds > 0 && timeSeconds - departures[pair.Key].Time < transitionSeconds) continue; - residents.Remove(pair.Key); arrivals.Remove(pair.Key); departures.Remove(pair.Key); - } - - var ordered = residents - .OrderBy(pair => pair.Value.Level) - .ThenBy(pair => pair.Value.Face) - .ThenBy(pair => pair.Value.X) - .ThenBy(pair => pair.Value.Y) - .ToArray(); - var tiles = new PlanetaryResidentTile[ordered.Length]; - for (var i = 0; i < ordered.Length; i++) - { - var pair = ordered[i]; - var departing = departures.TryGetValue(pair.Key, out var departure); - var blend = pair.Value.Level == 0 || transitionSeconds == 0 - ? 1 - : departing - ? departure.StartingBlend * Math.Clamp(1 - (timeSeconds - departure.Time) / transitionSeconds, 0, 1) - : Math.Clamp((timeSeconds - arrivals[pair.Key]) / transitionSeconds, 0, 1); - tiles[i] = new(pair.Value, blend, departing); - } - return new(Hash(ordered.Select(pair => pair.Key)), Hash(tiles.Select(tile => tile.Tile.StableKey ^ (uint)BitConverter.SingleToInt32Bits(tile.Blend))), tiles); - } - - private static ulong Hash(IEnumerable values) - { - const ulong offset = 14695981039346656037UL; - const ulong prime = 1099511628211UL; - var hash = offset; - foreach (var value in values) hash = unchecked((hash ^ value) * prime); - return hash == 0 ? 1 : hash; - } -} diff --git a/src/CultMath/PlanetaryResidency.cs.meta b/src/CultMath/PlanetaryResidency.cs.meta deleted file mode 100644 index 24347624..00000000 --- a/src/CultMath/PlanetaryResidency.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 0585ea15edd7f1c4fa272df4911a8d6f \ No newline at end of file diff --git a/src/CultMath/PlanetaryTopology.cs b/src/CultMath/PlanetaryTopology.cs deleted file mode 100644 index 57d562cc..00000000 --- a/src/CultMath/PlanetaryTopology.cs +++ /dev/null @@ -1,191 +0,0 @@ -using System; - -namespace CultMath; - -public enum PlanetaryCubeFace -{ - PositiveX, - NegativeX, - PositiveY, - NegativeY, - PositiveZ, - NegativeZ, -} - -public readonly record struct PlanetaryFaceCoordinate(PlanetaryCubeFace Face, double U, double V) -{ - public PlanetaryFaceCoordinate Validate(bool allowOutsideFace = false) - { - if (!double.IsFinite(U) || !double.IsFinite(V)) throw new ArgumentOutOfRangeException(nameof(U)); - if (!allowOutsideFace && (U is < -1.0 or > 1.0 || V is < -1.0 or > 1.0)) - throw new ArgumentOutOfRangeException(nameof(U), "Face coordinates must be in [-1, 1]."); - if (!Enum.IsDefined(typeof(PlanetaryCubeFace), Face)) throw new ArgumentOutOfRangeException(nameof(Face)); - return this; - } -} - -public readonly record struct PlanetaryTileAddress -{ - public const int MaxLevel = 30; - - public PlanetaryTileAddress(PlanetaryCubeFace face, int level, int x, int y) - { - if (!Enum.IsDefined(typeof(PlanetaryCubeFace), face)) throw new ArgumentOutOfRangeException(nameof(face)); - if (level is < 0 or > MaxLevel) throw new ArgumentOutOfRangeException(nameof(level)); - var count = 1 << level; - if ((uint)x >= (uint)count) throw new ArgumentOutOfRangeException(nameof(x)); - if ((uint)y >= (uint)count) throw new ArgumentOutOfRangeException(nameof(y)); - Face = face; - Level = level; - X = x; - Y = y; - } - - public PlanetaryCubeFace Face { get; } - public int Level { get; } - public int X { get; } - public int Y { get; } - public int AxisTileCount => 1 << Level; - - public PlanetaryTileAddress Parent() => Level == 0 - ? throw new InvalidOperationException("Root cube tile has no parent.") - : new(Face, Level - 1, X >> 1, Y >> 1); - - public PlanetaryTileAddress Child(int childX, int childY) - { - if ((uint)childX > 1) throw new ArgumentOutOfRangeException(nameof(childX)); - if ((uint)childY > 1) throw new ArgumentOutOfRangeException(nameof(childY)); - if (Level == MaxLevel) throw new InvalidOperationException($"Level {MaxLevel} cannot be subdivided."); - return new(Face, Level + 1, (X << 1) | childX, (Y << 1) | childY); - } - - public PlanetaryFaceCoordinate PositionAt(double localU, double localV) - { - if (!double.IsFinite(localU) || localU is < 0.0 or > 1.0) throw new ArgumentOutOfRangeException(nameof(localU)); - if (!double.IsFinite(localV) || localV is < 0.0 or > 1.0) throw new ArgumentOutOfRangeException(nameof(localV)); - var count = AxisTileCount; - return new(Face, -1.0 + 2.0 * (X + localU) / count, -1.0 + 2.0 * (Y + localV) / count); - } - - public ulong StableKey - { - get - { - const ulong offset = 14695981039346656037UL; - const ulong prime = 1099511628211UL; - var hash = offset; - hash = unchecked((hash ^ (uint)Face) * prime); - hash = unchecked((hash ^ (uint)Level) * prime); - hash = unchecked((hash ^ (uint)X) * prime); - hash = unchecked((hash ^ (uint)Y) * prime); - return hash == 0 ? 1 : hash; - } - } - public override string ToString() => $"{Face}/L{Level:D2}/{X}/{Y}"; -} - -public static class PlanetaryTopology -{ - private const float QuarterPi = MathF.PI * 0.25f; - - public static float3 Direction(PlanetaryFaceCoordinate coordinate) - { - coordinate.Validate(allowOutsideFace: true); - var u = MathF.Tan((float)coordinate.U * QuarterPi); - var v = MathF.Tan((float)coordinate.V * QuarterPi); - var cube = coordinate.Face switch - { - PlanetaryCubeFace.PositiveX => new float3(1, v, -u), - PlanetaryCubeFace.NegativeX => new float3(-1, v, u), - PlanetaryCubeFace.PositiveY => new float3(u, 1, -v), - PlanetaryCubeFace.NegativeY => new float3(u, -1, v), - PlanetaryCubeFace.PositiveZ => new float3(u, v, 1), - PlanetaryCubeFace.NegativeZ => new float3(-u, v, -1), - _ => throw new ArgumentOutOfRangeException(nameof(coordinate)), - }; - return math.normalize(cube); - } - - public static float3 NormalizedCubeDirection(PlanetaryFaceCoordinate coordinate) - { - coordinate.Validate(allowOutsideFace: true); - var u = (float)coordinate.U; - var v = (float)coordinate.V; - return math.normalize(CubeVector(coordinate.Face, u, v)); - } - - public static PlanetaryFaceCoordinate FaceCoordinate(float3 direction) - { - ValidateDirection(direction); - var d = math.normalize(direction); - var a = math.abs(d); - if (a.x >= a.y && a.x >= a.z) - return d.x >= 0 - ? FromCubeUv(PlanetaryCubeFace.PositiveX, -d.z / a.x, d.y / a.x) - : FromCubeUv(PlanetaryCubeFace.NegativeX, d.z / a.x, d.y / a.x); - if (a.y >= a.z) - return d.y >= 0 - ? FromCubeUv(PlanetaryCubeFace.PositiveY, d.x / a.y, -d.z / a.y) - : FromCubeUv(PlanetaryCubeFace.NegativeY, d.x / a.y, d.z / a.y); - return d.z >= 0 - ? FromCubeUv(PlanetaryCubeFace.PositiveZ, d.x / a.z, d.y / a.z) - : FromCubeUv(PlanetaryCubeFace.NegativeZ, -d.x / a.z, d.y / a.z); - } - - public static PlanetaryTileAddress TileAt(float3 direction, int level) - { - if (level is < 0 or > PlanetaryTileAddress.MaxLevel) throw new ArgumentOutOfRangeException(nameof(level)); - var face = FaceCoordinate(direction); - var count = 1 << level; - var x = Math.Clamp((int)((face.U * 0.5 + 0.5) * count), 0, count - 1); - var y = Math.Clamp((int)((face.V * 0.5 + 0.5) * count), 0, count - 1); - return new(face.Face, level, x, y); - } - - public static bool TryLocalCoordinate(float3 direction, PlanetaryTileAddress tile, out float2 local) - { - var face = FaceCoordinate(direction); - if (face.Face != tile.Face) { local = float2.zero; return false; } - var scaledU = (face.U * 0.5 + 0.5) * tile.AxisTileCount; - var scaledV = (face.V * 0.5 + 0.5) * tile.AxisTileCount; - local = new((float)(scaledU - tile.X), (float)(scaledV - tile.Y)); - return local.x is >= 0 and <= 1 && local.y is >= 0 and <= 1; - } - - public static float3 SurfaceNormal(float3 unitDirection, float3 worldDistanceTangentGradient) - { - ValidateDirection(unitDirection); - ValidateFinite(worldDistanceTangentGradient, nameof(worldDistanceTangentGradient)); - var direction = math.normalize(unitDirection); - var tangent = worldDistanceTangentGradient - direction * math.dot(worldDistanceTangentGradient, direction); - return math.normalize(direction - tangent); - } - - private static PlanetaryFaceCoordinate FromCubeUv(PlanetaryCubeFace face, float cubeU, float cubeV) => new( - face, - MathF.Atan(cubeU) / QuarterPi, - MathF.Atan(cubeV) / QuarterPi); - - private static float3 CubeVector(PlanetaryCubeFace face, float u, float v) => face switch - { - PlanetaryCubeFace.PositiveX => new float3(1, v, -u), - PlanetaryCubeFace.NegativeX => new float3(-1, v, u), - PlanetaryCubeFace.PositiveY => new float3(u, 1, -v), - PlanetaryCubeFace.NegativeY => new float3(u, -1, v), - PlanetaryCubeFace.PositiveZ => new float3(u, v, 1), - PlanetaryCubeFace.NegativeZ => new float3(-u, v, -1), - _ => throw new ArgumentOutOfRangeException(nameof(face)), - }; - - internal static void ValidateDirection(float3 direction) - { - ValidateFinite(direction, nameof(direction)); - if (math.length(direction) < 1.0e-12f) throw new ArgumentOutOfRangeException(nameof(direction)); - } - - internal static void ValidateFinite(float3 value, string name) - { - if (!float.IsFinite(value.x) || !float.IsFinite(value.y) || !float.IsFinite(value.z)) - throw new ArgumentOutOfRangeException(name); - } -} diff --git a/src/CultMath/PlanetaryTopology.cs.meta b/src/CultMath/PlanetaryTopology.cs.meta deleted file mode 100644 index 411a8bdb..00000000 --- a/src/CultMath/PlanetaryTopology.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 88f6789c4384f7846ac4be37613fe5ed \ No newline at end of file diff --git a/src/CultMath/SphericalErosion.cs b/src/CultMath/SphericalErosion.cs deleted file mode 100644 index 93ddb0ec..00000000 --- a/src/CultMath/SphericalErosion.cs +++ /dev/null @@ -1,108 +0,0 @@ -namespace CultMath; - -public readonly record struct SphericalErosionParameters( - float Frequency, - float Amplitude, - float Lacunarity, - float Gain, - float SlopeStrength, - float Detail, - float Seed, - int Octaves) -{ - public static SphericalErosionParameters Default => new(18.0f, 0.035f, 2.03f, 0.52f, 6.0f, 1.35f, 0.0f, 5); -} - -public readonly record struct SphericalErosionSample(float HeightOffset, float Ridge, float Gully, float3 Gradient); - -/// -/// Stateless, point-evaluable erosion-like synthesis on a unit sphere. -/// The matching shader body is cultmath_spherical_erosion in CultMath.hlsl. -/// Position and gradient are planet-space; the gradient is projected tangent -/// internally so cube faces and tile request order never enter the result. -/// -public static class SphericalErosion -{ - public static SphericalErosionSample Sample( - float3 unitPosition, - float baseHeight, - float3 baseGradient, - SphericalErosionParameters parameters) - { - var position = math.normalize(unitPosition); - var gradient = baseGradient - position * math.dot(baseGradient, position); - var slope = math.length(gradient); - var flow = slope > 1.0e-6f ? -gradient / slope : StableTangent(position); - var frequency = math.max(parameters.Frequency, 0.001f); - var amplitude = parameters.Amplitude; - var combiMask = EaseOut(math.saturate(slope * parameters.SlopeStrength)); - var fadeTarget = math.saturate(baseHeight * 0.5f + 0.5f) * 2.0f - 1.0f; - var heightOffset = 0.0f; - var ridge = 0.0f; - var gully = 0.0f; - - var octaveCount = math.min(math.max(parameters.Octaves, 0), 8); - for (var octave = 0; octave < octaveCount; octave++) - { - var phase = DirectionalCellWave(position * frequency, flow, parameters.Seed + octave * 19.19f); - var wave = math.cos(phase); - var waveSlope = math.sin(phase); - var faded = math.lerp(fadeTarget, wave, combiMask); - heightOffset += faded * amplitude; - ridge = math.max(ridge, math.saturate(faded)); - gully = math.max(gully, math.saturate(-faded)); - - var across = math.normalize(math.cross(position, flow)); - gradient += across * (math.sign(waveSlope) * amplitude * frequency * combiMask); - gradient -= position * math.dot(gradient, position); - slope = math.length(gradient); - flow = slope > 1.0e-6f ? -gradient / slope : StableTangent(position); - - var newMask = EaseOut(math.saturate(math.abs(waveSlope) * 1.35f)); - combiMask = PowInverse(combiMask, parameters.Detail) * newMask; - fadeTarget = faded; - frequency *= math.max(parameters.Lacunarity, 1.01f); - amplitude *= math.saturate(parameters.Gain); - } - - return new SphericalErosionSample(heightOffset, ridge, gully, gradient); - } - - private static float DirectionalCellWave(float3 position, float3 flow, float seed) - { - var cell = math.floor(position); - var local = math.frac(position); - var weights = local * local * (3.0f - 2.0f * local); - var x00 = CellWave(position, flow, cell + new float3(0, 0, 0), seed); - var x10 = CellWave(position, flow, cell + new float3(1, 0, 0), seed); - var x01 = CellWave(position, flow, cell + new float3(0, 1, 0), seed); - var x11 = CellWave(position, flow, cell + new float3(1, 1, 0), seed); - var y00 = math.lerp(x00, x10, weights.x); - var y10 = math.lerp(x01, x11, weights.x); - var z0 = math.lerp(y00, y10, weights.y); - var x00z = CellWave(position, flow, cell + new float3(0, 0, 1), seed); - var x10z = CellWave(position, flow, cell + new float3(1, 0, 1), seed); - var x01z = CellWave(position, flow, cell + new float3(0, 1, 1), seed); - var x11z = CellWave(position, flow, cell + new float3(1, 1, 1), seed); - var z1 = math.lerp(math.lerp(x00z, x10z, weights.x), math.lerp(x01z, x11z, weights.x), weights.y); - return math.lerp(z0, z1, weights.z); - } - - private static float CellWave(float3 position, float3 flow, float3 cell, float seed) - { - var pivot = cell + new float3( - math.hash(cell + seed + 11.7f), - math.hash(cell.yzx + seed + 37.1f), - math.hash(cell.zyx + seed + 73.9f)); - return math.dot(position - pivot, flow) * math.TAU + math.hash(cell + seed + 101.3f) * math.TAU; - } - - private static float3 StableTangent(float3 position) - { - var axis = math.abs(position.z) < 0.8f ? new float3(0, 0, 1) : new float3(0, 1, 0); - return math.normalize(math.cross(axis, position)); - } - - private static float EaseOut(float value) => 1.0f - (1.0f - value) * (1.0f - value); - private static float PowInverse(float value, float power) => 1.0f - math.pow(1.0f - math.saturate(value), math.max(power, 0.001f)); -} diff --git a/src/CultMath/SphericalErosion.cs.meta b/src/CultMath/SphericalErosion.cs.meta deleted file mode 100644 index 82db7730..00000000 --- a/src/CultMath/SphericalErosion.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 59ec2db73065f6c4483ad90f5e17850e \ No newline at end of file diff --git a/src/CultMath/math.cs b/src/CultMath/math.cs index e15fbf08..d0a56e76 100644 --- a/src/CultMath/math.cs +++ b/src/CultMath/math.cs @@ -22,9 +22,6 @@ public static class math public static float4 float4(float3 xyz, float w) => new(xyz, w); public static float4 float4(float x, float3 yzw) => new(x, yzw); public static float4 float4(float value) => new(value, value, value, value); - public static rect rect(float2 min, float2 max) => new(min, max); - public static rect rect(float minX, float minY, float maxX, float maxY) => new(minX, minY, maxX, maxY); - public static float radians(float degrees) => degrees * (PI / 180.0f); public static float degrees(float radians) => radians * (180.0f / PI); public static float sin(float value) => MathF.Sin(value); diff --git a/src/CultMath/rect.cs b/src/CultMath/rect.cs deleted file mode 100644 index 67b210b9..00000000 --- a/src/CultMath/rect.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace CultMath; - -public readonly record struct rect(float2 min, float2 max) -{ - public rect(float minX, float minY, float maxX, float maxY) - : this(math.float2(math.min(minX, maxX), math.min(minY, maxY)), - math.float2(math.max(minX, maxX), math.max(minY, maxY))) - { - } - - public float2 size => max - min; - public float2 center => (min + max) * 0.5f; - - public bool Contains(float2 point) - { - return point.x >= min.x && - point.x <= max.x && - point.y >= min.y && - point.y <= max.y; - } -} diff --git a/src/CultMath/rect.cs.meta b/src/CultMath/rect.cs.meta deleted file mode 100644 index 9f7598ed..00000000 --- a/src/CultMath/rect.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: b00dc5f108967db47ac2f54a47033e33 \ No newline at end of file diff --git a/tests/CultMath.Tests/AdvancedErosionFilterTests.cs b/tests/CultMath.Tests/AdvancedErosionFilterTests.cs deleted file mode 100644 index cccebd64..00000000 --- a/tests/CultMath.Tests/AdvancedErosionFilterTests.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Xunit; - -namespace CultMath.Tests; - -public sealed class AdvancedErosionFilterTests -{ - [Fact] - public void DefaultReferenceFixtureIsStable() - { - var result = AdvancedErosionFilter.Sample( - new float2(0.42f, 0.31f), - new float3(0.5f, 0.1f, -0.2f), - 0.0f, - AdvancedErosionParameters.Default); - - Assert.Equal(0.0639375f, result.Magnitude, precision: 7); - Assert.True(float.IsFinite(result.Delta.x)); - Assert.True(float.IsFinite(result.Delta.y)); - Assert.True(float.IsFinite(result.Delta.z)); - Assert.InRange(result.RidgeMap, -1.0f, 1.0f); - } - - [Fact] - public void FlatInputAndZeroRoundingRemainFinite() - { - var parameters = AdvancedErosionParameters.Default with { Rounding = float4.zero }; - var result = AdvancedErosionFilter.Sample(new float2(0.25f, 0.75f), float3.zero, 0.0f, parameters); - - Assert.True(float.IsFinite(result.Delta.x)); - Assert.True(float.IsFinite(result.RidgeMap)); - Assert.True(float.IsFinite(result.FadeTarget)); - } - - [Fact] - public void PhacellePartialNormalizationIsFiniteAtEndpoints() - { - foreach (var normalization in new[] { 0.0f, 0.5f, 1.0f }) - { - var sample = AdvancedErosionFilter.Phacelle(new float2(1.7f, -3.2f), new float2(0.6f, -0.8f), 0.7f, 0.25f, normalization); - Assert.True(float.IsFinite(sample.x)); - Assert.True(float.IsFinite(sample.y)); - } - } -} diff --git a/tests/CultMath.Tests/AdvancedErosionFilterTests.cs.meta b/tests/CultMath.Tests/AdvancedErosionFilterTests.cs.meta deleted file mode 100644 index 253ee425..00000000 --- a/tests/CultMath.Tests/AdvancedErosionFilterTests.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: a7c85309318ae3f4ba75ac28a4f661cf \ No newline at end of file diff --git a/tests/CultMath.Tests/ErosionFrequencyBandsTests.cs b/tests/CultMath.Tests/ErosionFrequencyBandsTests.cs deleted file mode 100644 index f57213a4..00000000 --- a/tests/CultMath.Tests/ErosionFrequencyBandsTests.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Xunit; - -namespace CultMath.Tests; - -public sealed class ErosionFrequencyBandsTests -{ - [Fact] - public void RadiusIndependentWorldWavelengthSelectsSameBands() - { - var small = ErosionFrequencyBands.Select(1_000.0f, 100.0f, 8, 2.0f, 20.0f, 0.5f); - var large = ErosionFrequencyBands.Select(1_000.0f, 100.0f, 8, 2.0f, 20.0f, 0.5f); - Assert.Equal(small, large); - Assert.Equal(3, small.ActiveOctaves); - } - - [Fact] - public void TransitionPartiallyWeightsLastResolvableOctave() - { - var selection = ErosionFrequencyBands.Select(1_000.0f, 50.0f, 8, 2.0f, 1.0f, 0.5f); - Assert.Equal(4, selection.ActiveOctaves); - Assert.InRange(selection.FinalOctaveWeight, 0.0f, 1.0f); - Assert.True(selection.UnresolvedHeightBound > 0.0f); - } - - [Fact] - public void BandedFilterPreservesLowOctaveResultExactly() - { - var p = AdvancedErosionParameters.Default; - var band = new ErosionBandSelection(2, 1.0f, 0.0f, 0.0f); - var banded = AdvancedErosionFilter.Sample(new float2(0.42f, 0.31f), new float3(0.5f, 0.1f, -0.2f), 0.0f, p, band); - var truncated = AdvancedErosionFilter.Sample(new float2(0.42f, 0.31f), new float3(0.5f, 0.1f, -0.2f), 0.0f, p with { Octaves = 2 }); - Assert.Equal(truncated, banded); - } -} diff --git a/tests/CultMath.Tests/ErosionFrequencyBandsTests.cs.meta b/tests/CultMath.Tests/ErosionFrequencyBandsTests.cs.meta deleted file mode 100644 index ef15b7ee..00000000 --- a/tests/CultMath.Tests/ErosionFrequencyBandsTests.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 095f8ed13d2f2f74baefd23310395256 \ No newline at end of file diff --git a/tests/CultMath.Tests/HlslMirrorTests.cs b/tests/CultMath.Tests/HlslMirrorTests.cs index 47f58971..b9396bdf 100644 --- a/tests/CultMath.Tests/HlslMirrorTests.cs +++ b/tests/CultMath.Tests/HlslMirrorTests.cs @@ -5,22 +5,13 @@ namespace CultMath.Tests; public sealed class HlslMirrorTests { [Fact] - public void HlslMirrorPublishesSphericalErosionKernel() + public void HlslMirrorDoesNotPublishGeometryKernels() { var source = File.ReadAllText(Path.Combine(GetRepositoryRoot(), "shaders", "CultMath.hlsl")); - Assert.Contains("cultmath_spherical_erosion", source); - Assert.Contains("CultMathSphericalErosionParameters", source); - } - - [Fact] - public void HlslMirrorPublishesFaithfulAdvancedErosionKernel() - { - var mirror = Path.Combine(GetRepositoryRoot(), "shaders", "CultMath.hlsl"); - var source = File.ReadAllText(mirror); - Assert.Contains("AdvancedErosionFilter.hlsl", source); - var advanced = File.ReadAllText(Path.Combine(Path.GetDirectoryName(mirror)!, "AdvancedErosionFilter.hlsl")); - Assert.Contains("cultmath_phacelle_noise", advanced); - Assert.Contains("cultmath_advanced_erosion_filter", advanced); + Assert.DoesNotContain("AdvancedErosionFilter.hlsl", source); + Assert.DoesNotContain("Planetary.hlsl", source); + Assert.DoesNotContain("spherical_erosion", source); + Assert.DoesNotContain("planetary_radial_refinement", source); } [Fact] @@ -66,24 +57,6 @@ public sealed class HlslMirrorTests Assert.Contains("max(length(value), CULTMATH_NORMALIZE_EPSILON)", include); } - [Fact] - public void HlslMirrorPublishesPlanetaryTopologyAndField() - { - var root = GetRepositoryRoot(); - var include = File.ReadAllText(Path.Combine(root, "shaders", "CultMath.hlsl")); - var planetary = File.ReadAllText(Path.Combine(root, "shaders", "Planetary.hlsl")); - Assert.Contains("Planetary.hlsl", include); - Assert.Contains("cultmath_planetary_face_direction", planetary); - Assert.Contains("cultmath_planetary_face_coordinate", planetary); - Assert.Contains("cultmath_planetary_page_local", planetary); - Assert.Contains("cultmath_planetary_field_sample", planetary); - Assert.Contains("cultmath_planetary_equirectangular_forward", planetary); - Assert.Contains("cultmath_planetary_equal_earth_forward", planetary); - Assert.Contains("cultmath_planetary_projection_forward", planetary); - Assert.Contains("cultmath_planetary_projection_inverse", planetary); - Assert.Contains("CultMathPlanetarySurfaceSample", planetary); - } - private static string GetRepositoryRoot() { var directory = new DirectoryInfo(AppContext.BaseDirectory); diff --git a/tests/CultMath.Tests/MathTests.cs b/tests/CultMath.Tests/MathTests.cs index 6979bdd6..ad268212 100644 --- a/tests/CultMath.Tests/MathTests.cs +++ b/tests/CultMath.Tests/MathTests.cs @@ -32,19 +32,6 @@ public sealed class MathTests Assert.Equal(new float4(1.0f, 2.0f, 3.0f, 4.0f), new float4(new float3(1.0f, 2.0f, 3.0f), 4.0f)); } - [Fact] - public void RectNormalizesBoundsAndContainsPoints() - { - var viewport = math.rect(10.0f, 20.0f, -5.0f, -2.0f); - - Assert.Equal(new float2(-5.0f, -2.0f), viewport.min); - Assert.Equal(new float2(10.0f, 20.0f), viewport.max); - Assert.Equal(new float2(15.0f, 22.0f), viewport.size); - Assert.Equal(new float2(2.5f, 9.0f), viewport.center); - Assert.True(viewport.Contains(new float2(0.0f, 0.0f))); - Assert.False(viewport.Contains(new float2(11.0f, 0.0f))); - } - [Fact] public void VectorsExposeCommonReadOnlySwizzles() { diff --git a/tests/CultMath.Tests/PlanetaryFieldTests.cs b/tests/CultMath.Tests/PlanetaryFieldTests.cs deleted file mode 100644 index 4dc75325..00000000 --- a/tests/CultMath.Tests/PlanetaryFieldTests.cs +++ /dev/null @@ -1,80 +0,0 @@ -using Xunit; - -namespace CultMath.Tests; - -public sealed class PlanetaryFieldTests -{ - private static readonly PlanetaryFieldDefinition Definition = new( - 0x7f59_6d11_02ab_9c31UL, - 8.4f, - 42, - AdvancedErosionParameters.Default with { Scale = 0.63f, Strength = 0.12f, Octaves = 7 }); - - [Fact] - public void SampleIsDeterministicScaleAwareAndTangent() - { - var direction = math.normalize(new float3(0.31f, -0.72f, 0.61f)); - var source = new FixtureField(); - var coarse = PlanetaryField.Sample(Definition, direction, source.Sample(direction), PlanetaryQueryScale.AtFootprint(0.1f)); - var fine = PlanetaryField.Sample(Definition, direction, source.Sample(direction), PlanetaryQueryScale.AtFootprint(0.01f)); - var repeated = PlanetaryField.Sample(Definition, direction, source.Sample(direction), PlanetaryQueryScale.AtFootprint(0.01f)); - - Assert.Equal(fine, repeated); - Assert.Equal(Definition.FieldVersion, fine.FieldVersion); - Assert.True(fine.UnresolvedHeightBound <= coarse.UnresolvedHeightBound); - Assert.True(fine.FinestResolvedWavelength <= coarse.FinestResolvedWavelength); - Assert.InRange(MathF.Abs(math.dot(fine.UnitDirection, fine.TangentGradient)), 0, 2.0e-5f); - Assert.Equal(1, math.length(fine.SurfaceNormal), 5); - } - - [Fact] - public void BatchAndDoublePositionUseThePointContract() - { - var directions = new[] - { - math.normalize(new float3(1, 2, 3)), - math.normalize(new float3(-2, 0.5f, 1)), - math.normalize(new float3(0.1f, -0.2f, -1)), - }; - var output = new PlanetarySurfaceSample[directions.Length]; - var source = new FixtureField(); - var scale = PlanetaryQueryScale.AtFootprint(0.05f); - PlanetaryField.SampleBatch(Definition, directions, scale, source, output); - - for (var i = 0; i < directions.Length; i++) - { - var normalized = math.normalize(directions[i]); - var expected = PlanetaryField.Sample(Definition, normalized, source.Sample(normalized), scale); - Assert.InRange(MathF.Abs(expected.RadialDisplacement - output[i].RadialDisplacement), 0, 1.0e-6f); - Assert.InRange(math.distance(expected.TangentGradient, output[i].TangentGradient), 0, 1.0e-6f); - } - - var d = directions[0]; - var position = new double3(d.x * 8.0e11, d.y * 8.0e11, d.z * 8.0e11); - var positioned = PlanetaryField.SamplePosition(Definition, position, scale, source); - Assert.InRange(math.distance(positioned.UnitDirection, d), 0, 2.0e-6f); - } - - [Fact] - public void FieldIdentityChangesWithEveryLoadBearingInput() - { - var erosion = AdvancedErosionParameters.Default; - var baseline = PlanetaryFieldDefinition.Create(3, 8.4f, 7, erosion); - Assert.Equal(baseline.FieldVersion, PlanetaryFieldDefinition.Create(3, 8.4f, 7, erosion).FieldVersion); - Assert.NotEqual(baseline.FieldVersion, PlanetaryFieldDefinition.Create(4, 8.4f, 7, erosion).FieldVersion); - Assert.NotEqual(baseline.FieldVersion, PlanetaryFieldDefinition.Create(3, 8.5f, 7, erosion).FieldVersion); - Assert.NotEqual(baseline.FieldVersion, PlanetaryFieldDefinition.Create(3, 8.4f, 8, erosion).FieldVersion); - Assert.NotEqual(baseline.FieldVersion, PlanetaryFieldDefinition.Create(3, 8.4f, 7, erosion with { Gain = 0.49f }).FieldVersion); - } - - private readonly struct FixtureField : IPlanetaryBaseField - { - public PlanetaryBaseFieldSample Sample(float3 direction) - { - var value = direction.x * 0.6f + direction.y * direction.z * 0.3f; - var fieldGradient = new float3(0.6f, direction.z * 0.3f, direction.y * 0.3f); - fieldGradient -= direction * math.dot(fieldGradient, direction); - return new(value * 0.1f, fieldGradient * 0.1f, value, fieldGradient, math.clamp(value, -1, 1)); - } - } -} diff --git a/tests/CultMath.Tests/PlanetaryFieldTests.cs.meta b/tests/CultMath.Tests/PlanetaryFieldTests.cs.meta deleted file mode 100644 index 1710b5ff..00000000 --- a/tests/CultMath.Tests/PlanetaryFieldTests.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: c747cfda80df21d41a57412d8d07c08a \ No newline at end of file diff --git a/tests/CultMath.Tests/PlanetaryGpuPageTests.cs b/tests/CultMath.Tests/PlanetaryGpuPageTests.cs deleted file mode 100644 index ea17b4b9..00000000 --- a/tests/CultMath.Tests/PlanetaryGpuPageTests.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Xunit; - -namespace CultMath.Tests; - -public sealed class PlanetaryGpuPageTests -{ - [Fact] - public void UploadContentUsesCanonicalDirectionsSpacingAndMetadata() - { - var layout = new PlanetaryPageLayout(new(PlanetaryCubeFace.NegativeY, 3, 4, 2), 9, 2); - var content = PlanetaryGpuPageBuilder.BuildContent(layout, 8.4f); - Assert.Equal(layout.StorageSize * layout.StorageSize, content.Inputs.Length); - Assert.True(content.ParentSampleSpacing > content.SampleSpacing); - var first = content.Inputs[0]; - Assert.Equal(PlanetaryPageSampling.Direction(layout, 0, 0), first.DirectionRadius.xyz); - Assert.Equal(8.4f, first.DirectionRadius.w); - Assert.Equal(content.SampleSpacing, first.Sampling.x); - Assert.Equal(content.ParentSampleSpacing, first.Sampling.y); - - var metadata = PlanetaryGpuPageBuilder.Metadata(content, 37, 0.25f); - Assert.Equal(new float4((int)layout.Tile.Face, layout.Tile.Level, layout.Tile.X, layout.Tile.Y), metadata.Address); - Assert.Equal(new float4(37, layout.StorageSize, layout.InteriorSize, layout.BorderSize), metadata.Layout); - Assert.Equal(0.25f, metadata.State.y); - } -} diff --git a/tests/CultMath.Tests/PlanetaryGpuPageTests.cs.meta b/tests/CultMath.Tests/PlanetaryGpuPageTests.cs.meta deleted file mode 100644 index 00f4a3a5..00000000 --- a/tests/CultMath.Tests/PlanetaryGpuPageTests.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 87266638e8010f546ab6c430a712868b \ No newline at end of file diff --git a/tests/CultMath.Tests/PlanetaryMapTileEncodingTests.cs b/tests/CultMath.Tests/PlanetaryMapTileEncodingTests.cs deleted file mode 100644 index 112cb31f..00000000 --- a/tests/CultMath.Tests/PlanetaryMapTileEncodingTests.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System.IO; -using Xunit; - -namespace CultMath.Tests; - -public sealed class PlanetaryMapTileEncodingTests -{ - [Fact] - public void BinaryTileRoundTripsIdentityValidityAndSurfaceEvidence() - { - var field = PlanetaryFieldDefinition.Create(5, 10, 3, AdvancedErosionParameters.Default); - var layout = new PlanetaryMapTileLayout(new(PlanetaryProjectionKind.EqualEarth), 1, 1, 0, 5, 1); - var key = new PlanetaryMapTileKey(field.FieldVersion, 2, 17, layout, PlanetaryQueryScale.AtFootprint(0.25f, 0.1f)); - var tile = PlanetaryMapTileBaker.Bake(field, key, new FlatField()); - using var bytes = new MemoryStream(); - PlanetaryMapTileEncoding.Write(bytes, tile, leaveOpen: true); - bytes.Position = 0; - var decoded = PlanetaryMapTileEncoding.Read(bytes); - - Assert.Equal(tile.Key, decoded.Key); - Assert.Equal(tile.Validity, decoded.Validity); - for (var i = 0; i < tile.Samples.Length; i++) - if (tile.Validity[i]) Assert.Equal(tile.Samples[i], decoded.Samples[i]); - } - - [Fact] - public void DecoderRejectsForeignMagicAndVersions() - { - Assert.Throws(() => PlanetaryMapTileEncoding.Read(new MemoryStream(new byte[] { 1, 2, 3, 4, 1, 0, 0, 0 }))); - var bytes = new byte[] { (byte)'C', (byte)'M', (byte)'P', (byte)'T', 99, 0, 0, 0 }; - Assert.Throws(() => PlanetaryMapTileEncoding.Read(new MemoryStream(bytes))); - } - - [Fact] - public void DecoderRejectsTrailingBytes() - { - var field = PlanetaryFieldDefinition.Create(2, 1, 0, AdvancedErosionParameters.Default); - var layout = new PlanetaryMapTileLayout(new(PlanetaryProjectionKind.Equirectangular), 0, 0, 0, 2, 0); - var key = new PlanetaryMapTileKey(field.FieldVersion, 1, 0, layout, PlanetaryQueryScale.AtFootprint(1)); - var tile = PlanetaryMapTileBaker.Bake(field, key, new FlatField()); - using var bytes = new MemoryStream(); - PlanetaryMapTileEncoding.Write(bytes, tile, leaveOpen: true); - bytes.WriteByte(0xff); - bytes.Position = 0; - Assert.Throws(() => PlanetaryMapTileEncoding.Read(bytes)); - } - - private readonly struct FlatField : IPlanetaryBaseField - { - public PlanetaryBaseFieldSample Sample(float3 direction) => new(0, float3.zero, 0, float3.zero, 0); - } -} diff --git a/tests/CultMath.Tests/PlanetaryMapTileEncodingTests.cs.meta b/tests/CultMath.Tests/PlanetaryMapTileEncodingTests.cs.meta deleted file mode 100644 index 027754e8..00000000 --- a/tests/CultMath.Tests/PlanetaryMapTileEncodingTests.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: e916ef83478d48b43ac99777f5e0f731 \ No newline at end of file diff --git a/tests/CultMath.Tests/PlanetaryPageTests.cs b/tests/CultMath.Tests/PlanetaryPageTests.cs deleted file mode 100644 index c4e4045b..00000000 --- a/tests/CultMath.Tests/PlanetaryPageTests.cs +++ /dev/null @@ -1,57 +0,0 @@ -using Xunit; - -namespace CultMath.Tests; - -public sealed class PlanetaryPageTests -{ - [Fact] - public void BilinearSamplingAndSummaryUseOnePageContract() - { - var layout = new PlanetaryPageLayout(new(PlanetaryCubeFace.PositiveZ, 0, 0, 0), 3, 1); - var samples = new PlanetaryPageSample[layout.StorageSize * layout.StorageSize]; - for (var y = 0; y < layout.StorageSize; y++) - for (var x = 0; x < layout.StorageSize; x++) - samples[y * layout.StorageSize + x] = new(x + y * 10, new float3(x, y, 0), x / 10.0f, y / 10.0f); - - var sample = PlanetaryPageSampling.Bilinear(samples, layout, new float2(0.25f, 0.75f)); - Assert.Equal(26.5f, sample.Height, 4); - Assert.Equal(new float3(1.5f, 2.5f, 0), sample.TangentGradient); - var summary = PlanetaryPageSampling.Summarize(samples, layout, 0.125f); - Assert.Equal(0, summary.MinimumHeight); - Assert.Equal(44, summary.MaximumHeight); - Assert.Equal(0.125f, summary.UnresolvedHeightBound); - Assert.True(summary.MaximumSlope > 0); - } - - [Fact] - public void ChildPageStoresOnlyResidualAndComposesBackToDirectField() - { - var field = new PlanetaryFieldDefinition(7, 8.4f, 3, AdvancedErosionParameters.Default with - { - Scale = 0.63f, - Strength = 0.12f, - Octaves = 7, - }); - var source = new FixtureField(); - var root = PlanetaryPageBaker.Bake(field, new(new(PlanetaryCubeFace.PositiveZ, 0, 0, 0), 17, 2), source); - var child = PlanetaryPageBaker.Bake(field, new(new(PlanetaryCubeFace.PositiveZ, 1, 1, 0), 17, 2), source); - var direction = PlanetaryPageSampling.DirectionAtLocal(child.Layout, 0.5, 0.5); - var pages = new[] { new PlanetaryResidentPage(root, 1), new PlanetaryResidentPage(child, 1) }; - Assert.True(PlanetaryPageSetSampling.TrySample(pages, direction, out var composed)); - var spacing = PlanetaryPageSampling.NominalAngularTexelSize(child.Layout) * field.Radius; - var direct = PlanetaryField.Sample(field, direction, source.Sample(direction), PlanetaryQueryScale.AtFootprint(spacing)); - Assert.InRange(MathF.Abs(composed.Height - direct.RadialDisplacement), 0, 2.0e-5f); - Assert.InRange(math.distance(composed.TangentGradient, direct.TangentGradient), 0, 3.0e-5f); - } - - private readonly struct FixtureField : IPlanetaryBaseField - { - public PlanetaryBaseFieldSample Sample(float3 direction) - { - var value = direction.x * 0.4f - direction.y * 0.2f + direction.z * 0.5f; - var gradient = new float3(0.4f, -0.2f, 0.5f); - gradient -= direction * math.dot(gradient, direction); - return new(value * 0.08f, gradient * 0.08f, value, gradient, value); - } - } -} diff --git a/tests/CultMath.Tests/PlanetaryPageTests.cs.meta b/tests/CultMath.Tests/PlanetaryPageTests.cs.meta deleted file mode 100644 index 70a43864..00000000 --- a/tests/CultMath.Tests/PlanetaryPageTests.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 7c3ae5598d3b9164a9bd3a736a22ba9a \ No newline at end of file diff --git a/tests/CultMath.Tests/PlanetaryPatchTests.cs b/tests/CultMath.Tests/PlanetaryPatchTests.cs deleted file mode 100644 index 6564c773..00000000 --- a/tests/CultMath.Tests/PlanetaryPatchTests.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Xunit; - -namespace CultMath.Tests; - -public sealed class PlanetaryPatchTests -{ - [Fact] - public void CubeSpherePatchMeshUsesCanonicalTopology() - { - var meshes = PlanetaryPatch.CreateCubeSphere(8); - Assert.Equal(6, meshes.Length); - foreach (var mesh in meshes) - { - Assert.Equal(81, mesh.Vertices.Length); - Assert.Equal(8 * 8 * 6, mesh.Indices.Length); - Assert.All(mesh.Vertices, vertex => Assert.Equal(1, math.length(vertex.UnitDirection), 5)); - foreach (var index in mesh.Indices) Assert.InRange(index, 0, mesh.Vertices.Length - 1); - } - } - - [Fact] - public void NeighborFaceCornersAreSingleValued() - { - var directions = PlanetaryPatch.CreateCubeSphere(1) - .SelectMany(mesh => mesh.Vertices.Select(vertex => vertex.UnitDirection)) - .ToArray(); - var groups = directions.GroupBy(direction => new - { - X = Math.Sign(direction.x), - Y = Math.Sign(direction.y), - Z = Math.Sign(direction.z), - }); - Assert.Equal(8, groups.Count()); - Assert.All(groups, group => - { - var first = group.First(); - Assert.All(group, direction => Assert.InRange(math.distance(first, direction), 0, 1.0e-6f)); - }); - } -} diff --git a/tests/CultMath.Tests/PlanetaryPatchTests.cs.meta b/tests/CultMath.Tests/PlanetaryPatchTests.cs.meta deleted file mode 100644 index 85990473..00000000 --- a/tests/CultMath.Tests/PlanetaryPatchTests.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 36840ef44326f84409f850163b00e1f7 \ No newline at end of file diff --git a/tests/CultMath.Tests/PlanetaryProjectionTests.cs b/tests/CultMath.Tests/PlanetaryProjectionTests.cs deleted file mode 100644 index ad811d6e..00000000 --- a/tests/CultMath.Tests/PlanetaryProjectionTests.cs +++ /dev/null @@ -1,73 +0,0 @@ -using Xunit; - -namespace CultMath.Tests; - -public sealed class PlanetaryProjectionTests -{ - [Theory] - [InlineData(PlanetaryProjectionKind.Equirectangular)] - [InlineData(PlanetaryProjectionKind.WebMercator)] - [InlineData(PlanetaryProjectionKind.EqualEarth)] - [InlineData(PlanetaryProjectionKind.Orthographic)] - [InlineData(PlanetaryProjectionKind.AzimuthalEquidistant)] - [InlineData(PlanetaryProjectionKind.AzimuthalEqualArea)] - [InlineData(PlanetaryProjectionKind.LocalTangent)] - public void ProjectionRoundTripsVisibleDirections(PlanetaryProjectionKind kind) - { - var parameters = new PlanetaryProjectionParameters(kind, 0.31, -0.22); - foreach (var longitude in new[] { -0.4, -0.1, 0.2, 0.65 }) - foreach (var latitude in new[] { -0.6, -0.15, 0.3, 0.7 }) - { - var direction = Direction(longitude + parameters.CenterLongitude, latitude); - if (!PlanetaryProjection.TryForward(direction, parameters, out var map)) continue; - Assert.True(PlanetaryProjection.TryInverse(map, parameters, out var roundTrip)); - Assert.InRange(math.distance(direction, roundTrip), 0, 3.0e-5f); - } - } - - [Fact] - public void CubeAtlasRoundTripsEveryFaceInterior() - { - var projection = new PlanetaryProjectionParameters(PlanetaryProjectionKind.CubeAtlas); - foreach (var face in Enum.GetValues()) - { - var direction = PlanetaryTopology.Direction(new(face, 0.23, -0.41)); - Assert.True(PlanetaryProjection.TryForward(direction, projection, out var map)); - Assert.True(PlanetaryProjection.TryInverse(map, projection, out var roundTrip)); - Assert.InRange(math.distance(direction, roundTrip), 0, 2.0e-6f); - } - } - - [Fact] - public void MercatorRejectsPolarSingularity() - { - var northPole = new float3(0, 0, 1); - Assert.False(PlanetaryProjection.TryForward(northPole, new(PlanetaryProjectionKind.WebMercator), out _)); - } - - [Fact] - public void MapTileBakerCarriesFieldIdentityAndProjectionValidity() - { - var field = new PlanetaryFieldDefinition(99, 10, 0, AdvancedErosionParameters.Default); - var layout = new PlanetaryMapTileLayout( - new(PlanetaryProjectionKind.Orthographic), 0, 0, 0, 9, 1); - var key = new PlanetaryMapTileKey(field.FieldVersion, 1, 7, layout, PlanetaryQueryScale.AtFootprint(0.1f)); - var tile = PlanetaryMapTileBaker.Bake(field, key, new FlatField()); - Assert.Equal(key, tile.Key); - Assert.Equal(layout.StorageSize * layout.StorageSize, tile.Samples.Length); - Assert.Contains(tile.Validity, valid => valid); - Assert.Contains(tile.Validity, valid => !valid); - Assert.All(tile.Samples.Where((_, index) => tile.Validity[index]), sample => Assert.Equal(field.FieldVersion, sample.FieldVersion)); - } - - private static float3 Direction(double longitude, double latitude) - { - var cos = Math.Cos(latitude); - return new((float)(cos * Math.Cos(longitude)), (float)(cos * Math.Sin(longitude)), (float)Math.Sin(latitude)); - } - - private readonly struct FlatField : IPlanetaryBaseField - { - public PlanetaryBaseFieldSample Sample(float3 unitDirection) => new(0, float3.zero, 0, float3.zero, 0); - } -} diff --git a/tests/CultMath.Tests/PlanetaryProjectionTests.cs.meta b/tests/CultMath.Tests/PlanetaryProjectionTests.cs.meta deleted file mode 100644 index 7f37f78f..00000000 --- a/tests/CultMath.Tests/PlanetaryProjectionTests.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: f370036bb1663524fb4a4d47dfd50401 \ No newline at end of file diff --git a/tests/CultMath.Tests/PlanetaryQueryTests.cs b/tests/CultMath.Tests/PlanetaryQueryTests.cs deleted file mode 100644 index 48d865f4..00000000 --- a/tests/CultMath.Tests/PlanetaryQueryTests.cs +++ /dev/null @@ -1,46 +0,0 @@ -using Xunit; - -namespace CultMath.Tests; - -public sealed class PlanetaryQueryTests -{ - private static readonly PlanetaryFieldDefinition Field = new(12, 10, 0, AdvancedErosionParameters.Default with { Strength = 0, Octaves = 0 }); - private static readonly PlanetaryQueryScale Scale = PlanetaryQueryScale.AtFootprint(0.1f, 0); - - [Fact] - public void RayIntersectionAndClearanceUseTheCpuSurfaceContract() - { - var source = new BulgedSphere(); - Assert.True(PlanetaryQueries.TryIntersectRay( - Field, new double3(0, 0, 20), new double3(0, 0, -1), 30, - Scale, new PlanetaryRadialBounds(-1, 1), source, out var hit)); - Assert.InRange(hit.Distance, 8.99999, 9.00001); - Assert.InRange(hit.PlanetLocalPosition.z, 10.99999, 11.00001); - var clearance = PlanetaryQueries.SegmentClearance( - Field, new double3(-2, 0, 12), new double3(2, 0, 12), 0.1, Scale, source); - Assert.True(clearance > 0.8); - } - - [Fact] - public void GreatCircleAndRegionQueriesReturnVersionedSamples() - { - var source = new BulgedSphere(); - var path = PlanetaryQueries.SampleGreatCircle(Field, new float3(1, 0, 0), new float3(0, 1, 0), 8, Scale, source); - Assert.Equal(9, path.Length); - Assert.Equal(MathF.PI * 5, path[^1].Distance, 4); - Assert.All(path, point => Assert.Equal(Field.FieldVersion, point.Surface.FieldVersion)); - var summary = PlanetaryQueries.Summarize(Field, path.Select(point => point.Surface.UnitDirection).ToArray(), Scale, source); - Assert.True(summary.MaximumDisplacement >= summary.MinimumDisplacement); - Assert.True(summary.MaximumSlope >= 0); - } - - private readonly struct BulgedSphere : IPlanetaryBaseField - { - public PlanetaryBaseFieldSample Sample(float3 direction) - { - var displacement = direction.z; - var gradient = new float3(0, 0, 1) - direction * direction.z; - return new(displacement, gradient, 0, float3.zero, 0); - } - } -} diff --git a/tests/CultMath.Tests/PlanetaryQueryTests.cs.meta b/tests/CultMath.Tests/PlanetaryQueryTests.cs.meta deleted file mode 100644 index d72b2cb6..00000000 --- a/tests/CultMath.Tests/PlanetaryQueryTests.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 93cf8771fdd520b41a4e931a6566a80a \ No newline at end of file diff --git a/tests/CultMath.Tests/PlanetaryRadialRefinementTests.cs b/tests/CultMath.Tests/PlanetaryRadialRefinementTests.cs deleted file mode 100644 index d0263b67..00000000 --- a/tests/CultMath.Tests/PlanetaryRadialRefinementTests.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Xunit; - -namespace CultMath.Tests; - -public sealed class PlanetaryRadialRefinementTests -{ - [Fact] - public void FourBoundedStepsConvergeFromTheRasterCaptureShell() - { - var center=new float3(0.3f,-0.2f,0.7f); - var radial=math.normalize(new float3(0.2f,-0.4f,0.9f)); - var targetRadius=3.85f; - var target=center+radial*targetRadius; - var origin=target+math.normalize(radial+new float3(0.12f,-0.05f,0.02f))*6.0f; - var position=center+radial*(targetRadius+0.30f); - var ray=math.normalize(position-origin); - for(var step=0;step<4;step++) - position=PlanetaryRadialRefinement.Step(position,ray,center,targetRadius); - Assert.InRange(math.abs(math.length(position-center)-targetRadius),0.0f,1.0e-4f); - } - - [Fact] - public void StepClampsWeakDerivativeCorrections() - { - var position=new float3(0,0,4.1f); - var result=PlanetaryRadialRefinement.Step(position,new float3(1,0,0),float3.zero,3.8f); - Assert.InRange(math.length(result-position),0.07999f,0.08001f); - } -} diff --git a/tests/CultMath.Tests/PlanetaryRadialRefinementTests.cs.meta b/tests/CultMath.Tests/PlanetaryRadialRefinementTests.cs.meta deleted file mode 100644 index b9f3bea9..00000000 --- a/tests/CultMath.Tests/PlanetaryRadialRefinementTests.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: d34c0018ee2b700448b16540eca8ebcf \ No newline at end of file diff --git a/tests/CultMath.Tests/PlanetaryResidencyTests.cs b/tests/CultMath.Tests/PlanetaryResidencyTests.cs deleted file mode 100644 index d2b89b7a..00000000 --- a/tests/CultMath.Tests/PlanetaryResidencyTests.cs +++ /dev/null @@ -1,57 +0,0 @@ -using Xunit; - -namespace CultMath.Tests; - -public sealed class PlanetaryResidencyTests -{ - private static readonly PlanetaryFieldDefinition Field = new( - 1, 8.4f, 0, AdvancedErosionParameters.Default with { Scale = 0.63f, Strength = 0.12f, Octaves = 7 }); - private static readonly PlanetaryLodParameters Lod = new(5, 17, 2, 720, 8.4f / 65536); - - [Fact] - public void SelectorReturnsSixRootsAndOneAncestorChain() - { - var direction = math.normalize(new float3(-0.2f, 0.91f, 0.37f)); - var selected = PlanetaryLodSelector.SelectAncestorChain(Field, direction, 8.45f, Lod); - Assert.Equal(6, selected.Count(tile => tile.Level == 0)); - var descendants = selected.Where(tile => tile.Level > 0).OrderBy(tile => tile.Level).ToArray(); - for (var i = 1; i < descendants.Length; i++) Assert.Equal(descendants[i - 1], descendants[i].Parent()); - if (descendants.Length > 0) Assert.Equal(PlanetaryTopology.TileAt(direction, descendants[^1].Level), descendants[^1]); - } - - [Fact] - public void ResidencyFadesResidualsWithoutChangingContentDuringPresentation() - { - var root = new PlanetaryTileAddress(PlanetaryCubeFace.PositiveX, 0, 0, 0); - var child = root.Child(1, 0); - var residency = new PlanetaryResidualResidency(); - var arrival = residency.Update(new[] { root, child }, 0, 1); - var midpoint = residency.Update(new[] { root, child }, 0.5f, 1); - var settled = residency.Update(new[] { root, child }, 1, 1); - Assert.Equal(arrival.ContentVersion, midpoint.ContentVersion); - Assert.Equal(midpoint.ContentVersion, settled.ContentVersion); - Assert.Equal(0, arrival.Tiles.Single(tile => tile.Tile == child).Blend); - Assert.Equal(0.5f, midpoint.Tiles.Single(tile => tile.Tile == child).Blend); - Assert.Equal(1, settled.Tiles.Single(tile => tile.Tile == child).Blend); - - var leaving = residency.Update(new[] { root }, 1.25f, 1); - Assert.True(leaving.Tiles.Single(tile => tile.Tile == child).Departing); - Assert.Equal(1, leaving.Tiles.Single(tile => tile.Tile == child).Blend); - var gone = residency.Update(new[] { root }, 2.25f, 1); - Assert.DoesNotContain(gone.Tiles, tile => tile.Tile == child); - } - - [Fact] - public void ReversingAnArrivalDepartsFromItsCurrentWeightWithoutJumping() - { - var root = new PlanetaryTileAddress(PlanetaryCubeFace.PositiveX, 0, 0, 0); - var child = root.Child(0, 1); - var residency = new PlanetaryResidualResidency(); - _ = residency.Update(new[] { root, child }, 0, 1); - var arriving = residency.Update(new[] { root, child }, 0.25f, 1); - var departing = residency.Update(new[] { root }, 0.25f, 1); - Assert.Equal(0.25f, arriving.Tiles.Single(tile => tile.Tile == child).Blend); - Assert.Equal(0.25f, departing.Tiles.Single(tile => tile.Tile == child).Blend); - Assert.True(departing.Tiles.Single(tile => tile.Tile == child).Departing); - } -} diff --git a/tests/CultMath.Tests/PlanetaryResidencyTests.cs.meta b/tests/CultMath.Tests/PlanetaryResidencyTests.cs.meta deleted file mode 100644 index be7de2b4..00000000 --- a/tests/CultMath.Tests/PlanetaryResidencyTests.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 9ece3b02dbd3d7448baabee7f1fba0ab \ No newline at end of file diff --git a/tests/CultMath.Tests/PlanetaryTopologyTests.cs b/tests/CultMath.Tests/PlanetaryTopologyTests.cs deleted file mode 100644 index 759928d8..00000000 --- a/tests/CultMath.Tests/PlanetaryTopologyTests.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Xunit; - -namespace CultMath.Tests; - -public sealed class PlanetaryTopologyTests -{ - [Fact] - public void FaceDirectionRoundTripsAcrossEveryFace() - { - foreach (var face in Enum.GetValues()) - foreach (var u in new[] { -0.9, -0.25, 0.0, 0.4, 0.9 }) - foreach (var v in new[] { -0.85, -0.1, 0.3, 0.88 }) - { - var direction = PlanetaryTopology.Direction(new(face, u, v)); - var roundTrip = PlanetaryTopology.FaceCoordinate(direction); - Assert.Equal(face, roundTrip.Face); - Assert.Equal(u, roundTrip.U, 5); - Assert.Equal(v, roundTrip.V, 5); - } - } - - [Fact] - public void SiblingPagesShareBitStableBoundaryDirections() - { - var left = new PlanetaryPageLayout(new(PlanetaryCubeFace.PositiveZ, 1, 0, 0), 17, 2); - var right = new PlanetaryPageLayout(new(PlanetaryCubeFace.PositiveZ, 1, 1, 0), 17, 2); - for (var y = 0; y < left.InteriorSize; y++) - { - var a = PlanetaryPageSampling.Direction(left, left.BorderSize + left.InteriorSize - 1, left.BorderSize + y); - var b = PlanetaryPageSampling.Direction(right, right.BorderSize, right.BorderSize + y); - Assert.Equal(a, b); - } - } - - [Fact] - public void DirectionSelectsContainingTileAndLocalCoordinate() - { - var expected = new PlanetaryTileAddress(PlanetaryCubeFace.NegativeY, 5, 19, 7); - var direction = PlanetaryPageSampling.DirectionAtLocal(new(expected, 17, 2), 0.37, 0.61); - Assert.Equal(expected, PlanetaryTopology.TileAt(direction, expected.Level)); - Assert.True(PlanetaryTopology.TryLocalCoordinate(direction, expected, out var local)); - Assert.Equal(0.37f, local.x, 4); - Assert.Equal(0.61f, local.y, 4); - } - - [Fact] - public void BorderSamplesDoNotRequireNeighborResidency() - { - var page = new PlanetaryPageLayout(new(PlanetaryCubeFace.PositiveX, 0, 0, 0), 17, 3); - var edge = PlanetaryPageSampling.Direction(page, page.BorderSize + page.InteriorSize - 1, page.BorderSize + 8); - var border = PlanetaryPageSampling.Direction(page, page.StorageSize - 1, page.BorderSize + 8); - Assert.NotEqual(edge, border); - Assert.Equal(1, math.length(border), 5); - } - - [Fact] - public void NormalizedCubeBaselineSharesFaceEdges() - { - var a = PlanetaryTopology.NormalizedCubeDirection(new(PlanetaryCubeFace.PositiveZ, 1, -0.4)); - var b = PlanetaryTopology.NormalizedCubeDirection(new(PlanetaryCubeFace.PositiveX, -1, -0.4)); - Assert.InRange(math.distance(a, b), 0, 1.0e-6f); - } -} diff --git a/tests/CultMath.Tests/PlanetaryTopologyTests.cs.meta b/tests/CultMath.Tests/PlanetaryTopologyTests.cs.meta deleted file mode 100644 index b6930142..00000000 --- a/tests/CultMath.Tests/PlanetaryTopologyTests.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: be3b0ec07fe65344db889d1e98448113 \ No newline at end of file diff --git a/tests/CultMath.Tests/SphericalErosionTests.cs b/tests/CultMath.Tests/SphericalErosionTests.cs deleted file mode 100644 index f634ba6d..00000000 --- a/tests/CultMath.Tests/SphericalErosionTests.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Xunit; - -namespace CultMath.Tests; - -public sealed class SphericalErosionTests -{ - [Fact] - public void SampleIsDeterministicAndScaleInvariant() - { - var parameters = SphericalErosionParameters.Default with { Seed = 42.0f }; - var a = SphericalErosion.Sample(new float3(0.31f, -0.74f, 0.59f), 0.2f, new float3(0.4f, -0.1f, 0.2f), parameters); - var repeated = SphericalErosion.Sample(new float3(0.31f, -0.74f, 0.59f), 0.2f, new float3(0.4f, -0.1f, 0.2f), parameters); - var b = SphericalErosion.Sample(new float3(3.1f, -7.4f, 5.9f), 0.2f, new float3(0.4f, -0.1f, 0.2f), parameters); - - Assert.Equal(a, repeated); - Assert.InRange(math.abs(a.HeightOffset-b.HeightOffset),0.0f,1.0e-6f); - Assert.InRange(math.abs(a.Ridge-b.Ridge),0.0f,1.0e-6f); - Assert.InRange(math.abs(a.Gully-b.Gully),0.0f,5.0e-5f); - Assert.InRange(math.length(a.Gradient-b.Gradient),0.0f,5.0e-6f); - Assert.InRange(a.HeightOffset, -0.08f, 0.08f); - Assert.InRange(a.Ridge, 0.0f, 1.0f); - Assert.InRange(a.Gully, 0.0f, 1.0f); - } - - [Fact] - public void NearbySamplesRemainContinuousAcrossAChartBoundary() - { - var parameters = SphericalErosionParameters.Default; - var left = SphericalErosion.Sample(math.normalize(new float3(1.0f, 0.99999f, 0.2f)), 0.1f, new float3(0.2f, -0.1f, 0.05f), parameters); - var right = SphericalErosion.Sample(math.normalize(new float3(0.99999f, 1.0f, 0.2f)), 0.1f, new float3(0.2f, -0.1f, 0.05f), parameters); - - Assert.InRange(math.abs(left.HeightOffset - right.HeightOffset), 0.0f, 0.0002f); - } -} diff --git a/tests/CultMath.Tests/SphericalErosionTests.cs.meta b/tests/CultMath.Tests/SphericalErosionTests.cs.meta deleted file mode 100644 index 00ff1de0..00000000 --- a/tests/CultMath.Tests/SphericalErosionTests.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 60eb9e9e9f8ae2948b13403f5080168e \ No newline at end of file diff --git a/tools/CultMath.PlanetaryTileFixture.meta b/tools/CultMath.PlanetaryTileFixture.meta deleted file mode 100644 index 7f40b6ae..00000000 --- a/tools/CultMath.PlanetaryTileFixture.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 7197a2202273a9445b974bdd69109b1a -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/unity/Runtime/PlanetaryPageUpload.cs b/unity/Runtime/PlanetaryPageUpload.cs deleted file mode 100644 index 1a61a707..00000000 --- a/unity/Runtime/PlanetaryPageUpload.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using UnityEngine; - -namespace CultMath.Unity; - -[StructLayout(LayoutKind.Sequential)] -public readonly struct PlanetaryPageInputGpu -{ - public PlanetaryPageInputGpu(Vector4 directionRadius, Vector4 sampling) - { - DirectionRadius = directionRadius; - Sampling = sampling; - } - - public readonly Vector4 DirectionRadius; - public readonly Vector4 Sampling; -} - -[StructLayout(LayoutKind.Sequential)] -public readonly struct PlanetaryPageMetadataGpu -{ - public PlanetaryPageMetadataGpu(Vector4 address, Vector4 layout, Vector4 bounds, Vector4 state) - { - Address = address; - Layout = layout; - Bounds = bounds; - State = state; - } - - public readonly Vector4 Address; - public readonly Vector4 Layout; - public readonly Vector4 Bounds; - public readonly Vector4 State; -} - -public readonly struct PlanetaryPageUpload -{ - public PlanetaryPageUpload( - PlanetaryPageInputGpu[] inputs, - PlanetaryPageMetadataGpu[] metadata, - int outputSampleCount, - ulong contentVersion, - ulong presentationVersion) - { - Inputs = inputs; - Metadata = metadata; - OutputSampleCount = outputSampleCount; - ContentVersion = contentVersion; - PresentationVersion = presentationVersion; - } - - public PlanetaryPageInputGpu[] Inputs { get; } - public PlanetaryPageMetadataGpu[] Metadata { get; } - public int OutputSampleCount { get; } - public ulong ContentVersion { get; } - public ulong PresentationVersion { get; } -} - -public static class PlanetaryPageUploadBuilder -{ - public static PlanetaryPageUpload Build( - in PlanetaryResidencySnapshot snapshot, - int interiorSize, - int borderSize, - float radius) - { - if (!float.IsFinite(radius) || radius <= 0) throw new ArgumentOutOfRangeException(nameof(radius)); - var inputs = new List(); - var metadata = new PlanetaryPageMetadataGpu[snapshot.Tiles.Length]; - foreach (var (resident, pageIndex) in snapshot.Tiles.Select((resident, index) => (resident, index))) - { - var layout = new PlanetaryPageLayout(resident.Tile, interiorSize, borderSize).Validate(); - var content = PlanetaryGpuPageBuilder.BuildContent(layout, radius); - var outputOffset = inputs.Count; - foreach (var input in content.Inputs) - { - inputs.Add(new( - ToUnity(input.DirectionRadius), - ToUnity(input.Sampling))); - } - var commonMetadata = PlanetaryGpuPageBuilder.Metadata(content, outputOffset, resident.Blend); - metadata[pageIndex] = new( - ToUnity(commonMetadata.Address), - ToUnity(commonMetadata.Layout), - ToUnity(commonMetadata.Bounds), - ToUnity(commonMetadata.State)); - } - return new(inputs.ToArray(), metadata, inputs.Count, snapshot.ContentVersion, snapshot.PresentationVersion); - } - - private static Vector4 ToUnity(float4 value) => new(value.x, value.y, value.z, value.w); -} diff --git a/unity/Runtime/PlanetaryPageUpload.cs.meta b/unity/Runtime/PlanetaryPageUpload.cs.meta deleted file mode 100644 index 87bcb61a..00000000 --- a/unity/Runtime/PlanetaryPageUpload.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 7edd3bb2edb2e6448a2d54fc082c27dc \ No newline at end of file diff --git a/unity/Runtime/PlanetaryPatchMeshAdapter.cs b/unity/Runtime/PlanetaryPatchMeshAdapter.cs deleted file mode 100644 index 69a72a2a..00000000 --- a/unity/Runtime/PlanetaryPatchMeshAdapter.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using UnityEngine; -using UnityEngine.Rendering; - -namespace CultMath.Unity; - -public static class PlanetaryPatchMeshAdapter -{ - public static Mesh CreateFaceMesh(PlanetaryCubeFace face, int cellsPerAxis, float radius = 1) - { - if (!float.IsFinite(radius) || radius <= 0) throw new ArgumentOutOfRangeException(nameof(radius)); - var source = PlanetaryPatch.CreateFace(face, cellsPerAxis); - var vertices = new Vector3[source.Vertices.Length]; - var normals = new Vector3[source.Vertices.Length]; - var uv = new Vector2[source.Vertices.Length]; - for (var i = 0; i < source.Vertices.Length; i++) - { - var direction = source.Vertices[i].UnitDirection; - var normal = new Vector3(direction.x, direction.y, direction.z); - vertices[i] = normal * radius; - normals[i] = normal; - uv[i] = new Vector2(source.Vertices[i].LocalCoordinate.x, source.Vertices[i].LocalCoordinate.y); - } - var mesh = new Mesh - { - name = $"CultMath Planetary {face} {cellsPerAxis}x{cellsPerAxis}", - indexFormat = vertices.Length > ushort.MaxValue ? IndexFormat.UInt32 : IndexFormat.UInt16, - vertices = vertices, - normals = normals, - uv = uv, - triangles = source.Indices, - }; - mesh.RecalculateBounds(); - return mesh; - } -} diff --git a/unity/Runtime/PlanetaryPatchMeshAdapter.cs.meta b/unity/Runtime/PlanetaryPatchMeshAdapter.cs.meta deleted file mode 100644 index 69af0abc..00000000 --- a/unity/Runtime/PlanetaryPatchMeshAdapter.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 9ad7b581e14ef774d8435069bb77ca6a \ No newline at end of file diff --git a/web/planetary-tile.cross-runtime.test.mjs b/web/planetary-tile.cross-runtime.test.mjs deleted file mode 100644 index 2b457219..00000000 --- a/web/planetary-tile.cross-runtime.test.mjs +++ /dev/null @@ -1,21 +0,0 @@ -import assert from "node:assert/strict"; -import { readFile } from "node:fs/promises"; -import { decodePlanetarySurfaceTile } from "./planetary-tile.ts"; - -if (process.argv.length !== 3) throw new Error("Expected a generated CMPT fixture path"); -const bytes = await readFile(process.argv[2]); -const arrayBuffer = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength); -const tile = decodePlanetarySurfaceTile(arrayBuffer); -assert.equal(tile.header.projectionVersion, 3); -assert.equal(tile.header.layerId, 29); -assert.equal(tile.header.projectionKind, 2); -assert.equal(tile.header.interiorSize, 5); -assert.equal(tile.header.borderSize, 1); -assert.equal(tile.storageSize, 7); -assert.equal(tile.samples.length, 49); -assert.ok(tile.samples.some(sample => sample !== null)); -for (const sample of tile.samples) { - if (sample === null) continue; - assert.ok(Number.isFinite(sample.radialDisplacement)); - assert.ok(Number.isFinite(sample.unresolvedHeightBound)); -} diff --git a/web/planetary-tile.cross-runtime.test.mjs.meta b/web/planetary-tile.cross-runtime.test.mjs.meta deleted file mode 100644 index 3c38da54..00000000 --- a/web/planetary-tile.cross-runtime.test.mjs.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 7bc397e5660d2b6448919c41983d35e8 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/web/planetary-tile.test.mjs b/web/planetary-tile.test.mjs deleted file mode 100644 index cb054f28..00000000 --- a/web/planetary-tile.test.mjs +++ /dev/null @@ -1,39 +0,0 @@ -import assert from "node:assert/strict"; -import { decodePlanetarySurfaceTile } from "./planetary-tile.ts"; - -const bytes = new ArrayBuffer(152); -const view = new DataView(bytes); -let offset = 0; -const u8 = value => view.setUint8(offset++, value); -const u32 = value => { view.setUint32(offset, value, true); offset += 4; }; -const i32 = value => { view.setInt32(offset, value, true); offset += 4; }; -const u64 = value => { view.setBigUint64(offset, value, true); offset += 8; }; -const f32 = value => { view.setFloat32(offset, value, true); offset += 4; }; -const f64 = value => { view.setFloat64(offset, value, true); offset += 8; }; - -for (const character of "CMPT") u8(character.charCodeAt(0)); -u32(1); u64(0x1234n); u32(2); u32(17); i32(0); -f64(0); f64(0); f64(1); -i32(0); i32(0); i32(0); i32(2); i32(0); -f32(10); f32(0.5); i32(4); -u8(1); -for (const value of [1, 0, 0]) f32(value); -f32(8.4); f32(0.25); -for (const value of [0, 0.1, 0]) f32(value); -for (const value of [0.99, -0.1, 0]) f32(value); -for (const value of [0.1, 0.8, 0.2, 2.5, 0.05]) f32(value); -u8(0); u8(0); u8(0); -assert.equal(offset, bytes.byteLength); - -const tile = decodePlanetarySurfaceTile(bytes); -assert.equal(tile.header.fieldVersion, 0x1234n); -assert.equal(tile.header.layerId, 17); -assert.equal(tile.storageSize, 2); -assert.equal(tile.samples.length, 4); -assert.equal(tile.samples[0]?.radialDisplacement, 0.25); -assert.equal(tile.samples[1], null); - -assert.throws(() => decodePlanetarySurfaceTile(bytes.slice(0, bytes.byteLength - 1)), /Truncated/); -const trailing = new Uint8Array(bytes.byteLength + 1); -trailing.set(new Uint8Array(bytes)); -assert.throws(() => decodePlanetarySurfaceTile(trailing.buffer), /trailing/); diff --git a/web/planetary-tile.test.mjs.meta b/web/planetary-tile.test.mjs.meta deleted file mode 100644 index d622095b..00000000 --- a/web/planetary-tile.test.mjs.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 04c93ecab90d465499aa3d60722e6fc3 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/web/planetary-tile.ts b/web/planetary-tile.ts deleted file mode 100644 index e68d70fa..00000000 --- a/web/planetary-tile.ts +++ /dev/null @@ -1,89 +0,0 @@ -export const CULTMATH_PLANETARY_TILE_VERSION = 1; - -export interface PlanetaryTileHeader { - fieldVersion: bigint; - projectionVersion: number; - layerId: number; - projectionKind: number; - centerLongitude: number; - centerLatitude: number; - projectionScale: number; - level: number; - x: number; - y: number; - interiorSize: number; - borderSize: number; - footprintMeters: number; - maximumUnresolvedHeight: number; -} - -export interface PlanetaryTileSample { - direction: readonly [number, number, number]; - radius: number; - radialDisplacement: number; - tangentGradient: readonly [number, number, number]; - surfaceNormal: readonly [number, number, number]; - slope: number; - ridge: number; - gully: number; - finestResolvedWavelength: number; - unresolvedHeightBound: number; -} - -export interface PlanetarySurfaceTile { - header: PlanetaryTileHeader; - storageSize: number; - samples: readonly (PlanetaryTileSample | null)[]; -} - -export function decodePlanetarySurfaceTile(bytes: ArrayBuffer): PlanetarySurfaceTile { - const view = new DataView(bytes); - let offset = 0; - const u8 = () => view.getUint8(offset++); - const u32 = () => { const value = view.getUint32(offset, true); offset += 4; return value; }; - const i32 = () => { const value = view.getInt32(offset, true); offset += 4; return value; }; - const f32 = () => { const value = view.getFloat32(offset, true); offset += 4; return value; }; - const f64 = () => { const value = view.getFloat64(offset, true); offset += 8; return value; }; - const u64 = () => { const value = view.getBigUint64(offset, true); offset += 8; return value; }; - const vector3 = (): [number, number, number] => [f32(), f32(), f32()]; - const requireRemaining = (count: number) => { - if (offset + count > view.byteLength) throw new Error("Truncated CultMath planetary tile"); - }; - - requireRemaining(8); - if (String.fromCharCode(u8(), u8(), u8(), u8()) !== "CMPT") throw new Error("Not a CultMath planetary tile"); - const version = u32(); - if (version !== CULTMATH_PLANETARY_TILE_VERSION) throw new Error(`Unsupported CultMath planetary tile version ${version}`); - requireRemaining(76); - const header: PlanetaryTileHeader = { - fieldVersion: u64(), - projectionVersion: u32(), - layerId: u32(), - projectionKind: i32(), - centerLongitude: f64(), - centerLatitude: f64(), - projectionScale: f64(), - level: i32(), x: i32(), y: i32(), interiorSize: i32(), borderSize: i32(), - footprintMeters: f32(), maximumUnresolvedHeight: f32(), - }; - const count = i32(); - const storageSize = header.interiorSize + header.borderSize * 2; - if (count !== storageSize * storageSize) throw new Error("CultMath planetary tile sample count does not match layout"); - const samples: (PlanetaryTileSample | null)[] = new Array(count); - for (let index = 0; index < count; index++) { - requireRemaining(1); - if (u8() === 0) { samples[index] = null; continue; } - requireRemaining(64); - samples[index] = { - direction: vector3(), - radius: f32(), - radialDisplacement: f32(), - tangentGradient: vector3(), - surfaceNormal: vector3(), - slope: f32(), ridge: f32(), gully: f32(), - finestResolvedWavelength: f32(), unresolvedHeightBound: f32(), - }; - } - if (offset !== view.byteLength) throw new Error("CultMath planetary tile has trailing bytes"); - return { header, storageSize, samples }; -} diff --git a/web/planetary-tile.ts.meta b/web/planetary-tile.ts.meta deleted file mode 100644 index 337da3bd..00000000 --- a/web/planetary-tile.ts.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: f284e64628320844196b7aaea76475a4 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: From 756f5a333748fc34c4331d5fd097a8cd40445aaa Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 03:47:57 +0100 Subject: [PATCH 029/283] Transfer planetary geometry into GameCult.Geometry --- .gitignore | 10 + CultLib.sln | 15 + Directory.Build.props | 2 + ...th-gamecult-geometry-migration-progress.md | 41 +- package.json | 3 +- packages/gamecult-geometry-ts/package.json | 10 + .../src/planetary-tile.ts | 47 +++ .../planetary-tile.cross-runtime.test.mjs | 16 + .../test/planetary-tile.test.mjs | 24 ++ scripts/build-geometry-unity-package.ps1 | 14 +- scripts/test-geometry-planetary-tile.ps1 | 9 + .../GameCult.Geometry.csproj | 14 +- src/GameCult.Geometry/IsExternalInit.cs | 7 + src/GameCult.Geometry/LICENSES.md | 13 + .../Planetary/AdvancedErosionFilter.cs | 141 +++++++ .../Planetary/ErosionFrequencyBands.cs | 63 +++ .../Planetary/PlanetaryField.cs | 220 ++++++++++ .../Planetary/PlanetaryGpuPages.cs | 60 +++ .../Planetary/PlanetaryMapTileEncoding.cs | 122 ++++++ .../Planetary/PlanetaryPages.cs | 192 +++++++++ .../Planetary/PlanetaryPatch.cs | 50 +++ .../Planetary/PlanetaryProjection.cs | 327 +++++++++++++++ .../Planetary/PlanetaryQueries.cs | 198 +++++++++ .../Planetary/PlanetaryRadialRefinement.cs | 34 ++ .../Planetary/PlanetaryResidency.cs | 153 +++++++ .../Planetary/PlanetaryTopology.cs | 196 +++++++++ .../Planetary/SphericalErosion.cs | 114 +++++ src/GameCult.Geometry/README.md | 35 +- .../Shaders/AdvancedErosionFilter.hlsl | 147 +++++++ .../Shaders/AdvancedErosionFilter.hlsl.meta | 7 + .../Shaders/GameCult.Geometry.hlsl | 14 + .../Shaders/GameCult.Geometry.hlsl.meta | 7 + src/GameCult.Geometry/Shaders/Planetary.hlsl | 392 ++++++++++++++++++ .../Shaders/Planetary.hlsl.meta | 7 + .../Shaders/PlanetaryRadialRefinement.hlsl | 27 ++ .../PlanetaryRadialRefinement.hlsl.meta | 7 + .../Shaders/SphericalErosion.hlsl | 80 ++++ .../Shaders/SphericalErosion.hlsl.meta | 7 + src/GameCult.Geometry/THIRD-PARTY-NOTICES.md | 24 ++ src/GameCult.Geometry/docs/planetary.md | 135 ++++++ .../AdvancedErosionFilterTests.cs | 47 +++ .../ErosionFrequencyBandsTests.cs | 37 ++ .../GameCult.Geometry.Planetary.Tests.csproj | 18 + .../PlanetaryFieldTests.cs | 83 ++++ .../PlanetaryGpuPageTests.cs | 28 ++ .../PlanetaryMapTileEncodingTests.cs | 55 +++ .../PlanetaryPageTests.cs | 60 +++ .../PlanetaryPatchTests.cs | 43 ++ .../PlanetaryProjectionTests.cs | 76 ++++ .../PlanetaryQueryTests.cs | 49 +++ .../PlanetaryRadialRefinementTests.cs | 32 ++ .../PlanetaryResidencyTests.cs | 60 +++ .../PlanetaryTopologyTests.cs | 66 +++ .../SphericalErosionTests.cs | 37 ++ .../GeometryShaderOwnershipTests.cs | 79 ++++ ...eCult.Geometry.PlanetaryTileFixture.csproj | 11 + .../Program.cs | 23 + unity/org.gamecult.geometry/README.md | 9 +- .../Runtime/GameCult.Geometry.Unity.asmdef | 8 + .../Runtime/PlanetaryPageUpload.cs | 29 ++ .../Runtime/PlanetaryPageUpload.cs.meta | 2 + .../Runtime/PlanetaryPatchMeshAdapter.cs | 27 ++ .../Runtime/PlanetaryPatchMeshAdapter.cs.meta | 2 + ...ult.Geometry.PlanetaryViewer.Editor.asmdef | 1 + .../GameCultGeometryPlanetaryViewerMenu.cs | 27 ++ .../Samples~/PlanetaryViewer/README.md | 7 + .../GameCult.Geometry.PlanetaryViewer.asmdef | 1 + .../GameCultGeometryPlanetaryViewer.cs | 141 +++++++ .../GameCultGeometryPlanetaryViewer.shader | 91 ++++ unity/org.gamecult.geometry/package.json | 3 +- 70 files changed, 4105 insertions(+), 31 deletions(-) create mode 100644 packages/gamecult-geometry-ts/package.json create mode 100644 packages/gamecult-geometry-ts/src/planetary-tile.ts create mode 100644 packages/gamecult-geometry-ts/test/planetary-tile.cross-runtime.test.mjs create mode 100644 packages/gamecult-geometry-ts/test/planetary-tile.test.mjs create mode 100644 scripts/test-geometry-planetary-tile.ps1 create mode 100644 src/GameCult.Geometry/IsExternalInit.cs create mode 100644 src/GameCult.Geometry/LICENSES.md create mode 100644 src/GameCult.Geometry/Planetary/AdvancedErosionFilter.cs create mode 100644 src/GameCult.Geometry/Planetary/ErosionFrequencyBands.cs create mode 100644 src/GameCult.Geometry/Planetary/PlanetaryField.cs create mode 100644 src/GameCult.Geometry/Planetary/PlanetaryGpuPages.cs create mode 100644 src/GameCult.Geometry/Planetary/PlanetaryMapTileEncoding.cs create mode 100644 src/GameCult.Geometry/Planetary/PlanetaryPages.cs create mode 100644 src/GameCult.Geometry/Planetary/PlanetaryPatch.cs create mode 100644 src/GameCult.Geometry/Planetary/PlanetaryProjection.cs create mode 100644 src/GameCult.Geometry/Planetary/PlanetaryQueries.cs create mode 100644 src/GameCult.Geometry/Planetary/PlanetaryRadialRefinement.cs create mode 100644 src/GameCult.Geometry/Planetary/PlanetaryResidency.cs create mode 100644 src/GameCult.Geometry/Planetary/PlanetaryTopology.cs create mode 100644 src/GameCult.Geometry/Planetary/SphericalErosion.cs create mode 100644 src/GameCult.Geometry/Shaders/AdvancedErosionFilter.hlsl create mode 100644 src/GameCult.Geometry/Shaders/AdvancedErosionFilter.hlsl.meta create mode 100644 src/GameCult.Geometry/Shaders/GameCult.Geometry.hlsl create mode 100644 src/GameCult.Geometry/Shaders/GameCult.Geometry.hlsl.meta create mode 100644 src/GameCult.Geometry/Shaders/Planetary.hlsl create mode 100644 src/GameCult.Geometry/Shaders/Planetary.hlsl.meta create mode 100644 src/GameCult.Geometry/Shaders/PlanetaryRadialRefinement.hlsl create mode 100644 src/GameCult.Geometry/Shaders/PlanetaryRadialRefinement.hlsl.meta create mode 100644 src/GameCult.Geometry/Shaders/SphericalErosion.hlsl create mode 100644 src/GameCult.Geometry/Shaders/SphericalErosion.hlsl.meta create mode 100644 src/GameCult.Geometry/THIRD-PARTY-NOTICES.md create mode 100644 src/GameCult.Geometry/docs/planetary.md create mode 100644 tests/GameCult.Geometry.Planetary.Tests/AdvancedErosionFilterTests.cs create mode 100644 tests/GameCult.Geometry.Planetary.Tests/ErosionFrequencyBandsTests.cs create mode 100644 tests/GameCult.Geometry.Planetary.Tests/GameCult.Geometry.Planetary.Tests.csproj create mode 100644 tests/GameCult.Geometry.Planetary.Tests/PlanetaryFieldTests.cs create mode 100644 tests/GameCult.Geometry.Planetary.Tests/PlanetaryGpuPageTests.cs create mode 100644 tests/GameCult.Geometry.Planetary.Tests/PlanetaryMapTileEncodingTests.cs create mode 100644 tests/GameCult.Geometry.Planetary.Tests/PlanetaryPageTests.cs create mode 100644 tests/GameCult.Geometry.Planetary.Tests/PlanetaryPatchTests.cs create mode 100644 tests/GameCult.Geometry.Planetary.Tests/PlanetaryProjectionTests.cs create mode 100644 tests/GameCult.Geometry.Planetary.Tests/PlanetaryQueryTests.cs create mode 100644 tests/GameCult.Geometry.Planetary.Tests/PlanetaryRadialRefinementTests.cs create mode 100644 tests/GameCult.Geometry.Planetary.Tests/PlanetaryResidencyTests.cs create mode 100644 tests/GameCult.Geometry.Planetary.Tests/PlanetaryTopologyTests.cs create mode 100644 tests/GameCult.Geometry.Planetary.Tests/SphericalErosionTests.cs create mode 100644 tests/GameCult.Geometry.Tests/GeometryShaderOwnershipTests.cs create mode 100644 tools/GameCult.Geometry.PlanetaryTileFixture/GameCult.Geometry.PlanetaryTileFixture.csproj create mode 100644 tools/GameCult.Geometry.PlanetaryTileFixture/Program.cs create mode 100644 unity/org.gamecult.geometry/Runtime/GameCult.Geometry.Unity.asmdef create mode 100644 unity/org.gamecult.geometry/Runtime/PlanetaryPageUpload.cs create mode 100644 unity/org.gamecult.geometry/Runtime/PlanetaryPageUpload.cs.meta create mode 100644 unity/org.gamecult.geometry/Runtime/PlanetaryPatchMeshAdapter.cs create mode 100644 unity/org.gamecult.geometry/Runtime/PlanetaryPatchMeshAdapter.cs.meta create mode 100644 unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Editor/GameCult.Geometry.PlanetaryViewer.Editor.asmdef create mode 100644 unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Editor/GameCultGeometryPlanetaryViewerMenu.cs create mode 100644 unity/org.gamecult.geometry/Samples~/PlanetaryViewer/README.md create mode 100644 unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Runtime/GameCult.Geometry.PlanetaryViewer.asmdef create mode 100644 unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Runtime/GameCultGeometryPlanetaryViewer.cs create mode 100644 unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Runtime/GameCultGeometryPlanetaryViewer.shader diff --git a/.gitignore b/.gitignore index 2e7fdf6c..2fdb5151 100644 --- a/.gitignore +++ b/.gitignore @@ -209,6 +209,14 @@ PublishScripts/ !/packages/gamecult-geometry-rs/ !/packages/gamecult-geometry-rs/** packages/gamecult-geometry-rs/target/ +.tools/ +!/packages/gamecult-geometry-ts/ +!/packages/gamecult-geometry-ts/** +!/unity/org.gamecult.geometry/Samples~/ +!/unity/org.gamecult.geometry/Samples~/** +!/unity/org.gamecult.geometry/Runtime/PlanetaryPatchMeshAdapter.cs.meta +!/unity/org.gamecult.geometry/Runtime/PlanetaryPageUpload.cs.meta +!/src/GameCult.Geometry/Shaders/*.hlsl.meta # except build/, which is used as an MSBuild target. !**/[Pp]ackages/build/ # Uncomment if necessary however generally it will be regenerated when needed @@ -244,6 +252,8 @@ _pkginfo.txt ClientBin/ ~$* *~ +!/unity/org.gamecult.geometry/Samples~/ +!/unity/org.gamecult.geometry/Samples~/** *.dbmdl *.dbproj.schemaview *.jfm diff --git a/CultLib.sln b/CultLib.sln index f6ae25e9..0319071d 100644 --- a/CultLib.sln +++ b/CultLib.sln @@ -29,6 +29,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCult.Geometry", "src\Ga EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCult.Geometry.Tests", "tests\GameCult.Geometry.Tests\GameCult.Geometry.Tests.csproj", "{C95A9A21-34FA-4D82-BE5B-88FBDA836D31}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCult.Geometry.Planetary.Tests", "tests\GameCult.Geometry.Planetary.Tests\GameCult.Geometry.Planetary.Tests.csproj", "{CE447820-B407-48DE-8957-F373E032C4AE}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCult.Mesh.Tests", "tests\GameCult.Mesh.Tests\GameCult.Mesh.Tests.csproj", "{F8A5060A-FB0B-4B8B-AE06-5147BB4CA127}" EndProject Global @@ -173,6 +175,18 @@ Global {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 + {CE447820-B407-48DE-8957-F373E032C4AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CE447820-B407-48DE-8957-F373E032C4AE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CE447820-B407-48DE-8957-F373E032C4AE}.Debug|x64.ActiveCfg = Debug|Any CPU + {CE447820-B407-48DE-8957-F373E032C4AE}.Debug|x64.Build.0 = Debug|Any CPU + {CE447820-B407-48DE-8957-F373E032C4AE}.Debug|x86.ActiveCfg = Debug|Any CPU + {CE447820-B407-48DE-8957-F373E032C4AE}.Debug|x86.Build.0 = Debug|Any CPU + {CE447820-B407-48DE-8957-F373E032C4AE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CE447820-B407-48DE-8957-F373E032C4AE}.Release|Any CPU.Build.0 = Release|Any CPU + {CE447820-B407-48DE-8957-F373E032C4AE}.Release|x64.ActiveCfg = Release|Any CPU + {CE447820-B407-48DE-8957-F373E032C4AE}.Release|x64.Build.0 = Release|Any CPU + {CE447820-B407-48DE-8957-F373E032C4AE}.Release|x86.ActiveCfg = Release|Any CPU + {CE447820-B407-48DE-8957-F373E032C4AE}.Release|x86.Build.0 = Release|Any CPU {F8A5060A-FB0B-4B8B-AE06-5147BB4CA127}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F8A5060A-FB0B-4B8B-AE06-5147BB4CA127}.Debug|Any CPU.Build.0 = Debug|Any CPU {F8A5060A-FB0B-4B8B-AE06-5147BB4CA127}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -201,6 +215,7 @@ Global {EB15435B-7147-4BD9-BB9C-B0A14318D3D5} = {39D316AB-ABB5-49A2-8E83-CAF4C75B48F4} {94C086DA-3359-424B-9688-29A198806481} = {E733CBFF-42AE-4B6A-B5B9-0071ECFB45F1} {C95A9A21-34FA-4D82-BE5B-88FBDA836D31} = {39D316AB-ABB5-49A2-8E83-CAF4C75B48F4} + {CE447820-B407-48DE-8957-F373E032C4AE} = {39D316AB-ABB5-49A2-8E83-CAF4C75B48F4} {F8A5060A-FB0B-4B8B-AE06-5147BB4CA127} = {39D316AB-ABB5-49A2-8E83-CAF4C75B48F4} EndGlobalSection EndGlobal diff --git a/Directory.Build.props b/Directory.Build.props index 519e7a93..e38b66bc 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -15,6 +15,8 @@ © Meta Vens and contributors true 1.0.3 + $(MSBuildThisFileDirectory)..\CultMath\.tools\local-feed + $(RestoreAdditionalProjectSources);$(CultMathCandidateFeed) true diff --git a/docs/cultmath-gamecult-geometry-migration-progress.md b/docs/cultmath-gamecult-geometry-migration-progress.md index 3fefd608..3a882a81 100644 --- a/docs/cultmath-gamecult-geometry-migration-progress.md +++ b/docs/cultmath-gamecult-geometry-migration-progress.md @@ -57,7 +57,7 @@ Demotions: | 0. Freeze and baseline | Complete | Source bodies, contracts, consumers, licenses, fixtures, and focused baselines mapped | | 1. Destination/dependency/formatters/SoA | Complete | NuGet and dedicated UPM artifacts prove dependency direction and owned vector integration | | 2. Primitive deletion and v2 schemas | Complete | C# and Geometry-owned Rust emit identical v2 bytes and record keys for all four roots | -| 3. Planetary transfer | In progress | Transfer C#/tests first, then shaders and runtime projections; delete CultMath owners in the same stage | +| 3. Planetary transfer | Complete | Managed, HLSL, CMPT, Unity, web, tool, docs, tests, and package authority moved; CultMath owners deleted | | 4. Mine `vg-csg` | Pending | Requires v1 fixture capture and target Rust package seam | | 5. CultCache/CultNet/CultMesh integration | Pending | Requires current schemas and runtime packages | | 6. Consumer cutover/release | Pending | Requires local candidate feed and downstream passes | @@ -199,11 +199,38 @@ a broader stage gate. the v2 boundary; signed zero, a chosen NaN payload, and infinity are pinned across MessagePack so this cannot quietly diverge again. +### Stage 3 receipts + +- Thirteen planetary/erosion C# sources and thirteen xUnit suites now live + under GameCult.Geometry; `CultMath.rect`, its factories, and all original + planetary sources/tests are deleted. Destination planetary tests pass 41/41; + remaining CultMath tests pass 28/28 for both target frameworks. +- Geometry owns five HLSL files behind `GameCult.Geometry.hlsl`; public geometry + symbols use `gamecult_geometry_*`. CultMath's umbrella and NuGet candidate + contain only numeric `CultMath.hlsl`. A DXC SPIR-V smoke compiled the joined + umbrella successfully to a 1,428-byte module. +- The CMPT v1 tool and TypeScript decoder moved intact. The end-to-end fixture + is exactly 1,221 bytes with SHA-256 + `8b2bc46e4123b8ac8936b43f8d08a34e3f2e74f38d0bb3f101cf3728cd201962`; + the C# emitter and TypeScript decoder pass together. +- Unity adapters retain their original `.meta` GUIDs; the Planetary Viewer uses + the Geometry umbrella and owned shader symbols. The staged UPM artifact has + one owned DLL, both adapters, the sample, all five shaders, and explicit + MIT/MPL license and provenance documents. +- Stale candidate cache was made impossible by rotating CultMath and Geometry + to `0.1.0-geometry-migration.2`. CultMath's candidate contains only its DLLs, + README, and numeric shader. Geometry's candidate declares the exact CultMath + `.2` dependency and contains all Geometry shaders/docs/notices under a + mixed-license file declaration rather than the inherited blanket MIT claim. +- Full Geometry tests pass 27/27 after the joined shader/Unity integration; + planetary tests pass 41/41. Negative searches find obsolete CultMath geometry + names only inside tests that assert their absence or ignored generated output. + ## Next Actions -1. Establish the Geometry-owned planetary parity harness and move the 13 C# - source/test files while deleting the matching CultMath owners and `rect`. -2. Transfer and rename planetary/erosion HLSL ownership, then remove the - implicit geometry includes and bodies from `CultMath.hlsl`. -3. Transfer the CMPT tool/web decoder, Unity adapters/sample, docs, and license - notices; inspect both packages and run the complete negative gate. +1. Mine convex splitting, brush/CSG tree, domain lowering, dirty-frontier, + selected-cut, and mesh assembly into `gamecult-geometry-rs` in dependency + order, preserving the pinned v1 evidence while emitting v2. +2. Remove `bevy_math` from the public Rust boundary and port earned correctness + and performance fixtures before deleting VibeGeometry build authority. +3. Connect the completed Rust runtime to the v2 CultCache/CultNet/CultMesh path. diff --git a/package.json b/package.json index f1b995a2..a6803b6b 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "workspaces": [ "packages/cultcache-ts", "packages/cultnet-ts", - "packages/cultmesh-ts" + "packages/cultmesh-ts", + "packages/gamecult-geometry-ts" ], "scripts": { "build:ts": "npm --workspaces run build", diff --git a/packages/gamecult-geometry-ts/package.json b/packages/gamecult-geometry-ts/package.json new file mode 100644 index 00000000..ea7f8a32 --- /dev/null +++ b/packages/gamecult-geometry-ts/package.json @@ -0,0 +1,10 @@ +{ + "name": "@gamecult/geometry", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "build": "node --no-warnings --experimental-strip-types --check src/planetary-tile.ts", + "test": "node --no-warnings --experimental-strip-types test/planetary-tile.test.mjs" + } +} diff --git a/packages/gamecult-geometry-ts/src/planetary-tile.ts b/packages/gamecult-geometry-ts/src/planetary-tile.ts new file mode 100644 index 00000000..82849c82 --- /dev/null +++ b/packages/gamecult-geometry-ts/src/planetary-tile.ts @@ -0,0 +1,47 @@ +export const GAMECULT_GEOMETRY_PLANETARY_TILE_VERSION = 1; + +export interface PlanetaryTileHeader { + fieldVersion: bigint; projectionVersion: number; layerId: number; projectionKind: number; + centerLongitude: number; centerLatitude: number; projectionScale: number; + level: number; x: number; y: number; interiorSize: number; borderSize: number; + footprintMeters: number; maximumUnresolvedHeight: number; +} +export interface PlanetaryTileSample { + direction: readonly [number, number, number]; radius: number; radialDisplacement: number; + tangentGradient: readonly [number, number, number]; surfaceNormal: readonly [number, number, number]; + slope: number; ridge: number; gully: number; finestResolvedWavelength: number; unresolvedHeightBound: number; +} +export interface PlanetarySurfaceTile { header: PlanetaryTileHeader; storageSize: number; samples: readonly (PlanetaryTileSample | null)[]; } + +export function decodePlanetarySurfaceTile(bytes: ArrayBuffer): PlanetarySurfaceTile { + const view = new DataView(bytes); let offset = 0; + const u8 = () => view.getUint8(offset++); + const u32 = () => { const value = view.getUint32(offset, true); offset += 4; return value; }; + const i32 = () => { const value = view.getInt32(offset, true); offset += 4; return value; }; + const f32 = () => { const value = view.getFloat32(offset, true); offset += 4; return value; }; + const f64 = () => { const value = view.getFloat64(offset, true); offset += 8; return value; }; + const u64 = () => { const value = view.getBigUint64(offset, true); offset += 8; return value; }; + const vector3 = (): [number, number, number] => [f32(), f32(), f32()]; + const requireRemaining = (count: number) => { if (offset + count > view.byteLength) throw new Error("Truncated GameCult.Geometry planetary tile"); }; + requireRemaining(8); + if (String.fromCharCode(u8(), u8(), u8(), u8()) !== "CMPT") throw new Error("Not a GameCult.Geometry planetary tile"); + const version = u32(); + if (version !== GAMECULT_GEOMETRY_PLANETARY_TILE_VERSION) throw new Error(`Unsupported GameCult.Geometry planetary tile version ${version}`); + requireRemaining(76); + const header: PlanetaryTileHeader = { + fieldVersion: u64(), projectionVersion: u32(), layerId: u32(), projectionKind: i32(), + centerLongitude: f64(), centerLatitude: f64(), projectionScale: f64(), + level: i32(), x: i32(), y: i32(), interiorSize: i32(), borderSize: i32(), + footprintMeters: f32(), maximumUnresolvedHeight: f32(), + }; + const count = i32(); const storageSize = header.interiorSize + header.borderSize * 2; + if (count !== storageSize * storageSize) throw new Error("GameCult.Geometry planetary tile sample count does not match layout"); + const samples: (PlanetaryTileSample | null)[] = new Array(count); + for (let index = 0; index < count; index++) { + requireRemaining(1); if (u8() === 0) { samples[index] = null; continue; } + requireRemaining(64); + samples[index] = { direction: vector3(), radius: f32(), radialDisplacement: f32(), tangentGradient: vector3(), surfaceNormal: vector3(), slope: f32(), ridge: f32(), gully: f32(), finestResolvedWavelength: f32(), unresolvedHeightBound: f32() }; + } + if (offset !== view.byteLength) throw new Error("GameCult.Geometry planetary tile has trailing bytes"); + return { header, storageSize, samples }; +} diff --git a/packages/gamecult-geometry-ts/test/planetary-tile.cross-runtime.test.mjs b/packages/gamecult-geometry-ts/test/planetary-tile.cross-runtime.test.mjs new file mode 100644 index 00000000..04243ce8 --- /dev/null +++ b/packages/gamecult-geometry-ts/test/planetary-tile.cross-runtime.test.mjs @@ -0,0 +1,16 @@ +import assert from "node:assert/strict"; +import { createHash } from "node:crypto"; +import { readFile } from "node:fs/promises"; +import { decodePlanetarySurfaceTile } from "../src/planetary-tile.ts"; +if (process.argv.length !== 3) throw new Error("Expected a generated CMPT fixture path"); +const bytes = await readFile(process.argv[2]); +assert.equal(bytes.length, 1221); +assert.equal(createHash("sha256").update(bytes).digest("hex"), "8b2bc46e4123b8ac8936b43f8d08a34e3f2e74f38d0bb3f101cf3728cd201962"); +const tile = decodePlanetarySurfaceTile(bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength)); +assert.equal(tile.header.projectionVersion, 3); assert.equal(tile.header.layerId, 29); +assert.equal(tile.header.projectionKind, 2); assert.equal(tile.header.interiorSize, 5); +assert.equal(tile.header.borderSize, 1); assert.equal(tile.storageSize, 7); assert.equal(tile.samples.length, 49); +assert.ok(tile.samples.some(sample => sample !== null)); +for (const sample of tile.samples) if (sample !== null) { + assert.ok(Number.isFinite(sample.radialDisplacement)); assert.ok(Number.isFinite(sample.unresolvedHeightBound)); +} diff --git a/packages/gamecult-geometry-ts/test/planetary-tile.test.mjs b/packages/gamecult-geometry-ts/test/planetary-tile.test.mjs new file mode 100644 index 00000000..c5c27027 --- /dev/null +++ b/packages/gamecult-geometry-ts/test/planetary-tile.test.mjs @@ -0,0 +1,24 @@ +import assert from "node:assert/strict"; +import { decodePlanetarySurfaceTile } from "../src/planetary-tile.ts"; +const bytes = new ArrayBuffer(152); const view = new DataView(bytes); let offset = 0; +const u8 = value => view.setUint8(offset++, value); +const u32 = value => { view.setUint32(offset, value, true); offset += 4; }; +const i32 = value => { view.setInt32(offset, value, true); offset += 4; }; +const u64 = value => { view.setBigUint64(offset, value, true); offset += 8; }; +const f32 = value => { view.setFloat32(offset, value, true); offset += 4; }; +const f64 = value => { view.setFloat64(offset, value, true); offset += 8; }; +for (const character of "CMPT") u8(character.charCodeAt(0)); +u32(1); u64(0x1234n); u32(2); u32(17); i32(0); f64(0); f64(0); f64(1); +i32(0); i32(0); i32(0); i32(2); i32(0); f32(10); f32(0.5); i32(4); u8(1); +for (const value of [1, 0, 0]) f32(value); f32(8.4); f32(0.25); +for (const value of [0, 0.1, 0]) f32(value); +for (const value of [0.99, -0.1, 0]) f32(value); +for (const value of [0.1, 0.8, 0.2, 2.5, 0.05]) f32(value); +u8(0); u8(0); u8(0); assert.equal(offset, bytes.byteLength); +const tile = decodePlanetarySurfaceTile(bytes); +assert.equal(tile.header.fieldVersion, 0x1234n); assert.equal(tile.header.layerId, 17); +assert.equal(tile.storageSize, 2); assert.equal(tile.samples.length, 4); +assert.equal(tile.samples[0]?.radialDisplacement, 0.25); assert.equal(tile.samples[1], null); +assert.throws(() => decodePlanetarySurfaceTile(bytes.slice(0, -1)), /Truncated/); +const trailing = new Uint8Array(bytes.byteLength + 1); trailing.set(new Uint8Array(bytes)); +assert.throws(() => decodePlanetarySurfaceTile(trailing.buffer), /trailing/); diff --git a/scripts/build-geometry-unity-package.ps1 b/scripts/build-geometry-unity-package.ps1 index c5665b1e..8c1b8b1f 100644 --- a/scripts/build-geometry-unity-package.ps1 +++ b/scripts/build-geometry-unity-package.ps1 @@ -22,7 +22,7 @@ $candidateFeed = if ([System.IO.Path]::IsPathRooted($CultMathCandidateFeed)) { } $pluginRoot = Join-Path $outputRoot "Runtime\Plugins" -if (-not (Test-Path -LiteralPath (Join-Path $candidateFeed "CultMath.0.1.0-geometry-migration.1.nupkg"))) { +if (-not (Test-Path -LiteralPath (Join-Path $candidateFeed "CultMath.0.1.0-geometry-migration.2.nupkg"))) { throw "CultMath migration candidate is missing from $candidateFeed. Pack CultMath before staging Geometry." } @@ -47,6 +47,18 @@ New-Item -ItemType Directory -Force -Path $pluginRoot | Out-Null Copy-Item -LiteralPath (Join-Path $templateRoot "package.json") -Destination $outputRoot Copy-Item -LiteralPath (Join-Path $templateRoot "README.md") -Destination $outputRoot Copy-Item -LiteralPath (Join-Path $templateRoot "Runtime\GameCult.Geometry.asmdef") -Destination (Join-Path $outputRoot "Runtime") +Copy-Item -LiteralPath (Join-Path $templateRoot "Runtime\GameCult.Geometry.Unity.asmdef") -Destination (Join-Path $outputRoot "Runtime") +Copy-Item -LiteralPath (Join-Path $templateRoot "Runtime\PlanetaryPatchMeshAdapter.cs") -Destination (Join-Path $outputRoot "Runtime") +Copy-Item -LiteralPath (Join-Path $templateRoot "Runtime\PlanetaryPatchMeshAdapter.cs.meta") -Destination (Join-Path $outputRoot "Runtime") +Copy-Item -LiteralPath (Join-Path $templateRoot "Runtime\PlanetaryPageUpload.cs") -Destination (Join-Path $outputRoot "Runtime") +Copy-Item -LiteralPath (Join-Path $templateRoot "Runtime\PlanetaryPageUpload.cs.meta") -Destination (Join-Path $outputRoot "Runtime") +Copy-Item -LiteralPath (Join-Path $templateRoot "Samples~") -Destination $outputRoot -Recurse +$shaderOutputRoot = Join-Path $outputRoot "Shaders" +New-Item -ItemType Directory -Force -Path $shaderOutputRoot | Out-Null +Copy-Item -Path (Join-Path $repoRoot "src\GameCult.Geometry\Shaders\*.hlsl") -Destination $shaderOutputRoot +Copy-Item -Path (Join-Path $repoRoot "src\GameCult.Geometry\Shaders\*.hlsl.meta") -Destination $shaderOutputRoot -ErrorAction SilentlyContinue +Copy-Item -LiteralPath (Join-Path $repoRoot "src\GameCult.Geometry\LICENSES.md") -Destination $outputRoot +Copy-Item -LiteralPath (Join-Path $repoRoot "src\GameCult.Geometry\THIRD-PARTY-NOTICES.md") -Destination $outputRoot $geometryAssembly = Join-Path $publishRoot "GameCult.Geometry.dll" if (-not (Test-Path -LiteralPath $geometryAssembly)) { diff --git a/scripts/test-geometry-planetary-tile.ps1 b/scripts/test-geometry-planetary-tile.ps1 new file mode 100644 index 00000000..59cc859b --- /dev/null +++ b/scripts/test-geometry-planetary-tile.ps1 @@ -0,0 +1,9 @@ +$ErrorActionPreference = "Stop" +$root = Split-Path -Parent $PSScriptRoot +$fixture = Join-Path $root ".tools\planetary-tile\fixture.cmpt" +dotnet run --project (Join-Path $root "tools\GameCult.Geometry.PlanetaryTileFixture\GameCult.Geometry.PlanetaryTileFixture.csproj") -- $fixture +if ($LASTEXITCODE -ne 0) { throw "Planetary tile fixture generation failed." } +node --no-warnings --experimental-strip-types (Join-Path $root "packages\gamecult-geometry-ts\test\planetary-tile.cross-runtime.test.mjs") $fixture +if ($LASTEXITCODE -ne 0) { throw "Planetary tile web decoding failed." } +node --no-warnings --experimental-strip-types (Join-Path $root "packages\gamecult-geometry-ts\test\planetary-tile.test.mjs") +if ($LASTEXITCODE -ne 0) { throw "Planetary tile decoder unit test failed." } diff --git a/src/GameCult.Geometry/GameCult.Geometry.csproj b/src/GameCult.Geometry/GameCult.Geometry.csproj index 22c991ab..32d72d0a 100644 --- a/src/GameCult.Geometry/GameCult.Geometry.csproj +++ b/src/GameCult.Geometry/GameCult.Geometry.csproj @@ -1,13 +1,13 @@ - Typed CultCache geometry domain and chunk artifact documents for VibeGeometry and Fensalir + Spatial values, planetary geometry, queries, and typed geometry state built on CultMath primitives GameCult.Geometry - game;geometry;csg;lod;cultcache;cultmesh;vibegeometry;fensalir + game;geometry;planetary;csg;lod;cultcache;cultmesh README.md + + LICENSES.md $(NoWarn);1591 - 0.1.0-geometry-migration.1 - $(MSBuildThisFileDirectory)..\..\..\CultMath\.tools\local-feed - $(RestoreAdditionalProjectSources);$(CultMathCandidateFeed) + 0.1.0-geometry-migration.2 @@ -20,5 +20,9 @@ + + + + diff --git a/src/GameCult.Geometry/IsExternalInit.cs b/src/GameCult.Geometry/IsExternalInit.cs new file mode 100644 index 00000000..b33e9e1d --- /dev/null +++ b/src/GameCult.Geometry/IsExternalInit.cs @@ -0,0 +1,7 @@ +#if NETSTANDARD2_1 +namespace System.Runtime.CompilerServices; + +internal static class IsExternalInit +{ +} +#endif diff --git a/src/GameCult.Geometry/LICENSES.md b/src/GameCult.Geometry/LICENSES.md new file mode 100644 index 00000000..67455b87 --- /dev/null +++ b/src/GameCult.Geometry/LICENSES.md @@ -0,0 +1,13 @@ +# GameCult.Geometry licenses + +GameCult.Geometry is a mixed-license package. License follows file ownership; +the package as a whole is not relicensed under one blanket expression. + +- CultLib-authored integration, persistence, schema, and packaging files are + licensed under the MIT License published by the CultLib repository. +- Files under `Planetary/` and `Shaders/` transferred from CultMath remain + licensed under the Mozilla Public License 2.0. Their source notices and + provenance are preserved in `THIRD-PARTY-NOTICES.md`. + +Downstream redistributors must preserve the applicable notices for the files +they redistribute. diff --git a/src/GameCult.Geometry/Planetary/AdvancedErosionFilter.cs b/src/GameCult.Geometry/Planetary/AdvancedErosionFilter.cs new file mode 100644 index 00000000..487cdc87 --- /dev/null +++ b/src/GameCult.Geometry/Planetary/AdvancedErosionFilter.cs @@ -0,0 +1,141 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. +// +// Mathematical procedure adapted from Rune Skovbo Johansen's Advanced Terrain +// Erosion Filter (2025): https://www.shadertoy.com/view/wXcfWn + +using CultMath; + +namespace GameCult.Geometry; + +public readonly record struct AdvancedErosionParameters( + float Scale, + float Strength, + float GullyWeight, + float Detail, + float4 Rounding, + float4 Onset, + float2 AssumedSlope, + float CellScale, + float Normalization, + int Octaves, + float Lacunarity, + float Gain) +{ + public static AdvancedErosionParameters Default => new( + 0.15f, 0.22f, 0.5f, 1.5f, + new float4(0.1f, 0.0f, 0.1f, 2.0f), + new float4(1.25f, 1.25f, 2.8f, 1.5f), + new float2(0.7f, 1.0f), + 0.7f, 0.5f, 5, 2.0f, 0.5f); +} + +public readonly record struct AdvancedErosionResult(float3 Delta, float Magnitude, float RidgeMap, float FadeTarget); + +public static class AdvancedErosionFilter +{ + public static AdvancedErosionResult Sample(float2 position, float3 baseHeightAndSlope, float fadeTarget, AdvancedErosionParameters p) + => Sample(position, baseHeightAndSlope, fadeTarget, p, new ErosionBandSelection(p.Octaves, 1.0f, 0.0f, 0.0f)); + + public static AdvancedErosionResult Sample(float2 position, float3 baseHeightAndSlope, float fadeTarget, AdvancedErosionParameters p, ErosionBandSelection band) + { + var strength = p.Strength * p.Scale; + fadeTarget = math.clamp(fadeTarget, -1.0f, 1.0f); + var input = baseHeightAndSlope; + var heightAndSlope = input; + var frequency = 1.0f / math.max(p.Scale * p.CellScale, 1.0e-10f); + var slope = new float2(heightAndSlope.y, heightAndSlope.z); + var slopeLength = math.max(math.length(slope), 1.0e-10f); + var magnitude = 0.0f; + var roundingMultiplier = 1.0f; + + var inputRounding = math.lerp(p.Rounding.y, p.Rounding.x, math.saturate(fadeTarget + 0.5f)) * p.Rounding.z; + var combinedMask = EaseOut(SmoothStart(slopeLength * p.Onset.x, inputRounding * p.Onset.x)); + var ridgeMask = EaseOut(slopeLength * p.Onset.z); + var ridgeFade = fadeTarget; + var gullySlope = math.lerp(slope, slope / slopeLength * p.AssumedSlope.x, p.AssumedSlope.y); + + var octaves = math.min(math.min(math.max(p.Octaves, 0), 8), math.max(band.ActiveOctaves, 0)); + for (var octave = 0; octave < octaves; octave++) + { + var phacelle = Phacelle(position * frequency, SafeNormalize(gullySlope), p.CellScale, 0.25f, p.Normalization); + var derivativeDirection = new float2(phacelle.z, phacelle.w) * -frequency; + var sloping = math.abs(phacelle.y); + gullySlope += math.sign(phacelle.y) * derivativeDirection * strength * p.GullyWeight; + + var gullies = new float3(phacelle.x, phacelle.y * derivativeDirection.x, phacelle.y * derivativeDirection.y); + var faded = math.lerp(new float3(fadeTarget, 0.0f, 0.0f), gullies * p.GullyWeight, combinedMask); + var octaveWeight = octave == octaves - 1 ? math.saturate(band.FinalOctaveWeight) : 1.0f; + heightAndSlope += faded * strength * octaveWeight; + magnitude += strength * octaveWeight; + fadeTarget = faded.x; + + var octaveRounding = math.lerp(p.Rounding.y, p.Rounding.x, math.saturate(phacelle.x + 0.5f)) * roundingMultiplier; + var newMask = EaseOut(SmoothStart(sloping * p.Onset.y, octaveRounding * p.Onset.y)); + combinedMask = PowInverse(combinedMask, p.Detail) * newMask; + + ridgeFade = math.lerp(ridgeFade, math.lerp(ridgeFade, gullies.x, ridgeMask), octaveWeight); + ridgeMask *= math.lerp(1.0f, EaseOut(sloping * p.Onset.w), octaveWeight); + strength *= p.Gain; + frequency *= p.Lacunarity; + roundingMultiplier *= p.Rounding.w; + } + + return new AdvancedErosionResult(heightAndSlope - input, magnitude, ridgeFade * (1.0f - ridgeMask), fadeTarget); + } + + public static float4 Phacelle(float2 position, float2 normalDirection, float frequency, float offsetCycles, float normalization) + { + var sideDirection = new float2(-normalDirection.y, normalDirection.x) * frequency * math.TAU; + var offset = offsetCycles * math.TAU; + var cell = math.floor(position); + var local = math.frac(position); + var phase = float2.zero; + var weightSum = 0.0f; + + for (var x = -1; x <= 2; x++) + for (var y = -1; y <= 2; y++) + { + var gridOffset = new float2(x, y); + var gridPoint = cell + gridOffset; + var randomOffset = Hash2(gridPoint) * 0.5f; + var delta = local - gridOffset - randomOffset; + var weight = math.max(0.0f, math.exp(-math.dot(delta, delta) * 2.0f) - 0.01111f); + weightSum += weight; + var wave = math.dot(delta, sideDirection) + offset; + phase += new float2(math.cos(wave), math.sin(wave)) * weight; + } + + var interpolated = phase / math.max(weightSum, 1.0e-20f); + var magnitude = math.max(1.0f - math.saturate(normalization), math.length(interpolated)); + var normalized = interpolated / math.max(magnitude, 1.0e-20f); + return new float4(normalized, sideDirection.x, sideDirection.y); + } + + private static float2 Hash2(float2 input) + { + var x = (int)input.x; + var y = (int)input.y; + return new float2(HashUnit(x, y, 0x68bc21ebu), HashUnit(x, y, 0x02e5be93u)) * 2.0f - float2.one; + } + + private static float HashUnit(int x, int y, uint salt) + { + var value = unchecked((uint)x * 0x8da6b343u ^ (uint)y * 0xd8163841u ^ salt); + value ^= value >> 16; value *= 0x7feb352du; value ^= value >> 15; value *= 0x846ca68bu; value ^= value >> 16; + return (value & 0x00ffffffu) * (1.0f / 16777216.0f); + } + + private static float2 SafeNormalize(float2 value) + { + var length = math.length(value); + return math.abs(length) > 1.0e-10f ? value / length : value; + } + + private static float PowInverse(float value, float power) => 1.0f - math.pow(1.0f - math.saturate(value), power); + private static float EaseOut(float value) { var inverse = 1.0f - math.saturate(value); return 1.0f - inverse * inverse; } + private static float SmoothStart(float value, float smoothing) => smoothing <= 1.0e-10f || value >= smoothing + ? value - 0.5f * smoothing + : 0.5f * value * value / smoothing; +} diff --git a/src/GameCult.Geometry/Planetary/ErosionFrequencyBands.cs b/src/GameCult.Geometry/Planetary/ErosionFrequencyBands.cs new file mode 100644 index 00000000..8cadbf11 --- /dev/null +++ b/src/GameCult.Geometry/Planetary/ErosionFrequencyBands.cs @@ -0,0 +1,63 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +using CultMath; + +namespace GameCult.Geometry; + +public readonly record struct ErosionBandSelection( + int ActiveOctaves, + float FinalOctaveWeight, + float FinestIncludedWavelength, + float UnresolvedHeightBound) +{ + public bool HasSamples => ActiveOctaves > 0; +} + +public static class ErosionFrequencyBands +{ + public static ErosionBandSelection Select( + float baseWavelength, + float sampleSpacing, + int maximumOctaves, + float lacunarity, + float baseAmplitude, + float gain, + float transitionRatio = 2.0f) + { + baseWavelength = math.max(baseWavelength, 1.0e-6f); + sampleSpacing = math.max(sampleSpacing, 0.0f); + lacunarity = math.max(lacunarity, 1.01f); + transitionRatio = math.max(transitionRatio, 1.01f); + maximumOctaves = math.min(math.max(maximumOctaves, 0), 16); + var nyquistWavelength = sampleSpacing * 2.0f; + var wavelength = baseWavelength; + var active = 0; + var finalWeight = 0.0f; + var finest = 0.0f; + + for (var octave = 0; octave < maximumOctaves; octave++) + { + var weight = nyquistWavelength <= 0.0f + ? 1.0f + : math.smoothstep(nyquistWavelength, nyquistWavelength * transitionRatio, wavelength); + if (weight <= 0.0f) break; + active++; + finalWeight = weight; + finest = wavelength; + wavelength /= lacunarity; + } + + var omittedAmplitude = 0.0f; + var amplitude = math.abs(baseAmplitude); + for (var octave = 0; octave < maximumOctaves; octave++) + { + if (octave >= active) omittedAmplitude += amplitude; + else if (octave == active - 1) omittedAmplitude += amplitude * (1.0f - finalWeight); + amplitude *= math.abs(gain); + } + + return new ErosionBandSelection(active, active > 0 ? finalWeight : 0.0f, finest, omittedAmplitude); + } +} diff --git a/src/GameCult.Geometry/Planetary/PlanetaryField.cs b/src/GameCult.Geometry/Planetary/PlanetaryField.cs new file mode 100644 index 00000000..21f4f805 --- /dev/null +++ b/src/GameCult.Geometry/Planetary/PlanetaryField.cs @@ -0,0 +1,220 @@ +using System; +using CultMath; + +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +namespace GameCult.Geometry; + +public readonly record struct PlanetaryQueryScale(float FootprintMeters, float MaximumUnresolvedHeight) +{ + public static PlanetaryQueryScale AtFootprint(float footprintMeters, float maximumUnresolvedHeight = float.PositiveInfinity) + => new PlanetaryQueryScale(footprintMeters, maximumUnresolvedHeight).Validate(); + + public PlanetaryQueryScale Validate() + { + if (!float.IsFinite(FootprintMeters) || FootprintMeters < 0) throw new ArgumentOutOfRangeException(nameof(FootprintMeters)); + if (float.IsNaN(MaximumUnresolvedHeight) || MaximumUnresolvedHeight < 0) throw new ArgumentOutOfRangeException(nameof(MaximumUnresolvedHeight)); + return this; + } +} + +public readonly record struct PlanetaryFieldDefinition( + ulong FieldVersion, + float Radius, + int Seed, + AdvancedErosionParameters Erosion) +{ + public static PlanetaryFieldDefinition Create( + ulong baseFieldVersion, + float radius, + int seed, + AdvancedErosionParameters erosion) + => new PlanetaryFieldDefinition(PlanetaryFieldIdentity.Compute(baseFieldVersion, radius, seed, erosion), radius, seed, erosion).Validate(); + + public PlanetaryFieldDefinition Validate() + { + if (FieldVersion == 0) throw new ArgumentOutOfRangeException(nameof(FieldVersion)); + if (!float.IsFinite(Radius) || Radius <= 0) throw new ArgumentOutOfRangeException(nameof(Radius)); + if (!float.IsFinite(Erosion.Scale) || Erosion.Scale <= 0) throw new ArgumentOutOfRangeException(nameof(Erosion)); + return this; + } +} + +public static class PlanetaryFieldIdentity +{ + public static ulong Compute(ulong baseFieldVersion, float radius, int seed, in AdvancedErosionParameters erosion) + { + if (baseFieldVersion == 0) throw new ArgumentOutOfRangeException(nameof(baseFieldVersion)); + const ulong offset = 14695981039346656037UL; + const ulong prime = 1099511628211UL; + var hash = offset; + Add(baseFieldVersion); + Add((uint)BitConverter.SingleToInt32Bits(radius)); Add((uint)seed); + Add((uint)BitConverter.SingleToInt32Bits(erosion.Scale)); Add((uint)BitConverter.SingleToInt32Bits(erosion.Strength)); + Add((uint)BitConverter.SingleToInt32Bits(erosion.GullyWeight)); Add((uint)BitConverter.SingleToInt32Bits(erosion.Detail)); + AddFloat4(erosion.Rounding); AddFloat4(erosion.Onset); + Add((uint)BitConverter.SingleToInt32Bits(erosion.AssumedSlope.x)); Add((uint)BitConverter.SingleToInt32Bits(erosion.AssumedSlope.y)); + Add((uint)BitConverter.SingleToInt32Bits(erosion.CellScale)); Add((uint)BitConverter.SingleToInt32Bits(erosion.Normalization)); + Add((uint)erosion.Octaves); Add((uint)BitConverter.SingleToInt32Bits(erosion.Lacunarity)); Add((uint)BitConverter.SingleToInt32Bits(erosion.Gain)); + return hash == 0 ? 1 : hash; + + void Add(ulong value) => hash = unchecked((hash ^ value) * prime); + void AddFloat4(float4 value) + { + Add((uint)BitConverter.SingleToInt32Bits(value.x)); Add((uint)BitConverter.SingleToInt32Bits(value.y)); + Add((uint)BitConverter.SingleToInt32Bits(value.z)); Add((uint)BitConverter.SingleToInt32Bits(value.w)); + } + } +} + +/// +/// Application-supplied base evidence at one unit spherical direction. +/// FieldValue and FieldGradient drive erosion. RadialDisplacement and +/// RadialGradient describe the uneroded surface in metres. +/// +public readonly record struct PlanetaryBaseFieldSample( + float RadialDisplacement, + float3 RadialGradient, + float FieldValue, + float3 FieldGradient, + float FadeTarget); + +public readonly record struct PlanetarySurfaceSample( + ulong FieldVersion, + float3 UnitDirection, + float Radius, + float RadialDisplacement, + float3 TangentGradient, + float3 SurfaceNormal, + float Slope, + float Ridge, + float Gully, + float FinestResolvedWavelength, + float UnresolvedHeightBound) +{ + public float SurfaceRadius => Radius + RadialDisplacement; + public float3 PlanetLocalPosition => UnitDirection * SurfaceRadius; + public bool Meets(PlanetaryQueryScale scale) => UnresolvedHeightBound <= scale.MaximumUnresolvedHeight; +} + +public static class PlanetaryField +{ + public static PlanetarySurfaceSample Sample( + in PlanetaryFieldDefinition definition, + float3 unitDirection, + in PlanetaryBaseFieldSample baseSample, + in PlanetaryQueryScale scale) + { + definition.Validate(); + scale.Validate(); + PlanetaryTopology.ValidateDirection(unitDirection); + PlanetaryTopology.ValidateFinite(baseSample.RadialGradient, nameof(baseSample)); + PlanetaryTopology.ValidateFinite(baseSample.FieldGradient, nameof(baseSample)); + if (!float.IsFinite(baseSample.RadialDisplacement) || !float.IsFinite(baseSample.FieldValue) || !float.IsFinite(baseSample.FadeTarget)) + throw new ArgumentOutOfRangeException(nameof(baseSample)); + + var direction = math.normalize(unitDirection); + var radialGradient = Tangent(direction, baseSample.RadialGradient); + var fieldGradient = Tangent(direction, baseSample.FieldGradient); + var p = definition.Erosion; + var band = ErosionFrequencyBands.Select( + p.Scale * p.CellScale, + scale.FootprintMeters, + p.Octaves, + p.Lacunarity, + p.Strength * p.Scale, + p.Gain); + + var powers = new float3( + Pow4(MathF.Abs(direction.x)), + Pow4(MathF.Abs(direction.y)), + Pow4(MathF.Abs(direction.z))); + var powerSum = math.max(powers.x + powers.y + powers.z, 1.0e-6f); + var weights = powers / powerSum; + var world = direction * definition.Radius; + var seed = definition.Seed; + var xy = AdvancedErosionFilter.Sample( + world.xy + new float2(713 + seed * 0.754877666f, -291 + seed * 0.569840296f), + new float3(baseSample.FieldValue, fieldGradient.x, fieldGradient.y), baseSample.FadeTarget, p, band); + var yz = AdvancedErosionFilter.Sample( + world.yz + new float2(-431 + seed * 0.438289027f, 887 + seed * 0.328438163f), + new float3(baseSample.FieldValue, fieldGradient.y, fieldGradient.z), baseSample.FadeTarget, p, band); + var zx = AdvancedErosionFilter.Sample( + new float2(world.z, world.x) + new float2(197 + seed * 0.219783071f, 557 + seed * 0.145898034f), + new float3(baseSample.FieldValue, fieldGradient.z, fieldGradient.x), baseSample.FadeTarget, p, band); + + var erosionHeight = xy.Delta.x * weights.z + yz.Delta.x * weights.x + zx.Delta.x * weights.y; + var erosionGradient = new float3( + xy.Delta.y * weights.z + zx.Delta.z * weights.y, + xy.Delta.z * weights.z + yz.Delta.y * weights.x, + yz.Delta.z * weights.x + zx.Delta.y * weights.y); + var powerGradientX = Tangent(direction, new float3(4 * direction.x * direction.x * direction.x / definition.Radius, 0, 0)); + var powerGradientY = Tangent(direction, new float3(0, 4 * direction.y * direction.y * direction.y / definition.Radius, 0)); + var powerGradientZ = Tangent(direction, new float3(0, 0, 4 * direction.z * direction.z * direction.z / definition.Radius)); + var sumGradient = powerGradientX + powerGradientY + powerGradientZ; + var weightGradientX = (powerGradientX * powerSum - sumGradient * powers.x) / (powerSum * powerSum); + var weightGradientY = (powerGradientY * powerSum - sumGradient * powers.y) / (powerSum * powerSum); + var weightGradientZ = (powerGradientZ * powerSum - sumGradient * powers.z) / (powerSum * powerSum); + erosionGradient += yz.Delta.x * weightGradientX + zx.Delta.x * weightGradientY + xy.Delta.x * weightGradientZ; + var gradient = Tangent(direction, radialGradient + erosionGradient); + var ridgeEvidence = xy.RidgeMap * weights.z + yz.RidgeMap * weights.x + zx.RidgeMap * weights.y; + var ridge = math.saturate(ridgeEvidence * 0.5f + 0.5f); + var gully = math.saturate(0.5f - ridgeEvidence * 0.5f); + var displacement = baseSample.RadialDisplacement + erosionHeight; + + return new( + definition.FieldVersion, + direction, + definition.Radius, + displacement, + gradient, + PlanetaryTopology.SurfaceNormal(direction, gradient), + math.length(gradient), + ridge, + gully, + band.FinestIncludedWavelength, + band.UnresolvedHeightBound); + } + + public static void SampleBatch( + in PlanetaryFieldDefinition definition, + ReadOnlySpan directions, + in PlanetaryQueryScale scale, + TSource source, + Span destination) + where TSource : IPlanetaryBaseField + { + if (destination.Length < directions.Length) throw new ArgumentException("Destination is shorter than directions.", nameof(destination)); + for (var i = 0; i < directions.Length; i++) + { + var direction = math.normalize(directions[i]); + var baseSample = source.Sample(direction); + destination[i] = Sample(definition, direction, baseSample, scale); + } + } + + public static PlanetarySurfaceSample SamplePosition( + in PlanetaryFieldDefinition definition, + double3 planetLocalPosition, + in PlanetaryQueryScale scale, + TSource source) + where TSource : IPlanetaryBaseField + { + if (!double.IsFinite(planetLocalPosition.x) || !double.IsFinite(planetLocalPosition.y) || !double.IsFinite(planetLocalPosition.z)) + throw new ArgumentOutOfRangeException(nameof(planetLocalPosition)); + var length = Math.Sqrt(planetLocalPosition.x * planetLocalPosition.x + planetLocalPosition.y * planetLocalPosition.y + planetLocalPosition.z * planetLocalPosition.z); + if (length < 1.0e-12) throw new ArgumentOutOfRangeException(nameof(planetLocalPosition)); + var direction = new float3((float)(planetLocalPosition.x / length), (float)(planetLocalPosition.y / length), (float)(planetLocalPosition.z / length)); + return Sample(definition, direction, source.Sample(direction), scale); + } + + private static float3 Tangent(float3 direction, float3 gradient) => gradient - direction * math.dot(gradient, direction); + private static float Pow4(float value) { var square = value * value; return square * square; } +} + +public interface IPlanetaryBaseField +{ + PlanetaryBaseFieldSample Sample(float3 unitDirection); +} diff --git a/src/GameCult.Geometry/Planetary/PlanetaryGpuPages.cs b/src/GameCult.Geometry/Planetary/PlanetaryGpuPages.cs new file mode 100644 index 00000000..a6d7f4df --- /dev/null +++ b/src/GameCult.Geometry/Planetary/PlanetaryGpuPages.cs @@ -0,0 +1,60 @@ +using System; +using CultMath; + +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +namespace GameCult.Geometry; + +public readonly record struct PlanetaryGpuPageInput(float4 DirectionRadius, float4 Sampling); + +public readonly record struct PlanetaryGpuPageMetadata(float4 Address, float4 Layout, float4 Bounds, float4 State); + +public readonly record struct PlanetaryGpuPageContent( + PlanetaryPageLayout Layout, + PlanetaryGpuPageInput[] Inputs, + float SampleSpacing, + float ParentSampleSpacing); + +public static class PlanetaryGpuPageBuilder +{ + public static PlanetaryGpuPageContent BuildContent(PlanetaryPageLayout layout, float radius) + { + layout.Validate(); + if (!float.IsFinite(radius) || radius <= 0) throw new ArgumentOutOfRangeException(nameof(radius)); + var spacing = PlanetaryPageSampling.NominalAngularTexelSize(layout) * radius; + var parentSpacing = layout.Tile.Level == 0 + ? 0 + : PlanetaryPageSampling.NominalAngularTexelSize(new(layout.Tile.Parent(), layout.InteriorSize, layout.BorderSize)) * radius; + var inputs = new PlanetaryGpuPageInput[layout.StorageSize * layout.StorageSize]; + for (var y = 0; y < layout.StorageSize; y++) + for (var x = 0; x < layout.StorageSize; x++) + { + var direction = PlanetaryPageSampling.Direction(layout, x, y); + inputs[y * layout.StorageSize + x] = new( + new float4(direction, radius), + new float4(spacing, parentSpacing, 0, 0)); + } + return new(layout, inputs, spacing, parentSpacing); + } + + public static PlanetaryGpuPageMetadata Metadata( + in PlanetaryGpuPageContent content, + int outputOffset, + float blend, + float4 bounds = default) + { + content.Layout.Validate(); + if (content.Inputs == null || content.Inputs.Length != content.Layout.StorageSize * content.Layout.StorageSize) + throw new ArgumentException("GPU page content does not match its layout.", nameof(content)); + if (outputOffset < 0) throw new ArgumentOutOfRangeException(nameof(outputOffset)); + if (!float.IsFinite(blend) || blend is < 0 or > 1) throw new ArgumentOutOfRangeException(nameof(blend)); + var tile = content.Layout.Tile; + return new( + new float4((int)tile.Face, tile.Level, tile.X, tile.Y), + new float4(outputOffset, content.Layout.StorageSize, content.Layout.InteriorSize, content.Layout.BorderSize), + bounds, + new float4(1, blend, PlanetaryPageSampling.NominalAngularTexelSize(content.Layout), content.SampleSpacing)); + } +} diff --git a/src/GameCult.Geometry/Planetary/PlanetaryMapTileEncoding.cs b/src/GameCult.Geometry/Planetary/PlanetaryMapTileEncoding.cs new file mode 100644 index 00000000..90c93fee --- /dev/null +++ b/src/GameCult.Geometry/Planetary/PlanetaryMapTileEncoding.cs @@ -0,0 +1,122 @@ +using System; +using System.IO; +using System.Text; +using CultMath; + +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +namespace GameCult.Geometry; + +public static class PlanetaryMapTileEncoding +{ + public const uint FormatVersion = 1; + private static readonly byte[] Magic = Encoding.ASCII.GetBytes("CMPT"); + + public static void Write(Stream stream, in PlanetarySurfaceMapTile tile, bool leaveOpen = false) + { + if (stream == null || !stream.CanWrite) throw new ArgumentException("A writable stream is required.", nameof(stream)); + tile.Key.Validate(); + if (tile.Samples == null || tile.Validity == null || tile.Samples.Length != tile.Validity.Length) + throw new ArgumentException("Tile samples and validity must have equal lengths.", nameof(tile)); + var expectedCount = tile.Key.Layout.StorageSize * tile.Key.Layout.StorageSize; + if (tile.Samples.Length != expectedCount) throw new ArgumentException("Tile payload does not match its layout.", nameof(tile)); + + using var writer = new BinaryWriter(stream, Encoding.UTF8, leaveOpen); + writer.Write(Magic); + writer.Write(FormatVersion); + writer.Write(tile.Key.FieldVersion); + writer.Write(tile.Key.ProjectionVersion); + writer.Write(tile.Key.LayerId); + var projection = tile.Key.Layout.Projection; + writer.Write((int)projection.Kind); + writer.Write(projection.CenterLongitude); + writer.Write(projection.CenterLatitude); + writer.Write(projection.Scale); + writer.Write(tile.Key.Layout.Level); + writer.Write(tile.Key.Layout.X); + writer.Write(tile.Key.Layout.Y); + writer.Write(tile.Key.Layout.InteriorSize); + writer.Write(tile.Key.Layout.BorderSize); + writer.Write(tile.Key.QueryScale.FootprintMeters); + writer.Write(tile.Key.QueryScale.MaximumUnresolvedHeight); + writer.Write(tile.Samples.Length); + for (var i = 0; i < tile.Samples.Length; i++) + { + writer.Write(tile.Validity[i]); + if (!tile.Validity[i]) continue; + WriteSample(writer, tile.Samples[i], tile.Key.FieldVersion); + } + } + + public static PlanetarySurfaceMapTile Read(Stream stream, bool leaveOpen = false) + { + if (stream == null || !stream.CanRead) throw new ArgumentException("A readable stream is required.", nameof(stream)); + using var reader = new BinaryReader(stream, Encoding.UTF8, leaveOpen); + var magic = reader.ReadBytes(Magic.Length); + if (magic.Length != Magic.Length || !magic.AsSpan().SequenceEqual(Magic)) throw new InvalidDataException("Not a CultMath planetary tile."); + var version = reader.ReadUInt32(); + if (version != FormatVersion) throw new InvalidDataException($"Unsupported planetary tile version {version}."); + var fieldVersion = reader.ReadUInt64(); + var projectionVersion = reader.ReadUInt32(); + var layerId = reader.ReadUInt32(); + var kindValue = reader.ReadInt32(); + if (!Enum.IsDefined(typeof(PlanetaryProjectionKind), kindValue)) throw new InvalidDataException("Unknown planetary projection kind."); + var projection = new PlanetaryProjectionParameters( + (PlanetaryProjectionKind)kindValue, + reader.ReadDouble(), reader.ReadDouble(), reader.ReadDouble()).Validate(); + var layout = new PlanetaryMapTileLayout( + projection, + reader.ReadInt32(), reader.ReadInt32(), reader.ReadInt32(), + reader.ReadInt32(), reader.ReadInt32()).Validate(); + var scale = new PlanetaryQueryScale(reader.ReadSingle(), reader.ReadSingle()).Validate(); + var key = new PlanetaryMapTileKey(fieldVersion, projectionVersion, layerId, layout, scale).Validate(); + var count = reader.ReadInt32(); + if (count != layout.StorageSize * layout.StorageSize) throw new InvalidDataException("Planetary tile sample count does not match layout."); + var samples = new PlanetarySurfaceSample[count]; + var validity = new bool[count]; + for (var i = 0; i < count; i++) + { + validity[i] = reader.ReadBoolean(); + if (validity[i]) samples[i] = ReadSample(reader, fieldVersion); + } + if (stream.CanSeek && stream.Position != stream.Length) throw new InvalidDataException("Planetary tile has trailing bytes."); + return new(key, samples, validity); + } + + private static void WriteSample(BinaryWriter writer, PlanetarySurfaceSample sample, ulong fieldVersion) + { + if (sample.FieldVersion != fieldVersion) throw new ArgumentException("Sample field version does not match tile identity."); + Write(writer, sample.UnitDirection); + writer.Write(sample.Radius); + writer.Write(sample.RadialDisplacement); + Write(writer, sample.TangentGradient); + Write(writer, sample.SurfaceNormal); + writer.Write(sample.Slope); + writer.Write(sample.Ridge); + writer.Write(sample.Gully); + writer.Write(sample.FinestResolvedWavelength); + writer.Write(sample.UnresolvedHeightBound); + } + + private static PlanetarySurfaceSample ReadSample(BinaryReader reader, ulong fieldVersion) + { + var direction = ReadFloat3(reader); + var radius = reader.ReadSingle(); + var displacement = reader.ReadSingle(); + var gradient = ReadFloat3(reader); + var normal = ReadFloat3(reader); + return new( + fieldVersion, direction, radius, displacement, gradient, normal, + reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), + reader.ReadSingle(), reader.ReadSingle()); + } + + private static void Write(BinaryWriter writer, float3 value) + { + writer.Write(value.x); writer.Write(value.y); writer.Write(value.z); + } + + private static float3 ReadFloat3(BinaryReader reader) => new(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); +} diff --git a/src/GameCult.Geometry/Planetary/PlanetaryPages.cs b/src/GameCult.Geometry/Planetary/PlanetaryPages.cs new file mode 100644 index 00000000..919a6320 --- /dev/null +++ b/src/GameCult.Geometry/Planetary/PlanetaryPages.cs @@ -0,0 +1,192 @@ +using System; +using CultMath; + +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +namespace GameCult.Geometry; + +public readonly record struct PlanetaryPageLayout(PlanetaryTileAddress Tile, int InteriorSize, int BorderSize) +{ + public int StorageSize => checked(InteriorSize + BorderSize * 2); + + public PlanetaryPageLayout Validate() + { + if (InteriorSize < 2) throw new ArgumentOutOfRangeException(nameof(InteriorSize)); + if (BorderSize < 0 || BorderSize >= InteriorSize) throw new ArgumentOutOfRangeException(nameof(BorderSize)); + return this; + } +} + +public readonly record struct PlanetaryPageSummary( + float MinimumHeight, + float MaximumHeight, + float MaximumSlope, + float UnresolvedHeightBound, + float AngularTexelSize); + +public readonly record struct PlanetaryPageSample(float Height, float3 TangentGradient, float Ridge, float Gully); + +public static class PlanetaryPageSampling +{ + public static float3 Direction(PlanetaryPageLayout page, int storageX, int storageY) + { + page.Validate(); + if ((uint)storageX >= (uint)page.StorageSize || (uint)storageY >= (uint)page.StorageSize) + throw new ArgumentOutOfRangeException(nameof(storageX)); + var localU = (storageX - page.BorderSize) / (double)(page.InteriorSize - 1); + var localV = (storageY - page.BorderSize) / (double)(page.InteriorSize - 1); + return DirectionAtLocal(page, localU, localV); + } + + public static float3 DirectionAtLocal(PlanetaryPageLayout page, double localU, double localV) + { + page.Validate(); + if (!double.IsFinite(localU) || !double.IsFinite(localV)) throw new ArgumentOutOfRangeException(nameof(localU)); + var count = page.Tile.AxisTileCount; + return PlanetaryTopology.Direction(new( + page.Tile.Face, + -1.0 + 2.0 * (page.Tile.X + localU) / count, + -1.0 + 2.0 * (page.Tile.Y + localV) / count)); + } + + public static float AngularTexelSize(PlanetaryPageLayout page) + { + var center = page.BorderSize + (page.InteriorSize - 1) / 2; + var a = Direction(page, center, center); + var b = Direction(page, Math.Min(center + 1, page.StorageSize - 1), center); + return MathF.Acos(math.clamp(math.dot(a, b), -1.0f, 1.0f)); + } + + public static float NominalAngularTexelSize(PlanetaryPageLayout page) + { + page.Validate(); + return MathF.PI * 0.5f / (page.Tile.AxisTileCount * (page.InteriorSize - 1)); + } + + public static PlanetaryPageSample Bilinear( + ReadOnlySpan samples, + PlanetaryPageLayout page, + float2 local) + { + page.Validate(); + if (samples.Length != page.StorageSize * page.StorageSize) throw new ArgumentException("Page sample count does not match layout.", nameof(samples)); + var texel = local * (page.InteriorSize - 1) + page.BorderSize; + var x0 = Math.Clamp((int)MathF.Floor(texel.x), 0, page.StorageSize - 1); + var y0 = Math.Clamp((int)MathF.Floor(texel.y), 0, page.StorageSize - 1); + var x1 = Math.Min(x0 + 1, page.StorageSize - 1); + var y1 = Math.Min(y0 + 1, page.StorageSize - 1); + var tx = math.frac(texel.x); + var ty = math.frac(texel.y); + var a = Lerp(samples[y0 * page.StorageSize + x0], samples[y0 * page.StorageSize + x1], tx); + var b = Lerp(samples[y1 * page.StorageSize + x0], samples[y1 * page.StorageSize + x1], tx); + return Lerp(a, b, ty); + } + + public static PlanetaryPageSummary Summarize(ReadOnlySpan samples, PlanetaryPageLayout page, float unresolvedHeightBound) + { + page.Validate(); + if (samples.Length != page.StorageSize * page.StorageSize) throw new ArgumentException("Page sample count does not match layout.", nameof(samples)); + var min = float.PositiveInfinity; + var max = float.NegativeInfinity; + var maxSlope = 0.0f; + foreach (var sample in samples) + { + min = MathF.Min(min, sample.Height); + max = MathF.Max(max, sample.Height); + maxSlope = MathF.Max(maxSlope, math.length(sample.TangentGradient)); + } + return new(min, max, maxSlope, MathF.Max(unresolvedHeightBound, 0), AngularTexelSize(page)); + } + + private static PlanetaryPageSample Lerp(PlanetaryPageSample a, PlanetaryPageSample b, float t) => new( + math.lerp(a.Height, b.Height, t), + math.lerp(a.TangentGradient, b.TangentGradient, t), + math.lerp(a.Ridge, b.Ridge, t), + math.lerp(a.Gully, b.Gully, t)); +} + +public readonly record struct PlanetaryBakedPage( + PlanetaryPageLayout Layout, + PlanetaryPageSample[] Samples, + PlanetaryPageSummary Summary); + +public static class PlanetaryPageBaker +{ + public static PlanetaryBakedPage Bake( + in PlanetaryFieldDefinition field, + PlanetaryPageLayout layout, + TSource source) + where TSource : IPlanetaryBaseField + { + layout.Validate(); field.Validate(); + var spacing = PlanetaryPageSampling.NominalAngularTexelSize(layout) * field.Radius; + var parentSpacing = layout.Tile.Level == 0 + ? 0 + : PlanetaryPageSampling.NominalAngularTexelSize(new(layout.Tile.Parent(), layout.InteriorSize, layout.BorderSize)) * field.Radius; + var samples = new PlanetaryPageSample[layout.StorageSize * layout.StorageSize]; + var unresolved = 0.0f; + for (var y = 0; y < layout.StorageSize; y++) + for (var x = 0; x < layout.StorageSize; x++) + { + var direction = PlanetaryPageSampling.Direction(layout, x, y); + var baseSample = source.Sample(direction); + var child = PlanetaryField.Sample(field, direction, baseSample, PlanetaryQueryScale.AtFootprint(spacing)); + var height = child.RadialDisplacement; + var gradient = child.TangentGradient; + if (parentSpacing > 0) + { + var parent = PlanetaryField.Sample(field, direction, baseSample, PlanetaryQueryScale.AtFootprint(parentSpacing)); + height -= parent.RadialDisplacement; + gradient -= parent.TangentGradient; + } + samples[y * layout.StorageSize + x] = new(height, gradient, child.Ridge, child.Gully); + unresolved = MathF.Max(unresolved, child.UnresolvedHeightBound); + } + return new(layout, samples, PlanetaryPageSampling.Summarize(samples, layout, unresolved)); + } +} + +public readonly record struct PlanetaryResidentPage(PlanetaryBakedPage Page, float Blend) +{ + public PlanetaryResidentPage Validate() + { + if (!float.IsFinite(Blend) || Blend is < 0 or > 1) throw new ArgumentOutOfRangeException(nameof(Blend)); + Page.Layout.Validate(); + if (Page.Samples.Length != Page.Layout.StorageSize * Page.Layout.StorageSize) throw new ArgumentException("Page payload does not match layout."); + return this; + } +} + +public static class PlanetaryPageSetSampling +{ + public static bool TrySample(ReadOnlySpan pages, float3 direction, out PlanetaryPageSample sample) + { + PlanetaryTopology.ValidateDirection(direction); + var height = 0.0f; + var gradient = float3.zero; + var ridge = 0.0f; + var gully = 0.0f; + var found = false; + var deepestLevel = -1; + foreach (var resident in pages) + { + resident.Validate(); + if (!PlanetaryTopology.TryLocalCoordinate(direction, resident.Page.Layout.Tile, out var local)) continue; + var contribution = PlanetaryPageSampling.Bilinear(resident.Page.Samples, resident.Page.Layout, local); + var blend = math.saturate(resident.Blend); + height += contribution.Height * blend; + gradient += contribution.TangentGradient * blend; + if (resident.Page.Layout.Tile.Level >= deepestLevel) + { + ridge = found ? math.lerp(ridge, contribution.Ridge, blend) : contribution.Ridge; + gully = found ? math.lerp(gully, contribution.Gully, blend) : contribution.Gully; + deepestLevel = resident.Page.Layout.Tile.Level; + } + found = true; + } + sample = new(height, gradient, ridge, gully); + return found; + } +} diff --git a/src/GameCult.Geometry/Planetary/PlanetaryPatch.cs b/src/GameCult.Geometry/Planetary/PlanetaryPatch.cs new file mode 100644 index 00000000..76a3fe92 --- /dev/null +++ b/src/GameCult.Geometry/Planetary/PlanetaryPatch.cs @@ -0,0 +1,50 @@ +using System; +using System.Linq; +using CultMath; + +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +namespace GameCult.Geometry; + +public readonly record struct PlanetaryPatchVertex(float2 LocalCoordinate, float3 UnitDirection); + +public readonly record struct PlanetaryPatchMesh( + PlanetaryCubeFace Face, + int CellsPerAxis, + PlanetaryPatchVertex[] Vertices, + int[] Indices); + +public static class PlanetaryPatch +{ + public static PlanetaryPatchMesh CreateFace(PlanetaryCubeFace face, int cellsPerAxis) + { + if (!Enum.IsDefined(typeof(PlanetaryCubeFace), face)) throw new ArgumentOutOfRangeException(nameof(face)); + if (cellsPerAxis < 1 || cellsPerAxis > 4096) throw new ArgumentOutOfRangeException(nameof(cellsPerAxis)); + var axisVertices = cellsPerAxis + 1; + var vertices = new PlanetaryPatchVertex[checked(axisVertices * axisVertices)]; + for (var y = 0; y < axisVertices; y++) + for (var x = 0; x < axisVertices; x++) + { + var local = new float2(x / (float)cellsPerAxis, y / (float)cellsPerAxis); + vertices[y * axisVertices + x] = new(local, PlanetaryTopology.Direction(new(face, local.x * 2 - 1, local.y * 2 - 1))); + } + var indices = new int[checked(cellsPerAxis * cellsPerAxis * 6)]; + var write = 0; + for (var y = 0; y < cellsPerAxis; y++) + for (var x = 0; x < cellsPerAxis; x++) + { + var lowerLeft = y * axisVertices + x; + var lowerRight = lowerLeft + 1; + var upperLeft = lowerLeft + axisVertices; + var upperRight = upperLeft + 1; + indices[write++] = lowerLeft; indices[write++] = lowerRight; indices[write++] = upperRight; + indices[write++] = lowerLeft; indices[write++] = upperRight; indices[write++] = upperLeft; + } + return new(face, cellsPerAxis, vertices, indices); + } + + public static PlanetaryPatchMesh[] CreateCubeSphere(int cellsPerAxis) + => ((PlanetaryCubeFace[])Enum.GetValues(typeof(PlanetaryCubeFace))).Select(face => CreateFace(face, cellsPerAxis)).ToArray(); +} diff --git a/src/GameCult.Geometry/Planetary/PlanetaryProjection.cs b/src/GameCult.Geometry/Planetary/PlanetaryProjection.cs new file mode 100644 index 00000000..5851d367 --- /dev/null +++ b/src/GameCult.Geometry/Planetary/PlanetaryProjection.cs @@ -0,0 +1,327 @@ +using System; +using CultMath; + +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +namespace GameCult.Geometry; + +public enum PlanetaryProjectionKind +{ + Equirectangular, + WebMercator, + EqualEarth, + Orthographic, + AzimuthalEquidistant, + AzimuthalEqualArea, + CubeAtlas, + LocalTangent, +} + +public readonly record struct PlanetaryProjectionParameters( + PlanetaryProjectionKind Kind, + double CenterLongitude = 0, + double CenterLatitude = 0, + double Scale = 1) +{ + public PlanetaryProjectionParameters Validate() + { + if (!double.IsFinite(CenterLongitude) || !double.IsFinite(CenterLatitude) || !double.IsFinite(Scale) || Scale <= 0) + throw new ArgumentOutOfRangeException(nameof(Scale)); + if (CenterLatitude is < -Math.PI / 2 or > Math.PI / 2) throw new ArgumentOutOfRangeException(nameof(CenterLatitude)); + return this; + } +} + +public static class PlanetaryProjection +{ + private const double EqualEarthA1 = 1.340264; + private const double EqualEarthA2 = -0.081106; + private const double EqualEarthA3 = 0.000893; + private const double EqualEarthA4 = 0.003796; + private static readonly double EqualEarthM = Math.Sqrt(3) / 2; + private static readonly double EqualEarthXMax = Math.PI / (EqualEarthM * EqualEarthA1); + private static readonly double EqualEarthYMax = EqualEarthY(Math.Asin(EqualEarthM)); + public static readonly double WebMercatorMaximumLatitude = Math.Atan(Math.Sinh(Math.PI)); + + public static bool TryForward(float3 direction, PlanetaryProjectionParameters parameters, out double2 coordinate) + { + parameters.Validate(); + PlanetaryTopology.ValidateDirection(direction); + var d = math.normalize(direction); + if (parameters.Kind == PlanetaryProjectionKind.CubeAtlas) + { + var face = PlanetaryTopology.FaceCoordinate(d); + var index = (int)face.Face; + var column = index % 3; + var row = index / 3; + coordinate = new( + (-1 + (column + (face.U + 1) * 0.5) * (2.0 / 3.0)) / parameters.Scale, + (1 - (row + (face.V + 1) * 0.5)) / parameters.Scale); + return true; + } + + var longitude = Math.Atan2(d.y, d.x); + var latitude = Math.Asin(Math.Clamp(d.z, -1, 1)); + var deltaLongitude = WrapLongitude(longitude - parameters.CenterLongitude); + var centered = CenteredForward(deltaLongitude, latitude, parameters, out coordinate); + coordinate /= parameters.Scale; + return centered; + } + + public static bool TryInverse(double2 coordinate, PlanetaryProjectionParameters parameters, out float3 direction) + { + parameters.Validate(); + if (!double.IsFinite(coordinate.x) || !double.IsFinite(coordinate.y)) + { + direction = float3.zero; + return false; + } + coordinate *= parameters.Scale; + if (parameters.Kind == PlanetaryProjectionKind.CubeAtlas) + return TryInverseCubeAtlas(coordinate, out direction); + + if (!CenteredInverse(coordinate, parameters, out var deltaLongitude, out var latitude)) + { + direction = float3.zero; + return false; + } + var longitude = WrapLongitude(deltaLongitude + parameters.CenterLongitude); + var cosLatitude = Math.Cos(latitude); + direction = math.normalize(new float3( + (float)(cosLatitude * Math.Cos(longitude)), + (float)(cosLatitude * Math.Sin(longitude)), + (float)Math.Sin(latitude))); + return true; + } + + private static bool CenteredForward(double longitude, double latitude, PlanetaryProjectionParameters p, out double2 coordinate) + { + switch (p.Kind) + { + case PlanetaryProjectionKind.Equirectangular: + coordinate = new(longitude / Math.PI, latitude / (Math.PI * 0.5)); + return true; + case PlanetaryProjectionKind.WebMercator: + if (Math.Abs(latitude) > WebMercatorMaximumLatitude) { coordinate = double2.zero; return false; } + coordinate = new(longitude / Math.PI, Math.Asinh(Math.Tan(latitude)) / Math.PI); + return true; + case PlanetaryProjectionKind.EqualEarth: + { + var theta = Math.Asin(EqualEarthM * Math.Sin(latitude)); + var theta2 = theta * theta; + var theta6 = theta2 * theta2 * theta2; + var denominator = EqualEarthM * (EqualEarthA1 + 3 * EqualEarthA2 * theta2 + theta6 * (7 * EqualEarthA3 + 9 * EqualEarthA4 * theta2)); + coordinate = new(longitude * Math.Cos(theta) / denominator / EqualEarthXMax, EqualEarthY(theta) / EqualEarthYMax); + return true; + } + case PlanetaryProjectionKind.Orthographic: + case PlanetaryProjectionKind.AzimuthalEquidistant: + case PlanetaryProjectionKind.AzimuthalEqualArea: + case PlanetaryProjectionKind.LocalTangent: + return ForwardAzimuthal(longitude, latitude, p, out coordinate); + default: + throw new ArgumentOutOfRangeException(nameof(p)); + } + } + + private static bool CenteredInverse(double2 coordinate, PlanetaryProjectionParameters p, out double longitude, out double latitude) + { + longitude = latitude = 0; + switch (p.Kind) + { + case PlanetaryProjectionKind.Equirectangular: + if (Math.Abs(coordinate.y) > 1) return false; + longitude = coordinate.x * Math.PI; latitude = coordinate.y * Math.PI * 0.5; return Math.Abs(coordinate.x) <= 1; + case PlanetaryProjectionKind.WebMercator: + if (Math.Abs(coordinate.x) > 1 || Math.Abs(coordinate.y) > 1) return false; + longitude = coordinate.x * Math.PI; latitude = Math.Atan(Math.Sinh(coordinate.y * Math.PI)); return true; + case PlanetaryProjectionKind.EqualEarth: + { + if (Math.Abs(coordinate.x) > 1 || Math.Abs(coordinate.y) > 1) return false; + var targetY = coordinate.y * EqualEarthYMax; + var theta = targetY / EqualEarthA1; + for (var i = 0; i < 8; i++) + { + var theta2 = theta * theta; + var theta6 = theta2 * theta2 * theta2; + var f = EqualEarthY(theta) - targetY; + var derivative = EqualEarthA1 + 3 * EqualEarthA2 * theta2 + theta6 * (7 * EqualEarthA3 + 9 * EqualEarthA4 * theta2); + theta -= f / derivative; + } + var sinLatitude = Math.Sin(theta) / EqualEarthM; + if (Math.Abs(sinLatitude) > 1.0000000001) return false; + latitude = Math.Asin(Math.Clamp(sinLatitude, -1, 1)); + var thetaSquared = theta * theta; + var thetaSixth = thetaSquared * thetaSquared * thetaSquared; + var denominator = EqualEarthM * (EqualEarthA1 + 3 * EqualEarthA2 * thetaSquared + thetaSixth * (7 * EqualEarthA3 + 9 * EqualEarthA4 * thetaSquared)); + longitude = coordinate.x * EqualEarthXMax * denominator / Math.Cos(theta); + return Math.Abs(longitude) <= Math.PI + 1.0e-10; + } + case PlanetaryProjectionKind.Orthographic: + case PlanetaryProjectionKind.AzimuthalEquidistant: + case PlanetaryProjectionKind.AzimuthalEqualArea: + case PlanetaryProjectionKind.LocalTangent: + return InverseAzimuthal(coordinate, p, out longitude, out latitude); + default: + throw new ArgumentOutOfRangeException(nameof(p)); + } + } + + private static bool ForwardAzimuthal(double longitude, double latitude, PlanetaryProjectionParameters p, out double2 coordinate) + { + var sin0 = Math.Sin(p.CenterLatitude); var cos0 = Math.Cos(p.CenterLatitude); + var sin = Math.Sin(latitude); var cos = Math.Cos(latitude); var cosLon = Math.Cos(longitude); + var cosC = Math.Clamp(sin0 * sin + cos0 * cos * cosLon, -1, 1); + var rawX = cos * Math.Sin(longitude); + var rawY = cos0 * sin - sin0 * cos * cosLon; + double factor; + switch (p.Kind) + { + case PlanetaryProjectionKind.Orthographic: + if (cosC < 0) { coordinate = double2.zero; return false; } + factor = 1; break; + case PlanetaryProjectionKind.AzimuthalEquidistant: + { + var c = Math.Acos(cosC); factor = c < 1.0e-12 ? 1 : c / Math.Sin(c); factor /= Math.PI; break; + } + case PlanetaryProjectionKind.AzimuthalEqualArea: + factor = Math.Sqrt(2 / Math.Max(1 + cosC, 1.0e-20)) * 0.5; break; + case PlanetaryProjectionKind.LocalTangent: + if (cosC <= 0) { coordinate = double2.zero; return false; } + factor = 1 / cosC; break; + default: throw new ArgumentOutOfRangeException(nameof(p)); + } + coordinate = new(rawX * factor, rawY * factor); + return true; + } + + private static bool InverseAzimuthal(double2 coordinate, PlanetaryProjectionParameters p, out double longitude, out double latitude) + { + longitude = latitude = 0; + var rho = Math.Sqrt(coordinate.x * coordinate.x + coordinate.y * coordinate.y); + double c; + switch (p.Kind) + { + case PlanetaryProjectionKind.Orthographic: if (rho > 1) return false; c = Math.Asin(Math.Clamp(rho, 0, 1)); break; + case PlanetaryProjectionKind.AzimuthalEquidistant: if (rho > 1) return false; c = rho * Math.PI; break; + case PlanetaryProjectionKind.AzimuthalEqualArea: if (rho > 1) return false; c = 2 * Math.Asin(Math.Clamp(rho, 0, 1)); break; + case PlanetaryProjectionKind.LocalTangent: c = Math.Atan(rho); break; + default: throw new ArgumentOutOfRangeException(nameof(p)); + } + if (rho < 1.0e-12) { latitude = p.CenterLatitude; return true; } + var sinC = Math.Sin(c); var cosC = Math.Cos(c); + var sin0 = Math.Sin(p.CenterLatitude); var cos0 = Math.Cos(p.CenterLatitude); + latitude = Math.Asin(Math.Clamp(cosC * sin0 + coordinate.y * sinC * cos0 / rho, -1, 1)); + longitude = Math.Atan2(coordinate.x * sinC, rho * cos0 * cosC - coordinate.y * sin0 * sinC); + return true; + } + + private static bool TryInverseCubeAtlas(double2 coordinate, out float3 direction) + { + direction = float3.zero; + if (coordinate.x is < -1 or > 1 || coordinate.y is < -1 or > 1) return false; + var column = Math.Min((int)((coordinate.x + 1) * 1.5), 2); + var row = Math.Min((int)((1 - coordinate.y)), 1); + var u = ((coordinate.x + 1) * 1.5 - column) * 2 - 1; + var v = ((1 - coordinate.y) - row) * 2 - 1; + direction = PlanetaryTopology.Direction(new((PlanetaryCubeFace)(row * 3 + column), u, v)); + return true; + } + + private static double EqualEarthY(double theta) + { + var theta2 = theta * theta; + var theta6 = theta2 * theta2 * theta2; + return theta * (EqualEarthA1 + EqualEarthA2 * theta2 + theta6 * (EqualEarthA3 + EqualEarthA4 * theta2)); + } + + private static double WrapLongitude(double longitude) + { + longitude %= Math.PI * 2; + if (longitude > Math.PI) longitude -= Math.PI * 2; + if (longitude < -Math.PI) longitude += Math.PI * 2; + return longitude; + } +} + +public readonly record struct PlanetaryMapTileLayout( + PlanetaryProjectionParameters Projection, + int Level, + int X, + int Y, + int InteriorSize, + int BorderSize) +{ + public int StorageSize => checked(InteriorSize + BorderSize * 2); + + public PlanetaryMapTileLayout Validate() + { + Projection.Validate(); + if (Level is < 0 or > 30) throw new ArgumentOutOfRangeException(nameof(Level)); + var count = 1 << Level; + if ((uint)X >= (uint)count || (uint)Y >= (uint)count) throw new ArgumentOutOfRangeException(nameof(X)); + if (InteriorSize < 2 || BorderSize < 0 || BorderSize >= InteriorSize) throw new ArgumentOutOfRangeException(nameof(InteriorSize)); + return this; + } +} + +public static class PlanetaryMapTileSampling +{ + public static bool TryDirection(PlanetaryMapTileLayout tile, int storageX, int storageY, out float3 direction) + { + tile.Validate(); + if ((uint)storageX >= (uint)tile.StorageSize || (uint)storageY >= (uint)tile.StorageSize) throw new ArgumentOutOfRangeException(nameof(storageX)); + var count = 1 << tile.Level; + var localU = (storageX - tile.BorderSize) / (double)(tile.InteriorSize - 1); + var localV = (storageY - tile.BorderSize) / (double)(tile.InteriorSize - 1); + var map = new double2(-1 + 2 * (tile.X + localU) / count, 1 - 2 * (tile.Y + localV) / count); + return PlanetaryProjection.TryInverse(map, tile.Projection, out direction); + } +} + +public readonly record struct PlanetaryMapTileKey( + ulong FieldVersion, + uint ProjectionVersion, + uint LayerId, + PlanetaryMapTileLayout Layout, + PlanetaryQueryScale QueryScale) +{ + public PlanetaryMapTileKey Validate() + { + if (FieldVersion == 0 || ProjectionVersion == 0) throw new ArgumentOutOfRangeException(nameof(FieldVersion)); + Layout.Validate(); QueryScale.Validate(); + return this; + } +} + +public readonly record struct PlanetarySurfaceMapTile( + PlanetaryMapTileKey Key, + PlanetarySurfaceSample[] Samples, + bool[] Validity); + +public static class PlanetaryMapTileBaker +{ + public static PlanetarySurfaceMapTile Bake( + in PlanetaryFieldDefinition field, + PlanetaryMapTileKey key, + TSource source) + where TSource : IPlanetaryBaseField + { + field.Validate(); key.Validate(); + if (field.FieldVersion != key.FieldVersion) throw new ArgumentException("Tile field version does not match definition.", nameof(key)); + var count = key.Layout.StorageSize * key.Layout.StorageSize; + var samples = new PlanetarySurfaceSample[count]; + var validity = new bool[count]; + for (var y = 0; y < key.Layout.StorageSize; y++) + for (var x = 0; x < key.Layout.StorageSize; x++) + { + var index = y * key.Layout.StorageSize + x; + if (!PlanetaryMapTileSampling.TryDirection(key.Layout, x, y, out var direction)) continue; + samples[index] = PlanetaryField.Sample(field, direction, source.Sample(direction), key.QueryScale); + validity[index] = true; + } + return new(key, samples, validity); + } +} diff --git a/src/GameCult.Geometry/Planetary/PlanetaryQueries.cs b/src/GameCult.Geometry/Planetary/PlanetaryQueries.cs new file mode 100644 index 00000000..b50b7785 --- /dev/null +++ b/src/GameCult.Geometry/Planetary/PlanetaryQueries.cs @@ -0,0 +1,198 @@ +using System; +using CultMath; + +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +namespace GameCult.Geometry; + +public readonly record struct PlanetaryRadialBounds(float MinimumDisplacement, float MaximumDisplacement) +{ + public PlanetaryRadialBounds Validate() + { + if (!float.IsFinite(MinimumDisplacement) || !float.IsFinite(MaximumDisplacement) || MinimumDisplacement > MaximumDisplacement) + throw new ArgumentOutOfRangeException(nameof(MinimumDisplacement)); + return this; + } +} + +public readonly record struct PlanetaryRayHit( + double Distance, + double3 PlanetLocalPosition, + PlanetarySurfaceSample Surface); + +public readonly record struct PlanetaryPathSample(double Distance, PlanetarySurfaceSample Surface); + +public readonly record struct PlanetaryRegionSummary( + float MinimumDisplacement, + float MaximumDisplacement, + float MaximumSlope, + float MaximumUnresolvedHeight); + +public static class PlanetaryQueries +{ + public static bool TryIntersectRay( + in PlanetaryFieldDefinition field, + double3 rayOrigin, + double3 rayDirection, + double maximumDistance, + in PlanetaryQueryScale scale, + in PlanetaryRadialBounds bounds, + TSource source, + out PlanetaryRayHit hit) + where TSource : IPlanetaryBaseField + { + field.Validate(); scale.Validate(); bounds.Validate(); + ValidateFinite(rayOrigin, nameof(rayOrigin)); ValidateFinite(rayDirection, nameof(rayDirection)); + if (!double.IsFinite(maximumDistance) || maximumDistance <= 0) throw new ArgumentOutOfRangeException(nameof(maximumDistance)); + var directionLength = Length(rayDirection); + if (directionLength < 1.0e-15) throw new ArgumentOutOfRangeException(nameof(rayDirection)); + var direction = rayDirection / directionLength; + var outerRadius = field.Radius + bounds.MaximumDisplacement + scale.MaximumUnresolvedHeight; + if (!double.IsFinite(outerRadius)) outerRadius = field.Radius + bounds.MaximumDisplacement; + if (!TrySphereInterval(rayOrigin, direction, outerRadius, out var enter, out var leave)) { hit = default; return false; } + var start = Math.Max(enter, 0); + var end = Math.Min(leave, maximumDistance); + if (start > end) { hit = default; return false; } + + var previousDistance = start; + var previous = SignedSurfaceDistance(field, rayOrigin + direction * previousDistance, scale, source, out var previousSample); + if (previous <= 0) + { + hit = new(previousDistance, rayOrigin + direction * previousDistance, previousSample); + return true; + } + var minimumStep = Math.Max(scale.FootprintMeters * 0.5, field.Radius * 1.0e-7); + for (var iteration = 0; iteration < 512 && previousDistance < end; iteration++) + { + var nextDistance = Math.Min(previousDistance + Math.Max(previous * 0.5, minimumStep), end); + var next = SignedSurfaceDistance(field, rayOrigin + direction * nextDistance, scale, source, out var nextSample); + if (next <= 0) + { + var low = previousDistance; + var high = nextDistance; + var surface = nextSample; + for (var refine = 0; refine < 32; refine++) + { + var middle = (low + high) * 0.5; + var value = SignedSurfaceDistance(field, rayOrigin + direction * middle, scale, source, out var middleSample); + if (value > 0) low = middle; + else { high = middle; surface = middleSample; } + } + var position = rayOrigin + direction * high; + hit = new(high, position, surface); + return true; + } + if (nextDistance >= end) break; + previousDistance = nextDistance; + previous = next; + previousSample = nextSample; + } + hit = default; + return false; + } + + public static double SegmentClearance( + in PlanetaryFieldDefinition field, + double3 start, + double3 end, + double sampleSpacing, + in PlanetaryQueryScale scale, + TSource source) + where TSource : IPlanetaryBaseField + { + ValidateFinite(start, nameof(start)); ValidateFinite(end, nameof(end)); + if (!double.IsFinite(sampleSpacing) || sampleSpacing <= 0) throw new ArgumentOutOfRangeException(nameof(sampleSpacing)); + var delta = end - start; + var distance = Length(delta); + var steps = Math.Max((int)Math.Ceiling(distance / sampleSpacing), 1); + var minimum = double.PositiveInfinity; + for (var i = 0; i <= steps; i++) + { + var position = start + delta * (i / (double)steps); + minimum = Math.Min(minimum, SignedSurfaceDistance(field, position, scale, source, out _)); + } + return minimum; + } + + public static PlanetaryPathSample[] SampleGreatCircle( + in PlanetaryFieldDefinition field, + float3 startDirection, + float3 endDirection, + int segmentCount, + in PlanetaryQueryScale scale, + TSource source) + where TSource : IPlanetaryBaseField + { + if (segmentCount < 1) throw new ArgumentOutOfRangeException(nameof(segmentCount)); + PlanetaryTopology.ValidateDirection(startDirection); PlanetaryTopology.ValidateDirection(endDirection); + var a = math.normalize(startDirection); var b = math.normalize(endDirection); + var angle = MathF.Acos(math.clamp(math.dot(a, b), -1, 1)); + var sinAngle = MathF.Sin(angle); + var result = new PlanetaryPathSample[segmentCount + 1]; + for (var i = 0; i <= segmentCount; i++) + { + var t = i / (float)segmentCount; + var direction = sinAngle < 1.0e-6f + ? math.normalize(math.lerp(a, b, t)) + : math.normalize(a * (MathF.Sin((1 - t) * angle) / sinAngle) + b * (MathF.Sin(t * angle) / sinAngle)); + var sample = PlanetaryField.Sample(field, direction, source.Sample(direction), scale); + result[i] = new(angle * field.Radius * t, sample); + } + return result; + } + + public static PlanetaryRegionSummary Summarize( + in PlanetaryFieldDefinition field, + ReadOnlySpan directions, + in PlanetaryQueryScale scale, + TSource source) + where TSource : IPlanetaryBaseField + { + if (directions.IsEmpty) throw new ArgumentException("At least one direction is required.", nameof(directions)); + var min = float.PositiveInfinity; var max = float.NegativeInfinity; var slope = 0.0f; var unresolved = 0.0f; + foreach (var direction in directions) + { + var normalized = math.normalize(direction); + var sample = PlanetaryField.Sample(field, normalized, source.Sample(normalized), scale); + min = MathF.Min(min, sample.RadialDisplacement); + max = MathF.Max(max, sample.RadialDisplacement); + slope = MathF.Max(slope, sample.Slope); + unresolved = MathF.Max(unresolved, sample.UnresolvedHeightBound); + } + return new(min, max, slope, unresolved); + } + + private static double SignedSurfaceDistance( + in PlanetaryFieldDefinition field, + double3 position, + in PlanetaryQueryScale scale, + TSource source, + out PlanetarySurfaceSample sample) + where TSource : IPlanetaryBaseField + { + var radius = Length(position); + if (radius < 1.0e-15) { sample = default; return double.NegativeInfinity; } + var direction = new float3((float)(position.x / radius), (float)(position.y / radius), (float)(position.z / radius)); + sample = PlanetaryField.Sample(field, direction, source.Sample(direction), scale); + return radius - sample.SurfaceRadius; + } + + private static bool TrySphereInterval(double3 origin, double3 direction, double radius, out double enter, out double leave) + { + var b = Dot(origin, direction); + var c = Dot(origin, origin) - radius * radius; + var discriminant = b * b - c; + if (discriminant < 0) { enter = leave = 0; return false; } + var root = Math.Sqrt(discriminant); + enter = -b - root; leave = -b + root; return leave >= 0; + } + + private static double Dot(double3 a, double3 b) => a.x * b.x + a.y * b.y + a.z * b.z; + private static double Length(double3 value) => Math.Sqrt(Dot(value, value)); + private static void ValidateFinite(double3 value, string name) + { + if (!double.IsFinite(value.x) || !double.IsFinite(value.y) || !double.IsFinite(value.z)) throw new ArgumentOutOfRangeException(name); + } +} diff --git a/src/GameCult.Geometry/Planetary/PlanetaryRadialRefinement.cs b/src/GameCult.Geometry/Planetary/PlanetaryRadialRefinement.cs new file mode 100644 index 00000000..a958bc1a --- /dev/null +++ b/src/GameCult.Geometry/Planetary/PlanetaryRadialRefinement.cs @@ -0,0 +1,34 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +using CultMath; + +namespace GameCult.Geometry; + +public static class PlanetaryRadialRefinement +{ + public static float3 Step( + float3 position, + float3 rayDirection, + float3 center, + float targetRadius, + float minimumDerivative = 0.2f, + float maximumCorrection = 0.08f) + { + var local = position - center; + var radius = math.length(local); + var radial = local / math.max(radius, 0.0001f); + var error = radius - targetRadius; + var derivative = math.dot(rayDirection, radial); + var safeMinimum = math.max(minimumDerivative, 0.0001f); + var safeDerivative = math.abs(derivative) > safeMinimum + ? derivative + : derivative < 0.0f ? -safeMinimum : safeMinimum; + var correction = math.clamp( + -error / safeDerivative, + -math.abs(maximumCorrection), + math.abs(maximumCorrection)); + return position + rayDirection * correction; + } +} diff --git a/src/GameCult.Geometry/Planetary/PlanetaryResidency.cs b/src/GameCult.Geometry/Planetary/PlanetaryResidency.cs new file mode 100644 index 00000000..79acc317 --- /dev/null +++ b/src/GameCult.Geometry/Planetary/PlanetaryResidency.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using CultMath; + +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +namespace GameCult.Geometry; + +public readonly record struct PlanetaryLodParameters( + int MaximumLevel, + int PageInteriorSize, + int PageBorderSize, + float ViewportHeightPixels, + float MinimumFootprintMeters) +{ + public PlanetaryLodParameters Validate() + { + if (MaximumLevel is < 0 or > PlanetaryTileAddress.MaxLevel) throw new ArgumentOutOfRangeException(nameof(MaximumLevel)); + _ = new PlanetaryPageLayout(new(PlanetaryCubeFace.PositiveX, 0, 0, 0), PageInteriorSize, PageBorderSize).Validate(); + if (!float.IsFinite(ViewportHeightPixels) || ViewportHeightPixels <= 0) throw new ArgumentOutOfRangeException(nameof(ViewportHeightPixels)); + if (!float.IsFinite(MinimumFootprintMeters) || MinimumFootprintMeters < 0) throw new ArgumentOutOfRangeException(nameof(MinimumFootprintMeters)); + return this; + } +} + +public static class PlanetaryLodSelector +{ + public static int SelectLevel( + in PlanetaryFieldDefinition field, + float cameraDistanceFromCenter, + in PlanetaryLodParameters parameters) + { + field.Validate(); parameters.Validate(); + if (!float.IsFinite(cameraDistanceFromCenter) || cameraDistanceFromCenter < 0) throw new ArgumentOutOfRangeException(nameof(cameraDistanceFromCenter)); + var altitude = MathF.Max(cameraDistanceFromCenter - field.Radius, 0.001f); + var footprint = MathF.Max(altitude / parameters.ViewportHeightPixels * 2, parameters.MinimumFootprintMeters); + var erosion = field.Erosion; + for (var level = 0; level <= parameters.MaximumLevel; level++) + { + var page = new PlanetaryPageLayout(new(PlanetaryCubeFace.PositiveX, level, 0, 0), parameters.PageInteriorSize, parameters.PageBorderSize); + var spacing = PlanetaryPageSampling.NominalAngularTexelSize(page) * field.Radius; + var unresolved = ErosionFrequencyBands.Select( + erosion.Scale * erosion.CellScale, spacing, erosion.Octaves, + erosion.Lacunarity, erosion.Strength * erosion.Scale, erosion.Gain).UnresolvedHeightBound; + if (unresolved <= footprint) return level; + } + return parameters.MaximumLevel; + } + + public static PlanetaryTileAddress[] SelectAncestorChain( + in PlanetaryFieldDefinition field, + float3 cameraDirection, + float cameraDistanceFromCenter, + in PlanetaryLodParameters parameters) + { + PlanetaryTopology.ValidateDirection(cameraDirection); + var level = SelectLevel(field, cameraDistanceFromCenter, parameters); + var result = new PlanetaryTileAddress[6 + level]; + for (var face = 0; face < 6; face++) result[face] = new((PlanetaryCubeFace)face, 0, 0, 0); + var leaf = PlanetaryTopology.TileAt(cameraDirection, level); + for (var currentLevel = level; currentLevel >= 1; currentLevel--) + { + result[6 + currentLevel - 1] = leaf; + leaf = leaf.Parent(); + } + return result; + } +} + +public readonly record struct PlanetaryResidentTile(PlanetaryTileAddress Tile, float Blend, bool Departing); + +public readonly record struct PlanetaryResidencySnapshot( + ulong ContentVersion, + ulong PresentationVersion, + PlanetaryResidentTile[] Tiles); + +/// Owns presentation residency only. It never owns field content. +public sealed class PlanetaryResidualResidency +{ + private readonly Dictionary residents = new(); + private readonly Dictionary arrivals = new(); + private readonly Dictionary departures = new(); + private float lastTime = float.NegativeInfinity; + + public void Reset() + { + residents.Clear(); arrivals.Clear(); departures.Clear(); lastTime = float.NegativeInfinity; + } + + public PlanetaryResidencySnapshot Update(ReadOnlySpan desired, float timeSeconds, float transitionSeconds) + { + if (!float.IsFinite(timeSeconds)) throw new ArgumentOutOfRangeException(nameof(timeSeconds)); + if (!float.IsFinite(transitionSeconds) || transitionSeconds < 0) throw new ArgumentOutOfRangeException(nameof(transitionSeconds)); + if (timeSeconds < lastTime) Reset(); + lastTime = timeSeconds; + + var desiredKeys = new HashSet(); + foreach (var tile in desired) + { + var key = tile.StableKey; + desiredKeys.Add(key); + residents[key] = tile; + if (!arrivals.ContainsKey(key)) arrivals[key] = timeSeconds; + departures.Remove(key); + } + + foreach (var pair in residents.ToArray()) + { + if (pair.Value.Level == 0 || desiredKeys.Contains(pair.Key)) continue; + if (!departures.ContainsKey(pair.Key)) + { + var startingBlend = transitionSeconds == 0 + ? 1 + : Math.Clamp((timeSeconds - arrivals[pair.Key]) / transitionSeconds, 0, 1); + departures[pair.Key] = (timeSeconds, startingBlend); + } + if (transitionSeconds > 0 && timeSeconds - departures[pair.Key].Time < transitionSeconds) continue; + residents.Remove(pair.Key); arrivals.Remove(pair.Key); departures.Remove(pair.Key); + } + + var ordered = residents + .OrderBy(pair => pair.Value.Level) + .ThenBy(pair => pair.Value.Face) + .ThenBy(pair => pair.Value.X) + .ThenBy(pair => pair.Value.Y) + .ToArray(); + var tiles = new PlanetaryResidentTile[ordered.Length]; + for (var i = 0; i < ordered.Length; i++) + { + var pair = ordered[i]; + var departing = departures.TryGetValue(pair.Key, out var departure); + var blend = pair.Value.Level == 0 || transitionSeconds == 0 + ? 1 + : departing + ? departure.StartingBlend * Math.Clamp(1 - (timeSeconds - departure.Time) / transitionSeconds, 0, 1) + : Math.Clamp((timeSeconds - arrivals[pair.Key]) / transitionSeconds, 0, 1); + tiles[i] = new(pair.Value, blend, departing); + } + return new(Hash(ordered.Select(pair => pair.Key)), Hash(tiles.Select(tile => tile.Tile.StableKey ^ (uint)BitConverter.SingleToInt32Bits(tile.Blend))), tiles); + } + + private static ulong Hash(IEnumerable values) + { + const ulong offset = 14695981039346656037UL; + const ulong prime = 1099511628211UL; + var hash = offset; + foreach (var value in values) hash = unchecked((hash ^ value) * prime); + return hash == 0 ? 1 : hash; + } +} diff --git a/src/GameCult.Geometry/Planetary/PlanetaryTopology.cs b/src/GameCult.Geometry/Planetary/PlanetaryTopology.cs new file mode 100644 index 00000000..18ff4f31 --- /dev/null +++ b/src/GameCult.Geometry/Planetary/PlanetaryTopology.cs @@ -0,0 +1,196 @@ +using System; +using CultMath; + +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +namespace GameCult.Geometry; + +public enum PlanetaryCubeFace +{ + PositiveX, + NegativeX, + PositiveY, + NegativeY, + PositiveZ, + NegativeZ, +} + +public readonly record struct PlanetaryFaceCoordinate(PlanetaryCubeFace Face, double U, double V) +{ + public PlanetaryFaceCoordinate Validate(bool allowOutsideFace = false) + { + if (!double.IsFinite(U) || !double.IsFinite(V)) throw new ArgumentOutOfRangeException(nameof(U)); + if (!allowOutsideFace && (U is < -1.0 or > 1.0 || V is < -1.0 or > 1.0)) + throw new ArgumentOutOfRangeException(nameof(U), "Face coordinates must be in [-1, 1]."); + if (!Enum.IsDefined(typeof(PlanetaryCubeFace), Face)) throw new ArgumentOutOfRangeException(nameof(Face)); + return this; + } +} + +public readonly record struct PlanetaryTileAddress +{ + public const int MaxLevel = 30; + + public PlanetaryTileAddress(PlanetaryCubeFace face, int level, int x, int y) + { + if (!Enum.IsDefined(typeof(PlanetaryCubeFace), face)) throw new ArgumentOutOfRangeException(nameof(face)); + if (level is < 0 or > MaxLevel) throw new ArgumentOutOfRangeException(nameof(level)); + var count = 1 << level; + if ((uint)x >= (uint)count) throw new ArgumentOutOfRangeException(nameof(x)); + if ((uint)y >= (uint)count) throw new ArgumentOutOfRangeException(nameof(y)); + Face = face; + Level = level; + X = x; + Y = y; + } + + public PlanetaryCubeFace Face { get; } + public int Level { get; } + public int X { get; } + public int Y { get; } + public int AxisTileCount => 1 << Level; + + public PlanetaryTileAddress Parent() => Level == 0 + ? throw new InvalidOperationException("Root cube tile has no parent.") + : new(Face, Level - 1, X >> 1, Y >> 1); + + public PlanetaryTileAddress Child(int childX, int childY) + { + if ((uint)childX > 1) throw new ArgumentOutOfRangeException(nameof(childX)); + if ((uint)childY > 1) throw new ArgumentOutOfRangeException(nameof(childY)); + if (Level == MaxLevel) throw new InvalidOperationException($"Level {MaxLevel} cannot be subdivided."); + return new(Face, Level + 1, (X << 1) | childX, (Y << 1) | childY); + } + + public PlanetaryFaceCoordinate PositionAt(double localU, double localV) + { + if (!double.IsFinite(localU) || localU is < 0.0 or > 1.0) throw new ArgumentOutOfRangeException(nameof(localU)); + if (!double.IsFinite(localV) || localV is < 0.0 or > 1.0) throw new ArgumentOutOfRangeException(nameof(localV)); + var count = AxisTileCount; + return new(Face, -1.0 + 2.0 * (X + localU) / count, -1.0 + 2.0 * (Y + localV) / count); + } + + public ulong StableKey + { + get + { + const ulong offset = 14695981039346656037UL; + const ulong prime = 1099511628211UL; + var hash = offset; + hash = unchecked((hash ^ (uint)Face) * prime); + hash = unchecked((hash ^ (uint)Level) * prime); + hash = unchecked((hash ^ (uint)X) * prime); + hash = unchecked((hash ^ (uint)Y) * prime); + return hash == 0 ? 1 : hash; + } + } + public override string ToString() => $"{Face}/L{Level:D2}/{X}/{Y}"; +} + +public static class PlanetaryTopology +{ + private const float QuarterPi = MathF.PI * 0.25f; + + public static float3 Direction(PlanetaryFaceCoordinate coordinate) + { + coordinate.Validate(allowOutsideFace: true); + var u = MathF.Tan((float)coordinate.U * QuarterPi); + var v = MathF.Tan((float)coordinate.V * QuarterPi); + var cube = coordinate.Face switch + { + PlanetaryCubeFace.PositiveX => new float3(1, v, -u), + PlanetaryCubeFace.NegativeX => new float3(-1, v, u), + PlanetaryCubeFace.PositiveY => new float3(u, 1, -v), + PlanetaryCubeFace.NegativeY => new float3(u, -1, v), + PlanetaryCubeFace.PositiveZ => new float3(u, v, 1), + PlanetaryCubeFace.NegativeZ => new float3(-u, v, -1), + _ => throw new ArgumentOutOfRangeException(nameof(coordinate)), + }; + return math.normalize(cube); + } + + public static float3 NormalizedCubeDirection(PlanetaryFaceCoordinate coordinate) + { + coordinate.Validate(allowOutsideFace: true); + var u = (float)coordinate.U; + var v = (float)coordinate.V; + return math.normalize(CubeVector(coordinate.Face, u, v)); + } + + public static PlanetaryFaceCoordinate FaceCoordinate(float3 direction) + { + ValidateDirection(direction); + var d = math.normalize(direction); + var a = math.abs(d); + if (a.x >= a.y && a.x >= a.z) + return d.x >= 0 + ? FromCubeUv(PlanetaryCubeFace.PositiveX, -d.z / a.x, d.y / a.x) + : FromCubeUv(PlanetaryCubeFace.NegativeX, d.z / a.x, d.y / a.x); + if (a.y >= a.z) + return d.y >= 0 + ? FromCubeUv(PlanetaryCubeFace.PositiveY, d.x / a.y, -d.z / a.y) + : FromCubeUv(PlanetaryCubeFace.NegativeY, d.x / a.y, d.z / a.y); + return d.z >= 0 + ? FromCubeUv(PlanetaryCubeFace.PositiveZ, d.x / a.z, d.y / a.z) + : FromCubeUv(PlanetaryCubeFace.NegativeZ, -d.x / a.z, d.y / a.z); + } + + public static PlanetaryTileAddress TileAt(float3 direction, int level) + { + if (level is < 0 or > PlanetaryTileAddress.MaxLevel) throw new ArgumentOutOfRangeException(nameof(level)); + var face = FaceCoordinate(direction); + var count = 1 << level; + var x = Math.Clamp((int)((face.U * 0.5 + 0.5) * count), 0, count - 1); + var y = Math.Clamp((int)((face.V * 0.5 + 0.5) * count), 0, count - 1); + return new(face.Face, level, x, y); + } + + public static bool TryLocalCoordinate(float3 direction, PlanetaryTileAddress tile, out float2 local) + { + var face = FaceCoordinate(direction); + if (face.Face != tile.Face) { local = float2.zero; return false; } + var scaledU = (face.U * 0.5 + 0.5) * tile.AxisTileCount; + var scaledV = (face.V * 0.5 + 0.5) * tile.AxisTileCount; + local = new((float)(scaledU - tile.X), (float)(scaledV - tile.Y)); + return local.x is >= 0 and <= 1 && local.y is >= 0 and <= 1; + } + + public static float3 SurfaceNormal(float3 unitDirection, float3 worldDistanceTangentGradient) + { + ValidateDirection(unitDirection); + ValidateFinite(worldDistanceTangentGradient, nameof(worldDistanceTangentGradient)); + var direction = math.normalize(unitDirection); + var tangent = worldDistanceTangentGradient - direction * math.dot(worldDistanceTangentGradient, direction); + return math.normalize(direction - tangent); + } + + private static PlanetaryFaceCoordinate FromCubeUv(PlanetaryCubeFace face, float cubeU, float cubeV) => new( + face, + MathF.Atan(cubeU) / QuarterPi, + MathF.Atan(cubeV) / QuarterPi); + + private static float3 CubeVector(PlanetaryCubeFace face, float u, float v) => face switch + { + PlanetaryCubeFace.PositiveX => new float3(1, v, -u), + PlanetaryCubeFace.NegativeX => new float3(-1, v, u), + PlanetaryCubeFace.PositiveY => new float3(u, 1, -v), + PlanetaryCubeFace.NegativeY => new float3(u, -1, v), + PlanetaryCubeFace.PositiveZ => new float3(u, v, 1), + PlanetaryCubeFace.NegativeZ => new float3(-u, v, -1), + _ => throw new ArgumentOutOfRangeException(nameof(face)), + }; + + internal static void ValidateDirection(float3 direction) + { + ValidateFinite(direction, nameof(direction)); + if (math.length(direction) < 1.0e-12f) throw new ArgumentOutOfRangeException(nameof(direction)); + } + + internal static void ValidateFinite(float3 value, string name) + { + if (!float.IsFinite(value.x) || !float.IsFinite(value.y) || !float.IsFinite(value.z)) + throw new ArgumentOutOfRangeException(name); + } +} diff --git a/src/GameCult.Geometry/Planetary/SphericalErosion.cs b/src/GameCult.Geometry/Planetary/SphericalErosion.cs new file mode 100644 index 00000000..b20e0f00 --- /dev/null +++ b/src/GameCult.Geometry/Planetary/SphericalErosion.cs @@ -0,0 +1,114 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +using CultMath; + +namespace GameCult.Geometry; + +public readonly record struct SphericalErosionParameters( + float Frequency, + float Amplitude, + float Lacunarity, + float Gain, + float SlopeStrength, + float Detail, + float Seed, + int Octaves) +{ + public static SphericalErosionParameters Default => new(18.0f, 0.035f, 2.03f, 0.52f, 6.0f, 1.35f, 0.0f, 5); +} + +public readonly record struct SphericalErosionSample(float HeightOffset, float Ridge, float Gully, float3 Gradient); + +/// +/// Stateless, point-evaluable erosion-like synthesis on a unit sphere. +/// The matching shader body is gamecult_geometry_spherical_erosion in GameCult.Geometry.hlsl. +/// Position and gradient are planet-space; the gradient is projected tangent +/// internally so cube faces and tile request order never enter the result. +/// +public static class SphericalErosion +{ + public static SphericalErosionSample Sample( + float3 unitPosition, + float baseHeight, + float3 baseGradient, + SphericalErosionParameters parameters) + { + var position = math.normalize(unitPosition); + var gradient = baseGradient - position * math.dot(baseGradient, position); + var slope = math.length(gradient); + var flow = slope > 1.0e-6f ? -gradient / slope : StableTangent(position); + var frequency = math.max(parameters.Frequency, 0.001f); + var amplitude = parameters.Amplitude; + var combiMask = EaseOut(math.saturate(slope * parameters.SlopeStrength)); + var fadeTarget = math.saturate(baseHeight * 0.5f + 0.5f) * 2.0f - 1.0f; + var heightOffset = 0.0f; + var ridge = 0.0f; + var gully = 0.0f; + + var octaveCount = math.min(math.max(parameters.Octaves, 0), 8); + for (var octave = 0; octave < octaveCount; octave++) + { + var phase = DirectionalCellWave(position * frequency, flow, parameters.Seed + octave * 19.19f); + var wave = math.cos(phase); + var waveSlope = math.sin(phase); + var faded = math.lerp(fadeTarget, wave, combiMask); + heightOffset += faded * amplitude; + ridge = math.max(ridge, math.saturate(faded)); + gully = math.max(gully, math.saturate(-faded)); + + var across = math.normalize(math.cross(position, flow)); + gradient += across * (math.sign(waveSlope) * amplitude * frequency * combiMask); + gradient -= position * math.dot(gradient, position); + slope = math.length(gradient); + flow = slope > 1.0e-6f ? -gradient / slope : StableTangent(position); + + var newMask = EaseOut(math.saturate(math.abs(waveSlope) * 1.35f)); + combiMask = PowInverse(combiMask, parameters.Detail) * newMask; + fadeTarget = faded; + frequency *= math.max(parameters.Lacunarity, 1.01f); + amplitude *= math.saturate(parameters.Gain); + } + + return new SphericalErosionSample(heightOffset, ridge, gully, gradient); + } + + private static float DirectionalCellWave(float3 position, float3 flow, float seed) + { + var cell = math.floor(position); + var local = math.frac(position); + var weights = local * local * (3.0f - 2.0f * local); + var x00 = CellWave(position, flow, cell + new float3(0, 0, 0), seed); + var x10 = CellWave(position, flow, cell + new float3(1, 0, 0), seed); + var x01 = CellWave(position, flow, cell + new float3(0, 1, 0), seed); + var x11 = CellWave(position, flow, cell + new float3(1, 1, 0), seed); + var y00 = math.lerp(x00, x10, weights.x); + var y10 = math.lerp(x01, x11, weights.x); + var z0 = math.lerp(y00, y10, weights.y); + var x00z = CellWave(position, flow, cell + new float3(0, 0, 1), seed); + var x10z = CellWave(position, flow, cell + new float3(1, 0, 1), seed); + var x01z = CellWave(position, flow, cell + new float3(0, 1, 1), seed); + var x11z = CellWave(position, flow, cell + new float3(1, 1, 1), seed); + var z1 = math.lerp(math.lerp(x00z, x10z, weights.x), math.lerp(x01z, x11z, weights.x), weights.y); + return math.lerp(z0, z1, weights.z); + } + + private static float CellWave(float3 position, float3 flow, float3 cell, float seed) + { + var pivot = cell + new float3( + math.hash(cell + seed + 11.7f), + math.hash(cell.yzx + seed + 37.1f), + math.hash(cell.zyx + seed + 73.9f)); + return math.dot(position - pivot, flow) * math.TAU + math.hash(cell + seed + 101.3f) * math.TAU; + } + + private static float3 StableTangent(float3 position) + { + var axis = math.abs(position.z) < 0.8f ? new float3(0, 0, 1) : new float3(0, 1, 0); + return math.normalize(math.cross(axis, position)); + } + + private static float EaseOut(float value) => 1.0f - (1.0f - value) * (1.0f - value); + private static float PowInverse(float value, float power) => 1.0f - math.pow(1.0f - math.saturate(value), math.max(power, 0.001f)); +} diff --git a/src/GameCult.Geometry/README.md b/src/GameCult.Geometry/README.md index 4fb881bc..3c1f75bd 100644 --- a/src/GameCult.Geometry/README.md +++ b/src/GameCult.Geometry/README.md @@ -1,8 +1,8 @@ # GameCult.Geometry -`GameCult.Geometry` defines shared geometry values plus CultCache-native -documents for procedural geometry domains, LOD build requests, selected-cut -manifests, and mesh chunk artifacts. +`GameCult.Geometry` owns spatial values, planetary fields and topology, +residual-page residency, map projections and tiles, geometry queries, and the +CultCache-native documents that coordinate geometry production. The package is deliberately substrate-shaped: @@ -20,8 +20,8 @@ The package is deliberately substrate-shaped: The small value layer is for cross-runtime query contracts, physics probes, native slices, and UI surfaces: -- `CultMath.float2` and `CultMath.float3`: whole-vector values for positions, velocities, - accelerations, and query inputs. SoA layouts may store them efficiently, but +- `CultMath.float2` and `CultMath.float3`: whole-vector values for positions, + velocities, accelerations, and query inputs. SoA layouts may store them efficiently, but the semantic API does not force callers to split x/y/z into unrelated fields. - `CultRect`: canonical XY viewport/query rectangle stored as min/max corners. - `CultCircle`: 2D influence/query brush with rect intersection helpers. @@ -33,10 +33,10 @@ runtime equivalents instead of bespoke `{ minX, minY, maxX, maxY }` payloads. ## Runtime Path -`vg-csg` emits domain documents, selected-cut manifests, and chunk artifacts as -MessagePack CultCache documents. A Unity runtime, local worker, or remote -geometry process should receive the same records through CultMesh/CultNet and -read them back as `CultGeometry*` types. +Geometry workers emit domain documents, selected-cut manifests, and chunk +artifacts as MessagePack CultCache documents. A Unity runtime, local worker, or +remote geometry process receives the same records through CultMesh/CultNet and +reads them back as `CultGeometry*` types. ```csharp using GameCult.Caching; @@ -66,18 +66,27 @@ using var chunks = node.Database The record key is part of the contract. Rust and C# must compute the same key for the same geometry record, so stable fingerprints use the Rust canonical -field order and invariant float text. If this drifts, the same chunk becomes two +field order and exact IEEE-754 component bits. If this drifts, the same chunk becomes two different chunks depending on which runtime touched it first. That is not a cache miss; that is split-brain geometry. ## Documents -- `CultMath.float2`, `CultMath.float3`, `CultRect`, `CultCircle`, `CultSphere`: shared value - primitives for query and view contracts. +- `CultMath.float2`, `CultMath.float3`, `CultRect`, `CultCircle`, and + `CultSphere`: shared value primitives for query and view contracts. - `CultGeometryDomainDocument`: one hierarchical domain tree, suitable for - Ragnarok/Fensalir-style feature DSL output. + hierarchical feature DSL output. - `CultGeometryBuildRequest`: one LOD/frustum/budget request for workers. - `CultGeometrySelectedCutManifest`: the selected domain cut, deferred children, fallback rows, and diagnostic contribution rows. - `CultGeometryChunkArtifact`: render mesh, optional collider mesh, source domain/claim identities, build counters, and transition clipping seed. + +## Planetary geometry + +The planetary field, cube-sphere topology, pages, residency, projections, +queries, and versioned `CMPT` map tiles are described in +[`docs/planetary.md`](docs/planetary.md). Shader consumers include +`Shaders/GameCult.Geometry.hlsl`; Unity consumers use the +`org.gamecult.geometry` package, and browser tile consumers use +`packages/gamecult-geometry-ts`. diff --git a/src/GameCult.Geometry/Shaders/AdvancedErosionFilter.hlsl b/src/GameCult.Geometry/Shaders/AdvancedErosionFilter.hlsl new file mode 100644 index 00000000..219afc86 --- /dev/null +++ b/src/GameCult.Geometry/Shaders/AdvancedErosionFilter.hlsl @@ -0,0 +1,147 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. +// Mathematical procedure adapted from Rune Skovbo Johansen's Advanced Terrain +// Erosion Filter (2025): https://www.shadertoy.com/view/wXcfWn + +#ifndef GAMECULT_GEOMETRY_ADVANCED_EROSION_FILTER_HLSL +#define GAMECULT_GEOMETRY_ADVANCED_EROSION_FILTER_HLSL + +struct GameCultGeometryAdvancedErosionParameters +{ + float scale; float strength; float gully_weight; float detail; + float4 rounding; float4 onset; float2 assumed_slope; + float cell_scale; float normalization; int octaves; float lacunarity; float gain; +}; + +struct GameCultGeometryAdvancedErosionResult +{ + float3 delta; float magnitude; float ridge_map; float fade_target; +}; + +struct GameCultGeometryErosionBandSelection +{ + int active_octaves; float final_octave_weight; float finest_included_wavelength; float unresolved_height_bound; +}; + +GameCultGeometryErosionBandSelection gamecult_geometry_select_erosion_bands(float base_wavelength, float sample_spacing, int maximum_octaves, float lacunarity, float base_amplitude, float gain, float transition_ratio) +{ + base_wavelength=max(base_wavelength,1.0e-6); sample_spacing=max(sample_spacing,0.0); lacunarity=max(lacunarity,1.01); transition_ratio=max(transition_ratio,1.01); maximum_octaves=min(max(maximum_octaves,0),16); + float nyquist=sample_spacing*2.0, wavelength=base_wavelength, final_weight=0.0, finest=0.0; int active=0; + [loop] for(int octave=0; octave=active) omitted+=amplitude; else if(index==active-1) omitted+=amplitude*(1.0-final_weight); amplitude*=abs(gain); + } + GameCultGeometryErosionBandSelection result; result.active_octaves=active; result.final_octave_weight=active>0?final_weight:0.0; result.finest_included_wavelength=finest; result.unresolved_height_bound=omitted; return result; +} + +float gamecult_geometry_erosion_hash_unit(int2 cell, uint salt) +{ + uint value = (uint)cell.x * 0x8da6b343u ^ (uint)cell.y * 0xd8163841u ^ salt; + value ^= value >> 16; value *= 0x7feb352du; value ^= value >> 15; value *= 0x846ca68bu; value ^= value >> 16; + return (value & 0x00ffffffu) * (1.0 / 16777216.0); +} +float2 gamecult_geometry_erosion_hash2(float2 input) +{ + int2 cell = (int2)input; + return float2(gamecult_geometry_erosion_hash_unit(cell, 0x68bc21ebu), gamecult_geometry_erosion_hash_unit(cell, 0x02e5be93u)) * 2.0 - 1.0; +} + +float4 gamecult_geometry_phacelle_noise(float2 position, float2 normal_direction, float frequency, float offset_cycles, float normalization) +{ + float2 side_direction = float2(-normal_direction.y, normal_direction.x) * frequency * 6.28318530718; + float offset = offset_cycles * 6.28318530718; + float2 cell = floor(position); + float2 local = frac(position); + float2 phase = 0.0; + float weight_sum = 0.0; + [unroll] for (int x = -1; x <= 2; x++) + [unroll] for (int y = -1; y <= 2; y++) + { + float2 grid_offset = float2(x, y); + float2 grid_point = cell + grid_offset; + float2 random_offset = gamecult_geometry_erosion_hash2(grid_point) * 0.5; + float2 delta = local - grid_offset - random_offset; + float weight = max(0.0, exp(-dot(delta, delta) * 2.0) - 0.01111); + weight_sum += weight; + float wave = dot(delta, side_direction) + offset; + phase += float2(cos(wave), sin(wave)) * weight; + } + float2 interpolated = phase / max(weight_sum, 1.0e-20); + float magnitude = max(1.0 - saturate(normalization), length(interpolated)); + return float4(interpolated / max(magnitude, 1.0e-20), side_direction); +} + +float gamecult_geometry_erosion_pow_inverse(float value, float power) { return 1.0 - pow(1.0 - saturate(value), power); } +float gamecult_geometry_erosion_ease_out(float value) { float inverse = 1.0 - saturate(value); return 1.0 - inverse * inverse; } +float gamecult_geometry_erosion_smooth_start(float value, float smoothing) +{ + return smoothing <= 1.0e-10 || value >= smoothing ? value - 0.5 * smoothing : 0.5 * value * value / smoothing; +} +float2 gamecult_geometry_erosion_safe_normalize(float2 value) +{ + float value_length = length(value); + return abs(value_length) > 1.0e-10 ? value / value_length : value; +} + +GameCultGeometryAdvancedErosionResult gamecult_geometry_advanced_erosion_filter_banded(float2 position, float3 base_height_and_slope, float fade_target, GameCultGeometryAdvancedErosionParameters p, GameCultGeometryErosionBandSelection band) +{ + float strength = p.strength * p.scale; + fade_target = clamp(fade_target, -1.0, 1.0); + float3 input_value = base_height_and_slope; + float3 height_and_slope = input_value; + float frequency = 1.0 / max(p.scale * p.cell_scale, 1.0e-10); + float2 slope = height_and_slope.yz; + float slope_length = max(length(slope), 1.0e-10); + float magnitude = 0.0; + float rounding_multiplier = 1.0; + float input_rounding = lerp(p.rounding.y, p.rounding.x, saturate(fade_target + 0.5)) * p.rounding.z; + float combined_mask = gamecult_geometry_erosion_ease_out(gamecult_geometry_erosion_smooth_start(slope_length * p.onset.x, input_rounding * p.onset.x)); + float ridge_mask = gamecult_geometry_erosion_ease_out(slope_length * p.onset.z); + float ridge_fade = fade_target; + float2 gully_slope = lerp(slope, slope / slope_length * p.assumed_slope.x, p.assumed_slope.y); + + int octave_count=min(min(max(p.octaves,0),8),max(band.active_octaves,0)); + [loop] for (int octave = 0; octave < octave_count; octave++) + { + float4 phacelle = gamecult_geometry_phacelle_noise(position * frequency, gamecult_geometry_erosion_safe_normalize(gully_slope), p.cell_scale, 0.25, p.normalization); + float2 derivative_direction = phacelle.zw * -frequency; + float sloping = abs(phacelle.y); + gully_slope += sign(phacelle.y) * derivative_direction * strength * p.gully_weight; + float3 gullies = float3(phacelle.x, phacelle.y * derivative_direction.x, phacelle.y * derivative_direction.y); + float3 faded = lerp(float3(fade_target, 0.0, 0.0), gullies * p.gully_weight, combined_mask); + float octave_weight=octave==octave_count-1?saturate(band.final_octave_weight):1.0; + height_and_slope += faded * strength * octave_weight; + magnitude += strength * octave_weight; + fade_target = faded.x; + float octave_rounding = lerp(p.rounding.y, p.rounding.x, saturate(phacelle.x + 0.5)) * rounding_multiplier; + float new_mask = gamecult_geometry_erosion_ease_out(gamecult_geometry_erosion_smooth_start(sloping * p.onset.y, octave_rounding * p.onset.y)); + combined_mask = gamecult_geometry_erosion_pow_inverse(combined_mask, p.detail) * new_mask; + ridge_fade = lerp(ridge_fade, lerp(ridge_fade, gullies.x, ridge_mask), octave_weight); + ridge_mask *= lerp(1.0, gamecult_geometry_erosion_ease_out(sloping * p.onset.w), octave_weight); + strength *= p.gain; + frequency *= p.lacunarity; + rounding_multiplier *= p.rounding.w; + } + + GameCultGeometryAdvancedErosionResult result; + result.delta = height_and_slope - input_value; + result.magnitude = magnitude; + result.ridge_map = ridge_fade * (1.0 - ridge_mask); + result.fade_target = fade_target; + return result; +} + +GameCultGeometryAdvancedErosionResult gamecult_geometry_advanced_erosion_filter(float2 position, float3 base_height_and_slope, float fade_target, GameCultGeometryAdvancedErosionParameters p) +{ + GameCultGeometryErosionBandSelection band; band.active_octaves=p.octaves; band.final_octave_weight=1.0; band.finest_included_wavelength=0.0; band.unresolved_height_bound=0.0; + return gamecult_geometry_advanced_erosion_filter_banded(position, base_height_and_slope, fade_target, p, band); +} + +#endif diff --git a/src/GameCult.Geometry/Shaders/AdvancedErosionFilter.hlsl.meta b/src/GameCult.Geometry/Shaders/AdvancedErosionFilter.hlsl.meta new file mode 100644 index 00000000..015c51c2 --- /dev/null +++ b/src/GameCult.Geometry/Shaders/AdvancedErosionFilter.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3252ac02e8853ef4b9d1fbc5204b5c6b +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/GameCult.Geometry/Shaders/GameCult.Geometry.hlsl b/src/GameCult.Geometry/Shaders/GameCult.Geometry.hlsl new file mode 100644 index 00000000..fb159077 --- /dev/null +++ b/src/GameCult.Geometry/Shaders/GameCult.Geometry.hlsl @@ -0,0 +1,14 @@ +#ifndef GAMECULT_GEOMETRY_HLSL +#define GAMECULT_GEOMETRY_HLSL + +#ifndef GAMECULT_GEOMETRY_CULTMATH_INCLUDE +#define GAMECULT_GEOMETRY_CULTMATH_INCLUDE "CultMath.hlsl" +#endif + +#include GAMECULT_GEOMETRY_CULTMATH_INCLUDE +#include "AdvancedErosionFilter.hlsl" +#include "Planetary.hlsl" +#include "SphericalErosion.hlsl" +#include "PlanetaryRadialRefinement.hlsl" + +#endif diff --git a/src/GameCult.Geometry/Shaders/GameCult.Geometry.hlsl.meta b/src/GameCult.Geometry/Shaders/GameCult.Geometry.hlsl.meta new file mode 100644 index 00000000..d685ccce --- /dev/null +++ b/src/GameCult.Geometry/Shaders/GameCult.Geometry.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b253fa50ddd34bf3b69fb323fe6e00e8 +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/GameCult.Geometry/Shaders/Planetary.hlsl b/src/GameCult.Geometry/Shaders/Planetary.hlsl new file mode 100644 index 00000000..8e16bfff --- /dev/null +++ b/src/GameCult.Geometry/Shaders/Planetary.hlsl @@ -0,0 +1,392 @@ +#ifndef GAMECULT_GEOMETRY_PLANETARY_HLSL +#define GAMECULT_GEOMETRY_PLANETARY_HLSL + +static const float GAMECULT_GEOMETRY_PLANETARY_QUARTER_PI = 0.78539816339744830962; + +float3 gamecult_geometry_planetary_face_direction(int face, float2 coordinate) +{ + float2 tangent = tan(coordinate * GAMECULT_GEOMETRY_PLANETARY_QUARTER_PI); + float3 cube = face == 0 ? float3(1.0, tangent.y, -tangent.x) + : face == 1 ? float3(-1.0, tangent.y, tangent.x) + : face == 2 ? float3(tangent.x, 1.0, -tangent.y) + : face == 3 ? float3(tangent.x, -1.0, tangent.y) + : face == 4 ? float3(tangent.x, tangent.y, 1.0) + : float3(-tangent.x, tangent.y, -1.0); + return cultmath_normalize(cube); +} + +float2 gamecult_geometry_planetary_face_coordinate(float3 direction, out int face) +{ + float3 d = cultmath_normalize(direction); + float3 a = abs(d); + float2 cube_uv; + if (a.x >= a.y && a.x >= a.z) + { + if (d.x >= 0.0) { face = 0; cube_uv = float2(-d.z, d.y) / a.x; } + else { face = 1; cube_uv = float2(d.z, d.y) / a.x; } + } + else if (a.y >= a.z) + { + if (d.y >= 0.0) { face = 2; cube_uv = float2(d.x, -d.z) / a.y; } + else { face = 3; cube_uv = float2(d.x, d.z) / a.y; } + } + else + { + if (d.z >= 0.0) { face = 4; cube_uv = d.xy / a.z; } + else { face = 5; cube_uv = float2(-d.x, d.y) / a.z; } + } + return atan(cube_uv) / GAMECULT_GEOMETRY_PLANETARY_QUARTER_PI; +} + +bool gamecult_geometry_planetary_page_local(float3 direction, float4 tile_address, float active, out float2 local) +{ + int face; + float2 uv = gamecult_geometry_planetary_face_coordinate(direction, face); + local = 0.0; + if (active < 0.5 || abs((float)face - tile_address.x) > 0.25) return false; + float axis_tiles = exp2(tile_address.y); + float2 scaled = (uv * 0.5 + 0.5) * axis_tiles; + float2 canonical = floor(min(scaled, axis_tiles - 1.0e-5)); + if (any(abs(canonical - tile_address.zw) > 0.25)) return false; + local = scaled - tile_address.zw; + return all(local >= 0.0) && all(local <= 1.0); +} + +float3 gamecult_geometry_planetary_surface_normal(float3 direction, float3 world_distance_tangent_gradient) +{ + direction = cultmath_normalize(direction); + float3 tangent_gradient = world_distance_tangent_gradient - direction * dot(world_distance_tangent_gradient, direction); + return cultmath_normalize(direction - tangent_gradient); +} + +float2 gamecult_geometry_planetary_equirectangular_forward(float3 direction) +{ + direction = cultmath_normalize(direction); + return float2(atan2(direction.y, direction.x) / CULTMATH_PI, asin(clamp(direction.z, -1.0, 1.0)) / CULTMATH_HALF_PI); +} + +float3 gamecult_geometry_planetary_equirectangular_inverse(float2 coordinate) +{ + float longitude = coordinate.x * CULTMATH_PI; + float latitude = coordinate.y * CULTMATH_HALF_PI; + float cos_latitude = cos(latitude); + return cultmath_normalize(float3(cos_latitude * cos(longitude), cos_latitude * sin(longitude), sin(latitude))); +} + +static const float GAMECULT_GEOMETRY_EQUAL_EARTH_A1 = 1.340264; +static const float GAMECULT_GEOMETRY_EQUAL_EARTH_A2 = -0.081106; +static const float GAMECULT_GEOMETRY_EQUAL_EARTH_A3 = 0.000893; +static const float GAMECULT_GEOMETRY_EQUAL_EARTH_A4 = 0.003796; +static const float GAMECULT_GEOMETRY_EQUAL_EARTH_M = 0.8660254037844386; +static const float GAMECULT_GEOMETRY_EQUAL_EARTH_X_MAX = 2.706629; +static const float GAMECULT_GEOMETRY_EQUAL_EARTH_Y_MAX = 1.3173628; + +float gamecult_geometry_equal_earth_y(float theta) +{ + float theta2 = theta * theta; + float theta6 = theta2 * theta2 * theta2; + return theta * (GAMECULT_GEOMETRY_EQUAL_EARTH_A1 + GAMECULT_GEOMETRY_EQUAL_EARTH_A2 * theta2 + theta6 * (GAMECULT_GEOMETRY_EQUAL_EARTH_A3 + GAMECULT_GEOMETRY_EQUAL_EARTH_A4 * theta2)); +} + +float2 gamecult_geometry_planetary_equal_earth_forward(float3 direction) +{ + direction = cultmath_normalize(direction); + float longitude = atan2(direction.y, direction.x); + float latitude = asin(clamp(direction.z, -1.0, 1.0)); + float theta = asin(GAMECULT_GEOMETRY_EQUAL_EARTH_M * sin(latitude)); + float theta2 = theta * theta; + float theta6 = theta2 * theta2 * theta2; + float denominator = GAMECULT_GEOMETRY_EQUAL_EARTH_M * (GAMECULT_GEOMETRY_EQUAL_EARTH_A1 + 3.0 * GAMECULT_GEOMETRY_EQUAL_EARTH_A2 * theta2 + theta6 * (7.0 * GAMECULT_GEOMETRY_EQUAL_EARTH_A3 + 9.0 * GAMECULT_GEOMETRY_EQUAL_EARTH_A4 * theta2)); + return float2(longitude * cos(theta) / denominator / GAMECULT_GEOMETRY_EQUAL_EARTH_X_MAX, gamecult_geometry_equal_earth_y(theta) / GAMECULT_GEOMETRY_EQUAL_EARTH_Y_MAX); +} + +float3 gamecult_geometry_planetary_equal_earth_inverse(float2 coordinate) +{ + float target_y = coordinate.y * GAMECULT_GEOMETRY_EQUAL_EARTH_Y_MAX; + float theta = target_y / GAMECULT_GEOMETRY_EQUAL_EARTH_A1; + [unroll] for (int iteration = 0; iteration < 8; iteration++) + { + float theta2 = theta * theta; + float theta6 = theta2 * theta2 * theta2; + float derivative = GAMECULT_GEOMETRY_EQUAL_EARTH_A1 + 3.0 * GAMECULT_GEOMETRY_EQUAL_EARTH_A2 * theta2 + theta6 * (7.0 * GAMECULT_GEOMETRY_EQUAL_EARTH_A3 + 9.0 * GAMECULT_GEOMETRY_EQUAL_EARTH_A4 * theta2); + theta -= (gamecult_geometry_equal_earth_y(theta) - target_y) / derivative; + } + float latitude = asin(clamp(sin(theta) / GAMECULT_GEOMETRY_EQUAL_EARTH_M, -1.0, 1.0)); + float theta2 = theta * theta; + float theta6 = theta2 * theta2 * theta2; + float denominator = GAMECULT_GEOMETRY_EQUAL_EARTH_M * (GAMECULT_GEOMETRY_EQUAL_EARTH_A1 + 3.0 * GAMECULT_GEOMETRY_EQUAL_EARTH_A2 * theta2 + theta6 * (7.0 * GAMECULT_GEOMETRY_EQUAL_EARTH_A3 + 9.0 * GAMECULT_GEOMETRY_EQUAL_EARTH_A4 * theta2)); + float longitude = coordinate.x * GAMECULT_GEOMETRY_EQUAL_EARTH_X_MAX * denominator / cos(theta); + float cos_latitude = cos(latitude); + return cultmath_normalize(float3(cos_latitude * cos(longitude), cos_latitude * sin(longitude), sin(latitude))); +} + +float gamecult_geometry_planetary_wrap_longitude(float longitude) +{ + longitude = fmod(longitude, CULTMATH_TAU); + if (longitude > CULTMATH_PI) longitude -= CULTMATH_TAU; + if (longitude < -CULTMATH_PI) longitude += CULTMATH_TAU; + return longitude; +} + +float3 gamecult_geometry_planetary_lon_lat_direction(float longitude, float latitude) +{ + float cos_latitude = cos(latitude); + return cultmath_normalize(float3(cos_latitude * cos(longitude), cos_latitude * sin(longitude), sin(latitude))); +} + +float gamecult_geometry_planetary_asinh(float value) { return log(value + sqrt(value * value + 1.0)); } +float gamecult_geometry_planetary_sinh(float value) { return 0.5 * (exp(value) - exp(-value)); } + +bool gamecult_geometry_planetary_azimuthal_forward(float3 direction, float2 center_lon_lat, int kind, out float2 coordinate) +{ + direction = cultmath_normalize(direction); + float longitude = gamecult_geometry_planetary_wrap_longitude(atan2(direction.y, direction.x) - center_lon_lat.x); + float latitude = asin(clamp(direction.z, -1.0, 1.0)); + float sin0 = sin(center_lon_lat.y), cos0 = cos(center_lon_lat.y); + float sin_latitude = sin(latitude), cos_latitude = cos(latitude), cos_longitude = cos(longitude); + float cos_c = clamp(sin0 * sin_latitude + cos0 * cos_latitude * cos_longitude, -1.0, 1.0); + float2 raw = float2(cos_latitude * sin(longitude), cos0 * sin_latitude - sin0 * cos_latitude * cos_longitude); + float factor = 1.0; + if (kind == 3) + { + if (cos_c < 0.0) { coordinate = 0.0; return false; } + } + else if (kind == 4) + { + float c = acos(cos_c); factor = (c < 1.0e-6 ? 1.0 : c / sin(c)) / CULTMATH_PI; + } + else if (kind == 5) factor = sqrt(2.0 / max(1.0 + cos_c, 1.0e-20)) * 0.5; + else + { + if (cos_c <= 0.0) { coordinate = 0.0; return false; } + factor = 1.0 / cos_c; + } + coordinate = raw * factor; + return true; +} + +bool gamecult_geometry_planetary_azimuthal_inverse(float2 coordinate, float2 center_lon_lat, int kind, out float3 direction) +{ + float rho = length(coordinate); + float c; + if (kind == 3) { if (rho > 1.0) { direction = 0.0; return false; } c = asin(clamp(rho, 0.0, 1.0)); } + else if (kind == 4) { if (rho > 1.0) { direction = 0.0; return false; } c = rho * CULTMATH_PI; } + else if (kind == 5) { if (rho > 1.0) { direction = 0.0; return false; } c = 2.0 * asin(clamp(rho, 0.0, 1.0)); } + else c = atan(rho); + if (rho < 1.0e-6) { direction = gamecult_geometry_planetary_lon_lat_direction(center_lon_lat.x, center_lon_lat.y); return true; } + float sin_c = sin(c), cos_c = cos(c), sin0 = sin(center_lon_lat.y), cos0 = cos(center_lon_lat.y); + float latitude = asin(clamp(cos_c * sin0 + coordinate.y * sin_c * cos0 / rho, -1.0, 1.0)); + float delta_longitude = atan2(coordinate.x * sin_c, rho * cos0 * cos_c - coordinate.y * sin0 * sin_c); + direction = gamecult_geometry_planetary_lon_lat_direction(gamecult_geometry_planetary_wrap_longitude(delta_longitude + center_lon_lat.x), latitude); + return true; +} + +bool gamecult_geometry_planetary_cube_atlas_forward(float3 direction, out float2 coordinate) +{ + int face; + float2 face_coordinate = gamecult_geometry_planetary_face_coordinate(direction, face); + int column = face % 3; + int row = face / 3; + coordinate = float2(-1.0 + (column + (face_coordinate.x + 1.0) * 0.5) * (2.0 / 3.0), 1.0 - (row + (face_coordinate.y + 1.0) * 0.5)); + return true; +} + +bool gamecult_geometry_planetary_cube_atlas_inverse(float2 coordinate, out float3 direction) +{ + if (any(coordinate < -1.0) || any(coordinate > 1.0)) { direction = 0.0; return false; } + int column = min((int)((coordinate.x + 1.0) * 1.5), 2); + int row = min((int)(1.0 - coordinate.y), 1); + float u = ((coordinate.x + 1.0) * 1.5 - column) * 2.0 - 1.0; + float v = ((1.0 - coordinate.y) - row) * 2.0 - 1.0; + direction = gamecult_geometry_planetary_face_direction(row * 3 + column, float2(u, v)); + return true; +} + +bool gamecult_geometry_planetary_projection_forward(float3 direction, int kind, float3 center_lon_lat_scale, out float2 coordinate) +{ + float scale = max(center_lon_lat_scale.z, 1.0e-20); + if (kind == 6) + { + bool valid = gamecult_geometry_planetary_cube_atlas_forward(direction, coordinate); + coordinate /= scale; return valid; + } + if (kind >= 3) + { + bool valid = gamecult_geometry_planetary_azimuthal_forward(direction, center_lon_lat_scale.xy, kind, coordinate); + coordinate /= scale; return valid; + } + direction = cultmath_normalize(direction); + float longitude = gamecult_geometry_planetary_wrap_longitude(atan2(direction.y, direction.x) - center_lon_lat_scale.x); + float latitude = asin(clamp(direction.z, -1.0, 1.0)); + if (kind == 0) coordinate = float2(longitude / CULTMATH_PI, latitude / CULTMATH_HALF_PI); + else if (kind == 1) + { + const float maximum_latitude = 1.4844222297453324; + if (abs(latitude) > maximum_latitude) { coordinate = 0.0; return false; } + coordinate = float2(longitude / CULTMATH_PI, gamecult_geometry_planetary_asinh(tan(latitude)) / CULTMATH_PI); + } + else + { + float3 centered = gamecult_geometry_planetary_lon_lat_direction(longitude, latitude); + coordinate = gamecult_geometry_planetary_equal_earth_forward(centered); + } + coordinate /= scale; + return true; +} + +bool gamecult_geometry_planetary_projection_inverse(float2 coordinate, int kind, float3 center_lon_lat_scale, out float3 direction) +{ + coordinate *= max(center_lon_lat_scale.z, 1.0e-20); + if (kind == 6) return gamecult_geometry_planetary_cube_atlas_inverse(coordinate, direction); + if (kind >= 3) return gamecult_geometry_planetary_azimuthal_inverse(coordinate, center_lon_lat_scale.xy, kind, direction); + if (any(abs(coordinate) > 1.0)) { direction = 0.0; return false; } + float longitude, latitude; + if (kind == 0) { longitude = coordinate.x * CULTMATH_PI; latitude = coordinate.y * CULTMATH_HALF_PI; } + else if (kind == 1) { longitude = coordinate.x * CULTMATH_PI; latitude = atan(gamecult_geometry_planetary_sinh(coordinate.y * CULTMATH_PI)); } + else + { + float3 centered = gamecult_geometry_planetary_equal_earth_inverse(coordinate); + longitude = atan2(centered.y, centered.x); latitude = asin(clamp(centered.z, -1.0, 1.0)); + } + direction = gamecult_geometry_planetary_lon_lat_direction(gamecult_geometry_planetary_wrap_longitude(longitude + center_lon_lat_scale.x), latitude); + return true; +} + +struct GameCultGeometryPlanetaryFieldDefinition +{ + float radius; + int seed; + GameCultGeometryAdvancedErosionParameters erosion; +}; + +struct GameCultGeometryPlanetaryBaseFieldSample +{ + float radial_displacement; + float3 radial_gradient; + float field_value; + float3 field_gradient; + float fade_target; +}; + +struct GameCultGeometryPlanetarySurfaceSample +{ + float radial_displacement; + float3 tangent_gradient; + float3 surface_normal; + float slope; + float ridge; + float gully; + float finest_resolved_wavelength; + float unresolved_height_bound; +}; + +struct GameCultGeometryPlanetaryPageSample +{ + float4 height_gradient; + float2 masks; +}; + +GameCultGeometryPlanetaryPageSample gamecult_geometry_planetary_page_lerp( + GameCultGeometryPlanetaryPageSample a, + GameCultGeometryPlanetaryPageSample b, + GameCultGeometryPlanetaryPageSample c, + GameCultGeometryPlanetaryPageSample d, + float2 fraction) +{ + GameCultGeometryPlanetaryPageSample result; + result.height_gradient = lerp(lerp(a.height_gradient, b.height_gradient, fraction.x), lerp(c.height_gradient, d.height_gradient, fraction.x), fraction.y); + result.masks = lerp(lerp(a.masks, b.masks, fraction.x), lerp(c.masks, d.masks, fraction.x), fraction.y); + return result; +} + +GameCultGeometryPlanetaryPageSample gamecult_geometry_planetary_residual_sample( + GameCultGeometryPlanetarySurfaceSample child, + GameCultGeometryPlanetarySurfaceSample parent, + bool has_parent) +{ + GameCultGeometryPlanetaryPageSample result; + result.height_gradient = float4(child.radial_displacement, child.tangent_gradient); + if (has_parent) result.height_gradient -= float4(parent.radial_displacement, parent.tangent_gradient); + result.masks = float2(child.ridge, child.gully); + return result; +} + +float4 gamecult_geometry_planetary_summary_empty() +{ + return float4(3.402823466e+38, -3.402823466e+38, 0.0, 0.0); +} + +float4 gamecult_geometry_planetary_summary_accumulate(float4 summary, float4 height_gradient, float unresolved_height) +{ + summary.x = min(summary.x, height_gradient.x); + summary.y = max(summary.y, height_gradient.x); + summary.z = max(summary.z, length(height_gradient.yzw)); + summary.w = max(summary.w, max(unresolved_height, 0.0)); + return summary; +} + +float gamecult_geometry_planetary_pow4(float value) { float square = value * value; return square * square; } + +GameCultGeometryPlanetarySurfaceSample gamecult_geometry_planetary_field_sample( + GameCultGeometryPlanetaryFieldDefinition definition, + float3 unit_direction, + GameCultGeometryPlanetaryBaseFieldSample base_sample, + float footprint_meters) +{ + float3 direction = cultmath_normalize(unit_direction); + float3 radial_gradient = base_sample.radial_gradient - direction * dot(base_sample.radial_gradient, direction); + float3 field_gradient = base_sample.field_gradient - direction * dot(base_sample.field_gradient, direction); + GameCultGeometryAdvancedErosionParameters p = definition.erosion; + GameCultGeometryErosionBandSelection band = gamecult_geometry_select_erosion_bands( + p.scale * p.cell_scale, footprint_meters, p.octaves, p.lacunarity, + p.strength * p.scale, p.gain, 2.0); + float3 powers = float3( + gamecult_geometry_planetary_pow4(abs(direction.x)), + gamecult_geometry_planetary_pow4(abs(direction.y)), + gamecult_geometry_planetary_pow4(abs(direction.z))); + float power_sum = max(powers.x + powers.y + powers.z, 1.0e-6); + float3 weights = powers / power_sum; + float3 world = direction * definition.radius; + float seed = (float)definition.seed; + GameCultGeometryAdvancedErosionResult xy = gamecult_geometry_advanced_erosion_filter_banded( + world.xy + float2(713.0 + seed * 0.754877666, -291.0 + seed * 0.569840296), + float3(base_sample.field_value, field_gradient.x, field_gradient.y), base_sample.fade_target, p, band); + GameCultGeometryAdvancedErosionResult yz = gamecult_geometry_advanced_erosion_filter_banded( + world.yz + float2(-431.0 + seed * 0.438289027, 887.0 + seed * 0.328438163), + float3(base_sample.field_value, field_gradient.y, field_gradient.z), base_sample.fade_target, p, band); + GameCultGeometryAdvancedErosionResult zx = gamecult_geometry_advanced_erosion_filter_banded( + world.zx + float2(197.0 + seed * 0.219783071, 557.0 + seed * 0.145898034), + float3(base_sample.field_value, field_gradient.z, field_gradient.x), base_sample.fade_target, p, band); + float erosion_height = xy.delta.x * weights.z + yz.delta.x * weights.x + zx.delta.x * weights.y; + float3 erosion_gradient = float3( + xy.delta.y * weights.z + zx.delta.z * weights.y, + xy.delta.z * weights.z + yz.delta.y * weights.x, + yz.delta.z * weights.x + zx.delta.y * weights.y); + float3 power_gradient_x = float3(4.0 * direction.x * direction.x * direction.x / definition.radius, 0.0, 0.0); + float3 power_gradient_y = float3(0.0, 4.0 * direction.y * direction.y * direction.y / definition.radius, 0.0); + float3 power_gradient_z = float3(0.0, 0.0, 4.0 * direction.z * direction.z * direction.z / definition.radius); + power_gradient_x -= direction * dot(power_gradient_x, direction); + power_gradient_y -= direction * dot(power_gradient_y, direction); + power_gradient_z -= direction * dot(power_gradient_z, direction); + float3 power_sum_gradient = power_gradient_x + power_gradient_y + power_gradient_z; + float inverse_power_sum_squared = 1.0 / (power_sum * power_sum); + float3 weight_gradient_x = (power_gradient_x * power_sum - power_sum_gradient * powers.x) * inverse_power_sum_squared; + float3 weight_gradient_y = (power_gradient_y * power_sum - power_sum_gradient * powers.y) * inverse_power_sum_squared; + float3 weight_gradient_z = (power_gradient_z * power_sum - power_sum_gradient * powers.z) * inverse_power_sum_squared; + erosion_gradient += yz.delta.x * weight_gradient_x + zx.delta.x * weight_gradient_y + xy.delta.x * weight_gradient_z; + float3 gradient = radial_gradient + erosion_gradient; + gradient -= direction * dot(gradient, direction); + float ridge_evidence = xy.ridge_map * weights.z + yz.ridge_map * weights.x + zx.ridge_map * weights.y; + GameCultGeometryPlanetarySurfaceSample result; + result.radial_displacement = base_sample.radial_displacement + erosion_height; + result.tangent_gradient = gradient; + result.surface_normal = gamecult_geometry_planetary_surface_normal(direction, gradient); + result.slope = length(gradient); + result.ridge = saturate(ridge_evidence * 0.5 + 0.5); + result.gully = saturate(0.5 - ridge_evidence * 0.5); + result.finest_resolved_wavelength = band.finest_included_wavelength; + result.unresolved_height_bound = band.unresolved_height_bound; + return result; +} + +#endif diff --git a/src/GameCult.Geometry/Shaders/Planetary.hlsl.meta b/src/GameCult.Geometry/Shaders/Planetary.hlsl.meta new file mode 100644 index 00000000..009c2989 --- /dev/null +++ b/src/GameCult.Geometry/Shaders/Planetary.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: bb055ad5328888e479e90ae3fe62c3fe +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/GameCult.Geometry/Shaders/PlanetaryRadialRefinement.hlsl b/src/GameCult.Geometry/Shaders/PlanetaryRadialRefinement.hlsl new file mode 100644 index 00000000..20f3e2e5 --- /dev/null +++ b/src/GameCult.Geometry/Shaders/PlanetaryRadialRefinement.hlsl @@ -0,0 +1,27 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef GAMECULT_GEOMETRY_PLANETARY_RADIAL_REFINEMENT_HLSL +#define GAMECULT_GEOMETRY_PLANETARY_RADIAL_REFINEMENT_HLSL + +float3 gamecult_geometry_planetary_radial_refinement_step( + float3 position, + float3 ray_direction, + float3 center, + float target_radius, + float minimum_derivative, + float maximum_correction) +{ + float3 local=position-center; + float radius=length(local); + float3 radial=local/max(radius,0.0001); + float error=radius-target_radius; + float derivative=dot(ray_direction,radial); + float safe_minimum=max(minimum_derivative,0.0001); + float safe_derivative=abs(derivative)>safe_minimum?derivative:(derivative<0?-safe_minimum:safe_minimum); + float correction=clamp(-error/safe_derivative,-abs(maximum_correction),abs(maximum_correction)); + return position+ray_direction*correction; +} + +#endif diff --git a/src/GameCult.Geometry/Shaders/PlanetaryRadialRefinement.hlsl.meta b/src/GameCult.Geometry/Shaders/PlanetaryRadialRefinement.hlsl.meta new file mode 100644 index 00000000..28d629b1 --- /dev/null +++ b/src/GameCult.Geometry/Shaders/PlanetaryRadialRefinement.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 356389371b854e12b9d419f7ee310d81 +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/GameCult.Geometry/Shaders/SphericalErosion.hlsl b/src/GameCult.Geometry/Shaders/SphericalErosion.hlsl new file mode 100644 index 00000000..107ba24b --- /dev/null +++ b/src/GameCult.Geometry/Shaders/SphericalErosion.hlsl @@ -0,0 +1,80 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef GAMECULT_GEOMETRY_SPHERICAL_EROSION_HLSL +#define GAMECULT_GEOMETRY_SPHERICAL_EROSION_HLSL + +struct GameCultGeometrySphericalErosionParameters +{ + float frequency; float amplitude; float lacunarity; float gain; + float slope_strength; float detail; float seed; int octaves; +}; + +struct GameCultGeometrySphericalErosionSample +{ + float height_offset; float ridge; float gully; float3 gradient; +}; + +float gamecult_geometry_spherical_cell_wave(float3 position, float3 flow, float3 cell, float seed) +{ + float3 pivot = cell + float3(cultmath_hash(cell + seed + 11.7), cultmath_hash(cell.yzx + seed + 37.1), cultmath_hash(cell.zyx + seed + 73.9)); + return dot(position - pivot, flow) * 6.28318530718 + cultmath_hash(cell + seed + 101.3) * 6.28318530718; +} + +float gamecult_geometry_spherical_directional_wave(float3 position, float3 flow, float seed) +{ + float3 cell = floor(position); + float3 local = cultmath_frac(position); + float3 weights = local * local * (3.0 - 2.0 * local); + float z0 = cultmath_lerp( + cultmath_lerp(gamecult_geometry_spherical_cell_wave(position, flow, cell + float3(0,0,0), seed), gamecult_geometry_spherical_cell_wave(position, flow, cell + float3(1,0,0), seed), weights.x), + cultmath_lerp(gamecult_geometry_spherical_cell_wave(position, flow, cell + float3(0,1,0), seed), gamecult_geometry_spherical_cell_wave(position, flow, cell + float3(1,1,0), seed), weights.x), weights.y); + float z1 = cultmath_lerp( + cultmath_lerp(gamecult_geometry_spherical_cell_wave(position, flow, cell + float3(0,0,1), seed), gamecult_geometry_spherical_cell_wave(position, flow, cell + float3(1,0,1), seed), weights.x), + cultmath_lerp(gamecult_geometry_spherical_cell_wave(position, flow, cell + float3(0,1,1), seed), gamecult_geometry_spherical_cell_wave(position, flow, cell + float3(1,1,1), seed), weights.x), weights.y); + return cultmath_lerp(z0, z1, weights.z); +} + +float3 gamecult_geometry_spherical_stable_tangent(float3 position) +{ + float3 axis = abs(position.z) < 0.8 ? float3(0,0,1) : float3(0,1,0); + return cultmath_normalize(cross(axis, position)); +} + +GameCultGeometrySphericalErosionSample gamecult_geometry_spherical_erosion(float3 unit_position, float base_height, float3 base_gradient, GameCultGeometrySphericalErosionParameters p) +{ + float3 position = cultmath_normalize(unit_position); + float3 gradient = base_gradient - position * dot(base_gradient, position); + float slope = length(gradient); + float3 flow = slope > 1.0e-6 ? -gradient / slope : gamecult_geometry_spherical_stable_tangent(position); + float frequency = max(p.frequency, 0.001); + float amplitude = p.amplitude; + float combi_mask = 1.0 - pow(1.0 - cultmath_saturate(slope * p.slope_strength), 2.0); + float fade_target = cultmath_saturate(base_height * 0.5 + 0.5) * 2.0 - 1.0; + GameCultGeometrySphericalErosionSample result = (GameCultGeometrySphericalErosionSample)0; + [loop] for (int octave = 0; octave < min(max(p.octaves, 0), 8); octave++) + { + float phase = gamecult_geometry_spherical_directional_wave(position * frequency, flow, p.seed + octave * 19.19); + float wave = cos(phase); + float wave_slope = sin(phase); + float faded = cultmath_lerp(fade_target, wave, combi_mask); + result.height_offset += faded * amplitude; + result.ridge = max(result.ridge, cultmath_saturate(faded)); + result.gully = max(result.gully, cultmath_saturate(-faded)); + float3 across = cultmath_normalize(cross(position, flow)); + gradient += across * (sign(wave_slope) * amplitude * frequency * combi_mask); + gradient -= position * dot(gradient, position); + slope = length(gradient); + flow = slope > 1.0e-6 ? -gradient / slope : gamecult_geometry_spherical_stable_tangent(position); + float new_mask = 1.0 - pow(1.0 - cultmath_saturate(abs(wave_slope) * 1.35), 2.0); + combi_mask = (1.0 - pow(1.0 - cultmath_saturate(combi_mask), max(p.detail, 0.001))) * new_mask; + fade_target = faded; + frequency *= max(p.lacunarity, 1.01); + amplitude *= cultmath_saturate(p.gain); + } + result.gradient = gradient; + return result; +} + +#endif diff --git a/src/GameCult.Geometry/Shaders/SphericalErosion.hlsl.meta b/src/GameCult.Geometry/Shaders/SphericalErosion.hlsl.meta new file mode 100644 index 00000000..7b7ddc79 --- /dev/null +++ b/src/GameCult.Geometry/Shaders/SphericalErosion.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 43d458fc5b6b441a941e37001df919e3 +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/GameCult.Geometry/THIRD-PARTY-NOTICES.md b/src/GameCult.Geometry/THIRD-PARTY-NOTICES.md new file mode 100644 index 00000000..3388b601 --- /dev/null +++ b/src/GameCult.Geometry/THIRD-PARTY-NOTICES.md @@ -0,0 +1,24 @@ +# GameCult.Geometry source provenance + +## CultMath planetary geometry + +The C# files under `Planetary/` and the HLSL files under `Shaders/` are licensed +under the Mozilla Public License 2.0 and retain MPL-2.0 notices. CultMath owns +the numeric primitives used by these geometry systems; GameCult.Geometry owns +their spatial meaning. + +## Advanced Terrain Erosion Filter + +`Planetary/AdvancedErosionFilter.cs` and `Shaders/AdvancedErosionFilter.hlsl` +adapt the mathematical procedure from +Rune Skovbo Johansen's **Advanced Terrain Erosion Filter**. + +- Copyright 2025 Rune Skovbo Johansen. +- Upstream: +- Explanation: +- License: Mozilla Public License 2.0, + +The implementation includes C#/HLSL type lowering, bounded octave counts, +finite zero-rounding behavior, and a shared integer avalanche hash for CPU/GPU +cell-selection parity. The technique builds on earlier work credited upstream +to Fewes and Clay John; the hash form follows public shader math by Inigo Quilez. diff --git a/src/GameCult.Geometry/docs/planetary.md b/src/GameCult.Geometry/docs/planetary.md new file mode 100644 index 00000000..94eab553 --- /dev/null +++ b/src/GameCult.Geometry/docs/planetary.md @@ -0,0 +1,135 @@ +# Planetary Field Runtime + +GameCult.Geometry owns the deterministic, renderer-independent planetary field. The same +definition can be queried by a CPU simulation, baked into residual pages, +sampled through a map projection, or evaluated by HLSL. Render resources and +gameplay interpretation remain consumer responsibilities. + +## Authority + +- `PlanetaryFieldDefinition` identifies radius, seed, erosion parameters, and a + version that includes the consumer-owned base-field version. +- `IPlanetaryBaseField` supplies deterministic application-authored base + evidence without making Geometry depend on an application. +- `PlanetaryQueryScale` makes the physical footprint and accepted unresolved + error explicit. There is deliberately no scale-free authoritative + `HeightAt` call. +- `PlanetarySurfaceSample` carries displacement, tangent gradient, normal, + slope, ridge/gully evidence, resolved wavelength, and unresolved bound. +- pages, residency, patches, and map tiles are disposable lowerings of that + contract. + +The C# surface targets .NET and Unity-compatible `netstandard2.1`. The matching +HLSL lives in `Shaders/Planetary.hlsl`. Consumers include +`Shaders/GameCult.Geometry.hlsl`, which imports CultMath's numeric mirror before +the geometry kernels. + +## Point and batch queries + +```csharp +var erosion = AdvancedErosionParameters.Default with +{ + Scale = radius * 0.075f, + Strength = 0.12f, + Octaves = 7, +}; +var field = PlanetaryFieldDefinition.Create( + baseFieldVersion: 17, + radius, + seed: 42, + erosion); +var scale = PlanetaryQueryScale.AtFootprint( + footprintMeters: 10, + maximumUnresolvedHeight: 0.5f); + +PlanetaryBaseFieldSample basis = source.Sample(direction); +PlanetarySurfaceSample sample = PlanetaryField.Sample( + field, direction, basis, scale); +``` + +`PlanetaryField.SampleBatch` writes into a caller-owned span. `SamplePosition` +accepts `double3`, reduces the astronomical position to a stable unit direction, +and then evaluates the same float field contract. + +Higher-level CPU queries include bounded ray intersection, segment clearance, +great-circle profiles, and region summaries. Their answers remain field queries; +only a consuming simulation can turn them into committed game consequences. + +## Cube-sphere topology and pages + +`PlanetaryTopology` owns the tangent/QSC cube-sphere mapping, inverse face +coordinates, tile selection, local page coordinates, and radial-graph surface +normal. `PlanetaryPageSampling` owns bordered directions, nominal spacing, +bilinear sampling, and summaries. + +`PlanetaryPageBaker` evaluates a root page at its physical sample spacing. A +child stores `child filtered field - parent filtered field`. A +`PlanetaryPageSetSampling` query adds every containing ancestor contribution +and applies transition weights only to residuals. + +`PlanetaryLodSelector` selects six roots plus one camera-facing ancestor chain +from the unresolved-height error. `PlanetaryResidualResidency` owns arrival and +departure presentation weights, content and presentation versions, and nothing +about field truth. + +## Patches + +`PlanetaryPatch.CreateFace` and `CreateCubeSphere` produce renderer-neutral +coarse meshes from the canonical topology. HLSL calls +`gamecult_geometry_planetary_face_direction` for procedural vertices and +`gamecult_geometry_planetary_radial_refinement_step` for bounded pixel refinement. + +Renderers still own cameras, clip space, depth, materials, buffers, dispatch, +and draw submission. + +`PlanetaryGpuPageBuilder` owns the renderer-neutral page input and metadata +payload. Host adapters may convert its `float4` values to native vector types, +but do not recalculate directions, spacing, addressing, or transition state. + +The `GameCult.Geometry.Unity` assembly in `org.gamecult.geometry` converts a canonical face patch into a +Unity `Mesh` and converts the shared GPU payload into Unity-native structs. It +owns no field parameters, page selection, or simulation state. The package's +Planetary Field Viewer sample renders the shared HLSL field and reports matching +CPU queries. Unity render code remains responsible for allocating/binding +graphics buffers and dispatching application-specific base-field entry points. +The host Unity project must set `-langversion:latest` in `Assets/csc.rsp`. + +## Maps + +`PlanetaryProjection` supplies forward and inverse transforms for: + +- equirectangular; +- Web Mercator with an explicit polar cutoff; +- Equal Earth; +- orthographic; +- azimuthal equidistant and equal-area; +- cube atlas; +- local tangent/gnomonic views. + +`PlanetaryMapTileBaker` maps each valid tile sample through the inverse +projection and canonical field query. `PlanetaryMapTileKey` includes field, +projection, layer, layout, and query-scale identity. Palettes, contours, labels, +and strategic overlays do not enter GameCult.Geometry's canonical field. + +`PlanetaryMapTileEncoding` writes the resulting evidence as a versioned +little-endian `CMPT` binary asset. +`packages/gamecult-geometry-ts/src/planetary-tile.ts` decodes that exact format +into browser-native values without defining another terrain generator. +Cross-runtime fixtures are generated by +`tools/GameCult.Geometry.PlanetaryTileFixture`. +Typed CultMesh documents should carry the tile key and asset reference; the +binary payload is derived CDN/cache data, not committed game state. + +## Numeric contract + +Integer hashes and published field versions are exact. Basic arithmetic follows +CultMath's matched C#/HLSL semantics. Hardware transcendental functions such as +`atan` and `tan` use measured tolerances rather than fictional bit identity. +Every filtered terrain query carries an unresolved-height bound so consumers can +reject insufficient fidelity explicitly. + +Current D3D12 parity evidence covers the advanced erosion kernel, QSC topology, +and forward/inverse transforms for every supported map projection, including +center and scale parameters. Production page and patch shaders use the common +functions and retain their seam, residual, summary, and radial-hit integration +probes in Fensalir. diff --git a/tests/GameCult.Geometry.Planetary.Tests/AdvancedErosionFilterTests.cs b/tests/GameCult.Geometry.Planetary.Tests/AdvancedErosionFilterTests.cs new file mode 100644 index 00000000..de5ccfb0 --- /dev/null +++ b/tests/GameCult.Geometry.Planetary.Tests/AdvancedErosionFilterTests.cs @@ -0,0 +1,47 @@ +using Xunit; + +using CultMath; +using GameCult.Geometry; + +namespace GameCult.Geometry.Planetary.Tests; + +public sealed class AdvancedErosionFilterTests +{ + [Fact] + public void DefaultReferenceFixtureIsStable() + { + var result = AdvancedErosionFilter.Sample( + new float2(0.42f, 0.31f), + new float3(0.5f, 0.1f, -0.2f), + 0.0f, + AdvancedErosionParameters.Default); + + Assert.Equal(0.0639375f, result.Magnitude, precision: 7); + Assert.True(float.IsFinite(result.Delta.x)); + Assert.True(float.IsFinite(result.Delta.y)); + Assert.True(float.IsFinite(result.Delta.z)); + Assert.InRange(result.RidgeMap, -1.0f, 1.0f); + } + + [Fact] + public void FlatInputAndZeroRoundingRemainFinite() + { + var parameters = AdvancedErosionParameters.Default with { Rounding = float4.zero }; + var result = AdvancedErosionFilter.Sample(new float2(0.25f, 0.75f), float3.zero, 0.0f, parameters); + + Assert.True(float.IsFinite(result.Delta.x)); + Assert.True(float.IsFinite(result.RidgeMap)); + Assert.True(float.IsFinite(result.FadeTarget)); + } + + [Fact] + public void PhacellePartialNormalizationIsFiniteAtEndpoints() + { + foreach (var normalization in new[] { 0.0f, 0.5f, 1.0f }) + { + var sample = AdvancedErosionFilter.Phacelle(new float2(1.7f, -3.2f), new float2(0.6f, -0.8f), 0.7f, 0.25f, normalization); + Assert.True(float.IsFinite(sample.x)); + Assert.True(float.IsFinite(sample.y)); + } + } +} diff --git a/tests/GameCult.Geometry.Planetary.Tests/ErosionFrequencyBandsTests.cs b/tests/GameCult.Geometry.Planetary.Tests/ErosionFrequencyBandsTests.cs new file mode 100644 index 00000000..b17a2292 --- /dev/null +++ b/tests/GameCult.Geometry.Planetary.Tests/ErosionFrequencyBandsTests.cs @@ -0,0 +1,37 @@ +using Xunit; + +using CultMath; +using GameCult.Geometry; + +namespace GameCult.Geometry.Planetary.Tests; + +public sealed class ErosionFrequencyBandsTests +{ + [Fact] + public void RadiusIndependentWorldWavelengthSelectsSameBands() + { + var small = ErosionFrequencyBands.Select(1_000.0f, 100.0f, 8, 2.0f, 20.0f, 0.5f); + var large = ErosionFrequencyBands.Select(1_000.0f, 100.0f, 8, 2.0f, 20.0f, 0.5f); + Assert.Equal(small, large); + Assert.Equal(3, small.ActiveOctaves); + } + + [Fact] + public void TransitionPartiallyWeightsLastResolvableOctave() + { + var selection = ErosionFrequencyBands.Select(1_000.0f, 50.0f, 8, 2.0f, 1.0f, 0.5f); + Assert.Equal(4, selection.ActiveOctaves); + Assert.InRange(selection.FinalOctaveWeight, 0.0f, 1.0f); + Assert.True(selection.UnresolvedHeightBound > 0.0f); + } + + [Fact] + public void BandedFilterPreservesLowOctaveResultExactly() + { + var p = AdvancedErosionParameters.Default; + var band = new ErosionBandSelection(2, 1.0f, 0.0f, 0.0f); + var banded = AdvancedErosionFilter.Sample(new float2(0.42f, 0.31f), new float3(0.5f, 0.1f, -0.2f), 0.0f, p, band); + var truncated = AdvancedErosionFilter.Sample(new float2(0.42f, 0.31f), new float3(0.5f, 0.1f, -0.2f), 0.0f, p with { Octaves = 2 }); + Assert.Equal(truncated, banded); + } +} diff --git a/tests/GameCult.Geometry.Planetary.Tests/GameCult.Geometry.Planetary.Tests.csproj b/tests/GameCult.Geometry.Planetary.Tests/GameCult.Geometry.Planetary.Tests.csproj new file mode 100644 index 00000000..b2511182 --- /dev/null +++ b/tests/GameCult.Geometry.Planetary.Tests/GameCult.Geometry.Planetary.Tests.csproj @@ -0,0 +1,18 @@ + + + net10.0 + enable + enable + false + + + + + + + + + + + + diff --git a/tests/GameCult.Geometry.Planetary.Tests/PlanetaryFieldTests.cs b/tests/GameCult.Geometry.Planetary.Tests/PlanetaryFieldTests.cs new file mode 100644 index 00000000..ba934f33 --- /dev/null +++ b/tests/GameCult.Geometry.Planetary.Tests/PlanetaryFieldTests.cs @@ -0,0 +1,83 @@ +using Xunit; + +using CultMath; +using GameCult.Geometry; + +namespace GameCult.Geometry.Planetary.Tests; + +public sealed class PlanetaryFieldTests +{ + private static readonly PlanetaryFieldDefinition Definition = new( + 0x7f59_6d11_02ab_9c31UL, + 8.4f, + 42, + AdvancedErosionParameters.Default with { Scale = 0.63f, Strength = 0.12f, Octaves = 7 }); + + [Fact] + public void SampleIsDeterministicScaleAwareAndTangent() + { + var direction = math.normalize(new float3(0.31f, -0.72f, 0.61f)); + var source = new FixtureField(); + var coarse = PlanetaryField.Sample(Definition, direction, source.Sample(direction), PlanetaryQueryScale.AtFootprint(0.1f)); + var fine = PlanetaryField.Sample(Definition, direction, source.Sample(direction), PlanetaryQueryScale.AtFootprint(0.01f)); + var repeated = PlanetaryField.Sample(Definition, direction, source.Sample(direction), PlanetaryQueryScale.AtFootprint(0.01f)); + + Assert.Equal(fine, repeated); + Assert.Equal(Definition.FieldVersion, fine.FieldVersion); + Assert.True(fine.UnresolvedHeightBound <= coarse.UnresolvedHeightBound); + Assert.True(fine.FinestResolvedWavelength <= coarse.FinestResolvedWavelength); + Assert.InRange(MathF.Abs(math.dot(fine.UnitDirection, fine.TangentGradient)), 0, 2.0e-5f); + Assert.Equal(1, math.length(fine.SurfaceNormal), 5); + } + + [Fact] + public void BatchAndDoublePositionUseThePointContract() + { + var directions = new[] + { + math.normalize(new float3(1, 2, 3)), + math.normalize(new float3(-2, 0.5f, 1)), + math.normalize(new float3(0.1f, -0.2f, -1)), + }; + var output = new PlanetarySurfaceSample[directions.Length]; + var source = new FixtureField(); + var scale = PlanetaryQueryScale.AtFootprint(0.05f); + PlanetaryField.SampleBatch(Definition, directions, scale, source, output); + + for (var i = 0; i < directions.Length; i++) + { + var normalized = math.normalize(directions[i]); + var expected = PlanetaryField.Sample(Definition, normalized, source.Sample(normalized), scale); + Assert.InRange(MathF.Abs(expected.RadialDisplacement - output[i].RadialDisplacement), 0, 1.0e-6f); + Assert.InRange(math.distance(expected.TangentGradient, output[i].TangentGradient), 0, 1.0e-6f); + } + + var d = directions[0]; + var position = new double3(d.x * 8.0e11, d.y * 8.0e11, d.z * 8.0e11); + var positioned = PlanetaryField.SamplePosition(Definition, position, scale, source); + Assert.InRange(math.distance(positioned.UnitDirection, d), 0, 2.0e-6f); + } + + [Fact] + public void FieldIdentityChangesWithEveryLoadBearingInput() + { + var erosion = AdvancedErosionParameters.Default; + var baseline = PlanetaryFieldDefinition.Create(3, 8.4f, 7, erosion); + Assert.Equal(baseline.FieldVersion, PlanetaryFieldDefinition.Create(3, 8.4f, 7, erosion).FieldVersion); + Assert.NotEqual(baseline.FieldVersion, PlanetaryFieldDefinition.Create(4, 8.4f, 7, erosion).FieldVersion); + Assert.NotEqual(baseline.FieldVersion, PlanetaryFieldDefinition.Create(3, 8.5f, 7, erosion).FieldVersion); + Assert.NotEqual(baseline.FieldVersion, PlanetaryFieldDefinition.Create(3, 8.4f, 8, erosion).FieldVersion); + Assert.NotEqual(baseline.FieldVersion, PlanetaryFieldDefinition.Create(3, 8.4f, 7, erosion with { Gain = 0.49f }).FieldVersion); + } + + private readonly struct FixtureField : IPlanetaryBaseField + { + public PlanetaryBaseFieldSample Sample(float3 direction) + { + var value = direction.x * 0.6f + direction.y * direction.z * 0.3f; + var fieldGradient = new float3(0.6f, direction.z * 0.3f, direction.y * 0.3f); + fieldGradient -= direction * math.dot(fieldGradient, direction); + return new(value * 0.1f, fieldGradient * 0.1f, value, fieldGradient, math.clamp(value, -1, 1)); + } + } +} diff --git a/tests/GameCult.Geometry.Planetary.Tests/PlanetaryGpuPageTests.cs b/tests/GameCult.Geometry.Planetary.Tests/PlanetaryGpuPageTests.cs new file mode 100644 index 00000000..1a8f96ef --- /dev/null +++ b/tests/GameCult.Geometry.Planetary.Tests/PlanetaryGpuPageTests.cs @@ -0,0 +1,28 @@ +using Xunit; + +using CultMath; +using GameCult.Geometry; + +namespace GameCult.Geometry.Planetary.Tests; + +public sealed class PlanetaryGpuPageTests +{ + [Fact] + public void UploadContentUsesCanonicalDirectionsSpacingAndMetadata() + { + var layout = new PlanetaryPageLayout(new(PlanetaryCubeFace.NegativeY, 3, 4, 2), 9, 2); + var content = PlanetaryGpuPageBuilder.BuildContent(layout, 8.4f); + Assert.Equal(layout.StorageSize * layout.StorageSize, content.Inputs.Length); + Assert.True(content.ParentSampleSpacing > content.SampleSpacing); + var first = content.Inputs[0]; + Assert.Equal(PlanetaryPageSampling.Direction(layout, 0, 0), first.DirectionRadius.xyz); + Assert.Equal(8.4f, first.DirectionRadius.w); + Assert.Equal(content.SampleSpacing, first.Sampling.x); + Assert.Equal(content.ParentSampleSpacing, first.Sampling.y); + + var metadata = PlanetaryGpuPageBuilder.Metadata(content, 37, 0.25f); + Assert.Equal(new float4((int)layout.Tile.Face, layout.Tile.Level, layout.Tile.X, layout.Tile.Y), metadata.Address); + Assert.Equal(new float4(37, layout.StorageSize, layout.InteriorSize, layout.BorderSize), metadata.Layout); + Assert.Equal(0.25f, metadata.State.y); + } +} diff --git a/tests/GameCult.Geometry.Planetary.Tests/PlanetaryMapTileEncodingTests.cs b/tests/GameCult.Geometry.Planetary.Tests/PlanetaryMapTileEncodingTests.cs new file mode 100644 index 00000000..5b7f2397 --- /dev/null +++ b/tests/GameCult.Geometry.Planetary.Tests/PlanetaryMapTileEncodingTests.cs @@ -0,0 +1,55 @@ +using System.IO; +using Xunit; + +using CultMath; +using GameCult.Geometry; + +namespace GameCult.Geometry.Planetary.Tests; + +public sealed class PlanetaryMapTileEncodingTests +{ + [Fact] + public void BinaryTileRoundTripsIdentityValidityAndSurfaceEvidence() + { + var field = PlanetaryFieldDefinition.Create(5, 10, 3, AdvancedErosionParameters.Default); + var layout = new PlanetaryMapTileLayout(new(PlanetaryProjectionKind.EqualEarth), 1, 1, 0, 5, 1); + var key = new PlanetaryMapTileKey(field.FieldVersion, 2, 17, layout, PlanetaryQueryScale.AtFootprint(0.25f, 0.1f)); + var tile = PlanetaryMapTileBaker.Bake(field, key, new FlatField()); + using var bytes = new MemoryStream(); + PlanetaryMapTileEncoding.Write(bytes, tile, leaveOpen: true); + bytes.Position = 0; + var decoded = PlanetaryMapTileEncoding.Read(bytes); + + Assert.Equal(tile.Key, decoded.Key); + Assert.Equal(tile.Validity, decoded.Validity); + for (var i = 0; i < tile.Samples.Length; i++) + if (tile.Validity[i]) Assert.Equal(tile.Samples[i], decoded.Samples[i]); + } + + [Fact] + public void DecoderRejectsForeignMagicAndVersions() + { + Assert.Throws(() => PlanetaryMapTileEncoding.Read(new MemoryStream(new byte[] { 1, 2, 3, 4, 1, 0, 0, 0 }))); + var bytes = new byte[] { (byte)'C', (byte)'M', (byte)'P', (byte)'T', 99, 0, 0, 0 }; + Assert.Throws(() => PlanetaryMapTileEncoding.Read(new MemoryStream(bytes))); + } + + [Fact] + public void DecoderRejectsTrailingBytes() + { + var field = PlanetaryFieldDefinition.Create(2, 1, 0, AdvancedErosionParameters.Default); + var layout = new PlanetaryMapTileLayout(new(PlanetaryProjectionKind.Equirectangular), 0, 0, 0, 2, 0); + var key = new PlanetaryMapTileKey(field.FieldVersion, 1, 0, layout, PlanetaryQueryScale.AtFootprint(1)); + var tile = PlanetaryMapTileBaker.Bake(field, key, new FlatField()); + using var bytes = new MemoryStream(); + PlanetaryMapTileEncoding.Write(bytes, tile, leaveOpen: true); + bytes.WriteByte(0xff); + bytes.Position = 0; + Assert.Throws(() => PlanetaryMapTileEncoding.Read(bytes)); + } + + private readonly struct FlatField : IPlanetaryBaseField + { + public PlanetaryBaseFieldSample Sample(float3 direction) => new(0, float3.zero, 0, float3.zero, 0); + } +} diff --git a/tests/GameCult.Geometry.Planetary.Tests/PlanetaryPageTests.cs b/tests/GameCult.Geometry.Planetary.Tests/PlanetaryPageTests.cs new file mode 100644 index 00000000..88ae15c1 --- /dev/null +++ b/tests/GameCult.Geometry.Planetary.Tests/PlanetaryPageTests.cs @@ -0,0 +1,60 @@ +using Xunit; + +using CultMath; +using GameCult.Geometry; + +namespace GameCult.Geometry.Planetary.Tests; + +public sealed class PlanetaryPageTests +{ + [Fact] + public void BilinearSamplingAndSummaryUseOnePageContract() + { + var layout = new PlanetaryPageLayout(new(PlanetaryCubeFace.PositiveZ, 0, 0, 0), 3, 1); + var samples = new PlanetaryPageSample[layout.StorageSize * layout.StorageSize]; + for (var y = 0; y < layout.StorageSize; y++) + for (var x = 0; x < layout.StorageSize; x++) + samples[y * layout.StorageSize + x] = new(x + y * 10, new float3(x, y, 0), x / 10.0f, y / 10.0f); + + var sample = PlanetaryPageSampling.Bilinear(samples, layout, new float2(0.25f, 0.75f)); + Assert.Equal(26.5f, sample.Height, 4); + Assert.Equal(new float3(1.5f, 2.5f, 0), sample.TangentGradient); + var summary = PlanetaryPageSampling.Summarize(samples, layout, 0.125f); + Assert.Equal(0, summary.MinimumHeight); + Assert.Equal(44, summary.MaximumHeight); + Assert.Equal(0.125f, summary.UnresolvedHeightBound); + Assert.True(summary.MaximumSlope > 0); + } + + [Fact] + public void ChildPageStoresOnlyResidualAndComposesBackToDirectField() + { + var field = new PlanetaryFieldDefinition(7, 8.4f, 3, AdvancedErosionParameters.Default with + { + Scale = 0.63f, + Strength = 0.12f, + Octaves = 7, + }); + var source = new FixtureField(); + var root = PlanetaryPageBaker.Bake(field, new(new(PlanetaryCubeFace.PositiveZ, 0, 0, 0), 17, 2), source); + var child = PlanetaryPageBaker.Bake(field, new(new(PlanetaryCubeFace.PositiveZ, 1, 1, 0), 17, 2), source); + var direction = PlanetaryPageSampling.DirectionAtLocal(child.Layout, 0.5, 0.5); + var pages = new[] { new PlanetaryResidentPage(root, 1), new PlanetaryResidentPage(child, 1) }; + Assert.True(PlanetaryPageSetSampling.TrySample(pages, direction, out var composed)); + var spacing = PlanetaryPageSampling.NominalAngularTexelSize(child.Layout) * field.Radius; + var direct = PlanetaryField.Sample(field, direction, source.Sample(direction), PlanetaryQueryScale.AtFootprint(spacing)); + Assert.InRange(MathF.Abs(composed.Height - direct.RadialDisplacement), 0, 2.0e-5f); + Assert.InRange(math.distance(composed.TangentGradient, direct.TangentGradient), 0, 3.0e-5f); + } + + private readonly struct FixtureField : IPlanetaryBaseField + { + public PlanetaryBaseFieldSample Sample(float3 direction) + { + var value = direction.x * 0.4f - direction.y * 0.2f + direction.z * 0.5f; + var gradient = new float3(0.4f, -0.2f, 0.5f); + gradient -= direction * math.dot(gradient, direction); + return new(value * 0.08f, gradient * 0.08f, value, gradient, value); + } + } +} diff --git a/tests/GameCult.Geometry.Planetary.Tests/PlanetaryPatchTests.cs b/tests/GameCult.Geometry.Planetary.Tests/PlanetaryPatchTests.cs new file mode 100644 index 00000000..bea83edf --- /dev/null +++ b/tests/GameCult.Geometry.Planetary.Tests/PlanetaryPatchTests.cs @@ -0,0 +1,43 @@ +using Xunit; + +using CultMath; +using GameCult.Geometry; + +namespace GameCult.Geometry.Planetary.Tests; + +public sealed class PlanetaryPatchTests +{ + [Fact] + public void CubeSpherePatchMeshUsesCanonicalTopology() + { + var meshes = PlanetaryPatch.CreateCubeSphere(8); + Assert.Equal(6, meshes.Length); + foreach (var mesh in meshes) + { + Assert.Equal(81, mesh.Vertices.Length); + Assert.Equal(8 * 8 * 6, mesh.Indices.Length); + Assert.All(mesh.Vertices, vertex => Assert.Equal(1, math.length(vertex.UnitDirection), 5)); + foreach (var index in mesh.Indices) Assert.InRange(index, 0, mesh.Vertices.Length - 1); + } + } + + [Fact] + public void NeighborFaceCornersAreSingleValued() + { + var directions = PlanetaryPatch.CreateCubeSphere(1) + .SelectMany(mesh => mesh.Vertices.Select(vertex => vertex.UnitDirection)) + .ToArray(); + var groups = directions.GroupBy(direction => new + { + X = Math.Sign(direction.x), + Y = Math.Sign(direction.y), + Z = Math.Sign(direction.z), + }); + Assert.Equal(8, groups.Count()); + Assert.All(groups, group => + { + var first = group.First(); + Assert.All(group, direction => Assert.InRange(math.distance(first, direction), 0, 1.0e-6f)); + }); + } +} diff --git a/tests/GameCult.Geometry.Planetary.Tests/PlanetaryProjectionTests.cs b/tests/GameCult.Geometry.Planetary.Tests/PlanetaryProjectionTests.cs new file mode 100644 index 00000000..55f5676b --- /dev/null +++ b/tests/GameCult.Geometry.Planetary.Tests/PlanetaryProjectionTests.cs @@ -0,0 +1,76 @@ +using Xunit; + +using CultMath; +using GameCult.Geometry; + +namespace GameCult.Geometry.Planetary.Tests; + +public sealed class PlanetaryProjectionTests +{ + [Theory] + [InlineData(PlanetaryProjectionKind.Equirectangular)] + [InlineData(PlanetaryProjectionKind.WebMercator)] + [InlineData(PlanetaryProjectionKind.EqualEarth)] + [InlineData(PlanetaryProjectionKind.Orthographic)] + [InlineData(PlanetaryProjectionKind.AzimuthalEquidistant)] + [InlineData(PlanetaryProjectionKind.AzimuthalEqualArea)] + [InlineData(PlanetaryProjectionKind.LocalTangent)] + public void ProjectionRoundTripsVisibleDirections(PlanetaryProjectionKind kind) + { + var parameters = new PlanetaryProjectionParameters(kind, 0.31, -0.22); + foreach (var longitude in new[] { -0.4, -0.1, 0.2, 0.65 }) + foreach (var latitude in new[] { -0.6, -0.15, 0.3, 0.7 }) + { + var direction = Direction(longitude + parameters.CenterLongitude, latitude); + if (!PlanetaryProjection.TryForward(direction, parameters, out var map)) continue; + Assert.True(PlanetaryProjection.TryInverse(map, parameters, out var roundTrip)); + Assert.InRange(math.distance(direction, roundTrip), 0, 3.0e-5f); + } + } + + [Fact] + public void CubeAtlasRoundTripsEveryFaceInterior() + { + var projection = new PlanetaryProjectionParameters(PlanetaryProjectionKind.CubeAtlas); + foreach (var face in Enum.GetValues()) + { + var direction = PlanetaryTopology.Direction(new(face, 0.23, -0.41)); + Assert.True(PlanetaryProjection.TryForward(direction, projection, out var map)); + Assert.True(PlanetaryProjection.TryInverse(map, projection, out var roundTrip)); + Assert.InRange(math.distance(direction, roundTrip), 0, 2.0e-6f); + } + } + + [Fact] + public void MercatorRejectsPolarSingularity() + { + var northPole = new float3(0, 0, 1); + Assert.False(PlanetaryProjection.TryForward(northPole, new(PlanetaryProjectionKind.WebMercator), out _)); + } + + [Fact] + public void MapTileBakerCarriesFieldIdentityAndProjectionValidity() + { + var field = new PlanetaryFieldDefinition(99, 10, 0, AdvancedErosionParameters.Default); + var layout = new PlanetaryMapTileLayout( + new(PlanetaryProjectionKind.Orthographic), 0, 0, 0, 9, 1); + var key = new PlanetaryMapTileKey(field.FieldVersion, 1, 7, layout, PlanetaryQueryScale.AtFootprint(0.1f)); + var tile = PlanetaryMapTileBaker.Bake(field, key, new FlatField()); + Assert.Equal(key, tile.Key); + Assert.Equal(layout.StorageSize * layout.StorageSize, tile.Samples.Length); + Assert.Contains(tile.Validity, valid => valid); + Assert.Contains(tile.Validity, valid => !valid); + Assert.All(tile.Samples.Where((_, index) => tile.Validity[index]), sample => Assert.Equal(field.FieldVersion, sample.FieldVersion)); + } + + private static float3 Direction(double longitude, double latitude) + { + var cos = Math.Cos(latitude); + return new((float)(cos * Math.Cos(longitude)), (float)(cos * Math.Sin(longitude)), (float)Math.Sin(latitude)); + } + + private readonly struct FlatField : IPlanetaryBaseField + { + public PlanetaryBaseFieldSample Sample(float3 unitDirection) => new(0, float3.zero, 0, float3.zero, 0); + } +} diff --git a/tests/GameCult.Geometry.Planetary.Tests/PlanetaryQueryTests.cs b/tests/GameCult.Geometry.Planetary.Tests/PlanetaryQueryTests.cs new file mode 100644 index 00000000..17636165 --- /dev/null +++ b/tests/GameCult.Geometry.Planetary.Tests/PlanetaryQueryTests.cs @@ -0,0 +1,49 @@ +using Xunit; + +using CultMath; +using GameCult.Geometry; + +namespace GameCult.Geometry.Planetary.Tests; + +public sealed class PlanetaryQueryTests +{ + private static readonly PlanetaryFieldDefinition Field = new(12, 10, 0, AdvancedErosionParameters.Default with { Strength = 0, Octaves = 0 }); + private static readonly PlanetaryQueryScale Scale = PlanetaryQueryScale.AtFootprint(0.1f, 0); + + [Fact] + public void RayIntersectionAndClearanceUseTheCpuSurfaceContract() + { + var source = new BulgedSphere(); + Assert.True(PlanetaryQueries.TryIntersectRay( + Field, new double3(0, 0, 20), new double3(0, 0, -1), 30, + Scale, new PlanetaryRadialBounds(-1, 1), source, out var hit)); + Assert.InRange(hit.Distance, 8.99999, 9.00001); + Assert.InRange(hit.PlanetLocalPosition.z, 10.99999, 11.00001); + var clearance = PlanetaryQueries.SegmentClearance( + Field, new double3(-2, 0, 12), new double3(2, 0, 12), 0.1, Scale, source); + Assert.True(clearance > 0.8); + } + + [Fact] + public void GreatCircleAndRegionQueriesReturnVersionedSamples() + { + var source = new BulgedSphere(); + var path = PlanetaryQueries.SampleGreatCircle(Field, new float3(1, 0, 0), new float3(0, 1, 0), 8, Scale, source); + Assert.Equal(9, path.Length); + Assert.Equal(MathF.PI * 5, path[^1].Distance, 4); + Assert.All(path, point => Assert.Equal(Field.FieldVersion, point.Surface.FieldVersion)); + var summary = PlanetaryQueries.Summarize(Field, path.Select(point => point.Surface.UnitDirection).ToArray(), Scale, source); + Assert.True(summary.MaximumDisplacement >= summary.MinimumDisplacement); + Assert.True(summary.MaximumSlope >= 0); + } + + private readonly struct BulgedSphere : IPlanetaryBaseField + { + public PlanetaryBaseFieldSample Sample(float3 direction) + { + var displacement = direction.z; + var gradient = new float3(0, 0, 1) - direction * direction.z; + return new(displacement, gradient, 0, float3.zero, 0); + } + } +} diff --git a/tests/GameCult.Geometry.Planetary.Tests/PlanetaryRadialRefinementTests.cs b/tests/GameCult.Geometry.Planetary.Tests/PlanetaryRadialRefinementTests.cs new file mode 100644 index 00000000..18d8529b --- /dev/null +++ b/tests/GameCult.Geometry.Planetary.Tests/PlanetaryRadialRefinementTests.cs @@ -0,0 +1,32 @@ +using Xunit; + +using CultMath; +using GameCult.Geometry; + +namespace GameCult.Geometry.Planetary.Tests; + +public sealed class PlanetaryRadialRefinementTests +{ + [Fact] + public void FourBoundedStepsConvergeFromTheRasterCaptureShell() + { + var center=new float3(0.3f,-0.2f,0.7f); + var radial=math.normalize(new float3(0.2f,-0.4f,0.9f)); + var targetRadius=3.85f; + var target=center+radial*targetRadius; + var origin=target+math.normalize(radial+new float3(0.12f,-0.05f,0.02f))*6.0f; + var position=center+radial*(targetRadius+0.30f); + var ray=math.normalize(position-origin); + for(var step=0;step<4;step++) + position=PlanetaryRadialRefinement.Step(position,ray,center,targetRadius); + Assert.InRange(math.abs(math.length(position-center)-targetRadius),0.0f,1.0e-4f); + } + + [Fact] + public void StepClampsWeakDerivativeCorrections() + { + var position=new float3(0,0,4.1f); + var result=PlanetaryRadialRefinement.Step(position,new float3(1,0,0),float3.zero,3.8f); + Assert.InRange(math.length(result-position),0.07999f,0.08001f); + } +} diff --git a/tests/GameCult.Geometry.Planetary.Tests/PlanetaryResidencyTests.cs b/tests/GameCult.Geometry.Planetary.Tests/PlanetaryResidencyTests.cs new file mode 100644 index 00000000..b8ed63f5 --- /dev/null +++ b/tests/GameCult.Geometry.Planetary.Tests/PlanetaryResidencyTests.cs @@ -0,0 +1,60 @@ +using Xunit; + +using CultMath; +using GameCult.Geometry; + +namespace GameCult.Geometry.Planetary.Tests; + +public sealed class PlanetaryResidencyTests +{ + private static readonly PlanetaryFieldDefinition Field = new( + 1, 8.4f, 0, AdvancedErosionParameters.Default with { Scale = 0.63f, Strength = 0.12f, Octaves = 7 }); + private static readonly PlanetaryLodParameters Lod = new(5, 17, 2, 720, 8.4f / 65536); + + [Fact] + public void SelectorReturnsSixRootsAndOneAncestorChain() + { + var direction = math.normalize(new float3(-0.2f, 0.91f, 0.37f)); + var selected = PlanetaryLodSelector.SelectAncestorChain(Field, direction, 8.45f, Lod); + Assert.Equal(6, selected.Count(tile => tile.Level == 0)); + var descendants = selected.Where(tile => tile.Level > 0).OrderBy(tile => tile.Level).ToArray(); + for (var i = 1; i < descendants.Length; i++) Assert.Equal(descendants[i - 1], descendants[i].Parent()); + if (descendants.Length > 0) Assert.Equal(PlanetaryTopology.TileAt(direction, descendants[^1].Level), descendants[^1]); + } + + [Fact] + public void ResidencyFadesResidualsWithoutChangingContentDuringPresentation() + { + var root = new PlanetaryTileAddress(PlanetaryCubeFace.PositiveX, 0, 0, 0); + var child = root.Child(1, 0); + var residency = new PlanetaryResidualResidency(); + var arrival = residency.Update(new[] { root, child }, 0, 1); + var midpoint = residency.Update(new[] { root, child }, 0.5f, 1); + var settled = residency.Update(new[] { root, child }, 1, 1); + Assert.Equal(arrival.ContentVersion, midpoint.ContentVersion); + Assert.Equal(midpoint.ContentVersion, settled.ContentVersion); + Assert.Equal(0, arrival.Tiles.Single(tile => tile.Tile == child).Blend); + Assert.Equal(0.5f, midpoint.Tiles.Single(tile => tile.Tile == child).Blend); + Assert.Equal(1, settled.Tiles.Single(tile => tile.Tile == child).Blend); + + var leaving = residency.Update(new[] { root }, 1.25f, 1); + Assert.True(leaving.Tiles.Single(tile => tile.Tile == child).Departing); + Assert.Equal(1, leaving.Tiles.Single(tile => tile.Tile == child).Blend); + var gone = residency.Update(new[] { root }, 2.25f, 1); + Assert.DoesNotContain(gone.Tiles, tile => tile.Tile == child); + } + + [Fact] + public void ReversingAnArrivalDepartsFromItsCurrentWeightWithoutJumping() + { + var root = new PlanetaryTileAddress(PlanetaryCubeFace.PositiveX, 0, 0, 0); + var child = root.Child(0, 1); + var residency = new PlanetaryResidualResidency(); + _ = residency.Update(new[] { root, child }, 0, 1); + var arriving = residency.Update(new[] { root, child }, 0.25f, 1); + var departing = residency.Update(new[] { root }, 0.25f, 1); + Assert.Equal(0.25f, arriving.Tiles.Single(tile => tile.Tile == child).Blend); + Assert.Equal(0.25f, departing.Tiles.Single(tile => tile.Tile == child).Blend); + Assert.True(departing.Tiles.Single(tile => tile.Tile == child).Departing); + } +} diff --git a/tests/GameCult.Geometry.Planetary.Tests/PlanetaryTopologyTests.cs b/tests/GameCult.Geometry.Planetary.Tests/PlanetaryTopologyTests.cs new file mode 100644 index 00000000..27bb4cef --- /dev/null +++ b/tests/GameCult.Geometry.Planetary.Tests/PlanetaryTopologyTests.cs @@ -0,0 +1,66 @@ +using Xunit; + +using CultMath; +using GameCult.Geometry; + +namespace GameCult.Geometry.Planetary.Tests; + +public sealed class PlanetaryTopologyTests +{ + [Fact] + public void FaceDirectionRoundTripsAcrossEveryFace() + { + foreach (var face in Enum.GetValues()) + foreach (var u in new[] { -0.9, -0.25, 0.0, 0.4, 0.9 }) + foreach (var v in new[] { -0.85, -0.1, 0.3, 0.88 }) + { + var direction = PlanetaryTopology.Direction(new(face, u, v)); + var roundTrip = PlanetaryTopology.FaceCoordinate(direction); + Assert.Equal(face, roundTrip.Face); + Assert.Equal(u, roundTrip.U, 5); + Assert.Equal(v, roundTrip.V, 5); + } + } + + [Fact] + public void SiblingPagesShareBitStableBoundaryDirections() + { + var left = new PlanetaryPageLayout(new(PlanetaryCubeFace.PositiveZ, 1, 0, 0), 17, 2); + var right = new PlanetaryPageLayout(new(PlanetaryCubeFace.PositiveZ, 1, 1, 0), 17, 2); + for (var y = 0; y < left.InteriorSize; y++) + { + var a = PlanetaryPageSampling.Direction(left, left.BorderSize + left.InteriorSize - 1, left.BorderSize + y); + var b = PlanetaryPageSampling.Direction(right, right.BorderSize, right.BorderSize + y); + Assert.Equal(a, b); + } + } + + [Fact] + public void DirectionSelectsContainingTileAndLocalCoordinate() + { + var expected = new PlanetaryTileAddress(PlanetaryCubeFace.NegativeY, 5, 19, 7); + var direction = PlanetaryPageSampling.DirectionAtLocal(new(expected, 17, 2), 0.37, 0.61); + Assert.Equal(expected, PlanetaryTopology.TileAt(direction, expected.Level)); + Assert.True(PlanetaryTopology.TryLocalCoordinate(direction, expected, out var local)); + Assert.Equal(0.37f, local.x, 4); + Assert.Equal(0.61f, local.y, 4); + } + + [Fact] + public void BorderSamplesDoNotRequireNeighborResidency() + { + var page = new PlanetaryPageLayout(new(PlanetaryCubeFace.PositiveX, 0, 0, 0), 17, 3); + var edge = PlanetaryPageSampling.Direction(page, page.BorderSize + page.InteriorSize - 1, page.BorderSize + 8); + var border = PlanetaryPageSampling.Direction(page, page.StorageSize - 1, page.BorderSize + 8); + Assert.NotEqual(edge, border); + Assert.Equal(1, math.length(border), 5); + } + + [Fact] + public void NormalizedCubeBaselineSharesFaceEdges() + { + var a = PlanetaryTopology.NormalizedCubeDirection(new(PlanetaryCubeFace.PositiveZ, 1, -0.4)); + var b = PlanetaryTopology.NormalizedCubeDirection(new(PlanetaryCubeFace.PositiveX, -1, -0.4)); + Assert.InRange(math.distance(a, b), 0, 1.0e-6f); + } +} diff --git a/tests/GameCult.Geometry.Planetary.Tests/SphericalErosionTests.cs b/tests/GameCult.Geometry.Planetary.Tests/SphericalErosionTests.cs new file mode 100644 index 00000000..adf7ea0e --- /dev/null +++ b/tests/GameCult.Geometry.Planetary.Tests/SphericalErosionTests.cs @@ -0,0 +1,37 @@ +using Xunit; + +using CultMath; +using GameCult.Geometry; + +namespace GameCult.Geometry.Planetary.Tests; + +public sealed class SphericalErosionTests +{ + [Fact] + public void SampleIsDeterministicAndScaleInvariant() + { + var parameters = SphericalErosionParameters.Default with { Seed = 42.0f }; + var a = SphericalErosion.Sample(new float3(0.31f, -0.74f, 0.59f), 0.2f, new float3(0.4f, -0.1f, 0.2f), parameters); + var repeated = SphericalErosion.Sample(new float3(0.31f, -0.74f, 0.59f), 0.2f, new float3(0.4f, -0.1f, 0.2f), parameters); + var b = SphericalErosion.Sample(new float3(3.1f, -7.4f, 5.9f), 0.2f, new float3(0.4f, -0.1f, 0.2f), parameters); + + Assert.Equal(a, repeated); + Assert.InRange(math.abs(a.HeightOffset-b.HeightOffset),0.0f,1.0e-6f); + Assert.InRange(math.abs(a.Ridge-b.Ridge),0.0f,1.0e-6f); + Assert.InRange(math.abs(a.Gully-b.Gully),0.0f,5.0e-5f); + Assert.InRange(math.length(a.Gradient-b.Gradient),0.0f,5.0e-6f); + Assert.InRange(a.HeightOffset, -0.08f, 0.08f); + Assert.InRange(a.Ridge, 0.0f, 1.0f); + Assert.InRange(a.Gully, 0.0f, 1.0f); + } + + [Fact] + public void NearbySamplesRemainContinuousAcrossAChartBoundary() + { + var parameters = SphericalErosionParameters.Default; + var left = SphericalErosion.Sample(math.normalize(new float3(1.0f, 0.99999f, 0.2f)), 0.1f, new float3(0.2f, -0.1f, 0.05f), parameters); + var right = SphericalErosion.Sample(math.normalize(new float3(0.99999f, 1.0f, 0.2f)), 0.1f, new float3(0.2f, -0.1f, 0.05f), parameters); + + Assert.InRange(math.abs(left.HeightOffset - right.HeightOffset), 0.0f, 0.0002f); + } +} diff --git a/tests/GameCult.Geometry.Tests/GeometryShaderOwnershipTests.cs b/tests/GameCult.Geometry.Tests/GeometryShaderOwnershipTests.cs new file mode 100644 index 00000000..ba5bcf64 --- /dev/null +++ b/tests/GameCult.Geometry.Tests/GeometryShaderOwnershipTests.cs @@ -0,0 +1,79 @@ +using System; +using System.IO; +using NUnit.Framework; + +namespace GameCult.Geometry.Tests; + +public sealed class GeometryShaderOwnershipTests +{ + [Test] + public void GeometryUmbrellaOwnsTheCompleteShaderSurface() + { + var shaders = Path.Combine(GetRepositoryRoot(), "src", "GameCult.Geometry", "Shaders"); + var umbrella = File.ReadAllText(Path.Combine(shaders, "GameCult.Geometry.hlsl")); + var erosion = File.ReadAllText(Path.Combine(shaders, "AdvancedErosionFilter.hlsl")); + var planetary = File.ReadAllText(Path.Combine(shaders, "Planetary.hlsl")); + var spherical = File.ReadAllText(Path.Combine(shaders, "SphericalErosion.hlsl")); + var refinement = File.ReadAllText(Path.Combine(shaders, "PlanetaryRadialRefinement.hlsl")); + + Assert.That(umbrella, Does.Contain("#define GAMECULT_GEOMETRY_CULTMATH_INCLUDE \"CultMath.hlsl\"") + .And.Contain("#include GAMECULT_GEOMETRY_CULTMATH_INCLUDE") + .And.Contain("#include \"AdvancedErosionFilter.hlsl\"") + .And.Contain("#include \"Planetary.hlsl\"") + .And.Contain("#include \"SphericalErosion.hlsl\"") + .And.Contain("#include \"PlanetaryRadialRefinement.hlsl\"")); + Assert.That(erosion, Does.Contain("gamecult_geometry_advanced_erosion_filter") + .And.Contain("GameCultGeometryAdvancedErosionParameters")); + Assert.That(planetary, Does.Contain("gamecult_geometry_planetary_face_direction") + .And.Contain("gamecult_geometry_planetary_field_sample") + .And.Contain("GameCultGeometryPlanetarySurfaceSample")); + Assert.That(spherical, Does.Contain("gamecult_geometry_spherical_erosion") + .And.Contain("GameCultGeometrySphericalErosionParameters")); + Assert.That(refinement, Does.Contain("gamecult_geometry_planetary_radial_refinement_step")); + } + + [Test] + public void GeometryShadersDoNotPublishCultMathGeometrySymbols() + { + var shaders = Path.Combine(GetRepositoryRoot(), "src", "GameCult.Geometry", "Shaders"); + foreach (var path in Directory.GetFiles(shaders, "*.hlsl")) + { + var source = File.ReadAllText(path); + Assert.That(source, Does.Not.Contain("cultmath_planetary_"), Path.GetFileName(path)); + Assert.That(source, Does.Not.Contain("cultmath_spherical_"), Path.GetFileName(path)); + Assert.That(source, Does.Not.Contain("cultmath_advanced_erosion_"), Path.GetFileName(path)); + } + } + + [Test] + public void UnityPlanetaryViewerUsesTheGeometryUmbrellaAndOwnedSymbols() + { + var shader = File.ReadAllText(Path.Combine( + GetRepositoryRoot(), + "unity", "org.gamecult.geometry", "Samples~", "PlanetaryViewer", "Runtime", + "GameCultGeometryPlanetaryViewer.shader")); + + Assert.That(shader, Does.Contain( + "#define GAMECULT_GEOMETRY_CULTMATH_INCLUDE \"Packages/org.gamecult.cultmath/shaders/CultMath.hlsl\"") + .And.Contain("#include \"Packages/org.gamecult.geometry/Shaders/GameCult.Geometry.hlsl\"") + .And.Contain("gamecult_geometry_planetary_field_sample") + .And.Not.Contain("cultmath_planetary_") + .And.Not.Contain("CultMathPlanetary")); + } + + private static string GetRepositoryRoot() + { + var directory = new DirectoryInfo(AppContext.BaseDirectory); + while (directory is not null) + { + if (File.Exists(Path.Combine(directory.FullName, "CultLib.sln"))) + { + return directory.FullName; + } + + directory = directory.Parent; + } + + throw new InvalidOperationException("Could not locate CultLib repository root."); + } +} diff --git a/tools/GameCult.Geometry.PlanetaryTileFixture/GameCult.Geometry.PlanetaryTileFixture.csproj b/tools/GameCult.Geometry.PlanetaryTileFixture/GameCult.Geometry.PlanetaryTileFixture.csproj new file mode 100644 index 00000000..21a2c04b --- /dev/null +++ b/tools/GameCult.Geometry.PlanetaryTileFixture/GameCult.Geometry.PlanetaryTileFixture.csproj @@ -0,0 +1,11 @@ + + + Exe + net10.0 + enable + enable + + + + + diff --git a/tools/GameCult.Geometry.PlanetaryTileFixture/Program.cs b/tools/GameCult.Geometry.PlanetaryTileFixture/Program.cs new file mode 100644 index 00000000..c9ce965b --- /dev/null +++ b/tools/GameCult.Geometry.PlanetaryTileFixture/Program.cs @@ -0,0 +1,23 @@ +using CultMath; +using GameCult.Geometry; + +if (args.Length != 1) throw new ArgumentException("Expected one output path."); +var field = GameCult.Geometry.PlanetaryFieldDefinition.Create(0x55aa, 10, 7, GameCult.Geometry.AdvancedErosionParameters.Default); +var layout = new GameCult.Geometry.PlanetaryMapTileLayout(new(GameCult.Geometry.PlanetaryProjectionKind.EqualEarth), 0, 0, 0, 5, 1); +var key = new GameCult.Geometry.PlanetaryMapTileKey(field.FieldVersion, 3, 29, layout, GameCult.Geometry.PlanetaryQueryScale.AtFootprint(0.25f, 0.125f)); +var tile = GameCult.Geometry.PlanetaryMapTileBaker.Bake(field, key, new FixtureField()); +var path = Path.GetFullPath(args[0]); +Directory.CreateDirectory(Path.GetDirectoryName(path)!); +using var stream = File.Create(path); +GameCult.Geometry.PlanetaryMapTileEncoding.Write(stream, tile); + +readonly struct FixtureField : GameCult.Geometry.IPlanetaryBaseField +{ + public GameCult.Geometry.PlanetaryBaseFieldSample Sample(float3 direction) + { + var value = direction.x * 0.2f + direction.z * 0.4f; + var gradient = new float3(0.2f, 0, 0.4f); + gradient -= direction * math.dot(gradient, direction); + return new(value, gradient, value, gradient * 0.1f, value); + } +} diff --git a/unity/org.gamecult.geometry/README.md b/unity/org.gamecult.geometry/README.md index 7a6e0823..3fe2f10e 100644 --- a/unity/org.gamecult.geometry/README.md +++ b/unity/org.gamecult.geometry/README.md @@ -7,6 +7,9 @@ depends on `org.gamecult.cultmath` for numeric primitives and Build it with `scripts/build-geometry-unity-package.ps1`. Do not edit generated plugin assemblies in the package output. -CultLib-authored files are MIT licensed. Geometry sources transferred from -CultMath retain their MPL-2.0 notices and provenance; those files will be listed -here as they enter this package. No transferred CultMath source is relicensed. +CultLib-authored integration files are MIT licensed. The planetary C# compiled +into `GameCult.Geometry.dll` and the geometry HLSL under `Shaders` are +MPL-2.0 and retain their source notices and provenance. See `LICENSES.md` and +`THIRD-PARTY-NOTICES.md` in the staged package. No MPL-covered source is +relicensed. The package manifest therefore uses `SEE LICENSES IN README.md` +rather than claiming one license for every file. diff --git a/unity/org.gamecult.geometry/Runtime/GameCult.Geometry.Unity.asmdef b/unity/org.gamecult.geometry/Runtime/GameCult.Geometry.Unity.asmdef new file mode 100644 index 00000000..3a0a02ee --- /dev/null +++ b/unity/org.gamecult.geometry/Runtime/GameCult.Geometry.Unity.asmdef @@ -0,0 +1,8 @@ +{ + "name": "GameCult.Geometry.Unity", + "rootNamespace": "GameCult.Geometry.Unity", + "references": ["CultMath", "GameCult.Geometry"], + "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, + "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, + "defineConstraints": [], "versionDefines": [], "noEngineReferences": false +} diff --git a/unity/org.gamecult.geometry/Runtime/PlanetaryPageUpload.cs b/unity/org.gamecult.geometry/Runtime/PlanetaryPageUpload.cs new file mode 100644 index 00000000..8e0b431e --- /dev/null +++ b/unity/org.gamecult.geometry/Runtime/PlanetaryPageUpload.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using CultMath; +using UnityEngine; + +namespace GameCult.Geometry.Unity; + +[StructLayout(LayoutKind.Sequential)] public readonly struct PlanetaryPageInputGpu { public PlanetaryPageInputGpu(Vector4 directionRadius, Vector4 sampling) { DirectionRadius = directionRadius; Sampling = sampling; } public readonly Vector4 DirectionRadius; public readonly Vector4 Sampling; } +[StructLayout(LayoutKind.Sequential)] public readonly struct PlanetaryPageMetadataGpu { public PlanetaryPageMetadataGpu(Vector4 address, Vector4 layout, Vector4 bounds, Vector4 state) { Address = address; Layout = layout; Bounds = bounds; State = state; } public readonly Vector4 Address; public readonly Vector4 Layout; public readonly Vector4 Bounds; public readonly Vector4 State; } +public readonly struct PlanetaryPageUpload { public PlanetaryPageUpload(PlanetaryPageInputGpu[] inputs, PlanetaryPageMetadataGpu[] metadata, int outputSampleCount, ulong contentVersion, ulong presentationVersion) { Inputs = inputs; Metadata = metadata; OutputSampleCount = outputSampleCount; ContentVersion = contentVersion; PresentationVersion = presentationVersion; } public PlanetaryPageInputGpu[] Inputs { get; } public PlanetaryPageMetadataGpu[] Metadata { get; } public int OutputSampleCount { get; } public ulong ContentVersion { get; } public ulong PresentationVersion { get; } } +public static class PlanetaryPageUploadBuilder +{ + public static PlanetaryPageUpload Build(in PlanetaryResidencySnapshot snapshot, int interiorSize, int borderSize, float radius) + { + if (!float.IsFinite(radius) || radius <= 0) throw new ArgumentOutOfRangeException(nameof(radius)); + var inputs = new List(); var metadata = new PlanetaryPageMetadataGpu[snapshot.Tiles.Length]; + foreach (var (resident, pageIndex) in snapshot.Tiles.Select((resident, index) => (resident, index))) + { + var content = PlanetaryGpuPageBuilder.BuildContent(new PlanetaryPageLayout(resident.Tile, interiorSize, borderSize).Validate(), radius); var outputOffset = inputs.Count; + foreach (var input in content.Inputs) inputs.Add(new(ToUnity(input.DirectionRadius), ToUnity(input.Sampling))); + var common = PlanetaryGpuPageBuilder.Metadata(content, outputOffset, resident.Blend); + metadata[pageIndex] = new(ToUnity(common.Address), ToUnity(common.Layout), ToUnity(common.Bounds), ToUnity(common.State)); + } + return new(inputs.ToArray(), metadata, inputs.Count, snapshot.ContentVersion, snapshot.PresentationVersion); + } + private static Vector4 ToUnity(float4 value) => new(value.x, value.y, value.z, value.w); +} diff --git a/unity/org.gamecult.geometry/Runtime/PlanetaryPageUpload.cs.meta b/unity/org.gamecult.geometry/Runtime/PlanetaryPageUpload.cs.meta new file mode 100644 index 00000000..904f752e --- /dev/null +++ b/unity/org.gamecult.geometry/Runtime/PlanetaryPageUpload.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7edd3bb2edb2e6448a2d54fc082c27dc diff --git a/unity/org.gamecult.geometry/Runtime/PlanetaryPatchMeshAdapter.cs b/unity/org.gamecult.geometry/Runtime/PlanetaryPatchMeshAdapter.cs new file mode 100644 index 00000000..8e758426 --- /dev/null +++ b/unity/org.gamecult.geometry/Runtime/PlanetaryPatchMeshAdapter.cs @@ -0,0 +1,27 @@ +using System; +using CultMath; +using UnityEngine; +using UnityEngine.Rendering; + +namespace GameCult.Geometry.Unity; + +public static class PlanetaryPatchMeshAdapter +{ + public static Mesh CreateFaceMesh(PlanetaryCubeFace face, int cellsPerAxis, float radius = 1) + { + if (!float.IsFinite(radius) || radius <= 0) throw new ArgumentOutOfRangeException(nameof(radius)); + var source = PlanetaryPatch.CreateFace(face, cellsPerAxis); + var vertices = new Vector3[source.Vertices.Length]; + var normals = new Vector3[source.Vertices.Length]; + var uv = new Vector2[source.Vertices.Length]; + for (var i = 0; i < source.Vertices.Length; i++) + { + var direction = source.Vertices[i].UnitDirection; + var normal = new Vector3(direction.x, direction.y, direction.z); + vertices[i] = normal * radius; normals[i] = normal; + uv[i] = new Vector2(source.Vertices[i].LocalCoordinate.x, source.Vertices[i].LocalCoordinate.y); + } + var mesh = new Mesh { name = $"GameCult.Geometry Planetary {face} {cellsPerAxis}x{cellsPerAxis}", indexFormat = vertices.Length > ushort.MaxValue ? IndexFormat.UInt32 : IndexFormat.UInt16, vertices = vertices, normals = normals, uv = uv, triangles = source.Indices }; + mesh.RecalculateBounds(); return mesh; + } +} diff --git a/unity/org.gamecult.geometry/Runtime/PlanetaryPatchMeshAdapter.cs.meta b/unity/org.gamecult.geometry/Runtime/PlanetaryPatchMeshAdapter.cs.meta new file mode 100644 index 00000000..4a2d9754 --- /dev/null +++ b/unity/org.gamecult.geometry/Runtime/PlanetaryPatchMeshAdapter.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9ad7b581e14ef774d8435069bb77ca6a diff --git a/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Editor/GameCult.Geometry.PlanetaryViewer.Editor.asmdef b/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Editor/GameCult.Geometry.PlanetaryViewer.Editor.asmdef new file mode 100644 index 00000000..7f842880 --- /dev/null +++ b/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Editor/GameCult.Geometry.PlanetaryViewer.Editor.asmdef @@ -0,0 +1 @@ +{"name":"GameCult.Geometry.PlanetaryViewer.Editor","rootNamespace":"GameCult.Geometry.Unity.Samples.Editor","references":["GameCult.Geometry.PlanetaryViewer"],"includePlatforms":["Editor"],"excludePlatforms":[],"allowUnsafeCode":false,"overrideReferences":false,"precompiledReferences":[],"autoReferenced":true,"defineConstraints":[],"versionDefines":[],"noEngineReferences":false} diff --git a/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Editor/GameCultGeometryPlanetaryViewerMenu.cs b/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Editor/GameCultGeometryPlanetaryViewerMenu.cs new file mode 100644 index 00000000..e2a32d17 --- /dev/null +++ b/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Editor/GameCultGeometryPlanetaryViewerMenu.cs @@ -0,0 +1,27 @@ +using UnityEditor; +using UnityEngine; +using GameCult.Geometry.Unity.Samples; + +namespace GameCult.Geometry.Unity.Samples.Editor; + +public static class GameCultGeometryPlanetaryViewerMenu +{ + [MenuItem("GameObject/GameCult.Geometry/Planetary Field Viewer", false, 10)] + public static void CreateViewer() + { + var root = new GameObject("GameCult.Geometry Planetary Field Viewer"); + Undo.RegisterCreatedObjectUndo(root, "Create GameCult.Geometry Planetary Viewer"); + root.AddComponent(); + Selection.activeGameObject = root; + + if (Camera.main != null) return; + var cameraObject = new GameObject("Planetary Viewer Camera"); + Undo.RegisterCreatedObjectUndo(cameraObject, "Create Planetary Viewer Camera"); + cameraObject.tag = "MainCamera"; + cameraObject.transform.position = new Vector3(0, 0, -24); + cameraObject.transform.LookAt(root.transform); + var camera = cameraObject.AddComponent(); + camera.nearClipPlane = 0.01f; + camera.farClipPlane = 1000; + } +} diff --git a/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/README.md b/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/README.md new file mode 100644 index 00000000..85bb4585 --- /dev/null +++ b/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/README.md @@ -0,0 +1,7 @@ +# Planetary Field Viewer + +Import this sample through Unity Package Manager, then choose +`GameObject > GameCult.Geometry > Planetary Field Viewer`. + +The six-face mesh and planetary field are owned by GameCult.Geometry and use +CultMath numeric primitives. This is a renderer fixture, not gameplay state. diff --git a/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Runtime/GameCult.Geometry.PlanetaryViewer.asmdef b/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Runtime/GameCult.Geometry.PlanetaryViewer.asmdef new file mode 100644 index 00000000..ff41a80b --- /dev/null +++ b/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Runtime/GameCult.Geometry.PlanetaryViewer.asmdef @@ -0,0 +1 @@ +{"name":"GameCult.Geometry.PlanetaryViewer","rootNamespace":"GameCult.Geometry.Unity.Samples","references":["CultMath","GameCult.Geometry","GameCult.Geometry.Unity"],"includePlatforms":[],"excludePlatforms":[],"allowUnsafeCode":false,"overrideReferences":false,"precompiledReferences":[],"autoReferenced":true,"defineConstraints":[],"versionDefines":[],"noEngineReferences":false} diff --git a/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Runtime/GameCultGeometryPlanetaryViewer.cs b/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Runtime/GameCultGeometryPlanetaryViewer.cs new file mode 100644 index 00000000..708d7423 --- /dev/null +++ b/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Runtime/GameCultGeometryPlanetaryViewer.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections.Generic; +using CultMath; +using GameCult.Geometry; +using UnityEngine; + +namespace GameCult.Geometry.Unity.Samples; + +[ExecuteAlways] +public sealed class GameCultGeometryPlanetaryViewer : MonoBehaviour +{ + [Min(0.001f)] public float Radius = 8.4f; + [Range(1, 256)] public int CellsPerFace = 64; + public int Seed = 42; + [Min(0.0001f)] public float SampleFootprint = 0.01f; + public Shader? PlanetShader; + public Vector3 LightDirection = new(-0.4f, 0.7f, -0.6f); + public Color LowColor = new(0.055f, 0.16f, 0.09f, 1); + public Color HighColor = new(0.62f, 0.48f, 0.28f, 1); + public Color RidgeColor = new(0.88f, 0.83f, 0.7f, 1); + + private readonly List meshes = new(); + private Material? material; + private int builtCells; + + public PlanetaryFieldDefinition Definition => PlanetaryFieldDefinition.Create( + 1, + Radius, + Seed, + ViewerErosion(Radius)); + + public PlanetarySurfaceSample Sample(float3 direction) + { + var source = new ViewerBaseField(Radius); + var normalized = math.normalize(direction); + return PlanetaryField.Sample(Definition, normalized, source.Sample(normalized), PlanetaryQueryScale.AtFootprint(SampleFootprint)); + } + + private void OnEnable() => Rebuild(); + + private void OnValidate() + { + Radius = Mathf.Max(Radius, 0.001f); + CellsPerFace = Mathf.Clamp(CellsPerFace, 1, 256); + SampleFootprint = Mathf.Max(SampleFootprint, 0.0001f); + if (isActiveAndEnabled) Rebuild(); + } + + private void Update() + { + if (builtCells != CellsPerFace || material == null) Rebuild(); + ApplyMaterial(); + } + + private void Rebuild() + { + ClearGenerated(); + PlanetShader ??= Shader.Find("GameCult.Geometry/Planetary Field Viewer"); + if (PlanetShader == null) return; + material = new Material(PlanetShader) { name = "CultMath Planetary Viewer Material", hideFlags = HideFlags.HideAndDontSave }; + foreach (var face in (PlanetaryCubeFace[])Enum.GetValues(typeof(PlanetaryCubeFace))) + { + var mesh = PlanetaryPatchMeshAdapter.CreateFaceMesh(face, CellsPerFace); + mesh.hideFlags = HideFlags.HideAndDontSave; + meshes.Add(mesh); + var child = new GameObject(face.ToString()) { hideFlags = HideFlags.DontSave }; + child.transform.SetParent(transform, false); + child.AddComponent().sharedMesh = mesh; + child.AddComponent().sharedMaterial = material; + } + builtCells = CellsPerFace; + ApplyMaterial(); + } + + private void ApplyMaterial() + { + if (material == null) return; + var p = ViewerErosion(Radius); + material.SetFloat("_Radius", Radius); + material.SetFloat("_SampleFootprint", SampleFootprint); + material.SetInt("_Seed", Seed); + material.SetFloat("_ErosionScale", p.Scale); + material.SetFloat("_ErosionStrength", p.Strength); + material.SetFloat("_GullyWeight", p.GullyWeight); + material.SetFloat("_Detail", p.Detail); + material.SetVector("_Rounding", new(p.Rounding.x, p.Rounding.y, p.Rounding.z, p.Rounding.w)); + material.SetVector("_Onset", new(p.Onset.x, p.Onset.y, p.Onset.z, p.Onset.w)); + material.SetVector("_AssumedSlope", new(p.AssumedSlope.x, p.AssumedSlope.y, 0, 0)); + material.SetFloat("_CellScale", p.CellScale); + material.SetFloat("_Normalization", p.Normalization); + material.SetInt("_Octaves", p.Octaves); + material.SetFloat("_Lacunarity", p.Lacunarity); + material.SetFloat("_Gain", p.Gain); + material.SetVector("_LightDirection", LightDirection.normalized); + material.SetColor("_LowColor", LowColor); + material.SetColor("_HighColor", HighColor); + material.SetColor("_RidgeColor", RidgeColor); + } + + private void OnDisable() => ClearGenerated(); + private void OnDestroy() => ClearGenerated(); + + private void ClearGenerated() + { + for (var i = transform.childCount - 1; i >= 0; i--) DestroyGenerated(transform.GetChild(i).gameObject); + foreach (var mesh in meshes) DestroyGenerated(mesh); + meshes.Clear(); + if (material != null) DestroyGenerated(material); + material = null; + builtCells = 0; + } + + private static void DestroyGenerated(UnityEngine.Object value) + { + if (Application.isPlaying) Destroy(value); + else DestroyImmediate(value); + } + + private static AdvancedErosionParameters ViewerErosion(float radius) => new( + radius * 0.075f, 0.12f, 0.58f, 1.45f, + new float4(0.1f, 0.015f, 0.1f, 2), + new float4(1.25f, 1.25f, 2.8f, 1.5f), + new float2(0.7f, 0.85f), 0.7f, 0.5f, 7, 2, 0.5f); + + private readonly struct ViewerBaseField : IPlanetaryBaseField + { + private readonly float radius; + public ViewerBaseField(float radius) => this.radius = radius; + + public PlanetaryBaseFieldSample Sample(float3 direction) + { + var value = direction.x * 0.6f + direction.y * direction.z * 0.3f; + var angularGradient = new float3(0.6f, direction.z * 0.3f, direction.y * 0.3f); + angularGradient -= direction * math.dot(angularGradient, direction); + var fieldGradient = angularGradient / radius; + var radialDisplacement = value * radius * 0.035f; + var radialGradient = angularGradient * 0.035f; + return new(radialDisplacement, radialGradient, value, fieldGradient, math.clamp(value, -1, 1)); + } + } +} diff --git a/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Runtime/GameCultGeometryPlanetaryViewer.shader b/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Runtime/GameCultGeometryPlanetaryViewer.shader new file mode 100644 index 00000000..850e1dd5 --- /dev/null +++ b/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Runtime/GameCultGeometryPlanetaryViewer.shader @@ -0,0 +1,91 @@ +Shader "GameCult.Geometry/Planetary Field Viewer" +{ + Properties + { + _LowColor ("Low Color", Color) = (0.055, 0.16, 0.09, 1) + _HighColor ("High Color", Color) = (0.62, 0.48, 0.28, 1) + _RidgeColor ("Ridge Color", Color) = (0.88, 0.83, 0.7, 1) + } + SubShader + { + Tags { "RenderType"="Opaque" "Queue"="Geometry" } + Pass + { + Cull Back + ZWrite On + HLSLPROGRAM + #pragma target 5.0 + #pragma vertex vert + #pragma fragment frag + #include "UnityCG.cginc" + #define GAMECULT_GEOMETRY_CULTMATH_INCLUDE "Packages/org.gamecult.cultmath/shaders/CultMath.hlsl" + #include "Packages/org.gamecult.geometry/Shaders/GameCult.Geometry.hlsl" + + float _Radius; + float _SampleFootprint; + int _Seed; + float _ErosionScale, _ErosionStrength, _GullyWeight, _Detail; + float4 _Rounding, _Onset, _AssumedSlope; + float _CellScale, _Normalization, _Lacunarity, _Gain; + int _Octaves; + float3 _LightDirection; + float4 _LowColor, _HighColor, _RidgeColor; + + struct Attributes { float4 vertex : POSITION; }; + struct Varyings + { + float4 position : SV_POSITION; + float3 worldNormal : TEXCOORD0; + float height : TEXCOORD1; + float ridge : TEXCOORD2; + }; + + GameCultGeometryPlanetarySurfaceSample viewer_sample(float3 direction) + { + direction = normalize(direction); + float value = direction.x * 0.6 + direction.y * direction.z * 0.3; + float3 angular_gradient = float3(0.6, direction.z * 0.3, direction.y * 0.3); + angular_gradient -= direction * dot(angular_gradient, direction); + GameCultGeometryPlanetaryBaseFieldSample base_sample; + base_sample.radial_displacement = value * _Radius * 0.035; + base_sample.radial_gradient = angular_gradient * 0.035; + base_sample.field_value = value; + base_sample.field_gradient = angular_gradient / _Radius; + base_sample.fade_target = clamp(value, -1.0, 1.0); + GameCultGeometryAdvancedErosionParameters erosion; + erosion.scale = _ErosionScale; erosion.strength = _ErosionStrength; + erosion.gully_weight = _GullyWeight; erosion.detail = _Detail; + erosion.rounding = _Rounding; erosion.onset = _Onset; + erosion.assumed_slope = _AssumedSlope.xy; erosion.cell_scale = _CellScale; + erosion.normalization = _Normalization; erosion.octaves = _Octaves; + erosion.lacunarity = _Lacunarity; erosion.gain = _Gain; + GameCultGeometryPlanetaryFieldDefinition definition; + definition.radius = _Radius; definition.seed = _Seed; definition.erosion = erosion; + return gamecult_geometry_planetary_field_sample(definition, direction, base_sample, _SampleFootprint); + } + + Varyings vert(Attributes input) + { + float3 direction = normalize(input.vertex.xyz); + GameCultGeometryPlanetarySurfaceSample sample = viewer_sample(direction); + float3 local = direction * (_Radius + sample.radial_displacement); + Varyings output; + output.position = UnityObjectToClipPos(float4(local, 1)); + output.worldNormal = UnityObjectToWorldNormal(sample.surface_normal); + output.height = sample.radial_displacement / max(_Radius * 0.1, 1.0e-5); + output.ridge = sample.ridge; + return output; + } + + float4 frag(Varyings input) : SV_Target + { + float height = saturate(input.height * 0.5 + 0.5); + float3 albedo = lerp(_LowColor.rgb, _HighColor.rgb, height); + albedo = lerp(albedo, _RidgeColor.rgb, saturate((input.ridge - 0.55) * 2.5)); + float diffuse = saturate(dot(normalize(input.worldNormal), normalize(-_LightDirection))) * 0.82 + 0.08; + return float4(albedo * diffuse, 1); + } + ENDHLSL + } + } +} diff --git a/unity/org.gamecult.geometry/package.json b/unity/org.gamecult.geometry/package.json index 023fed98..7ac223b5 100644 --- a/unity/org.gamecult.geometry/package.json +++ b/unity/org.gamecult.geometry/package.json @@ -11,5 +11,6 @@ "dependencies": { "org.gamecult.cultmath": "0.1.0", "org.gamecult.cultlib": "1.0.7" - } + }, + "samples": [{"displayName":"Planetary Field Viewer","description":"Planetary geometry CPU/HLSL parity viewer.","path":"Samples~/PlanetaryViewer"}] } From 99c893bd646caac1796a6788c2034fb0a7e06aeb Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 03:52:56 +0100 Subject: [PATCH 030/283] Fix remaining planetary ownership labels --- src/GameCult.Geometry/Planetary/PlanetaryMapTileEncoding.cs | 2 +- .../PlanetaryViewer/Runtime/GameCultGeometryPlanetaryViewer.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/GameCult.Geometry/Planetary/PlanetaryMapTileEncoding.cs b/src/GameCult.Geometry/Planetary/PlanetaryMapTileEncoding.cs index 90c93fee..ed07e7ba 100644 --- a/src/GameCult.Geometry/Planetary/PlanetaryMapTileEncoding.cs +++ b/src/GameCult.Geometry/Planetary/PlanetaryMapTileEncoding.cs @@ -55,7 +55,7 @@ public static class PlanetaryMapTileEncoding if (stream == null || !stream.CanRead) throw new ArgumentException("A readable stream is required.", nameof(stream)); using var reader = new BinaryReader(stream, Encoding.UTF8, leaveOpen); var magic = reader.ReadBytes(Magic.Length); - if (magic.Length != Magic.Length || !magic.AsSpan().SequenceEqual(Magic)) throw new InvalidDataException("Not a CultMath planetary tile."); + if (magic.Length != Magic.Length || !magic.AsSpan().SequenceEqual(Magic)) throw new InvalidDataException("Not a GameCult.Geometry planetary tile."); var version = reader.ReadUInt32(); if (version != FormatVersion) throw new InvalidDataException($"Unsupported planetary tile version {version}."); var fieldVersion = reader.ReadUInt64(); diff --git a/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Runtime/GameCultGeometryPlanetaryViewer.cs b/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Runtime/GameCultGeometryPlanetaryViewer.cs index 708d7423..2cfb0ce5 100644 --- a/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Runtime/GameCultGeometryPlanetaryViewer.cs +++ b/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Runtime/GameCultGeometryPlanetaryViewer.cs @@ -57,7 +57,7 @@ public sealed class GameCultGeometryPlanetaryViewer : MonoBehaviour ClearGenerated(); PlanetShader ??= Shader.Find("GameCult.Geometry/Planetary Field Viewer"); if (PlanetShader == null) return; - material = new Material(PlanetShader) { name = "CultMath Planetary Viewer Material", hideFlags = HideFlags.HideAndDontSave }; + material = new Material(PlanetShader) { name = "GameCult.Geometry Planetary Viewer Material", hideFlags = HideFlags.HideAndDontSave }; foreach (var face in (PlanetaryCubeFace[])Enum.GetValues(typeof(PlanetaryCubeFace))) { var mesh = PlanetaryPatchMeshAdapter.CreateFaceMesh(face, CellsPerFace); From 6b44f969a973d3acfac1d5a4cdf507a3b252ad83 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 03:56:28 +0100 Subject: [PATCH 031/283] Absorb CSG kernel into GameCult.Geometry --- ...th-gamecult-geometry-migration-progress.md | 38 +- packages/gamecult-geometry-rs/Cargo.lock | 777 +++++++- packages/gamecult-geometry-rs/Cargo.toml | 3 + .../gamecult-geometry-rs/src/assembler.rs | 1509 ++++++++++++++++ packages/gamecult-geometry-rs/src/brush.rs | 370 ++++ packages/gamecult-geometry-rs/src/convex.rs | 905 ++++++++++ packages/gamecult-geometry-rs/src/domain.rs | 1560 +++++++++++++++++ packages/gamecult-geometry-rs/src/dsl.rs | 164 ++ packages/gamecult-geometry-rs/src/frontier.rs | 321 ++++ packages/gamecult-geometry-rs/src/lib.rs | 117 ++ packages/gamecult-geometry-rs/src/mesh.rs | 103 ++ .../gamecult-geometry-rs/src/primitives.rs | 173 ++ .../src/realtime_csg_parity.rs | 166 ++ packages/gamecult-geometry-rs/src/tree.rs | 402 +++++ 14 files changed, 6598 insertions(+), 10 deletions(-) create mode 100644 packages/gamecult-geometry-rs/src/assembler.rs create mode 100644 packages/gamecult-geometry-rs/src/brush.rs create mode 100644 packages/gamecult-geometry-rs/src/convex.rs create mode 100644 packages/gamecult-geometry-rs/src/domain.rs create mode 100644 packages/gamecult-geometry-rs/src/dsl.rs create mode 100644 packages/gamecult-geometry-rs/src/frontier.rs create mode 100644 packages/gamecult-geometry-rs/src/mesh.rs create mode 100644 packages/gamecult-geometry-rs/src/primitives.rs create mode 100644 packages/gamecult-geometry-rs/src/realtime_csg_parity.rs create mode 100644 packages/gamecult-geometry-rs/src/tree.rs diff --git a/docs/cultmath-gamecult-geometry-migration-progress.md b/docs/cultmath-gamecult-geometry-migration-progress.md index 3a882a81..ace7653e 100644 --- a/docs/cultmath-gamecult-geometry-migration-progress.md +++ b/docs/cultmath-gamecult-geometry-migration-progress.md @@ -4,7 +4,7 @@ Plan: `docs/cultmath-gamecult-geometry-migration-plan.md` (locked) Started: 2026-07-22 -Status: Stages 0-1 complete; Stage 2 in progress +Status: Stages 0-4 complete; Stage 5 in progress ## Objective @@ -58,8 +58,8 @@ Demotions: | 1. Destination/dependency/formatters/SoA | Complete | NuGet and dedicated UPM artifacts prove dependency direction and owned vector integration | | 2. Primitive deletion and v2 schemas | Complete | C# and Geometry-owned Rust emit identical v2 bytes and record keys for all four roots | | 3. Planetary transfer | Complete | Managed, HLSL, CMPT, Unity, web, tool, docs, tests, and package authority moved; CultMath owners deleted | -| 4. Mine `vg-csg` | Pending | Requires v1 fixture capture and target Rust package seam | -| 5. CultCache/CultNet/CultMesh integration | Pending | Requires current schemas and runtime packages | +| 4. Mine `vg-csg` | Complete | Geometry-owned Rust kernel passes correctness, parity, performance, formatting, and warning-denied lint gates | +| 5. CultCache/CultNet/CultMesh integration | In progress | Provider/dataflow mapped; typed commit-path smoke remains | | 6. Consumer cutover/release | Pending | Requires local candidate feed and downstream passes | | 7. Delete obsolete authorities/audit | Pending | Requires every prior stage gate | @@ -226,11 +226,31 @@ a broader stage gate. planetary tests pass 41/41. Negative searches find obsolete CultMath geometry names only inside tests that assert their absence or ignored generated output. +### Stage 4 receipts + +- `packages/gamecult-geometry-rs` now owns the mined convex splitting, ordered + brush CSG, tree lowering, dirty frontiers, prefix checkpoints, domain/LOD + selection, feature lowering, and triangle/collider assembly kernels. No build + or runtime dependency points at VibeGeometry or `vg-csg`. +- The public `GeometryBrushAssembler` facade accepts Geometry-owned + `Float3` values and returns `GeometryTriangleMesh`; `bevy_math` remains a + private implementation dependency and is not re-exported. +- The duplicate quarry persistence authority (`DomainSpecDocument`, + `DomainNodeDocument`, `FeatureClaimDocument`, and its local schema version) + was deleted. Private specs are in-memory builders; the v2 `Geometry*` + documents remain the sole wire authority. +- Nine RealtimeCSG behavioral fixtures and a bounded 512-distant-cutter + performance fixture moved under Geometry ownership. `cargo test --locked` + passes 67/67 plus doc tests; rustfmt and warning-denied Clippy pass. +- The authority transfer commits are CultLib `756f5a33`, CultMath `6a16260`, + and the post-transfer label cleanup `99c893bd`. The Rust absorption commit is + recorded after this progress update is committed. + ## Next Actions -1. Mine convex splitting, brush/CSG tree, domain lowering, dirty-frontier, - selected-cut, and mesh assembly into `gamecult-geometry-rs` in dependency - order, preserving the pinned v1 evidence while emitting v2. -2. Remove `bevy_math` from the public Rust boundary and port earned correctness - and performance fixtures before deleting VibeGeometry build authority. -3. Connect the completed Rust runtime to the v2 CultCache/CultNet/CultMesh path. +1. Add the Geometry-owned worker provider with `CultNetDatabase.PutAsync` as + the single commit/publication primitive for direct and operation-handle use. +2. Prove domain/request to selected-cut/artifact persistence, raw envelope + replication, worker-state observation, and typed dev-probe agreement. +3. Add exact C#/Rust raw-envelope parity without growing a second networking + stack or a load-bearing JSON projection. diff --git a/packages/gamecult-geometry-rs/Cargo.lock b/packages/gamecult-geometry-rs/Cargo.lock index ba7661a8..986160f0 100644 --- a/packages/gamecult-geometry-rs/Cargo.lock +++ b/packages/gamecult-geometry-rs/Cargo.lock @@ -2,12 +2,147 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "assert_type_match" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f548ad2c4031f2902e3edc1f29c29e835829437de49562d8eb5dc5584d3a1043" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "autocfg" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" +[[package]] +name = "bevy_macro_utils" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62d984f9f8bd0f0d9fb020492a955e641e30e7a425f3588bf346cb3e61fec3c3" +dependencies = [ + "parking_lot", + "proc-macro2", + "quote", + "syn 2.0.119", + "toml_edit", +] + +[[package]] +name = "bevy_math" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fa74ae5d968749cc073da991757d3c7e3504ac6dbaac5f8c2a54b9d19b0b7ed" +dependencies = [ + "approx", + "bevy_reflect", + "derive_more", + "glam", + "itertools", + "rand", + "rand_distr", + "serde", + "smallvec", + "thiserror", + "variadics_please", +] + +[[package]] +name = "bevy_platform" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4691af6d7cfd1b5deb2fc926a43a180a546cdc3fe1e5a013fcee60db9bb2c81f" +dependencies = [ + "critical-section", + "foldhash", + "futures-channel", + "hashbrown 0.16.1", + "js-sys", + "portable-atomic", + "portable-atomic-util", + "serde", + "spin", + "wasm-bindgen", + "wasm-bindgen-futures", +] + +[[package]] +name = "bevy_ptr" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17d24d7906c7de556033168b3485de36c59049fbaef0c2c44c715a23e0329b10" + +[[package]] +name = "bevy_reflect" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5472b91928c0f3e4e3988c0d036b00719f19520f53a0c3f8c2af72f00e693c5" +dependencies = [ + "assert_type_match", + "bevy_platform", + "bevy_ptr", + "bevy_reflect_derive", + "bevy_utils", + "derive_more", + "disqualified", + "downcast-rs", + "erased-serde", + "foldhash", + "glam", + "serde", + "smol_str", + "thiserror", + "uuid", + "variadics_please", + "wgpu-types", +] + +[[package]] +name = "bevy_reflect_derive" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "083784255162fa39960aa3cf3c23af0e515db2daa7f2e796ae34df993f4d3f6c" +dependencies = [ + "bevy_macro_utils", + "indexmap", + "proc-macro2", + "quote", + "syn 2.0.119", + "uuid", +] + +[[package]] +name = "bevy_utils" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "789d04f88c764877a4552e07745b402dbc45f5d0545e6d102558f2f1752a1d89" +dependencies = [ + "bevy_platform", + "disqualified", +] + +[[package]] +name = "bitflags" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" +dependencies = [ + "serde_core", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -17,6 +152,32 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "bytemuck" +version = "1.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f65693059b6b9c588b9f62fed1cedbf0a8b805631457ea162d68f0de186f3de5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "cfg-if" version = "1.0.4" @@ -32,6 +193,12 @@ dependencies = [ "libc", ] +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + [[package]] name = "crypto-common" version = "0.1.7" @@ -42,6 +209,27 @@ dependencies = [ "typenum", ] +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.119", +] + [[package]] name = "digest" version = "0.10.7" @@ -52,10 +240,86 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "disqualified" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9c272297e804878a2a4b707cfcfc6d2328b5bb936944613b4fdf2b9269afdfd" + +[[package]] +name = "downcast-rs" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "117240f60069e65410b3ae1bb213295bd828f707b5bec6596a1afc8793ce0cbc" + +[[package]] +name = "either" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "erased-serde" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec" +dependencies = [ + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "futures-channel" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "262590f4fe6afeb0bc83be1daa64e52657fe185690a958af7f3ad0e92085c5ae" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7" + +[[package]] +name = "futures-task" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109" + +[[package]] +name = "futures-util" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] + [[package]] name = "gamecult-geometry" version = "0.1.0" dependencies = [ + "approx", + "bevy_math", "rmp-serde", "serde", "sha2", @@ -71,12 +335,120 @@ dependencies = [ "version_check", ] +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", +] + +[[package]] +name = "glam" +version = "0.30.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19fc433e8437a212d1b6f1e68c7824af3aed907da60afa994e7f542d18d12aa9" +dependencies = [ + "bytemuck", + "rand", + "serde_core", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "equivalent", + "serde", + "serde_core", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "js-sys" +version = "0.3.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + [[package]] name = "libc" version = "0.2.189" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + [[package]] name = "num-traits" version = "0.2.19" @@ -84,6 +456,66 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "portable-atomic" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d20d5497ef88037a52ff98267d066e7f11fcc5e99bbfbd58a42336193aacec3" + +[[package]] +name = "portable-atomic-util" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", ] [[package]] @@ -104,6 +536,66 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "rand_distr" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8615d50dcf34fa31f7ab52692afec947c4dd0ab803cc87cb3b0b4570ff7463" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + [[package]] name = "rmp" version = "0.8.15" @@ -123,6 +615,33 @@ dependencies = [ "serde", ] +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + [[package]] name = "serde" version = "1.0.229" @@ -150,7 +669,7 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.3", ] [[package]] @@ -164,6 +683,47 @@ dependencies = [ "digest", ] +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" + +[[package]] +name = "smol_str" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" +dependencies = [ + "serde", +] + +[[package]] +name = "spin" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "023a211cb3138dbc438680b32560ad89f699977624c9f8dbb95a47d5b4c07dd3" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "3.0.3" @@ -175,6 +735,62 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "thiserror" +version = "2.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a43598840e33d5b0331f38c5e30d13bb11c11210a4b58f0d9b18a5a5eefcd9" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43cbfe0cf76104d42a574802844187e84a305e531ed54455f11fbde0f10541cd" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.23.10+spec-1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow 0.7.15", +] + +[[package]] +name = "toml_parser" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +dependencies = [ + "winnow 1.0.4", +] + +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + [[package]] name = "typenum" version = "1.20.1" @@ -187,8 +803,167 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "uuid" +version = "1.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf3923a6f5c4c6382e0b653c4117f48d631ea17f38ed86e2a828e6f7412f5239" +dependencies = [ + "getrandom 0.4.3", + "js-sys", + "serde_core", + "wasm-bindgen", +] + +[[package]] +name = "variadics_please" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41b6d82be61465f97d42bd1d15bf20f3b0a3a0905018f38f9d6f6962055b0b5c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.119", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wgpu-types" +version = "26.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca7a8d8af57c18f57d393601a1fb159ace8b2328f1b6b5f80893f7d672c9ae2" +dependencies = [ + "bitflags", + "bytemuck", + "js-sys", + "log", + "serde", + "thiserror", + "web-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "zerocopy" +version = "0.8.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a105cd7b140f6eeec8acff2ea38135d3cab283ada58540f629fe51e46696eb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fe976fb70c78cd64cccfe3a6fc142244e8a77b70959b30faf9d0ac37ee228eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] diff --git a/packages/gamecult-geometry-rs/Cargo.toml b/packages/gamecult-geometry-rs/Cargo.toml index 4cabb87a..b05c0246 100644 --- a/packages/gamecult-geometry-rs/Cargo.toml +++ b/packages/gamecult-geometry-rs/Cargo.toml @@ -8,7 +8,10 @@ repository = "https://github.com/GameCult/CultLib" readme = "README.md" [dependencies] +bevy_math = "0.17" rmp-serde = "1" serde = { version = "1", features = ["derive"] } sha2 = "0.10" +[dev-dependencies] +approx = "0.5" diff --git a/packages/gamecult-geometry-rs/src/assembler.rs b/packages/gamecult-geometry-rs/src/assembler.rs new file mode 100644 index 00000000..078a07b5 --- /dev/null +++ b/packages/gamecult-geometry-rs/src/assembler.rs @@ -0,0 +1,1509 @@ +#![allow(dead_code)] +use std::cell::RefCell; + +use bevy_math::Vec3; + +use crate::{ + Aabb, Brush, BrushId, BrushOp, ConvexPolygon, ConvexSolid, DirtyDemandFrontier, MaterialId, + PolygonRouteScratch, Primitive, TriangleMesh, append_cylinder_z, append_dome_cap_z, + append_floret_arm, + primitives::{DomeCapZSpec, FloretArmSpec}, +}; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum BuildWarning { + SubtractIgnoredForNonBox { brush: String }, + IntersectIgnoredForNonBox { brush: String }, +} + +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct BuildReport { + pub input_brushes: usize, + pub emitted_convex_fragments: usize, + pub operator_brushes: usize, + pub candidate_pairs: usize, + pub rejected_pairs: usize, + pub reused_mesh: bool, + pub used_checkpoint: bool, + pub checkpoint_rebuild_from: Option, + pub direct_dirty_rebuild: bool, + pub warnings: Vec, +} + +#[derive(Clone, Debug)] +pub struct BuildOutput { + pub mesh: TriangleMesh, + pub report: BuildReport, + pub generation: u64, +} + +#[derive(Clone, Debug, Default)] +pub struct Assembler { + brushes: Vec, + compiled: Vec, + cache: RefCell>, + box_cache: RefCell>, + general_cache: RefCell>, + first_dirty_index: RefCell>, + next_id: u32, + generation: u64, +} + +#[derive(Clone, Debug)] +struct CompiledBrush { + op: BrushOp, + material: MaterialId, + bounds: Aabb, + geometry: CompiledGeometry, + name: String, +} + +#[derive(Clone, Debug)] +enum CompiledGeometry { + Box(Aabb), + Convex(ConvexSolid), + CylinderZ { + center: Vec3, + radius: f32, + depth: f32, + segments: usize, + }, + DomeCapZ { + center: Vec3, + radius: f32, + height: f32, + rings: usize, + segments: usize, + }, + FloretArm { + anchor: Vec3, + direction: Vec3, + length: f32, + root_width: f32, + tip_width: f32, + thickness: f32, + tip_lift: f32, + }, +} + +#[derive(Clone, Debug, Default)] +struct BoxBuildCache { + generation: u64, + valid_checkpoint_index: usize, + checkpoints: Vec, +} + +#[derive(Clone, Debug, Default, PartialEq)] +struct BoxBuildState { + boxes: Vec<(Aabb, MaterialId)>, + report: BuildReport, +} + +#[derive(Clone, Debug, Default)] +struct GeneralBuildCache { + generation: u64, + valid_checkpoint_index: usize, + checkpoints: Vec, +} + +#[derive(Clone, Debug, Default, PartialEq)] +struct GeneralBuildState { + mesh: TriangleMesh, + solids: Vec, + report: BuildReport, +} + +impl Assembler { + pub fn new() -> Self { + Self::default() + } + + pub fn brushes(&self) -> &[Brush] { + &self.brushes + } + + pub fn generation(&self) -> u64 { + self.generation + } + + pub fn brush_index(&self, id: BrushId) -> Option { + self.brushes.iter().position(|brush| brush.id == id) + } + + pub fn dirty_frontier_for_indices( + &self, + dirty_indices: impl IntoIterator, + ) -> DirtyDemandFrontier { + DirtyDemandFrontier::from_dirty_indices(&self.brushes, dirty_indices) + } + + pub fn dirty_frontier_for_brushes( + &self, + dirty_brushes: impl IntoIterator, + ) -> DirtyDemandFrontier { + let indices = dirty_brushes + .into_iter() + .filter_map(|id| self.brush_index(id)) + .collect::>(); + self.dirty_frontier_for_indices(indices) + } + + pub fn add_brush( + &mut self, + name: impl Into, + op: BrushOp, + primitive: Primitive, + material: MaterialId, + ) -> BrushId { + let id = BrushId(self.next_id); + self.next_id += 1; + let index = self.brushes.len(); + let brush = Brush::new(id, name, op, primitive, material); + self.compiled.push(CompiledBrush::from_brush(&brush)); + self.brushes.push(brush); + self.generation = self.generation.wrapping_add(1); + self.mark_dirty_index(index); + id + } + + pub fn set_brush_primitive(&mut self, id: BrushId, primitive: Primitive) -> bool { + let Some(index) = self.brush_index(id) else { + return false; + }; + self.brushes[index].primitive = primitive; + self.brushes[index].set_dirty(); + self.compiled[index] = CompiledBrush::from_brush(&self.brushes[index]); + self.generation = self.generation.wrapping_add(1); + self.mark_dirty_index(index); + true + } + + pub fn set_brush_op(&mut self, id: BrushId, op: BrushOp) -> bool { + let Some(index) = self.brush_index(id) else { + return false; + }; + self.brushes[index].op = op; + self.brushes[index].set_dirty(); + self.compiled[index] = CompiledBrush::from_brush(&self.brushes[index]); + self.generation = self.generation.wrapping_add(1); + self.mark_dirty_index(index); + true + } + + pub fn solid_box( + &mut self, + name: impl Into, + bounds: Aabb, + material: MaterialId, + ) -> BrushId { + self.add_brush(name, BrushOp::Add, Primitive::Box { bounds }, material) + } + + pub fn cut_box(&mut self, name: impl Into, bounds: Aabb) -> BrushId { + self.add_brush( + name, + BrushOp::Subtract, + Primitive::Box { bounds }, + MaterialId::default(), + ) + } + + pub fn solid_oriented_box( + &mut self, + name: impl Into, + center: Vec3, + size: Vec3, + rotation: bevy_math::Quat, + material: MaterialId, + ) -> BrushId { + self.add_brush( + name, + BrushOp::Add, + Primitive::OrientedBox { + center, + size, + rotation, + }, + material, + ) + } + + pub fn cut_oriented_box( + &mut self, + name: impl Into, + center: Vec3, + size: Vec3, + rotation: bevy_math::Quat, + ) -> BrushId { + self.add_brush( + name, + BrushOp::Subtract, + Primitive::OrientedBox { + center, + size, + rotation, + }, + MaterialId::default(), + ) + } + + pub fn build(&self) -> BuildOutput { + if let Some(output) = self + .cache + .borrow() + .as_ref() + .filter(|output| output.generation == self.generation) + { + return output.clone(); + } + + let output = self.build_with_checkpoints(); + *self.cache.borrow_mut() = Some(output.clone()); + *self.first_dirty_index.borrow_mut() = None; + output + } + + pub fn build_incremental(&self) -> BuildOutput { + if let Some(output) = self + .cache + .borrow() + .as_ref() + .filter(|output| output.generation == self.generation) + { + return output.clone(); + } + + let first_dirty_index = *self.first_dirty_index.borrow(); + let output = self + .try_build_axis_aligned_boxes_from_cache(first_dirty_index) + .unwrap_or_else(|| self.build_general_from_cache(first_dirty_index)); + *self.cache.borrow_mut() = Some(output.clone()); + *self.first_dirty_index.borrow_mut() = None; + output + } + + pub fn rebuild_incremental_for_indices( + &self, + dirty_indices: impl IntoIterator, + ) -> BuildOutput { + let first_dirty_index = self + .dirty_frontier_for_indices(dirty_indices) + .first_dirty_index; + self.try_build_axis_aligned_boxes_from_cache(first_dirty_index) + .unwrap_or_else(|| self.build_general_from_cache(first_dirty_index)) + } + + pub fn rebuild_incremental_for_brushes( + &self, + dirty_brushes: impl IntoIterator, + ) -> BuildOutput { + let indices = dirty_brushes + .into_iter() + .filter_map(|id| self.brush_index(id)) + .collect::>(); + self.rebuild_incremental_for_indices(indices) + } + + pub fn rebuild(&self) -> BuildOutput { + self.build_uncached() + } + + pub fn rebuild_routed_surfaces(&self) -> BuildOutput { + self.try_build_routed_surfaces() + .unwrap_or_else(|| self.build_uncached()) + } + + pub fn supports_routed_surfaces(&self) -> bool { + self.supports_routed_surface_subset() + } + + fn mark_dirty_index(&self, index: usize) { + let mut first_dirty_index = self.first_dirty_index.borrow_mut(); + *first_dirty_index = Some(first_dirty_index.map_or(index, |dirty| dirty.min(index))); + } + + fn try_build_routed_surfaces(&self) -> Option { + if !self.supports_routed_surface_subset() { + return None; + } + + let mut report = BuildReport { + input_brushes: self.brushes.len(), + ..BuildReport::default() + }; + let mut source = None::; + let mut surfaces = Vec::::new(); + let mut previous_cutters = Vec::::new(); + let mut scratch = PolygonRouteScratch::default(); + + for brush in &self.compiled { + match brush.op { + BrushOp::Add => { + if source.is_some() { + return None; + } + let solid = brush.convex_cutter()?; + surfaces = solid.polygons.clone(); + source = Some(solid); + } + BrushOp::Subtract => { + report.operator_brushes += 1; + let source_solid = source.as_ref()?; + if !source_solid.bounds.intersects(brush.bounds) { + report.rejected_pairs += 1; + continue; + } + let cutter = brush.convex_cutter()?; + report.candidate_pairs += 1; + surfaces = scratch.route_outside_of(surfaces, &cutter); + + let mut caps = scratch.route_inside_of(cutter.polygons.clone(), source_solid); + for previous in &previous_cutters { + caps = scratch.route_outside_of(caps, previous); + } + for cap in &mut caps { + cap.material = source_solid.material; + cap.reversed = !cap.reversed; + } + surfaces.extend(caps); + previous_cutters.push(cutter); + } + BrushOp::Intersect => return None, + } + } + + let mut mesh = TriangleMesh::new(); + ConvexSolid::append_polygons_to_mesh(&surfaces, &mut mesh); + report.emitted_convex_fragments = surfaces.len(); + + Some(BuildOutput { + mesh, + report, + generation: self.generation, + }) + } + + fn supports_routed_surface_subset(&self) -> bool { + let mut source = None::; + let mut candidate_subtracts = 0usize; + + for brush in &self.compiled { + match brush.op { + BrushOp::Add => { + if source.is_some() || brush.convex_cutter().is_none() { + return false; + } + source = Some(brush.bounds); + } + BrushOp::Subtract => { + let Some(source_bounds) = source else { + return false; + }; + if brush.convex_cutter().is_none() { + return false; + } + if source_bounds.intersects(brush.bounds) { + candidate_subtracts += 1; + if candidate_subtracts > 1 { + return false; + } + } + } + BrushOp::Intersect => return false, + } + } + + source.is_some() && candidate_subtracts == 1 + } + + fn build_uncached(&self) -> BuildOutput { + if self + .compiled + .iter() + .all(|brush| matches!(brush.geometry, CompiledGeometry::Box(_))) + { + return self.build_axis_aligned_boxes_direct(); + } + + self.build_general_direct() + } + + fn build_with_checkpoints(&self) -> BuildOutput { + self.try_build_axis_aligned_boxes_from_cache(Some(0)) + .unwrap_or_else(|| self.build_general_from_cache(Some(0))) + } + + fn build_general_direct(&self) -> BuildOutput { + let mut state = GeneralBuildState::default(); + for brush in &self.compiled { + state.apply_compiled_brush(brush); + } + state.into_output(self.brushes.len(), self.generation) + } + + fn build_axis_aligned_boxes_direct(&self) -> BuildOutput { + let mut state = BoxBuildState::default(); + for brush in &self.compiled { + state.apply_compiled_box(brush); + } + state.report.direct_dirty_rebuild = true; + state.into_output_with_mesh(self.brushes.len(), self.generation, None) + } + + fn try_build_axis_aligned_boxes_from_cache( + &self, + first_dirty_index: Option, + ) -> Option { + if !self + .compiled + .iter() + .all(|brush| matches!(brush.geometry, CompiledGeometry::Box(_))) + { + return None; + } + + let brush_count = self.compiled.len(); + let previous_output = self.cache.borrow().as_ref().cloned(); + if let Some(first_dirty_index) = first_dirty_index + && first_dirty_index > 0 + { + return Some(self.build_axis_aligned_boxes_direct()); + } + let rebuild_from = match first_dirty_index { + Some(index) => index.min(brush_count), + None => self + .box_cache + .borrow() + .as_ref() + .filter(|cache| { + cache.generation == self.generation + && cache.valid_checkpoint_index == brush_count + && cache.checkpoints.len() == brush_count + 1 + }) + .map_or(0, |_| brush_count), + }; + let cached_state = self + .box_cache + .borrow() + .as_ref() + .filter(|cache| rebuild_from <= cache.valid_checkpoint_index) + .and_then(|cache| cache.checkpoints.get(rebuild_from).cloned()); + let (mut state, start_index) = if let Some(state) = cached_state { + (state, rebuild_from) + } else { + (BoxBuildState::default(), 0) + }; + if start_index > 0 { + state.report.used_checkpoint = true; + state.report.checkpoint_rebuild_from = Some(start_index); + } + + let mut checkpoints = (start_index == 0).then(|| vec![BoxBuildState::default()]); + + let mut changed_geometry = start_index == 0; + for brush in &self.compiled[start_index..] { + changed_geometry |= state.apply_compiled_box(brush); + if let Some(checkpoints) = &mut checkpoints { + checkpoints.push(state.clone()); + } + } + + if let Some(checkpoints) = checkpoints { + *self.box_cache.borrow_mut() = Some(BoxBuildCache { + generation: self.generation, + valid_checkpoint_index: brush_count, + checkpoints, + }); + } else if let Some(cache) = self.box_cache.borrow_mut().as_mut() { + cache.generation = self.generation; + cache.valid_checkpoint_index = cache.valid_checkpoint_index.min(start_index); + } + + let reused_mesh = (!changed_geometry) + .then_some(previous_output) + .flatten() + .map(|output| output.mesh); + Some(state.into_output_with_mesh(self.brushes.len(), self.generation, reused_mesh)) + } + + fn build_general_from_cache(&self, first_dirty_index: Option) -> BuildOutput { + let brush_count = self.compiled.len(); + let previous_output = self.cache.borrow().as_ref().cloned(); + let rebuild_from = match first_dirty_index { + Some(index) => index.min(brush_count), + None => self + .general_cache + .borrow() + .as_ref() + .filter(|cache| { + cache.generation == self.generation + && cache.valid_checkpoint_index == brush_count + && cache.checkpoints.len() == brush_count + 1 + }) + .map_or(0, |_| brush_count), + }; + let cached_state = self + .general_cache + .borrow() + .as_ref() + .filter(|cache| rebuild_from <= cache.valid_checkpoint_index) + .and_then(|cache| cache.checkpoints.get(rebuild_from).cloned()); + let (mut state, start_index) = if let Some(state) = cached_state { + (state, rebuild_from) + } else { + (GeneralBuildState::default(), 0) + }; + if start_index > 0 { + state.report.used_checkpoint = true; + state.report.checkpoint_rebuild_from = Some(start_index); + } + + let mut checkpoints = (start_index == 0).then(|| vec![GeneralBuildState::default()]); + + let mut changed_geometry = start_index == 0; + for brush in &self.compiled[start_index..] { + changed_geometry |= state.apply_compiled_brush(brush); + if let Some(checkpoints) = &mut checkpoints { + checkpoints.push(state.clone()); + } + } + + if let Some(checkpoints) = checkpoints { + *self.general_cache.borrow_mut() = Some(GeneralBuildCache { + generation: self.generation, + valid_checkpoint_index: brush_count, + checkpoints, + }); + } else if let Some(cache) = self.general_cache.borrow_mut().as_mut() { + cache.generation = self.generation; + cache.valid_checkpoint_index = cache.valid_checkpoint_index.min(start_index); + } + + let reused_mesh = (!changed_geometry) + .then_some(previous_output) + .flatten() + .map(|output| output.mesh); + state.into_output_with_mesh(self.brushes.len(), self.generation, reused_mesh) + } + + pub fn sample_room_with_door() -> Self { + let wall = MaterialId(1); + let floor = MaterialId(2); + let mut asm = Self::new(); + asm.solid_box( + "floor", + Aabb::from_center_size(Vec3::new(0.0, 0.0, -0.1), Vec3::new(8.0, 8.0, 0.2)), + floor, + ); + asm.solid_box( + "north wall", + Aabb::from_center_size(Vec3::new(0.0, 4.0, 1.5), Vec3::new(8.0, 0.25, 3.0)), + wall, + ); + asm.cut_box( + "door void", + Aabb::from_center_size(Vec3::new(0.0, 4.0, 1.0), Vec3::new(1.2, 0.5, 2.0)), + ); + asm + } +} + +impl CompiledBrush { + fn from_brush(brush: &Brush) -> Self { + let bounds = brush.bounds(); + let geometry = match &brush.primitive { + Primitive::Box { bounds } => CompiledGeometry::Box(*bounds), + Primitive::OrientedBox { + center, + size, + rotation, + } => CompiledGeometry::Convex(ConvexSolid::box_from_center_size( + *center, + *size, + *rotation, + brush.material, + )), + Primitive::CylinderZ { + center, + radius, + depth, + segments, + } => CompiledGeometry::CylinderZ { + center: *center, + radius: *radius, + depth: *depth, + segments: *segments, + }, + Primitive::DomeCapZ { + center, + radius, + height, + rings, + segments, + } => CompiledGeometry::DomeCapZ { + center: *center, + radius: *radius, + height: *height, + rings: *rings, + segments: *segments, + }, + Primitive::FloretArm { + anchor, + direction, + length, + root_width, + tip_width, + thickness, + tip_lift, + } => CompiledGeometry::FloretArm { + anchor: *anchor, + direction: *direction, + length: *length, + root_width: *root_width, + tip_width: *tip_width, + thickness: *thickness, + tip_lift: *tip_lift, + }, + }; + + Self { + op: brush.op, + material: brush.material, + bounds, + geometry, + name: brush.name.clone(), + } + } + + fn convex_cutter(&self) -> Option { + match &self.geometry { + CompiledGeometry::Box(bounds) => Some(ConvexSolid::from_aabb(*bounds, self.material)), + CompiledGeometry::Convex(solid) => Some(solid.clone()), + _ => None, + } + } +} + +impl BoxBuildState { + fn apply_compiled_box(&mut self, brush: &CompiledBrush) -> bool { + let CompiledGeometry::Box(bounds) = brush.geometry else { + unreachable!("box build state received a non-box brush"); + }; + + match brush.op { + BrushOp::Add => { + self.boxes.push((bounds, brush.material)); + true + } + BrushOp::Subtract => { + self.report.operator_brushes += 1; + if !bounds.intersects_any(self.boxes.iter().map(|(bounds, _)| *bounds)) { + self.report.rejected_pairs += self.boxes.len(); + return false; + } + + let mut out = Vec::with_capacity(self.boxes.len() + 4); + for (solid, material) in self.boxes.drain(..) { + if solid.intersects(bounds) { + self.report.candidate_pairs += 1; + out.extend( + solid + .subtract_box(bounds) + .into_iter() + .map(|piece| (piece, material)), + ); + } else { + self.report.rejected_pairs += 1; + out.push((solid, material)); + } + } + self.boxes = out; + true + } + BrushOp::Intersect => { + self.report.operator_brushes += 1; + if !bounds.intersects_any(self.boxes.iter().map(|(bounds, _)| *bounds)) { + let changed = !self.boxes.is_empty(); + self.report.rejected_pairs += self.boxes.len(); + self.boxes.clear(); + return changed; + } + + self.boxes = self + .boxes + .drain(..) + .filter_map(|(solid, material)| { + if let Some(hit) = solid.intersection(bounds) { + self.report.candidate_pairs += 1; + Some((hit, material)) + } else { + self.report.rejected_pairs += 1; + None + } + }) + .collect(); + true + } + } + } + + fn into_output_with_mesh( + mut self, + input_brushes: usize, + generation: u64, + reused_mesh: Option, + ) -> BuildOutput { + let mut mesh = TriangleMesh::new(); + self.report.input_brushes = input_brushes; + self.report.emitted_convex_fragments = self.boxes.len(); + if let Some(reused_mesh) = reused_mesh { + self.report.reused_mesh = true; + mesh = reused_mesh; + } else { + for (bounds, material) in self.boxes { + mesh.append_box(bounds, material); + } + } + + BuildOutput { + mesh, + report: self.report, + generation, + } + } +} + +impl GeneralBuildState { + fn apply_compiled_brush(&mut self, brush: &CompiledBrush) -> bool { + match brush.op { + BrushOp::Add => { + self.add_brush_geometry(brush); + true + } + BrushOp::Subtract => { + self.report.operator_brushes += 1; + if !brush + .bounds + .intersects_any(self.solids.iter().map(|solid| solid.bounds)) + { + self.report.rejected_pairs += self.solids.len(); + return false; + } + if let Some(cutter) = brush.convex_cutter() { + self.solids = subtract_from_solids( + std::mem::take(&mut self.solids), + &cutter, + &mut self.report, + ); + true + } else { + let has_candidate = + record_solid_pairs(&self.solids, brush.bounds, &mut self.report); + if has_candidate { + self.report + .warnings + .push(BuildWarning::SubtractIgnoredForNonBox { + brush: brush.name.clone(), + }); + } + false + } + } + BrushOp::Intersect => { + self.report.operator_brushes += 1; + if !brush + .bounds + .intersects_any(self.solids.iter().map(|solid| solid.bounds)) + { + let changed = !self.solids.is_empty(); + self.report.rejected_pairs += self.solids.len(); + self.solids.clear(); + return changed; + } + if let Some(cutter) = brush.convex_cutter() { + self.solids = intersect_solids( + std::mem::take(&mut self.solids), + &cutter, + &mut self.report, + ); + true + } else { + let has_candidate = + record_solid_pairs(&self.solids, brush.bounds, &mut self.report); + let changed = !self.solids.is_empty(); + self.solids.clear(); + if has_candidate { + self.report + .warnings + .push(BuildWarning::IntersectIgnoredForNonBox { + brush: brush.name.clone(), + }); + } + changed + } + } + } + } + + fn add_brush_geometry(&mut self, brush: &CompiledBrush) { + match &brush.geometry { + CompiledGeometry::Box(bounds) => { + self.solids + .push(ConvexSolid::from_aabb(*bounds, brush.material)); + } + CompiledGeometry::Convex(solid) => self.solids.push(solid.clone()), + CompiledGeometry::CylinderZ { + center, + radius, + depth, + segments, + } => append_cylinder_z( + &mut self.mesh, + *center, + *radius, + *depth, + *segments, + brush.material, + ), + CompiledGeometry::DomeCapZ { + center, + radius, + height, + rings, + segments, + } => append_dome_cap_z( + &mut self.mesh, + DomeCapZSpec { + center: *center, + radius: *radius, + height: *height, + rings: *rings, + segments: *segments, + material: brush.material, + }, + ), + CompiledGeometry::FloretArm { + anchor, + direction, + length, + root_width, + tip_width, + thickness, + tip_lift, + } => append_floret_arm( + &mut self.mesh, + FloretArmSpec { + anchor: *anchor, + direction: *direction, + length: *length, + root_width: *root_width, + tip_width: *tip_width, + thickness: *thickness, + tip_lift: *tip_lift, + material: brush.material, + }, + ), + } + } + + fn into_output(self, input_brushes: usize, generation: u64) -> BuildOutput { + self.into_output_with_mesh(input_brushes, generation, None) + } + + fn into_output_with_mesh( + mut self, + input_brushes: usize, + generation: u64, + reused_mesh: Option, + ) -> BuildOutput { + self.report.input_brushes = input_brushes; + self.report.emitted_convex_fragments = self.solids.len(); + if let Some(reused_mesh) = reused_mesh { + self.report.reused_mesh = true; + self.mesh = reused_mesh; + } else { + for solid in self.solids { + solid.append_to_mesh(&mut self.mesh); + } + } + + BuildOutput { + mesh: self.mesh, + report: self.report, + generation, + } + } +} + +fn subtract_from_solids( + solids: Vec, + cutter: &ConvexSolid, + report: &mut BuildReport, +) -> Vec { + let mut out = Vec::with_capacity(solids.len() + 4); + for solid in solids { + if solid.bounds.intersects(cutter.bounds) { + report.candidate_pairs += 1; + out.extend(solid.subtract_convex_owned(cutter)); + } else { + report.rejected_pairs += 1; + out.push(solid); + } + } + out +} + +fn intersect_solids( + solids: Vec, + cutter: &ConvexSolid, + report: &mut BuildReport, +) -> Vec { + let mut out = Vec::with_capacity(solids.len()); + for solid in solids { + if !solid.bounds.intersects(cutter.bounds) { + report.rejected_pairs += 1; + continue; + } + report.candidate_pairs += 1; + if let Some(fragment) = solid.intersect_convex_owned(cutter) { + out.push(fragment); + } + } + out +} + +fn record_solid_pairs(solids: &[ConvexSolid], bounds: Aabb, report: &mut BuildReport) -> bool { + let mut has_candidate = false; + for solid in solids { + if solid.bounds.intersects(bounds) { + report.candidate_pairs += 1; + has_candidate = true; + } else { + report.rejected_pairs += 1; + } + } + has_candidate +} + +#[cfg(test)] +mod tests { + use bevy_math::Vec3; + + use super::*; + + #[test] + fn centered_subtract_splits_box_into_six_fragments() { + let source = Aabb::from_center_size(Vec3::ZERO, Vec3::splat(4.0)); + let cutter = Aabb::from_center_size(Vec3::ZERO, Vec3::splat(2.0)); + let pieces = source.subtract_box(cutter); + + assert_eq!(pieces.len(), 6); + assert!(pieces.iter().all(|piece| piece.is_valid())); + assert!(pieces.iter().all(|piece| !piece.intersects(cutter))); + } + + #[test] + fn door_cut_leaves_no_box_fragment_inside_void() { + let output = Assembler::sample_room_with_door().build(); + let cutter = Aabb::from_center_size(Vec3::new(0.0, 4.0, 1.0), Vec3::new(1.2, 0.5, 2.0)); + + assert!(output.report.emitted_convex_fragments > 2); + for tri in output.mesh.indices.chunks_exact(3) { + let center = (output.mesh.positions[tri[0] as usize] + + output.mesh.positions[tri[1] as usize] + + output.mesh.positions[tri[2] as usize]) + / 3.0; + assert!(!cutter.contains_point_strict(center, 1.0e-4)); + } + } + + #[test] + fn rotated_door_cut_produces_diagonal_portal_faces() { + let mut asm = Assembler::new(); + asm.solid_box( + "wall", + Aabb::from_center_size(Vec3::new(0.0, 0.0, 1.5), Vec3::new(5.0, 0.5, 3.0)), + MaterialId(1), + ); + asm.cut_oriented_box( + "angled void", + Vec3::new(0.0, 0.0, 1.5), + Vec3::new(1.5, 2.0, 2.0), + bevy_math::Quat::from_rotation_z(std::f32::consts::FRAC_PI_4), + ); + + let output = asm.build(); + assert!(output.report.emitted_convex_fragments > 2); + assert!(output.mesh.normals.iter().any(|normal| { + normal.x.abs() > 0.2 && normal.y.abs() > 0.2 && normal.z.abs() < 0.1 + })); + } + + #[test] + fn mesh_box_emits_twelve_triangles() { + let mut mesh = TriangleMesh::new(); + mesh.append_box(Aabb::from_center_size(Vec3::ZERO, Vec3::ONE), MaterialId(7)); + + assert_eq!(mesh.triangle_count(), 12); + assert_eq!(mesh.triangle_materials.len(), 12); + assert_eq!(mesh.triangle_materials[0], MaterialId(7)); + } + + #[test] + fn distant_subtract_skips_convex_split_and_keeps_source_solid() { + let mut asm = Assembler::new(); + asm.solid_box( + "source", + Aabb::from_center_size(Vec3::ZERO, Vec3::splat(2.0)), + MaterialId(1), + ); + asm.cut_box( + "far void", + Aabb::from_center_size(Vec3::splat(10.0), Vec3::splat(1.0)), + ); + + let output = asm.build(); + assert_eq!(output.report.emitted_convex_fragments, 1); + assert_eq!(output.report.operator_brushes, 1); + assert_eq!(output.report.candidate_pairs, 0); + assert_eq!(output.report.rejected_pairs, 1); + assert_eq!(output.mesh.triangle_count(), 12); + } + + #[test] + fn intersecting_box_keeps_common_convex_region() { + let mut asm = Assembler::new(); + asm.solid_box( + "a", + Aabb::from_center_size(Vec3::ZERO, Vec3::splat(4.0)), + MaterialId(1), + ); + asm.add_brush( + "b", + BrushOp::Intersect, + Primitive::Box { + bounds: Aabb::from_center_size(Vec3::X, Vec3::splat(4.0)), + }, + MaterialId(1), + ); + + let output = asm.build(); + assert_eq!(output.report.emitted_convex_fragments, 1); + assert_eq!(output.report.operator_brushes, 1); + assert_eq!(output.report.candidate_pairs, 1); + assert_eq!(output.report.rejected_pairs, 0); + assert_eq!(output.report.warnings.len(), 0); + assert_eq!(output.mesh.triangle_count(), 12); + } + + #[test] + fn cached_build_and_dirty_rebuild_emit_same_output() { + let mut asm = Assembler::new(); + asm.solid_box( + "slab", + Aabb::from_center_size(Vec3::ZERO, Vec3::new(8.0, 8.0, 2.0)), + MaterialId(1), + ); + asm.cut_box( + "center void", + Aabb::from_center_size(Vec3::ZERO, Vec3::splat(2.0)), + ); + asm.cut_oriented_box( + "angled void", + Vec3::new(1.0, 1.0, 0.0), + Vec3::new(1.25, 4.0, 2.5), + bevy_math::Quat::from_rotation_z(0.35), + ); + + let stable = asm.build(); + let cached = asm.build(); + let dirty = asm.rebuild(); + + assert_eq!( + stable.report.emitted_convex_fragments, + dirty.report.emitted_convex_fragments + ); + assert_eq!( + stable.report.operator_brushes, + dirty.report.operator_brushes + ); + assert_eq!(stable.report.candidate_pairs, dirty.report.candidate_pairs); + assert_eq!(stable.report.rejected_pairs, dirty.report.rejected_pairs); + assert_eq!(stable.report.warnings, dirty.report.warnings); + assert_eq!(stable.mesh.triangle_count(), dirty.mesh.triangle_count()); + assert_eq!(stable.mesh.vertex_count(), dirty.mesh.vertex_count()); + assert_eq!(stable.mesh.positions, dirty.mesh.positions); + assert_eq!(stable.mesh.indices, dirty.mesh.indices); + assert_eq!(cached.mesh.positions, stable.mesh.positions); + assert_eq!(cached.mesh.indices, stable.mesh.indices); + } + + #[test] + fn routed_surface_rebuild_emits_clean_center_cut_boundary() { + let mut asm = Assembler::new(); + let cutter = Aabb::from_center_size(Vec3::ZERO, Vec3::splat(2.0)); + asm.solid_box( + "source", + Aabb::from_center_size(Vec3::ZERO, Vec3::splat(4.0)), + MaterialId(1), + ); + asm.cut_box("void", cutter); + + let routed = asm.rebuild_routed_surfaces(); + + assert_eq!(routed.report.operator_brushes, 1); + assert_eq!(routed.report.candidate_pairs, 1); + assert_eq!(routed.report.rejected_pairs, 0); + assert_eq!(routed.report.emitted_convex_fragments, 24); + assert!(routed.mesh.triangle_count() < asm.rebuild().mesh.triangle_count()); + for tri in routed.mesh.indices.chunks_exact(3) { + let center = (routed.mesh.positions[tri[0] as usize] + + routed.mesh.positions[tri[1] as usize] + + routed.mesh.positions[tri[2] as usize]) + / 3.0; + assert!(!cutter.contains_point_strict(center, 1.0e-4)); + } + } + + #[test] + fn routed_surface_rebuild_falls_back_for_intersections() { + let mut asm = Assembler::new(); + asm.solid_box( + "source", + Aabb::from_center_size(Vec3::ZERO, Vec3::splat(4.0)), + MaterialId(1), + ); + asm.add_brush( + "common", + BrushOp::Intersect, + Primitive::Box { + bounds: Aabb::from_center_size(Vec3::X, Vec3::splat(4.0)), + }, + MaterialId(1), + ); + + let stable = asm.rebuild(); + let routed = asm.rebuild_routed_surfaces(); + + assert_eq!( + routed.report.emitted_convex_fragments, + stable.report.emitted_convex_fragments + ); + assert_eq!(routed.mesh.triangle_count(), stable.mesh.triangle_count()); + assert_eq!(routed.mesh.positions, stable.mesh.positions); + assert_eq!(routed.mesh.indices, stable.mesh.indices); + } + + #[test] + fn routed_surface_rebuild_falls_back_for_multiple_candidate_cutters() { + let mut asm = Assembler::new(); + asm.solid_box( + "source", + Aabb::from_center_size(Vec3::ZERO, Vec3::splat(4.0)), + MaterialId(1), + ); + asm.cut_oriented_box( + "a", + Vec3::new(-0.5, 0.0, 0.0), + Vec3::new(1.0, 5.0, 5.0), + bevy_math::Quat::from_rotation_z(0.25), + ); + asm.cut_oriented_box( + "b", + Vec3::new(0.5, 0.0, 0.0), + Vec3::new(1.0, 5.0, 5.0), + bevy_math::Quat::from_rotation_z(-0.25), + ); + + let stable = asm.rebuild(); + let routed = asm.rebuild_routed_surfaces(); + + assert_eq!( + routed.report.emitted_convex_fragments, + stable.report.emitted_convex_fragments + ); + assert_eq!(routed.mesh.triangle_count(), stable.mesh.triangle_count()); + assert_eq!(routed.mesh.positions, stable.mesh.positions); + assert_eq!(routed.mesh.indices, stable.mesh.indices); + } + + #[test] + fn routed_surface_rebuild_falls_back_when_no_cutter_touches_source() { + let mut asm = Assembler::new(); + asm.solid_box( + "source", + Aabb::from_center_size(Vec3::ZERO, Vec3::splat(4.0)), + MaterialId(1), + ); + asm.cut_box( + "far", + Aabb::from_center_size(Vec3::splat(20.0), Vec3::splat(2.0)), + ); + + let stable = asm.rebuild(); + let routed = asm.rebuild_routed_surfaces(); + + assert_eq!( + routed.report.emitted_convex_fragments, + stable.report.emitted_convex_fragments + ); + assert_eq!(routed.mesh.triangle_count(), stable.mesh.triangle_count()); + assert_eq!(routed.mesh.positions, stable.mesh.positions); + assert_eq!(routed.mesh.indices, stable.mesh.indices); + } + + #[test] + fn mutating_brush_primitive_invalidates_cache_and_exposes_dirty_frontier() { + let mut asm = Assembler::new(); + let source = asm.solid_box( + "source", + Aabb::from_center_size(Vec3::ZERO, Vec3::splat(4.0)), + MaterialId(1), + ); + let cutter = asm.cut_box("void", Aabb::from_center_size(Vec3::ZERO, Vec3::splat(1.0))); + let before = asm.build(); + + assert!(asm.set_brush_primitive( + cutter, + Primitive::Box { + bounds: Aabb::from_center_size(Vec3::ZERO, Vec3::splat(2.0)), + }, + )); + let frontier = asm.dirty_frontier_for_brushes([cutter]); + let after = asm.build(); + + assert_eq!(frontier.first_dirty_index, Some(1)); + assert_eq!(frontier.operator_brushes, 1); + assert_eq!(frontier.candidate_pairs(), 1); + assert_eq!(frontier.rejected_pairs, 0); + assert!(after.generation > before.generation); + assert_ne!(after.mesh.positions, before.mesh.positions); + assert_eq!(asm.brush_index(source), Some(0)); + assert_eq!(asm.brush_index(cutter), Some(1)); + } + + #[test] + fn incremental_box_rebuild_reuses_prefix_and_matches_full_rebuild() { + let mut asm = Assembler::new(); + asm.solid_box( + "source", + Aabb::from_center_size(Vec3::ZERO, Vec3::splat(8.0)), + MaterialId(1), + ); + asm.cut_box( + "early", + Aabb::from_center_size(Vec3::new(-2.0, 0.0, 0.0), Vec3::splat(2.0)), + ); + let dirty = asm.cut_box( + "dirty", + Aabb::from_center_size(Vec3::ZERO, Vec3::splat(2.0)), + ); + asm.cut_box( + "late", + Aabb::from_center_size(Vec3::new(2.0, 0.0, 0.0), Vec3::splat(2.0)), + ); + let before = asm.build(); + + assert!(asm.set_brush_primitive( + dirty, + Primitive::Box { + bounds: Aabb::from_center_size(Vec3::ZERO, Vec3::splat(3.0)), + }, + )); + let incremental = asm.build_incremental(); + let full = asm.rebuild(); + + assert!(!incremental.report.used_checkpoint); + assert!(incremental.report.direct_dirty_rebuild); + assert_eq!(incremental.mesh.positions, full.mesh.positions); + assert_eq!(incremental.mesh.indices, full.mesh.indices); + assert_eq!( + incremental.report.candidate_pairs, + full.report.candidate_pairs + ); + assert_eq!( + incremental.report.rejected_pairs, + full.report.rejected_pairs + ); + assert_eq!(incremental.generation, full.generation); + assert_ne!(incremental.mesh.positions, before.mesh.positions); + } + + #[test] + fn explicit_incremental_box_rebuild_matches_full_rebuild() { + let mut asm = Assembler::new(); + asm.solid_box( + "source", + Aabb::from_center_size(Vec3::ZERO, Vec3::splat(8.0)), + MaterialId(1), + ); + asm.cut_box( + "early", + Aabb::from_center_size(Vec3::new(-2.0, 0.0, 0.0), Vec3::splat(2.0)), + ); + let dirty = asm.cut_box( + "dirty", + Aabb::from_center_size(Vec3::ZERO, Vec3::splat(2.0)), + ); + asm.cut_box( + "late", + Aabb::from_center_size(Vec3::new(2.0, 0.0, 0.0), Vec3::splat(2.0)), + ); + asm.build_incremental(); + + assert!(asm.set_brush_primitive( + dirty, + Primitive::Box { + bounds: Aabb::from_center_size(Vec3::ZERO, Vec3::splat(3.0)), + }, + )); + let incremental = asm.rebuild_incremental_for_brushes([dirty]); + let full = asm.rebuild(); + + assert_eq!(incremental.mesh.positions, full.mesh.positions); + assert_eq!(incremental.mesh.indices, full.mesh.indices); + assert_eq!( + incremental.report.candidate_pairs, + full.report.candidate_pairs + ); + assert_eq!( + incremental.report.rejected_pairs, + full.report.rejected_pairs + ); + } + + #[test] + fn incremental_distant_tail_edit_reuses_previous_mesh() { + let mut asm = Assembler::new(); + asm.solid_box( + "source", + Aabb::from_center_size(Vec3::ZERO, Vec3::splat(8.0)), + MaterialId(1), + ); + let far = asm.cut_oriented_box( + "far", + Vec3::splat(100.0), + Vec3::splat(1.0), + bevy_math::Quat::from_rotation_z(0.2), + ); + let before = asm.build_incremental(); + + assert!(asm.set_brush_primitive( + far, + Primitive::OrientedBox { + center: Vec3::splat(120.0), + size: Vec3::splat(1.0), + rotation: bevy_math::Quat::from_rotation_z(0.2), + }, + )); + let after = asm.build_incremental(); + + assert_eq!(after.mesh, before.mesh); + assert!(after.report.reused_mesh); + assert!(after.report.used_checkpoint); + assert_eq!(after.report.checkpoint_rebuild_from, Some(1)); + assert!(!after.report.direct_dirty_rebuild); + assert_eq!(after.report.candidate_pairs, 0); + assert_eq!(after.report.rejected_pairs, 1); + } + + #[test] + fn incremental_convex_rebuild_matches_full_rebuild() { + let mut asm = Assembler::new(); + asm.solid_box( + "slab", + Aabb::from_center_size(Vec3::ZERO, Vec3::new(16.0, 16.0, 4.0)), + MaterialId(1), + ); + + let mut tail = BrushId(0); + for index in 0..12 { + let angle = index as f32 * 0.217; + let center = Vec3::new(angle.cos() * 4.0, angle.sin() * 4.0, 0.0); + tail = asm.cut_oriented_box( + format!("rotated_void_{index}"), + center, + Vec3::new(1.0, 6.0, 5.0), + bevy_math::Quat::from_rotation_z(angle), + ); + } + asm.build_incremental(); + + assert!(asm.set_brush_primitive( + tail, + Primitive::OrientedBox { + center: Vec3::new(3.0, 0.0, 0.0), + size: Vec3::new(1.25, 6.0, 5.0), + rotation: bevy_math::Quat::from_rotation_z(0.5), + }, + )); + let incremental = asm.build_incremental(); + let full = asm.rebuild(); + + assert!(incremental.report.used_checkpoint); + assert_eq!(incremental.report.checkpoint_rebuild_from, Some(12)); + assert!(!incremental.report.direct_dirty_rebuild); + assert_eq!(incremental.mesh.positions, full.mesh.positions); + assert_eq!(incremental.mesh.indices, full.mesh.indices); + assert_eq!( + incremental.report.candidate_pairs, + full.report.candidate_pairs + ); + assert_eq!( + incremental.report.rejected_pairs, + full.report.rejected_pairs + ); + } + + #[test] + fn mutating_brush_operation_changes_ordered_output() { + let mut asm = Assembler::new(); + let _source = asm.solid_box( + "source", + Aabb::from_center_size(Vec3::ZERO, Vec3::splat(4.0)), + MaterialId(1), + ); + let other = asm.solid_box( + "other", + Aabb::from_center_size(Vec3::new(0.5, 0.0, 0.0), Vec3::splat(3.0)), + MaterialId(1), + ); + let before = asm.rebuild(); + + assert!(asm.set_brush_op(other, BrushOp::Intersect)); + let after = asm.rebuild(); + + assert_eq!(after.report.operator_brushes, 1); + assert_eq!(after.report.candidate_pairs, 1); + assert!(after.mesh.triangle_count() < before.mesh.triangle_count()); + } + + #[test] + fn rotated_cut_stack_regression_preserves_ordered_output_shape() { + let mut asm = Assembler::new(); + asm.solid_box( + "slab", + Aabb::from_center_size(Vec3::ZERO, Vec3::new(32.0, 32.0, 4.0)), + MaterialId(1), + ); + + for index in 0..64 { + let angle = index as f32 * 0.173; + let radius = 11.0 + (index % 7) as f32 * 0.35; + let center = Vec3::new(angle.cos() * radius, angle.sin() * radius, 0.0); + asm.cut_oriented_box( + format!("rotated_void_{index}"), + center, + Vec3::new(1.0 + (index % 3) as f32 * 0.3, 8.0, 5.0), + bevy_math::Quat::from_rotation_z(angle), + ); + } + + let output = asm.rebuild(); + + assert_eq!(output.report.emitted_convex_fragments, 280); + assert_eq!(output.mesh.triangle_count(), 3404); + assert_eq!(output.report.candidate_pairs, 804); + assert_eq!(output.report.rejected_pairs, 9417); + } +} diff --git a/packages/gamecult-geometry-rs/src/brush.rs b/packages/gamecult-geometry-rs/src/brush.rs new file mode 100644 index 00000000..314c84d0 --- /dev/null +++ b/packages/gamecult-geometry-rs/src/brush.rs @@ -0,0 +1,370 @@ +#![allow(dead_code)] +use bevy_math::{Quat, Vec3}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct BrushId(pub u32); + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)] +pub struct MaterialId(pub u32); + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum BrushOp { + Add, + Subtract, + Intersect, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum PolygonCategory { + Inside, + Outside, + Aligned, + ReverseAligned, +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Aabb { + pub min: Vec3, + pub max: Vec3, +} + +impl Aabb { + pub fn empty() -> Self { + Self { + min: Vec3::splat(f32::INFINITY), + max: Vec3::splat(f32::NEG_INFINITY), + } + } + + pub fn from_center_size(center: Vec3, size: Vec3) -> Self { + let half = size * 0.5; + Self { + min: center - half, + max: center + half, + } + } + + pub fn new(min: Vec3, max: Vec3) -> Self { + Self { min, max } + } + + pub fn from_points(points: &[Vec3]) -> Self { + let mut bounds = Self::empty(); + for point in points { + bounds.include_point(*point); + } + bounds + } + + pub fn include_point(&mut self, point: Vec3) { + self.min = self.min.min(point); + self.max = self.max.max(point); + } + + pub fn union(self, other: Self) -> Self { + if !self.has_finite_extents() { + return other; + } + if !other.has_finite_extents() { + return self; + } + Self { + min: self.min.min(other.min), + max: self.max.max(other.max), + } + } + + pub fn size(self) -> Vec3 { + self.max - self.min + } + + pub fn center(self) -> Vec3 { + (self.min + self.max) * 0.5 + } + + pub fn is_valid(self) -> bool { + self.max.x > self.min.x && self.max.y > self.min.y && self.max.z > self.min.z + } + + pub fn has_finite_extents(self) -> bool { + self.min.is_finite() && self.max.is_finite() + } + + pub fn intersects(self, other: Self) -> bool { + self.min.x < other.max.x + && self.max.x > other.min.x + && self.min.y < other.max.y + && self.max.y > other.min.y + && self.min.z < other.max.z + && self.max.z > other.min.z + } + + pub fn intersects_any(self, others: impl IntoIterator) -> bool { + others.into_iter().any(|other| self.intersects(other)) + } + + pub fn intersection(self, other: Self) -> Option { + if !self.intersects(other) { + return None; + } + + let min = self.min.max(other.min); + let max = self.max.min(other.max); + let hit = Self { min, max }; + hit.is_valid().then_some(hit) + } + + pub fn contains_point(self, point: Vec3) -> bool { + point.x >= self.min.x + && point.x <= self.max.x + && point.y >= self.min.y + && point.y <= self.max.y + && point.z >= self.min.z + && point.z <= self.max.z + } + + pub fn contains_point_strict(self, point: Vec3, epsilon: f32) -> bool { + point.x > self.min.x + epsilon + && point.x < self.max.x - epsilon + && point.y > self.min.y + epsilon + && point.y < self.max.y - epsilon + && point.z > self.min.z + epsilon + && point.z < self.max.z - epsilon + } + + pub fn subtract_box(self, cutter: Self) -> Vec { + let Some(hit) = self.intersection(cutter) else { + return vec![self]; + }; + + let mut pieces = Vec::with_capacity(6); + + push_valid( + &mut pieces, + Self::new(self.min, Vec3::new(hit.min.x, self.max.y, self.max.z)), + ); + push_valid( + &mut pieces, + Self::new(Vec3::new(hit.max.x, self.min.y, self.min.z), self.max), + ); + + let x_min = self.min.x.max(hit.min.x); + let x_max = self.max.x.min(hit.max.x); + + push_valid( + &mut pieces, + Self::new( + Vec3::new(x_min, self.min.y, self.min.z), + Vec3::new(x_max, hit.min.y, self.max.z), + ), + ); + push_valid( + &mut pieces, + Self::new( + Vec3::new(x_min, hit.max.y, self.min.z), + Vec3::new(x_max, self.max.y, self.max.z), + ), + ); + + let y_min = self.min.y.max(hit.min.y); + let y_max = self.max.y.min(hit.max.y); + + push_valid( + &mut pieces, + Self::new( + Vec3::new(x_min, y_min, self.min.z), + Vec3::new(x_max, y_max, hit.min.z), + ), + ); + push_valid( + &mut pieces, + Self::new( + Vec3::new(x_min, y_min, hit.max.z), + Vec3::new(x_max, y_max, self.max.z), + ), + ); + + pieces + } +} + +fn push_valid(pieces: &mut Vec, bounds: Aabb) { + if bounds.is_valid() { + pieces.push(bounds); + } +} + +#[derive(Clone, Debug)] +pub enum Primitive { + Box { + bounds: Aabb, + }, + OrientedBox { + center: Vec3, + size: Vec3, + rotation: Quat, + }, + CylinderZ { + center: Vec3, + radius: f32, + depth: f32, + segments: usize, + }, + DomeCapZ { + center: Vec3, + radius: f32, + height: f32, + rings: usize, + segments: usize, + }, + FloretArm { + anchor: Vec3, + direction: Vec3, + length: f32, + root_width: f32, + tip_width: f32, + thickness: f32, + tip_lift: f32, + }, +} + +#[derive(Clone, Debug)] +pub struct Brush { + pub id: BrushId, + pub name: String, + pub op: BrushOp, + pub primitive: Primitive, + pub material: MaterialId, + pub rotation: Quat, + pub generation: u64, +} + +impl Brush { + pub fn new( + id: BrushId, + name: impl Into, + op: BrushOp, + primitive: Primitive, + material: MaterialId, + ) -> Self { + Self { + id, + name: name.into(), + op, + primitive, + material, + rotation: Quat::IDENTITY, + generation: 0, + } + } + + pub fn set_dirty(&mut self) { + self.generation = self.generation.wrapping_add(1); + } + + pub fn as_box(&self) -> Option { + match self.primitive { + Primitive::Box { bounds } => Some(bounds), + _ => None, + } + } + + pub fn bounds(&self) -> Aabb { + self.primitive.bounds() + } +} + +impl Primitive { + pub fn bounds(&self) -> Aabb { + match *self { + Self::Box { bounds } => bounds, + Self::OrientedBox { + center, + size, + rotation, + } => oriented_box_bounds(center, size, rotation), + Self::CylinderZ { + center, + radius, + depth, + .. + } => Aabb::new( + center - Vec3::new(radius, radius, depth * 0.5), + center + Vec3::new(radius, radius, depth * 0.5), + ), + Self::DomeCapZ { + center, + radius, + height, + .. + } => Aabb::new( + center - Vec3::new(radius, radius, 0.0), + center + Vec3::new(radius, radius, height), + ), + Self::FloretArm { + anchor, + direction, + length, + root_width, + tip_width, + thickness, + tip_lift, + } => floret_bounds( + anchor, direction, length, root_width, tip_width, thickness, tip_lift, + ), + } + } +} + +fn oriented_box_bounds(center: Vec3, size: Vec3, rotation: Quat) -> Aabb { + let half = size * 0.5; + let local_corners = [ + Vec3::new(-half.x, -half.y, -half.z), + Vec3::new(half.x, -half.y, -half.z), + Vec3::new(half.x, half.y, -half.z), + Vec3::new(-half.x, half.y, -half.z), + Vec3::new(-half.x, -half.y, half.z), + Vec3::new(half.x, -half.y, half.z), + Vec3::new(half.x, half.y, half.z), + Vec3::new(-half.x, half.y, half.z), + ]; + let corners = local_corners.map(|point| center + rotation * point); + Aabb::from_points(&corners) +} + +fn floret_bounds( + anchor: Vec3, + direction: Vec3, + length: f32, + root_width: f32, + tip_width: f32, + thickness: f32, + tip_lift: f32, +) -> Aabb { + let forward = direction.normalize_or_zero(); + let forward = if forward.length_squared() == 0.0 { + Vec3::X + } else { + forward + }; + let mut side = forward.cross(Vec3::Z).normalize_or_zero(); + if side.length_squared() == 0.0 { + side = Vec3::Y; + } + + let root_center = anchor; + let tip_center = anchor + forward * length + Vec3::Z * tip_lift; + let z = Vec3::Z * (thickness * 0.5); + let r = side * (root_width * 0.5); + let t = side * (tip_width * 0.5); + Aabb::from_points(&[ + root_center - r - z, + root_center + r - z, + root_center - r + z, + root_center + r + z, + tip_center - t - z, + tip_center + t - z, + tip_center - t + z, + tip_center + t + z, + ]) +} diff --git a/packages/gamecult-geometry-rs/src/convex.rs b/packages/gamecult-geometry-rs/src/convex.rs new file mode 100644 index 00000000..7c8d78b6 --- /dev/null +++ b/packages/gamecult-geometry-rs/src/convex.rs @@ -0,0 +1,905 @@ +#![allow(dead_code)] +use bevy_math::{Quat, Vec2, Vec3}; + +use crate::{Aabb, MaterialId, PolygonCategory, TriangleMesh}; + +const EPSILON: f32 = 1.0e-5; + +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Plane { + pub normal: Vec3, + pub distance: f32, +} + +impl Plane { + pub fn from_point_normal(point: Vec3, normal: Vec3) -> Self { + let normal = normal.normalize_or_zero(); + Self { + normal, + distance: -normal.dot(point), + } + } + + pub fn signed_distance(self, point: Vec3) -> f32 { + self.normal.dot(point) + self.distance + } + + pub fn is_coplanar_with(self, other: Self) -> bool { + self.normal.dot(other.normal).abs() > 1.0 - EPSILON + && (self.distance - other.distance).abs() <= EPSILON + } +} + +#[derive(Clone, Debug, PartialEq)] +pub struct ConvexPolygon { + pub vertices: Vec, + pub normal: Vec3, + pub material: MaterialId, + pub category: PolygonCategory, + pub visible: bool, + pub reversed: bool, + pub bounds: Aabb, +} + +impl ConvexPolygon { + pub fn new(vertices: Vec, normal: Vec3, material: MaterialId) -> Self { + Self { + bounds: Aabb::from_points(&vertices), + vertices, + normal: normal.normalize_or_zero(), + material, + category: PolygonCategory::Aligned, + visible: true, + reversed: false, + } + } + + pub fn centroid(&self) -> Vec3 { + if self.vertices.is_empty() { + return Vec3::ZERO; + } + self.vertices.iter().copied().sum::() / self.vertices.len() as f32 + } + + fn with_vertices(&self, vertices: Vec) -> Self { + Self { + bounds: Aabb::from_points(&vertices), + vertices, + normal: self.normal, + material: self.material, + category: self.category, + visible: self.visible, + reversed: self.reversed, + } + } +} + +#[derive(Clone, Debug, PartialEq)] +pub struct ConvexSolid { + pub polygons: Vec, + pub clip_planes: Vec, + pub material: MaterialId, + pub bounds: Aabb, +} + +#[derive(Clone, Debug, Default)] +pub struct CategorizedPolygons { + pub inside: Vec, + pub outside: Vec, + pub aligned: Vec, + pub reverse_aligned: Vec, +} + +#[derive(Default)] +pub struct PolygonRouteScratch { + pieces: Vec, + inside_pieces: Vec, + cap_points: Vec, +} + +impl ConvexSolid { + pub fn from_aabb(bounds: Aabb, material: MaterialId) -> Self { + Self::box_from_center_size(bounds.center(), bounds.size(), Quat::IDENTITY, material) + } + + pub fn box_from_center_size( + center: Vec3, + size: Vec3, + rotation: Quat, + material: MaterialId, + ) -> Self { + let half = size * 0.5; + let local_corners = [ + Vec3::new(-half.x, -half.y, -half.z), + Vec3::new(half.x, -half.y, -half.z), + Vec3::new(half.x, half.y, -half.z), + Vec3::new(-half.x, half.y, -half.z), + Vec3::new(-half.x, -half.y, half.z), + Vec3::new(half.x, -half.y, half.z), + Vec3::new(half.x, half.y, half.z), + Vec3::new(-half.x, half.y, half.z), + ]; + let corners = local_corners.map(|point| center + rotation * point); + let faces = [ + ([0, 3, 2, 1], Vec3::NEG_Z), + ([4, 5, 6, 7], Vec3::Z), + ([0, 1, 5, 4], Vec3::NEG_Y), + ([3, 7, 6, 2], Vec3::Y), + ([0, 4, 7, 3], Vec3::NEG_X), + ([1, 2, 6, 5], Vec3::X), + ]; + + let mut polygons = Vec::with_capacity(6); + let mut clip_planes = Vec::with_capacity(6); + for (indices, local_normal) in faces { + let normal = rotation * local_normal; + let vertices = indices.map(|index| corners[index]).to_vec(); + clip_planes.push(Plane::from_point_normal(vertices[0], normal)); + polygons.push(ConvexPolygon::new(vertices, normal, material)); + } + + Self { + bounds: Aabb::from_points(&corners), + polygons, + clip_planes, + material, + } + } + + pub fn subtract_convex(&self, cutter: &Self) -> Vec { + self.clone().subtract_convex_owned(cutter) + } + + pub fn subtract_convex_owned(self, cutter: &Self) -> Vec { + let mut fragments = Vec::new(); + let mut remainder = Some(self); + + for plane in &cutter.clip_planes { + let Some(current) = remainder.take() else { + break; + }; + + match current.split_owned(*plane) { + SplitResult::Front(front) => { + fragments.push(front); + break; + } + SplitResult::Back(back) => { + remainder = Some(back); + } + SplitResult::Both { front, back } => { + fragments.push(front); + remainder = Some(back); + } + SplitResult::Coplanar(solid) => { + remainder = Some(solid); + } + } + } + + fragments + } + + pub fn intersect_convex(&self, cutter: &Self) -> Option { + self.clone().intersect_convex_owned(cutter) + } + + pub fn intersect_convex_owned(self, cutter: &Self) -> Option { + if cutter.contains_solid(&self) { + return Some(self); + } + if self.contains_solid(cutter) { + return Some(cutter.clone_with_material(self.material)); + } + + let mut remainder = self; + + for plane in &cutter.clip_planes { + remainder = match remainder.split_owned(*plane) { + SplitResult::Front(_) => return None, + SplitResult::Back(back) | SplitResult::Coplanar(back) => back, + SplitResult::Both { back, .. } => back, + }; + } + + Some(remainder) + } + + pub fn contains_point(&self, point: Vec3) -> bool { + self.clip_planes + .iter() + .all(|plane| plane.signed_distance(point) <= EPSILON) + } + + pub fn contains_solid(&self, other: &Self) -> bool { + other + .polygons + .iter() + .flat_map(|polygon| polygon.vertices.iter()) + .all(|point| self.contains_point(*point)) + } + + pub fn clone_with_material(&self, material: MaterialId) -> Self { + let mut solid = self.clone(); + solid.material = material; + for polygon in &mut solid.polygons { + polygon.material = material; + } + solid + } + + pub fn append_to_mesh(&self, mesh: &mut TriangleMesh) { + for polygon in &self.polygons { + if !polygon.visible || polygon.vertices.len() < 3 { + continue; + } + let base = polygon.vertices[0]; + for i in 1..polygon.vertices.len() - 1 { + let triangle = if polygon.reversed { + [base, polygon.vertices[i + 1], polygon.vertices[i]] + } else { + [base, polygon.vertices[i], polygon.vertices[i + 1]] + }; + let normal = if polygon.reversed { + -polygon.normal + } else { + polygon.normal + }; + mesh.append_triangle( + triangle, + normal, + [Vec2::ZERO, Vec2::X, Vec2::Y], + polygon.material, + ); + } + } + } + + pub fn categorize_whole_polygons_against(&mut self, cutter: &Self) { + for polygon in &mut self.polygons { + if let Some(category) = whole_polygon_category_against(polygon, cutter) { + polygon.category = category; + } + } + } + + pub fn categorize_polygons_against(&self, cutter: &Self) -> CategorizedPolygons { + PolygonRouteScratch::default().categorize_against(&self.polygons, cutter) + } + + pub fn route_polygons_outside_of( + polygons: Vec, + cutter: &Self, + ) -> Vec { + let categorized = PolygonRouteScratch::default().categorize_against(&polygons, cutter); + categorized.outside + } + + pub fn route_polygons_inside_of( + polygons: Vec, + cutter: &Self, + ) -> Vec { + let categorized = PolygonRouteScratch::default().categorize_against(&polygons, cutter); + let mut inside = categorized.inside; + inside.extend(categorized.aligned); + inside.extend(categorized.reverse_aligned); + inside + } + + pub fn subtract_convex_routed_polygons(&self, cutter: &Self) -> Vec { + let mut polygons = Vec::new(); + let source = self.categorize_polygons_against(cutter); + polygons.extend(source.outside); + + let cutter_inside_source = cutter.categorize_polygons_against(self); + for mut polygon in cutter_inside_source.inside { + polygon.reversed = !polygon.reversed; + polygons.push(polygon); + } + for mut polygon in cutter_inside_source.aligned { + polygon.reversed = !polygon.reversed; + polygons.push(polygon); + } + for mut polygon in cutter_inside_source.reverse_aligned { + polygon.reversed = !polygon.reversed; + polygons.push(polygon); + } + + polygons + } + + pub fn append_polygons_to_mesh(polygons: &[ConvexPolygon], mesh: &mut TriangleMesh) { + for polygon in polygons { + if !polygon.visible || polygon.vertices.len() < 3 { + continue; + } + let base = polygon.vertices[0]; + for i in 1..polygon.vertices.len() - 1 { + let triangle = if polygon.reversed { + [base, polygon.vertices[i + 1], polygon.vertices[i]] + } else { + [base, polygon.vertices[i], polygon.vertices[i + 1]] + }; + let normal = if polygon.reversed { + -polygon.normal + } else { + polygon.normal + }; + mesh.append_triangle( + triangle, + normal, + [Vec2::ZERO, Vec2::X, Vec2::Y], + polygon.material, + ); + } + } + } + + fn split_owned(self, plane: Plane) -> SplitResult { + let mut saw_front = false; + let mut saw_back = false; + for polygon in &self.polygons { + for vertex in &polygon.vertices { + let distance = plane.signed_distance(*vertex); + saw_front |= distance > EPSILON; + saw_back |= distance < -EPSILON; + } + } + + match (saw_front, saw_back) { + (true, false) => return SplitResult::Front(self), + (false, true) => return SplitResult::Back(self), + (false, false) => return SplitResult::Coplanar(self), + (true, true) => {} + } + + let mut front_polygons = Vec::with_capacity(self.polygons.len() + 1); + let mut back_polygons = Vec::with_capacity(self.polygons.len() + 1); + let mut cap_points = Vec::with_capacity(self.polygons.len() * 2); + + for polygon in &self.polygons { + let front = clip_polygon(&polygon.vertices, plane, KeepSide::Front, &mut cap_points); + if front.len() >= 3 { + front_polygons.push(polygon.with_vertices(front)); + } + + let back = clip_polygon(&polygon.vertices, plane, KeepSide::Back, &mut cap_points); + if back.len() >= 3 { + back_polygons.push(polygon.with_vertices(back)); + } + } + + let cap_points = unique_points_on_plane(cap_points); + if cap_points.len() >= 3 { + front_polygons.push(make_cap_polygon(&cap_points, -plane.normal, self.material)); + back_polygons.push(make_cap_polygon(&cap_points, plane.normal, self.material)); + } + + SplitResult::Both { + front: Self { + bounds: bounds_from_polygons(&front_polygons), + clip_planes: planes_from_polygons(&front_polygons), + polygons: front_polygons, + material: self.material, + }, + back: Self { + bounds: bounds_from_polygons(&back_polygons), + clip_planes: planes_from_polygons(&back_polygons), + polygons: back_polygons, + material: self.material, + }, + } + } +} + +impl PolygonRouteScratch { + pub fn categorize_against( + &mut self, + polygons: &[ConvexPolygon], + cutter: &ConvexSolid, + ) -> CategorizedPolygons { + let mut categorized = CategorizedPolygons::default(); + + for polygon in polygons { + self.pieces.clear(); + self.pieces.push(CategorizationPiece { + polygon: polygon.clone(), + aligned_category: None, + }); + + for plane in &cutter.clip_planes { + self.inside_pieces.clear(); + for piece in self.pieces.drain(..) { + classify_piece_against_plane( + piece, + *plane, + &mut self.inside_pieces, + &mut categorized, + &mut self.cap_points, + ); + } + std::mem::swap(&mut self.pieces, &mut self.inside_pieces); + } + + for piece in self.pieces.drain(..) { + match piece.aligned_category { + Some(PolygonCategory::Aligned) => categorized.aligned.push(piece.polygon), + Some(PolygonCategory::ReverseAligned) => { + categorized.reverse_aligned.push(piece.polygon); + } + _ => categorized.inside.push(piece.polygon), + } + } + } + + categorized + } + + pub fn route_outside_of( + &mut self, + polygons: Vec, + cutter: &ConvexSolid, + ) -> Vec { + self.categorize_against(&polygons, cutter).outside + } + + pub fn route_inside_of( + &mut self, + polygons: Vec, + cutter: &ConvexSolid, + ) -> Vec { + let categorized = self.categorize_against(&polygons, cutter); + let mut inside = categorized.inside; + inside.extend(categorized.aligned); + inside.extend(categorized.reverse_aligned); + inside + } +} + +enum SplitResult { + Front(ConvexSolid), + Back(ConvexSolid), + Both { + front: ConvexSolid, + back: ConvexSolid, + }, + Coplanar(ConvexSolid), +} + +struct CategorizationPiece { + polygon: ConvexPolygon, + aligned_category: Option, +} + +#[derive(Clone, Copy)] +enum KeepSide { + Front, + Back, +} + +fn classify_piece_against_plane( + mut piece: CategorizationPiece, + plane: Plane, + inside_pieces: &mut Vec, + categorized: &mut CategorizedPolygons, + cap_points: &mut Vec, +) { + let piece_plane = piece + .polygon + .vertices + .first() + .map(|point| Plane::from_point_normal(*point, piece.polygon.normal)); + + if piece_plane.is_some_and(|piece_plane| piece_plane.is_coplanar_with(plane)) { + piece.aligned_category = Some(if piece.polygon.normal.dot(plane.normal) >= 0.0 { + PolygonCategory::Aligned + } else { + PolygonCategory::ReverseAligned + }); + inside_pieces.push(piece); + return; + } + + let mut saw_front = false; + let mut saw_back = false; + for vertex in &piece.polygon.vertices { + let distance = plane.signed_distance(*vertex); + saw_front |= distance > EPSILON; + saw_back |= distance < -EPSILON; + } + + match (saw_front, saw_back) { + (true, false) => { + let mut polygon = piece.polygon; + polygon.category = PolygonCategory::Outside; + categorized.outside.push(polygon); + } + (false, true) | (false, false) => inside_pieces.push(piece), + (true, true) => { + cap_points.clear(); + let outside = clip_polygon(&piece.polygon.vertices, plane, KeepSide::Front, cap_points); + if outside.len() >= 3 { + let mut outside_polygon = piece.polygon.with_vertices(outside); + outside_polygon.category = PolygonCategory::Outside; + categorized.outside.push(outside_polygon); + } + + let inside = clip_polygon(&piece.polygon.vertices, plane, KeepSide::Back, cap_points); + if inside.len() >= 3 { + inside_pieces.push(CategorizationPiece { + polygon: piece.polygon.with_vertices(inside), + aligned_category: piece.aligned_category, + }); + } + } + } +} + +fn clip_polygon( + vertices: &[Vec3], + plane: Plane, + keep: KeepSide, + cap_points: &mut Vec, +) -> Vec { + let mut output = Vec::with_capacity(vertices.len() + 1); + if vertices.is_empty() { + return output; + } + + let mut previous = *vertices.last().expect("checked non-empty"); + let mut previous_distance = plane.signed_distance(previous); + let mut previous_inside = inside(previous_distance, keep); + + for ¤t in vertices { + let current_distance = plane.signed_distance(current); + let current_inside = inside(current_distance, keep); + + if current_inside != previous_inside { + let t = previous_distance / (previous_distance - current_distance); + let intersection = previous + (current - previous) * t; + output.push(intersection); + cap_points.push(intersection); + } + + if current_inside { + output.push(current); + } + + previous = current; + previous_distance = current_distance; + previous_inside = current_inside; + } + + output +} + +fn inside(distance: f32, keep: KeepSide) -> bool { + match keep { + KeepSide::Front => distance >= -EPSILON, + KeepSide::Back => distance <= EPSILON, + } +} + +fn make_cap_polygon(points: &[Vec3], normal: Vec3, material: MaterialId) -> ConvexPolygon { + let center = points.iter().copied().sum::() / points.len() as f32; + let axis = if normal.z.abs() < 0.9 { + Vec3::Z + } else { + Vec3::Y + }; + let tangent = normal.cross(axis).normalize_or_zero(); + let bitangent = normal.cross(tangent).normalize_or_zero(); + let mut vertices = points.to_vec(); + + vertices.sort_by(|a, b| { + let da = *a - center; + let db = *b - center; + let aa = da.dot(bitangent).atan2(da.dot(tangent)); + let ab = db.dot(bitangent).atan2(db.dot(tangent)); + aa.total_cmp(&ab) + }); + + if polygon_normal(&vertices).dot(normal) < 0.0 { + vertices.reverse(); + } + + ConvexPolygon::new(vertices, normal, material) +} + +fn unique_points_on_plane(points: Vec) -> Vec { + let mut unique = Vec::new(); + 'outer: for point in points { + for seen in &unique { + let delta: Vec3 = point - *seen; + if delta.length_squared() < EPSILON * EPSILON { + continue 'outer; + } + } + unique.push(point); + } + unique +} + +fn planes_from_polygons(polygons: &[ConvexPolygon]) -> Vec { + polygons + .iter() + .filter_map(|polygon| { + polygon + .vertices + .first() + .map(|point| Plane::from_point_normal(*point, polygon.normal)) + }) + .collect() +} + +fn bounds_from_polygons(polygons: &[ConvexPolygon]) -> Aabb { + polygons.iter().fold(Aabb::empty(), |bounds, polygon| { + bounds.union(polygon.bounds) + }) +} + +fn whole_polygon_category_against( + polygon: &ConvexPolygon, + cutter: &ConvexSolid, +) -> Option { + let polygon_plane = polygon + .vertices + .first() + .map(|point| Plane::from_point_normal(*point, polygon.normal))?; + + for cutter_plane in &cutter.clip_planes { + if polygon_plane.is_coplanar_with(*cutter_plane) + && polygon + .vertices + .iter() + .all(|vertex| cutter_plane.signed_distance(*vertex).abs() <= EPSILON) + { + return Some(if polygon.normal.dot(cutter_plane.normal) >= 0.0 { + PolygonCategory::Aligned + } else { + PolygonCategory::ReverseAligned + }); + } + } + + let mut fully_inside = true; + for cutter_plane in &cutter.clip_planes { + let mut all_outside_this_plane = true; + for vertex in &polygon.vertices { + let distance = cutter_plane.signed_distance(*vertex); + if distance > EPSILON { + fully_inside = false; + } else { + all_outside_this_plane = false; + } + } + if all_outside_this_plane { + return Some(PolygonCategory::Outside); + } + } + + fully_inside.then_some(PolygonCategory::Inside) +} + +fn polygon_normal(vertices: &[Vec3]) -> Vec3 { + if vertices.len() < 3 { + return Vec3::ZERO; + } + (vertices[1] - vertices[0]) + .cross(vertices[2] - vertices[0]) + .normalize_or_zero() +} + +#[cfg(test)] +mod tests { + use super::*; + + fn assert_box_parity(solid: &ConvexSolid, material: MaterialId) { + assert_eq!(solid.polygons.len(), 6); + assert_eq!(solid.clip_planes.len(), 6); + assert!( + solid + .polygons + .iter() + .all(|polygon| polygon.vertices.len() == 4) + ); + assert!( + solid + .polygons + .iter() + .all(|polygon| polygon.material == material) + ); + } + + #[test] + fn parity_box_brush_from_planes_has_six_quad_polygons() { + let solid = ConvexSolid::box_from_center_size( + Vec3::ZERO, + Vec3::splat(2.0), + Quat::IDENTITY, + MaterialId(9), + ); + + assert_box_parity(&solid, MaterialId(9)); + } + + #[test] + fn subtract_center_box_emits_six_convex_fragments() { + let source = ConvexSolid::box_from_center_size( + Vec3::ZERO, + Vec3::splat(4.0), + Quat::IDENTITY, + MaterialId(1), + ); + let cutter = ConvexSolid::box_from_center_size( + Vec3::ZERO, + Vec3::splat(2.0), + Quat::IDENTITY, + MaterialId(0), + ); + + let fragments = source.subtract_convex(&cutter); + assert_eq!(fragments.len(), 6); + assert!( + fragments + .iter() + .all(|fragment| !fragment.polygons.is_empty()) + ); + } + + #[test] + fn intersect_overlapping_boxes_emits_single_common_solid() { + let source = ConvexSolid::box_from_center_size( + Vec3::ZERO, + Vec3::splat(4.0), + Quat::IDENTITY, + MaterialId(1), + ); + let cutter = ConvexSolid::box_from_center_size( + Vec3::X, + Vec3::splat(4.0), + Quat::IDENTITY, + MaterialId(0), + ); + + let common = source.intersect_convex(&cutter).expect("intersection"); + + assert!(common.bounds.is_valid()); + assert_eq!(common.polygons.len(), 6); + assert!(common.bounds.contains_point(Vec3::ZERO)); + assert!(common.bounds.contains_point(Vec3::new(2.0, 0.0, 0.0))); + assert!(!common.bounds.contains_point(Vec3::new(-2.0, 0.0, 0.0))); + } + + #[test] + fn categorize_crossing_coplanar_face_splits_visible_categories() { + let source = ConvexSolid::box_from_center_size( + Vec3::ZERO, + Vec3::splat(4.0), + Quat::IDENTITY, + MaterialId(1), + ); + let cutter = ConvexSolid::box_from_center_size( + Vec3::new(0.0, 0.0, 1.0), + Vec3::new(2.0, 2.0, 2.0), + Quat::IDENTITY, + MaterialId(0), + ); + + let categorized = source.categorize_polygons_against(&cutter); + + assert_eq!(categorized.aligned.len(), 1); + assert!(categorized.outside.len() > 6); + assert!(categorized.inside.is_empty()); + assert!(categorized.reverse_aligned.is_empty()); + assert!( + categorized + .aligned + .iter() + .all(|polygon| polygon.category == PolygonCategory::Aligned) + ); + assert!( + categorized + .outside + .iter() + .all(|polygon| polygon.category == PolygonCategory::Outside) + ); + } + + #[test] + fn subtract_rotated_box_creates_non_axis_aligned_faces() { + let source = ConvexSolid::box_from_center_size( + Vec3::ZERO, + Vec3::splat(4.0), + Quat::IDENTITY, + MaterialId(1), + ); + let cutter = ConvexSolid::box_from_center_size( + Vec3::ZERO, + Vec3::new(2.0, 5.0, 2.0), + Quat::from_rotation_z(std::f32::consts::FRAC_PI_4), + MaterialId(0), + ); + + let fragments = source.subtract_convex(&cutter); + assert!(fragments.len() > 2); + assert!(fragments.iter().any(|fragment| { + fragment + .polygons + .iter() + .any(|polygon| polygon.normal.x.abs() > 0.01 && polygon.normal.y.abs() > 0.01) + })); + } + + #[test] + fn routed_subtraction_emits_source_shell_and_reversed_cutter_shell() { + let source = ConvexSolid::box_from_center_size( + Vec3::ZERO, + Vec3::splat(4.0), + Quat::IDENTITY, + MaterialId(1), + ); + let cutter = ConvexSolid::box_from_center_size( + Vec3::ZERO, + Vec3::splat(2.0), + Quat::IDENTITY, + MaterialId(0), + ); + + let routed = source.subtract_convex_routed_polygons(&cutter); + + assert_eq!(routed.len(), 24); + assert_eq!( + routed + .iter() + .filter(|polygon| polygon.material == MaterialId(1)) + .count(), + 18 + ); + assert_eq!( + routed + .iter() + .filter(|polygon| polygon.material == MaterialId(0)) + .count(), + 6 + ); + assert_eq!( + routed + .iter() + .filter(|polygon| polygon.material == MaterialId(0) && polygon.reversed) + .count(), + 6 + ); + } + + #[test] + fn routed_subtraction_clips_crossing_cutter_surfaces_to_source() { + let source = ConvexSolid::box_from_center_size( + Vec3::ZERO, + Vec3::splat(4.0), + Quat::IDENTITY, + MaterialId(1), + ); + let cutter = ConvexSolid::box_from_center_size( + Vec3::new(1.5, 0.0, 0.0), + Vec3::splat(2.0), + Quat::IDENTITY, + MaterialId(0), + ); + + let routed = source.subtract_convex_routed_polygons(&cutter); + + assert!(!routed.is_empty()); + assert!( + routed + .iter() + .flat_map(|polygon| polygon.vertices.iter()) + .all(|vertex| source.bounds.contains_point(*vertex)) + ); + assert!( + routed + .iter() + .any(|polygon| polygon.material == MaterialId(0) && polygon.reversed) + ); + } +} diff --git a/packages/gamecult-geometry-rs/src/domain.rs b/packages/gamecult-geometry-rs/src/domain.rs new file mode 100644 index 00000000..a946305e --- /dev/null +++ b/packages/gamecult-geometry-rs/src/domain.rs @@ -0,0 +1,1560 @@ +#![allow(dead_code)] +use bevy_math::{Quat, Vec3}; + +use serde::{Deserialize, Serialize}; + +use crate::{ + Aabb, BrushOp, BuildReport, CsgBranchOp, CsgNodeId, CsgOperationType, CsgTreeArena, MaterialId, + Primitive, TriangleMesh, +}; + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct DomainKey(pub String); + +impl DomainKey { + pub fn new(value: impl Into) -> Self { + Self(value.into()) + } + + pub fn child(&self, name: impl AsRef) -> Self { + Self(format!("{}/{}", self.0, name.as_ref())) + } +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct DomainFrame { + pub translation: Vec3, + pub rotation: Quat, +} + +impl DomainFrame { + pub const IDENTITY: Self = Self { + translation: Vec3::ZERO, + rotation: Quat::IDENTITY, + }; + + pub fn translated(translation: Vec3) -> Self { + Self { + translation, + rotation: Quat::IDENTITY, + } + } + + pub fn rotated_z(translation: Vec3, radians: f32) -> Self { + Self { + translation, + rotation: Quat::from_rotation_z(radians), + } + } + + pub fn transform_point(self, point: Vec3) -> Vec3 { + self.translation + self.rotation * point + } + + pub fn transform_bounds(self, bounds: Aabb) -> Aabb { + let min = bounds.min; + let max = bounds.max; + let corners = [ + Vec3::new(min.x, min.y, min.z), + Vec3::new(max.x, min.y, min.z), + Vec3::new(max.x, max.y, min.z), + Vec3::new(min.x, max.y, min.z), + Vec3::new(min.x, min.y, max.z), + Vec3::new(max.x, min.y, max.z), + Vec3::new(max.x, max.y, max.z), + Vec3::new(min.x, max.y, max.z), + ]; + let world = corners.map(|corner| self.transform_point(corner)); + Aabb::from_points(&world) + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum DomainKind { + Root, + Column, + AltitudeBand, + RoadSpine, + BranchRoad, + Roundabout, + SupportMass, + ClearanceVolume, + Chunk, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum FieldLayer { + Form, + Appearance, + Transport, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum FieldEncoding { + Mesh, + Sdf3d, + Occupancy, + Material, + Confidence, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum FeatureClaimKind { + SolidBrush, + VoidBrush, + RoadSurfaceSlab, + ClearanceVolume, + SupportShell, + ColliderProxy, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum FeatureLoweringPolicy { + RenderOnly, + ColliderOnly, + RenderAndCollider, + BooleanOperator, +} + +impl FeatureLoweringPolicy { + pub fn default_for_kind(kind: FeatureClaimKind) -> Self { + match kind { + FeatureClaimKind::VoidBrush | FeatureClaimKind::ClearanceVolume => { + Self::BooleanOperator + } + FeatureClaimKind::ColliderProxy => Self::ColliderOnly, + FeatureClaimKind::SolidBrush + | FeatureClaimKind::RoadSurfaceSlab + | FeatureClaimKind::SupportShell => Self::RenderAndCollider, + } + } + + pub fn emits_to(self, target: ClaimLoweringTarget) -> bool { + match self { + Self::RenderOnly => target == ClaimLoweringTarget::Render, + Self::ColliderOnly => target == ClaimLoweringTarget::Collider, + Self::RenderAndCollider | Self::BooleanOperator => true, + } + } +} + +impl FeatureClaimKind { + pub fn field_layer(self) -> FieldLayer { + match self { + Self::SolidBrush + | Self::VoidBrush + | Self::RoadSurfaceSlab + | Self::ClearanceVolume + | Self::SupportShell + | Self::ColliderProxy => FieldLayer::Form, + } + } + + pub fn field_encoding(self) -> FieldEncoding { + match self { + Self::VoidBrush | Self::ClearanceVolume => FieldEncoding::Sdf3d, + Self::ColliderProxy => FieldEncoding::Occupancy, + _ => FieldEncoding::Mesh, + } + } + + pub fn brush_op(self) -> BrushOp { + match self { + Self::VoidBrush | Self::ClearanceVolume => BrushOp::Subtract, + _ => BrushOp::Add, + } + } + + pub fn emits_render(self) -> bool { + !matches!(self, Self::ColliderProxy | Self::ClearanceVolume) + } + + pub fn emits_collider(self) -> bool { + matches!( + self, + Self::SolidBrush | Self::RoadSurfaceSlab | Self::SupportShell | Self::ColliderProxy + ) + } +} + +#[derive(Clone, Debug, PartialEq)] +pub struct FeatureClaim { + pub key: String, + pub domain_key: DomainKey, + pub frame: DomainFrame, + pub support: Aabb, + pub kind: FeatureClaimKind, + pub material: MaterialId, + pub lowering: FeatureLoweringPolicy, +} + +impl FeatureClaim { + pub fn world_bounds(&self) -> Aabb { + self.frame.transform_bounds(self.support) + } + + pub fn primitive(&self) -> Primitive { + Primitive::OrientedBox { + center: self.frame.transform_point(self.support.center()), + size: self.support.size(), + rotation: self.frame.rotation, + } + } +} + +#[derive(Clone, Debug, PartialEq)] +pub struct DomainSummary { + pub bounds: Aabb, + pub estimated_triangle_cost: usize, + pub estimated_brush_cost: usize, + pub projected_error: f32, + pub contribution_weight: f32, + pub has_children: bool, + pub fallback_claims: Vec, +} + +#[derive(Clone, Debug, PartialEq)] +pub struct DomainNode { + pub key: DomainKey, + pub parent: Option, + pub kind: DomainKind, + pub frame: DomainFrame, + pub bounds: Aabb, + pub seed: u64, + pub summary: DomainSummary, + pub claims: Vec, + pub children: Vec, +} + +#[derive(Clone, Debug, PartialEq)] +pub struct FeatureClaimSpec { + pub name: String, + pub frame: DomainFrame, + pub support: Aabb, + pub kind: FeatureClaimKind, + pub material: MaterialId, + pub lowering: FeatureLoweringPolicy, +} + +impl FeatureClaimSpec { + pub fn new( + name: impl Into, + frame: DomainFrame, + support: Aabb, + kind: FeatureClaimKind, + material: MaterialId, + ) -> Self { + Self { + name: name.into(), + frame, + support, + kind, + material, + lowering: FeatureLoweringPolicy::default_for_kind(kind), + } + } + + pub fn with_lowering_policy(mut self, lowering: FeatureLoweringPolicy) -> Self { + self.lowering = lowering; + self + } + + pub fn compile(&self, domain_key: &DomainKey) -> FeatureClaim { + FeatureClaim { + key: format!("{}/claim/{}", domain_key.0, self.name), + domain_key: domain_key.clone(), + frame: self.frame, + support: self.support, + kind: self.kind, + material: self.material, + lowering: self.lowering, + } + } +} + +#[derive(Clone, Debug, PartialEq)] +pub struct DomainNodeSpec { + pub name: String, + pub kind: DomainKind, + pub frame: DomainFrame, + pub seed: u64, + pub claims: Vec, + pub children: Vec, +} + +impl DomainNodeSpec { + pub fn new(name: impl Into, kind: DomainKind, frame: DomainFrame, seed: u64) -> Self { + Self { + name: name.into(), + kind, + frame, + seed, + claims: Vec::new(), + children: Vec::new(), + } + } + + pub fn with_claim(mut self, claim: FeatureClaimSpec) -> Self { + self.claims.push(claim); + self + } + + pub fn with_child(mut self, child: DomainNodeSpec) -> Self { + self.children.push(child); + self + } + + pub fn compile_root(&self) -> DomainNode { + self.compile(DomainKey::new(self.name.clone()), None) + } + + fn compile(&self, key: DomainKey, parent: Option) -> DomainNode { + let claims = self + .claims + .iter() + .map(|claim| claim.compile(&key)) + .collect::>(); + let children = self + .children + .iter() + .map(|child| child.compile(key.child(&child.name), Some(key.clone()))) + .collect::>(); + DomainNode::new( + key, parent, self.kind, self.frame, self.seed, claims, children, + ) + } +} + +impl DomainNode { + pub fn new( + key: DomainKey, + parent: Option, + kind: DomainKind, + frame: DomainFrame, + seed: u64, + claims: Vec, + children: Vec, + ) -> Self { + let claim_bounds = claims + .iter() + .map(FeatureClaim::world_bounds) + .fold(Aabb::empty(), Aabb::union); + let child_bounds = children + .iter() + .map(|child| child.summary.bounds) + .fold(Aabb::empty(), Aabb::union); + let bounds = claim_bounds.union(child_bounds); + let has_children = !children.is_empty(); + let estimated_brush_cost = claims.len() + + children + .iter() + .map(|child| child.summary.estimated_brush_cost) + .sum::(); + let estimated_triangle_cost = claims.len().max(1) * 12 + + children + .iter() + .map(|child| child.summary.estimated_triangle_cost) + .sum::(); + let contribution_weight = domain_priority(kind) * bounds.size().length().max(1.0); + let fallback_claims = if claims.is_empty() { + fallback_box_claim(&key, kind, frame, bounds) + } else { + claims.clone() + }; + + Self { + key, + parent, + kind, + frame, + bounds, + seed, + summary: DomainSummary { + bounds, + estimated_triangle_cost, + estimated_brush_cost, + projected_error: bounds.size().length().max(1.0), + contribution_weight, + has_children, + fallback_claims, + }, + claims, + children, + } + } + + pub fn find(&self, key: &DomainKey) -> Option<&Self> { + if &self.key == key { + return Some(self); + } + self.children.iter().find_map(|child| child.find(key)) + } +} + +#[derive(Clone, Debug, PartialEq)] +pub struct DomainQuery { + pub camera_position: Vec3, + pub frustum: Aabb, + pub viewport_height_px: f32, + pub vertical_fov_radians: f32, + pub target_error: f32, + pub triangle_budget: usize, + pub collider_budget: usize, + pub semantic_filter: Vec, + pub requested_chunk_keys: Vec, + pub dirty_domain_keys: Vec, +} + +impl DomainQuery { + pub fn accepts_kind(&self, kind: DomainKind) -> bool { + self.semantic_filter.is_empty() || self.semantic_filter.contains(&kind) + } +} + +#[derive(Clone, Debug, PartialEq)] +pub struct ContributionRow { + pub domain_key: DomainKey, + pub kind: DomainKind, + pub contribution: f32, + pub projected_screen_error: f32, + pub semantic_priority: f32, + pub estimated_triangle_cost: usize, + pub child_cost: usize, + pub remaining_triangle_budget: usize, + pub requested: bool, + pub dirty: bool, + pub selected: bool, + pub used_fallback: bool, + pub deferred_by_budget: bool, +} + +#[derive(Clone, Debug, PartialEq)] +pub struct SelectedCut { + pub id: String, + pub selected_nodes: Vec, + pub emitted_claims: Vec, + pub deferred_children: Vec, + pub fallback_nodes: Vec, + pub diagnostics: Vec, +} + +#[derive(Clone, Debug)] +pub struct DomainChunkBuild { + pub cut: SelectedCut, + pub chunks: Vec, + pub manifest: SelectedCutManifest, +} + +impl DomainChunkBuild {} + +#[derive(Clone, Debug)] +pub struct TriangleChunk { + pub key: DomainKey, + pub selected_cut_id: String, + pub bounds: Aabb, + pub mesh: TriangleMesh, + pub collider_mesh: Option, + pub source_domain_keys: Vec, + pub source_claim_keys: Vec, + pub report: BuildReport, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct TriangleChunkManifest { + pub key: String, + pub selected_cut_id: String, + pub bounds_min: [f32; 3], + pub bounds_max: [f32; 3], + pub render_vertices: usize, + pub render_triangles: usize, + pub collider_triangles: usize, + pub source_domain_keys: Vec, + pub source_claim_keys: Vec, + pub input_brushes: usize, + pub candidate_pairs: usize, + pub rejected_pairs: usize, + pub transition_hint: ChunkTransitionHint, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct SelectedCutManifest { + pub id: String, + pub selected_nodes: Vec, + pub deferred_child_requests: Vec, + pub parent_fallback_nodes: Vec, + pub diagnostics: Vec, + pub chunks: Vec, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct ContributionManifest { + pub domain_key: String, + pub kind: DomainKind, + pub contribution: f32, + pub projected_screen_error: f32, + pub semantic_priority: f32, + pub estimated_triangle_cost: usize, + pub child_cost: usize, + pub remaining_triangle_budget: usize, + pub requested: bool, + pub dirty: bool, + pub selected: bool, + pub used_fallback: bool, + pub deferred_by_budget: bool, +} + +impl SelectedCut { + pub fn manifest(&self, chunks: &[TriangleChunk]) -> SelectedCutManifest { + SelectedCutManifest { + id: self.id.clone(), + selected_nodes: self + .selected_nodes + .iter() + .map(|key| key.0.clone()) + .collect(), + deferred_child_requests: self + .deferred_children + .iter() + .map(|key| key.0.clone()) + .collect(), + parent_fallback_nodes: self + .fallback_nodes + .iter() + .map(|key| key.0.clone()) + .collect(), + diagnostics: self + .diagnostics + .iter() + .map(ContributionManifest::from_row) + .collect(), + chunks: chunks.iter().map(TriangleChunk::manifest).collect(), + } + } +} + +impl ContributionManifest { + pub fn from_row(row: &ContributionRow) -> Self { + Self { + domain_key: row.domain_key.0.clone(), + kind: row.kind, + contribution: row.contribution, + projected_screen_error: row.projected_screen_error, + semantic_priority: row.semantic_priority, + estimated_triangle_cost: row.estimated_triangle_cost, + child_cost: row.child_cost, + remaining_triangle_budget: row.remaining_triangle_budget, + requested: row.requested, + dirty: row.dirty, + selected: row.selected, + used_fallback: row.used_fallback, + deferred_by_budget: row.deferred_by_budget, + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct ChunkTransitionHint { + pub stable_clip_seed: u64, + pub supports_parent_child_coexistence: bool, +} + +impl TriangleChunk { + pub fn manifest(&self) -> TriangleChunkManifest { + TriangleChunkManifest { + key: self.key.0.clone(), + selected_cut_id: self.selected_cut_id.clone(), + bounds_min: vec3_to_array(self.bounds.min), + bounds_max: vec3_to_array(self.bounds.max), + render_vertices: self.mesh.vertex_count(), + render_triangles: self.mesh.triangle_count(), + collider_triangles: self + .collider_mesh + .as_ref() + .map_or(0, TriangleMesh::triangle_count), + source_domain_keys: self + .source_domain_keys + .iter() + .map(|key| key.0.clone()) + .collect(), + source_claim_keys: self.source_claim_keys.clone(), + input_brushes: self.report.input_brushes, + candidate_pairs: self.report.candidate_pairs, + rejected_pairs: self.report.rejected_pairs, + transition_hint: ChunkTransitionHint { + stable_clip_seed: stable_str_hash(&self.key.0), + supports_parent_child_coexistence: true, + }, + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum ClaimLoweringTarget { + Render, + Collider, +} + +#[derive(Clone, Debug)] +pub struct CsgClaimLowering { + pub arena: CsgTreeArena, + pub root: Option, + pub bounds: Aabb, + pub source_domain_keys: Vec, + pub source_claim_keys: Vec, +} + +pub fn select_domain_cut(root: &DomainNode, query: &DomainQuery) -> SelectedCut { + let mut state = CutState { + query, + selected: Vec::new(), + claims: Vec::new(), + deferred: Vec::new(), + fallback: Vec::new(), + diagnostics: Vec::new(), + remaining_triangles: query.triangle_budget, + remaining_colliders: query.collider_budget, + }; + state.visit(root, true); + SelectedCut { + id: stable_cut_id(&state.selected), + selected_nodes: state.selected, + emitted_claims: state.claims, + deferred_children: state.deferred, + fallback_nodes: state.fallback, + diagnostics: state.diagnostics, + } +} + +pub fn build_domain_chunks(root: &DomainNode, query: &DomainQuery) -> DomainChunkBuild { + let cut = select_domain_cut(root, query); + let chunks = lower_selected_cut_chunks(&cut); + let manifest = cut.manifest(&chunks); + DomainChunkBuild { + cut, + chunks, + manifest, + } +} + +pub fn lower_selected_cut(cut: &SelectedCut) -> TriangleChunk { + lower_claims_to_chunk( + DomainKey::new(format!("chunk/{}", cut.id)), + &cut.id, + &cut.emitted_claims, + ) +} + +pub fn lower_selected_cut_chunks(cut: &SelectedCut) -> Vec { + let mut chunks = Vec::new(); + for domain_key in &cut.selected_nodes { + let claims = cut + .emitted_claims + .iter() + .filter(|claim| &claim.domain_key == domain_key) + .cloned() + .collect::>(); + if claims.is_empty() { + continue; + } + chunks.push(lower_claims_to_chunk( + DomainKey::new(format!("chunk/{}/{}", cut.id, domain_key.0)), + &cut.id, + &claims, + )); + } + chunks +} + +pub fn lower_feature_claims_to_csg_tree( + claims: &[FeatureClaim], + target: ClaimLoweringTarget, +) -> CsgClaimLowering { + let mut arena = CsgTreeArena::new(); + let mut additive_nodes = Vec::new(); + let mut subtractive_nodes = Vec::new(); + let mut source_domain_keys = Vec::::new(); + let mut source_claim_keys = Vec::::new(); + let mut bounds = Aabb::empty(); + + for claim in claims.iter().filter(|claim| claim_in_target(claim, target)) { + source_claim_keys.push(claim.key.clone()); + if !source_domain_keys.contains(&claim.domain_key) { + source_domain_keys.push(claim.domain_key.clone()); + } + bounds = bounds.union(claim.world_bounds()); + let brush = arena.generate_brush( + claim.key.clone(), + CsgOperationType::Additive, + claim.primitive(), + claim.material, + ); + match claim.kind.brush_op() { + BrushOp::Add => additive_nodes.push(brush.node), + BrushOp::Subtract => subtractive_nodes.push(brush.node), + BrushOp::Intersect => additive_nodes.push(brush.node), + } + } + + let root = build_claim_tree(&mut arena, additive_nodes, subtractive_nodes); + CsgClaimLowering { + arena, + root, + bounds, + source_domain_keys, + source_claim_keys, + } +} + +fn lower_claims_to_chunk( + key: DomainKey, + selected_cut_id: &str, + claims: &[FeatureClaim], +) -> TriangleChunk { + let render = lower_feature_claims_to_csg_tree(claims, ClaimLoweringTarget::Render); + let collider = lower_feature_claims_to_csg_tree(claims, ClaimLoweringTarget::Collider); + let (source_domain_keys, source_claim_keys) = claim_metadata(claims); + + let output = render + .root + .map(|root| { + render + .arena + .compile_tree_to_assembler(render.arena.generate_tree(root)) + .build() + }) + .unwrap_or_else(|| crate::Assembler::new().build()); + let collider_output = collider.root.map(|root| { + collider + .arena + .compile_tree_to_assembler(collider.arena.generate_tree(root)) + .build() + }); + + TriangleChunk { + key, + selected_cut_id: selected_cut_id.to_owned(), + bounds: render.bounds.union(collider.bounds), + mesh: output.mesh, + collider_mesh: collider_output.map(|output| output.mesh), + source_domain_keys, + source_claim_keys, + report: output.report, + } +} + +fn claim_metadata(claims: &[FeatureClaim]) -> (Vec, Vec) { + let mut source_domain_keys = Vec::::new(); + let mut source_claim_keys = Vec::::new(); + for claim in claims { + source_claim_keys.push(claim.key.clone()); + if !source_domain_keys.contains(&claim.domain_key) { + source_domain_keys.push(claim.domain_key.clone()); + } + } + (source_domain_keys, source_claim_keys) +} + +fn claim_in_target(claim: &FeatureClaim, target: ClaimLoweringTarget) -> bool { + claim.lowering.emits_to(target) +} + +fn build_claim_tree( + arena: &mut CsgTreeArena, + additive_nodes: Vec, + subtractive_nodes: Vec, +) -> Option { + let additive_root = match additive_nodes.len() { + 0 => None, + 1 => additive_nodes.first().copied(), + _ => Some( + arena + .generate_branch( + "domain-additive-claims", + CsgBranchOp::Addition, + additive_nodes, + ) + .node, + ), + }?; + + if subtractive_nodes.is_empty() { + return Some(additive_root); + } + + let subtractive_root = match subtractive_nodes.len() { + 0 => unreachable!(), + 1 => subtractive_nodes[0], + _ => { + arena + .generate_branch( + "domain-subtractive-claims", + CsgBranchOp::Addition, + subtractive_nodes, + ) + .node + } + }; + + Some( + arena + .generate_branch( + "domain-claims", + CsgBranchOp::Subtraction, + [additive_root, subtractive_root], + ) + .node, + ) +} + +pub fn ragnarok_column_fixture() -> DomainNode { + ragnarok_column_spec().compile_root() +} + +pub fn ragnarok_column_spec() -> DomainNodeSpec { + let mut column = DomainNodeSpec::new( + "stellarator-column-00", + DomainKind::Column, + DomainFrame::IDENTITY, + 0xC011_0000, + ) + .with_claim(claim_spec( + "column-support-shell", + DomainFrame::IDENTITY, + Aabb::from_center_size(Vec3::new(0.0, 0.0, 45.0), Vec3::new(18.0, 18.0, 96.0)), + FeatureClaimKind::SupportShell, + MaterialId(10), + )) + .with_claim(claim_spec( + "column-core-clearance", + DomainFrame::IDENTITY, + Aabb::from_center_size(Vec3::new(0.0, 0.0, 45.0), Vec3::new(7.0, 7.0, 100.0)), + FeatureClaimKind::ClearanceVolume, + MaterialId(0), + )); + for index in 0..3 { + column = column.with_child(ragnarok_band(index)); + } + + DomainNodeSpec::new( + "ragnarok-column", + DomainKind::Root, + DomainFrame::IDENTITY, + 0x5EED, + ) + .with_child(column) +} + +fn ragnarok_band(index: usize) -> DomainNodeSpec { + let z = 15.0 + index as f32 * 30.0; + let frame = DomainFrame::translated(Vec3::new(0.0, 0.0, z)); + let mut band = DomainNodeSpec::new( + format!("altitude-band-{index}"), + DomainKind::AltitudeBand, + frame, + 0xBADD_0000 + index as u64, + ) + .with_claim(claim_spec( + "coarse-ring-road", + frame, + Aabb::from_center_size(Vec3::ZERO, Vec3::new(34.0, 5.0, 1.0)), + FeatureClaimKind::RoadSurfaceSlab, + MaterialId(20 + index as u32), + )); + for lane in 0..2 { + band = band.with_child(ragnarok_branch(index, lane)); + } + band.with_child(ragnarok_roundabout(index)) +} + +fn ragnarok_branch(band: usize, lane: usize) -> DomainNodeSpec { + let angle = band as f32 * 0.41 + lane as f32 * std::f32::consts::PI; + let radius = 16.0 + lane as f32 * 5.0; + let frame = DomainFrame::rotated_z( + Vec3::new(angle.cos() * radius, angle.sin() * radius, 0.0), + angle, + ); + let mut branch = DomainNodeSpec::new( + format!("branch-road-{lane}"), + DomainKind::BranchRoad, + frame, + 0xA11E_0000 + (band * 10 + lane) as u64, + ) + .with_claim(claim_spec( + "road-slab", + frame, + Aabb::from_center_size(Vec3::new(7.0, 0.0, 0.0), Vec3::new(18.0, 4.0, 0.8)), + FeatureClaimKind::RoadSurfaceSlab, + MaterialId(40 + band as u32), + )) + .with_claim(claim_spec( + "hover-clearance", + frame, + Aabb::from_center_size(Vec3::new(7.0, 0.0, 2.2), Vec3::new(17.0, 3.0, 2.0)), + FeatureClaimKind::ClearanceVolume, + MaterialId(0), + )) + .with_claim(claim_spec( + "coarse-support-rib", + frame, + Aabb::from_center_size(Vec3::new(7.0, 0.0, -1.0), Vec3::new(18.5, 1.0, 1.5)), + FeatureClaimKind::SupportShell, + MaterialId(12), + )); + for segment in 0..3 { + branch = branch.with_child(ragnarok_road_chunk(band, lane, segment, frame)); + } + branch +} + +fn ragnarok_roundabout(band: usize) -> DomainNodeSpec { + let frame = DomainFrame::translated(Vec3::ZERO); + let mut roundabout = DomainNodeSpec::new( + "roundabout", + DomainKind::Roundabout, + frame, + 0xF00D_0000 + band as u64, + ) + .with_claim(claim_spec( + "roundabout-east-west", + frame, + Aabb::from_center_size(Vec3::ZERO, Vec3::new(26.0, 4.5, 0.9)), + FeatureClaimKind::RoadSurfaceSlab, + MaterialId(60 + band as u32), + )) + .with_claim(claim_spec( + "roundabout-north-south", + DomainFrame::rotated_z(Vec3::ZERO, std::f32::consts::FRAC_PI_2), + Aabb::from_center_size(Vec3::ZERO, Vec3::new(26.0, 4.5, 0.9)), + FeatureClaimKind::RoadSurfaceSlab, + MaterialId(60 + band as u32), + )); + for quadrant in 0..4 { + roundabout = roundabout.with_child(ragnarok_roundabout_chunk(band, quadrant)); + } + roundabout +} + +fn ragnarok_road_chunk( + band: usize, + lane: usize, + segment: usize, + frame: DomainFrame, +) -> DomainNodeSpec { + let x = 1.5 + segment as f32 * 5.5; + DomainNodeSpec::new( + format!("chunk-{segment}"), + DomainKind::Chunk, + frame, + 0xC40B_0000 + (band * 100 + lane * 10 + segment) as u64, + ) + .with_claim(claim_spec( + "road-slab", + frame, + Aabb::from_center_size(Vec3::new(x, 0.0, 0.0), Vec3::new(6.5, 4.0, 0.75)), + FeatureClaimKind::RoadSurfaceSlab, + MaterialId(80 + band as u32), + )) + .with_claim(claim_spec( + "hover-clearance", + frame, + Aabb::from_center_size(Vec3::new(x, 0.0, 2.1), Vec3::new(6.0, 3.0, 1.9)), + FeatureClaimKind::ClearanceVolume, + MaterialId(0), + )) + .with_claim(claim_spec( + "support-rib", + frame, + Aabb::from_center_size(Vec3::new(x, 0.0, -1.05), Vec3::new(6.8, 0.9, 1.4)), + FeatureClaimKind::SupportShell, + MaterialId(90 + lane as u32), + )) + .with_claim(claim_spec( + "collider-proxy", + frame, + Aabb::from_center_size(Vec3::new(x, 0.0, 0.35), Vec3::new(6.8, 4.2, 0.35)), + FeatureClaimKind::ColliderProxy, + MaterialId(0), + )) +} + +fn ragnarok_roundabout_chunk(band: usize, quadrant: usize) -> DomainNodeSpec { + let angle = quadrant as f32 * std::f32::consts::FRAC_PI_2; + let frame = DomainFrame::rotated_z(Vec3::ZERO, angle); + DomainNodeSpec::new( + format!("chunk-{quadrant}"), + DomainKind::Chunk, + frame, + 0xC10C_0000 + (band * 10 + quadrant) as u64, + ) + .with_claim(claim_spec( + "arc-road-slab", + frame, + Aabb::from_center_size(Vec3::new(5.0, 5.0, 0.0), Vec3::new(12.0, 4.0, 0.8)), + FeatureClaimKind::RoadSurfaceSlab, + MaterialId(100 + band as u32), + )) + .with_claim(claim_spec( + "arc-clearance", + frame, + Aabb::from_center_size(Vec3::new(5.0, 5.0, 2.1), Vec3::new(11.0, 3.0, 1.8)), + FeatureClaimKind::ClearanceVolume, + MaterialId(0), + )) + .with_claim(claim_spec( + "arc-support", + frame, + Aabb::from_center_size(Vec3::new(5.0, 5.0, -1.0), Vec3::new(12.5, 0.8, 1.2)), + FeatureClaimKind::SupportShell, + MaterialId(90), + )) +} + +fn claim_spec( + name: &str, + frame: DomainFrame, + support: Aabb, + kind: FeatureClaimKind, + material: MaterialId, +) -> FeatureClaimSpec { + FeatureClaimSpec::new(name, frame, support, kind, material) +} + +fn vec3_to_array(value: Vec3) -> [f32; 3] { + [value.x, value.y, value.z] +} + +fn array_to_vec3(value: [f32; 3]) -> Vec3 { + Vec3::new(value[0], value[1], value[2]) +} + +fn quat_to_array(value: Quat) -> [f32; 4] { + [value.x, value.y, value.z, value.w] +} + +fn array_to_quat(value: [f32; 4]) -> Quat { + Quat::from_xyzw(value[0], value[1], value[2], value[3]) +} + +fn fallback_box_claim( + key: &DomainKey, + kind: DomainKind, + frame: DomainFrame, + bounds: Aabb, +) -> Vec { + if !bounds.is_valid() { + return Vec::new(); + } + let kind = match kind { + DomainKind::ClearanceVolume => FeatureClaimKind::ClearanceVolume, + DomainKind::RoadSpine | DomainKind::BranchRoad | DomainKind::Roundabout => { + FeatureClaimKind::RoadSurfaceSlab + } + _ => FeatureClaimKind::SupportShell, + }; + vec![FeatureClaim { + key: format!("{}/claim/fallback-summary", key.0), + domain_key: key.clone(), + frame, + support: Aabb::from_center_size(Vec3::ZERO, bounds.size()), + kind, + material: MaterialId(1), + lowering: FeatureLoweringPolicy::default_for_kind(kind), + }] +} + +fn domain_priority(kind: DomainKind) -> f32 { + match kind { + DomainKind::Root => 0.5, + DomainKind::Column => 1.0, + DomainKind::AltitudeBand => 1.4, + DomainKind::RoadSpine | DomainKind::BranchRoad | DomainKind::Roundabout => 2.0, + DomainKind::SupportMass => 1.1, + DomainKind::ClearanceVolume => 1.8, + DomainKind::Chunk => 1.0, + } +} + +fn contribution(node: &DomainNode, query: &DomainQuery) -> f32 { + let projected_error = projected_screen_error(node, query); + let stale_multiplier = if query.dirty_domain_keys.contains(&node.key) { + 1.5 + } else { + 1.0 + }; + let cost_pressure = selection_triangle_cost(node).max(1) as f32; + (projected_error * domain_priority(node.kind) * stale_multiplier) / cost_pressure.sqrt() +} + +fn projected_screen_error(node: &DomainNode, query: &DomainQuery) -> f32 { + let center = node.summary.bounds.center(); + let distance = center.distance(query.camera_position).max(1.0); + let radius = node.summary.bounds.size().length() * 0.5; + let focal_pixels = query.viewport_height_px.max(1.0) + / (2.0 * (query.vertical_fov_radians.max(0.01) * 0.5).tan()); + (radius / distance) * focal_pixels +} + +fn stable_cut_id(keys: &[DomainKey]) -> String { + let mut hash = FNV_OFFSET_BASIS; + for key in keys { + hash = stable_hash_bytes(hash, key.0.as_bytes()); + } + format!("cut-{hash:016x}") +} + +const FNV_OFFSET_BASIS: u64 = 0xcbf2_9ce4_8422_2325; +const FNV_PRIME: u64 = 0x1000_0000_01b3; + +fn stable_str_hash(value: &str) -> u64 { + stable_hash_bytes(FNV_OFFSET_BASIS, value.as_bytes()) +} + +fn stable_hash_bytes(mut hash: u64, bytes: &[u8]) -> u64 { + for byte in bytes { + hash ^= u64::from(*byte); + hash = hash.wrapping_mul(FNV_PRIME); + } + hash +} + +struct CutState<'a> { + query: &'a DomainQuery, + selected: Vec, + claims: Vec, + deferred: Vec, + fallback: Vec, + diagnostics: Vec, + remaining_triangles: usize, + remaining_colliders: usize, +} + +impl CutState<'_> { + fn visit(&mut self, node: &DomainNode, force_visit: bool) { + let requested_self = self.query.requested_chunk_keys.contains(&node.key); + let requested_descendant = has_requested_descendant(node, &self.query.requested_chunk_keys); + let dirty_descendant = has_requested_descendant(node, &self.query.dirty_domain_keys); + if !force_visit + && !requested_self + && !requested_descendant + && !dirty_descendant + && !node.summary.bounds.intersects(self.query.frustum) + { + return; + } + let score = contribution(node, self.query); + let projected_error = projected_screen_error(node, self.query); + let semantic_priority = domain_priority(node.kind); + let dirty = self.query.dirty_domain_keys.contains(&node.key); + let child_cost = node + .children + .iter() + .map(selection_triangle_cost) + .sum::(); + let child_collider_cost = node + .children + .iter() + .map(selection_collider_cost) + .sum::(); + let budget_allows_children = child_cost <= self.remaining_triangles + && child_collider_cost <= self.remaining_colliders; + let descend_for_detail = score >= self.query.target_error && budget_allows_children; + let descend_for_request = requested_descendant && !requested_self; + let descend_for_dirty = dirty_descendant && budget_allows_children; + let should_descend = node.summary.has_children + && !requested_self + && (descend_for_request || descend_for_dirty || descend_for_detail); + self.diagnostics.push(ContributionRow { + domain_key: node.key.clone(), + kind: node.kind, + contribution: score, + projected_screen_error: projected_error, + semantic_priority, + estimated_triangle_cost: node.summary.estimated_triangle_cost, + child_cost, + remaining_triangle_budget: self.remaining_triangles, + requested: requested_self, + dirty, + selected: !should_descend && self.query.accepts_kind(node.kind), + used_fallback: !should_descend && node.summary.has_children, + deferred_by_budget: node.summary.has_children + && !requested_self + && score >= self.query.target_error + && !budget_allows_children, + }); + + if should_descend { + if budget_allows_children { + self.remaining_triangles = self.remaining_triangles.saturating_sub(child_cost); + self.remaining_colliders = + self.remaining_colliders.saturating_sub(child_collider_cost); + } + for child in &node.children { + let child_requested = self.query.requested_chunk_keys.contains(&child.key) + || has_requested_descendant(child, &self.query.requested_chunk_keys); + let child_dirty = self.query.dirty_domain_keys.contains(&child.key) + || has_requested_descendant(child, &self.query.dirty_domain_keys); + self.visit(child, child_requested || child_dirty); + } + return; + } + + for child in &node.children { + self.deferred.push(child.key.clone()); + } + if self.query.accepts_kind(node.kind) { + self.selected.push(node.key.clone()); + let claims = if node.summary.has_children { + self.fallback.push(node.key.clone()); + &node.summary.fallback_claims + } else { + &node.claims + }; + self.claims.extend(claims.iter().cloned()); + } + } +} + +fn selection_triangle_cost(node: &DomainNode) -> usize { + let claim_count = if node.summary.has_children { + node.summary.fallback_claims.len() + } else { + node.claims.len() + }; + claim_count.max(1) * 12 +} + +fn selection_collider_cost(node: &DomainNode) -> usize { + let claims = if node.summary.has_children { + &node.summary.fallback_claims + } else { + &node.claims + }; + claims + .iter() + .filter(|claim| claim.lowering.emits_to(ClaimLoweringTarget::Collider)) + .count() + .max(1) + * 12 +} + +fn has_requested_descendant(node: &DomainNode, requested: &[DomainKey]) -> bool { + node.children + .iter() + .any(|child| requested.contains(&child.key) || has_requested_descendant(child, requested)) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn query(target_error: f32, triangle_budget: usize) -> DomainQuery { + DomainQuery { + camera_position: Vec3::new(36.0, -42.0, 30.0), + frustum: Aabb::from_center_size(Vec3::new(0.0, 0.0, 45.0), Vec3::splat(150.0)), + viewport_height_px: 1080.0, + vertical_fov_radians: std::f32::consts::FRAC_PI_3, + target_error, + triangle_budget, + collider_budget: triangle_budget, + semantic_filter: Vec::new(), + requested_chunk_keys: Vec::new(), + dirty_domain_keys: Vec::new(), + } + } + + #[test] + fn ragnarok_domain_keys_are_stable() { + let a = ragnarok_column_fixture(); + let b = ragnarok_column_fixture(); + assert_eq!(a.key, b.key); + assert_eq!(a.children[0].children[1].key, b.children[0].children[1].key); + } + + #[test] + fn domain_tree_spec_compiles_stable_parent_claim_identity() { + let spec = DomainNodeSpec::new("root", DomainKind::Root, DomainFrame::IDENTITY, 1) + .with_child( + DomainNodeSpec::new("road", DomainKind::BranchRoad, DomainFrame::IDENTITY, 2) + .with_claim(FeatureClaimSpec::new( + "slab", + DomainFrame::IDENTITY, + Aabb::from_center_size(Vec3::ZERO, Vec3::ONE), + FeatureClaimKind::RoadSurfaceSlab, + MaterialId(1), + )), + ); + let domain = spec.compile_root(); + let road = &domain.children[0]; + assert_eq!(road.key, DomainKey::new("root/road")); + assert_eq!(road.parent, Some(domain.key.clone())); + assert_eq!(road.claims[0].key, "root/road/claim/slab"); + assert_eq!(road.claims[0].domain_key, road.key); + assert_eq!( + road.claims[0].lowering, + FeatureLoweringPolicy::RenderAndCollider + ); + } + + #[test] + fn domain_summary_contains_child_bounds() { + let fixture = ragnarok_column_fixture(); + let column = &fixture.children[0]; + for band in &column.children { + assert!( + column + .summary + .bounds + .contains_point(band.summary.bounds.center()) + ); + } + } + + #[test] + fn selected_cut_chooses_parent_under_tight_budget_and_children_when_relaxed() { + let fixture = ragnarok_column_fixture(); + let tight = select_domain_cut(&fixture, &query(10_000.0, 100)); + let relaxed = select_domain_cut(&fixture, &query(0.01, 10_000)); + assert!(tight.selected_nodes.len() < relaxed.selected_nodes.len()); + assert!( + tight + .fallback_nodes + .iter() + .any(|key| key.0.contains("ragnarok-column")) + ); + assert!( + relaxed + .selected_nodes + .iter() + .any(|key| key.0.contains("branch-road")) + ); + } + + #[test] + fn selected_cut_honors_collider_budget() { + let fixture = ragnarok_column_fixture(); + let mut collider_tight = query(0.01, 10_000); + collider_tight.collider_budget = 1; + let cut = select_domain_cut(&fixture, &collider_tight); + assert_eq!(cut.selected_nodes, vec![fixture.key.clone()]); + assert!(cut.diagnostics[0].deferred_by_budget); + } + + #[test] + fn selected_cut_reports_projected_error_and_dirty_pressure() { + let fixture = ragnarok_column_fixture(); + let dirty_key = fixture.key.clone(); + let mut request = query(10_000.0, 100); + request.dirty_domain_keys.push(dirty_key.clone()); + let cut = select_domain_cut(&fixture, &request); + let row = cut + .diagnostics + .iter() + .find(|row| row.domain_key == dirty_key) + .unwrap(); + assert!(row.projected_screen_error > 0.0); + assert_eq!(row.semantic_priority, domain_priority(row.kind)); + assert!(row.dirty); + } + + #[test] + fn dirty_descendant_pulls_selection_down_when_budget_allows() { + let fixture = ragnarok_column_fixture(); + let dirty_key = fixture.children[0].children[0].children[0].children[0] + .key + .clone(); + let mut request = query(10_000.0, 10_000); + request.dirty_domain_keys.push(dirty_key.clone()); + let cut = select_domain_cut(&fixture, &request); + assert!(cut.selected_nodes.contains(&dirty_key)); + assert!( + cut.diagnostics + .iter() + .any(|row| row.domain_key == dirty_key && row.dirty) + ); + } + + #[test] + fn missing_children_degrade_to_parent_fallback_claims() { + let fixture = ragnarok_column_fixture(); + let cut = select_domain_cut(&fixture, &query(10_000.0, 100)); + assert!(!cut.fallback_nodes.is_empty()); + assert!(!cut.emitted_claims.is_empty()); + } + + #[test] + fn feature_claims_lower_deterministically_to_triangle_chunks() { + let fixture = ragnarok_column_fixture(); + let cut = select_domain_cut(&fixture, &query(0.01, 10_000)); + let a = lower_selected_cut(&cut); + let b = lower_selected_cut(&cut); + assert_eq!(a.source_claim_keys, b.source_claim_keys); + assert_eq!(a.mesh.positions, b.mesh.positions); + assert_eq!(a.mesh.indices, b.mesh.indices); + } + + #[test] + fn triangle_chunks_preserve_source_domain_and_claim_ids() { + let fixture = ragnarok_column_fixture(); + let cut = select_domain_cut(&fixture, &query(0.01, 10_000)); + let chunk = lower_selected_cut(&cut); + assert!(!chunk.source_domain_keys.is_empty()); + assert!(!chunk.source_claim_keys.is_empty()); + assert!(chunk.collider_mesh.is_some()); + } + + #[test] + fn feature_claims_lower_through_csg_tree_branches() { + let fixture = ragnarok_column_fixture(); + let cut = select_domain_cut(&fixture, &query(0.01, 10_000)); + let lowering = + lower_feature_claims_to_csg_tree(&cut.emitted_claims, ClaimLoweringTarget::Render); + assert!(lowering.root.is_some()); + assert!(lowering.arena.brush_count() > 0); + assert!(lowering.arena.branch_count() > 0); + } + + #[test] + fn lowering_policy_controls_render_and_collider_streams() { + let fixture = ragnarok_column_fixture(); + let cut = select_domain_cut(&fixture, &query(0.01, 10_000)); + let render = + lower_feature_claims_to_csg_tree(&cut.emitted_claims, ClaimLoweringTarget::Render); + let collider = + lower_feature_claims_to_csg_tree(&cut.emitted_claims, ClaimLoweringTarget::Collider); + assert!( + !render + .source_claim_keys + .iter() + .any(|key| key.ends_with("/claim/collider-proxy")) + ); + assert!( + collider + .source_claim_keys + .iter() + .any(|key| key.ends_with("/claim/collider-proxy")) + ); + assert!( + render + .source_claim_keys + .iter() + .any(|key| key.ends_with("/claim/hover-clearance")) + ); + } + + #[test] + fn selected_cut_chunks_emit_per_selected_domain() { + let fixture = ragnarok_column_fixture(); + let cut = select_domain_cut(&fixture, &query(0.01, 10_000)); + let chunks = lower_selected_cut_chunks(&cut); + assert_eq!(chunks.len(), cut.selected_nodes.len()); + for chunk in chunks { + assert_eq!(chunk.source_domain_keys.len(), 1); + assert!(cut.selected_nodes.contains(&chunk.source_domain_keys[0])); + assert!(chunk.mesh.triangle_count() > 0); + } + } + + #[test] + fn triangle_chunk_manifest_preserves_streaming_metadata() { + let fixture = ragnarok_column_fixture(); + let cut = select_domain_cut(&fixture, &query(0.01, 10_000)); + let chunks = lower_selected_cut_chunks(&cut); + let manifest = chunks[0].manifest(); + assert_eq!(manifest.selected_cut_id, cut.id); + assert!(manifest.render_triangles > 0); + assert!(!manifest.source_domain_keys.is_empty()); + assert!(manifest.transition_hint.supports_parent_child_coexistence); + assert_ne!(manifest.transition_hint.stable_clip_seed, 0); + } + + #[test] + fn selected_cut_manifest_carries_worker_artifact_context() { + let fixture = ragnarok_column_fixture(); + let cut = select_domain_cut(&fixture, &query(0.01, 10_000)); + let chunks = lower_selected_cut_chunks(&cut); + let manifest = cut.manifest(&chunks); + assert_eq!(manifest.id, cut.id); + assert_eq!(manifest.chunks.len(), chunks.len()); + assert_eq!(manifest.selected_nodes.len(), cut.selected_nodes.len()); + assert!(!manifest.diagnostics.is_empty()); + } + + #[test] + fn build_domain_chunks_runs_full_runtime_pipeline() { + let fixture = ragnarok_column_fixture(); + let build = build_domain_chunks(&fixture, &query(0.01, 10_000)); + assert_eq!(build.manifest.id, build.cut.id); + assert_eq!(build.manifest.chunks.len(), build.chunks.len()); + assert!(!build.chunks.is_empty()); + assert!( + build + .chunks + .iter() + .all(|chunk| !chunk.mesh.indices.is_empty()) + ); + } + + #[test] + fn requested_chunk_bypasses_frustum_and_budget() { + let fixture = ragnarok_column_fixture(); + let requested = fixture.children[0].children[2].children[0].children[1] + .key + .clone(); + let mut request = query(0.01, 1); + request.frustum = + Aabb::from_center_size(Vec3::new(10_000.0, 10_000.0, 10_000.0), Vec3::splat(1.0)); + request.requested_chunk_keys.push(requested.clone()); + let cut = select_domain_cut(&fixture, &request); + assert_eq!(cut.selected_nodes, vec![requested.clone()]); + assert!( + cut.diagnostics + .iter() + .any(|row| row.domain_key == requested && row.requested) + ); + } + + #[test] + fn ragnarok_fixture_emits_lod_chunks_and_preserves_parent_for_transition() { + let fixture = ragnarok_column_fixture(); + let tight_cut = select_domain_cut(&fixture, &query(10_000.0, 100)); + let medium_cut = select_domain_cut(&fixture, &query(0.01, 560)); + let relaxed_cut = select_domain_cut(&fixture, &query(0.01, 10_000)); + let tight = lower_selected_cut(&tight_cut); + let medium = lower_selected_cut(&medium_cut); + let relaxed = lower_selected_cut(&relaxed_cut); + assert!(tight.mesh.triangle_count() > 0); + assert!(medium.mesh.triangle_count() > tight.mesh.triangle_count()); + assert!(relaxed.mesh.triangle_count() > medium.mesh.triangle_count()); + assert!(medium_cut.selected_nodes.len() > tight_cut.selected_nodes.len()); + assert!(relaxed_cut.selected_nodes.len() > medium_cut.selected_nodes.len()); + assert!(!tight_cut.fallback_nodes.is_empty()); + assert!(!relaxed_cut.selected_nodes.is_empty()); + assert!( + relaxed_cut + .selected_nodes + .iter() + .any(|key| key.0.contains("/chunk-")) + ); + } + + #[test] + fn clearance_voids_leave_no_triangle_centers_inside_strict_bounds() { + let fixture = ragnarok_column_fixture(); + let cut = select_domain_cut(&fixture, &query(0.01, 10_000)); + let chunk = lower_selected_cut(&cut); + for clearance in cut + .emitted_claims + .iter() + .filter(|claim| claim.kind == FeatureClaimKind::ClearanceVolume) + { + let bounds = clearance.world_bounds(); + for tri in chunk.mesh.indices.chunks_exact(3) { + let center = (chunk.mesh.positions[tri[0] as usize] + + chunk.mesh.positions[tri[1] as usize] + + chunk.mesh.positions[tri[2] as usize]) + / 3.0; + assert!(!bounds.contains_point_strict(center, 1.0e-4)); + } + } + } +} diff --git a/packages/gamecult-geometry-rs/src/dsl.rs b/packages/gamecult-geometry-rs/src/dsl.rs new file mode 100644 index 00000000..77e31e68 --- /dev/null +++ b/packages/gamecult-geometry-rs/src/dsl.rs @@ -0,0 +1,164 @@ +#![allow(dead_code)] +use bevy_math::{Quat, Vec3}; + +use crate::{ + Aabb, Assembler, BrushId, BrushOp, BuildOutput, DomeCapZSpec, FloretArmSpec, MaterialId, + Primitive, +}; + +#[derive(Clone, Debug, Default)] +pub struct LevelDsl { + assembler: Assembler, +} + +impl LevelDsl { + pub fn new() -> Self { + Self::default() + } + + pub fn solid_box( + &mut self, + name: impl Into, + center: Vec3, + size: Vec3, + material: MaterialId, + ) -> BrushId { + self.assembler + .solid_box(name, Aabb::from_center_size(center, size), material) + } + + pub fn cut_box(&mut self, name: impl Into, center: Vec3, size: Vec3) -> BrushId { + self.assembler + .cut_box(name, Aabb::from_center_size(center, size)) + } + + pub fn solid_oriented_box( + &mut self, + name: impl Into, + center: Vec3, + size: Vec3, + rotation: Quat, + material: MaterialId, + ) -> BrushId { + self.assembler + .solid_oriented_box(name, center, size, rotation, material) + } + + pub fn cut_oriented_box( + &mut self, + name: impl Into, + center: Vec3, + size: Vec3, + rotation: Quat, + ) -> BrushId { + self.assembler + .cut_oriented_box(name, center, size, rotation) + } + + pub fn cylinder_z( + &mut self, + name: impl Into, + center: Vec3, + radius: f32, + depth: f32, + segments: usize, + material: MaterialId, + ) -> BrushId { + self.assembler.add_brush( + name, + BrushOp::Add, + Primitive::CylinderZ { + center, + radius, + depth, + segments, + }, + material, + ) + } + + pub fn dome_cap_z(&mut self, name: impl Into, spec: DomeCapZSpec) -> BrushId { + self.assembler.add_brush( + name, + BrushOp::Add, + Primitive::DomeCapZ { + center: spec.center, + radius: spec.radius, + height: spec.height, + rings: spec.rings, + segments: spec.segments, + }, + spec.material, + ) + } + + pub fn floret_arm(&mut self, name: impl Into, spec: FloretArmSpec) -> BrushId { + self.assembler.add_brush( + name, + BrushOp::Add, + Primitive::FloretArm { + anchor: spec.anchor, + direction: spec.direction, + length: spec.length, + root_width: spec.root_width, + tip_width: spec.tip_width, + thickness: spec.thickness, + tip_lift: spec.tip_lift, + }, + spec.material, + ) + } + + pub fn assemble(&self) -> BuildOutput { + self.assembler.build() + } + + pub fn into_assembler(self) -> Assembler { + self.assembler + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn dsl_builds_room_and_habitat_primitives() { + let mut dsl = LevelDsl::new(); + dsl.solid_box( + "wall", + Vec3::new(0.0, 0.0, 1.5), + Vec3::new(5.0, 0.25, 3.0), + MaterialId(1), + ); + dsl.cut_box("door", Vec3::new(0.0, 0.0, 1.0), Vec3::new(1.0, 0.5, 2.0)); + dsl.dome_cap_z( + "city dome", + DomeCapZSpec { + center: Vec3::new(0.0, 0.0, 0.0), + radius: 3.0, + height: 1.5, + rings: 4, + segments: 16, + material: MaterialId(2), + }, + ); + dsl.floret_arm( + "solar petal", + FloretArmSpec { + anchor: Vec3::new(3.0, 0.0, 0.0), + direction: Vec3::X, + length: 12.0, + root_width: 1.2, + tip_width: 3.0, + thickness: 0.08, + tip_lift: 0.6, + material: MaterialId(3), + }, + ); + + let output = dsl.assemble(); + assert!(output.mesh.triangle_count() > 12); + assert!(output.report.warnings.is_empty()); + } +} diff --git a/packages/gamecult-geometry-rs/src/frontier.rs b/packages/gamecult-geometry-rs/src/frontier.rs new file mode 100644 index 00000000..e48af14f --- /dev/null +++ b/packages/gamecult-geometry-rs/src/frontier.rs @@ -0,0 +1,321 @@ +#![allow(dead_code)] +use crate::{Brush, BrushOp}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct DemandPair { + pub source_index: usize, + pub operator_index: usize, +} + +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct DemandFrontier { + pub pairs: Vec, + pub rejected_pairs: usize, + pub operator_brushes: usize, +} + +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct DirtyDemandFrontier { + pub first_dirty_index: Option, + pub pairs: Vec, + pub rejected_pairs: usize, + pub operator_brushes: usize, + pub skipped_prefix_pairs: usize, +} + +impl DemandFrontier { + pub fn from_ordered_brushes(brushes: &[Brush]) -> Self { + let mut frontier = Self::default(); + let mut active_sources = Vec::::new(); + + for (operator_index, brush) in brushes.iter().enumerate() { + match brush.op { + BrushOp::Add => active_sources.push(operator_index), + BrushOp::Subtract => { + frontier.operator_brushes += 1; + frontier.collect_pairs(brushes, &active_sources, operator_index); + } + BrushOp::Intersect => { + frontier.operator_brushes += 1; + let retained = frontier.collect_pairs(brushes, &active_sources, operator_index); + active_sources = retained; + } + } + } + + frontier + } + + pub fn candidate_pairs(&self) -> usize { + self.pairs.len() + } + + fn collect_pairs( + &mut self, + brushes: &[Brush], + active_sources: &[usize], + operator_index: usize, + ) -> Vec { + let operator_bounds = brushes[operator_index].bounds(); + let mut retained = Vec::new(); + + for &source_index in active_sources { + if brushes[source_index].bounds().intersects(operator_bounds) { + self.pairs.push(DemandPair { + source_index, + operator_index, + }); + retained.push(source_index); + } else { + self.rejected_pairs += 1; + } + } + + retained + } +} + +impl DirtyDemandFrontier { + pub fn from_dirty_indices( + brushes: &[Brush], + dirty_indices: impl IntoIterator, + ) -> Self { + let first_dirty_index = dirty_indices + .into_iter() + .filter(|index| *index < brushes.len()) + .min(); + let Some(first_dirty_index) = first_dirty_index else { + return Self::default(); + }; + + let mut frontier = Self { + first_dirty_index: Some(first_dirty_index), + ..Self::default() + }; + let mut active_sources = Vec::::new(); + + for (operator_index, brush) in brushes.iter().enumerate() { + match brush.op { + BrushOp::Add => active_sources.push(operator_index), + BrushOp::Subtract => { + frontier.operator_brushes += usize::from(operator_index >= first_dirty_index); + frontier.collect_pairs( + brushes, + &active_sources, + operator_index, + first_dirty_index, + ); + } + BrushOp::Intersect => { + frontier.operator_brushes += usize::from(operator_index >= first_dirty_index); + let retained = frontier.collect_pairs( + brushes, + &active_sources, + operator_index, + first_dirty_index, + ); + active_sources = retained; + } + } + } + + frontier + } + + pub fn candidate_pairs(&self) -> usize { + self.pairs.len() + } + + fn collect_pairs( + &mut self, + brushes: &[Brush], + active_sources: &[usize], + operator_index: usize, + first_dirty_index: usize, + ) -> Vec { + let operator_bounds = brushes[operator_index].bounds(); + let mut retained = Vec::new(); + + for &source_index in active_sources { + if brushes[source_index].bounds().intersects(operator_bounds) { + if operator_index >= first_dirty_index { + self.pairs.push(DemandPair { + source_index, + operator_index, + }); + } else { + self.skipped_prefix_pairs += 1; + } + retained.push(source_index); + } else if operator_index >= first_dirty_index { + self.rejected_pairs += 1; + } else { + self.skipped_prefix_pairs += 1; + } + } + + retained + } +} + +#[cfg(test)] +mod tests { + use bevy_math::{Quat, Vec3}; + + use super::*; + use crate::{Aabb, Brush, MaterialId, Primitive}; + + fn brush(name: &str, op: BrushOp, bounds: Aabb) -> Brush { + Brush::new( + crate::BrushId(0), + name, + op, + Primitive::Box { bounds }, + MaterialId(1), + ) + } + + #[test] + fn frontier_keeps_only_touching_ordered_pairs() { + let brushes = vec![ + brush( + "source", + BrushOp::Add, + Aabb::from_center_size(Vec3::ZERO, Vec3::splat(4.0)), + ), + brush( + "far cutter", + BrushOp::Subtract, + Aabb::from_center_size(Vec3::splat(20.0), Vec3::ONE), + ), + brush( + "near cutter", + BrushOp::Subtract, + Aabb::from_center_size(Vec3::ZERO, Vec3::ONE), + ), + ]; + + let frontier = DemandFrontier::from_ordered_brushes(&brushes); + + assert_eq!(frontier.operator_brushes, 2); + assert_eq!(frontier.rejected_pairs, 1); + assert_eq!( + frontier.pairs, + vec![DemandPair { + source_index: 0, + operator_index: 2, + }] + ); + } + + #[test] + fn intersection_frontier_reduces_active_sources() { + let brushes = vec![ + brush( + "a", + BrushOp::Add, + Aabb::from_center_size(Vec3::ZERO, Vec3::splat(2.0)), + ), + brush( + "b", + BrushOp::Add, + Aabb::from_center_size(Vec3::new(20.0, 0.0, 0.0), Vec3::splat(2.0)), + ), + Brush::new( + crate::BrushId(2), + "common", + BrushOp::Intersect, + Primitive::OrientedBox { + center: Vec3::ZERO, + size: Vec3::splat(3.0), + rotation: Quat::IDENTITY, + }, + MaterialId(1), + ), + brush( + "cut", + BrushOp::Subtract, + Aabb::from_center_size(Vec3::ZERO, Vec3::ONE), + ), + ]; + + let frontier = DemandFrontier::from_ordered_brushes(&brushes); + + assert_eq!(frontier.operator_brushes, 2); + assert_eq!(frontier.rejected_pairs, 1); + assert_eq!( + frontier.pairs, + vec![ + DemandPair { + source_index: 0, + operator_index: 2, + }, + DemandPair { + source_index: 0, + operator_index: 3, + }, + ] + ); + } + + #[test] + fn dirty_frontier_preserves_prefix_before_first_dirty_brush() { + let brushes = vec![ + brush( + "source", + BrushOp::Add, + Aabb::from_center_size(Vec3::ZERO, Vec3::splat(8.0)), + ), + brush( + "early", + BrushOp::Subtract, + Aabb::from_center_size(Vec3::new(-2.0, 0.0, 0.0), Vec3::splat(2.0)), + ), + brush( + "dirty", + BrushOp::Subtract, + Aabb::from_center_size(Vec3::ZERO, Vec3::splat(2.0)), + ), + brush( + "later", + BrushOp::Subtract, + Aabb::from_center_size(Vec3::new(2.0, 0.0, 0.0), Vec3::splat(2.0)), + ), + ]; + + let frontier = DirtyDemandFrontier::from_dirty_indices(&brushes, [2]); + + assert_eq!(frontier.first_dirty_index, Some(2)); + assert_eq!(frontier.operator_brushes, 2); + assert_eq!(frontier.skipped_prefix_pairs, 1); + assert_eq!(frontier.candidate_pairs(), 2); + assert_eq!( + frontier.pairs, + vec![ + DemandPair { + source_index: 0, + operator_index: 2, + }, + DemandPair { + source_index: 0, + operator_index: 3, + }, + ] + ); + } + + #[test] + fn dirty_frontier_ignores_out_of_range_dirty_indices() { + let brushes = vec![brush( + "source", + BrushOp::Add, + Aabb::from_center_size(Vec3::ZERO, Vec3::splat(2.0)), + )]; + + let frontier = DirtyDemandFrontier::from_dirty_indices(&brushes, [99]); + + assert_eq!(frontier.first_dirty_index, None); + assert_eq!(frontier.candidate_pairs(), 0); + assert_eq!(frontier.operator_brushes, 0); + } +} diff --git a/packages/gamecult-geometry-rs/src/lib.rs b/packages/gamecult-geometry-rs/src/lib.rs index 7882c457..04727ed1 100644 --- a/packages/gamecult-geometry-rs/src/lib.rs +++ b/packages/gamecult-geometry-rs/src/lib.rs @@ -4,6 +4,50 @@ //! commit `8f070f4`, then rewritten around typed vector values. This crate has //! no runtime or build dependency on VibeGeometry or `vg-csg`. +mod assembler; +mod brush; +mod convex; +mod domain; +mod dsl; +mod frontier; +mod mesh; +mod primitives; +#[cfg(test)] +mod realtime_csg_parity; +mod tree; + +#[allow(unused_imports)] +pub(crate) use assembler::{Assembler, BuildOutput, BuildReport, BuildWarning}; +#[allow(unused_imports)] +pub(crate) use brush::{Aabb, Brush, BrushId, BrushOp, MaterialId, PolygonCategory, Primitive}; +#[allow(unused_imports)] +pub(crate) use convex::{ + CategorizedPolygons, ConvexPolygon, ConvexSolid, Plane, PolygonRouteScratch, +}; +#[allow(unused_imports)] +pub(crate) use domain::{ + ClaimLoweringTarget, ContributionManifest, ContributionRow, CsgClaimLowering, DomainChunkBuild, + DomainFrame, DomainKey, DomainKind, DomainNode, DomainNodeSpec, DomainQuery, DomainSummary, + FeatureClaim, FeatureClaimKind, FeatureClaimSpec, FeatureLoweringPolicy, FieldEncoding, + FieldLayer, SelectedCut, SelectedCutManifest, TriangleChunk, TriangleChunkManifest, + build_domain_chunks, lower_feature_claims_to_csg_tree, lower_selected_cut, + lower_selected_cut_chunks, ragnarok_column_fixture, ragnarok_column_spec, select_domain_cut, +}; +#[allow(unused_imports)] +pub(crate) use dsl::LevelDsl; +#[allow(unused_imports)] +pub(crate) use frontier::{DemandFrontier, DemandPair, DirtyDemandFrontier}; +pub(crate) use mesh::TriangleMesh; +#[allow(unused_imports)] +pub(crate) use primitives::{ + DomeCapZSpec, FloretArmSpec, append_cylinder_z, append_dome_cap_z, append_floret_arm, +}; +#[allow(unused_imports)] +pub(crate) use tree::{ + CsgBranchOp, CsgNode, CsgNodeId, CsgOperationType, CsgTree, CsgTreeArena, CsgTreeBranch, + CsgTreeBrush, +}; + use std::fmt::Write; use serde::{Deserialize, Serialize, de::DeserializeOwned}; @@ -40,6 +84,54 @@ pub trait GeometryDocument: Serialize + DeserializeOwned + Sized { } } +/// Geometry-owned CSG facade. The implementation uses an internal math kernel, +/// but no `bevy_math` type crosses this public boundary. +#[derive(Default)] +pub struct GeometryBrushAssembler(Assembler); + +impl GeometryBrushAssembler { + pub fn new() -> Self { + Self(Assembler::new()) + } + pub fn add_box( + &mut self, + name: impl Into, + center: Float3, + size: Float3, + material: u32, + ) { + self.0 + .solid_box(name, internal_aabb(center, size), MaterialId(material)); + } + pub fn subtract_box(&mut self, name: impl Into, center: Float3, size: Float3) { + self.0.cut_box(name, internal_aabb(center, size)); + } + pub fn build(&self) -> GeometryTriangleMesh { + internal_mesh(&self.0.build().mesh) + } +} + +fn internal_aabb(center: Float3, size: Float3) -> Aabb { + use bevy_math::Vec3; + Aabb::from_center_size( + Vec3::new(center.0, center.1, center.2), + Vec3::new(size.0, size.1, size.2), + ) +} + +fn internal_mesh(mesh: &TriangleMesh) -> GeometryTriangleMesh { + GeometryTriangleMesh( + mesh.positions + .iter() + .map(|v| Float3(v.x, v.y, v.z)) + .collect(), + mesh.normals.iter().map(|v| Float3(v.x, v.y, v.z)).collect(), + mesh.uvs.iter().map(|v| Float2(v.x, v.y)).collect(), + mesh.indices.clone(), + mesh.triangle_materials.iter().map(|v| v.0).collect(), + ) +} + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct GeometryDomainDocument( pub String, @@ -463,6 +555,31 @@ mod tests { ); } + #[test] + fn mined_csg_performance_fixture_keeps_large_distant_cutters_bounded() { + use bevy_math::Vec3; + use std::time::{Duration, Instant}; + + let mut assembler = Assembler::new(); + assembler.solid_box( + "source", + Aabb::from_center_size(Vec3::ZERO, Vec3::splat(4.0)), + MaterialId(1), + ); + for index in 0..512 { + assembler.cut_box( + format!("distant-{index}"), + Aabb::from_center_size(Vec3::new(100.0 + index as f32 * 2.0, 0.0, 0.0), Vec3::ONE), + ); + } + let started = Instant::now(); + let output = assembler.build(); + assert_eq!(output.mesh.triangle_count(), 12); + assert_eq!(output.report.candidate_pairs, 0); + assert_eq!(output.report.rejected_pairs, 512); + assert!(started.elapsed() < Duration::from_secs(2)); + } + #[test] fn exact_v2_messagepack_and_record_key_witnesses() { let domain = domain(); diff --git a/packages/gamecult-geometry-rs/src/mesh.rs b/packages/gamecult-geometry-rs/src/mesh.rs new file mode 100644 index 00000000..9e23b7ab --- /dev/null +++ b/packages/gamecult-geometry-rs/src/mesh.rs @@ -0,0 +1,103 @@ +#![allow(dead_code)] +use bevy_math::{Vec2, Vec3}; + +use crate::{Aabb, MaterialId}; + +#[derive(Clone, Debug, Default, PartialEq)] +pub struct TriangleMesh { + pub positions: Vec, + pub normals: Vec, + pub uvs: Vec, + pub indices: Vec, + pub triangle_materials: Vec, +} + +impl TriangleMesh { + pub fn new() -> Self { + Self::default() + } + + pub fn triangle_count(&self) -> usize { + self.indices.len() / 3 + } + + pub fn vertex_count(&self) -> usize { + self.positions.len() + } + + pub fn append_box(&mut self, bounds: Aabb, material: MaterialId) { + let min = bounds.min; + let max = bounds.max; + let corners = [ + Vec3::new(min.x, min.y, min.z), + Vec3::new(max.x, min.y, min.z), + Vec3::new(max.x, max.y, min.z), + Vec3::new(min.x, max.y, min.z), + Vec3::new(min.x, min.y, max.z), + Vec3::new(max.x, min.y, max.z), + Vec3::new(max.x, max.y, max.z), + Vec3::new(min.x, max.y, max.z), + ]; + + self.append_quad( + [corners[0], corners[3], corners[2], corners[1]], + Vec3::NEG_Z, + material, + ); + self.append_quad( + [corners[4], corners[5], corners[6], corners[7]], + Vec3::Z, + material, + ); + self.append_quad( + [corners[0], corners[1], corners[5], corners[4]], + Vec3::NEG_Y, + material, + ); + self.append_quad( + [corners[3], corners[7], corners[6], corners[2]], + Vec3::Y, + material, + ); + self.append_quad( + [corners[0], corners[4], corners[7], corners[3]], + Vec3::NEG_X, + material, + ); + self.append_quad( + [corners[1], corners[2], corners[6], corners[5]], + Vec3::X, + material, + ); + } + + pub fn append_quad(&mut self, points: [Vec3; 4], normal: Vec3, material: MaterialId) { + let base = self.positions.len() as u32; + self.positions.extend(points); + self.normals.extend([normal; 4]); + self.uvs.extend([ + Vec2::new(0.0, 0.0), + Vec2::new(1.0, 0.0), + Vec2::new(1.0, 1.0), + Vec2::new(0.0, 1.0), + ]); + self.indices + .extend([base, base + 1, base + 2, base, base + 2, base + 3]); + self.triangle_materials.extend([material; 2]); + } + + pub fn append_triangle( + &mut self, + points: [Vec3; 3], + normal: Vec3, + uvs: [Vec2; 3], + material: MaterialId, + ) { + let base = self.positions.len() as u32; + self.positions.extend(points); + self.normals.extend([normal; 3]); + self.uvs.extend(uvs); + self.indices.extend([base, base + 1, base + 2]); + self.triangle_materials.push(material); + } +} diff --git a/packages/gamecult-geometry-rs/src/primitives.rs b/packages/gamecult-geometry-rs/src/primitives.rs new file mode 100644 index 00000000..bc100e59 --- /dev/null +++ b/packages/gamecult-geometry-rs/src/primitives.rs @@ -0,0 +1,173 @@ +#![allow(dead_code)] +use bevy_math::{Vec2, Vec3}; + +use crate::{MaterialId, TriangleMesh}; + +#[derive(Clone, Copy, Debug)] +pub struct DomeCapZSpec { + pub center: Vec3, + pub radius: f32, + pub height: f32, + pub rings: usize, + pub segments: usize, + pub material: MaterialId, +} + +#[derive(Clone, Copy, Debug)] +pub struct FloretArmSpec { + pub anchor: Vec3, + pub direction: Vec3, + pub length: f32, + pub root_width: f32, + pub tip_width: f32, + pub thickness: f32, + pub tip_lift: f32, + pub material: MaterialId, +} + +pub fn append_cylinder_z( + mesh: &mut TriangleMesh, + center: Vec3, + radius: f32, + depth: f32, + segments: usize, + material: MaterialId, +) { + let segments = segments.max(3); + let half = depth * 0.5; + let bottom_center = center - Vec3::Z * half; + let top_center = center + Vec3::Z * half; + + for i in 0..segments { + let a0 = ring_angle(i, segments); + let a1 = ring_angle(i + 1, segments); + let p0 = center + Vec3::new(a0.cos() * radius, a0.sin() * radius, -half); + let p1 = center + Vec3::new(a1.cos() * radius, a1.sin() * radius, -half); + let p2 = center + Vec3::new(a1.cos() * radius, a1.sin() * radius, half); + let p3 = center + Vec3::new(a0.cos() * radius, a0.sin() * radius, half); + let normal = Vec3::new(((a0 + a1) * 0.5).cos(), ((a0 + a1) * 0.5).sin(), 0.0); + mesh.append_quad([p0, p1, p2, p3], normal, material); + mesh.append_triangle( + [bottom_center, p1, p0], + Vec3::NEG_Z, + [Vec2::ZERO, Vec2::X, Vec2::Y], + material, + ); + mesh.append_triangle( + [top_center, p3, p2], + Vec3::Z, + [Vec2::ZERO, Vec2::X, Vec2::Y], + material, + ); + } +} + +pub fn append_dome_cap_z(mesh: &mut TriangleMesh, spec: DomeCapZSpec) { + let rings = spec.rings.max(2); + let segments = spec.segments.max(6); + let top = spec.center + Vec3::Z * spec.height; + + for ring in 0..rings { + let t0 = ring as f32 / rings as f32; + let t1 = (ring + 1) as f32 / rings as f32; + let r0 = spec.radius * (1.0 - t0 * t0).sqrt(); + let r1 = spec.radius * (1.0 - t1 * t1).sqrt(); + let z0 = spec.center.z + spec.height * t0; + let z1 = spec.center.z + spec.height * t1; + + for seg in 0..segments { + let a0 = ring_angle(seg, segments); + let a1 = ring_angle(seg + 1, segments); + let p0 = Vec3::new( + spec.center.x + a0.cos() * r0, + spec.center.y + a0.sin() * r0, + z0, + ); + let p1 = Vec3::new( + spec.center.x + a1.cos() * r0, + spec.center.y + a1.sin() * r0, + z0, + ); + + if ring + 1 == rings { + let normal = (p0 - spec.center) + .cross(top - spec.center) + .normalize_or_zero(); + mesh.append_triangle( + [p0, p1, top], + normal, + [Vec2::ZERO, Vec2::X, Vec2::Y], + spec.material, + ); + } else { + let p2 = Vec3::new( + spec.center.x + a1.cos() * r1, + spec.center.y + a1.sin() * r1, + z1, + ); + let p3 = Vec3::new( + spec.center.x + a0.cos() * r1, + spec.center.y + a0.sin() * r1, + z1, + ); + let normal = ((p0 + p1 + p2 + p3) * 0.25 - spec.center).normalize_or_zero(); + mesh.append_quad([p0, p1, p2, p3], normal, spec.material); + } + } + } +} + +pub fn append_floret_arm(mesh: &mut TriangleMesh, spec: FloretArmSpec) { + let forward = spec.direction.normalize_or_zero(); + let forward = if forward.length_squared() == 0.0 { + Vec3::X + } else { + forward + }; + let mut side = forward.cross(Vec3::Z).normalize_or_zero(); + if side.length_squared() == 0.0 { + side = Vec3::Y; + } + + let root_center = spec.anchor; + let tip_center = spec.anchor + forward * spec.length + Vec3::Z * spec.tip_lift; + let z = Vec3::Z * (spec.thickness * 0.5); + let r = side * (spec.root_width * 0.5); + let t = side * (spec.tip_width * 0.5); + + let bottom = [ + root_center - r - z, + root_center + r - z, + tip_center + t - z, + tip_center - t - z, + ]; + let top = [ + root_center - r + z, + root_center + r + z, + tip_center + t + z, + tip_center - t + z, + ]; + + mesh.append_quad( + [bottom[0], bottom[3], bottom[2], bottom[1]], + Vec3::NEG_Z, + spec.material, + ); + mesh.append_quad([top[0], top[1], top[2], top[3]], Vec3::Z, spec.material); + mesh.append_quad( + [bottom[0], bottom[1], top[1], top[0]], + -forward, + spec.material, + ); + mesh.append_quad( + [bottom[3], top[3], top[2], bottom[2]], + forward, + spec.material, + ); + mesh.append_quad([bottom[0], top[0], top[3], bottom[3]], -side, spec.material); + mesh.append_quad([bottom[1], bottom[2], top[2], top[1]], side, spec.material); +} + +fn ring_angle(index: usize, segments: usize) -> f32 { + index as f32 * std::f32::consts::TAU / segments as f32 +} diff --git a/packages/gamecult-geometry-rs/src/realtime_csg_parity.rs b/packages/gamecult-geometry-rs/src/realtime_csg_parity.rs new file mode 100644 index 00000000..fbb1ac70 --- /dev/null +++ b/packages/gamecult-geometry-rs/src/realtime_csg_parity.rs @@ -0,0 +1,166 @@ +use crate::{ + Aabb, Assembler, ConvexSolid, CsgBranchOp, CsgOperationType, CsgTreeArena, MaterialId, + PolygonCategory, Primitive, +}; +use bevy_math::{Quat, Vec3}; + +#[test] +fn parity_polygon_category_vocabulary_matches_public_demo() { + let categories = [ + PolygonCategory::Inside, + PolygonCategory::Outside, + PolygonCategory::Aligned, + PolygonCategory::ReverseAligned, + ]; + + assert_eq!(categories.len(), 4); +} + +#[test] +fn parity_operation_type_ordinals_match_public_api() { + assert_eq!(CsgOperationType::Additive as u8, 0); + assert_eq!(CsgOperationType::Subtractive as u8, 1); + assert_eq!(CsgOperationType::Intersecting as u8, 2); +} + +#[test] +fn parity_demo_branch_vocabulary_matches_public_demo() { + let branches = [ + CsgBranchOp::Addition, + CsgBranchOp::Subtraction, + CsgBranchOp::Common, + ]; + + assert_eq!(branches.len(), 3); +} + +#[test] +fn parity_tree_api_exposes_brush_branch_tree_handles() { + let mut arena = CsgTreeArena::new(); + let brush = arena.generate_brush( + "brush", + CsgOperationType::Additive, + Primitive::Box { + bounds: Aabb::from_center_size(Vec3::ZERO, Vec3::ONE), + }, + MaterialId(1), + ); + let branch = arena.generate_branch("branch", CsgBranchOp::Addition, [brush.node]); + let tree = arena.generate_tree(branch.node); + + assert_eq!(arena.brush_count(), 1); + assert_eq!(arena.branch_count(), 1); + assert_eq!(arena.child_nodes(branch).expect("branch"), &[brush.node]); + assert_eq!(tree.root, branch.node); +} + +#[test] +fn parity_box_brush_observable_counts_match_realtime_csg_demo() { + let solid = ConvexSolid::box_from_center_size( + Vec3::ZERO, + Vec3::splat(2.0), + Quat::IDENTITY, + MaterialId(3), + ); + + assert_eq!(solid.clip_planes.len(), 6); + assert_eq!(solid.polygons.len(), 6); + assert_eq!( + solid + .polygons + .iter() + .map(|polygon| polygon.vertices.len()) + .sum::(), + 24 + ); +} + +#[test] +fn parity_center_box_subtraction_has_six_surviving_regions() { + let mut asm = Assembler::new(); + asm.solid_box( + "source", + Aabb::from_center_size(Vec3::ZERO, Vec3::splat(4.0)), + MaterialId(1), + ); + asm.cut_box("void", Aabb::from_center_size(Vec3::ZERO, Vec3::splat(2.0))); + + let output = asm.build(); + assert_eq!(output.report.emitted_convex_fragments, 6); + assert_eq!(output.report.warnings.len(), 0); +} + +#[test] +fn parity_identical_box_polygons_classify_as_aligned() { + let cutter = ConvexSolid::box_from_center_size( + Vec3::ZERO, + Vec3::splat(2.0), + Quat::IDENTITY, + MaterialId(0), + ); + let mut source = ConvexSolid::box_from_center_size( + Vec3::ZERO, + Vec3::splat(2.0), + Quat::IDENTITY, + MaterialId(1), + ); + + source.categorize_whole_polygons_against(&cutter); + + assert_eq!(source.polygons.len(), 6); + assert!( + source + .polygons + .iter() + .all(|polygon| polygon.category == PolygonCategory::Aligned) + ); +} + +#[test] +fn parity_outer_box_polygons_classify_as_outside_inner_box() { + let cutter = ConvexSolid::box_from_center_size( + Vec3::ZERO, + Vec3::splat(2.0), + Quat::IDENTITY, + MaterialId(0), + ); + let mut source = ConvexSolid::box_from_center_size( + Vec3::ZERO, + Vec3::splat(4.0), + Quat::IDENTITY, + MaterialId(1), + ); + + source.categorize_whole_polygons_against(&cutter); + + assert_eq!(source.polygons.len(), 6); + assert!( + source + .polygons + .iter() + .all(|polygon| polygon.category == PolygonCategory::Outside) + ); +} + +#[test] +fn parity_crossing_polygons_split_before_final_category() { + let source = ConvexSolid::box_from_center_size( + Vec3::ZERO, + Vec3::splat(4.0), + Quat::IDENTITY, + MaterialId(1), + ); + let cutter = ConvexSolid::box_from_center_size( + Vec3::new(0.0, 0.0, 1.0), + Vec3::new(2.0, 2.0, 2.0), + Quat::IDENTITY, + MaterialId(0), + ); + + let categorized = source.categorize_polygons_against(&cutter); + + assert_eq!(categorized.aligned.len(), 1); + assert!(categorized.outside.len() > source.polygons.len()); + assert_eq!(categorized.inside.len(), 0); + assert_eq!(categorized.reverse_aligned.len(), 0); +} diff --git a/packages/gamecult-geometry-rs/src/tree.rs b/packages/gamecult-geometry-rs/src/tree.rs new file mode 100644 index 00000000..14bdc226 --- /dev/null +++ b/packages/gamecult-geometry-rs/src/tree.rs @@ -0,0 +1,402 @@ +#![allow(dead_code)] +use crate::{Aabb, Assembler, Brush, BrushId, BrushOp, MaterialId, Primitive}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct CsgNodeId(pub u32); + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct CsgTreeBrush { + pub node: CsgNodeId, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct CsgTreeBranch { + pub node: CsgNodeId, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct CsgTree { + pub root: CsgNodeId, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum CsgOperationType { + Additive = 0, + Subtractive = 1, + Intersecting = 2, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum CsgBranchOp { + Addition, + Subtraction, + Common, +} + +#[derive(Clone, Debug)] +pub enum CsgNode { + Brush(Brush), + Branch { + name: String, + op: CsgBranchOp, + children: Vec, + }, +} + +#[derive(Clone, Debug, Default)] +pub struct CsgTreeArena { + nodes: Vec, +} + +impl CsgTreeArena { + pub fn new() -> Self { + Self::default() + } + + pub fn nodes(&self) -> &[CsgNode] { + &self.nodes + } + + pub fn node(&self, id: CsgNodeId) -> Option<&CsgNode> { + self.nodes.get(id.0 as usize) + } + + pub fn node_mut(&mut self, id: CsgNodeId) -> Option<&mut CsgNode> { + self.nodes.get_mut(id.0 as usize) + } + + pub fn brush_count(&self) -> usize { + self.nodes + .iter() + .filter(|node| matches!(node, CsgNode::Brush(_))) + .count() + } + + pub fn branch_count(&self) -> usize { + self.nodes + .iter() + .filter(|node| matches!(node, CsgNode::Branch { .. })) + .count() + } + + pub fn generate_brush( + &mut self, + name: impl Into, + operation: CsgOperationType, + primitive: Primitive, + material: MaterialId, + ) -> CsgTreeBrush { + let id = CsgNodeId(self.nodes.len() as u32); + let brush = Brush::new( + BrushId(id.0), + name, + operation.into_brush_op(), + primitive, + material, + ); + self.nodes.push(CsgNode::Brush(brush)); + CsgTreeBrush { node: id } + } + + pub fn generate_branch( + &mut self, + name: impl Into, + op: CsgBranchOp, + children: impl IntoIterator, + ) -> CsgTreeBranch { + let id = CsgNodeId(self.nodes.len() as u32); + self.nodes.push(CsgNode::Branch { + name: name.into(), + op, + children: children.into_iter().collect(), + }); + CsgTreeBranch { node: id } + } + + pub fn generate_tree(&self, root: CsgNodeId) -> CsgTree { + CsgTree { root } + } + + pub fn set_brush_operation_type( + &mut self, + brush: CsgTreeBrush, + operation: CsgOperationType, + ) -> bool { + let Some(CsgNode::Brush(node)) = self.node_mut(brush.node) else { + return false; + }; + node.op = operation.into_brush_op(); + node.set_dirty(); + true + } + + pub fn set_branch_operation_type(&mut self, branch: CsgTreeBranch, op: CsgBranchOp) -> bool { + let Some(CsgNode::Branch { op: current_op, .. }) = self.node_mut(branch.node) else { + return false; + }; + *current_op = op; + true + } + + pub fn set_child_nodes( + &mut self, + branch: CsgTreeBranch, + children: impl IntoIterator, + ) -> bool { + let Some(CsgNode::Branch { + children: current_children, + .. + }) = self.node_mut(branch.node) + else { + return false; + }; + *current_children = children.into_iter().collect(); + true + } + + pub fn child_nodes(&self, branch: CsgTreeBranch) -> Option<&[CsgNodeId]> { + let Some(CsgNode::Branch { children, .. }) = self.node(branch.node) else { + return None; + }; + Some(children) + } + + pub fn node_bounds(&self, id: CsgNodeId) -> Option { + match self.node(id)? { + CsgNode::Brush(brush) => Some(brush.bounds()), + CsgNode::Branch { op, children, .. } => self.branch_bounds(*op, children), + } + } + + pub fn compile_tree_to_assembler(&self, tree: CsgTree) -> Assembler { + let mut assembler = Assembler::new(); + self.compile_node(tree.root, &mut assembler, None); + assembler + } + + fn compile_node( + &self, + id: CsgNodeId, + assembler: &mut Assembler, + operation_override: Option, + ) { + let Some(node) = self.node(id) else { + return; + }; + + match node { + CsgNode::Brush(brush) => { + let op = operation_override + .map(CsgOperationType::into_brush_op) + .unwrap_or(brush.op); + assembler.add_brush( + brush.name.clone(), + op, + brush.primitive.clone(), + brush.material, + ); + } + CsgNode::Branch { op, children, .. } => match op { + CsgBranchOp::Addition => { + for child in children { + self.compile_node(*child, assembler, operation_override); + } + } + CsgBranchOp::Subtraction => { + if let Some((first, rest)) = children.split_first() { + self.compile_node(*first, assembler, operation_override); + for child in rest { + self.compile_node( + *child, + assembler, + Some(CsgOperationType::Subtractive), + ); + } + } + } + CsgBranchOp::Common => { + if let Some((first, rest)) = children.split_first() { + self.compile_node(*first, assembler, operation_override); + for child in rest { + self.compile_node( + *child, + assembler, + Some(CsgOperationType::Intersecting), + ); + } + } + } + }, + } + } + + fn branch_bounds(&self, op: CsgBranchOp, children: &[CsgNodeId]) -> Option { + let mut child_bounds = children.iter().filter_map(|child| self.node_bounds(*child)); + match op { + CsgBranchOp::Addition => child_bounds.reduce(Aabb::union), + CsgBranchOp::Subtraction => child_bounds.next(), + CsgBranchOp::Common => { + let first = child_bounds.next()?; + child_bounds.try_fold(first, |bounds, child| bounds.intersection(child)) + } + } + } +} + +impl CsgOperationType { + pub fn into_brush_op(self) -> BrushOp { + match self { + Self::Additive => BrushOp::Add, + Self::Subtractive => BrushOp::Subtract, + Self::Intersecting => BrushOp::Intersect, + } + } +} + +impl From for CsgOperationType { + fn from(value: BrushOp) -> Self { + match value { + BrushOp::Add => Self::Additive, + BrushOp::Subtract => Self::Subtractive, + BrushOp::Intersect => Self::Intersecting, + } + } +} + +#[cfg(test)] +mod tests { + use bevy_math::Vec3; + + use super::*; + use crate::{Aabb, Primitive}; + + #[test] + fn tree_subtraction_compiles_to_ordered_brush_stream() { + let mut arena = CsgTreeArena::new(); + let solid = arena.generate_brush( + "solid", + CsgOperationType::Additive, + Primitive::Box { + bounds: Aabb::from_center_size(Vec3::ZERO, Vec3::splat(4.0)), + }, + MaterialId(1), + ); + let void = arena.generate_brush( + "void", + CsgOperationType::Additive, + Primitive::Box { + bounds: Aabb::from_center_size(Vec3::ZERO, Vec3::splat(2.0)), + }, + MaterialId(0), + ); + let branch = arena.generate_branch( + "solid minus void", + CsgBranchOp::Subtraction, + [solid.node, void.node], + ); + let assembler = arena.compile_tree_to_assembler(arena.generate_tree(branch.node)); + + assert_eq!(assembler.brushes().len(), 2); + assert_eq!(assembler.brushes()[0].op, BrushOp::Add); + assert_eq!(assembler.brushes()[1].op, BrushOp::Subtract); + assert_eq!(assembler.build().report.emitted_convex_fragments, 6); + } + + #[test] + fn tree_edit_api_replaces_children_and_operations() { + let mut arena = CsgTreeArena::new(); + let a = arena.generate_brush( + "a", + CsgOperationType::Additive, + Primitive::Box { + bounds: Aabb::from_center_size(Vec3::ZERO, Vec3::splat(2.0)), + }, + MaterialId(1), + ); + let b = arena.generate_brush( + "b", + CsgOperationType::Additive, + Primitive::Box { + bounds: Aabb::from_center_size(Vec3::X, Vec3::splat(1.0)), + }, + MaterialId(1), + ); + let branch = arena.generate_branch("branch", CsgBranchOp::Addition, [a.node]); + + assert!(arena.set_child_nodes(branch, [a.node, b.node])); + assert_eq!(arena.child_nodes(branch).expect("branch").len(), 2); + assert!(arena.set_branch_operation_type(branch, CsgBranchOp::Subtraction)); + assert!(arena.set_brush_operation_type(b, CsgOperationType::Subtractive)); + assert_eq!(arena.brush_count(), 2); + assert_eq!(arena.branch_count(), 1); + } + + #[test] + fn tree_bounds_follow_boolean_branch_shape() { + let mut arena = CsgTreeArena::new(); + let a = arena.generate_brush( + "a", + CsgOperationType::Additive, + Primitive::Box { + bounds: Aabb::from_center_size(Vec3::ZERO, Vec3::splat(4.0)), + }, + MaterialId(1), + ); + let b = arena.generate_brush( + "b", + CsgOperationType::Additive, + Primitive::Box { + bounds: Aabb::from_center_size(Vec3::X * 2.5, Vec3::splat(2.0)), + }, + MaterialId(1), + ); + let union = arena.generate_branch("union", CsgBranchOp::Addition, [a.node, b.node]); + let common = arena.generate_branch("common", CsgBranchOp::Common, [a.node, b.node]); + let subtract = + arena.generate_branch("subtract", CsgBranchOp::Subtraction, [a.node, b.node]); + + assert_eq!( + arena.node_bounds(union.node).expect("union"), + Aabb::new(Vec3::splat(-2.0), Vec3::new(3.5, 2.0, 2.0)) + ); + assert_eq!( + arena.node_bounds(common.node).expect("common"), + Aabb::new(Vec3::new(1.5, -1.0, -1.0), Vec3::new(2.0, 1.0, 1.0)) + ); + assert_eq!( + arena.node_bounds(subtract.node).expect("subtract"), + Aabb::from_center_size(Vec3::ZERO, Vec3::splat(4.0)) + ); + } + + #[test] + fn tree_common_compiles_to_additive_source_then_intersections() { + let mut arena = CsgTreeArena::new(); + let a = arena.generate_brush( + "a", + CsgOperationType::Additive, + Primitive::Box { + bounds: Aabb::from_center_size(Vec3::ZERO, Vec3::splat(4.0)), + }, + MaterialId(1), + ); + let b = arena.generate_brush( + "b", + CsgOperationType::Additive, + Primitive::Box { + bounds: Aabb::from_center_size(Vec3::X, Vec3::splat(4.0)), + }, + MaterialId(1), + ); + let branch = arena.generate_branch("common", CsgBranchOp::Common, [a.node, b.node]); + + let assembler = arena.compile_tree_to_assembler(arena.generate_tree(branch.node)); + let output = assembler.build(); + + assert_eq!(assembler.brushes()[0].op, BrushOp::Add); + assert_eq!(assembler.brushes()[1].op, BrushOp::Intersect); + assert_eq!(output.report.emitted_convex_fragments, 1); + assert_eq!(output.report.warnings.len(), 0); + assert_eq!(output.mesh.triangle_count(), 12); + } +} From 9758940b35827b0ff0f1a93964390e22a71c26e7 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 04:01:20 +0100 Subject: [PATCH 032/283] Integrate geometry worker through CultMesh --- ...th-gamecult-geometry-migration-progress.md | 39 +++- .../CultGeometryWorkerDocuments.cs | 87 +++++++++ .../CultGeometryWorkerProvider.cs | 124 ++++++++++++ .../GameCult.Geometry.csproj | 2 + .../CultGeometryWorkerProviderTests.cs | 182 ++++++++++++++++++ 5 files changed, 424 insertions(+), 10 deletions(-) create mode 100644 src/GameCult.Geometry/CultGeometryWorkerDocuments.cs create mode 100644 src/GameCult.Geometry/CultGeometryWorkerProvider.cs create mode 100644 tests/GameCult.Geometry.Tests/CultGeometryWorkerProviderTests.cs diff --git a/docs/cultmath-gamecult-geometry-migration-progress.md b/docs/cultmath-gamecult-geometry-migration-progress.md index ace7653e..79dce55e 100644 --- a/docs/cultmath-gamecult-geometry-migration-progress.md +++ b/docs/cultmath-gamecult-geometry-migration-progress.md @@ -4,7 +4,7 @@ Plan: `docs/cultmath-gamecult-geometry-migration-plan.md` (locked) Started: 2026-07-22 -Status: Stages 0-4 complete; Stage 5 in progress +Status: Stages 0-5 complete; Stage 6 in progress ## Objective @@ -59,8 +59,8 @@ Demotions: | 2. Primitive deletion and v2 schemas | Complete | C# and Geometry-owned Rust emit identical v2 bytes and record keys for all four roots | | 3. Planetary transfer | Complete | Managed, HLSL, CMPT, Unity, web, tool, docs, tests, and package authority moved; CultMath owners deleted | | 4. Mine `vg-csg` | Complete | Geometry-owned Rust kernel passes correctness, parity, performance, formatting, and warning-denied lint gates | -| 5. CultCache/CultNet/CultMesh integration | In progress | Provider/dataflow mapped; typed commit-path smoke remains | -| 6. Consumer cutover/release | Pending | Requires local candidate feed and downstream passes | +| 5. CultCache/CultNet/CultMesh integration | Complete | One provider commit path persists, watches, replicates, and probes typed geometry state | +| 6. Consumer cutover/release | In progress | Fensalir/Aetheria exact cutover surfaces mapped; consumer edits and release receipts remain | | 7. Delete obsolete authorities/audit | Pending | Requires every prior stage gate | ## Verification Receipts @@ -244,13 +244,32 @@ a broader stage gate. passes 67/67 plus doc tests; rustfmt and warning-denied Clippy pass. - The authority transfer commits are CultLib `756f5a33`, CultMath `6a16260`, and the post-transfer label cleanup `99c893bd`. The Rust absorption commit is - recorded after this progress update is committed. + CultLib `6b44f969`. + +### Stage 5 receipts + +- `CultGeometryWorkerProvider` owns the build invocation and output commit + sequence. Direct calls and the `gamecult.geometry.worker.build` CultMesh + operation share `BuildAsync`; compute is injected through the persistence-free + `ICultGeometryBuildPipeline` port. +- Domain/request reads and selected-cut, artifact, and observational worker-state + writes use `CultNetDatabase` typed APIs. Watches and raw MessagePack envelopes + are consequences of that commit path rather than parallel publishers. +- The development probe derives owner, v2 schema, request/cut keys, selected + nodes, artifact identities, content hashes, and served assembly version from + persisted documents. Mutating worker display state cannot overwrite geometry + outputs or forge the served version. +- Worker state registers through the generated CultDocument registry. Focused + provider tests pass 4/4 and the full GameCult.Geometry suite passes 31/31. +- Rust raw-envelope duplication was deliberately omitted: CultNet owns that + protocol. Existing C#/Rust exact v2 document bytes and record keys remain the + cross-runtime geometry witness. ## Next Actions -1. Add the Geometry-owned worker provider with `CultNetDatabase.PutAsync` as - the single commit/publication primitive for direct and operation-handle use. -2. Prove domain/request to selected-cut/artifact persistence, raw envelope - replication, worker-state observation, and typed dev-probe agreement. -3. Add exact C#/Rust raw-envelope parity without growing a second networking - stack or a load-bearing JSON projection. +1. Cut Fensalir's C# and HLSL planetary surfaces atomically to + GameCult.Geometry, including shader resolver and parity harnesses. +2. Replace Aetheria Freeze's remaining `CultVec*` fixtures with CultMath values + under an exact serialization witness, then regenerate Unity project files. +3. Rebuild coordinated CultMath and Geometry candidates and run the named + downstream parity corpus before publication. diff --git a/src/GameCult.Geometry/CultGeometryWorkerDocuments.cs b/src/GameCult.Geometry/CultGeometryWorkerDocuments.cs new file mode 100644 index 00000000..280f7c4f --- /dev/null +++ b/src/GameCult.Geometry/CultGeometryWorkerDocuments.cs @@ -0,0 +1,87 @@ +using System; +using GameCult.Caching; +using MessagePack; + +namespace GameCult.Geometry +{ + public static class CultGeometryWorkerSchemaVersions + { + public const string State = "gamecult.geometry.worker_state.v1"; + } + + [MessagePackObject] + [CultDocument("gamecult.geometry.worker_state", CultGeometryWorkerSchemaVersions.State)] + public sealed class CultGeometryWorkerState + { + [Key(0), CultName] + public string WorkerId { get; set; } = string.Empty; + + [Key(1)] + public string Phase { get; set; } = string.Empty; + + [Key(2), CultReference(typeof(CultGeometryBuildRequest))] + public string ActiveRequestKey { get; set; } = string.Empty; + + [Key(3), CultReference(typeof(CultGeometrySelectedCutManifest))] + public string LastSelectedCutKey { get; set; } = string.Empty; + + [Key(4)] + public string[] LastArtifactKeys { get; set; } = Array.Empty(); + + [Key(5)] + public string LastError { get; set; } = string.Empty; + + [Key(6)] + public string UpdatedAt { get; set; } = string.Empty; + + [Key(7)] + public string ServedPackageVersion { get; set; } = string.Empty; + + public static CultRecordKey CreateRecordKey(string workerId) + { + if (string.IsNullOrWhiteSpace(workerId)) throw new ArgumentException("Value must be non-empty.", nameof(workerId)); + return new CultRecordKey("geometry:worker:" + workerId); + } + } + + [MessagePackObject] + public sealed class CultGeometryBuildCommand + { + [Key(0)] + public string RequestKey { get; set; } = string.Empty; + } + + [MessagePackObject] + public sealed class CultGeometryBuildReceipt + { + [Key(0)] + public string RequestKey { get; set; } = string.Empty; + + [Key(1)] + public string SelectedCutKey { get; set; } = string.Empty; + + [Key(2)] + public string[] ArtifactKeys { get; set; } = Array.Empty(); + + [Key(3)] + public string[] ContentHashes { get; set; } = Array.Empty(); + } + + public sealed class CultGeometryBuildOutput + { + public CultGeometrySelectedCutManifest SelectedCut { get; init; } = new(); + public CultGeometryChunkArtifact[] Artifacts { get; init; } = Array.Empty(); + } + + public sealed class CultGeometryDevelopmentProbe + { + public string Owner { get; init; } = string.Empty; + public string SchemaVersion { get; init; } = string.Empty; + public string SourceRecordKey { get; init; } = string.Empty; + public string SelectedCutKey { get; init; } = string.Empty; + public string[] SelectedNodes { get; init; } = Array.Empty(); + public string[] ArtifactKeys { get; init; } = Array.Empty(); + public string[] ContentHashes { get; init; } = Array.Empty(); + public string ServedPackageVersion { get; init; } = string.Empty; + } +} diff --git a/src/GameCult.Geometry/CultGeometryWorkerProvider.cs b/src/GameCult.Geometry/CultGeometryWorkerProvider.cs new file mode 100644 index 00000000..745da5a1 --- /dev/null +++ b/src/GameCult.Geometry/CultGeometryWorkerProvider.cs @@ -0,0 +1,124 @@ +using System; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using GameCult.Caching; +using GameCult.Mesh; +using GameCult.Networking; + +namespace GameCult.Geometry +{ + public interface ICultGeometryBuildPipeline + { + Task BuildAsync( + CultGeometryDomainDocument domain, + CultGeometryBuildRequest request); + } + + /// Owns geometry worker commands and the authoritative output commit path. + public sealed class CultGeometryWorkerProvider + { + public const string Owner = "GameCult.Geometry"; + public const string BuildOperationId = "gamecult.geometry.worker.build"; + + private readonly string _workerId; + private readonly CultNetDatabase _database; + private readonly ICultGeometryBuildPipeline _pipeline; + + public CultGeometryWorkerProvider( + string workerId, + CultNetDatabase database, + ICultGeometryBuildPipeline pipeline) + { + _workerId = string.IsNullOrWhiteSpace(workerId) + ? throw new ArgumentException("Value must be non-empty.", nameof(workerId)) + : workerId; + _database = database ?? throw new ArgumentNullException(nameof(database)); + _pipeline = pipeline ?? throw new ArgumentNullException(nameof(pipeline)); + BuildOperation = new CultMeshOperationHandle( + BuildOperationId, + (command, _) => BuildAsync(command)); + } + + public CultMeshOperationHandle BuildOperation { get; } + + public CultRecordKey WorkerStateKey => CultGeometryWorkerState.CreateRecordKey(_workerId); + + public async Task BuildAsync(CultGeometryBuildCommand command) + { + if (command == null) throw new ArgumentNullException(nameof(command)); + if (string.IsNullOrWhiteSpace(command.RequestKey)) + throw new ArgumentException("Request key must be non-empty.", nameof(command)); + + var requestKey = new CultRecordKey(command.RequestKey); + var request = await RequireAsync(requestKey).ConfigureAwait(false); + var domain = await RequireAsync(new CultRecordKey(request.DomainKey)).ConfigureAwait(false); + var output = await _pipeline.BuildAsync(domain, request).ConfigureAwait(false) + ?? throw new InvalidOperationException("Geometry build pipeline returned no output."); + + output.SelectedCut.RequestKey = requestKey.Value; + var cutKey = CultGeometrySelectedCutManifest.CreateRecordKey(output.SelectedCut); + await _database.PutAsync(cutKey, output.SelectedCut).ConfigureAwait(false); + + var artifactKeys = new string[output.Artifacts.Length]; + for (var index = 0; index < output.Artifacts.Length; index++) + { + var artifact = output.Artifacts[index]; + artifact.CutKey = cutKey.Value; + artifact.SelectedCutId = output.SelectedCut.CutId; + var artifactKey = CultGeometryChunkArtifact.CreateRecordKey(artifact); + await _database.PutAsync(artifactKey, artifact).ConfigureAwait(false); + artifactKeys[index] = artifactKey.Value; + } + + var receipt = new CultGeometryBuildReceipt + { + RequestKey = requestKey.Value, + SelectedCutKey = cutKey.Value, + ArtifactKeys = artifactKeys, + ContentHashes = artifactKeys.Select(ContentHashFromKey).ToArray() + }; + await _database.PutAsync(WorkerStateKey, new CultGeometryWorkerState + { + WorkerId = _workerId, + Phase = "completed", + ActiveRequestKey = requestKey.Value, + LastSelectedCutKey = cutKey.Value, + LastArtifactKeys = artifactKeys, + UpdatedAt = DateTimeOffset.UtcNow.ToString("O"), + ServedPackageVersion = PackageVersion + }).ConfigureAwait(false); + return receipt; + } + + public async Task ProbeAsync() + { + var state = await RequireAsync(WorkerStateKey).ConfigureAwait(false); + var cut = await RequireAsync(new CultRecordKey(state.LastSelectedCutKey)).ConfigureAwait(false); + return new CultGeometryDevelopmentProbe + { + Owner = Owner, + SchemaVersion = CultGeometrySchemaVersions.SelectedCut, + SourceRecordKey = state.ActiveRequestKey, + SelectedCutKey = state.LastSelectedCutKey, + SelectedNodes = cut.SelectedNodes, + ArtifactKeys = state.LastArtifactKeys, + ContentHashes = state.LastArtifactKeys.Select(ContentHashFromKey).ToArray(), + ServedPackageVersion = PackageVersion + }; + } + + private async Task RequireAsync(CultRecordKey key) where T : class => + await _database.GetAsync(key).ConfigureAwait(false) + ?? throw new InvalidOperationException($"Required geometry document '{key.Value}' was not found."); + + private static string ContentHashFromKey(string key) => + key[(key.LastIndexOf(':') + 1)..]; + + private static string PackageVersion => + typeof(CultGeometryWorkerProvider).Assembly + .GetCustomAttribute()?.InformationalVersion + ?? typeof(CultGeometryWorkerProvider).Assembly.GetName().Version?.ToString() + ?? "unknown"; + } +} diff --git a/src/GameCult.Geometry/GameCult.Geometry.csproj b/src/GameCult.Geometry/GameCult.Geometry.csproj index 32d72d0a..5f45e89b 100644 --- a/src/GameCult.Geometry/GameCult.Geometry.csproj +++ b/src/GameCult.Geometry/GameCult.Geometry.csproj @@ -13,6 +13,8 @@ + + diff --git a/tests/GameCult.Geometry.Tests/CultGeometryWorkerProviderTests.cs b/tests/GameCult.Geometry.Tests/CultGeometryWorkerProviderTests.cs new file mode 100644 index 00000000..0941f0f4 --- /dev/null +++ b/tests/GameCult.Geometry.Tests/CultGeometryWorkerProviderTests.cs @@ -0,0 +1,182 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using CultMath; +using FluentAssertions; +using GameCult.Caching; +using GameCult.Mesh; +using GameCult.Networking; +using NUnit.Framework; +using R3; + +namespace GameCult.Geometry.Tests +{ + public sealed class CultGeometryWorkerProviderTests + { + [Test] + public async Task BuildOperation_UsesTheDirectCommitPath_AndPublishesTypedState() + { + using var database = CreateDatabase("geometry-worker"); + var (domain, request) = await SeedAsync(database); + var provider = new CultGeometryWorkerProvider("worker-1", database, new FakePipeline()); + var artifactChanges = new List>(); + using var subscription = database.Watch() + .Subscribe(change => artifactChanges.Add(change)); + + var receipt = await provider.BuildOperation.InvokeAsync( + new CultGeometryBuildCommand { RequestKey = CultGeometryBuildRequest.CreateRecordKey(request).Value }, + "test-runtime"); + + receipt.RequestKey.Should().Be(CultGeometryBuildRequest.CreateRecordKey(request).Value); + receipt.ArtifactKeys.Should().ContainSingle(); + receipt.ContentHashes.Should().ContainSingle(); + artifactChanges.Should().ContainSingle(change => change.Key.Value == receipt.ArtifactKeys[0]); + (await database.GetAsync(new CultRecordKey(receipt.SelectedCutKey))) + .Should().NotBeNull(); + (await database.GetAsync(new CultRecordKey(receipt.ArtifactKeys[0]))) + .Should().NotBeNull(); + + var state = await database.GetAsync(provider.WorkerStateKey); + state.Should().NotBeNull(); + state!.ActiveRequestKey.Should().Be(receipt.RequestKey); + state.LastSelectedCutKey.Should().Be(receipt.SelectedCutKey); + domain.DomainId.Should().Be("domain-1"); + } + + [Test] + public async Task DirectAndOperationBuilds_DeriveTheSameCanonicalOutputKeys() + { + using var database = CreateDatabase("geometry-direct-operation"); + var (_, request) = await SeedAsync(database); + var provider = new CultGeometryWorkerProvider("worker-1", database, new FakePipeline()); + var command = new CultGeometryBuildCommand + { + RequestKey = CultGeometryBuildRequest.CreateRecordKey(request).Value + }; + + var direct = await provider.BuildAsync(command); + var operation = await provider.BuildOperation.InvokeAsync(command, "test-runtime"); + + operation.SelectedCutKey.Should().Be(direct.SelectedCutKey); + operation.ArtifactKeys.Should().Equal(direct.ArtifactKeys); + operation.ContentHashes.Should().Equal(direct.ContentHashes); + } + + [Test] + public async Task Artifact_RawEnvelopeReplicates_AndWorkerStateCannotOverrideProbeTruth() + { + using var source = CreateDatabase("geometry-source"); + var (_, request) = await SeedAsync(source); + var provider = new CultGeometryWorkerProvider("worker-1", source, new FakePipeline()); + var receipt = await provider.BuildAsync(new CultGeometryBuildCommand + { + RequestKey = CultGeometryBuildRequest.CreateRecordKey(request).Value + }); + var artifactKey = new CultRecordKey(receipt.ArtifactKeys[0]); + var artifact = await source.GetAsync(artifactKey); + artifact.Should().NotBeNull(); + + var put = source.Documents.CreateRawDocumentPutMessage( + "geometry-artifact", + new CultRecordHandle(artifactKey), + artifact!, + new CultNetDocumentMessageOptions { SourceRuntimeId = "geometry-source", SourceRole = "geometry-worker" }); + put.Document.PayloadEncoding.Should().Be("messagepack"); + + var targetCache = new CultCache(); + var replicated = await source.Documents.ApplyRawDocumentPutMessageAsync(targetCache, put); + CultGeometryChunkArtifact.CreateRecordKey(replicated).Should().Be(artifactKey); + + await source.PutAsync(provider.WorkerStateKey, new CultGeometryWorkerState + { + WorkerId = "worker-1", + Phase = "lying-status", + ActiveRequestKey = receipt.RequestKey, + LastSelectedCutKey = receipt.SelectedCutKey, + LastArtifactKeys = receipt.ArtifactKeys, + ServedPackageVersion = "false-version" + }); + var probe = await provider.ProbeAsync(); + + probe.Owner.Should().Be(CultGeometryWorkerProvider.Owner); + probe.SchemaVersion.Should().Be(CultGeometrySchemaVersions.SelectedCut); + probe.SelectedCutKey.Should().Be(receipt.SelectedCutKey); + probe.ContentHashes.Should().Equal(receipt.ContentHashes); + probe.ServedPackageVersion.Should().NotBe("false-version"); + (await source.GetAsync(artifactKey))!.ChunkId.Should().Be("chunk-1"); + } + + [Test] + public void WorkerState_RegistersThroughTheGeneratedDocumentRegistry() + { + var descriptor = new CultCache().Registry.GetRequired(); + descriptor.SchemaVersion.Should().Be(CultGeometryWorkerSchemaVersions.State); + descriptor.SchemaName.Should().Be("gamecult.geometry.worker_state"); + } + + private static CultNetDatabase CreateDatabase(string runtimeId) + { + var cache = new CultCache(); + return new CultNetDatabase(cache, new CultNetDatabaseOptions + { + RuntimeId = runtimeId, + DocumentRegistry = new CultNetDocumentRegistry(cache.Registry) + }); + } + + private static async Task<(CultGeometryDomainDocument Domain, CultGeometryBuildRequest Request)> SeedAsync( + CultNetDatabase database) + { + var domain = new CultGeometryDomainDocument + { + DomainId = "domain-1", + RootKey = "root", + SourceRuntime = "test", + Root = new CultGeometryDomainNode { Name = "root", Kind = "root" } + }; + var domainKey = CultGeometryDomainDocument.CreateRecordKey(domain); + var request = new CultGeometryBuildRequest + { + RequestId = "request-1", + DomainKey = domainKey.Value, + WorkerGroup = "test", + ViewportHeightPixels = 1080, + VerticalFovRadians = 1, + TargetError = 0.01f, + TriangleBudget = 100, + ColliderBudget = 100 + }; + await database.PutAsync(domainKey, domain); + await database.PutAsync(CultGeometryBuildRequest.CreateRecordKey(request), request); + return (domain, request); + } + + private sealed class FakePipeline : ICultGeometryBuildPipeline + { + public Task BuildAsync( + CultGeometryDomainDocument domain, + CultGeometryBuildRequest request) + { + return Task.FromResult(new CultGeometryBuildOutput + { + SelectedCut = new CultGeometrySelectedCutManifest + { + CutId = "cut-1", + SelectedNodes = [domain.Root.Name] + }, + Artifacts = + [ + new CultGeometryChunkArtifact + { + ChunkId = "chunk-1", + BoundsMin = float3.zero, + BoundsMax = new float3(1, 1, 1), + SourceDomainKeys = [request.DomainKey], + RenderMesh = new CultGeometryTriangleMesh() + } + ] + }); + } + } + } +} From cdeea4745487c11334c4f9e964490de4e7cd2a30 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 04:07:20 +0100 Subject: [PATCH 033/283] Use compiler-portable geometry shader includes --- src/GameCult.Geometry/Shaders/GameCult.Geometry.hlsl | 8 ++++---- .../GeometryShaderOwnershipTests.cs | 6 +++--- .../Runtime/GameCultGeometryPlanetaryViewer.shader | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/GameCult.Geometry/Shaders/GameCult.Geometry.hlsl b/src/GameCult.Geometry/Shaders/GameCult.Geometry.hlsl index fb159077..00623b75 100644 --- a/src/GameCult.Geometry/Shaders/GameCult.Geometry.hlsl +++ b/src/GameCult.Geometry/Shaders/GameCult.Geometry.hlsl @@ -1,11 +1,11 @@ #ifndef GAMECULT_GEOMETRY_HLSL #define GAMECULT_GEOMETRY_HLSL -#ifndef GAMECULT_GEOMETRY_CULTMATH_INCLUDE -#define GAMECULT_GEOMETRY_CULTMATH_INCLUDE "CultMath.hlsl" +#if defined(GAMECULT_GEOMETRY_UNITY_PACKAGE) +#include "Packages/org.gamecult.cultmath/shaders/CultMath.hlsl" +#else +#include "CultMath/CultMath.hlsl" #endif - -#include GAMECULT_GEOMETRY_CULTMATH_INCLUDE #include "AdvancedErosionFilter.hlsl" #include "Planetary.hlsl" #include "SphericalErosion.hlsl" diff --git a/tests/GameCult.Geometry.Tests/GeometryShaderOwnershipTests.cs b/tests/GameCult.Geometry.Tests/GeometryShaderOwnershipTests.cs index ba5bcf64..e3650f85 100644 --- a/tests/GameCult.Geometry.Tests/GeometryShaderOwnershipTests.cs +++ b/tests/GameCult.Geometry.Tests/GeometryShaderOwnershipTests.cs @@ -16,8 +16,8 @@ public sealed class GeometryShaderOwnershipTests var spherical = File.ReadAllText(Path.Combine(shaders, "SphericalErosion.hlsl")); var refinement = File.ReadAllText(Path.Combine(shaders, "PlanetaryRadialRefinement.hlsl")); - Assert.That(umbrella, Does.Contain("#define GAMECULT_GEOMETRY_CULTMATH_INCLUDE \"CultMath.hlsl\"") - .And.Contain("#include GAMECULT_GEOMETRY_CULTMATH_INCLUDE") + Assert.That(umbrella, Does.Contain("#include \"CultMath/CultMath.hlsl\"") + .And.Contain("#include \"Packages/org.gamecult.cultmath/shaders/CultMath.hlsl\"") .And.Contain("#include \"AdvancedErosionFilter.hlsl\"") .And.Contain("#include \"Planetary.hlsl\"") .And.Contain("#include \"SphericalErosion.hlsl\"") @@ -54,7 +54,7 @@ public sealed class GeometryShaderOwnershipTests "GameCultGeometryPlanetaryViewer.shader")); Assert.That(shader, Does.Contain( - "#define GAMECULT_GEOMETRY_CULTMATH_INCLUDE \"Packages/org.gamecult.cultmath/shaders/CultMath.hlsl\"") + "#define GAMECULT_GEOMETRY_UNITY_PACKAGE 1") .And.Contain("#include \"Packages/org.gamecult.geometry/Shaders/GameCult.Geometry.hlsl\"") .And.Contain("gamecult_geometry_planetary_field_sample") .And.Not.Contain("cultmath_planetary_") diff --git a/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Runtime/GameCultGeometryPlanetaryViewer.shader b/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Runtime/GameCultGeometryPlanetaryViewer.shader index 850e1dd5..9b4981c0 100644 --- a/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Runtime/GameCultGeometryPlanetaryViewer.shader +++ b/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Runtime/GameCultGeometryPlanetaryViewer.shader @@ -18,7 +18,7 @@ Shader "GameCult.Geometry/Planetary Field Viewer" #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" - #define GAMECULT_GEOMETRY_CULTMATH_INCLUDE "Packages/org.gamecult.cultmath/shaders/CultMath.hlsl" + #define GAMECULT_GEOMETRY_UNITY_PACKAGE 1 #include "Packages/org.gamecult.geometry/Shaders/GameCult.Geometry.hlsl" float _Radius; From 381d23aceec1c588e103ae170dfc26797046ce9a Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 04:08:32 +0100 Subject: [PATCH 034/283] Add coordinated Geometry candidate build --- scripts/build-geometry-candidate.ps1 | 31 ++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 scripts/build-geometry-candidate.ps1 diff --git a/scripts/build-geometry-candidate.ps1 b/scripts/build-geometry-candidate.ps1 new file mode 100644 index 00000000..0edffcf7 --- /dev/null +++ b/scripts/build-geometry-candidate.ps1 @@ -0,0 +1,31 @@ +param( + [string] $Version = "0.1.0-geometry-migration.2", + [string] $OutputDirectory = "artifacts\candidate-feed", + [string] $CultMathCandidateFeed = "..\CultMath\.tools\local-feed" +) +$ErrorActionPreference = "Stop" +$root = Split-Path -Parent $PSScriptRoot +$project = Join-Path $root "src\GameCult.Geometry\GameCult.Geometry.csproj" +$output = Join-Path $root $OutputDirectory +$feed = [IO.Path]::GetFullPath((Join-Path $root $CultMathCandidateFeed)) +New-Item -ItemType Directory -Force -Path $output | Out-Null +$supportProjects = @( + "src\GameCult.Logging\GameCult.Logging.csproj", + "src\GameCult.Caching\GameCult.Caching.csproj", + "src\GameCult.Caching.MessagePack.Analyzers\GameCult.Caching.MessagePack.Analyzers.csproj", + "src\GameCult.Caching.MessagePack\GameCult.Caching.MessagePack.csproj", + "src\GameCult.Networking\GameCult.Networking.csproj", + "src\GameCult.Mesh\GameCult.Mesh.csproj" +) +foreach ($relativeProject in $supportProjects) { + $supportProject = Join-Path $root $relativeProject + dotnet pack $supportProject -c Release -o $output --disable-build-servers -p:PackageVersion=$Version -p:UseSharedCompilation=false -m:1 + if ($LASTEXITCODE -ne 0) { throw "Candidate support pack failed: $relativeProject" } +} +dotnet restore $project --disable-build-servers -p:CultMathCandidateFeed=$feed -p:UseSharedCompilation=false -m:1 +if ($LASTEXITCODE -ne 0) { throw "Geometry candidate restore failed." } +dotnet pack $project -c Release -o $output --no-restore --disable-build-servers -p:PackageVersion=$Version -p:CultMathCandidateFeed=$feed -p:UseSharedCompilation=false -m:1 +if ($LASTEXITCODE -ne 0) { throw "Geometry candidate pack failed." } +$package = Join-Path $output "GameCult.Geometry.$Version.nupkg" +if (-not (Test-Path -LiteralPath $package)) { throw "Geometry candidate package was not produced." } +Write-Host $package From 8a7eee717e5783190bf17337d3560defa4b28fa7 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 04:13:43 +0100 Subject: [PATCH 035/283] Document generated geometry registry ownership --- src/GameCult.Geometry/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/GameCult.Geometry/README.md b/src/GameCult.Geometry/README.md index 3c1f75bd..42c681cb 100644 --- a/src/GameCult.Geometry/README.md +++ b/src/GameCult.Geometry/README.md @@ -44,11 +44,7 @@ using GameCult.Geometry; using GameCult.Mesh; using GameCult.Networking; -var geometryDocuments = new CultNetDocumentRegistry(CultDocumentRegistry.Shared) - .Register(CultNetDocumentBinding.ForDocument()) - .Register(CultNetDocumentBinding.ForDocument()) - .Register(CultNetDocumentBinding.ForDocument()) - .Register(CultNetDocumentBinding.ForDocument()); +var geometryDocuments = new CultNetDocumentRegistry(CultDocumentRegistry.Shared); using var node = await CultMesh.CreateNodeAsync("ragnarok-geometry.ccmp", new CultMeshNodeOptions { @@ -64,6 +60,10 @@ using var chunks = node.Database .Subscribe(change => ApplyChunk(change.Document)); ``` +The generated CultDocument metadata owns geometry registration. Consumers pass +the shared registry into CultNet; they do not maintain a second manual binding +list that can drift when the schema cohort changes. + The record key is part of the contract. Rust and C# must compute the same key for the same geometry record, so stable fingerprints use the Rust canonical field order and exact IEEE-754 component bits. If this drifts, the same chunk becomes two From b9f20a640ea426f4aac282f8930a2efdb9e855a6 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 04:14:10 +0100 Subject: [PATCH 036/283] Update Geometry repository scope --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d6e3778c..80dc90a5 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,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.Geometry`: geometry, planetary mapping, CSG, LOD selection, mesh assembly, and CultCache-native geometry documents built on CultMath primitives - `GameCult.Networking`: encrypted login/register/verify flows, schema-v0 contracts, transport adapters, and native RUDP sessions - `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 From 37e70a346c2c90fb0155027d4213a124f9df83de Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 04:16:16 +0100 Subject: [PATCH 037/283] Record consumer cutover and authority audit --- ...th-gamecult-geometry-migration-progress.md | 63 ++++++++++++++++--- 1 file changed, 54 insertions(+), 9 deletions(-) diff --git a/docs/cultmath-gamecult-geometry-migration-progress.md b/docs/cultmath-gamecult-geometry-migration-progress.md index 79dce55e..74a473c5 100644 --- a/docs/cultmath-gamecult-geometry-migration-progress.md +++ b/docs/cultmath-gamecult-geometry-migration-progress.md @@ -4,7 +4,8 @@ Plan: `docs/cultmath-gamecult-geometry-migration-plan.md` (locked) Started: 2026-07-22 -Status: Stages 0-5 complete; Stage 6 in progress +Status: Stages 0-5 complete; Stage 6 consumer cutover implemented with two +external verification/publication gates; Stage 7 source-authority cut complete ## Objective @@ -60,8 +61,8 @@ Demotions: | 3. Planetary transfer | Complete | Managed, HLSL, CMPT, Unity, web, tool, docs, tests, and package authority moved; CultMath owners deleted | | 4. Mine `vg-csg` | Complete | Geometry-owned Rust kernel passes correctness, parity, performance, formatting, and warning-denied lint gates | | 5. CultCache/CultNet/CultMesh integration | Complete | One provider commit path persists, watches, replicates, and probes typed geometry state | -| 6. Consumer cutover/release | In progress | Fensalir/Aetheria exact cutover surfaces mapped; consumer edits and release receipts remain | -| 7. Delete obsolete authorities/audit | Pending | Requires every prior stage gate | +| 6. Consumer cutover/release | Gate pending | Fensalir green; Aetheria source cut pushed but full build/Unity regeneration await external dependency/editor state and immutable UPM tag | +| 7. Delete obsolete authorities/audit | Complete | VibeGeometry workspace authority archived; tracked negative audit is clean apart from retained provenance/witnesses | ## Verification Receipts @@ -265,11 +266,55 @@ a broader stage gate. protocol. Existing C#/Rust exact v2 document bytes and record keys remain the cross-runtime geometry witness. +### Stage 6 receipts + +- Coordinated local candidates use + `scripts/build-geometry-candidate.ps1`. CultMath `.2` is primitives-only; + Geometry `.2` contains its managed assembly, notices/docs, and all five owned + shaders with exact support-package and CultMath candidate dependencies. A + clean net10 consumer restored and built; the Unity package staged one owned + assembly plus adapters, sample, and shaders. The Rust crate passed an + independent `cargo package --allow-dirty --no-verify` dry run. +- Fensalir cutover commit `42778c1` adds direct Geometry dependencies, migrates + planetary C# consumers, compiler include roots, shaders, and parity harnesses + while retaining CultMath for numeric primitives. The solution builds with no + warnings/errors; fractal tests pass 170/170, erosion parity 1/1, topology + parity 19/19, and planetary page tests 16/16. +- Aetheria cutover commits `26948f81` and `557bc71f` replace `CultVec*` fixtures + with CultMath vectors under an exact legacy MessagePack byte witness, move + spatial rectangles to `GameCult.Geometry.CultRect`, add the real .NET/Unity + Geometry dependencies, and remove stale ownership guidance. +- Aetheria's geometry compiler errors are gone. Its full build is presently + blocked by concurrent CultMesh API drift (`CultMeshBody*` and persisted-record + types), outside this migration. Unity regeneration is also deferred while an + active Unity editor owns the project. The coordinated local file dependency + must become an immutable Geometry Unity tag before publication. +- Legacy D3DCompiler exposed that macro-expanded HLSL includes were not + portable. CultLib commit `cdeea474` gives the Geometry umbrella direct default + and Unity include branches; Geometry shader ownership tests pass 3/3 and the + downstream D3D12 corpus passes. + +### Stage 7 receipts + +- Tracked negative audits across CultLib, CultMath, Fensalir, Aetheria, and + VibeGeometry find no live `CultVec*`, `CultMath.rect`, CultMath planetary + implementation, old planetary shader vocabulary, geometry v1 writer, or + VibeGeometry/`vg-csg` build dependency. Frozen fixtures, source attribution, + and negative ownership tests remain deliberately. +- VibeGeometry commit `bc9604a` removes its tracked Cargo workspace, lockfile, + submodule declaration/gitlink, scratch/build wiring, and live mission claims. + Its remaining documents point to source witness `8f070f4f` and Geometry + absorption commit `6b44f969`; repository history preserves provenance. +- CultLib commits `8a7eee71` and `b9f20a64` remove manual-registry guidance and + update the root package map. Generated CultDocument metadata remains the only + registration owner. + ## Next Actions -1. Cut Fensalir's C# and HLSL planetary surfaces atomically to - GameCult.Geometry, including shader resolver and parity harnesses. -2. Replace Aetheria Freeze's remaining `CultVec*` fixtures with CultMath values - under an exact serialization witness, then regenerate Unity project files. -3. Rebuild coordinated CultMath and Geometry candidates and run the named - downstream parity corpus before publication. +1. Resolve Aetheria's concurrent CultMesh API/worktree drift, then rerun its + State/Freeze verifier and daemon smoke against this migration branch. +2. Close the active Unity editor/import workers, regenerate Aetheria Unity + project/lock files through Unity, and run the canonical EditMode suite. +3. Publish an immutable `org.gamecult.geometry` Unity package tag in the + coordinated release window, replace Aetheria's local candidate reference, + and repeat package/version inspection before declaring Stage 6 complete. From 77fe95c7b9cc9e295a1cc081d25594d9ff8cb46a Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 04:25:04 +0100 Subject: [PATCH 038/283] Make Geometry Git UPM package self-contained --- scripts/build-geometry-unity-package.ps1 | 67 ++- unity/org.gamecult.geometry/LICENSES.md | 13 + unity/org.gamecult.geometry/Runtime.meta | 8 + .../GameCult.Geometry.Unity.asmdef.meta | 7 + .../Runtime/GameCult.Geometry.asmdef.meta | 7 + .../Runtime/Plugins.meta | 8 + .../Runtime/Plugins/GameCult.Geometry.dll | Bin 0 -> 144384 bytes .../Plugins/GameCult.Geometry.dll.meta | 21 + .../Runtime/Plugins/GameCult.Geometry.pdb | Bin 0 -> 62124 bytes .../Plugins/GameCult.Geometry.pdb.meta | 7 + unity/org.gamecult.geometry/Samples~.meta | 8 + .../Samples~/PlanetaryViewer.meta | 8 + .../Samples~/PlanetaryViewer/Editor.meta | 8 + ...eometry.PlanetaryViewer.Editor.asmdef.meta | 7 + ...ameCultGeometryPlanetaryViewerMenu.cs.meta | 11 + .../Samples~/PlanetaryViewer/Runtime.meta | 8 + ...eCult.Geometry.PlanetaryViewer.asmdef.meta | 7 + .../GameCultGeometryPlanetaryViewer.cs.meta | 11 + ...ameCultGeometryPlanetaryViewer.shader.meta | 9 + unity/org.gamecult.geometry/Shaders.meta | 8 + .../Shaders/AdvancedErosionFilter.hlsl | 147 +++++++ .../Shaders/AdvancedErosionFilter.hlsl.meta | 7 + .../Shaders/GameCult.Geometry.hlsl | 14 + .../Shaders/GameCult.Geometry.hlsl.meta | 7 + .../Shaders/Planetary.hlsl | 392 ++++++++++++++++++ .../Shaders/Planetary.hlsl.meta | 7 + .../Shaders/PlanetaryRadialRefinement.hlsl | 27 ++ .../PlanetaryRadialRefinement.hlsl.meta | 7 + .../Shaders/SphericalErosion.hlsl | 80 ++++ .../Shaders/SphericalErosion.hlsl.meta | 7 + .../THIRD-PARTY-NOTICES.md | 24 ++ 31 files changed, 922 insertions(+), 20 deletions(-) create mode 100644 unity/org.gamecult.geometry/LICENSES.md create mode 100644 unity/org.gamecult.geometry/Runtime.meta create mode 100644 unity/org.gamecult.geometry/Runtime/GameCult.Geometry.Unity.asmdef.meta create mode 100644 unity/org.gamecult.geometry/Runtime/GameCult.Geometry.asmdef.meta create mode 100644 unity/org.gamecult.geometry/Runtime/Plugins.meta create mode 100644 unity/org.gamecult.geometry/Runtime/Plugins/GameCult.Geometry.dll create mode 100644 unity/org.gamecult.geometry/Runtime/Plugins/GameCult.Geometry.dll.meta create mode 100644 unity/org.gamecult.geometry/Runtime/Plugins/GameCult.Geometry.pdb create mode 100644 unity/org.gamecult.geometry/Runtime/Plugins/GameCult.Geometry.pdb.meta create mode 100644 unity/org.gamecult.geometry/Samples~.meta create mode 100644 unity/org.gamecult.geometry/Samples~/PlanetaryViewer.meta create mode 100644 unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Editor.meta create mode 100644 unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Editor/GameCult.Geometry.PlanetaryViewer.Editor.asmdef.meta create mode 100644 unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Editor/GameCultGeometryPlanetaryViewerMenu.cs.meta create mode 100644 unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Runtime.meta create mode 100644 unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Runtime/GameCult.Geometry.PlanetaryViewer.asmdef.meta create mode 100644 unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Runtime/GameCultGeometryPlanetaryViewer.cs.meta create mode 100644 unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Runtime/GameCultGeometryPlanetaryViewer.shader.meta create mode 100644 unity/org.gamecult.geometry/Shaders.meta create mode 100644 unity/org.gamecult.geometry/Shaders/AdvancedErosionFilter.hlsl create mode 100644 unity/org.gamecult.geometry/Shaders/AdvancedErosionFilter.hlsl.meta create mode 100644 unity/org.gamecult.geometry/Shaders/GameCult.Geometry.hlsl create mode 100644 unity/org.gamecult.geometry/Shaders/GameCult.Geometry.hlsl.meta create mode 100644 unity/org.gamecult.geometry/Shaders/Planetary.hlsl create mode 100644 unity/org.gamecult.geometry/Shaders/Planetary.hlsl.meta create mode 100644 unity/org.gamecult.geometry/Shaders/PlanetaryRadialRefinement.hlsl create mode 100644 unity/org.gamecult.geometry/Shaders/PlanetaryRadialRefinement.hlsl.meta create mode 100644 unity/org.gamecult.geometry/Shaders/SphericalErosion.hlsl create mode 100644 unity/org.gamecult.geometry/Shaders/SphericalErosion.hlsl.meta create mode 100644 unity/org.gamecult.geometry/THIRD-PARTY-NOTICES.md diff --git a/scripts/build-geometry-unity-package.ps1 b/scripts/build-geometry-unity-package.ps1 index 8c1b8b1f..a16370eb 100644 --- a/scripts/build-geometry-unity-package.ps1 +++ b/scripts/build-geometry-unity-package.ps1 @@ -21,6 +21,7 @@ $candidateFeed = if ([System.IO.Path]::IsPathRooted($CultMathCandidateFeed)) { Join-Path $repoRoot $CultMathCandidateFeed } $pluginRoot = Join-Path $outputRoot "Runtime\Plugins" +$templatePluginRoot = Join-Path $templateRoot "Runtime\Plugins" if (-not (Test-Path -LiteralPath (Join-Path $candidateFeed "CultMath.0.1.0-geometry-migration.2.nupkg"))) { throw "CultMath migration candidate is missing from $candidateFeed. Pack CultMath before staging Geometry." @@ -43,33 +44,59 @@ if ($LASTEXITCODE -ne 0) { throw "GameCult.Geometry publish failed with exit code $LASTEXITCODE" } -New-Item -ItemType Directory -Force -Path $pluginRoot | Out-Null -Copy-Item -LiteralPath (Join-Path $templateRoot "package.json") -Destination $outputRoot -Copy-Item -LiteralPath (Join-Path $templateRoot "README.md") -Destination $outputRoot -Copy-Item -LiteralPath (Join-Path $templateRoot "Runtime\GameCult.Geometry.asmdef") -Destination (Join-Path $outputRoot "Runtime") -Copy-Item -LiteralPath (Join-Path $templateRoot "Runtime\GameCult.Geometry.Unity.asmdef") -Destination (Join-Path $outputRoot "Runtime") -Copy-Item -LiteralPath (Join-Path $templateRoot "Runtime\PlanetaryPatchMeshAdapter.cs") -Destination (Join-Path $outputRoot "Runtime") -Copy-Item -LiteralPath (Join-Path $templateRoot "Runtime\PlanetaryPatchMeshAdapter.cs.meta") -Destination (Join-Path $outputRoot "Runtime") -Copy-Item -LiteralPath (Join-Path $templateRoot "Runtime\PlanetaryPageUpload.cs") -Destination (Join-Path $outputRoot "Runtime") -Copy-Item -LiteralPath (Join-Path $templateRoot "Runtime\PlanetaryPageUpload.cs.meta") -Destination (Join-Path $outputRoot "Runtime") -Copy-Item -LiteralPath (Join-Path $templateRoot "Samples~") -Destination $outputRoot -Recurse -$shaderOutputRoot = Join-Path $outputRoot "Shaders" -New-Item -ItemType Directory -Force -Path $shaderOutputRoot | Out-Null -Copy-Item -Path (Join-Path $repoRoot "src\GameCult.Geometry\Shaders\*.hlsl") -Destination $shaderOutputRoot -Copy-Item -Path (Join-Path $repoRoot "src\GameCult.Geometry\Shaders\*.hlsl.meta") -Destination $shaderOutputRoot -ErrorAction SilentlyContinue -Copy-Item -LiteralPath (Join-Path $repoRoot "src\GameCult.Geometry\LICENSES.md") -Destination $outputRoot -Copy-Item -LiteralPath (Join-Path $repoRoot "src\GameCult.Geometry\THIRD-PARTY-NOTICES.md") -Destination $outputRoot - $geometryAssembly = Join-Path $publishRoot "GameCult.Geometry.dll" if (-not (Test-Path -LiteralPath $geometryAssembly)) { throw "Geometry Unity package is missing GameCult.Geometry.dll" } -Copy-Item -LiteralPath $geometryAssembly -Destination $pluginRoot $geometrySymbols = [System.IO.Path]::ChangeExtension($geometryAssembly, ".pdb") -if (Test-Path -LiteralPath $geometrySymbols) { - Copy-Item -LiteralPath $geometrySymbols -Destination $pluginRoot + +$requiredTemplateFiles = @( + "LICENSES.md", + "THIRD-PARTY-NOTICES.md", + "Runtime\Plugins\GameCult.Geometry.dll", + "Runtime\Plugins\GameCult.Geometry.dll.meta", + "Runtime\Plugins\GameCult.Geometry.pdb", + "Runtime\Plugins\GameCult.Geometry.pdb.meta", + "Shaders\AdvancedErosionFilter.hlsl", + "Shaders\GameCult.Geometry.hlsl", + "Shaders\Planetary.hlsl", + "Shaders\PlanetaryRadialRefinement.hlsl", + "Shaders\SphericalErosion.hlsl" +) +foreach ($relativePath in $requiredTemplateFiles) { + if (-not (Test-Path -LiteralPath (Join-Path $templateRoot $relativePath))) { + throw "Tracked Geometry Unity package is incomplete: missing $relativePath" + } } +$unityAssetFiles = @(Get-ChildItem -LiteralPath $templateRoot -Recurse -File | Where-Object { + $_.Extension -in @(".asmdef", ".cs", ".dll", ".pdb", ".shader", ".hlsl") +}) +$missingAssetMetas = @($unityAssetFiles | Where-Object { -not (Test-Path -LiteralPath ($_.FullName + ".meta")) }) +$missingDirectoryMetas = @(Get-ChildItem -LiteralPath $templateRoot -Recurse -Directory | Where-Object { + -not (Test-Path -LiteralPath ($_.FullName + ".meta")) +}) +if ($missingAssetMetas.Count -ne 0 -or $missingDirectoryMetas.Count -ne 0) { + $missing = @($missingAssetMetas.FullName) + @($missingDirectoryMetas.FullName) + throw "Tracked Geometry Unity package has assets without stable .meta files: $($missing -join ', ')" +} + +$trackedAssembly = Join-Path $templatePluginRoot "GameCult.Geometry.dll" +if ((Get-FileHash -Algorithm SHA256 -LiteralPath $trackedAssembly).Hash -ne + (Get-FileHash -Algorithm SHA256 -LiteralPath $geometryAssembly).Hash) { + throw "Tracked GameCult.Geometry.dll does not match the current Release publish output. Sync the tracked Git-UPM package before tagging." +} +if (Test-Path -LiteralPath $geometrySymbols) { + $trackedSymbols = Join-Path $templatePluginRoot "GameCult.Geometry.pdb" + if ((Get-FileHash -Algorithm SHA256 -LiteralPath $trackedSymbols).Hash -ne + (Get-FileHash -Algorithm SHA256 -LiteralPath $geometrySymbols).Hash) { + throw "Tracked GameCult.Geometry.pdb does not match the current Release publish output. Sync the tracked Git-UPM package before tagging." + } +} + +New-Item -ItemType Directory -Force -Path $outputRoot | Out-Null +Copy-Item -Path (Join-Path $templateRoot "*") -Destination $outputRoot -Recurse -Force + $manifest = Get-Content -LiteralPath (Join-Path $outputRoot "package.json") -Raw | ConvertFrom-Json $stagedAssemblies = @(Get-ChildItem -LiteralPath $pluginRoot -Filter "*.dll") if ($stagedAssemblies.Count -ne 1 -or $stagedAssemblies[0].Name -ne "GameCult.Geometry.dll") { diff --git a/unity/org.gamecult.geometry/LICENSES.md b/unity/org.gamecult.geometry/LICENSES.md new file mode 100644 index 00000000..67455b87 --- /dev/null +++ b/unity/org.gamecult.geometry/LICENSES.md @@ -0,0 +1,13 @@ +# GameCult.Geometry licenses + +GameCult.Geometry is a mixed-license package. License follows file ownership; +the package as a whole is not relicensed under one blanket expression. + +- CultLib-authored integration, persistence, schema, and packaging files are + licensed under the MIT License published by the CultLib repository. +- Files under `Planetary/` and `Shaders/` transferred from CultMath remain + licensed under the Mozilla Public License 2.0. Their source notices and + provenance are preserved in `THIRD-PARTY-NOTICES.md`. + +Downstream redistributors must preserve the applicable notices for the files +they redistribute. diff --git a/unity/org.gamecult.geometry/Runtime.meta b/unity/org.gamecult.geometry/Runtime.meta new file mode 100644 index 00000000..0f218627 --- /dev/null +++ b/unity/org.gamecult.geometry/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d888f08710df48a780e393bc7b6ce1f5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/unity/org.gamecult.geometry/Runtime/GameCult.Geometry.Unity.asmdef.meta b/unity/org.gamecult.geometry/Runtime/GameCult.Geometry.Unity.asmdef.meta new file mode 100644 index 00000000..deaa0678 --- /dev/null +++ b/unity/org.gamecult.geometry/Runtime/GameCult.Geometry.Unity.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 5a5dc5d9ba8d4aea93b53061d6376f7f +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/unity/org.gamecult.geometry/Runtime/GameCult.Geometry.asmdef.meta b/unity/org.gamecult.geometry/Runtime/GameCult.Geometry.asmdef.meta new file mode 100644 index 00000000..ab0835ee --- /dev/null +++ b/unity/org.gamecult.geometry/Runtime/GameCult.Geometry.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a4dee1a0c3f04709994b8cc1f974da7a +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/unity/org.gamecult.geometry/Runtime/Plugins.meta b/unity/org.gamecult.geometry/Runtime/Plugins.meta new file mode 100644 index 00000000..98acd60d --- /dev/null +++ b/unity/org.gamecult.geometry/Runtime/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7f8484deafdf444abe3b1dedb9d09d16 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/unity/org.gamecult.geometry/Runtime/Plugins/GameCult.Geometry.dll b/unity/org.gamecult.geometry/Runtime/Plugins/GameCult.Geometry.dll new file mode 100644 index 0000000000000000000000000000000000000000..5664e0edb164066c3f8b315e4a7c32f42c1380d4 GIT binary patch literal 144384 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

?*xxt>HT$a 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

Ry5r?Z8Mf&oM(n^c31E7C!7ztGU0Go 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 omitted+=amplitude; else if(index==active-1) omitted+=amplitude*(1.0-final_weight); amplitude*=abs(gain); + } + GameCultGeometryErosionBandSelection result; result.active_octaves=active; result.final_octave_weight=active>0?final_weight:0.0; result.finest_included_wavelength=finest; result.unresolved_height_bound=omitted; return result; +} + +float gamecult_geometry_erosion_hash_unit(int2 cell, uint salt) +{ + uint value = (uint)cell.x * 0x8da6b343u ^ (uint)cell.y * 0xd8163841u ^ salt; + value ^= value >> 16; value *= 0x7feb352du; value ^= value >> 15; value *= 0x846ca68bu; value ^= value >> 16; + return (value & 0x00ffffffu) * (1.0 / 16777216.0); +} +float2 gamecult_geometry_erosion_hash2(float2 input) +{ + int2 cell = (int2)input; + return float2(gamecult_geometry_erosion_hash_unit(cell, 0x68bc21ebu), gamecult_geometry_erosion_hash_unit(cell, 0x02e5be93u)) * 2.0 - 1.0; +} + +float4 gamecult_geometry_phacelle_noise(float2 position, float2 normal_direction, float frequency, float offset_cycles, float normalization) +{ + float2 side_direction = float2(-normal_direction.y, normal_direction.x) * frequency * 6.28318530718; + float offset = offset_cycles * 6.28318530718; + float2 cell = floor(position); + float2 local = frac(position); + float2 phase = 0.0; + float weight_sum = 0.0; + [unroll] for (int x = -1; x <= 2; x++) + [unroll] for (int y = -1; y <= 2; y++) + { + float2 grid_offset = float2(x, y); + float2 grid_point = cell + grid_offset; + float2 random_offset = gamecult_geometry_erosion_hash2(grid_point) * 0.5; + float2 delta = local - grid_offset - random_offset; + float weight = max(0.0, exp(-dot(delta, delta) * 2.0) - 0.01111); + weight_sum += weight; + float wave = dot(delta, side_direction) + offset; + phase += float2(cos(wave), sin(wave)) * weight; + } + float2 interpolated = phase / max(weight_sum, 1.0e-20); + float magnitude = max(1.0 - saturate(normalization), length(interpolated)); + return float4(interpolated / max(magnitude, 1.0e-20), side_direction); +} + +float gamecult_geometry_erosion_pow_inverse(float value, float power) { return 1.0 - pow(1.0 - saturate(value), power); } +float gamecult_geometry_erosion_ease_out(float value) { float inverse = 1.0 - saturate(value); return 1.0 - inverse * inverse; } +float gamecult_geometry_erosion_smooth_start(float value, float smoothing) +{ + return smoothing <= 1.0e-10 || value >= smoothing ? value - 0.5 * smoothing : 0.5 * value * value / smoothing; +} +float2 gamecult_geometry_erosion_safe_normalize(float2 value) +{ + float value_length = length(value); + return abs(value_length) > 1.0e-10 ? value / value_length : value; +} + +GameCultGeometryAdvancedErosionResult gamecult_geometry_advanced_erosion_filter_banded(float2 position, float3 base_height_and_slope, float fade_target, GameCultGeometryAdvancedErosionParameters p, GameCultGeometryErosionBandSelection band) +{ + float strength = p.strength * p.scale; + fade_target = clamp(fade_target, -1.0, 1.0); + float3 input_value = base_height_and_slope; + float3 height_and_slope = input_value; + float frequency = 1.0 / max(p.scale * p.cell_scale, 1.0e-10); + float2 slope = height_and_slope.yz; + float slope_length = max(length(slope), 1.0e-10); + float magnitude = 0.0; + float rounding_multiplier = 1.0; + float input_rounding = lerp(p.rounding.y, p.rounding.x, saturate(fade_target + 0.5)) * p.rounding.z; + float combined_mask = gamecult_geometry_erosion_ease_out(gamecult_geometry_erosion_smooth_start(slope_length * p.onset.x, input_rounding * p.onset.x)); + float ridge_mask = gamecult_geometry_erosion_ease_out(slope_length * p.onset.z); + float ridge_fade = fade_target; + float2 gully_slope = lerp(slope, slope / slope_length * p.assumed_slope.x, p.assumed_slope.y); + + int octave_count=min(min(max(p.octaves,0),8),max(band.active_octaves,0)); + [loop] for (int octave = 0; octave < octave_count; octave++) + { + float4 phacelle = gamecult_geometry_phacelle_noise(position * frequency, gamecult_geometry_erosion_safe_normalize(gully_slope), p.cell_scale, 0.25, p.normalization); + float2 derivative_direction = phacelle.zw * -frequency; + float sloping = abs(phacelle.y); + gully_slope += sign(phacelle.y) * derivative_direction * strength * p.gully_weight; + float3 gullies = float3(phacelle.x, phacelle.y * derivative_direction.x, phacelle.y * derivative_direction.y); + float3 faded = lerp(float3(fade_target, 0.0, 0.0), gullies * p.gully_weight, combined_mask); + float octave_weight=octave==octave_count-1?saturate(band.final_octave_weight):1.0; + height_and_slope += faded * strength * octave_weight; + magnitude += strength * octave_weight; + fade_target = faded.x; + float octave_rounding = lerp(p.rounding.y, p.rounding.x, saturate(phacelle.x + 0.5)) * rounding_multiplier; + float new_mask = gamecult_geometry_erosion_ease_out(gamecult_geometry_erosion_smooth_start(sloping * p.onset.y, octave_rounding * p.onset.y)); + combined_mask = gamecult_geometry_erosion_pow_inverse(combined_mask, p.detail) * new_mask; + ridge_fade = lerp(ridge_fade, lerp(ridge_fade, gullies.x, ridge_mask), octave_weight); + ridge_mask *= lerp(1.0, gamecult_geometry_erosion_ease_out(sloping * p.onset.w), octave_weight); + strength *= p.gain; + frequency *= p.lacunarity; + rounding_multiplier *= p.rounding.w; + } + + GameCultGeometryAdvancedErosionResult result; + result.delta = height_and_slope - input_value; + result.magnitude = magnitude; + result.ridge_map = ridge_fade * (1.0 - ridge_mask); + result.fade_target = fade_target; + return result; +} + +GameCultGeometryAdvancedErosionResult gamecult_geometry_advanced_erosion_filter(float2 position, float3 base_height_and_slope, float fade_target, GameCultGeometryAdvancedErosionParameters p) +{ + GameCultGeometryErosionBandSelection band; band.active_octaves=p.octaves; band.final_octave_weight=1.0; band.finest_included_wavelength=0.0; band.unresolved_height_bound=0.0; + return gamecult_geometry_advanced_erosion_filter_banded(position, base_height_and_slope, fade_target, p, band); +} + +#endif diff --git a/unity/org.gamecult.geometry/Shaders/AdvancedErosionFilter.hlsl.meta b/unity/org.gamecult.geometry/Shaders/AdvancedErosionFilter.hlsl.meta new file mode 100644 index 00000000..015c51c2 --- /dev/null +++ b/unity/org.gamecult.geometry/Shaders/AdvancedErosionFilter.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3252ac02e8853ef4b9d1fbc5204b5c6b +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/unity/org.gamecult.geometry/Shaders/GameCult.Geometry.hlsl b/unity/org.gamecult.geometry/Shaders/GameCult.Geometry.hlsl new file mode 100644 index 00000000..00623b75 --- /dev/null +++ b/unity/org.gamecult.geometry/Shaders/GameCult.Geometry.hlsl @@ -0,0 +1,14 @@ +#ifndef GAMECULT_GEOMETRY_HLSL +#define GAMECULT_GEOMETRY_HLSL + +#if defined(GAMECULT_GEOMETRY_UNITY_PACKAGE) +#include "Packages/org.gamecult.cultmath/shaders/CultMath.hlsl" +#else +#include "CultMath/CultMath.hlsl" +#endif +#include "AdvancedErosionFilter.hlsl" +#include "Planetary.hlsl" +#include "SphericalErosion.hlsl" +#include "PlanetaryRadialRefinement.hlsl" + +#endif diff --git a/unity/org.gamecult.geometry/Shaders/GameCult.Geometry.hlsl.meta b/unity/org.gamecult.geometry/Shaders/GameCult.Geometry.hlsl.meta new file mode 100644 index 00000000..d685ccce --- /dev/null +++ b/unity/org.gamecult.geometry/Shaders/GameCult.Geometry.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b253fa50ddd34bf3b69fb323fe6e00e8 +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/unity/org.gamecult.geometry/Shaders/Planetary.hlsl b/unity/org.gamecult.geometry/Shaders/Planetary.hlsl new file mode 100644 index 00000000..8e16bfff --- /dev/null +++ b/unity/org.gamecult.geometry/Shaders/Planetary.hlsl @@ -0,0 +1,392 @@ +#ifndef GAMECULT_GEOMETRY_PLANETARY_HLSL +#define GAMECULT_GEOMETRY_PLANETARY_HLSL + +static const float GAMECULT_GEOMETRY_PLANETARY_QUARTER_PI = 0.78539816339744830962; + +float3 gamecult_geometry_planetary_face_direction(int face, float2 coordinate) +{ + float2 tangent = tan(coordinate * GAMECULT_GEOMETRY_PLANETARY_QUARTER_PI); + float3 cube = face == 0 ? float3(1.0, tangent.y, -tangent.x) + : face == 1 ? float3(-1.0, tangent.y, tangent.x) + : face == 2 ? float3(tangent.x, 1.0, -tangent.y) + : face == 3 ? float3(tangent.x, -1.0, tangent.y) + : face == 4 ? float3(tangent.x, tangent.y, 1.0) + : float3(-tangent.x, tangent.y, -1.0); + return cultmath_normalize(cube); +} + +float2 gamecult_geometry_planetary_face_coordinate(float3 direction, out int face) +{ + float3 d = cultmath_normalize(direction); + float3 a = abs(d); + float2 cube_uv; + if (a.x >= a.y && a.x >= a.z) + { + if (d.x >= 0.0) { face = 0; cube_uv = float2(-d.z, d.y) / a.x; } + else { face = 1; cube_uv = float2(d.z, d.y) / a.x; } + } + else if (a.y >= a.z) + { + if (d.y >= 0.0) { face = 2; cube_uv = float2(d.x, -d.z) / a.y; } + else { face = 3; cube_uv = float2(d.x, d.z) / a.y; } + } + else + { + if (d.z >= 0.0) { face = 4; cube_uv = d.xy / a.z; } + else { face = 5; cube_uv = float2(-d.x, d.y) / a.z; } + } + return atan(cube_uv) / GAMECULT_GEOMETRY_PLANETARY_QUARTER_PI; +} + +bool gamecult_geometry_planetary_page_local(float3 direction, float4 tile_address, float active, out float2 local) +{ + int face; + float2 uv = gamecult_geometry_planetary_face_coordinate(direction, face); + local = 0.0; + if (active < 0.5 || abs((float)face - tile_address.x) > 0.25) return false; + float axis_tiles = exp2(tile_address.y); + float2 scaled = (uv * 0.5 + 0.5) * axis_tiles; + float2 canonical = floor(min(scaled, axis_tiles - 1.0e-5)); + if (any(abs(canonical - tile_address.zw) > 0.25)) return false; + local = scaled - tile_address.zw; + return all(local >= 0.0) && all(local <= 1.0); +} + +float3 gamecult_geometry_planetary_surface_normal(float3 direction, float3 world_distance_tangent_gradient) +{ + direction = cultmath_normalize(direction); + float3 tangent_gradient = world_distance_tangent_gradient - direction * dot(world_distance_tangent_gradient, direction); + return cultmath_normalize(direction - tangent_gradient); +} + +float2 gamecult_geometry_planetary_equirectangular_forward(float3 direction) +{ + direction = cultmath_normalize(direction); + return float2(atan2(direction.y, direction.x) / CULTMATH_PI, asin(clamp(direction.z, -1.0, 1.0)) / CULTMATH_HALF_PI); +} + +float3 gamecult_geometry_planetary_equirectangular_inverse(float2 coordinate) +{ + float longitude = coordinate.x * CULTMATH_PI; + float latitude = coordinate.y * CULTMATH_HALF_PI; + float cos_latitude = cos(latitude); + return cultmath_normalize(float3(cos_latitude * cos(longitude), cos_latitude * sin(longitude), sin(latitude))); +} + +static const float GAMECULT_GEOMETRY_EQUAL_EARTH_A1 = 1.340264; +static const float GAMECULT_GEOMETRY_EQUAL_EARTH_A2 = -0.081106; +static const float GAMECULT_GEOMETRY_EQUAL_EARTH_A3 = 0.000893; +static const float GAMECULT_GEOMETRY_EQUAL_EARTH_A4 = 0.003796; +static const float GAMECULT_GEOMETRY_EQUAL_EARTH_M = 0.8660254037844386; +static const float GAMECULT_GEOMETRY_EQUAL_EARTH_X_MAX = 2.706629; +static const float GAMECULT_GEOMETRY_EQUAL_EARTH_Y_MAX = 1.3173628; + +float gamecult_geometry_equal_earth_y(float theta) +{ + float theta2 = theta * theta; + float theta6 = theta2 * theta2 * theta2; + return theta * (GAMECULT_GEOMETRY_EQUAL_EARTH_A1 + GAMECULT_GEOMETRY_EQUAL_EARTH_A2 * theta2 + theta6 * (GAMECULT_GEOMETRY_EQUAL_EARTH_A3 + GAMECULT_GEOMETRY_EQUAL_EARTH_A4 * theta2)); +} + +float2 gamecult_geometry_planetary_equal_earth_forward(float3 direction) +{ + direction = cultmath_normalize(direction); + float longitude = atan2(direction.y, direction.x); + float latitude = asin(clamp(direction.z, -1.0, 1.0)); + float theta = asin(GAMECULT_GEOMETRY_EQUAL_EARTH_M * sin(latitude)); + float theta2 = theta * theta; + float theta6 = theta2 * theta2 * theta2; + float denominator = GAMECULT_GEOMETRY_EQUAL_EARTH_M * (GAMECULT_GEOMETRY_EQUAL_EARTH_A1 + 3.0 * GAMECULT_GEOMETRY_EQUAL_EARTH_A2 * theta2 + theta6 * (7.0 * GAMECULT_GEOMETRY_EQUAL_EARTH_A3 + 9.0 * GAMECULT_GEOMETRY_EQUAL_EARTH_A4 * theta2)); + return float2(longitude * cos(theta) / denominator / GAMECULT_GEOMETRY_EQUAL_EARTH_X_MAX, gamecult_geometry_equal_earth_y(theta) / GAMECULT_GEOMETRY_EQUAL_EARTH_Y_MAX); +} + +float3 gamecult_geometry_planetary_equal_earth_inverse(float2 coordinate) +{ + float target_y = coordinate.y * GAMECULT_GEOMETRY_EQUAL_EARTH_Y_MAX; + float theta = target_y / GAMECULT_GEOMETRY_EQUAL_EARTH_A1; + [unroll] for (int iteration = 0; iteration < 8; iteration++) + { + float theta2 = theta * theta; + float theta6 = theta2 * theta2 * theta2; + float derivative = GAMECULT_GEOMETRY_EQUAL_EARTH_A1 + 3.0 * GAMECULT_GEOMETRY_EQUAL_EARTH_A2 * theta2 + theta6 * (7.0 * GAMECULT_GEOMETRY_EQUAL_EARTH_A3 + 9.0 * GAMECULT_GEOMETRY_EQUAL_EARTH_A4 * theta2); + theta -= (gamecult_geometry_equal_earth_y(theta) - target_y) / derivative; + } + float latitude = asin(clamp(sin(theta) / GAMECULT_GEOMETRY_EQUAL_EARTH_M, -1.0, 1.0)); + float theta2 = theta * theta; + float theta6 = theta2 * theta2 * theta2; + float denominator = GAMECULT_GEOMETRY_EQUAL_EARTH_M * (GAMECULT_GEOMETRY_EQUAL_EARTH_A1 + 3.0 * GAMECULT_GEOMETRY_EQUAL_EARTH_A2 * theta2 + theta6 * (7.0 * GAMECULT_GEOMETRY_EQUAL_EARTH_A3 + 9.0 * GAMECULT_GEOMETRY_EQUAL_EARTH_A4 * theta2)); + float longitude = coordinate.x * GAMECULT_GEOMETRY_EQUAL_EARTH_X_MAX * denominator / cos(theta); + float cos_latitude = cos(latitude); + return cultmath_normalize(float3(cos_latitude * cos(longitude), cos_latitude * sin(longitude), sin(latitude))); +} + +float gamecult_geometry_planetary_wrap_longitude(float longitude) +{ + longitude = fmod(longitude, CULTMATH_TAU); + if (longitude > CULTMATH_PI) longitude -= CULTMATH_TAU; + if (longitude < -CULTMATH_PI) longitude += CULTMATH_TAU; + return longitude; +} + +float3 gamecult_geometry_planetary_lon_lat_direction(float longitude, float latitude) +{ + float cos_latitude = cos(latitude); + return cultmath_normalize(float3(cos_latitude * cos(longitude), cos_latitude * sin(longitude), sin(latitude))); +} + +float gamecult_geometry_planetary_asinh(float value) { return log(value + sqrt(value * value + 1.0)); } +float gamecult_geometry_planetary_sinh(float value) { return 0.5 * (exp(value) - exp(-value)); } + +bool gamecult_geometry_planetary_azimuthal_forward(float3 direction, float2 center_lon_lat, int kind, out float2 coordinate) +{ + direction = cultmath_normalize(direction); + float longitude = gamecult_geometry_planetary_wrap_longitude(atan2(direction.y, direction.x) - center_lon_lat.x); + float latitude = asin(clamp(direction.z, -1.0, 1.0)); + float sin0 = sin(center_lon_lat.y), cos0 = cos(center_lon_lat.y); + float sin_latitude = sin(latitude), cos_latitude = cos(latitude), cos_longitude = cos(longitude); + float cos_c = clamp(sin0 * sin_latitude + cos0 * cos_latitude * cos_longitude, -1.0, 1.0); + float2 raw = float2(cos_latitude * sin(longitude), cos0 * sin_latitude - sin0 * cos_latitude * cos_longitude); + float factor = 1.0; + if (kind == 3) + { + if (cos_c < 0.0) { coordinate = 0.0; return false; } + } + else if (kind == 4) + { + float c = acos(cos_c); factor = (c < 1.0e-6 ? 1.0 : c / sin(c)) / CULTMATH_PI; + } + else if (kind == 5) factor = sqrt(2.0 / max(1.0 + cos_c, 1.0e-20)) * 0.5; + else + { + if (cos_c <= 0.0) { coordinate = 0.0; return false; } + factor = 1.0 / cos_c; + } + coordinate = raw * factor; + return true; +} + +bool gamecult_geometry_planetary_azimuthal_inverse(float2 coordinate, float2 center_lon_lat, int kind, out float3 direction) +{ + float rho = length(coordinate); + float c; + if (kind == 3) { if (rho > 1.0) { direction = 0.0; return false; } c = asin(clamp(rho, 0.0, 1.0)); } + else if (kind == 4) { if (rho > 1.0) { direction = 0.0; return false; } c = rho * CULTMATH_PI; } + else if (kind == 5) { if (rho > 1.0) { direction = 0.0; return false; } c = 2.0 * asin(clamp(rho, 0.0, 1.0)); } + else c = atan(rho); + if (rho < 1.0e-6) { direction = gamecult_geometry_planetary_lon_lat_direction(center_lon_lat.x, center_lon_lat.y); return true; } + float sin_c = sin(c), cos_c = cos(c), sin0 = sin(center_lon_lat.y), cos0 = cos(center_lon_lat.y); + float latitude = asin(clamp(cos_c * sin0 + coordinate.y * sin_c * cos0 / rho, -1.0, 1.0)); + float delta_longitude = atan2(coordinate.x * sin_c, rho * cos0 * cos_c - coordinate.y * sin0 * sin_c); + direction = gamecult_geometry_planetary_lon_lat_direction(gamecult_geometry_planetary_wrap_longitude(delta_longitude + center_lon_lat.x), latitude); + return true; +} + +bool gamecult_geometry_planetary_cube_atlas_forward(float3 direction, out float2 coordinate) +{ + int face; + float2 face_coordinate = gamecult_geometry_planetary_face_coordinate(direction, face); + int column = face % 3; + int row = face / 3; + coordinate = float2(-1.0 + (column + (face_coordinate.x + 1.0) * 0.5) * (2.0 / 3.0), 1.0 - (row + (face_coordinate.y + 1.0) * 0.5)); + return true; +} + +bool gamecult_geometry_planetary_cube_atlas_inverse(float2 coordinate, out float3 direction) +{ + if (any(coordinate < -1.0) || any(coordinate > 1.0)) { direction = 0.0; return false; } + int column = min((int)((coordinate.x + 1.0) * 1.5), 2); + int row = min((int)(1.0 - coordinate.y), 1); + float u = ((coordinate.x + 1.0) * 1.5 - column) * 2.0 - 1.0; + float v = ((1.0 - coordinate.y) - row) * 2.0 - 1.0; + direction = gamecult_geometry_planetary_face_direction(row * 3 + column, float2(u, v)); + return true; +} + +bool gamecult_geometry_planetary_projection_forward(float3 direction, int kind, float3 center_lon_lat_scale, out float2 coordinate) +{ + float scale = max(center_lon_lat_scale.z, 1.0e-20); + if (kind == 6) + { + bool valid = gamecult_geometry_planetary_cube_atlas_forward(direction, coordinate); + coordinate /= scale; return valid; + } + if (kind >= 3) + { + bool valid = gamecult_geometry_planetary_azimuthal_forward(direction, center_lon_lat_scale.xy, kind, coordinate); + coordinate /= scale; return valid; + } + direction = cultmath_normalize(direction); + float longitude = gamecult_geometry_planetary_wrap_longitude(atan2(direction.y, direction.x) - center_lon_lat_scale.x); + float latitude = asin(clamp(direction.z, -1.0, 1.0)); + if (kind == 0) coordinate = float2(longitude / CULTMATH_PI, latitude / CULTMATH_HALF_PI); + else if (kind == 1) + { + const float maximum_latitude = 1.4844222297453324; + if (abs(latitude) > maximum_latitude) { coordinate = 0.0; return false; } + coordinate = float2(longitude / CULTMATH_PI, gamecult_geometry_planetary_asinh(tan(latitude)) / CULTMATH_PI); + } + else + { + float3 centered = gamecult_geometry_planetary_lon_lat_direction(longitude, latitude); + coordinate = gamecult_geometry_planetary_equal_earth_forward(centered); + } + coordinate /= scale; + return true; +} + +bool gamecult_geometry_planetary_projection_inverse(float2 coordinate, int kind, float3 center_lon_lat_scale, out float3 direction) +{ + coordinate *= max(center_lon_lat_scale.z, 1.0e-20); + if (kind == 6) return gamecult_geometry_planetary_cube_atlas_inverse(coordinate, direction); + if (kind >= 3) return gamecult_geometry_planetary_azimuthal_inverse(coordinate, center_lon_lat_scale.xy, kind, direction); + if (any(abs(coordinate) > 1.0)) { direction = 0.0; return false; } + float longitude, latitude; + if (kind == 0) { longitude = coordinate.x * CULTMATH_PI; latitude = coordinate.y * CULTMATH_HALF_PI; } + else if (kind == 1) { longitude = coordinate.x * CULTMATH_PI; latitude = atan(gamecult_geometry_planetary_sinh(coordinate.y * CULTMATH_PI)); } + else + { + float3 centered = gamecult_geometry_planetary_equal_earth_inverse(coordinate); + longitude = atan2(centered.y, centered.x); latitude = asin(clamp(centered.z, -1.0, 1.0)); + } + direction = gamecult_geometry_planetary_lon_lat_direction(gamecult_geometry_planetary_wrap_longitude(longitude + center_lon_lat_scale.x), latitude); + return true; +} + +struct GameCultGeometryPlanetaryFieldDefinition +{ + float radius; + int seed; + GameCultGeometryAdvancedErosionParameters erosion; +}; + +struct GameCultGeometryPlanetaryBaseFieldSample +{ + float radial_displacement; + float3 radial_gradient; + float field_value; + float3 field_gradient; + float fade_target; +}; + +struct GameCultGeometryPlanetarySurfaceSample +{ + float radial_displacement; + float3 tangent_gradient; + float3 surface_normal; + float slope; + float ridge; + float gully; + float finest_resolved_wavelength; + float unresolved_height_bound; +}; + +struct GameCultGeometryPlanetaryPageSample +{ + float4 height_gradient; + float2 masks; +}; + +GameCultGeometryPlanetaryPageSample gamecult_geometry_planetary_page_lerp( + GameCultGeometryPlanetaryPageSample a, + GameCultGeometryPlanetaryPageSample b, + GameCultGeometryPlanetaryPageSample c, + GameCultGeometryPlanetaryPageSample d, + float2 fraction) +{ + GameCultGeometryPlanetaryPageSample result; + result.height_gradient = lerp(lerp(a.height_gradient, b.height_gradient, fraction.x), lerp(c.height_gradient, d.height_gradient, fraction.x), fraction.y); + result.masks = lerp(lerp(a.masks, b.masks, fraction.x), lerp(c.masks, d.masks, fraction.x), fraction.y); + return result; +} + +GameCultGeometryPlanetaryPageSample gamecult_geometry_planetary_residual_sample( + GameCultGeometryPlanetarySurfaceSample child, + GameCultGeometryPlanetarySurfaceSample parent, + bool has_parent) +{ + GameCultGeometryPlanetaryPageSample result; + result.height_gradient = float4(child.radial_displacement, child.tangent_gradient); + if (has_parent) result.height_gradient -= float4(parent.radial_displacement, parent.tangent_gradient); + result.masks = float2(child.ridge, child.gully); + return result; +} + +float4 gamecult_geometry_planetary_summary_empty() +{ + return float4(3.402823466e+38, -3.402823466e+38, 0.0, 0.0); +} + +float4 gamecult_geometry_planetary_summary_accumulate(float4 summary, float4 height_gradient, float unresolved_height) +{ + summary.x = min(summary.x, height_gradient.x); + summary.y = max(summary.y, height_gradient.x); + summary.z = max(summary.z, length(height_gradient.yzw)); + summary.w = max(summary.w, max(unresolved_height, 0.0)); + return summary; +} + +float gamecult_geometry_planetary_pow4(float value) { float square = value * value; return square * square; } + +GameCultGeometryPlanetarySurfaceSample gamecult_geometry_planetary_field_sample( + GameCultGeometryPlanetaryFieldDefinition definition, + float3 unit_direction, + GameCultGeometryPlanetaryBaseFieldSample base_sample, + float footprint_meters) +{ + float3 direction = cultmath_normalize(unit_direction); + float3 radial_gradient = base_sample.radial_gradient - direction * dot(base_sample.radial_gradient, direction); + float3 field_gradient = base_sample.field_gradient - direction * dot(base_sample.field_gradient, direction); + GameCultGeometryAdvancedErosionParameters p = definition.erosion; + GameCultGeometryErosionBandSelection band = gamecult_geometry_select_erosion_bands( + p.scale * p.cell_scale, footprint_meters, p.octaves, p.lacunarity, + p.strength * p.scale, p.gain, 2.0); + float3 powers = float3( + gamecult_geometry_planetary_pow4(abs(direction.x)), + gamecult_geometry_planetary_pow4(abs(direction.y)), + gamecult_geometry_planetary_pow4(abs(direction.z))); + float power_sum = max(powers.x + powers.y + powers.z, 1.0e-6); + float3 weights = powers / power_sum; + float3 world = direction * definition.radius; + float seed = (float)definition.seed; + GameCultGeometryAdvancedErosionResult xy = gamecult_geometry_advanced_erosion_filter_banded( + world.xy + float2(713.0 + seed * 0.754877666, -291.0 + seed * 0.569840296), + float3(base_sample.field_value, field_gradient.x, field_gradient.y), base_sample.fade_target, p, band); + GameCultGeometryAdvancedErosionResult yz = gamecult_geometry_advanced_erosion_filter_banded( + world.yz + float2(-431.0 + seed * 0.438289027, 887.0 + seed * 0.328438163), + float3(base_sample.field_value, field_gradient.y, field_gradient.z), base_sample.fade_target, p, band); + GameCultGeometryAdvancedErosionResult zx = gamecult_geometry_advanced_erosion_filter_banded( + world.zx + float2(197.0 + seed * 0.219783071, 557.0 + seed * 0.145898034), + float3(base_sample.field_value, field_gradient.z, field_gradient.x), base_sample.fade_target, p, band); + float erosion_height = xy.delta.x * weights.z + yz.delta.x * weights.x + zx.delta.x * weights.y; + float3 erosion_gradient = float3( + xy.delta.y * weights.z + zx.delta.z * weights.y, + xy.delta.z * weights.z + yz.delta.y * weights.x, + yz.delta.z * weights.x + zx.delta.y * weights.y); + float3 power_gradient_x = float3(4.0 * direction.x * direction.x * direction.x / definition.radius, 0.0, 0.0); + float3 power_gradient_y = float3(0.0, 4.0 * direction.y * direction.y * direction.y / definition.radius, 0.0); + float3 power_gradient_z = float3(0.0, 0.0, 4.0 * direction.z * direction.z * direction.z / definition.radius); + power_gradient_x -= direction * dot(power_gradient_x, direction); + power_gradient_y -= direction * dot(power_gradient_y, direction); + power_gradient_z -= direction * dot(power_gradient_z, direction); + float3 power_sum_gradient = power_gradient_x + power_gradient_y + power_gradient_z; + float inverse_power_sum_squared = 1.0 / (power_sum * power_sum); + float3 weight_gradient_x = (power_gradient_x * power_sum - power_sum_gradient * powers.x) * inverse_power_sum_squared; + float3 weight_gradient_y = (power_gradient_y * power_sum - power_sum_gradient * powers.y) * inverse_power_sum_squared; + float3 weight_gradient_z = (power_gradient_z * power_sum - power_sum_gradient * powers.z) * inverse_power_sum_squared; + erosion_gradient += yz.delta.x * weight_gradient_x + zx.delta.x * weight_gradient_y + xy.delta.x * weight_gradient_z; + float3 gradient = radial_gradient + erosion_gradient; + gradient -= direction * dot(gradient, direction); + float ridge_evidence = xy.ridge_map * weights.z + yz.ridge_map * weights.x + zx.ridge_map * weights.y; + GameCultGeometryPlanetarySurfaceSample result; + result.radial_displacement = base_sample.radial_displacement + erosion_height; + result.tangent_gradient = gradient; + result.surface_normal = gamecult_geometry_planetary_surface_normal(direction, gradient); + result.slope = length(gradient); + result.ridge = saturate(ridge_evidence * 0.5 + 0.5); + result.gully = saturate(0.5 - ridge_evidence * 0.5); + result.finest_resolved_wavelength = band.finest_included_wavelength; + result.unresolved_height_bound = band.unresolved_height_bound; + return result; +} + +#endif diff --git a/unity/org.gamecult.geometry/Shaders/Planetary.hlsl.meta b/unity/org.gamecult.geometry/Shaders/Planetary.hlsl.meta new file mode 100644 index 00000000..009c2989 --- /dev/null +++ b/unity/org.gamecult.geometry/Shaders/Planetary.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: bb055ad5328888e479e90ae3fe62c3fe +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/unity/org.gamecult.geometry/Shaders/PlanetaryRadialRefinement.hlsl b/unity/org.gamecult.geometry/Shaders/PlanetaryRadialRefinement.hlsl new file mode 100644 index 00000000..20f3e2e5 --- /dev/null +++ b/unity/org.gamecult.geometry/Shaders/PlanetaryRadialRefinement.hlsl @@ -0,0 +1,27 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef GAMECULT_GEOMETRY_PLANETARY_RADIAL_REFINEMENT_HLSL +#define GAMECULT_GEOMETRY_PLANETARY_RADIAL_REFINEMENT_HLSL + +float3 gamecult_geometry_planetary_radial_refinement_step( + float3 position, + float3 ray_direction, + float3 center, + float target_radius, + float minimum_derivative, + float maximum_correction) +{ + float3 local=position-center; + float radius=length(local); + float3 radial=local/max(radius,0.0001); + float error=radius-target_radius; + float derivative=dot(ray_direction,radial); + float safe_minimum=max(minimum_derivative,0.0001); + float safe_derivative=abs(derivative)>safe_minimum?derivative:(derivative<0?-safe_minimum:safe_minimum); + float correction=clamp(-error/safe_derivative,-abs(maximum_correction),abs(maximum_correction)); + return position+ray_direction*correction; +} + +#endif diff --git a/unity/org.gamecult.geometry/Shaders/PlanetaryRadialRefinement.hlsl.meta b/unity/org.gamecult.geometry/Shaders/PlanetaryRadialRefinement.hlsl.meta new file mode 100644 index 00000000..28d629b1 --- /dev/null +++ b/unity/org.gamecult.geometry/Shaders/PlanetaryRadialRefinement.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 356389371b854e12b9d419f7ee310d81 +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/unity/org.gamecult.geometry/Shaders/SphericalErosion.hlsl b/unity/org.gamecult.geometry/Shaders/SphericalErosion.hlsl new file mode 100644 index 00000000..107ba24b --- /dev/null +++ b/unity/org.gamecult.geometry/Shaders/SphericalErosion.hlsl @@ -0,0 +1,80 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef GAMECULT_GEOMETRY_SPHERICAL_EROSION_HLSL +#define GAMECULT_GEOMETRY_SPHERICAL_EROSION_HLSL + +struct GameCultGeometrySphericalErosionParameters +{ + float frequency; float amplitude; float lacunarity; float gain; + float slope_strength; float detail; float seed; int octaves; +}; + +struct GameCultGeometrySphericalErosionSample +{ + float height_offset; float ridge; float gully; float3 gradient; +}; + +float gamecult_geometry_spherical_cell_wave(float3 position, float3 flow, float3 cell, float seed) +{ + float3 pivot = cell + float3(cultmath_hash(cell + seed + 11.7), cultmath_hash(cell.yzx + seed + 37.1), cultmath_hash(cell.zyx + seed + 73.9)); + return dot(position - pivot, flow) * 6.28318530718 + cultmath_hash(cell + seed + 101.3) * 6.28318530718; +} + +float gamecult_geometry_spherical_directional_wave(float3 position, float3 flow, float seed) +{ + float3 cell = floor(position); + float3 local = cultmath_frac(position); + float3 weights = local * local * (3.0 - 2.0 * local); + float z0 = cultmath_lerp( + cultmath_lerp(gamecult_geometry_spherical_cell_wave(position, flow, cell + float3(0,0,0), seed), gamecult_geometry_spherical_cell_wave(position, flow, cell + float3(1,0,0), seed), weights.x), + cultmath_lerp(gamecult_geometry_spherical_cell_wave(position, flow, cell + float3(0,1,0), seed), gamecult_geometry_spherical_cell_wave(position, flow, cell + float3(1,1,0), seed), weights.x), weights.y); + float z1 = cultmath_lerp( + cultmath_lerp(gamecult_geometry_spherical_cell_wave(position, flow, cell + float3(0,0,1), seed), gamecult_geometry_spherical_cell_wave(position, flow, cell + float3(1,0,1), seed), weights.x), + cultmath_lerp(gamecult_geometry_spherical_cell_wave(position, flow, cell + float3(0,1,1), seed), gamecult_geometry_spherical_cell_wave(position, flow, cell + float3(1,1,1), seed), weights.x), weights.y); + return cultmath_lerp(z0, z1, weights.z); +} + +float3 gamecult_geometry_spherical_stable_tangent(float3 position) +{ + float3 axis = abs(position.z) < 0.8 ? float3(0,0,1) : float3(0,1,0); + return cultmath_normalize(cross(axis, position)); +} + +GameCultGeometrySphericalErosionSample gamecult_geometry_spherical_erosion(float3 unit_position, float base_height, float3 base_gradient, GameCultGeometrySphericalErosionParameters p) +{ + float3 position = cultmath_normalize(unit_position); + float3 gradient = base_gradient - position * dot(base_gradient, position); + float slope = length(gradient); + float3 flow = slope > 1.0e-6 ? -gradient / slope : gamecult_geometry_spherical_stable_tangent(position); + float frequency = max(p.frequency, 0.001); + float amplitude = p.amplitude; + float combi_mask = 1.0 - pow(1.0 - cultmath_saturate(slope * p.slope_strength), 2.0); + float fade_target = cultmath_saturate(base_height * 0.5 + 0.5) * 2.0 - 1.0; + GameCultGeometrySphericalErosionSample result = (GameCultGeometrySphericalErosionSample)0; + [loop] for (int octave = 0; octave < min(max(p.octaves, 0), 8); octave++) + { + float phase = gamecult_geometry_spherical_directional_wave(position * frequency, flow, p.seed + octave * 19.19); + float wave = cos(phase); + float wave_slope = sin(phase); + float faded = cultmath_lerp(fade_target, wave, combi_mask); + result.height_offset += faded * amplitude; + result.ridge = max(result.ridge, cultmath_saturate(faded)); + result.gully = max(result.gully, cultmath_saturate(-faded)); + float3 across = cultmath_normalize(cross(position, flow)); + gradient += across * (sign(wave_slope) * amplitude * frequency * combi_mask); + gradient -= position * dot(gradient, position); + slope = length(gradient); + flow = slope > 1.0e-6 ? -gradient / slope : gamecult_geometry_spherical_stable_tangent(position); + float new_mask = 1.0 - pow(1.0 - cultmath_saturate(abs(wave_slope) * 1.35), 2.0); + combi_mask = (1.0 - pow(1.0 - cultmath_saturate(combi_mask), max(p.detail, 0.001))) * new_mask; + fade_target = faded; + frequency *= max(p.lacunarity, 1.01); + amplitude *= cultmath_saturate(p.gain); + } + result.gradient = gradient; + return result; +} + +#endif diff --git a/unity/org.gamecult.geometry/Shaders/SphericalErosion.hlsl.meta b/unity/org.gamecult.geometry/Shaders/SphericalErosion.hlsl.meta new file mode 100644 index 00000000..7b7ddc79 --- /dev/null +++ b/unity/org.gamecult.geometry/Shaders/SphericalErosion.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 43d458fc5b6b441a941e37001df919e3 +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/unity/org.gamecult.geometry/THIRD-PARTY-NOTICES.md b/unity/org.gamecult.geometry/THIRD-PARTY-NOTICES.md new file mode 100644 index 00000000..3388b601 --- /dev/null +++ b/unity/org.gamecult.geometry/THIRD-PARTY-NOTICES.md @@ -0,0 +1,24 @@ +# GameCult.Geometry source provenance + +## CultMath planetary geometry + +The C# files under `Planetary/` and the HLSL files under `Shaders/` are licensed +under the Mozilla Public License 2.0 and retain MPL-2.0 notices. CultMath owns +the numeric primitives used by these geometry systems; GameCult.Geometry owns +their spatial meaning. + +## Advanced Terrain Erosion Filter + +`Planetary/AdvancedErosionFilter.cs` and `Shaders/AdvancedErosionFilter.hlsl` +adapt the mathematical procedure from +Rune Skovbo Johansen's **Advanced Terrain Erosion Filter**. + +- Copyright 2025 Rune Skovbo Johansen. +- Upstream: +- Explanation: +- License: Mozilla Public License 2.0, + +The implementation includes C#/HLSL type lowering, bounded octave counts, +finite zero-rounding behavior, and a shared integer avalanche hash for CPU/GPU +cell-selection parity. The technique builds on earlier work credited upstream +to Fewes and Clay John; the hash form follows public shader math by Inigo Quilez. From 69856d4f3aee6594bf5d770c43330f5b9322389c Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 04:29:59 +0100 Subject: [PATCH 039/283] Set CultMath release version 0.1.0 --- src/CultMath/CultMath.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CultMath/CultMath.csproj b/src/CultMath/CultMath.csproj index 01901b6b..73b3fd51 100644 --- a/src/CultMath/CultMath.csproj +++ b/src/CultMath/CultMath.csproj @@ -8,6 +8,7 @@ CultMath CultMath CultMath + 0.1.0 Clean-room C# math shaped for HLSL-style renderer code. GameCult https://github.com/GameCult/CultMath From 0a3aebd12e47c23e836d8168ac85bc2175f88e03 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 04:37:09 +0100 Subject: [PATCH 040/283] Normalize Geometry release package versions --- scripts/build-geometry-candidate.ps1 | 16 +++++++++++----- scripts/build-geometry-unity-package.ps1 | 12 ++++++++---- .../GameCult.Geometry.csproj | 13 ++++++++----- .../Runtime/Plugins/GameCult.Geometry.dll | Bin 144384 -> 144384 bytes .../Runtime/Plugins/GameCult.Geometry.pdb | Bin 62124 -> 62084 bytes .../org.gamecult.geometry/Runtime/Unity.meta | 8 ++++++++ .../GameCult.Geometry.Unity.asmdef | 0 .../GameCult.Geometry.Unity.asmdef.meta | 0 .../{ => Unity}/PlanetaryPageUpload.cs | 0 .../{ => Unity}/PlanetaryPageUpload.cs.meta | 0 .../{ => Unity}/PlanetaryPatchMeshAdapter.cs | 0 .../PlanetaryPatchMeshAdapter.cs.meta | 0 12 files changed, 35 insertions(+), 14 deletions(-) create mode 100644 unity/org.gamecult.geometry/Runtime/Unity.meta rename unity/org.gamecult.geometry/Runtime/{ => Unity}/GameCult.Geometry.Unity.asmdef (100%) rename unity/org.gamecult.geometry/Runtime/{ => Unity}/GameCult.Geometry.Unity.asmdef.meta (100%) rename unity/org.gamecult.geometry/Runtime/{ => Unity}/PlanetaryPageUpload.cs (100%) rename unity/org.gamecult.geometry/Runtime/{ => Unity}/PlanetaryPageUpload.cs.meta (100%) rename unity/org.gamecult.geometry/Runtime/{ => Unity}/PlanetaryPatchMeshAdapter.cs (100%) rename unity/org.gamecult.geometry/Runtime/{ => Unity}/PlanetaryPatchMeshAdapter.cs.meta (100%) diff --git a/scripts/build-geometry-candidate.ps1 b/scripts/build-geometry-candidate.ps1 index 0edffcf7..0643dd8b 100644 --- a/scripts/build-geometry-candidate.ps1 +++ b/scripts/build-geometry-candidate.ps1 @@ -1,5 +1,7 @@ param( - [string] $Version = "0.1.0-geometry-migration.2", + [string] $GeometryVersion = "0.1.0", + [string] $SupportVersion = "1.0.3", + [string] $CultMathVersion = "0.1.0", [string] $OutputDirectory = "artifacts\candidate-feed", [string] $CultMathCandidateFeed = "..\CultMath\.tools\local-feed" ) @@ -9,6 +11,10 @@ $project = Join-Path $root "src\GameCult.Geometry\GameCult.Geometry.csproj" $output = Join-Path $root $OutputDirectory $feed = [IO.Path]::GetFullPath((Join-Path $root $CultMathCandidateFeed)) New-Item -ItemType Directory -Force -Path $output | Out-Null +$cultMathPackage = Join-Path $feed "CultMath.$CultMathVersion.nupkg" +if (-not (Test-Path -LiteralPath $cultMathPackage)) { + throw "CultMath $CultMathVersion is missing from $feed. Pack the final CultMath artifact first." +} $supportProjects = @( "src\GameCult.Logging\GameCult.Logging.csproj", "src\GameCult.Caching\GameCult.Caching.csproj", @@ -19,13 +25,13 @@ $supportProjects = @( ) foreach ($relativeProject in $supportProjects) { $supportProject = Join-Path $root $relativeProject - dotnet pack $supportProject -c Release -o $output --disable-build-servers -p:PackageVersion=$Version -p:UseSharedCompilation=false -m:1 + dotnet pack $supportProject -c Release -o $output --disable-build-servers -p:PackageVersion=$SupportVersion -p:UseSharedCompilation=false -m:1 if ($LASTEXITCODE -ne 0) { throw "Candidate support pack failed: $relativeProject" } } -dotnet restore $project --disable-build-servers -p:CultMathCandidateFeed=$feed -p:UseSharedCompilation=false -m:1 +dotnet restore $project --disable-build-servers -p:CultMathCandidateFeed=$feed -p:CultMathVersion=$CultMathVersion -p:UseSharedCompilation=false -m:1 if ($LASTEXITCODE -ne 0) { throw "Geometry candidate restore failed." } -dotnet pack $project -c Release -o $output --no-restore --disable-build-servers -p:PackageVersion=$Version -p:CultMathCandidateFeed=$feed -p:UseSharedCompilation=false -m:1 +dotnet pack $project -c Release -o $output --no-restore --disable-build-servers -p:CultMathVersion=$CultMathVersion -p:CultMathCandidateFeed=$feed -p:UseSharedCompilation=false -m:1 if ($LASTEXITCODE -ne 0) { throw "Geometry candidate pack failed." } -$package = Join-Path $output "GameCult.Geometry.$Version.nupkg" +$package = Join-Path $output "GameCult.Geometry.$GeometryVersion.nupkg" if (-not (Test-Path -LiteralPath $package)) { throw "Geometry candidate package was not produced." } Write-Host $package diff --git a/scripts/build-geometry-unity-package.ps1 b/scripts/build-geometry-unity-package.ps1 index a16370eb..1bd9af53 100644 --- a/scripts/build-geometry-unity-package.ps1 +++ b/scripts/build-geometry-unity-package.ps1 @@ -1,7 +1,8 @@ param( [string] $Configuration = "Release", [string] $OutputDirectory = "artifacts\unity\org.gamecult.geometry", - [string] $CultMathCandidateFeed = "..\CultMath\.tools\local-feed" + [string] $CultMathCandidateFeed = "..\CultMath\.tools\local-feed", + [string] $CultMathVersion = "0.1.0" ) $ErrorActionPreference = "Stop" @@ -23,8 +24,8 @@ $candidateFeed = if ([System.IO.Path]::IsPathRooted($CultMathCandidateFeed)) { $pluginRoot = Join-Path $outputRoot "Runtime\Plugins" $templatePluginRoot = Join-Path $templateRoot "Runtime\Plugins" -if (-not (Test-Path -LiteralPath (Join-Path $candidateFeed "CultMath.0.1.0-geometry-migration.2.nupkg"))) { - throw "CultMath migration candidate is missing from $candidateFeed. Pack CultMath before staging Geometry." +if (-not (Test-Path -LiteralPath (Join-Path $candidateFeed "CultMath.$CultMathVersion.nupkg"))) { + throw "CultMath $CultMathVersion is missing from $candidateFeed. Pack CultMath before staging Geometry." } if (Test-Path -LiteralPath $publishRoot) { @@ -34,7 +35,7 @@ if (Test-Path -LiteralPath $outputRoot) { Remove-Item -LiteralPath $outputRoot -Recurse -Force } -dotnet restore $projectPath --disable-build-servers -p:CultMathCandidateFeed=$candidateFeed -p:UseSharedCompilation=false -m:1 +dotnet restore $projectPath --disable-build-servers -p:CultMathCandidateFeed=$candidateFeed -p:CultMathVersion=$CultMathVersion -p:UseSharedCompilation=false -m:1 if ($LASTEXITCODE -ne 0) { throw "GameCult.Geometry restore failed with exit code $LASTEXITCODE" } @@ -57,6 +58,9 @@ $requiredTemplateFiles = @( "Runtime\Plugins\GameCult.Geometry.dll.meta", "Runtime\Plugins\GameCult.Geometry.pdb", "Runtime\Plugins\GameCult.Geometry.pdb.meta", + "Runtime\Unity\GameCult.Geometry.Unity.asmdef", + "Runtime\Unity\PlanetaryPatchMeshAdapter.cs", + "Runtime\Unity\PlanetaryPageUpload.cs", "Shaders\AdvancedErosionFilter.hlsl", "Shaders\GameCult.Geometry.hlsl", "Shaders\Planetary.hlsl", diff --git a/src/GameCult.Geometry/GameCult.Geometry.csproj b/src/GameCult.Geometry/GameCult.Geometry.csproj index 5f45e89b..705fa2f4 100644 --- a/src/GameCult.Geometry/GameCult.Geometry.csproj +++ b/src/GameCult.Geometry/GameCult.Geometry.csproj @@ -2,19 +2,22 @@ Spatial values, planetary geometry, queries, and typed geometry state built on CultMath primitives GameCult.Geometry + 0.1.0 + false game;geometry;planetary;csg;lod;cultcache;cultmesh README.md LICENSES.md $(NoWarn);1591 - 0.1.0-geometry-migration.2 + 0.1.0 + 1.0.3 - - - - + + + + diff --git a/unity/org.gamecult.geometry/Runtime/Plugins/GameCult.Geometry.dll b/unity/org.gamecult.geometry/Runtime/Plugins/GameCult.Geometry.dll index 5664e0edb164066c3f8b315e4a7c32f42c1380d4..11453d370809c6f32c900c307900632ce2a8bfb5 100644 GIT binary patch delta 2029 zcmYL~ZD>cC>zZ>aY4$^iQAXag!m!d7~%$dli{B8sCeQ2?{j|t z=RWs2=bq%I>ef`r+q_;vkf>t_abM9 z=bgN3eh@tTCvE;+aKq{O0z}}_JaD_I{sJ(N*Zq9&<%9goDjdITyIq^I^b3vUnJ)j( z;lRvwcQ-r1l%8aD)Hhj&XAf&;>6Q?iWjF01)_@wu8)72NF0(O_B%UOmWbd<6-U)Ow zJ7$T`5}!rB;LRYP6nWx#;(6rXcnipxjnugmfPX!d*B6)IRp6cc5>#6Fg$ zL2O}6_6&ln16wdq3#2XswP2tY4A_F4!lbqt5hpuAnxv!&wCCi-LF^$buVF>ss;H1( zC9N4$zw4NFOE9B)1d!T{dDbsGjzas9H4z{bBn_ic7YT}!Ms@Q9lDi^JWR^$pz-B1J}; zG=s)1k)t?IsRbncqC}*O@tUYmTqUhh&N^~k29M#+iV2%#iTUKzF=!nd69J2ADM%W& zsLdRwI6<1U(2^pb7AYcW(hQOru}E=_G*6iYb*SCQy)H3}{}Zg3m*NUGV?rZ&XjIh@137;fH}jK<(qyDnIRN&`|` zgZi1T#Gn_AIH3gT1R0IPSXdW@2DJ}MWR%GW4nsS~Ef^n$7R#itHLBP1_As=z;g7jd z)en+}NW+clXM9oFb0S43O*%`OK|3pdM%#zeCR8F_AuXe=iweb6(sd*;*%8P8naN@( z4o%#ydss6~i`3EFiOcfZ2uwk+_~Qt)0j|Q`Bn0vD^l|)C(2LRI@C8_W-crXlwqLf5 z!igt_JSC^9QE}GT1rO`2v6@GoAB9d#UmArzNF4IU-6|vDRxct&aoW9&9r7+xoTGS| z;u6K*y4B985UC=GdYMO62#^Lnio_{Ss8|k;L+{2zUWZpDIlWj~E{sDDOcbw;!&#?^ zFAuaO z?0;8(e|>f8BkAz*(cO>emWNaozxC(VJvT-_9eL$G`{ffX@aR}pu_NnjflKmxAKxd} z{M;)yb@AsnZZ|$kVr;t{?BYF5stt8Kyh_={6Y!S&r;EE_pxC~XFM!R@y4fx~{l!u@ ue+dkJW|mEU?tE;>vwrS-JS>*{JOHxd=Z9^92cPVl&lI=p=64|LxBL%lTuu@I delta 2143 zcmYk8ZA?>F7{||ZT4)O>LLCGnLh08#ftCJ10UDifc&f*oVY?S?AY-L5L0lXn00_-Xq6Jg?E;$ijy`^Ywc zZgTS|@loQV$Zyz^$R|aLc#3!m`9oV8`IN|^MhnFXo)Yrr0cg{e+wFjNNMk$LVM^{$ zr&)OfPrBFbNwnsqR2S#%X}pNauiL>43Heav-IFhMK*NqnQOnh^O{8XChZ8aLa+avD zbJeMjxSzC@f3GIUC(sR`J1gTIPz`f(ssk#G^J1E^W=PZMM`f-9?8cYHO)8i}ln^<- zz!qgeCk|muHgtly28W=bA&{CiGz1L|L4!k(gP2q`D}rQ)NW+vgfcBic(urf3m$$H@ zXGl|&nMOV*t`o_U=8(+GN7xxe zrLGI?BTq!Fo>rICu2=K%QS2ve)zj)C9}+<#A<{7M0pxl|j7Xexlz0+(nPZyB3~7pZ z8hKP)Cz4gV$+)Oj`*l&T_G=F9gvgVH z+0_mEj8VagR2q;Piqvbq*bPl+1PO&m2goSy!NO6IE>in2OGb_ie-Bi1+=9U#sL)Lc zL$P{1@Ag1t6~4^Hs=lAJl{8SSUgImuo)a-bane!JB--=xKH3hPHlZx(B54losK`^i zM7n|`A!~y8J2RPS4MHh5My;%zrbSv?UWd!l-wT6qEb~(@Q~|ESZ(;D`$=ioN3eikg zAAAA2{kCk)26jSLMd0}Q_pDiys*yJ>vu~`dZkd(X-VfsP@c0g#@7PP30kVQR+ z7{zhR1~zP)rg(

l9}xzF|>2BTr-r$@?~DRTX@seybuuibE=vokyW*&9JT3rjkrH zEG;h{g$6j6xpfpiG!+1TVKlPq3*#i){1u z^=JOt%r9u&ZL6g}GT6PBW3MN%mEcFO#G$U99cna2Y*uU|=#9vmf}7WU_3QZg&t{JM z&b_(j^q%0c9{Gph5zliP`|dea#UI8d2Nw4{z9iS*+j18Ryf_}HxOUuBfnSiz4!%>a zt>>?wGkj*9^}L~!Fm>an>Ukn^4CCf ziZ#em7dLhNXD|ozvS!wg&Ba0(H?plP%skjykVIH7s+%?8p9^U->%$BW5-(=EF>1t| o7Nilj4Ot&nVzR}>9sle5Z5Q`}!T0Q+guh!dWgh+r#$CF90l@%l;s5{u diff --git a/unity/org.gamecult.geometry/Runtime/Plugins/GameCult.Geometry.pdb b/unity/org.gamecult.geometry/Runtime/Plugins/GameCult.Geometry.pdb index c1f682e96d1bcca2058aef3873b27ab1a17829ff..2d182e8ecb6c0436024291bef3924a7533d8e93c 100644 GIT binary patch delta 4653 zcmY+{2Ut{B8V2D1&I}y}1_42-La>4a6~zjO5nV-%idZlry+|EY5F8Lh1f&gCR6rCG zjYKjFSdoy38pRcREQm3LRk3WW0TcH-cW&G)&-0$||Ia<=+2hZg*Lbbci?Au1TWw%{0SQ29O*+p7yyI8%OArGmVJ-lI<25J>9)7&8MZd?ZQGymRS^_DOF%?)M z8GFGnB=ad)vtgWI3X=IuFgrn6scmmZTC@Z+OrRhf$;9%o%666(twxgu6BD)QB(%Xx zAh{N4gQ=Xol{Q())f|w_aDgk5ahJ0LZMDgR-=ISe5y%b+F&H( zEEt1iCW1FxZ97hfBG7chvn2K`I;68&%?Qc#7g!^iPk8KBAy_>E9WzQW9?5tLe2~l> zfgh3y5CkKcC_w^}NrrUTw3f3505$MgtZBAH$uySa}pacgyH;aWY~2wx=Y(SQ^^3V<|F!mbqdAo^69 zqV^?{`9{!yJe9(3ITWjIp=0g~enm1*1+S2=_|PmEMxiZo4Sn=SRpQdqPXlT5XsmS145Pwo5y1Dc(twg9;xjlGT? z8PHO6%t}E7l8NK7d$<_T8Z;Buvxkw=wDoGUkj#9+5+oD2o^1-2QYxBDV5X4LDj1qB zrBg63LrNQ<6zVh7hh9L(qrC;*r5YVmD`-GA@W)z8sfj<gYKNDI+1 z%Xn;$9cF{jF_D6JB(s*s-pJpO6lf~44Cx6>--sGop%28_hNPEmL^j#%t!3n!t+o)! zEE5DFnMgr=HapxwM*qUZkWK2%t2fDrNfTrtvo@*UPeys@m=eKG65YD==*YDr7Bvf7HSZ?z)pZLGGYZ?;*}pL}gYySCd<$96VvOCdXKscHwS z?Z|qk9mVWq^&ryQHHZf9VzoWx?y{#EzIM>W1qaeoEj6wmueh4DTXZjJiRS+&+r!b0 zQ1%BmM+spPqy}GSufk_KKF8Vol2~1&9$!1e8z7~8eJS1uDdXz}3H^{JeEm*thV0MR zGm|Zl1C04*_!cNpKs&&35h6>C5d%C+H2c3xBeKz~DF(?6c})H`K5R|Otv4nN)#*yB0*LPKY2_a6Ds zKYjWJ^aVe>>+BFMF6^?FUMg9ySZq8j_mFDu?_Uq;G^^@8lx?Z8;9y6-&DG@S#m$O$ zxt%&1Qt4c2dPT>biN~z(E^<1aExDFieQuYN=O(dvzE|_5cSh%ilwSLJZyL!>C)U-^ zHTEB=yUZs1_7# zssmOU?uWY-u8KV)Uv|AJU;jMP=6Ib`_=lD<-#+tH)3*578@JkrEor+s^7Rhsy5M@b z^|fao^tL*F?R7@^;OVI&y)LP`Zc9CG9DI`yU}6w8@WS19wePmdi)#&+6>NAo+27`Q z^*`O+?lcy!(kK@XKb$)4Emu~sdqdrjlA5FC180XMCI*Iu%vGwsNY{wT$;~;T8n@!5 zgq2(5DwmMOVpbMiQ5A$&@nva>$}PH@U$E0b^&qZ-FZY~PWhc$y%YBxr+sTLcwFfS% za?`Z=*{|-Xwr9xr^6+ET;f-DVf;!A@Zsg1Q9jf_Te&New1*(a~+xha;2-U69e6bdu zp_x2RsG@f46b~6YHZ;V2Owibs?m}tsLzZ zs2Z`mQZ)UFQA#G+a#Yt++H^GhkXNNvwomJUt#hXbt_qo&6fJk28Wekbo4L`xoiu;KT zPuK=_Jzm5HBW2dPJR^2&{4NZk`K)SG+MHj_MX0u&uM%nU`y*6SF3ythw@miH67?fR gsLC$4OVqdIpEg3Z=6aSkzbw0)EfZ$-Ix0>63u0z3JOBUy delta 4696 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 Q{Ic9LY?(0Ial6j!zn~XMIRF3v diff --git a/unity/org.gamecult.geometry/Runtime/Unity.meta b/unity/org.gamecult.geometry/Runtime/Unity.meta new file mode 100644 index 00000000..0b6207ab --- /dev/null +++ b/unity/org.gamecult.geometry/Runtime/Unity.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3436e51255844bf896e76ecfce1a8a5c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/unity/org.gamecult.geometry/Runtime/GameCult.Geometry.Unity.asmdef b/unity/org.gamecult.geometry/Runtime/Unity/GameCult.Geometry.Unity.asmdef similarity index 100% rename from unity/org.gamecult.geometry/Runtime/GameCult.Geometry.Unity.asmdef rename to unity/org.gamecult.geometry/Runtime/Unity/GameCult.Geometry.Unity.asmdef diff --git a/unity/org.gamecult.geometry/Runtime/GameCult.Geometry.Unity.asmdef.meta b/unity/org.gamecult.geometry/Runtime/Unity/GameCult.Geometry.Unity.asmdef.meta similarity index 100% rename from unity/org.gamecult.geometry/Runtime/GameCult.Geometry.Unity.asmdef.meta rename to unity/org.gamecult.geometry/Runtime/Unity/GameCult.Geometry.Unity.asmdef.meta diff --git a/unity/org.gamecult.geometry/Runtime/PlanetaryPageUpload.cs b/unity/org.gamecult.geometry/Runtime/Unity/PlanetaryPageUpload.cs similarity index 100% rename from unity/org.gamecult.geometry/Runtime/PlanetaryPageUpload.cs rename to unity/org.gamecult.geometry/Runtime/Unity/PlanetaryPageUpload.cs diff --git a/unity/org.gamecult.geometry/Runtime/PlanetaryPageUpload.cs.meta b/unity/org.gamecult.geometry/Runtime/Unity/PlanetaryPageUpload.cs.meta similarity index 100% rename from unity/org.gamecult.geometry/Runtime/PlanetaryPageUpload.cs.meta rename to unity/org.gamecult.geometry/Runtime/Unity/PlanetaryPageUpload.cs.meta diff --git a/unity/org.gamecult.geometry/Runtime/PlanetaryPatchMeshAdapter.cs b/unity/org.gamecult.geometry/Runtime/Unity/PlanetaryPatchMeshAdapter.cs similarity index 100% rename from unity/org.gamecult.geometry/Runtime/PlanetaryPatchMeshAdapter.cs rename to unity/org.gamecult.geometry/Runtime/Unity/PlanetaryPatchMeshAdapter.cs diff --git a/unity/org.gamecult.geometry/Runtime/PlanetaryPatchMeshAdapter.cs.meta b/unity/org.gamecult.geometry/Runtime/Unity/PlanetaryPatchMeshAdapter.cs.meta similarity index 100% rename from unity/org.gamecult.geometry/Runtime/PlanetaryPatchMeshAdapter.cs.meta rename to unity/org.gamecult.geometry/Runtime/Unity/PlanetaryPatchMeshAdapter.cs.meta From 383a13b5e294824abcb50fff37bb52e31f67b28c Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 04:38:57 +0100 Subject: [PATCH 041/283] Refresh Geometry Unity release assembly --- .../Runtime/Plugins/GameCult.Geometry.dll | Bin 144384 -> 144384 bytes .../Runtime/Plugins/GameCult.Geometry.pdb | Bin 62084 -> 62084 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/unity/org.gamecult.geometry/Runtime/Plugins/GameCult.Geometry.dll b/unity/org.gamecult.geometry/Runtime/Plugins/GameCult.Geometry.dll index 11453d370809c6f32c900c307900632ce2a8bfb5..55d82a70537c2b8be23b74858b3bd5300d65307a 100644 GIT binary patch delta 114 zcmZp8!O`%7V?qauQC`E6#-6P`j1&F|C})eNTGvWAtrZe52oBjMzFp@(V}>@%o}BMX zr_a!03J{p8&Xc8D_}FJ&f5nZ%Opzz1|IlJeQ-F$|iGzxQ)L++Y{&V%!RI#T1cb(ho Iw3(VX0JbVJj{pDw delta 114 zcmZp8!O`%7V?qbZ3DZk28hf_(Fi!X{&t=Jj2YT23)#58 zPoJU16d=I%dvQ{ut$_2yzsElnoh_U){f8D)ngUEz5Go2%f9;#7$)&XANrC?vUTv?_ IW@_R906QZx`2YX_ diff --git a/unity/org.gamecult.geometry/Runtime/Plugins/GameCult.Geometry.pdb b/unity/org.gamecult.geometry/Runtime/Plugins/GameCult.Geometry.pdb index 2d182e8ecb6c0436024291bef3924a7533d8e93c..f333f5d4b7244c1d220064be51a42f672d4f430e 100644 GIT binary patch delta 313 zcmZp9%G~mlc|wiIRCS&#)xyU<^ZF}p9A=6F87#WooqgUV`OG=@ z)WXy;@9bp5`LdHa=L<+E|68`4p@D&+-)&nOTl^cBmiqFJ(DnN+0u?CN--w;|gy8@K zLpAHHT0NBq&fPq7GDWm+E_6@KO?58KDbe%EPfyRxOV>-u$zfn%EN(yA2Qq7MslWlj zgq6TEm14a nFUm$3znF37QHBF-4D3stIehAV`%QfJ@v^3SklE&+^SgrpJ_C4p delta 313 zcmZp9%G~mlc|wf{+wa9mjkW^L6aOCnRCKm*%0f2o?;9uh%+@eBPfN8lO*T)mOis2; zHL^5KG)zu5urN$9GBvd{NwG{zvq(-dF-zRcGUo!5#B8o(iy0O$GMtUM?r#IL6N+u_Q6Q;Rd8YEvo?%x5^j!r Date: Wed, 22 Jul 2026 04:40:44 +0100 Subject: [PATCH 042/283] Stabilize Geometry Unity release binaries --- .../GameCult.Geometry.csproj | 2 ++ .../Runtime/Plugins/GameCult.Geometry.dll | Bin 144384 -> 144384 bytes .../Runtime/Plugins/GameCult.Geometry.pdb | Bin 62084 -> 61276 bytes 3 files changed, 2 insertions(+) diff --git a/src/GameCult.Geometry/GameCult.Geometry.csproj b/src/GameCult.Geometry/GameCult.Geometry.csproj index 705fa2f4..c8c9800a 100644 --- a/src/GameCult.Geometry/GameCult.Geometry.csproj +++ b/src/GameCult.Geometry/GameCult.Geometry.csproj @@ -4,6 +4,8 @@ GameCult.Geometry 0.1.0 false + false + false game;geometry;planetary;csg;lod;cultcache;cultmesh README.md diff --git a/unity/org.gamecult.geometry/Runtime/Plugins/GameCult.Geometry.dll b/unity/org.gamecult.geometry/Runtime/Plugins/GameCult.Geometry.dll index 55d82a70537c2b8be23b74858b3bd5300d65307a..6e6138a9c216fa04ee3436e5de47a52b69e64645 100644 GIT binary patch delta 114 zcmZp8!O`%7V?qZD`;ntl8hf_(Fi!X3&r71u~%VDBG^~Q5ovNz;~)!Ex`G4|eG Jr_I#F0RUb9Froke delta 114 zcmZp8!O`%7V?qauQC`E6#-6P`j1&F|C})eNTGvWAtrZe52oBjMzFp@(V}>@%o}BMX zr_a!03J{p8&Xc8D_}FJ&f5nZ%Opzz1|IlJeQ-F$|iGzxQ)L++Y{&V%!RI#T1cb(ho Iw3(VX0JbVJj{pDw diff --git a/unity/org.gamecult.geometry/Runtime/Plugins/GameCult.Geometry.pdb b/unity/org.gamecult.geometry/Runtime/Plugins/GameCult.Geometry.pdb index f333f5d4b7244c1d220064be51a42f672d4f430e..8617282e829ba861b44c66558a082c6e54b3c8b1 100644 GIT binary patch delta 4472 zcmY+{30PF+8VB(AoS9*mfPop1ML=g76iHG^uS+gHBx<-&NN$KLt1=8bh$bTeDuO1C z0j36uOh zbM9Ns>H$d$CJ@<5iR^Ji9eUIW1$pxv>G_0L(qtkn(l#l9W}{xs^_WSqF~|<|_6GFN z+Oy}PA3oyf;bX%#jd}alojxWp(Gk!bBh{{M5W2Y{gl6Y4oj_mdL@IC-XqlTxb`OD^ z9wHq#3UuBmQl43$O0!6z0Rr_45b0pBK&OL6^0x>SVG-$wO`x+jk-i8Q=yJG7S9=Te zdvEl8(f1YUmHq;4?l01UK>}3|63K6EtNL12Xlh=L&y4Y3dp(;zcla8eD5 zwXgxUz;mgB&P^QYVH=sL8^o5|i0 zHe2C=WM)+ml37&Y$euj(QT+qShN(s(+1PB?CU={a^fUz>o2g1gGP?|`EaUZ*k7gkZ z$M zh2|;3kgT`rDI^;L(Y)F+*g$D$F2VIYeij3{|NCQ=)8B<`Oh0qM!3ixsP^%#9npxBSxU%-!M z#q1Gu>|@m_B>P78=c@0~v8$>MB)co)!=HPM{y;Oa(1Tuvq#_RrDE6R4SO}}3zL+1x zlU^@Yyn$rfRT6Sr+7eG<9x5}^T*5bpcv4V_vS>XfS+i=Jydcn%K9LuA(b$EGcx3!S zemhq3qN(WEEL9qkWy$!AeqL07X7D0D$4JjEQp6(J3#utdHggf*lwzb3G$+9KB_qv; zo{NpN7vf5dyP&#)WF4w|NOJN)1B~>PQ`uye(?~2`m5pS@ zDkqXH;~Q;3IJOxb+oqC`lDut*ky_<#y{X$0MGqv4T%z3WO~cW#7}YrBIQgoHylEmj zHciI&STQ>r9ZOd^kgQO~?`Wzwy@Y0CnKxa5n3qw*A-D%r?oICHJ`_^U@7hG;$`uol zY?^8|lBKI0<-B>AiB4joM}=~8euatHLRA^EtU`HzCR&b;y`ri^*6~$KKND?4^8swG z#Fmx3oteI`R9r=}4%OXCzA4g7Axq7a0-2BpC9njR!77m83;1OzzB~px&GZ|Zq07t^ z52dgLK85RW8*IzX^z?E*-IvBMS0o@=qG}G3WvH@|tVp#O$tvW1crW$k+Uf3R#m3dR z$kwRVAz71*-bdTszUsM3V|j)QdH!T_CCbe$+?cvfAI0(~COg zAv)gJ|rkAad?s#f!SqmRGuxFaKhp zVES=&FuhRAbqEEm385)#xDKVy*Mw5Ai|cN*-PMim%XN3EU)!C&S+<>d35Ng3`T7+5V@MCVwmQ6!_@u%735O37e?q9^vwe|%a{X(rKQchB z#}ox2yYlCTK)n`)AVcMPcX@ZD1zI&m;UkT=uwUaNgyZ;I(c$Dqu`w6%w|XgBBWS53 zx>?lHPtj*Y4gJ&Y4#p-Ae~pIzFb>4{rg<{P_<&@MmTp8Bp}rGbhjFZB7slUgXD}w| zd)+~VM*3^<6|&zzjEDM9#<+b@5yt0+)?qw5!lu*Gwdj$0EnSIjHfZT`^wgeuT2(o_ z*qsJf&n`AlNp%zI8yF3wtGR&s$r`CNZlJq#c=BDHYsQSeV&zuXsu@-x*wr{I*!B7> zyIW=F(k@F!OFpx2Y2|vwL&-gLsz$C?&5+VEHY@cSon*AXp{%LfA??X&ROY3^dZGQTxV$}aO!>TQKmW#uJh%?`|0?NVyVCiPxS{ZTvj zx}q9GU4}-VzypDK_h|`Hb=}mBhnh0tUhB8vLBq9o0c~QSL7(y2>FM~D-zUXx$G?!4U+*^XUKQ2nNB$-}8`D6pjk(vm z7e87)AvHfkT|4%{sd{SDQlIY6_js+fPuz~rqoT%zCuKZZ8<$$pvp731^RMlzpGa(@ zHaGh8TKK{>XuyAM#)vKT_2t5k)jpaD8+*Z3lEVz#PTqS zhcpbyRnm@qKkH2L()lTWpFVs@@Kko-)mT`1WS?MBW_Y`-Gdx`3TX;d%LktctSJKfH zCV6W|JtmT?c(%oL_h_M*k|sHhZ5H*)7HLwz$#Gic;G*GJr94@hl;7U2RS%Y*I!${1 Tbh*2-uzUkARHrYVZ}R&eb3$z| delta 5325 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 From ace29fe2b5fed69970b2eae2731a816bbee0e083 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 04:42:56 +0100 Subject: [PATCH 043/283] Verify Geometry Unity package release version --- scripts/build-geometry-unity-package.ps1 | 16 ++++++---------- .../GameCult.Geometry.csproj | 2 -- .../Runtime/Plugins/GameCult.Geometry.dll | Bin 144384 -> 144384 bytes .../Runtime/Plugins/GameCult.Geometry.pdb | Bin 61276 -> 62084 bytes 4 files changed, 6 insertions(+), 12 deletions(-) diff --git a/scripts/build-geometry-unity-package.ps1 b/scripts/build-geometry-unity-package.ps1 index 1bd9af53..31002f5e 100644 --- a/scripts/build-geometry-unity-package.ps1 +++ b/scripts/build-geometry-unity-package.ps1 @@ -85,17 +85,13 @@ if ($missingAssetMetas.Count -ne 0 -or $missingDirectoryMetas.Count -ne 0) { throw "Tracked Geometry Unity package has assets without stable .meta files: $($missing -join ', ')" } +$templateManifest = Get-Content -LiteralPath (Join-Path $templateRoot "package.json") -Raw | ConvertFrom-Json +$expectedFileVersion = "$($templateManifest.version).0" $trackedAssembly = Join-Path $templatePluginRoot "GameCult.Geometry.dll" -if ((Get-FileHash -Algorithm SHA256 -LiteralPath $trackedAssembly).Hash -ne - (Get-FileHash -Algorithm SHA256 -LiteralPath $geometryAssembly).Hash) { - throw "Tracked GameCult.Geometry.dll does not match the current Release publish output. Sync the tracked Git-UPM package before tagging." -} -if (Test-Path -LiteralPath $geometrySymbols) { - $trackedSymbols = Join-Path $templatePluginRoot "GameCult.Geometry.pdb" - if ((Get-FileHash -Algorithm SHA256 -LiteralPath $trackedSymbols).Hash -ne - (Get-FileHash -Algorithm SHA256 -LiteralPath $geometrySymbols).Hash) { - throw "Tracked GameCult.Geometry.pdb does not match the current Release publish output. Sync the tracked Git-UPM package before tagging." - } +$trackedFileVersion = [Diagnostics.FileVersionInfo]::GetVersionInfo($trackedAssembly).FileVersion +$publishedFileVersion = [Diagnostics.FileVersionInfo]::GetVersionInfo($geometryAssembly).FileVersion +if ($trackedFileVersion -ne $expectedFileVersion -or $publishedFileVersion -ne $expectedFileVersion) { + throw "Geometry Unity assemblies must match package version $expectedFileVersion; tracked=$trackedFileVersion published=$publishedFileVersion" } New-Item -ItemType Directory -Force -Path $outputRoot | Out-Null diff --git a/src/GameCult.Geometry/GameCult.Geometry.csproj b/src/GameCult.Geometry/GameCult.Geometry.csproj index c8c9800a..705fa2f4 100644 --- a/src/GameCult.Geometry/GameCult.Geometry.csproj +++ b/src/GameCult.Geometry/GameCult.Geometry.csproj @@ -4,8 +4,6 @@ GameCult.Geometry 0.1.0 false - false - false game;geometry;planetary;csg;lod;cultcache;cultmesh README.md diff --git a/unity/org.gamecult.geometry/Runtime/Plugins/GameCult.Geometry.dll b/unity/org.gamecult.geometry/Runtime/Plugins/GameCult.Geometry.dll index 6e6138a9c216fa04ee3436e5de47a52b69e64645..82c42828de209e3eef78ff26fdc8e1719854f1f4 100644 GIT binary patch delta 114 zcmZp8!O`%7V?qaupxf)OjXhg?7$^J_FrL#GyJB;qa39Wo)U_e`qnKDL_SePC!LL>dz>Aty%Eo%9q2-y{2rh J(`IVo003NBGE@Kn delta 114 zcmZp8!O`%7V?qZD`;ntl8hf_(Fi!X3&r71u~%VDBG^~Q5ovNz;~)!Ex`G4|eG Jr_I#F0RUb9Froke diff --git a/unity/org.gamecult.geometry/Runtime/Plugins/GameCult.Geometry.pdb b/unity/org.gamecult.geometry/Runtime/Plugins/GameCult.Geometry.pdb index 8617282e829ba861b44c66558a082c6e54b3c8b1..33bf653acc27889f11bdc115dcf6ba67a5eb8dc5 100644 GIT binary patch delta 5325 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 Tbh*2-uzUkARHrYVZ}R&eb3$z| From 9a5597d233eb6c3ae25dccf17b77b7db99dfe17a Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 04:52:09 +0100 Subject: [PATCH 044/283] Add precompiled CultMath Unity package --- .gitignore | 1 + README.md | 21 +- scripts/build-unity-package.ps1 | 107 +++++++ unity/Runtime/CultMath.Unity.asmdef | 16 - unity/org.gamecult.cultmath/LICENSE.md | 10 + unity/org.gamecult.cultmath/README.md | 28 ++ .../{ => org.gamecult.cultmath}/Runtime.meta | 2 +- .../Runtime/CultMath.asmdef | 16 + .../Runtime/CultMath.asmdef.meta} | 2 +- .../Runtime/Plugins.meta | 8 + .../Runtime/Plugins/CultMath.dll | Bin 0 -> 44544 bytes .../Runtime/Plugins/CultMath.dll.meta | 21 ++ .../Runtime/Plugins/CultMath.pdb | Bin 0 -> 23424 bytes .../Runtime/Plugins/CultMath.pdb.meta | 4 +- unity/org.gamecult.cultmath/Shaders.meta | 8 + .../Shaders/CultMath.hlsl | 302 ++++++++++++++++++ .../Shaders/CultMath.hlsl.meta | 7 + .../THIRD-PARTY-NOTICES.md | 11 + .../org.gamecult.cultmath/package.json | 11 +- 19 files changed, 542 insertions(+), 33 deletions(-) create mode 100644 scripts/build-unity-package.ps1 delete mode 100644 unity/Runtime/CultMath.Unity.asmdef create mode 100644 unity/org.gamecult.cultmath/LICENSE.md create mode 100644 unity/org.gamecult.cultmath/README.md rename unity/{ => org.gamecult.cultmath}/Runtime.meta (77%) create mode 100644 unity/org.gamecult.cultmath/Runtime/CultMath.asmdef rename unity/{Runtime/CultMath.Unity.asmdef.meta => org.gamecult.cultmath/Runtime/CultMath.asmdef.meta} (76%) create mode 100644 unity/org.gamecult.cultmath/Runtime/Plugins.meta create mode 100644 unity/org.gamecult.cultmath/Runtime/Plugins/CultMath.dll create mode 100644 unity/org.gamecult.cultmath/Runtime/Plugins/CultMath.dll.meta create mode 100644 unity/org.gamecult.cultmath/Runtime/Plugins/CultMath.pdb rename package.json.meta => unity/org.gamecult.cultmath/Runtime/Plugins/CultMath.pdb.meta (60%) create mode 100644 unity/org.gamecult.cultmath/Shaders.meta create mode 100644 unity/org.gamecult.cultmath/Shaders/CultMath.hlsl create mode 100644 unity/org.gamecult.cultmath/Shaders/CultMath.hlsl.meta create mode 100644 unity/org.gamecult.cultmath/THIRD-PARTY-NOTICES.md rename package.json => unity/org.gamecult.cultmath/package.json (52%) diff --git a/.gitignore b/.gitignore index 3779002b..c9b141d0 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ target/ **/target/ /native/cultmath-core/target.meta .tools/ +/artifacts/ diff --git a/README.md b/README.md index b471c7fd..02d47752 100644 --- a/README.md +++ b/README.md @@ -73,21 +73,24 @@ dotnet build CultMath.slnx dotnet test CultMath.slnx cargo test --manifest-path native/cultmath-core/Cargo.toml cargo build --release --manifest-path native/cultmath-core/Cargo.toml +.\scripts\build-unity-package.ps1 ``` -## Unity compiler +## Unity package -CultMath uses C# 10 record structs and file-scoped namespaces. Unity projects -must select the compiler's latest language mode with an `Assets/csc.rsp` file: +CultMath's Unity 2021.3 surface is the tracked precompiled package at +`unity/org.gamecult.cultmath`. Unity consumes `CultMath.dll` and the numeric +`CultMath.hlsl`; it does not compile the repository's current-language C# source +tree and does not require a consumer `csc.rsp` workaround. -```text --langversion:latest +```json +"org.gamecult.cultmath": "https://github.com/GameCult/CultMath.git?path=/unity/org.gamecult.cultmath" ``` -The package's Unity smoke project verifies this contract against Unity 6. The -setting is already present in current GameCult Unity clients; it belongs to the -consumer project because Unity only reads compiler response files from its -`Assets` root. +The repository root is not a Unity package. Build the tracked package with +`scripts/build-unity-package.ps1`; the script fresh-builds the netstandard2.1 +assembly and rejects stale binaries, missing metadata, unexpected assemblies, +or leaked C# source. ## Shader Tooling diff --git a/scripts/build-unity-package.ps1 b/scripts/build-unity-package.ps1 new file mode 100644 index 00000000..329cedb7 --- /dev/null +++ b/scripts/build-unity-package.ps1 @@ -0,0 +1,107 @@ +param( + [string] $Configuration = "Release", + [string] $OutputDirectory = "artifacts\unity\org.gamecult.cultmath" +) + +$ErrorActionPreference = "Stop" + +$repoRoot = Split-Path -Parent $PSScriptRoot +$projectPath = Join-Path $repoRoot "src\CultMath\CultMath.csproj" +$templateRoot = Join-Path $repoRoot "unity\org.gamecult.cultmath" +$buildRoot = Join-Path $repoRoot "artifacts\cultmath-unity-build" +$outputRoot = if ([System.IO.Path]::IsPathRooted($OutputDirectory)) { + $OutputDirectory +} else { + Join-Path $repoRoot $OutputDirectory +} +$freshAssembly = Join-Path $buildRoot "CultMath.dll" +$freshSymbols = Join-Path $buildRoot "CultMath.pdb" +$trackedPluginRoot = Join-Path $templateRoot "Runtime\Plugins" +$trackedAssembly = Join-Path $trackedPluginRoot "CultMath.dll" +$trackedSymbols = Join-Path $trackedPluginRoot "CultMath.pdb" + +if (Test-Path -LiteralPath $buildRoot) { + Remove-Item -LiteralPath $buildRoot -Recurse -Force +} +if (Test-Path -LiteralPath $outputRoot) { + Remove-Item -LiteralPath $outputRoot -Recurse -Force +} + +dotnet build $projectPath -c $Configuration -f netstandard2.1 -o $buildRoot ` + --disable-build-servers -p:UseSharedCompilation=false -p:ContinuousIntegrationBuild=true -m:1 +if ($LASTEXITCODE -ne 0) { + throw "CultMath Unity assembly build failed with exit code $LASTEXITCODE" +} + +foreach ($path in @($freshAssembly, $freshSymbols)) { + if (-not (Test-Path -LiteralPath $path -PathType Leaf)) { + throw "CultMath Unity build is missing $path" + } +} + +$requiredTemplateFiles = @( + "LICENSE.md", + "README.md", + "THIRD-PARTY-NOTICES.md", + "package.json", + "Runtime\CultMath.asmdef", + "Runtime\CultMath.asmdef.meta", + "Runtime\Plugins\CultMath.dll", + "Runtime\Plugins\CultMath.dll.meta", + "Runtime\Plugins\CultMath.pdb", + "Runtime\Plugins\CultMath.pdb.meta", + "Shaders\CultMath.hlsl", + "Shaders\CultMath.hlsl.meta" +) +foreach ($relativePath in $requiredTemplateFiles) { + if (-not (Test-Path -LiteralPath (Join-Path $templateRoot $relativePath) -PathType Leaf)) { + throw "Tracked CultMath Unity package is incomplete: missing $relativePath" + } +} + +$unityAssetFiles = @(Get-ChildItem -LiteralPath $templateRoot -Recurse -File | Where-Object { + $_.Extension -in @(".asmdef", ".dll", ".pdb", ".hlsl") +}) +$missingAssetMetas = @($unityAssetFiles | Where-Object { -not (Test-Path -LiteralPath ($_.FullName + ".meta")) }) +$missingDirectoryMetas = @(Get-ChildItem -LiteralPath $templateRoot -Recurse -Directory | Where-Object { + -not (Test-Path -LiteralPath ($_.FullName + ".meta")) +}) +if ($missingAssetMetas.Count -ne 0 -or $missingDirectoryMetas.Count -ne 0) { + $missing = @($missingAssetMetas.FullName) + @($missingDirectoryMetas.FullName) + throw "Tracked CultMath Unity package has assets without stable .meta files: $($missing -join ', ')" +} + +$manifest = Get-Content -LiteralPath (Join-Path $templateRoot "package.json") -Raw | ConvertFrom-Json +$expectedFileVersion = "$($manifest.version).0" +$trackedFileVersion = [Diagnostics.FileVersionInfo]::GetVersionInfo($trackedAssembly).FileVersion +$freshFileVersion = [Diagnostics.FileVersionInfo]::GetVersionInfo($freshAssembly).FileVersion +if ($trackedFileVersion -ne $expectedFileVersion -or $freshFileVersion -ne $expectedFileVersion) { + throw "CultMath Unity assemblies must match package version $expectedFileVersion; tracked=$trackedFileVersion fresh=$freshFileVersion" +} + +foreach ($pair in @(@($freshAssembly, $trackedAssembly), @($freshSymbols, $trackedSymbols))) { + $freshHash = (Get-FileHash -LiteralPath $pair[0] -Algorithm SHA256).Hash + $trackedHash = (Get-FileHash -LiteralPath $pair[1] -Algorithm SHA256).Hash + if ($freshHash -ne $trackedHash) { + throw "Tracked Unity artifact is stale: $($pair[1]) differs from a fresh deterministic build" + } +} + +$trackedSourceFiles = @(Get-ChildItem -LiteralPath $templateRoot -Recurse -File -Filter "*.cs") +if ($trackedSourceFiles.Count -ne 0) { + throw "CultMath Unity package must not compile repository C# sources: $($trackedSourceFiles.FullName -join ', ')" +} + +New-Item -ItemType Directory -Force -Path $outputRoot | Out-Null +Copy-Item -Path (Join-Path $templateRoot "*") -Destination $outputRoot -Recurse -Force + +$stagedAssemblies = @(Get-ChildItem -LiteralPath (Join-Path $outputRoot "Runtime\Plugins") -Filter "*.dll") +$stagedSources = @(Get-ChildItem -LiteralPath $outputRoot -Recurse -File -Filter "*.cs") +if ($stagedAssemblies.Count -ne 1 -or $stagedAssemblies[0].Name -ne "CultMath.dll" -or $stagedSources.Count -ne 0) { + throw "CultMath package must contain one owned DLL and no C# source files" +} + +Write-Host "CultMath Unity package: $outputRoot" +Write-Host "Package: $($manifest.name)@$($manifest.version)" +Write-Host "Managed assemblies: $($stagedAssemblies.Count)" +Write-Host "C# source files: $($stagedSources.Count)" diff --git a/unity/Runtime/CultMath.Unity.asmdef b/unity/Runtime/CultMath.Unity.asmdef deleted file mode 100644 index 632c4e4c..00000000 --- a/unity/Runtime/CultMath.Unity.asmdef +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "CultMath.Unity", - "rootNamespace": "CultMath.Unity", - "references": [ - "CultMath" - ], - "includePlatforms": [], - "excludePlatforms": [], - "allowUnsafeCode": false, - "overrideReferences": false, - "precompiledReferences": [], - "autoReferenced": true, - "defineConstraints": [], - "versionDefines": [], - "noEngineReferences": false -} diff --git a/unity/org.gamecult.cultmath/LICENSE.md b/unity/org.gamecult.cultmath/LICENSE.md new file mode 100644 index 00000000..5e50f2d6 --- /dev/null +++ b/unity/org.gamecult.cultmath/LICENSE.md @@ -0,0 +1,10 @@ +# CultMath License + +CultMath is licensed under the Mozilla Public License 2.0 (`MPL-2.0`). + +The complete license text is available from the Mozilla Foundation at +. Source and modification history for the +precompiled assembly in this package are available in the GameCult/CultMath +repository at the corresponding package tag. + +Third-party code retains its original license. See `THIRD-PARTY-NOTICES.md`. diff --git a/unity/org.gamecult.cultmath/README.md b/unity/org.gamecult.cultmath/README.md new file mode 100644 index 00000000..1802ae9a --- /dev/null +++ b/unity/org.gamecult.cultmath/README.md @@ -0,0 +1,28 @@ +# CultMath for Unity + +This is CultMath's Unity 2021.3-compatible Git-UPM surface. It contains the +precompiled `CultMath.dll`, portable symbols, and the numeric +`Shaders/CultMath.hlsl` mirror. + +Unity does not compile CultMath's repository source tree. That source uses the +current C# language and remains owned by the normal .NET project. The package +facade references only the tracked precompiled assembly, so consumers do not +need `csc.rsp` language overrides. + +Build and inspect the package from the repository root: + +```powershell +.\scripts\build-unity-package.ps1 +``` + +The builder fresh-builds CultMath for `netstandard2.1`, verifies the tracked +DLL/PDB and stable Unity metadata, and stages an inspectable package under +`artifacts/unity/org.gamecult.cultmath`. + +Consume the repository package with: + +```json +"org.gamecult.cultmath": "https://github.com/GameCult/CultMath.git?path=/unity/org.gamecult.cultmath" +``` + +Production consumers should pin that URL to a commit or release tag. diff --git a/unity/Runtime.meta b/unity/org.gamecult.cultmath/Runtime.meta similarity index 77% rename from unity/Runtime.meta rename to unity/org.gamecult.cultmath/Runtime.meta index 8e0678f8..b0e76599 100644 --- a/unity/Runtime.meta +++ b/unity/org.gamecult.cultmath/Runtime.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 8226365c03c5e1a438408b7e42b98740 +guid: a31bf2bb35e54dd1ad1c765337682769 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/unity/org.gamecult.cultmath/Runtime/CultMath.asmdef b/unity/org.gamecult.cultmath/Runtime/CultMath.asmdef new file mode 100644 index 00000000..72c968e8 --- /dev/null +++ b/unity/org.gamecult.cultmath/Runtime/CultMath.asmdef @@ -0,0 +1,16 @@ +{ + "name": "CultMath", + "rootNamespace": "CultMath", + "references": [], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": true, + "overrideReferences": true, + "precompiledReferences": [ + "CultMath.dll" + ], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": true +} diff --git a/unity/Runtime/CultMath.Unity.asmdef.meta b/unity/org.gamecult.cultmath/Runtime/CultMath.asmdef.meta similarity index 76% rename from unity/Runtime/CultMath.Unity.asmdef.meta rename to unity/org.gamecult.cultmath/Runtime/CultMath.asmdef.meta index 2dd3a36a..0ec09c2f 100644 --- a/unity/Runtime/CultMath.Unity.asmdef.meta +++ b/unity/org.gamecult.cultmath/Runtime/CultMath.asmdef.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: d1906c397c420ae4eb222a3f09f36843 +guid: 4b5c49d478124399a5310d7a9d8ed166 AssemblyDefinitionImporter: externalObjects: {} userData: diff --git a/unity/org.gamecult.cultmath/Runtime/Plugins.meta b/unity/org.gamecult.cultmath/Runtime/Plugins.meta new file mode 100644 index 00000000..fe8acafa --- /dev/null +++ b/unity/org.gamecult.cultmath/Runtime/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f84156013e814c14b73f668b6610b9e0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/unity/org.gamecult.cultmath/Runtime/Plugins/CultMath.dll b/unity/org.gamecult.cultmath/Runtime/Plugins/CultMath.dll new file mode 100644 index 0000000000000000000000000000000000000000..8cdb6700145956da7fb303fc1d9b0a39f19c91a4 GIT binary patch literal 44544 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 literal 0 HcmV?d00001 diff --git a/package.json.meta b/unity/org.gamecult.cultmath/Runtime/Plugins/CultMath.pdb.meta similarity index 60% rename from package.json.meta rename to unity/org.gamecult.cultmath/Runtime/Plugins/CultMath.pdb.meta index 23ed71cf..e18fedbe 100644 --- a/package.json.meta +++ b/unity/org.gamecult.cultmath/Runtime/Plugins/CultMath.pdb.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: 1abf066549a826c4ba7a30d6676735c0 -PackageManifestImporter: +guid: a8cc555f643a4d7eb4dd340025b208f6 +DefaultImporter: externalObjects: {} userData: assetBundleName: diff --git a/unity/org.gamecult.cultmath/Shaders.meta b/unity/org.gamecult.cultmath/Shaders.meta new file mode 100644 index 00000000..1e7e7110 --- /dev/null +++ b/unity/org.gamecult.cultmath/Shaders.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ca5d773061ed49b3a173526048d40cb3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/unity/org.gamecult.cultmath/Shaders/CultMath.hlsl b/unity/org.gamecult.cultmath/Shaders/CultMath.hlsl new file mode 100644 index 00000000..4c00fb69 --- /dev/null +++ b/unity/org.gamecult.cultmath/Shaders/CultMath.hlsl @@ -0,0 +1,302 @@ +#ifndef CULTMATH_HLSL +#define CULTMATH_HLSL + +// CultMath HLSL mirror. +// +// HLSL already owns the float2/float3/float4 type names and most primitive +// intrinsics. This include names the CultMath semantic surface explicitly so +// shader code, C# wrappers, and Rust/native parity fixtures can share the same +// small vocabulary without local helper drift. + +static const float CULTMATH_PI = 3.14159265358979323846; +static const float CULTMATH_TAU = 6.28318530717958647692; +static const float CULTMATH_HALF_PI = 1.57079632679489661923; +static const float CULTMATH_NORMALIZE_EPSILON = 1.0e-20; + +float cultmath_radians(float degrees_value) { return degrees_value * (CULTMATH_PI / 180.0); } +float cultmath_degrees(float radians_value) { return radians_value * (180.0 / CULTMATH_PI); } + +float cultmath_frac(float value) { return value - floor(value); } +float2 cultmath_frac(float2 value) { return value - floor(value); } +float3 cultmath_frac(float3 value) { return value - floor(value); } +float4 cultmath_frac(float4 value) { return value - floor(value); } + +float cultmath_clamp(float value, float minimum, float maximum) { return min(max(value, minimum), maximum); } +float2 cultmath_clamp(float2 value, float2 minimum, float2 maximum) { return min(max(value, minimum), maximum); } +float3 cultmath_clamp(float3 value, float3 minimum, float3 maximum) { return min(max(value, minimum), maximum); } +float4 cultmath_clamp(float4 value, float4 minimum, float4 maximum) { return min(max(value, minimum), maximum); } + +float cultmath_saturate(float value) { return cultmath_clamp(value, 0.0, 1.0); } +float2 cultmath_saturate(float2 value) { return cultmath_clamp(value, float2(0.0, 0.0), float2(1.0, 1.0)); } +float3 cultmath_saturate(float3 value) { return cultmath_clamp(value, float3(0.0, 0.0, 0.0), float3(1.0, 1.0, 1.0)); } +float4 cultmath_saturate(float4 value) { return cultmath_clamp(value, float4(0.0, 0.0, 0.0, 0.0), float4(1.0, 1.0, 1.0, 1.0)); } + +float cultmath_lerp(float start, float end, float amount) { return start + (end - start) * amount; } +float2 cultmath_lerp(float2 start, float2 end, float2 amount) { return start + (end - start) * amount; } +float3 cultmath_lerp(float3 start, float3 end, float3 amount) { return start + (end - start) * amount; } +float4 cultmath_lerp(float4 start, float4 end, float4 amount) { return start + (end - start) * amount; } + +float cultmath_step(float edge, float value) { return value < edge ? 0.0 : 1.0; } +float2 cultmath_step(float2 edge, float2 value) { return float2(cultmath_step(edge.x, value.x), cultmath_step(edge.y, value.y)); } +float3 cultmath_step(float3 edge, float3 value) { return float3(cultmath_step(edge.x, value.x), cultmath_step(edge.y, value.y), cultmath_step(edge.z, value.z)); } +float4 cultmath_step(float4 edge, float4 value) { return float4(cultmath_step(edge.x, value.x), cultmath_step(edge.y, value.y), cultmath_step(edge.z, value.z), cultmath_step(edge.w, value.w)); } + +float cultmath_smoothstep(float minimum, float maximum, float value) +{ + float t = cultmath_saturate((value - minimum) / (maximum - minimum)); + return t * t * (3.0 - 2.0 * t); +} + +float2 cultmath_smoothstep(float2 minimum, float2 maximum, float2 value) +{ + float2 t = cultmath_saturate((value - minimum) / (maximum - minimum)); + return t * t * (float2(3.0, 3.0) - float2(2.0, 2.0) * t); +} + +float3 cultmath_smoothstep(float3 minimum, float3 maximum, float3 value) +{ + float3 t = cultmath_saturate((value - minimum) / (maximum - minimum)); + return t * t * (float3(3.0, 3.0, 3.0) - float3(2.0, 2.0, 2.0) * t); +} + +float4 cultmath_smoothstep(float4 minimum, float4 maximum, float4 value) +{ + float4 t = cultmath_saturate((value - minimum) / (maximum - minimum)); + return t * t * (float4(3.0, 3.0, 3.0, 3.0) - float4(2.0, 2.0, 2.0, 2.0) * t); +} + +float cultmath_smoothstep01(float value) { return cultmath_smoothstep(0.0, 1.0, value); } + +float cultmath_smootherstep(float value) +{ + value = cultmath_saturate(value); + return value * value * value * (value * (value * 6.0 - 15.0) + 10.0); +} + +float2 cultmath_simplex_mod289(float2 value) { return value - floor(value * (1.0 / 289.0)) * 289.0; } +float3 cultmath_simplex_mod289(float3 value) { return value - floor(value * (1.0 / 289.0)) * 289.0; } +float3 cultmath_simplex_permute(float3 value) { return cultmath_simplex_mod289(((value * 34.0) + 1.0) * value); } + +float cultmath_simplex_noise(float2 value) +{ + const float4 c = float4( + 0.211324865405187, + 0.366025403784439, + -0.577350269189626, + 0.024390243902439); + float2 i = floor(value + dot(value, c.yy)); + float2 x0 = value - i + dot(i, c.xx); + float2 i1 = x0.x > x0.y ? float2(1.0, 0.0) : float2(0.0, 1.0); + float4 x12 = float4(x0.x + c.x - i1.x, x0.y + c.x - i1.y, x0.x + c.z, x0.y + c.z); + + i = cultmath_simplex_mod289(i); + float3 p = cultmath_simplex_permute( + cultmath_simplex_permute(i.y + float3(0.0, i1.y, 1.0)) + i.x + float3(0.0, i1.x, 1.0)); + float3 m = max(0.5 - float3(dot(x0, x0), dot(x12.xy, x12.xy), dot(x12.zw, x12.zw)), 0.0); + m *= m; + m *= m; + + float3 x = 2.0 * frac(p * c.w) - 1.0; + float3 h = abs(x) - 0.5; + float3 ox = floor(x + 0.5); + float3 a0 = x - ox; + m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h); + + float3 g = float3( + a0.x * x0.x + h.x * x0.y, + a0.y * x12.x + h.y * x12.y, + a0.z * x12.z + h.z * x12.w); + return 130.0 * dot(m, g); +} + +float cultmath_lengthsq(float2 value) { return dot(value, value); } +float cultmath_lengthsq(float3 value) { return dot(value, value); } +float cultmath_lengthsq(float4 value) { return dot(value, value); } + +float cultmath_distance(float2 left, float2 right) { return length(left - right); } +float cultmath_distance(float3 left, float3 right) { return length(left - right); } +float cultmath_distance(float4 left, float4 right) { return length(left - right); } + +float2 cultmath_normalize(float2 value) { return value / max(length(value), CULTMATH_NORMALIZE_EPSILON); } +float3 cultmath_normalize(float3 value) { return value / max(length(value), CULTMATH_NORMALIZE_EPSILON); } +float4 cultmath_normalize(float4 value) { return value / max(length(value), CULTMATH_NORMALIZE_EPSILON); } + +float2 cultmath_reflect(float2 incident, float2 normal_value) +{ + return incident - 2.0 * dot(normal_value, incident) * normal_value; +} + +float3 cultmath_reflect(float3 incident, float3 normal_value) +{ + return incident - 2.0 * dot(normal_value, incident) * normal_value; +} + +float2 cultmath_rotate(float2 value, float radians_value) +{ + float s = sin(radians_value); + float c = cos(radians_value); + return float2(value.x * c - value.y * s, value.x * s + value.y * c); +} + +float2 cultmath_rotate_degrees(float2 value, float degrees_value) +{ + return cultmath_rotate(value, cultmath_radians(degrees_value)); +} + +float cultmath_csum(float2 value) { return value.x + value.y; } +float cultmath_csum(float3 value) { return value.x + value.y + value.z; } +float cultmath_csum(float4 value) { return value.x + value.y + value.z + value.w; } + +float cultmath_decay(float source, float lambda_value, float dt) { return source * exp(-lambda_value * dt); } +float2 cultmath_decay(float2 source, float lambda_value, float dt) { return source * exp(-lambda_value * dt); } +float3 cultmath_decay(float3 source, float lambda_value, float dt) { return source * exp(-lambda_value * dt); } +float4 cultmath_decay(float4 source, float lambda_value, float dt) { return source * exp(-lambda_value * dt); } + +float cultmath_damp(float start, float end, float lambda_value, float dt) +{ + return cultmath_lerp(start, end, 1.0 - exp(-lambda_value * dt)); +} + +float2 cultmath_damp(float2 start, float2 end, float lambda_value, float dt) +{ + return cultmath_lerp(start, end, 1.0 - exp(-lambda_value * dt)); +} + +float3 cultmath_damp(float3 start, float3 end, float lambda_value, float dt) +{ + return cultmath_lerp(start, end, 1.0 - exp(-lambda_value * dt)); +} + +float4 cultmath_damp(float4 start, float4 end, float lambda_value, float dt) +{ + return cultmath_lerp(start, end, 1.0 - exp(-lambda_value * dt)); +} + +float cultmath_catmullrom(float p0, float p1, float p2, float p3, float t) +{ + float t2 = t * t; + float t3 = t2 * t; + return 0.5 * ((2.0 * p1) + (p2 - p0) * t + (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) * t2 + (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3); +} + +float2 cultmath_catmullrom(float2 p0, float2 p1, float2 p2, float2 p3, float t) +{ + float t2 = t * t; + float t3 = t2 * t; + return 0.5 * ((2.0 * p1) + (p2 - p0) * t + (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) * t2 + (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3); +} + +float3 cultmath_catmullrom(float3 p0, float3 p1, float3 p2, float3 p3, float t) +{ + float t2 = t * t; + float t3 = t2 * t; + return 0.5 * ((2.0 * p1) + (p2 - p0) * t + (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) * t2 + (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3); +} + +float4 cultmath_catmullrom(float4 p0, float4 p1, float4 p2, float4 p3, float t) +{ + float t2 = t * t; + float t3 = t2 * t; + return 0.5 * ((2.0 * p1) + (p2 - p0) * t + (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) * t2 + (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3); +} + +float cultmath_quadratic_bezier(float p0, float p1, float p2, float t) +{ + t = cultmath_saturate(t); + float inv = 1.0 - t; + return inv * inv * p0 + 2.0 * inv * t * p1 + t * t * p2; +} + +float3 cultmath_quadratic_bezier(float3 p0, float3 p1, float3 p2, float t) +{ + t = cultmath_saturate(t); + float inv = 1.0 - t; + return inv * inv * p0 + 2.0 * inv * t * p1 + t * t * p2; +} + +float cultmath_cubic_bezier(float p0, float p1, float p2, float p3, float t) +{ + t = cultmath_saturate(t); + float inv = 1.0 - t; + return inv * inv * inv * p0 + 3.0 * inv * inv * t * p1 + 3.0 * inv * t * t * p2 + t * t * t * p3; +} + +float3 cultmath_cubic_bezier(float3 p0, float3 p1, float3 p2, float3 p3, float t) +{ + t = cultmath_saturate(t); + float inv = 1.0 - t; + return inv * inv * inv * p0 + 3.0 * inv * inv * t * p1 + 3.0 * inv * t * t * p2 + t * t * t * p3; +} + +float cultmath_hash(float value) { return cultmath_frac(sin(value) * 43758.5453); } +float cultmath_hash(float2 value) { return cultmath_hash(dot(value, float2(127.1, 311.7))); } +float cultmath_hash(float3 value) { return cultmath_hash(dot(value, float3(127.1, 311.7, 74.7))); } + +float cultmath_value_noise(float2 position) +{ + float2 cell = floor(position); + float2 local = cultmath_frac(position); + float2 u = local * local * (float2(3.0, 3.0) - float2(2.0, 2.0) * local); + + float a = cultmath_hash(cell); + float b = cultmath_hash(cell + float2(1.0, 0.0)); + float c = cultmath_hash(cell + float2(0.0, 1.0)); + float d = cultmath_hash(cell + float2(1.0, 1.0)); + + return cultmath_lerp(cultmath_lerp(a, b, u.x), cultmath_lerp(c, d, u.x), u.y); +} + +float cultmath_value_noise_bicubic(float2 position) +{ + float2 cell = floor(position); + float2 local = cultmath_frac(position); + + float y0 = cultmath_catmullrom(cultmath_hash(cell + float2(-1.0, -1.0)), cultmath_hash(cell + float2(0.0, -1.0)), cultmath_hash(cell + float2(1.0, -1.0)), cultmath_hash(cell + float2(2.0, -1.0)), local.x); + float y1 = cultmath_catmullrom(cultmath_hash(cell + float2(-1.0, 0.0)), cultmath_hash(cell + float2(0.0, 0.0)), cultmath_hash(cell + float2(1.0, 0.0)), cultmath_hash(cell + float2(2.0, 0.0)), local.x); + float y2 = cultmath_catmullrom(cultmath_hash(cell + float2(-1.0, 1.0)), cultmath_hash(cell + float2(0.0, 1.0)), cultmath_hash(cell + float2(1.0, 1.0)), cultmath_hash(cell + float2(2.0, 1.0)), local.x); + float y3 = cultmath_catmullrom(cultmath_hash(cell + float2(-1.0, 2.0)), cultmath_hash(cell + float2(0.0, 2.0)), cultmath_hash(cell + float2(1.0, 2.0)), cultmath_hash(cell + float2(2.0, 2.0)), local.x); + + return cultmath_catmullrom(y0, y1, y2, y3, local.y); +} + +float cultmath_value_noise_texture(Texture2D noise_texture, SamplerState noise_sampler, float2 uv, float scale) +{ + return noise_texture.SampleLevel(noise_sampler, uv * scale, 0.0).r; +} + +float cultmath_value_noise_texture_bicubic(Texture2D noise_texture, SamplerState noise_sampler, float2 uv, float scale, float2 texel_size) +{ + float2 position = uv * scale; + float2 cell = floor(position); + float2 local = cultmath_frac(position); + float2 base_uv = cell / scale; + + float row0 = cultmath_catmullrom( + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(-1.0, -1.0), 0.0).r, + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(0.0, -1.0), 0.0).r, + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(1.0, -1.0), 0.0).r, + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(2.0, -1.0), 0.0).r, + local.x); + float row1 = cultmath_catmullrom( + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(-1.0, 0.0), 0.0).r, + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(0.0, 0.0), 0.0).r, + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(1.0, 0.0), 0.0).r, + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(2.0, 0.0), 0.0).r, + local.x); + float row2 = cultmath_catmullrom( + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(-1.0, 1.0), 0.0).r, + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(0.0, 1.0), 0.0).r, + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(1.0, 1.0), 0.0).r, + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(2.0, 1.0), 0.0).r, + local.x); + float row3 = cultmath_catmullrom( + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(-1.0, 2.0), 0.0).r, + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(0.0, 2.0), 0.0).r, + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(1.0, 2.0), 0.0).r, + noise_texture.SampleLevel(noise_sampler, base_uv + texel_size * float2(2.0, 2.0), 0.0).r, + local.x); + + return cultmath_catmullrom(row0, row1, row2, row3, local.y); +} + +#endif diff --git a/unity/org.gamecult.cultmath/Shaders/CultMath.hlsl.meta b/unity/org.gamecult.cultmath/Shaders/CultMath.hlsl.meta new file mode 100644 index 00000000..d3b6d2b3 --- /dev/null +++ b/unity/org.gamecult.cultmath/Shaders/CultMath.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a46136cb4acb4ff2bc47b6a4f786e4b3 +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/unity/org.gamecult.cultmath/THIRD-PARTY-NOTICES.md b/unity/org.gamecult.cultmath/THIRD-PARTY-NOTICES.md new file mode 100644 index 00000000..c283df2b --- /dev/null +++ b/unity/org.gamecult.cultmath/THIRD-PARTY-NOTICES.md @@ -0,0 +1,11 @@ +# Third-Party Notices + +## 2D Simplex Noise + +`math.simplex_noise` and `cultmath_simplex_noise` port the textureless 2D +simplex-noise function by Ian McEwan and Ashima Arts, as distributed by Stefan +Gustavson's `webgl-noise` project and Unity Mathematics. + +- Copyright 2011 Ashima Arts. +- Upstream: +- License: MIT. diff --git a/package.json b/unity/org.gamecult.cultmath/package.json similarity index 52% rename from package.json rename to unity/org.gamecult.cultmath/package.json index 6da2a17a..e45d0a35 100644 --- a/package.json +++ b/unity/org.gamecult.cultmath/package.json @@ -3,12 +3,15 @@ "displayName": "CultMath", "version": "0.1.0", "unity": "2021.3", - "description": "Clean-room C# math primitives shaped for HLSL-style renderer and simulation code.", + "description": "Precompiled CultMath numeric primitives and matching HLSL semantics for GameCult Unity runtimes.", + "license": "MPL-2.0", + "author": { + "name": "GameCult" + }, "keywords": [ "GameCult", "Math", + "HLSL", "Simulation" - ], - "license": "MPL-2.0", - "category": "Scripting" + ] } From 4fcb181d8dc58229ac1810be1ff8fff98d64c82b Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 04:59:59 +0100 Subject: [PATCH 045/283] Make Geometry Unity sources C# 9 compatible --- .../Runtime/Unity/PlanetaryPageUpload.cs | 4 +++- .../Runtime/Unity/PlanetaryPatchMeshAdapter.cs | 4 +++- .../Editor/GameCultGeometryPlanetaryViewerMenu.cs | 4 +++- .../Runtime/GameCultGeometryPlanetaryViewer.cs | 4 +++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/unity/org.gamecult.geometry/Runtime/Unity/PlanetaryPageUpload.cs b/unity/org.gamecult.geometry/Runtime/Unity/PlanetaryPageUpload.cs index 8e0b431e..195903b4 100644 --- a/unity/org.gamecult.geometry/Runtime/Unity/PlanetaryPageUpload.cs +++ b/unity/org.gamecult.geometry/Runtime/Unity/PlanetaryPageUpload.cs @@ -5,7 +5,8 @@ using System.Runtime.InteropServices; using CultMath; using UnityEngine; -namespace GameCult.Geometry.Unity; +namespace GameCult.Geometry.Unity +{ [StructLayout(LayoutKind.Sequential)] public readonly struct PlanetaryPageInputGpu { public PlanetaryPageInputGpu(Vector4 directionRadius, Vector4 sampling) { DirectionRadius = directionRadius; Sampling = sampling; } public readonly Vector4 DirectionRadius; public readonly Vector4 Sampling; } [StructLayout(LayoutKind.Sequential)] public readonly struct PlanetaryPageMetadataGpu { public PlanetaryPageMetadataGpu(Vector4 address, Vector4 layout, Vector4 bounds, Vector4 state) { Address = address; Layout = layout; Bounds = bounds; State = state; } public readonly Vector4 Address; public readonly Vector4 Layout; public readonly Vector4 Bounds; public readonly Vector4 State; } @@ -27,3 +28,4 @@ public static class PlanetaryPageUploadBuilder } private static Vector4 ToUnity(float4 value) => new(value.x, value.y, value.z, value.w); } +} diff --git a/unity/org.gamecult.geometry/Runtime/Unity/PlanetaryPatchMeshAdapter.cs b/unity/org.gamecult.geometry/Runtime/Unity/PlanetaryPatchMeshAdapter.cs index 8e758426..111b9931 100644 --- a/unity/org.gamecult.geometry/Runtime/Unity/PlanetaryPatchMeshAdapter.cs +++ b/unity/org.gamecult.geometry/Runtime/Unity/PlanetaryPatchMeshAdapter.cs @@ -3,7 +3,8 @@ using CultMath; using UnityEngine; using UnityEngine.Rendering; -namespace GameCult.Geometry.Unity; +namespace GameCult.Geometry.Unity +{ public static class PlanetaryPatchMeshAdapter { @@ -25,3 +26,4 @@ public static class PlanetaryPatchMeshAdapter mesh.RecalculateBounds(); return mesh; } } +} diff --git a/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Editor/GameCultGeometryPlanetaryViewerMenu.cs b/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Editor/GameCultGeometryPlanetaryViewerMenu.cs index e2a32d17..59ee6c22 100644 --- a/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Editor/GameCultGeometryPlanetaryViewerMenu.cs +++ b/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Editor/GameCultGeometryPlanetaryViewerMenu.cs @@ -2,7 +2,8 @@ using UnityEditor; using UnityEngine; using GameCult.Geometry.Unity.Samples; -namespace GameCult.Geometry.Unity.Samples.Editor; +namespace GameCult.Geometry.Unity.Samples.Editor +{ public static class GameCultGeometryPlanetaryViewerMenu { @@ -25,3 +26,4 @@ public static class GameCultGeometryPlanetaryViewerMenu camera.farClipPlane = 1000; } } +} diff --git a/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Runtime/GameCultGeometryPlanetaryViewer.cs b/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Runtime/GameCultGeometryPlanetaryViewer.cs index 2cfb0ce5..2f874747 100644 --- a/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Runtime/GameCultGeometryPlanetaryViewer.cs +++ b/unity/org.gamecult.geometry/Samples~/PlanetaryViewer/Runtime/GameCultGeometryPlanetaryViewer.cs @@ -4,7 +4,8 @@ using CultMath; using GameCult.Geometry; using UnityEngine; -namespace GameCult.Geometry.Unity.Samples; +namespace GameCult.Geometry.Unity.Samples +{ [ExecuteAlways] public sealed class GameCultGeometryPlanetaryViewer : MonoBehaviour @@ -139,3 +140,4 @@ public sealed class GameCultGeometryPlanetaryViewer : MonoBehaviour } } } +} From d91b59eb4a8c5a7db15cd30adcd6b33a8a3de206 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 05:05:56 +0100 Subject: [PATCH 046/283] Disambiguate Unity mesh adapter type --- .../Runtime/Unity/PlanetaryPatchMeshAdapter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unity/org.gamecult.geometry/Runtime/Unity/PlanetaryPatchMeshAdapter.cs b/unity/org.gamecult.geometry/Runtime/Unity/PlanetaryPatchMeshAdapter.cs index 111b9931..e880842d 100644 --- a/unity/org.gamecult.geometry/Runtime/Unity/PlanetaryPatchMeshAdapter.cs +++ b/unity/org.gamecult.geometry/Runtime/Unity/PlanetaryPatchMeshAdapter.cs @@ -8,7 +8,7 @@ namespace GameCult.Geometry.Unity public static class PlanetaryPatchMeshAdapter { - public static Mesh CreateFaceMesh(PlanetaryCubeFace face, int cellsPerAxis, float radius = 1) + public static UnityEngine.Mesh CreateFaceMesh(PlanetaryCubeFace face, int cellsPerAxis, float radius = 1) { if (!float.IsFinite(radius) || radius <= 0) throw new ArgumentOutOfRangeException(nameof(radius)); var source = PlanetaryPatch.CreateFace(face, cellsPerAxis); @@ -22,7 +22,7 @@ public static class PlanetaryPatchMeshAdapter vertices[i] = normal * radius; normals[i] = normal; uv[i] = new Vector2(source.Vertices[i].LocalCoordinate.x, source.Vertices[i].LocalCoordinate.y); } - var mesh = new Mesh { name = $"GameCult.Geometry Planetary {face} {cellsPerAxis}x{cellsPerAxis}", indexFormat = vertices.Length > ushort.MaxValue ? IndexFormat.UInt32 : IndexFormat.UInt16, vertices = vertices, normals = normals, uv = uv, triangles = source.Indices }; + var mesh = new UnityEngine.Mesh { name = $"GameCult.Geometry Planetary {face} {cellsPerAxis}x{cellsPerAxis}", indexFormat = vertices.Length > ushort.MaxValue ? IndexFormat.UInt32 : IndexFormat.UInt16, vertices = vertices, normals = normals, uv = uv, triangles = source.Indices }; mesh.RecalculateBounds(); return mesh; } } From b43cf4904f855e3d1b6da8a949326aa031bc5219 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 05:07:32 +0100 Subject: [PATCH 047/283] Fix CultMath Unity plugin references --- scripts/build-unity-package.ps1 | 20 ++++++++++++++---- unity/org.gamecult.cultmath/LICENSE.md.meta | 2 ++ unity/org.gamecult.cultmath/README.md | 4 ++-- unity/org.gamecult.cultmath/README.md.meta | 2 ++ .../Runtime/CultMath.asmdef | 16 -------------- .../Runtime/CultMath.asmdef.meta | 7 ------ .../Runtime/Plugins/CultMath.dll | Bin 44544 -> 44544 bytes .../Runtime/Plugins/CultMath.dll.meta | 2 +- .../Runtime/Plugins/CultMath.pdb | Bin 23424 -> 23420 bytes .../THIRD-PARTY-NOTICES.md.meta | 2 ++ unity/org.gamecult.cultmath/package.json.meta | 2 ++ 11 files changed, 27 insertions(+), 30 deletions(-) create mode 100644 unity/org.gamecult.cultmath/LICENSE.md.meta create mode 100644 unity/org.gamecult.cultmath/README.md.meta delete mode 100644 unity/org.gamecult.cultmath/Runtime/CultMath.asmdef delete mode 100644 unity/org.gamecult.cultmath/Runtime/CultMath.asmdef.meta create mode 100644 unity/org.gamecult.cultmath/THIRD-PARTY-NOTICES.md.meta create mode 100644 unity/org.gamecult.cultmath/package.json.meta diff --git a/scripts/build-unity-package.ps1 b/scripts/build-unity-package.ps1 index 329cedb7..f5fcacc0 100644 --- a/scripts/build-unity-package.ps1 +++ b/scripts/build-unity-package.ps1 @@ -41,11 +41,13 @@ foreach ($path in @($freshAssembly, $freshSymbols)) { $requiredTemplateFiles = @( "LICENSE.md", + "LICENSE.md.meta", "README.md", + "README.md.meta", "THIRD-PARTY-NOTICES.md", + "THIRD-PARTY-NOTICES.md.meta", "package.json", - "Runtime\CultMath.asmdef", - "Runtime\CultMath.asmdef.meta", + "package.json.meta", "Runtime\Plugins\CultMath.dll", "Runtime\Plugins\CultMath.dll.meta", "Runtime\Plugins\CultMath.pdb", @@ -72,6 +74,14 @@ if ($missingAssetMetas.Count -ne 0 -or $missingDirectoryMetas.Count -ne 0) { } $manifest = Get-Content -LiteralPath (Join-Path $templateRoot "package.json") -Raw | ConvertFrom-Json +$pluginMeta = Get-Content -LiteralPath ($trackedAssembly + ".meta") -Raw +if ($pluginMeta -notmatch '(?m)^\s*isExplicitlyReferenced:\s*0\s*$') { + throw "CultMath.dll must be auto-referenced; explicit-only plugins do not reach dependent Unity asmdefs" +} +$facadeDefinitions = @(Get-ChildItem -LiteralPath $templateRoot -Recurse -File -Filter "*.asmdef") +if ($facadeDefinitions.Count -ne 0) { + throw "CultMath's precompiled DLL is the Unity assembly authority; empty asmdef facades are forbidden" +} $expectedFileVersion = "$($manifest.version).0" $trackedFileVersion = [Diagnostics.FileVersionInfo]::GetVersionInfo($trackedAssembly).FileVersion $freshFileVersion = [Diagnostics.FileVersionInfo]::GetVersionInfo($freshAssembly).FileVersion @@ -97,11 +107,13 @@ Copy-Item -Path (Join-Path $templateRoot "*") -Destination $outputRoot -Recurse $stagedAssemblies = @(Get-ChildItem -LiteralPath (Join-Path $outputRoot "Runtime\Plugins") -Filter "*.dll") $stagedSources = @(Get-ChildItem -LiteralPath $outputRoot -Recurse -File -Filter "*.cs") -if ($stagedAssemblies.Count -ne 1 -or $stagedAssemblies[0].Name -ne "CultMath.dll" -or $stagedSources.Count -ne 0) { - throw "CultMath package must contain one owned DLL and no C# source files" +$stagedFacades = @(Get-ChildItem -LiteralPath $outputRoot -Recurse -File -Filter "*.asmdef") +if ($stagedAssemblies.Count -ne 1 -or $stagedAssemblies[0].Name -ne "CultMath.dll" -or $stagedSources.Count -ne 0 -or $stagedFacades.Count -ne 0) { + throw "CultMath package must contain one owned auto-referenced DLL, no C# source files, and no asmdef facade" } Write-Host "CultMath Unity package: $outputRoot" Write-Host "Package: $($manifest.name)@$($manifest.version)" Write-Host "Managed assemblies: $($stagedAssemblies.Count)" Write-Host "C# source files: $($stagedSources.Count)" +Write-Host "Asmdef facades: $($stagedFacades.Count)" diff --git a/unity/org.gamecult.cultmath/LICENSE.md.meta b/unity/org.gamecult.cultmath/LICENSE.md.meta new file mode 100644 index 00000000..c234cd28 --- /dev/null +++ b/unity/org.gamecult.cultmath/LICENSE.md.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7172bce28532878409e57f5fbbb12719 \ No newline at end of file diff --git a/unity/org.gamecult.cultmath/README.md b/unity/org.gamecult.cultmath/README.md index 1802ae9a..223e16ce 100644 --- a/unity/org.gamecult.cultmath/README.md +++ b/unity/org.gamecult.cultmath/README.md @@ -6,8 +6,8 @@ precompiled `CultMath.dll`, portable symbols, and the numeric Unity does not compile CultMath's repository source tree. That source uses the current C# language and remains owned by the normal .NET project. The package -facade references only the tracked precompiled assembly, so consumers do not -need `csc.rsp` language overrides. +imports only the tracked auto-referenced precompiled assembly, so consumers do +not need `csc.rsp` language overrides or an asmdef propagation shim. Build and inspect the package from the repository root: diff --git a/unity/org.gamecult.cultmath/README.md.meta b/unity/org.gamecult.cultmath/README.md.meta new file mode 100644 index 00000000..0ea270c2 --- /dev/null +++ b/unity/org.gamecult.cultmath/README.md.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: b7429934026d747489a3876fd15576e5 \ No newline at end of file diff --git a/unity/org.gamecult.cultmath/Runtime/CultMath.asmdef b/unity/org.gamecult.cultmath/Runtime/CultMath.asmdef deleted file mode 100644 index 72c968e8..00000000 --- a/unity/org.gamecult.cultmath/Runtime/CultMath.asmdef +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "CultMath", - "rootNamespace": "CultMath", - "references": [], - "includePlatforms": [], - "excludePlatforms": [], - "allowUnsafeCode": true, - "overrideReferences": true, - "precompiledReferences": [ - "CultMath.dll" - ], - "autoReferenced": true, - "defineConstraints": [], - "versionDefines": [], - "noEngineReferences": true -} diff --git a/unity/org.gamecult.cultmath/Runtime/CultMath.asmdef.meta b/unity/org.gamecult.cultmath/Runtime/CultMath.asmdef.meta deleted file mode 100644 index 0ec09c2f..00000000 --- a/unity/org.gamecult.cultmath/Runtime/CultMath.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 4b5c49d478124399a5310d7a9d8ed166 -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/unity/org.gamecult.cultmath/Runtime/Plugins/CultMath.dll b/unity/org.gamecult.cultmath/Runtime/Plugins/CultMath.dll index 8cdb6700145956da7fb303fc1d9b0a39f19c91a4..91b51d8d33ed8fcbc53a66b07131e2442f17c464 100644 GIT binary patch delta 237 zcmZp;!_;txX+j6fe6!yD8+&SI3Md?&m2hM4B;O@kA8G1bU4B{@0G&^*Z;h*FX)EmP7`4b2lL=PZ4|A~n_c#^iuy0Rl^PQ$L;D z?&myz@rr5F%r?HBykVKI0#xv`JX8>X6bNim|0qwnx&Ye z87HQunweUfB&C_An423Un;07#8>E>gSsEJ|8CzH;PtIBTfaR_B{x6dQmIVlCu1PV9 zi%@ZzAR}tDy=kS#VxcJanfKBdd7u~~MxH;ca+gC&CngDHa< zLkfclLmGoILn1>e5SjtSEP*0PKrvIGoH-C0FeC#-jKR~ZW6WR#gvLNqEE$qF JZ(r@n1OOHGN4Wq1 diff --git a/unity/org.gamecult.cultmath/Runtime/Plugins/CultMath.dll.meta b/unity/org.gamecult.cultmath/Runtime/Plugins/CultMath.dll.meta index d9935b36..917e3849 100644 --- a/unity/org.gamecult.cultmath/Runtime/Plugins/CultMath.dll.meta +++ b/unity/org.gamecult.cultmath/Runtime/Plugins/CultMath.dll.meta @@ -8,7 +8,7 @@ PluginImporter: defineConstraints: [] isPreloaded: 0 isOverridable: 0 - isExplicitlyReferenced: 1 + isExplicitlyReferenced: 0 validateReferences: 1 platformData: - first: diff --git a/unity/org.gamecult.cultmath/Runtime/Plugins/CultMath.pdb b/unity/org.gamecult.cultmath/Runtime/Plugins/CultMath.pdb index ed00f36e044b3063d654af2d537f4821c4c253f6..711cf76c53ef3d56a5f07fa25acb9c8532c93e3d 100644 GIT binary patch delta 2168 zcmZwHdr(wm7{~GV?5cZV5vhbEO^nMfEXZX+1T7Q@uprbSico{yMP=|-Nr^+PNMeIY zAW2>tBzIjeg+Z8Dc}t5DvqYT4%1B8{i7X`@%}d|I@@HrF^ZuUMbIx;~**WvBXpwI3 zm8zEbmP8BTm#|>5SqQN$H2>LrnYLR9GKAQWP!-ldV0wV+2|lc(@CC`8}DMM`m7@1is)g-kohlk_xjv0sE3 zDjqbrj3s4(h(|Kgk%=6bQ6S&tn>ti1G01Za<7St!q|7#`oLq}K?8i~Gp&gy*LeD_6 zq+z0OpqWbCHn=E*R6?eOAA%8qiHJus(vgWAn1kf0Y${O@Bu}NLk&7}&O(V5fHpoV< z!8+Kn3!mW#I`9K}aTPb=9jq1)BLE>VAr4cKiVS37b})~vu_{K{)WRy)Lcgs#a_<>cnn*jQu!@HngJ?UFbm{`tdIm zAv&SK2zcXR1Rw+^#9=B@k%27Ch82Z)5yel`P0w)@<2cO{xj^QNE z;AdRKAGn5FkjCqT8XoY%7z802Q}NVzolRs>%)wkN!pnFK<)}n0>fpp~?8QN};#*wC zRosFuOeY?|X!s)pQJ9P*q#+ZtV8wzkn@%jHD8cLKg(6%hLNNu?FcUdg2pg(l$NSia z!}uB}VTjO)a7@G$6h_D|uDhs?aM?i0whVH5QaI6okVto7iX3<=-9=pFaFK-Rcm@`f zp#qz+6+6+0797NvXpi&|o#;Xj5=|b$hJMV5@(>pMgF6@+?IGr2DZ974ttf@Whokv< zb%D>MD^YSSiF$vKUliP$ek|}fSof~=QzVAG6IALqdw3MzJQVj(feD=;^;g zr!TZ3GlCkj-nqD!E>i+u|z zv&KKO>ap1&JC<+vO5OfsL*}DlySDDo&Th#1)LC5Gy>M~t?+$BLe4{mg?WxLnKRwjc zA9CdAwQD&w^~s-?d7oZ2-+#%yReisPraf0ZzV2eN#gYEBbLDZ{p)B-OKV#`AZo!+RzL`Y+iJ9Y>YM1WXd;Bu$c1lBcrVr z%iM??+D9Ug|EfuWQVg(9A2V0f5eW_U;&6$B@ZQ$8#K1tg4!f=hBdr3Mb` zLmF%5f@qm%H+2+aL!e1fv-DWtk%|&=E8t)ot%`fhW%DRyu=~CYe|GPA{XXAw@BMx6 z@7#0G@3#|DO}n(~rO+CS5aDU%6-7db==bf31vwFEyMhA~+c&*uyQM#Sr)^iJlok>p ziI4FaKF7sKNob-Z;jfiMCMvK~O9!D4&04n)N!drZsjXk82-PXX$izb)Lg?I-q|AR( zAQ`CR;c%ny62UsRa8ee7bS%IkeiDpVZjhm8``9q6%STGCeSb#;yK_N<_tK!&!9V8w}z$?qUoxVthmxqG3QXtjNIASb{t(i{Z8Pc14iGN0iF7P_YI# zB`K?#^h%6M$Tp%Dd(gn3t9$L|kKKv6ma2t0q22Z_8Jb;G~q?g|}dDNFH0&OZ0 zI&sZcBO<>6dHWthd*k~)k)Pq*8J)CB|0|me!gtL5U};C$1j>s z?;bv!-~Yxd$=^jxUA))1HFit+KI?Alj>BznUw7>2RE^*3=r8&1mY4eV!HAIR6)8Qs ztj2^V{53sOyW8pw%@?N}+BM#q8{C;+9Cq|whw4$|`E0RVY+SMB})OtGobmYQmD`(x9lF@Nw%wtJT+U$P?1W#=_cfcGlqx`A# zz-iXPmX^jv8y24X(PA9AR#!K2VsB^9lWPXrzpT6W)E@hgv9K!e+tq1v?msrz-|=7j zCttf_<{#{+O4a}Ul-1hZ8~fGI@9*3D`ENILvvZq9P9z8Ct!=a?w{~~=9uE5Iq^W2) zcgy|j*W1J9zOm`mgrk0!Y~PRT`!CLX%N(|PR@UV{+vSGWedDV)va#CCsBC`0oZKD8pzblxdhfVrbV;cxmL$8m#I$Vr@+3>Dxv0cq zPfj)zn@uK@p~O;@YD!ErrKA?Ss^g+U9*&TlddZn7IiHoBFG$XE$yqHqce_q4nC>y< Wcka2aWzB!!cPF_tuJqhg#s2}kT^1(* diff --git a/unity/org.gamecult.cultmath/THIRD-PARTY-NOTICES.md.meta b/unity/org.gamecult.cultmath/THIRD-PARTY-NOTICES.md.meta new file mode 100644 index 00000000..a53f08d8 --- /dev/null +++ b/unity/org.gamecult.cultmath/THIRD-PARTY-NOTICES.md.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 0c88669e4d1db604588be2a726b7d231 \ No newline at end of file diff --git a/unity/org.gamecult.cultmath/package.json.meta b/unity/org.gamecult.cultmath/package.json.meta new file mode 100644 index 00000000..337ba716 --- /dev/null +++ b/unity/org.gamecult.cultmath/package.json.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 33d8d4af49bf0f946ad00a375f26b1d1 \ No newline at end of file From 4df2c2a42bb4a11fa9d49ffdcf1af6293ab09819 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 05:17:07 +0100 Subject: [PATCH 048/283] Add Geometry Unity EditMode package tests --- scripts/build-geometry-unity-package.ps1 | 8 +++ unity/org.gamecult.geometry/Tests.meta | 8 +++ unity/org.gamecult.geometry/Tests/Editor.meta | 8 +++ .../GameCult.Geometry.Tests.Editor.asmdef | 19 +++++++ ...GameCult.Geometry.Tests.Editor.asmdef.meta | 7 +++ .../Tests/Editor/GeometryPackageTests.cs | 54 +++++++++++++++++++ .../Tests/Editor/GeometryPackageTests.cs.meta | 11 ++++ 7 files changed, 115 insertions(+) create mode 100644 unity/org.gamecult.geometry/Tests.meta create mode 100644 unity/org.gamecult.geometry/Tests/Editor.meta create mode 100644 unity/org.gamecult.geometry/Tests/Editor/GameCult.Geometry.Tests.Editor.asmdef create mode 100644 unity/org.gamecult.geometry/Tests/Editor/GameCult.Geometry.Tests.Editor.asmdef.meta create mode 100644 unity/org.gamecult.geometry/Tests/Editor/GeometryPackageTests.cs create mode 100644 unity/org.gamecult.geometry/Tests/Editor/GeometryPackageTests.cs.meta diff --git a/scripts/build-geometry-unity-package.ps1 b/scripts/build-geometry-unity-package.ps1 index 31002f5e..27f3c567 100644 --- a/scripts/build-geometry-unity-package.ps1 +++ b/scripts/build-geometry-unity-package.ps1 @@ -61,6 +61,8 @@ $requiredTemplateFiles = @( "Runtime\Unity\GameCult.Geometry.Unity.asmdef", "Runtime\Unity\PlanetaryPatchMeshAdapter.cs", "Runtime\Unity\PlanetaryPageUpload.cs", + "Tests\Editor\GameCult.Geometry.Tests.Editor.asmdef", + "Tests\Editor\GeometryPackageTests.cs", "Shaders\AdvancedErosionFilter.hlsl", "Shaders\GameCult.Geometry.hlsl", "Shaders\Planetary.hlsl", @@ -85,6 +87,12 @@ if ($missingAssetMetas.Count -ne 0 -or $missingDirectoryMetas.Count -ne 0) { throw "Tracked Geometry Unity package has assets without stable .meta files: $($missing -join ', ')" } +$assemblyDirectories = @($unityAssetFiles | Where-Object { $_.Extension -eq ".asmdef" } | Group-Object DirectoryName) +$duplicateAssemblyDirectories = @($assemblyDirectories | Where-Object { $_.Count -ne 1 }) +if ($duplicateAssemblyDirectories.Count -ne 0) { + throw "Each Geometry Unity assembly directory must contain exactly one asmdef: $($duplicateAssemblyDirectories.Name -join ', ')" +} + $templateManifest = Get-Content -LiteralPath (Join-Path $templateRoot "package.json") -Raw | ConvertFrom-Json $expectedFileVersion = "$($templateManifest.version).0" $trackedAssembly = Join-Path $templatePluginRoot "GameCult.Geometry.dll" diff --git a/unity/org.gamecult.geometry/Tests.meta b/unity/org.gamecult.geometry/Tests.meta new file mode 100644 index 00000000..68cfab58 --- /dev/null +++ b/unity/org.gamecult.geometry/Tests.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 97ae3726627d441b8d85e69d4ea804b9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/unity/org.gamecult.geometry/Tests/Editor.meta b/unity/org.gamecult.geometry/Tests/Editor.meta new file mode 100644 index 00000000..89790e17 --- /dev/null +++ b/unity/org.gamecult.geometry/Tests/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3aa2de1207ba4593a6927bed95bdfea0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/unity/org.gamecult.geometry/Tests/Editor/GameCult.Geometry.Tests.Editor.asmdef b/unity/org.gamecult.geometry/Tests/Editor/GameCult.Geometry.Tests.Editor.asmdef new file mode 100644 index 00000000..817ba8f6 --- /dev/null +++ b/unity/org.gamecult.geometry/Tests/Editor/GameCult.Geometry.Tests.Editor.asmdef @@ -0,0 +1,19 @@ +{ + "name": "GameCult.Geometry.Tests.Editor", + "rootNamespace": "GameCult.Geometry.Tests.Editor", + "references": [ + "CultMath", + "GameCult.Geometry", + "GameCult.Geometry.Unity" + ], + "includePlatforms": ["Editor"], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": false, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false, + "optionalUnityReferences": ["TestAssemblies"] +} diff --git a/unity/org.gamecult.geometry/Tests/Editor/GameCult.Geometry.Tests.Editor.asmdef.meta b/unity/org.gamecult.geometry/Tests/Editor/GameCult.Geometry.Tests.Editor.asmdef.meta new file mode 100644 index 00000000..7d75ac20 --- /dev/null +++ b/unity/org.gamecult.geometry/Tests/Editor/GameCult.Geometry.Tests.Editor.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 73e8e3a82a3441ec9f2a0f668c90f5b5 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/unity/org.gamecult.geometry/Tests/Editor/GeometryPackageTests.cs b/unity/org.gamecult.geometry/Tests/Editor/GeometryPackageTests.cs new file mode 100644 index 00000000..dec669a7 --- /dev/null +++ b/unity/org.gamecult.geometry/Tests/Editor/GeometryPackageTests.cs @@ -0,0 +1,54 @@ +using CultMath; +using GameCult.Geometry.Unity; +using NUnit.Framework; +using UnityEngine; + +namespace GameCult.Geometry.Tests.Editor +{ + public sealed class GeometryPackageTests + { + [Test] + public void CultMathPrimitivesAreVisible() + { + var value = new float3(2f, 3f, 4f); + + Assert.That(value.x, Is.EqualTo(2f)); + Assert.That(value.y, Is.EqualTo(3f)); + Assert.That(value.z, Is.EqualTo(4f)); + } + + [Test] + public void CoreGeometryTypesUseCultMathPrimitives() + { + var sphere = new CultSphere(new float3(1f, 2f, 3f), 4f); + + Assert.That(sphere.Center, Is.EqualTo(new float3(1f, 2f, 3f))); + Assert.That(sphere.Radius, Is.EqualTo(4f)); + Assert.That(sphere.Contains(new float3(1f, 2f, 7f)), Is.True); + } + + [Test] + public void PlanetaryAdapterCreatesUnityMesh() + { + var mesh = PlanetaryPatchMeshAdapter.CreateFaceMesh( + PlanetaryCubeFace.PositiveZ, + 2, + 3f); + + try + { + Assert.That(mesh, Is.Not.Null); + Assert.That(mesh.name, Does.Contain("PositiveZ")); + Assert.That(mesh.vertexCount, Is.EqualTo(9)); + Assert.That(mesh.normals.Length, Is.EqualTo(9)); + Assert.That(mesh.uv.Length, Is.EqualTo(9)); + Assert.That(mesh.triangles.Length, Is.EqualTo(24)); + Assert.That(mesh.bounds.size.sqrMagnitude, Is.GreaterThan(0f)); + } + finally + { + Object.DestroyImmediate(mesh); + } + } + } +} diff --git a/unity/org.gamecult.geometry/Tests/Editor/GeometryPackageTests.cs.meta b/unity/org.gamecult.geometry/Tests/Editor/GeometryPackageTests.cs.meta new file mode 100644 index 00000000..89858d8d --- /dev/null +++ b/unity/org.gamecult.geometry/Tests/Editor/GeometryPackageTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cc0a7b5b20004c72b9c9395d3c73360c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 98d15eaf65a2f4ce141f57c98c215c771cb197d5 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 05:18:17 +0100 Subject: [PATCH 049/283] Harden CultLib Unity package build --- scripts/build-unity-package.ps1 | 127 +++++++++++++++++++----- unity/org.gamecult.cultlib/package.json | 2 +- 2 files changed, 104 insertions(+), 25 deletions(-) diff --git a/scripts/build-unity-package.ps1 b/scripts/build-unity-package.ps1 index e5cc82aa..6ba396e8 100644 --- a/scripts/build-unity-package.ps1 +++ b/scripts/build-unity-package.ps1 @@ -15,22 +15,7 @@ $outputRoot = if ([System.IO.Path]::IsPathRooted($OutputDirectory)) { Join-Path $repoRoot $OutputDirectory } $pluginRoot = Join-Path $outputRoot "Runtime\Plugins" - -if (Test-Path -LiteralPath $publishRoot) { - Remove-Item -LiteralPath $publishRoot -Recurse -Force -} -if (Test-Path -LiteralPath $outputRoot) { - Remove-Item -LiteralPath $outputRoot -Recurse -Force -} - -dotnet publish $projectPath -c $Configuration -o $publishRoot -if ($LASTEXITCODE -ne 0) { - throw "CultLib publish failed with exit code $LASTEXITCODE" -} - -New-Item -ItemType Directory -Force -Path $pluginRoot | Out-Null -Copy-Item -LiteralPath (Join-Path $templateRoot "package.json") -Destination $outputRoot -Copy-Item -LiteralPath (Join-Path $templateRoot "README.md") -Destination $outputRoot +$manifest = Get-Content -LiteralPath (Join-Path $templateRoot "package.json") -Raw | ConvertFrom-Json $expectedAssemblies = @( "ConcurrentCollections.dll", @@ -57,6 +42,68 @@ $expectedAssemblies = @( "System.Text.Json.dll", "System.Threading.Channels.dll" ) +$ownedAssemblies = @( + "GameCult.Caching.dll", + "GameCult.Caching.MessagePack.dll", + "GameCult.Logging.dll", + "GameCult.Mesh.dll", + "GameCult.Networking.dll" +) +$expectedPdbs = $ownedAssemblies | ForEach-Object { [System.IO.Path]::ChangeExtension($_, ".pdb") } + +function Assert-SameNames([string[]] $Actual, [string[]] $Expected, [string] $Description) { + $difference = Compare-Object ($Expected | Sort-Object) ($Actual | Sort-Object) + if ($difference) { + throw "$Description differs from the expected package contract:`n$($difference | Out-String)" + } +} + +function Assert-Meta([string] $Path) { + if (-not (Test-Path -LiteralPath "$Path.meta")) { + throw "Unity metadata is missing for: $Path" + } +} + +if ($manifest.name -ne "org.gamecult.cultlib" -or $manifest.version -notmatch '^\d+\.\d+\.\d+$') { + throw "CultLib package manifest has an invalid name or semantic version." +} + +$templatePluginRoot = Join-Path $templateRoot "Runtime\Plugins" +Assert-SameNames ` + (Get-ChildItem -LiteralPath $templatePluginRoot -Filter "*.dll" | Select-Object -ExpandProperty Name) ` + $expectedAssemblies ` + "Tracked Unity DLL set" +Assert-SameNames ` + (Get-ChildItem -LiteralPath $templatePluginRoot -Filter "*.pdb" | Select-Object -ExpandProperty Name) ` + $expectedPdbs ` + "Tracked Unity PDB set" + +@( + (Join-Path $templateRoot "package.json"), + (Join-Path $templateRoot "README.md"), + (Join-Path $templateRoot "Runtime"), + (Join-Path $templateRoot "Runtime\GameCult.CultLib.asmdef"), + $templatePluginRoot +) + ($expectedAssemblies | ForEach-Object { Join-Path $templatePluginRoot $_ }) + + ($expectedPdbs | ForEach-Object { Join-Path $templatePluginRoot $_ }) | + ForEach-Object { Assert-Meta $_ } + +$asmdef = Get-Content -LiteralPath (Join-Path $templateRoot "Runtime\GameCult.CultLib.asmdef") -Raw | ConvertFrom-Json +Assert-SameNames $asmdef.precompiledReferences $expectedAssemblies "asmdef precompiled reference set" + +if (Test-Path -LiteralPath $publishRoot) { + Remove-Item -LiteralPath $publishRoot -Recurse -Force +} +if (Test-Path -LiteralPath $outputRoot) { + Remove-Item -LiteralPath $outputRoot -Recurse -Force +} + +dotnet publish $projectPath -c $Configuration -o $publishRoot --disable-build-servers ` + -p:UseSharedCompilation=false -m:1 -p:Version=$($manifest.version) +if ($LASTEXITCODE -ne 0) { + throw "CultLib publish failed with exit code $LASTEXITCODE" +} + $publishedByName = @{} foreach ($assembly in Get-ChildItem -LiteralPath $publishRoot -Filter "*.dll") { $publishedByName[$assembly.Name] = $assembly @@ -67,18 +114,50 @@ foreach ($assemblyName in $expectedAssemblies) { } } -Copy-Item -LiteralPath (Join-Path $templateRoot "Runtime\GameCult.CultLib.asmdef") ` - -Destination (Join-Path $outputRoot "Runtime") +Copy-Item -LiteralPath $templateRoot -Destination $outputRoot -Recurse foreach ($assemblyName in $expectedAssemblies) { - $assembly = $publishedByName[$assemblyName] - Copy-Item -LiteralPath $assembly.FullName -Destination $pluginRoot - $pdb = [System.IO.Path]::ChangeExtension($assembly.FullName, ".pdb") - if (Test-Path -LiteralPath $pdb) { - Copy-Item -LiteralPath $pdb -Destination $pluginRoot + Copy-Item -LiteralPath $publishedByName[$assemblyName].FullName -Destination $pluginRoot -Force +} +foreach ($pdbName in $expectedPdbs) { + $pdbPath = Join-Path $publishRoot $pdbName + if (-not (Test-Path -LiteralPath $pdbPath)) { + throw "CultLib Unity package is missing expected symbols: $pdbName" + } + Copy-Item -LiteralPath $pdbPath -Destination $pluginRoot -Force +} + +Assert-SameNames ` + (Get-ChildItem -LiteralPath $pluginRoot -Filter "*.dll" | Select-Object -ExpandProperty Name) ` + $expectedAssemblies ` + "Staged Unity DLL set" +Assert-SameNames ` + (Get-ChildItem -LiteralPath $pluginRoot -Filter "*.pdb" | Select-Object -ExpandProperty Name) ` + $expectedPdbs ` + "Staged Unity PDB set" + +$expectedFileVersion = "$($manifest.version).0" +foreach ($assemblyName in $ownedAssemblies) { + $assemblyPath = Join-Path $pluginRoot $assemblyName + $fileVersion = [System.Diagnostics.FileVersionInfo]::GetVersionInfo($assemblyPath).FileVersion + if ($fileVersion -ne $expectedFileVersion) { + throw "$assemblyName has file version $fileVersion; expected $expectedFileVersion." + } + $freshHash = (Get-FileHash -LiteralPath (Join-Path $publishRoot $assemblyName) -Algorithm SHA256).Hash + $stagedHash = (Get-FileHash -LiteralPath $assemblyPath -Algorithm SHA256).Hash + if ($freshHash -ne $stagedHash) { + throw "$assemblyName differs between the fresh publish and staged package." } } -$manifest = Get-Content -LiteralPath (Join-Path $outputRoot "package.json") -Raw | ConvertFrom-Json +$resolverAssemblyPath = Join-Path $pluginRoot "GameCult.Caching.MessagePack.dll" +$resolverAssemblyMetadata = [System.Text.Encoding]::UTF8.GetString( + [System.IO.File]::ReadAllBytes($resolverAssemblyPath)) +if (-not $resolverAssemblyMetadata.Contains("CultDocumentMessagePackResolversAttribute")) { + throw "GameCult.Caching.MessagePack.dll lacks CultDocumentMessagePackResolversAttribute." +} + Write-Host "CultLib Unity package: $outputRoot" Write-Host "Package: $($manifest.name)@$($manifest.version)" Write-Host "Managed assemblies: $($expectedAssemblies.Count)" +Write-Host "Verified owned assembly version: $expectedFileVersion" +Write-Host "Verified Stage 1 MessagePack resolver attribute." diff --git a/unity/org.gamecult.cultlib/package.json b/unity/org.gamecult.cultlib/package.json index cd0c11ac..9fc5e04e 100644 --- a/unity/org.gamecult.cultlib/package.json +++ b/unity/org.gamecult.cultlib/package.json @@ -1,7 +1,7 @@ { "name": "org.gamecult.cultlib", "displayName": "CultLib", - "version": "1.0.7", + "version": "1.0.44", "unity": "2021.3", "description": "CultCache, CultNet, and CultMesh managed runtime assemblies for Unity.", "license": "MIT", From 3f454f2a8bf9fcb2a0457766b1e4c611a890abba Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 05:21:25 +0100 Subject: [PATCH 050/283] Refresh CultLib Unity binaries --- .../Plugins/GameCult.Caching.MessagePack.dll | Bin 25088 -> 27648 bytes .../Plugins/GameCult.Caching.MessagePack.pdb | Bin 16112 -> 16644 bytes .../Runtime/Plugins/GameCult.Caching.dll | Bin 78848 -> 78848 bytes .../Runtime/Plugins/GameCult.Caching.pdb | Bin 28352 -> 28628 bytes .../Runtime/Plugins/GameCult.Logging.dll | Bin 6656 -> 6656 bytes .../Runtime/Plugins/GameCult.Logging.pdb | Bin 9480 -> 9640 bytes .../Runtime/Plugins/GameCult.Mesh.dll | Bin 281600 -> 280576 bytes .../Runtime/Plugins/GameCult.Mesh.pdb | Bin 95544 -> 95548 bytes .../Runtime/Plugins/GameCult.Networking.dll | Bin 419328 -> 420864 bytes .../Runtime/Plugins/GameCult.Networking.pdb | Bin 211696 -> 212240 bytes unity/org.gamecult.geometry/package.json | 2 +- 11 files changed, 1 insertion(+), 1 deletion(-) diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.dll index 4b83a9e6985daa99013b273772dc7098634388ac..70b09dcbcb1c58e930d09699e50e83632d263817 100644 GIT binary patch literal 27648 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 U{r$XFH5C7jg8!@f|3d`+57FA1+5i9m literal 25088 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 N(Eh?Oe%J7<{{nuFS||Vj delta 3908 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 z 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 ML4#DPlo7Q3KjBkO-2eap delta 5861 zcmZA530%zS9|!Q~nfaxI)Vj%0ky28rOoy7ZD#S*yl&o$_*H(^|Ow-}W+LaOOh_*&z zms)L(-NZ)jBWKucBXay{?Vq)%?EXK`G^6J~^Lo91&+qempWpqP<2N^&=!r(U!AaJ~ znvmfu2{E=IWUv_XL1`(mi3?H*UZcklBA^{UD~Q-*K9kM+&6+$BZ3VKi7qWMJQUvnp zp9eivPV45kdd@=0+Ks;LkCbO$qMOVfcBs4lP(mo?*T4*LLTHB-lz5X~==c+%AKF0d zfG=7$m>B_ua2EzZDX@MFQ`J~KBLDU9AhxzfSgjslj8+$nK!Qc2L`1$oD@S`0?M1W# zrNoemh%edzv_GRgkM@9wl4Bx~;;P<286{hXQ&I$b-~d!XHJpU=a20Mt6Fh=e_zT*> z%z_dtu!C{n0TaO=0wEZ}U;!k;Vpsv$kO%oPObS5>-@!pR3Mb$UT!x$Q3|>Jyh(}V= z9eRTa*n%^7fDcTA5Qu;{NP*>$1$nR$wm~t-_F-}meu7#!57*!>5KBt>!!WRf#gGBH zupSDa5O%|UsDfiq2bbU`G(ro!gfWY=Rwd01iP7^s%PI2F61QDBz?uuD_iPC0~I1XiDzGQy6DU zNf6A1U9bnr;V>MBGjPQgx1Q=nNds~dJcbwW21H|Uq|g_J;Jw6d>;%m3gzw;2cp_65 zUaQ;p=rpp!X@_Aj8pgv!m zp#WrsnCyoAPzA@J4lcn>XoMDMbx<8DH^KEpzsXoihJ!PB!%SEVtH*LfRkPS(^gn?% z=;27oC`VlXbVm`%hC-+su31P#lq^FvT!TAs51zv-XanjbBKq(V426*}2HfFenB^oU z^I)YDTd$bpV*V6dfNOBaNhT)uF!LDxfY;CgVrMZi05cc`4iE#0umo1ZD)v+0q!mW$%PZp4EnADu>f0ec4a#!5D!-!;sYV7Oo)u#m5W>{NriOS0=r-jl*2=K z4u3%h2yVD`&<6&?2$%wa5CRbp2Pv=|vLFvO!Zs*|eQ*$da>Mnn#msrQ26v$u{sS+e z4MgsE8$mA^1m<83V__;py0atGyeP>;-x}Be-#`(RK?NLv6L1#l;kG;8|MxKS1pb7# zK*m#|2gWb}Ou-85!3Dfv5=@7A>UOcZ%}}?w7`q;JsdDEsdyvazm>h=V za0aeG12n;7c)>032Kiqu>w4g`!lUcR`>W>hxxw{Ws{8CPRsvFW_QQMt=09P3zgFF8 z?b*3!OI2;xit9Y_c>p(|5n4Xf#iW&+f9A2j5Lc-{CctE=W<>&-fgH@` zaH(biQyo$z)gjez63(jz;k#E#$sM>atqjvQ?koEh>zY7~NjmnLy|#cimnFzP6z?~6 zo&7@a<#G(NAD0IsPr|DB@sqXkl&&mO{p9fHR=|EJP3;<>s!!9(pJ?R(tvp>T&(O+& zA2Qyp?1+LsbadvK+zyRKeU?`JQ>{E(E6>r&!CE;)ld*l(4$RebAnQRWm)Q=^<1(v% z#${HY&t+B*<1(vmeJ(<`F44+L{u=kdfZf~xc7&x`c@LM_3d^+eUM_b>eV~L$*#WMD zZLplnY`{S-v%9#G%dCEg%j^J-aG9Oaqud#hBLB?Q`?6n4$G8r245-n{$GO}G^UHJR0`@oP!dk%a;E=rD!TSRh-y03L72SuW$DhFs(_ zJK{@RW@qHGR=%Q@>$z;iKL4&$gAW^Ir}!3^*?wrUH)@;I^&AxNOGEYd0ITOBvzis$ zqlRRa`T*Dt-Pg*^T$ZuByoKvv3p~=wPr1AwJEX~$7@P4Si%0@;5U~1c{99m(8vCGn zh2IlvklBkJ;9p&NDq+{~bytUKz~5YEpVe=1$}}rr_sBagv;R2SI&-DJWvfWxX+24{ zpWSLW1sx;UR@q-4_*cSF2QB*;z&{60Y_>dgp2Ss;9P;#%>XCo2+m+rnN^x%=H@)d8NpaDU zX{ov&FOE-}8XKV)Z)ZMAHZ2Vcl_lq1DYADyC>bwX?f-n%Cvh+POh4y2e|~A@LYJ(M{3~kp zOvom&Y1x_!z0$Ql3!go`T4v$Xd-|O(hsy45ubUnEX0LxozlI^MwUhq!zF{bT z=6iTjO-AnAz#NNrM^+9S{?E5oW`6{{-&m~w+xzC^-`xvKVi$Hx{cov}yxQ9`aiK+; zp^5!o1DjjjLVh@Ql2~lJGU`oPFDq{gdhl?0zxMQ_F@F9Avd^3F2ZwuYLG z^#?xod(*$hvh<+Ntd@sAT94kWXzr-~#=8vM>tBHoh42# z(N0lg9mhsGNune%(NPW(dwZwKW~VaIfHC!d*5I3%RLST3BFX%KwgABbjeH+ z=}qQ}$iSY0i1c$)7%sYQh9~dA*=_E+Xf3nb7O{3ncDpE6`A<|>C&{R&|}wTZMQF%^{XcEVu==5_kEm%V%9ai(HeIT(abnB_t!#XJ~{O zw9Y^4ZoKZsRRnpx)Z{p{PT5liAOH}xztwDdf*Z?^qJ3M9{mXL?hT6Zxy6o@%o2182 zphk(yaZ2Md0431AowZS>C}X;o)EHI9v_vLpCg?U`Xh?nT|Wd1 z9U!aXcBoan47G?r__#md*{uQu#QCu9iz0AmD;C0xToaq&CemjgibP123O=FLwfHDd zhyxDQzEIaos^&lzulBW$I=BrF0|oaO=%7Io4@2hU8YCct#K6n|j?}#G+Sg@#Mivest>6f>D zzjvM-#*VW--FGPmFbT9y16Y11o#1Jl#n*fVkD=bckV+6H9fvq9QO_f$AST?0uw)C~5WFFHgSaZS1!)V?CQ_C@!ckZz_2z7g zd|Tu`B%YKqULf__{yG2xfY1FB+Vw}@u9P>Jb7ivSKlin)N4DH=z4vge2O+4+imb^B zfQBH8V$`fz%&r-lT4Pq#&{(0s^rEd>c`a}1%wjd$QkkOYd@b@l0`PgW^Am7lN}}WD z`BHQskfn#q^5@aP;nwP*xx};coe6DlCnHz98;zf+Ox>BgVVjE!mD1f?ix;jN{CMo5 z`p+63{%`fBzPXyX{rJ;PYv6~m@qlLTucuy~a?(j`@(;0*uDu~hL6pxY4c-?&)f@8f z8v#Q6a=g&(BOqRbx8ha2#&_cxJmVfoB+#djMe835Xdr{)R{PJQ?;+&)s{EbGpi*Q+s-j|0pv^#sA~|&8dGh4xD_yu4xox5|+}Y#{ Vbd;{{6hIHPUXHo3gTIIb{{q@tl+geH diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Logging.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Logging.pdb index 238279b2f0a5d47d75b9e90e30ef3026394e496f..c083a175f27311e80e67dc6e079c6fd17493f2cb 100644 GIT binary patch delta 1231 zcmeD1TH!sRK%qv7fkD|RCqIdSfnmN1-vR@XjZO{qzjv1{^gd@{Yr0|LgbejM21bT1 z1}27`K>8Sv{sg4|1L87XV=cbkvRqB=&8ygs>rka=}S{RudBqmOFWLB%^j$vfs;un`yiipWoD4Zo( zyU&2BW1~m_N77oYYd%HK`c&<7nU*|UB&pnbeFm>vW=^V4etLRpkzR5!4?=6hYJ~?& zVqY2ED=sT^&`RWTTYhQcmWrD<8$35GTyo90dxk&vIG&0$KwQJ_Pnntae zlN~*q-OGVId#W^Z93m}QL$5iyM_jXI6ilfzh^)MJP@IV!N% zc?nf~l={|o;dcAHpSAHDqbJ_1NeudJ8l|x}e$P4P#tY`a*jPK|e)eqxf#dhN|H}8- zC*B0-+Pm7n9$9M7Z|b~T}k zuZlRxc$`^tL%`%l^C3Nf4WZ|%gP2&a{+K$KeT%BiM#BIB32~Mkw=OSPHrI^(!xr)T zUWY<|O`p}Dd-kQL_>HWH?~W^W+T2m&50MNybT01Lh4T_jrmgia_5bmBtgFAbHsq(`N?D@)k?dSEg*RId_$67NndD_&^H-GYcUNc8`)#uc0OKL3Fe|q`) z=c0<%?x%ZZC7Q*3Z!S+=-j=)LXxk#*lXuT8{J6$l%-LNrx9>s5oTWmn{KvMGHXi-? zZ?XC0=>{uZZxu{jHf!m-E|;BZe?v>GWLn>z-Y@&l>0|$n`2BBhO!;tf^MzAWOCAT- zo2Rf&IVdn`#&>2$=7x*aN-6otrManjCB;fs)k@A*F)`qb6B7fLh&O0$N zpv)5!LsssIiP2KBQktC3ZmeOFXlR&XYHV(tXkwURY?fwjVQ7(RVquzQVqj@%mSmJ@ f24ov28g4$szCecY+~j1HXqIz~i_|9{QgHzQ*;Uf& delta 1066 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

v*K&@s4LZE?BX9#YHRLwc`CNZe8*D z75A;!va)++@5+IdBP-vs^6HfzTKTD!|FLrRs`gczSLIgSusi;o?(%hJef9eG^=sE}T0gOVWWyC3-nQX}4IkaG_q

cl&t{oLAjBuX9D` zj?U{YNy0La9Mkh~i(q!wf45%-Qw{7d?%$Q2FL%+O0Ibpi-`@FbnqJ28Q~n?V_LWP+ z@jhu`38LiRdpqASou1M%ZW$-+I{c#NyYT!Yp6hXD@7;LbgXg_?ZoubpYi-3Jh$TcIG#`7`6QlC;rTS4&*1qN zJpYR4Hawrj^KW?m9na_Rd>+s3c<#XS1w8+O=Zkp0gy+k6?!7Tv zJon@I3Z4h>Jc#EZJpY9qfUm-u|1d23UxStY>v+C_=bLyQ!SgLx^YJZI$j39xcVNx` zE}rk<`97@qk6{#kfaiyJegq5rkMTSXuKN=_PvChH&rk9E49`=rjz5j(=XidB=a+bX z1xx!gc%H@cYdpV!z5KsnEq@Li`+x8}kLS1G-7nzz9c<$-!ZQAQ*v0<uW4SfXoVZ^P-d zx8Zc!wWa~jl-N6PO6?txaPNR*dj}-iJ0Qv4fm56BG}B`L2uXGuB-m#mxjqYt^*KnY z&p|?c4wC8fkVv10Br>r!7!c>iro~Rha~hs`cuvQ22A=tN&cw3-&slgD;#q`;beA+= z9-t>_zB&LM9`54G-_fhF>q?q`Ab#yVT})smq$=qag*5TVgA^~w&BAze8h&2+VH4N_a^IJ zVexOV_`kE^vDhg$z)Ek%Vpn%@9*o)cOj!7Yz>{VoR{0vvj|q#vQt|=aTKBCs-)n5X zZ?j?SAEEw9>>z2quealJy&b2UZ1^S{{ukS?|03lW?A$0l+-A%DH(TE4tb4n4zhK=j zTKCJ=z011ySodD*-f!IptotBb_QQj*{v)jKLl*vD7XDur{#6Tq*t%b{?$@pR4eNf> zx{p}*Th{%ybsx3vcdh$<>;BlfkHcks9=GNG#KNDj@Fy(%Nelm}h5yvTe<5(3T($l8 zOWS|HvhZi@yv2Tz(9^GN_%{+xV!ue~_<8HTVBHt3`v>d3WZhS+YvP(NZrwy&=_?Ue z`bxw(uanpjQg}+>3@d%5EWW~~ue5HJb*rsgW8GTo)?0UqbsMeQY~2>?P8Zjh8F8hn z8B(4xGi`XL4Y$UXpR~r6pUjEtJe+IY({23IZT$H*Jl}>F*z^l*`h^z1(Bc={@L~xk zu?waBw#>Ti)?IGv+acv9%?cY{X~U~*yfxNcYu$A=-g;ZkdRxv0i$B-8=UI1?b+=ge zeCv)__lR{zt@|eHUSZw8v+lTck6HIB>t1c$YpnZr>%Pmnw^;XM*1gNR_gME{>we9; zKeX;(Qsr}H>H(3{jVT?s#*~g*b4tg#Ii>QX#fDpKczR05b%wY}^RtxB|CS1Mr&s(% z_}7ezmD@QVXH@iFOZsiK_&L^{Yu(eV`*#&Op5xX%X5Fi-d$o11vF<-u_wCkwr*+?D z-RrIU9_!v<-5ag@0qfpm-A~(k+-}2Pu~>z+=pYA z#lL6ni2pqHeEj?7`S_3UJb~vaJTGFm?Ip7y@n`IoT@9#0pZZLxP%+zEGG{D#DRa393;44(hS z^IJR*J)QC;^ko^7$}x_a!4G$vncY)t;CaZa+MX>qc;t|R%`rfso1 znqD+NYJ$zE>D**}^Jt>Jd0VW$d0%oA&sEK@Pu|-+CGl8uCi&~;Y;wv;+2mu*Gh*43 zw#5#gG!FlZ=82PDG(X4l>ytW?C%1GY&%tv^%g2-Bc;4QUOr!-bPA8*Dp6HhCiF3{J_vFm4cR6II!W#Un|PtQD3!8Etc>P~!Z)(0x4CmyI6 ztbYj4ONpB+f0}we{uZPg!}C%iF=tyWG3Qh8e;&^rcz&3=Z_eV%=i^K9JeQc+wlZwj1MDx4o3Ox~)4=H}~A+yDDCYzpLV(K#!~OY>R#C)N`u7b?S}rZ=E_LHutnk zt1dV#T~%F|t$OEa*{Tnnc1`@=)1FKG^0aSOUl#wmJkQ5(s9HMjVbI5OiS6@lj`icY za^8&C!}GSqeu(Fpc`ur0=5-{mKYd&5{inZ_c>n3u)z8eUuKpq7T!MbT{ETg}qi4L7 zIC{pG)ct2Pr=B=tM(nSERn1=te|u`${Hv-L&R?HeJ-<7#3I1L4e~*5;rTW?Vw^TQr z`3UN;4dFkVE6)5j{3{c`IP;D1%RtMQ#fx~BCblg&4EJR`NAdg>aqdc97JoDRD--Ws zP+fCbycSOjp6Phz*Q`EkGjM;8=Mm88Tj2f~Cn7EeZe?Q8!tO-(!e>)Q@w^+)qYJMD z9`ge5lNLRjIvdZvMH>LSx8|`$_twl={A5jG@pCnwTm0vm2jPBwabxX_B|iXuY3+4O zmezg*&-a$})c(!Vp4ve?SK|57(w7oTmfcvpWZ5mXyO!Nnds+PU+H04+6=|-;b9?Qb z%bu(G-Ll(j7q{PDyP^;*E`P4(i+CQw^Z4?` zb&oZ#touaA;<_m(t*rZF$2JMqtk@>uSu1X#lFf)_n_bx=*ioDRJq_ z+iL5kT~&A8%B$)g#B<@Q8L{_H`*PjgtFl#Zp8nOkzpnao&5P5%T35CDmfAB`f3>a$ z&*18(>pr=p3r= zFCG+s>$=9;E7v_=|9w0^$Mc7EU#{D}K3g?yeoMnYtp9V(6KAwEynFpEwfE!s_WG8F z(>JsEA8qUI!QTIro;@Bj?^;`_XeZ3j9&{6X)Gt zyZpS@H&oZXzTu;AKa1y1Jg?x1cfP)%70+Tk7j!PhEx09ksU_EhO&q&BBAYT6wF4sHf_(O3$__i z8Tkp?JBXLIxz5{~9Vlk<(gliL(%W0iDL`VgjVm>sHgapax7dZBg>Ya-SS1m54QKM{ zVm3FlJ3Ts(OG_NZl(%h-m$i7%KfSrbnY@l0d!6-M;wmDcJ(+Z0XTF#{fZ}CfqM9l( zLxZ(^MPyusqW0nm=I_-*FeIDTW%9O*J<#q9V62JeQ#N|bm#t)>-NkfXs=Hi*?5p+_ z;@yGt7BYnf02C|@pt+_mNWQI0|L|!A2(Lu%RP;b$Z&EC;r9q@L=hx*qmO+0J? z2tJb@lnN`dtioQ3_EoI7Hvu%rx-3_OQo){)flR>>x?(s*`T&+GxINcX z*nYNxneS>TFgG}uExvXnmmeA2lpgBK_Mv+U-bmO;Zdz)PwUWf>=KTYheuKlgAvdc8 z@w)VYWE7+vL6p}g61aTX8lfDHn)vqSHl>T{f!x6@L&f~4jFlHdJg&SQ>7nd_OrhA_ zpB~OIo?x|_TQN6u;%nNnfrtdQpY1BLTzuZ}Xi(`&F}b0kOmA@#!qRNYN^D=_qucPdfK9o9 z0rVnx*~ZbG=|LGnBykmEGrGYh9o$alOab&)a6ne9B!QJzdrG6RZYXYKP~=UZkn+w7 zRm}o+3DZEr-KaD=;#m&Flc0Z()pS#)r0 zx`z5PM;#mt4l;OTptv*RamqcJgW#PySJ4u!+0I;FMrjLLgS0(M{_D!o3PYH4B7p?F zsLR{i&6>`R_RbZ{wruL$v~1IsjVm^bux^dI$)vGtRZ|Ydl*>2W_%3aENH4u(>mhx&_&>9v)I^#k7V;1FdwJYuU>W;lavdscBt1;2x{zvms0jF=xG+=*K-4)?d?#=qw<*? zvD&8aGqOTLvV*!Eo!ume)sw)_w(wvn+O1LyRNd%eEF#o=YQa${&YlFm8X93#{8dog zqTp2MqTs8bT1COh7ori=x*}6_OoCW73H$|fP06(`|_zGxgNRB+@A zyM_ivyV-M4Fc5ujx^RdxV<1C`+?^ZA3)sm&%S1Nyr-u$QI^jDqg?@kXl%O`Hp&Yq> z_ApQZ2Gd0>hXsvXc8&}TaA5&&*OnnH*z+#5E8mv^lPUp1VK|UII07&$+j%6Nl~oB6 z@7iC;z~B4`z0! zdk=YJ!A7v3f&d*_TX!W9tP27)v!YpK@2+8XRRP%Uk^OIgatR;T(A^pOTwBUJ8Yr(v zw?mml*mdxZ%wR4*$_T~GAm-bK)jd5&^66n@);(_>Rh@xcZ+f5r)P*3&fR5`F4}VU# zFE>4~5@0lYrIlSn*&^)>-B>cM2a;uW4HY|w$-(7^TYEI30`= zp_f`T_yK&Sf($G~!BqcNN*Q@Eqy!dK0w#V9@xIcCKpz@`HBx57O5|hK9mwVjMbe}V zOK({}SP5ol!G`j>a_X}~XraAgy0L*iYtwT$kZaNU3wG&egSn9+y2S>DGDn@4bw;iH zY2zaWW8^Q*Fay3!X(kA4Ss49*?gp|P!Dl3y9+JO*(wA`Cw!b-M-nQhHv`ha#*F9IY{ zWl7yVl85mz6No+uSdw_gP|LCXLc$pI{zzu;2!vZ8^WFIzSp*mcIBj;AsIK$#xshSA zc0acue*qg>ZZ>BnQ92*sQ_Ib^%&3&IJDp`DkD>Un2?ZBnCt5CoIo}a6{~*EvCasER zvN>+!K)r>}5eaEVA?e{^OrAbY0^s+9&mKhMhWfUqvjdQ!7G9u`5qW9>{*1Hv!-<+N z1cw*{fG09p5G`2WvJyNZ2E3eRnX<%|4bldT%N;n|Y0>n_xqaEH%Q}=Y8OL@yyqsnp z(YLQqfD_>!V)+Wkl2;*$4hKAw4Tp_`&WA79JcZ;lu~^WZ7kahB{z1pfWX?#C8C@CF-!3J51_jiuRR= zkS#yktb;fw(WFJWg+{TT`x+!%;5Ojdk)u_A1E@WpJ&YE0u@|^`C5qqXOc67-0Q81k zrhBvi7P6#k7fu`>CR6L_5hC4_!DR1E8<@lMSTkr~ukNXtJ?SH^zpd4FhZrxdUD?=4 z=IqQKvkn`5ZH8S1jFcDx9i3am-u$RE*0=3iL{G10?=5T`b-+HiN#}ty1DC4@F39Gf z*@RN_Y3Xg~xM_@j+7!_BUSQBcIUt)e1HdCkYm?;iBHOD_$GU?#F^zC;gzhqF+YmCvFL=@w^lQx!FF@6 zvL0i}%bC0lRQ!C=vw*wVg$*sNx{%L-^nNaSu=dd!bqyWP9kTua12j=Q%mLkWE@5y+ zIBQ_CmtrkrmW@^|Ilw>7mZO6@>v`jD|;G>^0i99eOBjMX(M@O1PsT(^=kQk zi$)H{h>|z1&1Hhcfn8Tb?kR8?2=QS@4-;97EKwm07%bF4?5Cy&)Ka1LC^TtcpmShg zBL)i^q3lLk%y9%qX@j-660?%cqC^6F9i;I?qF-oqQ{PaDKH$1M3|GBY^Ri9X0C=-{ zupU+qiOhl`1g!~e{G)aInw>SVqEY+1u-uX?(Mm4|DDzRu#lVy_6F62Ll7^JA_39n1}V zu+_P)p^gqa93X6F>3UD$E@pYt{glBNUNP+@#Y818jUfxnk~D;L07ChvQo5^8TImId zaq`v!I=SlsGDn9or!svW;6Qp{fNKyB09th7okfU%hlklKle7hUfni~tHp-@vJe27o zP62?A_U-M@({_R$-7wJ8lZ9O+n;!6h%#zDc;18%nh-gZ-49`#P$(CS+4P)rC)WO9v z>JoYZ=V8|5{WgO2N~_YWaR9eF2w)6r60=GDkW!cG*s5UfPvpq0}WCvZzeu!D~ zw1N+z&QuCvoUTFv8{2-YY+1M`?-ju4awy6cZMXi5qYlUtLcp{h5b$H+ut|aSWp*N$ zY}1{eaP1`rVZNmhsMY9Jhd&I}+U01K732xSJI|EZlJuYsi;@#N7P<+hsY9Ego@Ixa zq9nw6cxn`|j+le6oI9Ik^YfJ|0ERtNgT?w9A^^T_i~w8ci#i)!4x4z}*)P~Fw zJRjj!onXcC_Ot}N#OT2{=>hBIvI$y=4Ka=rfk+}WW)G|(2&GHTuG!420oca#Ly}1W zX2Vk?4f~df<4~9B zDg**sY1j{hcV>>9Kazz6mLrSVo}R7Q%m9L$`bUNimBF~-p$CKgc(fz=A*Wz$IMmZ) z^>3S>EYic^(zSRPkDBVrJB;#|kYQX39*RN9B}yL|Z`Mp~0k zRDFCwA5NwcJq-87dl=`*@G!~>?Jy!B!NW*jT8D7~`5Z>7unxnm$POc{{0k#W#cvoN z81+f>Aj1f!^h87$<=B51BL{RtWV_`sZgOCu8jan9&DKd!xQ~$?j83&R4_j_wH%{!x z22{8z=$QjrY#8T`t%Nb$Q-`#kJc8;=ljHT^OE_cl%PgdKVXzE^)Fq6A#y1IO zHwXnL({K_IUse`{u_U5Nk)ji98P4_ghZFjmSE$W0FGVQ}q5NwnArxk$clj!WlshTm zO6*P-BdR9V-kv)cjlD427nO(_K%Nl1G5k*jB|}+CUh! z1-4|%VZumRMPN@ZjNu7_$+6qh`!f-VJhcbAgHd>$SbK4zEL77hm&wohc#zDjIml- z7(u-Y$w0@vlo*=DB6NAeQsh@e1lik~3<-rVGt`F_T6%OxA)GmNnOBLj>%aln753(Y zCGLeB*cp+}<`KOF8HHn-LJ=%I3h7p35qU~i7PB~tdYnjh1s0Lqo2=dfDI$_zhBU9M zFCvb!7VI7vIY>ifL=-(BmmWAy6m0K{g~F=E5t%r1Nd(Giht%65(AF*7*?Rk z&^yvcyN0$7WDoWiCyU~*0`=TkL?IqM$*MRa!bUY$i9Ia>jat~{g4$U^6Fusdb|{i> zrwO4%xi}7fiymM(P7G8L9dwY#Tqda_`NgZp+M7NY(E(eAco>|Vf>WB?I#4$v;z>Iq z;c3{?aq1@Aa;|Bj;Bvz-0^td<2%K=z$P*ZX?MQiRU;^CpEMfe z16X`vq%diWZkkbxlcNL2L?T*2-cyKxJGM9(p7ajU1H&?`)WvDBJCq}@X zF(3lPa}_vAd7Kzz?e=1HsK6~leX;=(k+D06FnXLgG!$mA*{SzK$<-n<>K+*;=J=7y z4%kFwLwzjY2UBbW&S?$U`3`p~5@v9CCla^i=rFFE6{3>qaTh)9AI@}l_Go5cGUTS* z@aV>oKA6VC36=4}wxC21j-W&uhO7D!hF_2&KM%wALJ1wXa1x{)lgZGYs-*{4!kMe> zc`~dc#&9|i%;78!g-#yBZk~seiiUeZ7N_bbrQ$GV_dt3GUk2b={7|Y3v&A7y=t;0# zwM~M;2Sg^p>>ElS&f${-nB$~@Nn*Lp@^F>x(XGwdJnq2gDFSSlc#6BbM-XbtZp^Q6 zZrr7c#(1lra3c5Zf-uG&MF}H#ASDcC>CqVI*>Y2!`Y`Ns;iMox?iC*oU*x@sP(N_c zy5v%L2xYBdU47(P*`wjKVkD6DK^P}%K~@Q?*O!F2CvImVSE-DhJv7;Ff|jJ-lxhVpdfQncLdn=C5N z&*Fd&>^XrLIH-+-us*#@b@N(l>?7%!0n@e1Qkr*+pgb&d*a15WCBcI3yGjpZURuFo zdh&WW82jbC-nuJ)VLuN&4CA~o#+{uD52;!-03l^16mP==2ZG$*2ad?tYa^1x?OX6* zf!>sak?^VN_)>C+@ z@lSeKoSam&en$>&kYwep16dZsUocw)N!CetRgfYOPN$AQSx`Z1iN54^!zNfM*srvU zi=QW4Xnb`{hU-z)90kgbqGiK7yuT%I!n*_^fgu-F_zpJ%$OYwKNid;38XlRc!-;tp zW8%Ut9~U0hC z!r<>$`6p+0hEd6KG%M#<;&R^ZFOO1MhfoyW)bOrp9v`ck64*s_5j3*GGAI(!#Te9m zKb}n5!`(f(Ws(~@42x8$C^GAoZRqL2SFOD3FDixXY%bd*lnE*NL9hcPu278(p89&Z z-p8f=Lu4wvKwxn0Ra_2sH}@7bH}N?Z5xiw@y11X0D^Qd6s6rO9u#RVfxae#5QZ0M# zhFR>*ZO-8<2Qr7Ok5y3voUw*cImKf^#0GXXaX8o8;q>aGqE!}jr5SO?2J#7RfEsM| zVKHj4=j-g|Zit1b34cGVCAdr^w|nFmIIhWuzG+}nco@g4EWBS6Dw{J7$)bGDSJo6T zeLYK=&mF+mw9M;r;I8zrH)xZTQ4ZXyU^-G+{y zo<4gRRv@K!0TtvT;Buea-bbPehg2vtWYXp7ZgCWJBP5YcZ5xV?lIKzW(8QIl3Utl ze+a^O-gyS4WOus36g(eeK`^9oc6F%88e>xr_a}$NWyN66?AYAiz8AV2Q9fw71MMqh zj4m5C;+Velx)W}~)X+jN+|y@25aY2snVh;nU~0!(1uWYZvbEvCy=kCed)V3Rb?Sw^ zW#V*5hAkVrI+zlm;!Db4~$|Y<-%-d5g+E=k0V=V3oat_ zWVH|JDtPS02T~;fspn-`i6R2=y-53b3d#$i=By?a3m@iG5Fetk0*&!euF`w6#b6#X z^T3LN5qX;|z><9wzO?}Hj*kvTVs&3#sPRZHf5=bfYIQ*teKX|4w;Y8Xi02@DkgFv* z0m&s22>~o$JpwX4Flj7V3u5D4*iX2Gz^MZtxfxeUMPuQGav$uElQ;6-mv%5`_ql*WDxoLTC|neyVO91Zf}@;ME=&qvW+@KH)Kk|ic``l$E<_y7;y zC7le#{I5W=C=Vi-ZAZ=U9OA4Rfo48Vsvfn?k(#|C z&?TMk^ADq`0_|gflu4k0JA z1J?!odlJ-t+yx1k0N$9{b--*-7qrjer)aW=;c(+a4#jb)3f2Nr^Y|~!x3W1KgasGM z?ENB@HX)&gZXBF^uv7#v`4 z&iTA0LcomS`q9M^_T_&$)q%aFZoyifZa<8Hte1A2eEECJP;X9P=VRtE-zC&}7)ft( z(C48bkjUc%n;#h(qQ^GclIjx6n1~^vW7$RT-kkM-VyutGGexpCy0Ea80M$igec>Q( zsbwu_4y;>Sr6S+M2}{F0tdh%u4$DGW*Ng*DLn{Gj-X$R4;_gzh$H0Wt4B-Lu8H_vH ziO+a@FdH!%>Mw#^d>JDD#HMtKT3X}=q9wr+h%F%s<_N*%-qWiW8HEx^$9;14Q#;-d z$~w*T9N|YkBq~i>{44SMdGWnr*$ z<9Cr|7fS-7*l;rtXN~ouw%Ns9-Qm%#F6=J78m!;sa+xfYdJjo6rzL2i`t3*F9M%0z5AAkvF`)JkrWAv`WMc)R zo-g#L2RQm7oFvo0fnJmG5BCZVU!bIY7Dfdw37Jxjeq1>&k>k7sIy<<0R?*~!d(Iaw zlHUv4(5}1(-Hx1TnieFT3>c8VI8F?4>MiL5f~`>#3(qL) zToMb628GK?B{zi3M;smhq5phgXv*>f}S6d z8HA#O7i%H3M=?$_h@Ok)UB-eemcbGQh2@zZjn3pH%!J-qX{nwca$OfxM||vs=>n=U zqGfj#_ytp`26&}@YRbrO3$W)lqG#|kC?p$4Alh%xCt=n-ki~753}+>FkA}RqW7b$^ zz87|1z`3J@@2HYY6|y5cWL|?y*RszFA%#!hd#MAbfGh^49!6k`^$55$*Lw4ED4dn$ zDu;SLSrBwmZ#|@atjixsX>|#0iLfXKp`=izAmlux|GaI4+lAj zH)K2t<$#PPV-o}x`KkRN;IOT}Di4$+-I%cGPp{jeU`}6iah

|IST`WjLT8if-v| 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 lwzsoZ)6}Zr!?d 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

(437+}7S)Djb?*)>gYs{nT=}l77lBFqyPJ*HSn~ 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

+/// Axis-aligned 2D bounds stored canonically as normalized minimum and maximum +/// corners. Point containment and intersection include the boundary. +/// +public readonly record struct rect +{ + public rect(float minX, float minY, float maxX, float maxY) + : this(new float2(minX, minY), new float2(maxX, maxY)) + { + } + + public rect(float2 min, float2 max) + { + this.min = new float2(MathF.Min(min.x, max.x), MathF.Min(min.y, max.y)); + this.max = new float2(MathF.Max(min.x, max.x), MathF.Max(min.y, max.y)); + } + + public float2 min { get; } + public float2 max { get; } + + public float width => max.x - min.x; + public float height => max.y - min.y; + public float2 size => max - min; + public float2 center => (min + max) * 0.5f; + public float area => width * height; + public bool isEmpty => width == 0.0f || height == 0.0f; + + public bool Contains(float2 point) => + point.x >= min.x && point.x <= max.x && + point.y >= min.y && point.y <= max.y; + + public bool Contains(rect other) => + other.min.x >= min.x && other.max.x <= max.x && + other.min.y >= min.y && other.max.y <= max.y; + + public bool Intersects(rect other) => + min.x <= other.max.x && max.x >= other.min.x && + min.y <= other.max.y && max.y >= other.min.y; + + public rect Intersection(rect other) + { + if (!Intersects(other)) + return new rect(0.0f, 0.0f, 0.0f, 0.0f); + + return new rect( + MathF.Max(min.x, other.min.x), + MathF.Max(min.y, other.min.y), + MathF.Min(max.x, other.max.x), + MathF.Min(max.y, other.max.y)); + } + + public rect Encapsulate(float2 point) => new( + MathF.Min(min.x, point.x), + MathF.Min(min.y, point.y), + MathF.Max(max.x, point.x), + MathF.Max(max.y, point.y)); +} diff --git a/src/CultMath/rect.cs.meta b/src/CultMath/rect.cs.meta new file mode 100644 index 00000000..0b04a5ce --- /dev/null +++ b/src/CultMath/rect.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 5aab0d8e1ca94d42b85bba780a7ee449 diff --git a/tests/CultMath.Tests/MathTests.cs b/tests/CultMath.Tests/MathTests.cs index ad268212..8d42a0c1 100644 --- a/tests/CultMath.Tests/MathTests.cs +++ b/tests/CultMath.Tests/MathTests.cs @@ -199,6 +199,41 @@ public sealed class MathTests Assert.Equal(new float2(2.0f, 0.0f), closest); } + [Fact] + public void RectNormalizesAndDerivesFromMinMax() + { + var bounds = new rect(8.0f, 6.0f, 2.0f, -2.0f); + + Assert.Equal(new float2(2.0f, -2.0f), bounds.min); + Assert.Equal(new float2(8.0f, 6.0f), bounds.max); + Assert.Equal(new float2(6.0f, 8.0f), bounds.size); + Assert.Equal(new float2(5.0f, 2.0f), bounds.center); + Assert.Equal(48.0f, bounds.area); + } + + [Fact] + public void RectContainmentIncludesBoundary() + { + var bounds = new rect(-2.0f, -1.0f, 4.0f, 3.0f); + + Assert.True(bounds.Contains(new float2(-2.0f, -1.0f))); + Assert.True(bounds.Contains(new float2(4.0f, 3.0f))); + Assert.True(bounds.Contains(new rect(-1.0f, 0.0f, 1.0f, 2.0f))); + Assert.False(bounds.Contains(new float2(4.001f, 3.0f))); + } + + [Fact] + public void RectIntersectionTreatsTouchingEdgesAsContact() + { + var left = new rect(0.0f, 0.0f, 4.0f, 4.0f); + var touching = new rect(4.0f, 1.0f, 8.0f, 3.0f); + var separate = new rect(4.001f, 1.0f, 8.0f, 3.0f); + + Assert.True(left.Intersects(touching)); + Assert.Equal(0.0f, left.Intersection(touching).area); + Assert.False(left.Intersects(separate)); + } + [Fact] public void FirstOrderInterceptSolvesSimpleClosingTarget() { diff --git a/unity/org.gamecult.cultmath/package.json b/unity/org.gamecult.cultmath/package.json index e45d0a35..d7039df7 100644 --- a/unity/org.gamecult.cultmath/package.json +++ b/unity/org.gamecult.cultmath/package.json @@ -1,7 +1,7 @@ { "name": "org.gamecult.cultmath", "displayName": "CultMath", - "version": "0.1.0", + "version": "0.1.1", "unity": "2021.3", "description": "Precompiled CultMath numeric primitives and matching HLSL semantics for GameCult Unity runtimes.", "license": "MPL-2.0", From fcdddda72f6aa33ae6eeff3bce6a2d3e26eb16f3 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Fri, 7 Aug 2026 20:37:37 +0100 Subject: [PATCH 053/283] Rebuild Unity package with rectangle API --- src/CultMath/CultMath.csproj | 2 +- .../Runtime/Plugins/CultMath.dll | Bin 44544 -> 47104 bytes .../Runtime/Plugins/CultMath.pdb | Bin 23420 -> 23936 bytes unity/org.gamecult.cultmath/package.json | 2 +- 4 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CultMath/CultMath.csproj b/src/CultMath/CultMath.csproj index dfa5475d..4e0027db 100644 --- a/src/CultMath/CultMath.csproj +++ b/src/CultMath/CultMath.csproj @@ -8,7 +8,7 @@ CultMath CultMath CultMath - 0.1.1 + 0.1.2 Clean-room C# math shaped for HLSL-style renderer code. GameCult https://github.com/GameCult/CultMath diff --git a/unity/org.gamecult.cultmath/Runtime/Plugins/CultMath.dll b/unity/org.gamecult.cultmath/Runtime/Plugins/CultMath.dll index 91b51d8d33ed8fcbc53a66b07131e2442f17c464..379dad44e209aea24d0cd34f7cb28a1a490d2ae8 100644 GIT binary patch delta 17237 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 delta 14912 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 diff --git a/unity/org.gamecult.cultmath/Runtime/Plugins/CultMath.pdb b/unity/org.gamecult.cultmath/Runtime/Plugins/CultMath.pdb index 711cf76c53ef3d56a5f07fa25acb9c8532c93e3d..223b4de88b508404e9dd23578205c7692bc9427e 100644 GIT binary patch delta 3993 zcmZwJ3piBi9|!RF%nW1P!jjx)3FCenv$@r}wWyZV7F+916sBd6KWhltwpfhTMysrm zT4^^^Nv%}N{x|*iqKjQ!bWxOwM`3Hb{l5ph&C|2<_?+MSecyB5^PV|4=lM}8{{&Ue zUn?>r#4L}H#QB7X7-+8$r6r}VODFhTwIGCrYWBejas%y+bo;#z0{u`!ED3QGAp0Z> zV~~CM?h!twor_x|{UT4R>4OQ2OA&_vLPQzpbU0QPb6lO zUDFdOVWJrVR9f?_R@9Tw4SjG8Mqv^Zt(Axx7=t<3LJ%y6Fo=W%NC6S#z-HJA<cIbvaj9r6XwEuwXFa#VM4$%NzFa~q51s8A! zZwRoV&o}##Br|jZI3#$wPnks6%!o&&B||Z62MN?bJ?w*T;V5)K7o4-9?~YiRoVQUW zH{mXf!4$jzmaQsL0WHu2E?9y+xPmA6LJ%y6Fo=W%NC6S#z-HJAtW!MAV}I-m>A!FlM18!!x`FbU6rX|GC@K@;YI30Qy~@WBIoAP_=eEhK^n3hY(I zWGfmKuoLQGKOBN~I1Oi^7y98Q+=Fp=3Y3E?F#>b2gGKNj1jA~GgmoZMJU;#&XCr_0My`|F-x%Y&-^hF9vKGec z+4V#`nqPROIjEE==}?k>2Es{=b!E
  • U; zNYLyK#mLTRyTTD1umzd^2vO+#8L|)Z-{aem>BZ9dD8{$X?!O+n4Y_PKTjLdi&JsMe z-^bW~3OAYVs6xkTbX4L5bl!m+g`9(Y47m=O{?PZZT`p@PAD7Er$S05+X7`Um{$6&+ zc#yeFN-qxUxGqUC%pv^Or}>WCx`^?3K%pe!WuQ(?Wozd3zV;)I9iOhq^Y)Py9_$Gb zvXfHf*EPr$cZ&6fMQ%n5qI&8yhwuE}$oF5Nqo^C+$LN{Uw|1hEs~MQ?zeyCImKvQL zn3^Q|=VY6;x&A|j?tN~x3*S@Et8E(2P(EZQNi6!|ewc~L*o#WNQFnGqv?%fQ0m0mm zj&^QS#MI=a$Qt&Zr+0~O;7zrqi9SPv+C7iETt}R?O7eNS;=`V$M#C?D-NGsG)eosE zT_5(o#fkD|BPE@A7l}Zh=JfNfHqu&KXw}5+{YO8}VAea`ZD{m1e>LE1G-3OoI<_%n$>>Xou~ndI zaN(-LkJyFLg-L~*B&M)z1jZb@`bQqu34Sznpg7Ws@+O3RBYmtF9^ z7j0XbQeeBYci-vjC;v#PzV?#x{km4#blsqiA9UfVtZcA>U#znI*08IaI7a*Y*pJ=O zSKqP7e^hfrllg!ZGL_FAxDr=BdfUJ7;9hdedy8bpA(q|L9!EvSVAVPc^N`TO>!s`7 zZMxYTrea<&>3wRYM-6}C!WCB3<(;2@v9aQ1!_aWq&=a2G;QBwNy!Ux6+GUZoGCVZq zdk+(7q!VlXk}JDk*ag^&AL^WZDE@7-+BCU`H<6ZEYNylN^Wak3S=H4$-JR8&bEF=v zMFo2c7lwo+A7A8HY%WTlI$3;6;V@6FNYUebNcNW6D-R!f1_(J{?y|5jcCgx+niFs9 zrBUL0#WuUvwldj$sG-@jEmkS<)eku>k0iO_2OsAK-ruqC=V0CD?cdn0*>(Fr_2O#l z=8eT0I=)POwzZ=yXo|UQm4NrN=*JGtCBdeio?e}5ob}qCo4mi8v)J>`-Tl7|oI0R+ z?@V}2-{P7ui=MW7V}I5dYkN)Io_zVrQ8bqDY@vShO%;RsGaHV_99Waa=!sD}yK$6F zsZgw}9Md>qY(`3aswmymJ;&4`(!tu)UBb0<<;C({`7SYTe7;M(n;>ohe}S{WF+Rc3 z(b<(B=N#t}>zEKNh<1x}mV9EDOS#GZvfFPscLgQ=kdkIlQZXgnMoDWa=>bamgRDJB zpZV6mjLC+UJyI6a4#Yp} zd-@=jk~Ljal^o_9NbZLD|LeubPDy;jy(mLTLAZ!Al1zoK)y7-K()>b>Ia$LXHuSpl RKQoaee7J|=O4w^e{|97??IHjG delta 3501 zcmZwJ2Ut_r0tfJO6EMRti=a3NG6G>Q5f>_3L7XTW?uQlv>`v(pKVA_qbYP})tIL`qPfPuIhyLW%DP4A|DwHBEq2eQMg9vX;0&C0 zph!QK@e;IRM`**K%Mqq`TAd=Tg`otT8i)iXnB=0x{a zH&ce5hNQQXjtxqhBLqSyM8RZ;2N6iS2SyM>GT(__Ob?9Ku|Y{w>gA(c1r=}v8sQvV zh8Adr$KA7qV3v;V*;wR*lMd6FMQB{G10i_9U1!xPlK1fl&|+(GUaEK>{g|2AQDD#%Vbe z!&=x38rTJU;UFA`Cb$UK;0`>5XYf0`flpxQ#v?rV2CTsroWKJH!EgwMu`m&0-FQlp zh{|k`K?Y=j3JRbUHb5oRKrQTt!*CMLLNnZiU*HkEfLHJiD0d!Vg9%tde{cpr7zN|p zm3V7VnE|sv2LFMjkPpSM4l1Aq_P_x+22F4YoVJmLl;Ap#~sJj??nl!6AngM)Aaeu8Fj^5PLs7z`sJ#f$#x8j(^j zoed~ym3rnisL*P`)!T^pcU`qzHWRi; zE>HD#7pM2|AQY1o!mlmb`qJ@r`^THN^95IAo1Px2obl0~O?rdQluq4|2HxmPeFdF}NVx-nnfW(nVP#Gch1BjPx3=eKsAT9?`~Jl&?Y zRl22b>fy#$X+^E4bVGc<+@_A-|F8NM`G&jO466fK=6|(?U5ib4F)byi>)}$t%+)so z=CY)+uh-SaSB@zkwL0Sc+$B=cvY^J$;4$l~_g{LVt~W4VH8E@?_qN0=B0Xf0A~{W# zlo}zED*m}yt_A=6liBK+LLZ+TPV9RHtMA$G?!=5aD$|C?^|&ht2)mxnnwO-Q^JPFZ z|J|+ocEc-bZ?qJ;B`3w+%qx~g8u`t6Xy8=!Jfxw2HAs==x-b(gT|s|(8v)J-lAlwW$}vH6ld53GNS-TF!7 zxZv5acH@Q_RKb%~8FgJ1?NwJtZoF!mv-dK72eoVBQ~G+D=Cv~4nyB7iDO-HAc!8B* zYl$o(ZiVeB>AUgoJY6pS##O|IYVtq6NxFBV<>-mg)&3D-t$m7p&%Jt9Slp%=w!CMg zd5uw~Qe<)EWkX@(L3xxxFW(>SLR&ah(P>u&Myojq^4B*@G@nl>)9*EXu^qWLpSa3x_T!#@%Bc!+k=6h!!COCzxc<5f+qjE zXPT0sftzP7oE$$pZV4Y7Q$XhAnltqL<6ExftIlM-&PZ%9qB@j|1TG2gQ}aelcipjgyJh(H zv9*(jd+e&-!JRIyjX6}4nbS5;9`IBv39OSOuewq^`)=R8U9Kk^U%iS~SB3tlvbvTx z$A13jypCVpBI8QkD;{NvwNX=Qa?dM|-~3SZbYAp~m!D07-t6(WDcfs(Y@eA>RpZjs zRBAQeQhXslJzBleJ=!TC$H~-RBFOBZxn$pil1GbPZ zcx(@QYjsCl$iL21-%}kPKb-2T&W~46{nYQ{6D;~;&&pPD97sHaxR7uL$u1b6PD!Yu LY}CBz3X1#>Qw59x diff --git a/unity/org.gamecult.cultmath/package.json b/unity/org.gamecult.cultmath/package.json index d7039df7..80ceddad 100644 --- a/unity/org.gamecult.cultmath/package.json +++ b/unity/org.gamecult.cultmath/package.json @@ -1,7 +1,7 @@ { "name": "org.gamecult.cultmath", "displayName": "CultMath", - "version": "0.1.1", + "version": "0.1.2", "unity": "2021.3", "description": "Precompiled CultMath numeric primitives and matching HLSL semantics for GameCult Unity runtimes.", "license": "MPL-2.0", From 98bec47d7552686a9ae91e3e5fe4ec0600699587 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 17 Aug 2026 19:47:10 +0200 Subject: [PATCH 054/283] Make CultMesh document writes authority-explicit --- src/GameCult.Mesh/CultMesh.cs | 75 +--- src/GameCult.Mesh/CultMeshPrimitives.cs | 392 +++++++++++------- .../docs/document-write-authority.md | 72 ++++ src/GameCult.Networking/CultNetDatabase.cs | 16 + .../CultMeshStreamingTests.cs | 268 ++++++------ 5 files changed, 485 insertions(+), 338 deletions(-) create mode 100644 src/GameCult.Mesh/docs/document-write-authority.md diff --git a/src/GameCult.Mesh/CultMesh.cs b/src/GameCult.Mesh/CultMesh.cs index fbb08f22..232f847e 100644 --- a/src/GameCult.Mesh/CultMesh.cs +++ b/src/GameCult.Mesh/CultMesh.cs @@ -493,56 +493,6 @@ namespace GameCult.Mesh return Document(recordKey, verse.Context, documentId, sources, routeHint); } - /// - /// Creates a managed reactive document mirror over one distributed record hosted by this node. - /// - public Task> ReactiveDocumentAsync( - CultRecordKey key, - CultMeshVerseContext context, - CultMeshReactiveDocumentOptions? options = null) - where TDocument : class - { - return Document(key, context).ReactiveAsync(options); - } - - /// - /// Creates a managed reactive document mirror over one distributed record hosted by this node. - /// - public Task> ReactiveDocumentAsync( - CultRecordKey key, - CultMeshVerse verse, - CultMeshReactiveDocumentOptions? options = null) - where TDocument : class - { - if (verse == null) throw new ArgumentNullException(nameof(verse)); - return ReactiveDocumentAsync(key, verse.Context, options); - } - - /// - /// Creates a managed reactive document mirror over one distributed record hosted by this node. - /// - public Task> ReactiveDocumentAsync( - string recordKey, - CultMeshVerseContext context, - CultMeshReactiveDocumentOptions? options = null) - where TDocument : class - { - return ReactiveDocumentAsync(new CultRecordKey(recordKey), context, options); - } - - /// - /// Creates a managed reactive document mirror over one distributed record hosted by this node. - /// - public Task> ReactiveDocumentAsync( - string recordKey, - CultMeshVerse verse, - CultMeshReactiveDocumentOptions? options = null) - where TDocument : class - { - if (verse == null) throw new ArgumentNullException(nameof(verse)); - return ReactiveDocumentAsync(recordKey, verse.Context, options); - } - /// public void Dispose() { @@ -2010,21 +1960,22 @@ namespace GameCult.Mesh var sourceList = sources?.ToArray() ?? new[] { ProjectionSource(key.Value, descriptor.SchemaId, "CultNet database record") }; var route = routeHint ?? new CultMeshRouteHint(CultMeshLocalityKind.Automatic, "CultNet database document"); - return Document( + var feed = LiveFeed( ResolveDocumentId(documentId, key), - context, - async _ => await ReadDatabaseDocumentRequiredAsync(database, key).ConfigureAwait(false), - _ => WatchDatabaseRecordAs(database, key), - async value => - { - await PutDatabaseDocumentAsync(database, key, value, predicted: false).ConfigureAwait(false); - }, - async value => - { - await PutDatabaseDocumentAsync(database, key, value, predicted: true).ConfigureAwait(false); - }, + (_parameters, _context) => ReadDatabaseDocumentRequiredAsync(database, key), + (_parameters, _context) => WatchDatabaseRecordAs(database, key), sourceList, route); + Func? replace = database.CanWriteAuthoritatively(key) + ? value => PutDatabaseDocumentAsync(database, key, value, predicted: false) + : null; + Func? submitPrediction = database.CanSubmitPrediction(key) + ? value => PutDatabaseDocumentAsync(database, key, value, predicted: true) + : null; + return new CultMeshDocumentHandle( + BindLiveFeed(context, feed), + replace, + submitPrediction); } /// diff --git a/src/GameCult.Mesh/CultMeshPrimitives.cs b/src/GameCult.Mesh/CultMeshPrimitives.cs index dcc58143..00ba60b7 100644 --- a/src/GameCult.Mesh/CultMeshPrimitives.cs +++ b/src/GameCult.Mesh/CultMeshPrimitives.cs @@ -911,9 +911,6 @@ namespace GameCult.Mesh /// Gets whether this handle can submit a client prediction for the underlying document value. bool CanSubmitPrediction { get; } - /// Gets whether this handle can accept a transparent document mutation. - bool CanSet { get; } - /// Creates a same-schema alias presentation for another CLR document type. CultMeshDocumentHandle AsSchemaAlias() where TAlias : class; } @@ -975,9 +972,6 @@ namespace GameCult.Mesh /// Gets whether this handle can submit a client prediction for the underlying document value. public bool CanSubmitPrediction => _submitPrediction != null; - /// Gets whether this handle can accept a transparent document mutation. - public bool CanSet => CanSubmitPrediction || CanReplace; - /// Reads one coherent document snapshot. public Task LatestAsync() { @@ -1048,57 +1042,41 @@ namespace GameCult.Mesh return _submitPrediction(value); } - /// - /// Sets the document value through the configured authority shape. - /// Prediction-backed documents publish a prediction; mutable documents replace authoritatively. - /// - public Task SetAsync(TDocument value) + /// Gets an explicit authoritative replacement writer for this document. + public CultMeshDocumentWriter AuthoritativeWriter() { - if (value == null) throw new ArgumentNullException(nameof(value)); - if (_submitPrediction != null) - return _submitPrediction(value); - if (_replace != null) - return _replace(value); - - throw new NotSupportedException($"Document handle '{DocumentId}' does not accept mutations."); + if (_replace == null) + throw new NotSupportedException($"Document handle '{DocumentId}' is read-only."); + return new CultMeshDocumentWriter( + this, + CultMeshDocumentWriteKind.AuthoritativeReplacement, + _replace); } - /// Reads, updates, and sets the document value through the configured authority shape. - public async Task UpdateAsync(Func update) + /// Gets an explicit client prediction writer for this document. + public CultMeshDocumentWriter PredictionWriter() { - if (update == null) throw new ArgumentNullException(nameof(update)); - var next = update(await LatestAsync().ConfigureAwait(false)); - await SetAsync(next).ConfigureAwait(false); - return next; + if (_submitPrediction == null) + throw new NotSupportedException($"Document handle '{DocumentId}' does not accept client predictions."); + return new CultMeshDocumentWriter( + this, + CultMeshDocumentWriteKind.Prediction, + _submitPrediction); } - /// Reads, updates, and sets the document value through the configured authority shape. - public async Task UpdateAsync(Func> update) - { - if (update == null) throw new ArgumentNullException(nameof(update)); - var next = await update(await LatestAsync().ConfigureAwait(false)).ConfigureAwait(false); - await SetAsync(next).ConfigureAwait(false); - return next; - } - - /// - /// Creates a managed reactive document mirror whose local edits can be coalesced into one prediction or replacement. - /// - public async Task> ReactiveAsync( - CultMeshReactiveDocumentOptions? options = null) + /// Creates a read-only in-memory mirror updated by the document watch. + public async Task> ObserveAsync() { var current = CloneDocument(await LatestAsync().ConfigureAwait(false)); - var reactive = new CultMeshReactiveDocument(this, current, options); - reactive.Start(); - return reactive; + var observed = new CultMeshObservedDocument(this, current); + observed.Start(); + return observed; } - /// - /// Creates a managed reactive document mirror synchronously for host APIs that cannot be async. - /// - public CultMeshReactiveDocument Reactive(CultMeshReactiveDocumentOptions? options = null) + /// Creates a read-only in-memory mirror synchronously. + public CultMeshObservedDocument Observe() { - return ReactiveAsync(options).ConfigureAwait(false).GetAwaiter().GetResult(); + return ObserveAsync().ConfigureAwait(false).GetAwaiter().GetResult(); } /// Creates a same-schema alias presentation for another CLR document type. @@ -1215,6 +1193,174 @@ namespace GameCult.Mesh } } + /// + /// A read-only local mirror of a watched typed document. Observation never acquires a write + /// capability and never polls or serializes the document while idle. + /// + public sealed class CultMeshObservedDocument : IDisposable + where TDocument : class + { + private readonly object _gate = new(); + private IDisposable? _subscription; + private TDocument _current; + private bool _disposed; + + internal CultMeshObservedDocument( + CultMeshDocumentHandle document, + TDocument current) + { + Document = document ?? throw new ArgumentNullException(nameof(document)); + _current = current ?? throw new ArgumentNullException(nameof(current)); + } + + /// Gets the underlying read/watch handle. + public CultMeshDocumentHandle Document { get; } + + /// + /// Gets the current borrowed snapshot. Treat the object graph as read-only; local mutation + /// cannot publish and is replaced by the next canonical snapshot. + /// + public TDocument Current + { + get + { + lock (_gate) + { + ThrowIfDisposed(); + return _current; + } + } + } + + internal void Start() + { + _subscription = Document.Watch(ApplyCanonicalSnapshot); + } + + /// Reads and adopts a fresh canonical snapshot. + public async Task RefreshAsync() + { + ThrowIfDisposed(); + var latest = CultMeshDocumentHandle.CloneDocument( + await Document.LatestAsync().ConfigureAwait(false)); + lock (_gate) + { + ThrowIfDisposed(); + _current = latest; + return _current; + } + } + + /// + public void Dispose() + { + lock (_gate) + { + if (_disposed) + return; + _disposed = true; + } + + _subscription?.Dispose(); + } + + private void ApplyCanonicalSnapshot(TDocument canonical) + { + if (canonical == null) + return; + var next = CultMeshDocumentHandle.CloneDocument(canonical); + lock (_gate) + { + if (!_disposed) + _current = next; + } + } + + private void ThrowIfDisposed() + { + if (_disposed) + throw new ObjectDisposedException(nameof(CultMeshObservedDocument)); + } + } + + /// Names the one immutable authority path selected by a document writer. + public enum CultMeshDocumentWriteKind + { + /// The writer replaces canonical state through its owning provider. + AuthoritativeReplacement, + + /// The writer submits a client prediction or candidate for validation. + Prediction + } + + /// + /// An explicit, immutable write capability for one typed document. A writer never switches + /// between authoritative replacement and prediction based on runtime availability. + /// + public sealed class CultMeshDocumentWriter + where TDocument : class + { + private readonly Func _write; + + internal CultMeshDocumentWriter( + CultMeshDocumentHandle document, + CultMeshDocumentWriteKind kind, + Func write) + { + Document = document ?? throw new ArgumentNullException(nameof(document)); + Kind = kind; + _write = write ?? throw new ArgumentNullException(nameof(write)); + } + + /// Gets the document read/watch handle paired with this writer. + public CultMeshDocumentHandle Document { get; } + + /// Gets the immutable authority path selected for this writer. + public CultMeshDocumentWriteKind Kind { get; } + + /// Writes one value through this writer's named authority path. + public Task WriteAsync(TDocument value) + { + if (value == null) throw new ArgumentNullException(nameof(value)); + return _write(value); + } + + /// Reads, transforms, and writes through this writer's named authority path. + public async Task UpdateAsync(Func update) + { + if (update == null) throw new ArgumentNullException(nameof(update)); + var next = update(await Document.LatestAsync().ConfigureAwait(false)); + await WriteAsync(next).ConfigureAwait(false); + return next; + } + + /// Reads, transforms, and writes through this writer's named authority path. + public async Task UpdateAsync(Func> update) + { + if (update == null) throw new ArgumentNullException(nameof(update)); + var next = await update(await Document.LatestAsync().ConfigureAwait(false)).ConfigureAwait(false); + await WriteAsync(next).ConfigureAwait(false); + return next; + } + + /// Creates an explicitly writable reactive mirror. + public async Task> ReactiveAsync( + CultMeshReactiveDocumentOptions? options = null) + { + var current = CultMeshDocumentHandle.CloneDocument( + await Document.LatestAsync().ConfigureAwait(false)); + var reactive = new CultMeshReactiveDocument(this, current, options); + reactive.Start(); + return reactive; + } + + /// Creates an explicitly writable reactive mirror synchronously. + public CultMeshReactiveDocument Reactive(CultMeshReactiveDocumentOptions? options = null) + { + return ReactiveAsync(options).ConfigureAwait(false).GetAwaiter().GetResult(); + } + } + /// /// Configures a managed CultMesh reactive document mirror. /// @@ -1225,9 +1371,6 @@ namespace GameCult.Mesh /// public TimeSpan FlushDelay { get; set; } = TimeSpan.FromMilliseconds(16); - /// Gets or sets whether direct edits to Current should be detected and flushed automatically. - public bool DetectLocalChanges { get; set; } = true; - /// Gets or sets whether canonical snapshots replace dirty local predictions immediately. public bool ReplaceDirtyCurrentOnCanonicalSnapshot { get; set; } } @@ -1272,18 +1415,18 @@ namespace GameCult.Mesh } /// - /// Managed typed document mirror that keeps an editable current value and coalesces local edits into CultMesh mutations. + /// Managed typed document mirror that coalesces explicit local edits through one selected writer. /// public sealed class CultMeshReactiveDocument : IDisposable where TDocument : class { + private readonly CultMeshDocumentWriter _writer; private readonly CultMeshDocumentHandle _document; private readonly CultMeshReactiveDocumentOptions _options; private readonly object _gate = new(); private IDisposable? _subscription; private Timer? _flushTimer; - private Timer? _changeDetectionTimer; - private byte[] _lastCleanSnapshot; + private TDocument _current; private bool _dirty; private bool _flushQueued; private bool _flushing; @@ -1291,21 +1434,37 @@ namespace GameCult.Mesh private int _reconciliationVersion; internal CultMeshReactiveDocument( - CultMeshDocumentHandle document, + CultMeshDocumentWriter writer, TDocument current, CultMeshReactiveDocumentOptions? options) { - _document = document ?? throw new ArgumentNullException(nameof(document)); - Current = current ?? throw new ArgumentNullException(nameof(current)); + _writer = writer ?? throw new ArgumentNullException(nameof(writer)); + _document = writer.Document; + _current = current ?? throw new ArgumentNullException(nameof(current)); _options = options ?? new CultMeshReactiveDocumentOptions(); - _lastCleanSnapshot = SerializeDocument(Current); } + /// Gets the immutable write capability selected for this mirror. + public CultMeshDocumentWriter Writer => _writer; + /// Gets the underlying document handle. public CultMeshDocumentHandle Document => _document; - /// Gets the editable local document value. - public TDocument Current { get; private set; } + /// + /// Gets a cloned local snapshot. Mutating the returned object cannot mutate or publish the mirror; + /// use or for edits. + /// + public TDocument Snapshot + { + get + { + lock (_gate) + { + ThrowIfDisposed(); + return CultMeshDocumentHandle.CloneDocument(_current); + } + } + } /// Gets whether local edits are waiting to be sent. public bool IsDirty @@ -1323,25 +1482,6 @@ namespace GameCult.Mesh internal void Start() { _subscription = _document.Watch(ApplyCanonicalSnapshot); - if (_options.DetectLocalChanges && _document.CanSet) - { - var interval = _options.FlushDelay <= TimeSpan.Zero - ? TimeSpan.FromMilliseconds(1) - : _options.FlushDelay; - _changeDetectionTimer = new Timer(_ => _ = Task.Run(DetectLocalChangesAsync)); - _changeDetectionTimer.Change(interval, interval); - } - } - - /// Marks the current value dirty and schedules a coalesced prediction or replacement. - public void MarkDirty() - { - ThrowIfDisposed(); - lock (_gate) - { - _dirty = true; - ScheduleFlushLocked(); - } } /// Mutates the current value and schedules a coalesced prediction or replacement. @@ -1351,24 +1491,24 @@ namespace GameCult.Mesh ThrowIfDisposed(); lock (_gate) { - update(Current); + update(_current); _dirty = true; ScheduleFlushLocked(); - return Current; + return CultMeshDocumentHandle.CloneDocument(_current); } } /// Replaces the current local value and schedules a coalesced prediction or replacement. - public TDocument SetCurrent(TDocument value) + public TDocument ReplaceLocal(TDocument value) { if (value == null) throw new ArgumentNullException(nameof(value)); ThrowIfDisposed(); lock (_gate) { - Current = CultMeshDocumentHandle.CloneDocument(value); + _current = CultMeshDocumentHandle.CloneDocument(value); _dirty = true; ScheduleFlushLocked(); - return Current; + return CultMeshDocumentHandle.CloneDocument(_current); } } @@ -1380,11 +1520,10 @@ namespace GameCult.Mesh await _document.LatestAsync().ConfigureAwait(false)); lock (_gate) { - Current = latest; - _lastCleanSnapshot = SerializeDocument(Current); + _current = latest; _dirty = false; Reconciliation = null; - return Current; + return CultMeshDocumentHandle.CloneDocument(_current); } } @@ -1395,8 +1534,6 @@ namespace GameCult.Mesh lock (_gate) { ThrowIfDisposed(); - if (!_dirty && _document.CanSet) - DetectLocalChangesLocked(); if (!_dirty) return; if (_flushing) @@ -1408,13 +1545,12 @@ namespace GameCult.Mesh _flushTimer?.Change(Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan); _flushing = true; _dirty = false; - predicted = CultMeshDocumentHandle.CloneDocument(Current); - _lastCleanSnapshot = SerializeDocument(predicted); + predicted = CultMeshDocumentHandle.CloneDocument(_current); } try { - await _document.SetAsync(predicted).ConfigureAwait(false); + await _writer.WriteAsync(predicted).ConfigureAwait(false); } finally { @@ -1422,8 +1558,6 @@ namespace GameCult.Mesh lock (_gate) { _flushing = false; - if (_document.CanSet) - DetectLocalChangesLocked(); shouldFlushAgain = _flushQueued || _dirty; _flushQueued = false; } @@ -1452,7 +1586,6 @@ namespace GameCult.Mesh _subscription?.Dispose(); _flushTimer?.Dispose(); - _changeDetectionTimer?.Dispose(); } private void ApplyCanonicalSnapshot(TDocument canonical) @@ -1468,7 +1601,7 @@ namespace GameCult.Mesh var nextCanonical = CultMeshDocumentHandle.CloneDocument(canonical); if (_dirty || _flushing) { - var predicted = CultMeshDocumentHandle.CloneDocument(Current); + var predicted = CultMeshDocumentHandle.CloneDocument(_current); var delta = CreateReconciliationDelta(predicted, nextCanonical); if (delta.Count == 0) { @@ -1488,34 +1621,11 @@ namespace GameCult.Mesh return; } - Current = nextCanonical; - _lastCleanSnapshot = SerializeDocument(Current); + _current = nextCanonical; Reconciliation = null; } } - private Task DetectLocalChangesAsync() - { - lock (_gate) - { - if (_disposed || !_document.CanSet || _dirty || _flushing) - return Task.CompletedTask; - DetectLocalChangesLocked(); - if (_dirty) - ScheduleFlushLocked(); - } - - return Task.CompletedTask; - } - - private void DetectLocalChangesLocked() - { - var currentSnapshot = SerializeDocument(Current); - if (_lastCleanSnapshot.SequenceEqual(currentSnapshot)) - return; - _dirty = true; - } - private void ScheduleFlushLocked() { if (_options.FlushDelay <= TimeSpan.Zero) @@ -1528,11 +1638,6 @@ namespace GameCult.Mesh _flushTimer.Change(_options.FlushDelay, Timeout.InfiniteTimeSpan); } - private static byte[] SerializeDocument(TDocument document) - { - return CultDocumentMessagePackSerialization.SerializeUntyped(document, typeof(TDocument)); - } - private static IReadOnlyDictionary CreateReconciliationDelta( TDocument predicted, TDocument canonical) @@ -1778,13 +1883,6 @@ namespace GameCult.Mesh return TryGetDocument(out var document) && document.CanSubmitPrediction; } - /// Gets whether one typed document can accept transparent mutations by CLR type or same-schema alias. - public bool CanSet() - where TDocument : class - { - return TryGetDocument(out var document) && document.CanSet; - } - /// Submits a client prediction for one typed document by CLR type or same-schema alias. public Task SubmitPredictionAsync(TDocument value) where TDocument : class @@ -1792,25 +1890,18 @@ namespace GameCult.Mesh return Document().SubmitPredictionAsync(value); } - /// Sets one typed document through its configured authority shape by CLR type or same-schema alias. - public Task SetAsync(TDocument value) + /// Gets an explicit authoritative writer by CLR type or same-schema alias. + public CultMeshDocumentWriter AuthoritativeWriter() where TDocument : class { - return Document().SetAsync(value); + return Document().AuthoritativeWriter(); } - /// Reads, updates, and sets one typed document through its configured authority shape. - public Task UpdateAsync(Func update) + /// Gets an explicit prediction writer by CLR type or same-schema alias. + public CultMeshDocumentWriter PredictionWriter() where TDocument : class { - return Document().UpdateAsync(update); - } - - /// Reads, updates, and sets one typed document through its configured authority shape. - public Task UpdateAsync(Func> update) - where TDocument : class - { - return Document().UpdateAsync(update); + return Document().PredictionWriter(); } /// Watches one typed document by CLR type or same-schema alias. @@ -1827,21 +1918,6 @@ namespace GameCult.Mesh return Document().Watch(onNext); } - /// Creates a managed reactive document mirror by CLR type or same-schema alias. - public Task> ReactiveAsync( - CultMeshReactiveDocumentOptions? options = null) - where TDocument : class - { - return Document().ReactiveAsync(options); - } - - /// Creates a managed reactive document mirror synchronously by CLR type or same-schema alias. - public CultMeshReactiveDocument Reactive( - CultMeshReactiveDocumentOptions? options = null) - where TDocument : class - { - return Document().Reactive(options); - } } /// diff --git a/src/GameCult.Mesh/docs/document-write-authority.md b/src/GameCult.Mesh/docs/document-write-authority.md new file mode 100644 index 00000000..19cc4bb3 --- /dev/null +++ b/src/GameCult.Mesh/docs/document-write-authority.md @@ -0,0 +1,72 @@ +# CultMesh Document Write Authority + +CultMesh document reads, authoritative replacements, and client predictions are +different capabilities. A generic setter cannot choose between them without +hiding an authority decision from the caller. + +## Authority map + +Owner: + +- `CultMeshDocumentHandle` owns typed snapshot and watch access; +- an authoritative writer owns canonical replacement capability; +- a prediction writer owns candidate/prediction submission capability; +- `CultMeshReactiveDocument` owns only a local editable mirror and its + coalescing schedule. + +Inputs: + +- a bound typed live feed; +- an optional authoritative replacement delegate; +- an optional prediction delegate; +- explicit local mutations made through the reactive document API. + +Outputs: + +- coherent typed snapshots and watches; +- authoritative replacements only through an explicitly requested + authoritative writer; +- predictions only through an explicitly requested prediction writer; +- one coalesced write for each explicit burst of local mutations. + +Derived state: + +- the reactive snapshot is a local mirror, not canonical truth; +- reconciliation metadata compares a pending local write with an incoming + canonical snapshot; +- debounce timers schedule already-declared work and never inspect documents + for undeclared mutations. + +Forbidden writers: + +- `SetAsync` may not select prediction or replacement based on whichever + delegate happens to exist; +- reading or watching a document may not start serialization polling; +- mutating an exposed object graph may not silently become a network write; +- alias conversion may not erase which writer was selected. + +Shared paths: + +- direct edits, nested edits, automation, and UI bindings use `Update` or + `ReplaceLocal` on the same reactive mirror; +- explicit flush and debounced flush use the same selected writer; +- canonical watch updates and refresh use the same snapshot adoption path. + +Cut line: + +- remove `CanSet`, `SetAsync`, and ambiguous `UpdateAsync`/`ReactiveAsync` + entry points from document handles and catalogs; +- obtain either an authoritative writer or a prediction writer before editing; +- remove change-detection timers and full-document idle serialization; +- expose cloned snapshots so callers cannot mutate the live mirror behind the + mutation boundary. + +## Required proof + +- a handle carrying both capabilities cannot write until the caller selects a + writer; +- authoritative and prediction writers reach only their named delegates; +- nested edits made through `Update` are coalesced and published; +- direct mutation of a returned snapshot cannot publish; +- an idle reactive document creates no periodic detection work; +- canonical reconciliation and in-flight edits remain deterministic. diff --git a/src/GameCult.Networking/CultNetDatabase.cs b/src/GameCult.Networking/CultNetDatabase.cs index 6e1ed41f..8000e45b 100644 --- a/src/GameCult.Networking/CultNetDatabase.cs +++ b/src/GameCult.Networking/CultNetDatabase.cs @@ -503,6 +503,22 @@ namespace GameCult.Networking /// public IReadOnlyList ClientAuthorityScopes => _clientAuthorityScopes; + /// Gets whether this database instance can authoritatively replace the document at a key. + public bool CanWriteAuthoritatively(CultRecordKey key) where T : class + { + ThrowIfDisposed(); + var descriptor = _cache.Registry.GetRequired(); + return ResolveShardInternal(descriptor, key).IsPrimary; + } + + /// Gets whether this database instance can submit a prediction for the document at a key. + public bool CanSubmitPrediction(CultRecordKey key) where T : class + { + ThrowIfDisposed(); + var descriptor = _cache.Registry.GetRequired(); + return _clientAuthorityScopes.Any(scope => scope.Matches(_runtimeId, descriptor, key)); + } + /// /// Gets mutation log entries for a shard after the supplied sequence. /// diff --git a/tests/GameCult.Mesh.Tests/CultMeshStreamingTests.cs b/tests/GameCult.Mesh.Tests/CultMeshStreamingTests.cs index 05956d0d..6fafbf16 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshStreamingTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshStreamingTests.cs @@ -940,16 +940,17 @@ public sealed class CultMeshStreamingTests CultMesh.Verse("starbridge", "pilot-a")); var alias = handle.AsSchemaAlias(); - handle.CanReplace.Should().BeTrue(); + handle.CanReplace.Should().BeFalse(); + alias.CanReplace.Should().BeFalse(); alias.CanSubmitPrediction.Should().BeTrue(); - alias.CanSet.Should().BeTrue(); var catalog = CultMesh.Documents(handle); catalog.CanSubmitPrediction().Should().BeTrue(); - catalog.CanSet().Should().BeTrue(); + var predictionWriter = catalog.PredictionWriter(); + predictionWriter.Kind.Should().Be(CultMeshDocumentWriteKind.Prediction); MeshNoteDocument observed = null!; using var subscription = handle.Watch(value => observed = value); - await catalog.SetAsync(new MeshNoteAliasDocument + await predictionWriter.WriteAsync(new MeshNoteAliasDocument { Schema = "tests.mesh_note.v1", Text = "predicted-thermal", @@ -961,7 +962,7 @@ public sealed class CultMeshStreamingTests observed.Revision.Should().Be(5); (await handle.LatestAsync()).Text.Should().Be("predicted-thermal"); - var updated = await alias.UpdateAsync(value => new MeshNoteAliasDocument + var updated = await alias.PredictionWriter().UpdateAsync(value => new MeshNoteAliasDocument { Schema = value.Schema, Text = "updated-as-prediction", @@ -1002,13 +1003,13 @@ public sealed class CultMeshStreamingTests }); var catalog = CultMesh.Documents(handle); - using var reactive = await catalog.ReactiveAsync( + using var reactive = await catalog.PredictionWriter().ReactiveAsync( new CultMeshReactiveDocumentOptions { FlushDelay = TimeSpan.FromMinutes(1) }); - reactive.Current.Text.Should().Be("initial"); + reactive.Snapshot.Text.Should().Be("initial"); reactive.Update(document => { document.Text = "first-local-edit"; @@ -1052,7 +1053,7 @@ public sealed class CultMeshStreamingTests return Task.CompletedTask; }); - using var reactive = await handle.ReactiveAsync( + using var reactive = await handle.AuthoritativeWriter().ReactiveAsync( new CultMeshReactiveDocumentOptions { FlushDelay = TimeSpan.FromMinutes(1) @@ -1071,7 +1072,7 @@ public sealed class CultMeshStreamingTests Revision = 7 }); - reactive.Current.Text.Should().Be("local-prediction"); + reactive.Snapshot.Text.Should().Be("local-prediction"); reactive.Reconciliation.Should().NotBeNull(); reactive.Reconciliation!.Version.Should().Be(1); reactive.Reconciliation!.Canonical.Text.Should().Be("canonical-correction"); @@ -1112,7 +1113,7 @@ public sealed class CultMeshStreamingTests return Task.CompletedTask; }); - using var reactive = await handle.ReactiveAsync( + using var reactive = await handle.PredictionWriter().ReactiveAsync( new CultMeshReactiveDocumentOptions { FlushDelay = TimeSpan.FromMilliseconds(25) @@ -1137,7 +1138,7 @@ public sealed class CultMeshStreamingTests } [Test] - public async Task ReactiveDocument_DetectsAndCoalescesDirectCurrentMemberWrites() + public async Task ReactiveDocument_CoalescesExplicitMemberUpdates() { var subject = new Subject(); var current = new MeshNoteDocument @@ -1166,26 +1167,29 @@ public sealed class CultMeshStreamingTests return Task.CompletedTask; }); - using var reactive = await handle.ReactiveAsync( + using var reactive = await handle.PredictionWriter().ReactiveAsync( new CultMeshReactiveDocumentOptions { FlushDelay = TimeSpan.FromMilliseconds(25) }); - reactive.Current.Text = "direct-member-one"; - reactive.Current.Text = "direct-member-two"; - reactive.Current.Revision = 2; + reactive.Update(document => document.Text = "explicit-member-one"); + reactive.Update(document => + { + document.Text = "explicit-member-two"; + document.Revision = 2; + }); await WaitForAsync(() => predictions.Count == 1); - predictions[0].Text.Should().Be("direct-member-two"); + predictions[0].Text.Should().Be("explicit-member-two"); predictions[0].Revision.Should().Be(2); - current.Text.Should().Be("direct-member-two"); + current.Text.Should().Be("explicit-member-two"); reactive.IsDirty.Should().BeFalse(); } [Test] - public async Task ReactiveDocument_QueuesDirectCurrentEditsWhileFlushIsInFlight() + public async Task ReactiveDocument_QueuesExplicitEditsWhileFlushIsInFlight() { var subject = new Subject(); var current = new MeshNoteDocument @@ -1221,7 +1225,7 @@ public sealed class CultMeshStreamingTests subject.OnNext(value); }); - using var reactive = await handle.ReactiveAsync( + using var reactive = await handle.PredictionWriter().ReactiveAsync( new CultMeshReactiveDocumentOptions { FlushDelay = TimeSpan.FromMinutes(1) @@ -1235,8 +1239,11 @@ public sealed class CultMeshStreamingTests var flushTask = reactive.FlushAsync(); await firstPredictionStarted.Task; - reactive.Current.Text = "second-after-flight-started"; - reactive.Current.Revision = 3; + reactive.Update(document => + { + document.Text = "second-after-flight-started"; + document.Revision = 3; + }); releaseFirstPrediction.SetResult(); await flushTask; @@ -1274,7 +1281,7 @@ public sealed class CultMeshStreamingTests return Task.CompletedTask; }); - using var reactive = await handle.ReactiveAsync( + using var reactive = await handle.AuthoritativeWriter().ReactiveAsync( new CultMeshReactiveDocumentOptions { FlushDelay = TimeSpan.FromMinutes(1) @@ -1293,7 +1300,7 @@ public sealed class CultMeshStreamingTests } [Test] - public async Task ReactiveDocument_ReadOnlyHandleRejectsFlush() + public void ReactiveDocument_ReadOnlyHandleRejectsWriterSelection() { var current = new MeshNoteDocument { @@ -1307,16 +1314,45 @@ public sealed class CultMeshStreamingTests _ => Task.FromResult(current), _ => new Subject()); - using var reactive = await handle.ReactiveAsync( - new CultMeshReactiveDocumentOptions - { - FlushDelay = TimeSpan.FromMinutes(1) - }); - reactive.Update(document => document.Text = "not-allowed"); + Action authoritative = () => handle.AuthoritativeWriter(); + Action prediction = () => handle.PredictionWriter(); - Func act = () => reactive.FlushAsync(); + authoritative.Should().Throw(); + prediction.Should().Throw(); + } - await act.Should().ThrowAsync(); + [Test] + public async Task ObservedDocument_WatchesWithoutWriteCapabilityOrIdleTimer() + { + var subject = new Subject(); + var current = new MeshNoteDocument + { + Schema = "tests.mesh_note.v1", + Text = "initial", + Revision = 1 + }; + var handle = CultMesh.Document( + "mesh.note.observed.readonly", + CultMesh.Verse("starbridge", "observer"), + _ => Task.FromResult(current), + _ => subject); + + using var observed = await handle.ObserveAsync(); + observed.Current.Text.Should().Be("initial"); + typeof(CultMeshObservedDocument) + .GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic) + .Should() + .NotContain(field => field.FieldType == typeof(System.Threading.Timer)); + + subject.OnNext(new MeshNoteDocument + { + Schema = "tests.mesh_note.v1", + Text = "canonical-update", + Revision = 2 + }); + + observed.Current.Text.Should().Be("canonical-update"); + observed.Current.Revision.Should().Be(2); } [Test] @@ -1349,7 +1385,7 @@ public sealed class CultMeshStreamingTests return Task.CompletedTask; }); - var reactive = await handle.ReactiveAsync( + var reactive = await handle.PredictionWriter().ReactiveAsync( new CultMeshReactiveDocumentOptions { FlushDelay = TimeSpan.FromMilliseconds(25) @@ -1384,7 +1420,7 @@ public sealed class CultMeshStreamingTests return Task.CompletedTask; }); - using var reactive = await handle.ReactiveAsync( + using var reactive = await handle.AuthoritativeWriter().ReactiveAsync( new CultMeshReactiveDocumentOptions { FlushDelay = TimeSpan.FromMinutes(1), @@ -1399,8 +1435,8 @@ public sealed class CultMeshStreamingTests Revision = 9 }); - reactive.Current.Text.Should().Be("canonical-wins"); - reactive.Current.Revision.Should().Be(9); + reactive.Snapshot.Text.Should().Be("canonical-wins"); + reactive.Snapshot.Revision.Should().Be(9); reactive.Reconciliation.Should().BeNull(); } @@ -1426,7 +1462,7 @@ public sealed class CultMeshStreamingTests return Task.CompletedTask; }); - using var reactive = await handle.ReactiveAsync( + using var reactive = await handle.AuthoritativeWriter().ReactiveAsync( new CultMeshReactiveDocumentOptions { FlushDelay = TimeSpan.FromMinutes(1) @@ -1442,7 +1478,7 @@ public sealed class CultMeshStreamingTests await reactive.RefreshAsync(); await reactive.FlushAsync(); - reactive.Current.Text.Should().Be("fresh-canonical"); + reactive.Snapshot.Text.Should().Be("fresh-canonical"); reactive.IsDirty.Should().BeFalse(); replacements.Should().BeEmpty(); } @@ -1495,7 +1531,8 @@ public sealed class CultMeshStreamingTests .Watch(observedByCommander.Add); using var pilotReactive = await CultMesh .Documents(pilotHandle) - .ReactiveAsync( + .PredictionWriter() + .ReactiveAsync( new CultMeshReactiveDocumentOptions { FlushDelay = TimeSpan.FromMinutes(1) @@ -1557,14 +1594,13 @@ public sealed class CultMeshStreamingTests database, key, CultMesh.Verse("starbridge", "commander-rts")); - using var commanderReactive = await commanderHandle + MeshNoteAliasDocument commanderSnapshot = null!; + using var commanderSubscription = commanderHandle .AsSchemaAlias() - .ReactiveAsync(new CultMeshReactiveDocumentOptions - { - FlushDelay = TimeSpan.FromMinutes(1) - }); + .Watch(value => commanderSnapshot = value); using var pilotReactive = await pilotHandle .AsSchemaAlias() + .PredictionWriter() .ReactiveAsync(new CultMeshReactiveDocumentOptions { FlushDelay = TimeSpan.FromMinutes(1) @@ -1582,16 +1618,16 @@ public sealed class CultMeshStreamingTests }); await pilotReactive.FlushAsync(); - await WaitForAsync(() => commanderReactive.Current.Text == "pilot-coalesced-order"); + await WaitForAsync(() => commanderSnapshot?.Text == "pilot-coalesced-order"); pilotReactive.IsDirty.Should().BeFalse(); - commanderReactive.Document.Context.RuntimeId.Should().Be("commander-rts"); - commanderReactive.Current.Revision.Should().Be(3); + commanderHandle.Context.RuntimeId.Should().Be("commander-rts"); + commanderSnapshot.Revision.Should().Be(3); cache.Get(key)!.Text.Should().Be("pilot-coalesced-order"); } [Test] - public async Task NodeReactiveDocument_OpensSameSchemaAliasWithOneCall() + public async Task NodeDocument_OpensExplicitPredictionWriterForSameSchemaAlias() { var schemaId = CultDocumentRegistry.Shared.GetRequired().SchemaId; using var temp = new TemporaryDirectory(); @@ -1630,10 +1666,10 @@ public sealed class CultMeshStreamingTests Revision = 1 }, new CultRecordHandle(key)); - using var pilotReactive = await node.ReactiveDocumentAsync( - key, - CultMesh.Verse("starbridge", "pilot-a"), - new CultMeshReactiveDocumentOptions + using var pilotReactive = await node + .Document(key, CultMesh.Verse("starbridge", "pilot-a")) + .PredictionWriter() + .ReactiveAsync(new CultMeshReactiveDocumentOptions { FlushDelay = TimeSpan.FromMinutes(1) }); @@ -1658,7 +1694,7 @@ public sealed class CultMeshStreamingTests } [Test] - public async Task ReactiveDocument_SyncedSnapshotEndpointCapturesCanonicalCorrectionAcrossRuntimeBoundary() + public async Task SyncedSnapshotEndpointObservesCanonicalCorrectionAcrossRuntimeBoundary() { var sourceCache = new CultCache(); var registry = new CultNetDocumentRegistry(CultDocumentRegistry.Shared); @@ -1700,18 +1736,10 @@ public sealed class CultMeshStreamingTests { DocumentRegistry = registry } - }); + }); var handle = surface.SyncTo(node).Document(key.Value); - using var reactive = await handle.ReactiveAsync(new CultMeshReactiveDocumentOptions - { - FlushDelay = TimeSpan.FromMinutes(1) - }); - - reactive.Update(document => - { - document.Text = "local-prediction"; - document.Revision = 2; - }); + MeshNoteAliasDocument observed = null!; + using var subscription = handle.Watch(value => observed = value); await sourceCache.UpsertAsync(new MeshNoteDocument { Schema = "tests.mesh_note.v1", @@ -1719,11 +1747,9 @@ public sealed class CultMeshStreamingTests Revision = 7 }, new CultRecordHandle(key)); - await WaitForAsync(() => reactive.Reconciliation?.Canonical.Text == "remote-authority-correction"); + await WaitForAsync(() => observed?.Text == "remote-authority-correction"); - reactive.Current.Text.Should().Be("local-prediction"); - reactive.Reconciliation!.Predicted.Text.Should().Be("local-prediction"); - reactive.Reconciliation.Canonical.Revision.Should().Be(7); + observed.Revision.Should().Be(7); node.Cache.Get(key)!.Text.Should().Be("remote-authority-correction"); } @@ -1796,13 +1822,13 @@ public sealed class CultMeshStreamingTests DocumentRegistry = registry } }); - using var reactive = await surface + var reconstructed = await surface .SyncTo(freshRuntime) .Documents(CultMesh.SnapshotDocument(key.Value)) - .ReactiveAsync(); + .LatestAsync(); - reactive.Current.Text.Should().Be("after-reboot-authority"); - reactive.Current.Revision.Should().Be(4); + reconstructed.Text.Should().Be("after-reboot-authority"); + reconstructed.Revision.Should().Be(4); freshRuntime.Cache.Get(key)!.Text.Should().Be("after-reboot-authority"); } @@ -1849,17 +1875,11 @@ public sealed class CultMeshStreamingTests DocumentRegistry = registry } }); - using var reactive = await surface + var readOnlyHandle = surface .SyncTo(node) - .Document(key.Value) - .ReactiveAsync(new CultMeshReactiveDocumentOptions - { - FlushDelay = TimeSpan.FromMinutes(1) - }); - reactive.Update(document => document.Text = "observer-should-not-write"); - - Func flush = () => reactive.FlushAsync(); - await flush.Should().ThrowAsync(); + .Document(key.Value); + readOnlyHandle.CanReplace.Should().BeFalse(); + readOnlyHandle.CanSubmitPrediction.Should().BeFalse(); await sourceCache.UpsertAsync(new MeshNoteDocument { @@ -1867,16 +1887,14 @@ public sealed class CultMeshStreamingTests Text = "fresh-authority", Revision = 5 }, new CultRecordHandle(key)); - await reactive.RefreshAsync(); - await reactive.FlushAsync(); + var refreshed = await readOnlyHandle.LatestAsync(); - reactive.Current.Text.Should().Be("fresh-authority"); - reactive.IsDirty.Should().BeFalse(); + refreshed.Text.Should().Be("fresh-authority"); node.Cache.Get(key)!.Revision.Should().Be(5); } [Test] - public async Task ReactiveDocument_MarkDirtyFlushesDirectMemberEdits() + public async Task ReactiveDocument_SnapshotMutationCannotPublish() { var subject = new Subject(); var current = new MeshNoteDocument @@ -1905,24 +1923,24 @@ public sealed class CultMeshStreamingTests return Task.CompletedTask; }); - using var reactive = await handle.ReactiveAsync( + using var reactive = await handle.PredictionWriter().ReactiveAsync( new CultMeshReactiveDocumentOptions { FlushDelay = TimeSpan.FromMinutes(1) }); - reactive.Current.Text = "direct-member-edit"; - reactive.Current.Revision = 12; - reactive.MarkDirty(); + var escapedSnapshot = reactive.Snapshot; + escapedSnapshot.Text = "must-not-publish"; + escapedSnapshot.Revision = 12; await reactive.FlushAsync(); - predictions.Should().ContainSingle(); - predictions[0].Text.Should().Be("direct-member-edit"); - predictions[0].Revision.Should().Be(12); + predictions.Should().BeEmpty(); + reactive.Snapshot.Text.Should().Be("initial"); + reactive.IsDirty.Should().BeFalse(); } [Test] - public async Task ReactiveDocument_DetectsDirectMemberEditsWithoutMarkDirty() + public async Task ReactiveDocument_IdleMirrorDoesNotPublishUntilExplicitUpdate() { var subject = new Subject(); var current = new MeshNoteDocument @@ -1951,26 +1969,30 @@ public sealed class CultMeshStreamingTests return Task.CompletedTask; }); - using var reactive = await handle.ReactiveAsync( + using var reactive = await handle.PredictionWriter().ReactiveAsync( new CultMeshReactiveDocumentOptions { FlushDelay = TimeSpan.FromMilliseconds(10) }); - reactive.Current.Text = "direct-member-edit"; - reactive.Current.Revision = 2; - reactive.Current.Text = "direct-member-edit-final"; - reactive.Current.Revision = 3; + await Task.Delay(75); + predictions.Should().BeEmpty(); + + reactive.Update(document => + { + document.Text = "explicit-member-edit"; + document.Revision = 3; + }); await WaitForAsync(() => predictions.Count == 1); - predictions[0].Text.Should().Be("direct-member-edit-final"); + predictions[0].Text.Should().Be("explicit-member-edit"); predictions[0].Revision.Should().Be(3); reactive.IsDirty.Should().BeFalse(); } [Test] - public async Task ReactiveDocument_FlushAsyncCapturesDirectMemberEdit() + public async Task ReactiveDocument_ReplaceLocalFlushesWholeDocument() { var subject = new Subject(); var current = new MeshNoteDocument @@ -1999,18 +2021,22 @@ public sealed class CultMeshStreamingTests return Task.CompletedTask; }); - using var reactive = await handle.ReactiveAsync( + using var reactive = await handle.PredictionWriter().ReactiveAsync( new CultMeshReactiveDocumentOptions { FlushDelay = TimeSpan.FromMinutes(1) }); - reactive.Current.Text = "direct-member-flush"; - reactive.Current.Revision = 4; + reactive.ReplaceLocal(new MeshNoteDocument + { + Schema = "tests.mesh_note.v1", + Text = "whole-document-replacement", + Revision = 4 + }); await reactive.FlushAsync(); predictions.Should().ContainSingle(); - predictions[0].Text.Should().Be("direct-member-flush"); + predictions[0].Text.Should().Be("whole-document-replacement"); predictions[0].Revision.Should().Be(4); } @@ -2036,7 +2062,7 @@ public sealed class CultMeshStreamingTests return Task.CompletedTask; }); - using var reactive = await handle.ReactiveAsync(); + using var reactive = await handle.AuthoritativeWriter().ReactiveAsync(); await reactive.FlushAsync(); @@ -2081,7 +2107,7 @@ public sealed class CultMeshStreamingTests subject.OnNext(value); }); - using var reactive = await handle.ReactiveAsync( + using var reactive = await handle.PredictionWriter().ReactiveAsync( new CultMeshReactiveDocumentOptions { FlushDelay = TimeSpan.FromMinutes(1) @@ -2138,7 +2164,7 @@ public sealed class CultMeshStreamingTests return Task.CompletedTask; }); - using var reactive = await handle.ReactiveAsync( + using var reactive = await handle.PredictionWriter().ReactiveAsync( new CultMeshReactiveDocumentOptions { FlushDelay = TimeSpan.FromMilliseconds(35) @@ -2161,7 +2187,7 @@ public sealed class CultMeshStreamingTests } [Test] - public async Task ReactiveDocument_DirectEditsDuringInFlightFlushQueueLatestPrediction() + public async Task ReactiveDocument_ExplicitEditsDuringInFlightFlushQueueLatestPrediction() { var subject = new Subject(); var current = new MeshNoteDocument @@ -2197,24 +2223,30 @@ public sealed class CultMeshStreamingTests subject.OnNext(value); }); - using var reactive = await handle.ReactiveAsync( + using var reactive = await handle.PredictionWriter().ReactiveAsync( new CultMeshReactiveDocumentOptions { FlushDelay = TimeSpan.FromMinutes(1) }); - reactive.Current.Text = "first-direct"; - reactive.Current.Revision = 2; + reactive.Update(document => + { + document.Text = "first-explicit"; + document.Revision = 2; + }); var flush = reactive.FlushAsync(); await firstWriteStarted.Task; - reactive.Current.Text = "second-direct"; - reactive.Current.Revision = 3; + reactive.Update(document => + { + document.Text = "second-explicit"; + document.Revision = 3; + }); allowFirstWrite.SetResult(true); await flush; predictions.Should().HaveCount(2); - predictions[0].Text.Should().Be("first-direct"); - predictions[1].Text.Should().Be("second-direct"); + predictions[0].Text.Should().Be("first-explicit"); + predictions[1].Text.Should().Be("second-explicit"); reactive.IsDirty.Should().BeFalse(); } @@ -2246,7 +2278,7 @@ public sealed class CultMeshStreamingTests return Task.CompletedTask; }); - using var reactive = await handle.ReactiveAsync( + using var reactive = await handle.PredictionWriter().ReactiveAsync( new CultMeshReactiveDocumentOptions { FlushDelay = TimeSpan.FromMinutes(1) @@ -2259,7 +2291,7 @@ public sealed class CultMeshStreamingTests await reactive.FlushAsync(); - reactive.Current.Text.Should().Be("accepted"); + reactive.Snapshot.Text.Should().Be("accepted"); reactive.Reconciliation.Should().BeNull(); reactive.IsDirty.Should().BeFalse(); } From 425b430fe68622afa7f4a4ae6888aea7ce8bed4c Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 17 Aug 2026 19:58:54 +0200 Subject: [PATCH 055/283] Make CultMesh TypeScript document writes explicit --- packages/cultmesh-ts/README.md | 13 +- packages/cultmesh-ts/src/index.ts | 468 +++++++++++---------- packages/cultmesh-ts/test/cultmesh.test.ts | 192 ++++++--- 3 files changed, 388 insertions(+), 285 deletions(-) diff --git a/packages/cultmesh-ts/README.md b/packages/cultmesh-ts/README.md index 9c4dfb01..d3fe565b 100644 --- a/packages/cultmesh-ts/README.md +++ b/packages/cultmesh-ts/README.md @@ -99,11 +99,13 @@ const station = await CultMesh.startNode(statePath, { const stock = station.document(stationStockUiDocument, "station:starbridge:stock"); const current = await stock.latest(); -await stock.set(updatedStockFromUi); +await stock.authoritativeWriter().write(updatedStockFromUi); -const reactive = station.reactiveDocument(stationStockUiDocument, "station:starbridge:stock"); +const reactive = stock.authoritativeWriter().reactive(); await reactive.ready; -reactive.current.availableMissiles -= 4; +reactive.update(draft => { + draft.availableMissiles -= 4; +}); ``` State pointers are the same kind of managed surface for UI and tools. They can @@ -418,7 +420,8 @@ Use `node.syncDocumentFromPeerSnapshot(...)` or local node from the remote snapshot. The helper requests the raw snapshot, applies it through the node's document registry, and returns the requested typed definition. Same-schema aliases stay local after the call: the caller can -keep using `node.document(aliasDefinition, key)` or `node.reactiveDocument(...)` +keep using `node.document(aliasDefinition, key)` and explicitly select +`authoritativeWriter()`, `predictionWriter()`, or `observe()` without re-threading the RUDP peer. The same typed-definition overload is available for @@ -432,7 +435,7 @@ sync came from local persistence or a remote CultNet snapshot. Use `node.syncDocumentFromPublication(...)` or `CultMesh.syncDocumentFromPublication(...)` for the same source-agnostic shape when the publication should hydrate a local node before the caller continues -through `node.document(...)` or `node.reactiveDocument(...)`. +through `node.document(...)` and its explicit writer or observer. ## Streaming Mode diff --git a/packages/cultmesh-ts/src/index.ts b/packages/cultmesh-ts/src/index.ts index aa84f5f9..5d81425e 100644 --- a/packages/cultmesh-ts/src/index.ts +++ b/packages/cultmesh-ts/src/index.ts @@ -232,6 +232,7 @@ export interface CultMeshReactiveDocumentOptions { readonly context?: CultMeshQueryContext | string; readonly watch?: boolean; readonly debounceMs?: number; + readonly replaceDirtyCurrentOnCanonicalSnapshot?: boolean; readonly onError?: (error: unknown) => void; } @@ -248,15 +249,30 @@ export interface CultMeshReactiveDocumentReconciliation { - readonly current: TDocument; + readonly writer: CultMeshDocumentWriter; + readonly snapshot: TDocument; + readonly dirty: boolean; readonly reconciliation: CultMeshReactiveDocumentReconciliation | undefined; readonly ready: Promise; readonly disposed: boolean; + update(update: (draft: TDocument) => void | TDocument): TDocument; + replaceLocal(value: TDocument): TDocument; + flush(): Promise; clearReconciliation(): void; refresh(): Promise; dispose(): void; } +export interface CultMeshObservedDocument { + readonly current: TDocument; + readonly ready: Promise; + readonly disposed: boolean; + refresh(): Promise; + dispose(): void; +} + +export type CultMeshDocumentWriteKind = "authoritative-replacement" | "prediction"; + export interface CultMeshNativeSliceColumn { readonly name: string; readonly valueType: string; @@ -842,10 +858,6 @@ export class CultMeshDocumentHandle { return this.submitPredictionDocument !== undefined; } - public get canSet(): boolean { - return this.canSubmitPrediction || this.canReplace; - } - public latest(context: CultMeshQueryContext | string = "local"): Promise { return this.snapshotDocument( this.resolveContext(typeof context === "string" ? cultMeshQueryContext(context) : context), @@ -932,63 +944,44 @@ export class CultMeshDocumentHandle { return this.submitPredictionDocument(this.resolveContext(context), value); } - public set(value: TDocument): Promise; - public set(context: CultMeshQueryContext | string, value: TDocument): Promise; - public set( - contextOrValue: CultMeshQueryContext | string | TDocument, - maybeValue?: TDocument, - ): Promise { - const hasContext = - typeof contextOrValue === "string" || isCultMeshQueryContext(contextOrValue); - const context = hasContext - ? typeof contextOrValue === "string" - ? cultMeshQueryContext(contextOrValue) - : contextOrValue as CultMeshQueryContext - : cultMeshQueryContext("local"); - const value = hasContext ? maybeValue : contextOrValue as TDocument; - if (value === undefined) { - throw new Error(`Document '${this.documentId}' requires a value.`); + public authoritativeWriter( + context: CultMeshQueryContext | string = "local", + ): CultMeshDocumentWriter { + if (!this.replaceDocument) { + throw new Error(`Document '${this.documentId}' does not support authoritative replacement.`); } - - const resolved = this.resolveContext(context); - if (this.submitPredictionDocument) { - return this.submitPredictionDocument(resolved, value); - } - if (this.replaceDocument) { - return this.replaceDocument(resolved, value); - } - - throw new Error(`Document '${this.documentId}' does not support mutation.`); + const resolved = this.resolveContext( + typeof context === "string" ? cultMeshQueryContext(context) : context, + ); + return new CultMeshDocumentWriter( + this as unknown as CultMeshDocumentHandle, + "authoritative-replacement", + resolved, + value => this.replaceDocument!(resolved, value as unknown as TDocument), + ); } - public update(update: CultMeshDocumentUpdater): Promise; - public update( - context: CultMeshQueryContext | string, - update: CultMeshDocumentUpdater, - ): Promise; - public async update( - contextOrUpdate: CultMeshQueryContext | string | CultMeshDocumentUpdater, - maybeUpdate?: CultMeshDocumentUpdater, - ): Promise { - const hasContext = - typeof contextOrUpdate === "string" || isCultMeshQueryContext(contextOrUpdate); - const context = hasContext - ? contextOrUpdate as CultMeshQueryContext | string - : "local"; - const update = hasContext ? maybeUpdate : contextOrUpdate as CultMeshDocumentUpdater; - if (!update) { - throw new Error(`Document '${this.documentId}' requires an update function.`); + public predictionWriter( + context: CultMeshQueryContext | string = "local", + ): CultMeshDocumentWriter { + if (!this.submitPredictionDocument) { + throw new Error(`Document '${this.documentId}' does not support prediction submission.`); } - - const next = await update(await this.latest(context)); - await this.set(context, next); - return next; + const resolved = this.resolveContext( + typeof context === "string" ? cultMeshQueryContext(context) : context, + ); + return new CultMeshDocumentWriter( + this as unknown as CultMeshDocumentHandle, + "prediction", + resolved, + value => this.submitPredictionDocument!(resolved, value as unknown as TDocument), + ); } - public reactive( + public observe( options: CultMeshReactiveDocumentOptions = {}, - ): CultMeshReactiveDocument { - return new CultMeshReactiveDocumentHandle( + ): CultMeshObservedDocument { + return new CultMeshObservedDocumentHandle( this as unknown as CultMeshDocumentHandle, options, ); @@ -1041,22 +1034,40 @@ export class CultMeshDocumentHandle { } } -class CultMeshReactiveDocumentHandle - implements CultMeshReactiveDocument { +export class CultMeshDocumentWriter { + public constructor( + public readonly document: CultMeshDocumentHandle, + public readonly kind: CultMeshDocumentWriteKind, + public readonly context: CultMeshQueryContext, + private readonly writeDocument: (value: TDocument) => Promise, + ) {} + + public write(value: TDocument): Promise { + return this.writeDocument(cloneCultMeshDocument(value)); + } + + public async update(update: CultMeshDocumentUpdater): Promise { + const next = await update(cloneCultMeshDocument(await this.document.latest(this.context))); + await this.write(next); + return next; + } + + public reactive( + options: Omit = {}, + ): CultMeshReactiveDocument { + return new CultMeshReactiveDocumentHandle(this, options); + } +} + +class CultMeshObservedDocumentHandle + implements CultMeshObservedDocument { readonly #document: CultMeshDocumentHandle; readonly #context: CultMeshQueryContext | string; readonly #onError: (error: unknown) => void; - readonly #debounceMs: number; - #current: TDocument; + #canonicalVersion = 0; + #current = {} as TDocument; #disposed = false; - #applyingRemote = false; - #pendingSet: Promise = Promise.resolve(); - #flushScheduled = false; - #flushTimer: ReturnType | undefined; #unsubscribe: CultMeshUnsubscribe | undefined; - #lastPredicted: TDocument | undefined; - #reconciliation: CultMeshReactiveDocumentReconciliation | undefined; - #reconciliationVersion = 0; public readonly ready: Promise; @@ -1066,19 +1077,17 @@ class CultMeshReactiveDocumentHandle ) { this.#document = document; this.#context = options.context ?? "local"; - this.#debounceMs = options.debounceMs ?? 0; this.#onError = options.onError ?? ((error) => { queueMicrotask(() => { throw error; }); }); - this.#current = this.createProxy({} as TDocument); this.ready = this.refresh(); - if (options.watch !== false) { try { this.#unsubscribe = document.watch(this.#context, value => { - this.applySnapshot(value); + this.#current = cloneCultMeshDocument(value); + this.#canonicalVersion++; }); } catch (error) { this.#onError(error); @@ -1087,9 +1096,100 @@ class CultMeshReactiveDocumentHandle } public get current(): TDocument { + this.throwIfDisposed(); return this.#current; } + public get disposed(): boolean { + return this.#disposed; + } + + public async refresh(): Promise { + this.throwIfDisposed(); + const versionBeforeRead = this.#canonicalVersion; + const latest = cloneCultMeshDocument(await this.#document.latest(this.#context)); + if (versionBeforeRead === this.#canonicalVersion) { + this.#current = latest; + this.#canonicalVersion++; + } + return this.#current; + } + + public dispose(): void { + if (this.#disposed) return; + this.#disposed = true; + this.#unsubscribe?.(); + this.#unsubscribe = undefined; + } + + private throwIfDisposed(): void { + if (this.#disposed) { + throw new Error(`Observed document '${this.#document.documentId}' is disposed.`); + } + } +} + +class CultMeshReactiveDocumentHandle + implements CultMeshReactiveDocument { + readonly #writer: CultMeshDocumentWriter; + readonly #document: CultMeshDocumentHandle; + readonly #onError: (error: unknown) => void; + readonly #debounceMs: number; + readonly #replaceDirtyCurrentOnCanonicalSnapshot: boolean; + #current = {} as TDocument; + #disposed = false; + #pendingSet: Promise = Promise.resolve(); + #flushScheduled = false; + #flushTimer: ReturnType | undefined; + #unsubscribe: CultMeshUnsubscribe | undefined; + #dirty = false; + #lastPredicted: TDocument | undefined; + #reconciliation: CultMeshReactiveDocumentReconciliation | undefined; + #reconciliationVersion = 0; + #canonicalVersion = 0; + + public readonly ready: Promise; + + public constructor( + writer: CultMeshDocumentWriter, + options: Omit = {}, + ) { + this.#writer = writer; + this.#document = writer.document; + this.#debounceMs = options.debounceMs ?? 0; + this.#replaceDirtyCurrentOnCanonicalSnapshot = + options.replaceDirtyCurrentOnCanonicalSnapshot ?? false; + this.#onError = options.onError ?? ((error) => { + queueMicrotask(() => { + throw error; + }); + }); + this.ready = this.refresh(); + + if (options.watch !== false) { + try { + this.#unsubscribe = this.#document.watch(this.#writer.context, value => { + this.applySnapshot(value); + }); + } catch (error) { + this.#onError(error); + } + } + } + + public get writer(): CultMeshDocumentWriter { + return this.#writer; + } + + public get snapshot(): TDocument { + this.throwIfDisposed(); + return cloneCultMeshDocument(this.#current); + } + + public get dirty(): boolean { + return this.#dirty; + } + public get reconciliation(): CultMeshReactiveDocumentReconciliation | undefined { return this.#reconciliation; } @@ -1099,9 +1199,37 @@ class CultMeshReactiveDocumentHandle } public async refresh(): Promise { - const latest = await this.#document.latest(this.#context); - this.applySnapshot(latest); - return this.#current; + this.throwIfDisposed(); + const versionBeforeRead = this.#canonicalVersion; + const latest = await this.#document.latest(this.#writer.context); + if (versionBeforeRead === this.#canonicalVersion) { + this.applySnapshot(latest); + } + return this.snapshot; + } + + public update(update: (draft: TDocument) => void | TDocument): TDocument { + this.throwIfDisposed(); + const draft = cloneCultMeshDocument(this.#current); + const returned = update(draft); + this.#current = cloneCultMeshDocument(returned ?? draft); + this.#dirty = true; + this.queueSet(); + return this.snapshot; + } + + public replaceLocal(value: TDocument): TDocument { + this.throwIfDisposed(); + this.#current = cloneCultMeshDocument(value); + this.#dirty = true; + this.queueSet(); + return this.snapshot; + } + + public async flush(): Promise { + this.throwIfDisposed(); + this.flushNow(); + await this.#pendingSet; } public clearReconciliation(): void { @@ -1121,18 +1249,13 @@ class CultMeshReactiveDocumentHandle private applySnapshot(value: TDocument): void { const canonical = cloneCultMeshDocument(value); + this.#canonicalVersion++; this.captureReconciliation(canonical); - this.#applyingRemote = true; - try { - for (const key of Reflect.ownKeys(this.#current)) { - if (!Reflect.has(canonical, key)) { - Reflect.deleteProperty(this.#current, key); - } - } - Object.assign(this.#current, canonical); - } finally { - this.#applyingRemote = false; + if (this.#dirty && !this.#replaceDirtyCurrentOnCanonicalSnapshot) { + return; } + this.#current = canonical; + this.#dirty = false; } private captureReconciliation(canonical: TDocument): void { @@ -1158,27 +1281,6 @@ class CultMeshReactiveDocumentHandle this.#lastPredicted = undefined; } - private createProxy(seed: TDocument): TDocument { - return new Proxy(seed, { - set: (target, property, value) => { - const changed = !Object.is(Reflect.get(target, property), value); - const ok = Reflect.set(target, property, value); - if (ok && changed && !this.#applyingRemote) { - this.queueSet(); - } - return ok; - }, - deleteProperty: (target, property) => { - const hadProperty = Reflect.has(target, property); - const ok = Reflect.deleteProperty(target, property); - if (ok && hadProperty && !this.#applyingRemote) { - this.queueSet(); - } - return ok; - }, - }); - } - private queueSet(): void { if (this.#disposed) { return; @@ -1188,20 +1290,7 @@ class CultMeshReactiveDocumentHandle } this.#flushScheduled = true; - const flush = () => { - this.#flushScheduled = false; - this.#flushTimer = undefined; - if (this.#disposed) { - return; - } - - const snapshot = cloneCultMeshDocument(this.#current); - this.#lastPredicted = snapshot; - this.#pendingSet = this.#pendingSet - .catch(() => undefined) - .then(() => this.#document.set(this.#context, snapshot)) - .catch(error => this.#onError(error)); - }; + const flush = () => this.flushNow(); const debounceMs = this.#debounceMs; if (debounceMs > 0) { @@ -1219,6 +1308,29 @@ class CultMeshReactiveDocumentHandle this.#flushTimer = setTimeout(flush, 0); } + + private flushNow(): void { + if (!this.#flushScheduled && !this.#dirty) return; + this.#flushScheduled = false; + if (this.#flushTimer !== undefined) { + clearTimeout(this.#flushTimer); + this.#flushTimer = undefined; + } + if (this.#disposed || !this.#dirty) return; + const snapshot = cloneCultMeshDocument(this.#current); + this.#dirty = false; + this.#lastPredicted = snapshot; + this.#pendingSet = this.#pendingSet + .catch(() => undefined) + .then(() => this.#writer.write(snapshot)) + .catch(error => this.#onError(error)); + } + + private throwIfDisposed(): void { + if (this.#disposed) { + throw new Error(`Reactive document '${this.#document.documentId}' is disposed.`); + } + } } function cloneCultMeshDocument(value: TDocument): TDocument { @@ -1295,10 +1407,6 @@ export class CultMeshBoundDocumentHandle { return this.document.canSubmitPrediction; } - public get canSet(): boolean { - return this.document.canSet; - } - public latest(): Promise { return this.document.latest(cultMeshQueryContextFromVerse(this.verse)); } @@ -1319,18 +1427,18 @@ export class CultMeshBoundDocumentHandle { return this.document.submitPrediction(cultMeshQueryContextFromVerse(this.verse), value); } - public set(value: TDocument): Promise { - return this.document.set(cultMeshQueryContextFromVerse(this.verse), value); + public authoritativeWriter(): CultMeshDocumentWriter { + return this.document.authoritativeWriter(cultMeshQueryContextFromVerse(this.verse)); } - public update(update: CultMeshDocumentUpdater): Promise { - return this.document.update(cultMeshQueryContextFromVerse(this.verse), update); + public predictionWriter(): CultMeshDocumentWriter { + return this.document.predictionWriter(cultMeshQueryContextFromVerse(this.verse)); } - public reactive( + public observe( options: Omit = {}, - ): CultMeshReactiveDocument { - return this.document.reactive({ + ): CultMeshObservedDocument { + return this.document.observe({ ...options, context: cultMeshQueryContextFromVerse(this.verse), }); @@ -1451,10 +1559,6 @@ export class CultMeshDocumentCatalog { return this.tryDocument(schema)?.canSubmitPrediction ?? false; } - public canSet(schema: CultMeshDocumentSchemaDescriptor): boolean { - return this.tryDocument(schema)?.canSet ?? false; - } - public submitPrediction( schema: CultMeshDocumentSchemaDescriptor, value: TDocument, @@ -1482,60 +1586,18 @@ export class CultMeshDocumentCatalog { return this.document(schema, options).submitPrediction(context, value); } - public set( + public authoritativeWriter( schema: CultMeshDocumentSchemaDescriptor, - value: TDocument, - options?: { parse?: (value: unknown) => TDocument; context?: CultMeshQueryContext | string }, - ): Promise; - public set( - schema: CultMeshDocumentSchemaDescriptor, - context: CultMeshQueryContext | string, - value: TDocument, - options?: { parse?: (value: unknown) => TDocument }, - ): Promise; - public set( - schema: CultMeshDocumentSchemaDescriptor, - contextOrValue: CultMeshQueryContext | string | TDocument, - valueOrOptions?: TDocument | { parse?: (value: unknown) => TDocument; context?: CultMeshQueryContext | string }, - maybeOptions: { parse?: (value: unknown) => TDocument } = {}, - ): Promise { - const hasContext = - typeof contextOrValue === "string" || isCultMeshQueryContext(contextOrValue); - const context = hasContext - ? contextOrValue as CultMeshQueryContext | string - : (valueOrOptions as { context?: CultMeshQueryContext | string } | undefined)?.context ?? "local"; - const value = hasContext ? valueOrOptions as TDocument : contextOrValue as TDocument; - const options = hasContext ? maybeOptions : valueOrOptions as { parse?: (value: unknown) => TDocument } | undefined; - return this.document(schema, options).set(context, value); + options: { parse?: (value: unknown) => TDocument; context?: CultMeshQueryContext | string } = {}, + ): CultMeshDocumentWriter { + return this.document(schema, options).authoritativeWriter(options.context ?? "local"); } - public update( + public predictionWriter( schema: CultMeshDocumentSchemaDescriptor, - update: CultMeshDocumentUpdater, - options?: { parse?: (value: unknown) => TDocument; context?: CultMeshQueryContext | string }, - ): Promise; - public update( - schema: CultMeshDocumentSchemaDescriptor, - context: CultMeshQueryContext | string, - update: CultMeshDocumentUpdater, - options?: { parse?: (value: unknown) => TDocument }, - ): Promise; - public update( - schema: CultMeshDocumentSchemaDescriptor, - contextOrUpdate: CultMeshQueryContext | string | CultMeshDocumentUpdater, - updateOrOptions?: CultMeshDocumentUpdater | { parse?: (value: unknown) => TDocument; context?: CultMeshQueryContext | string }, - maybeOptions: { parse?: (value: unknown) => TDocument } = {}, - ): Promise { - const hasContext = - typeof contextOrUpdate === "string" || isCultMeshQueryContext(contextOrUpdate); - const context = hasContext - ? contextOrUpdate as CultMeshQueryContext | string - : (updateOrOptions as { context?: CultMeshQueryContext | string } | undefined)?.context ?? "local"; - const update = hasContext - ? updateOrOptions as CultMeshDocumentUpdater - : contextOrUpdate as CultMeshDocumentUpdater; - const options = hasContext ? maybeOptions : updateOrOptions as { parse?: (value: unknown) => TDocument } | undefined; - return this.document(schema, options).update(context, update); + options: { parse?: (value: unknown) => TDocument; context?: CultMeshQueryContext | string } = {}, + ): CultMeshDocumentWriter { + return this.document(schema, options).predictionWriter(options.context ?? "local"); } public watch( @@ -3927,29 +3989,6 @@ export class CultMeshNode { ); } - public reactiveDocument( - definition: TDefinition, - key: string, - options: { - context?: CultMeshQueryContext | string; - watch?: boolean; - debounceMs?: number; - onError?: (error: unknown) => void; - documentId?: string; - routeHint?: CultMeshRouteHint; - pollMs?: number; - } = {}, - ): CultMeshReactiveDocument & object> { - const { - documentId, - routeHint, - pollMs, - ...reactiveOptions - } = options; - return this.document(definition, key, { documentId, routeHint, pollMs }) - .reactive & object>(reactiveOptions); - } - public async syncDocumentFromPeerSnapshot( peer: CultNetPeer | (() => CultNetPeer | Promise), definition: TDefinition, @@ -5005,23 +5044,6 @@ export class CultMesh { return cultMeshGlobalDocumentFromCache(cache, definition, options); } - public static reactiveDocument( - node: CultMeshNode, - definition: TDefinition, - key: string, - options: { - context?: CultMeshQueryContext | string; - watch?: boolean; - debounceMs?: number; - onError?: (error: unknown) => void; - documentId?: string; - routeHint?: CultMeshRouteHint; - pollMs?: number; - } = {}, - ): CultMeshReactiveDocument & object> { - return node.reactiveDocument(definition, key, options); - } - public static syncDocumentFromPeerSnapshot( node: CultMeshNode, peer: CultNetPeer | (() => CultNetPeer | Promise), diff --git a/packages/cultmesh-ts/test/cultmesh.test.ts b/packages/cultmesh-ts/test/cultmesh.test.ts index e99bc454..709dc5b8 100644 --- a/packages/cultmesh-ts/test/cultmesh.test.ts +++ b/packages/cultmesh-ts/test/cultmesh.test.ts @@ -114,7 +114,6 @@ test("CultMesh TS document handles hide local cache plumbing behind typed reacti assert.equal(document.documentId, "cultmesh.note:note:1"); assert.equal(document.canReplace, true); assert.equal(document.canSubmitPrediction, false); - assert.equal(document.canSet, true); assert.equal((await bound.latest()).body, "initial"); await bound.replace({ @@ -131,13 +130,12 @@ test("CultMesh TS document handles hide local cache plumbing behind typed reacti const catalog = CultMesh.documents(document); assert.equal(catalog.canReplace(noteAliasDocument), true); - assert.equal(catalog.canSet(noteAliasDocument), true); - await catalog.set(noteAliasDocument, { - noteId: "note:1", - body: "catalog-updated", - }, { + await catalog.authoritativeWriter(noteAliasDocument, { parse: value => noteAliasDocument.schema.parse(value), context: "browser-client", + }).write({ + noteId: "note:1", + body: "catalog-updated", }); assert.equal( (await catalog.latest(noteAliasDocument, "browser-client", { @@ -145,7 +143,7 @@ test("CultMesh TS document handles hide local cache plumbing behind typed reacti })).body, "catalog-updated", ); - const incremented = await bound.update(value => ({ + const incremented = await bound.authoritativeWriter().update(value => ({ ...value, body: `${value.body}:updated-through-bound-set`, })); @@ -183,17 +181,15 @@ test("CultMesh TS document handles submit predictions through configured authori assert.equal(document.canReplace, false); assert.equal(document.canSubmitPrediction, true); - assert.equal(document.canSet, true); assert.equal(bound.canSubmitPrediction, true); - assert.equal(bound.canSet, true); assert.equal(catalog.canSubmitPrediction(noteAliasDocument), true); - assert.equal(catalog.canSet(noteAliasDocument), true); - await catalog.set(noteAliasDocument, "pilot-a", { + await catalog.predictionWriter(noteAliasDocument, { + parse: value => noteAliasDocument.schema.parse(value), + context: "pilot-a", + }).write({ noteId: "note:prediction", body: "predicted", - }, { - parse: value => noteAliasDocument.schema.parse(value), }); assert.deepEqual(contexts, ["pilot-a:network"]); @@ -204,14 +200,14 @@ test("CultMesh TS document handles submit predictions through configured authori parse: value => noteAliasDocument.schema.parse(value), }); assert.equal(alias.canSubmitPrediction, true); - await alias.set({ + await alias.predictionWriter().write({ noteId: "note:prediction", body: "alias-predicted", }); assert.deepEqual(predictions, ["predicted", "alias-predicted"]); assert.equal((await document.latest("pilot-a")).body, "alias-predicted"); - const updated = await document.update("pilot-a", value => ({ + const updated = await document.predictionWriter("pilot-a").update(value => ({ ...value, body: "updated-as-prediction", })); @@ -227,6 +223,34 @@ test("CultMesh TS document handles submit predictions through configured authori ); }); +test("CultMesh TS documents with both capabilities require an immutable writer choice", async () => { + let current = { noteId: "note:dual", body: "initial" }; + const writes: string[] = []; + const document = CultMesh.document( + "cultmesh.note:dual", + noteDocument, + async () => current, + { + replaceDocument: async (_context, value) => { + writes.push(`authoritative:${value.body}`); + current = value; + }, + submitPrediction: async (_context, value) => { + writes.push(`prediction:${value.body}`); + current = value; + }, + }, + ); + + assert.equal((document as unknown as { set?: unknown }).set, undefined); + await document.authoritativeWriter().write({ noteId: "note:dual", body: "canonical" }); + const predictionWriter = document.predictionWriter(); + await predictionWriter.write({ noteId: "note:dual", body: "predicted" }); + + assert.equal(predictionWriter.kind, "prediction"); + assert.deepEqual(writes, ["authoritative:canonical", "prediction:predicted"]); +}); + test("CultMesh TS store document handles choose compatible foreign schema payloads", async () => { const store = { async pullAll() { @@ -280,7 +304,7 @@ test("CultMesh TS store document handles choose compatible foreign schema payloa }); }); -test("CultMesh TS reactive documents submit predictions from member writes", async () => { +test("CultMesh TS reactive documents submit predictions from explicit updates", async () => { let current = { noteId: "note:reactive", body: "initial", @@ -299,23 +323,71 @@ test("CultMesh TS reactive documents submit predictions from member writes", asy }, ); - const reactive = document.reactive({ + const reactive = document.predictionWriter().reactive({ watch: false, }); await reactive.ready; - reactive.current.body = "member-write-prediction"; - reactive.current.body = "member-write-prediction-final"; + reactive.update(value => { + value.body = "explicit-update-prediction"; + }); + reactive.update(value => { + value.body = "explicit-update-prediction-final"; + }); await waitFor( - () => predictions.includes("member-write-prediction-final"), - "reactive member write prediction", + () => predictions.includes("explicit-update-prediction-final"), + "reactive explicit update prediction", ); - assert.equal(current.body, "member-write-prediction-final"); - assert.deepEqual(predictions, ["member-write-prediction-final"]); + assert.equal(current.body, "explicit-update-prediction-final"); + assert.deepEqual(predictions, ["explicit-update-prediction-final"]); reactive.dispose(); - reactive.current.body = "after-dispose"; + assert.throws(() => reactive.update(value => { + value.body = "after-dispose"; + }), /disposed/); + assert.deepEqual(predictions, ["explicit-update-prediction-final"]); +}); + +test("CultMesh TS reactive updates publish nested edits while snapshot mutation stays local", async () => { + let current = { + shipId: "ship:nested", + loadout: { + weapon: { + key: "weapon:laser", + tuning: { damage: 10 }, + }, + }, + }; + const predictions: typeof current[] = []; + const document = CultMesh.document( + "cultmesh.ship:nested", + { schemaId: "cultmesh.ship.nested.v0" }, + async () => current, + { + submitPrediction: async (_context, value) => { + current = structuredClone(value); + predictions.push(structuredClone(value)); + }, + }, + ); + const reactive = document.predictionWriter().reactive({ watch: false }); + await reactive.ready; + + reactive.update(draft => { + draft.loadout.weapon.tuning.damage = 12; + }); + await reactive.flush(); + + assert.equal(current.loadout.weapon.tuning.damage, 12); + assert.equal(predictions.length, 1); + + const borrowed = reactive.snapshot; + borrowed.loadout.weapon.tuning.damage = 99; await new Promise(resolve => setTimeout(resolve, 20)); - assert.deepEqual(predictions, ["member-write-prediction-final"]); + + assert.equal(reactive.snapshot.loadout.weapon.tuning.damage, 12); + assert.equal(current.loadout.weapon.tuning.damage, 12); + assert.equal(predictions.length, 1); + reactive.dispose(); }); test("CultMesh TS node opens same-schema aliases with one call", async () => { @@ -333,7 +405,7 @@ test("CultMesh TS node opens same-schema aliases with one call", async () => { }); assert.equal(aliasHandle.documentId, "cultmesh.note.ui:note:node-reactive"); assert.equal((await aliasHandle.latest()).body, "initial"); - await aliasHandle.set({ + await aliasHandle.authoritativeWriter().write({ noteId: "note:node-reactive", body: "edited-through-alias-handle", }); @@ -355,26 +427,29 @@ test("CultMesh TS node opens same-schema aliases with one call", async () => { ["edited-through-alias-put"], ); - const reactive = node.reactiveDocument(noteAliasDocument, "note:node-reactive", { - context: CultMesh.queryContext("browser-client"), + const reactive = aliasHandle.authoritativeWriter( + CultMesh.queryContext("browser-client"), + ).reactive({ watch: false, }); await reactive.ready; - reactive.current.body = "edited-through-node-helper"; + reactive.update(value => { + value.body = "edited-through-node-helper"; + }); await waitFor( () => node.getRequired(noteDocument, "note:node-reactive").body === "edited-through-node-helper", "node-level reactive alias write", ); - assert.equal(reactive.current.noteId, "note:node-reactive"); + assert.equal(reactive.snapshot.noteId, "note:node-reactive"); assert.equal( node.document(noteDocument, "note:node-reactive").asSchemaAlias(noteAliasDocument, { parse: value => noteAliasDocument.schema.parse(value), - }).canSet, + }).canReplace, true, ); assert.equal( - (await CultMesh.reactiveDocument(node, noteAliasDocument, "note:node-reactive", { + (await node.document(noteAliasDocument, "note:node-reactive").observe({ watch: false, }).ready).body, "edited-through-node-helper", @@ -409,10 +484,12 @@ test("CultMesh TS reactive documents store reconciliation deltas after mispredic }, ); - const reactive = document.reactive(); + const reactive = document.predictionWriter().reactive(); await reactive.ready; - reactive.current.body = "predicted"; - reactive.current.revision = 7; + reactive.update(value => { + value.body = "predicted"; + value.revision = 7; + }); await waitFor(() => predictions.length === 1, "reactive reconciliation prediction"); watcher?.({ @@ -421,8 +498,8 @@ test("CultMesh TS reactive documents store reconciliation deltas after mispredic revision: 5, }); - assert.equal(reactive.current.body, "authoritative"); - assert.equal(reactive.current.revision, 5); + assert.equal(reactive.snapshot.body, "authoritative"); + assert.equal(reactive.snapshot.revision, 5); assert.equal(reactive.reconciliation?.version, 1); assert.deepEqual(reactive.reconciliation?.canonical, { noteId: "note:reconcile", @@ -444,7 +521,7 @@ test("CultMesh TS reactive documents store reconciliation deltas after mispredic reactive.dispose(); }); -test("CultMesh TS reactive documents coalesce same-frame member writes", async () => { +test("CultMesh TS reactive documents coalesce same-frame explicit updates", async () => { let current = { noteId: "note:reactive-frame", body: "initial", @@ -468,14 +545,14 @@ test("CultMesh TS reactive documents coalesce same-frame member writes", async ( }, ); - const reactive = document.reactive({ + const reactive = document.predictionWriter().reactive({ watch: false, }); try { await reactive.ready; - reactive.current.body = "frame-1"; - reactive.current.body = "frame-2"; - reactive.current.body = "frame-3"; + reactive.update(value => { value.body = "frame-1"; }); + reactive.update(value => { value.body = "frame-2"; }); + reactive.update(value => { value.body = "frame-3"; }); assert.equal(frameCallbacks.length, 1); frameCallbacks[0](performance.now()); @@ -524,14 +601,14 @@ test("CultMesh TS reactive documents queue edits made while a prediction is in f }, ); - const reactive = document.reactive({ + const reactive = document.predictionWriter().reactive({ watch: false, debounceMs: 0, }); await reactive.ready; - reactive.current.body = "first"; + reactive.update(value => { value.body = "first"; }); await firstPredictionStarted; - reactive.current.body = "second"; + reactive.update(value => { value.body = "second"; }); releaseFirstPrediction(); await waitFor(() => predictions.length === 2, "in-flight queued prediction"); @@ -540,13 +617,13 @@ test("CultMesh TS reactive documents queue edits made while a prediction is in f reactive.dispose(); }); -test("CultMesh TS reactive read-only documents surface mutation failures and keep watching", async () => { +test("CultMesh TS observed documents never publish borrowed snapshot mutation and keep watching", async () => { let current = { noteId: "note:reactive-readonly", body: "initial", }; let watcher: ((value: typeof current) => void) | undefined; - const errors: string[] = []; + const writes: typeof current[] = []; const document = CultMesh.document( "cultmesh.note:reactive-readonly", noteDocument, @@ -558,15 +635,17 @@ test("CultMesh TS reactive read-only documents surface mutation failures and kee watcher = undefined; }; }, + submitPrediction: async (_context, value) => { + writes.push(value); + }, }, ); - const reactive = document.reactive({ - onError: error => errors.push(String((error as Error).message ?? error)), - }); - await reactive.ready; - reactive.current.body = "local-readonly-edit"; - await waitFor(() => errors.length === 1, "read-only mutation error"); + const observed = document.observe(); + await observed.ready; + observed.current.body = "borrowed-local-edit"; + await new Promise(resolve => setTimeout(resolve, 20)); + assert.deepEqual(writes, []); current = { noteId: "note:reactive-readonly", @@ -574,9 +653,8 @@ test("CultMesh TS reactive read-only documents surface mutation failures and kee }; watcher?.(current); - assert.match(errors[0], /does not support mutation/); - assert.equal(reactive.current.body, "canonical-after-error"); - reactive.dispose(); + assert.equal(observed.current.body, "canonical-after-error"); + observed.dispose(); }); test("CultMesh TS document handles read schema publications from single-file stores", async () => { @@ -796,7 +874,7 @@ test("CultMesh TS syncs configured publications into local node aliases", async assert.deepEqual(facadeSynced, synced); assert.equal(target.getRequired(noteDocument, "note:published").body, "publication source hydrates local alias"); assert.equal(target.getRequired(noteAliasDocument, "note:published").body, "publication source hydrates local alias"); - assert.equal((await target.reactiveDocument(noteAliasDocument, "note:published", { watch: false }).ready).body, "publication source hydrates local alias"); + assert.equal((await target.document(noteAliasDocument, "note:published").observe({ watch: false }).ready).body, "publication source hydrates local alias"); }); test("CultMesh TS syncs configured publication catalogs into local node aliases", async () => { From 1e1cfd840c1d593f1772f4bc35efa6a29c169932 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 17 Aug 2026 20:03:42 +0200 Subject: [PATCH 056/283] Remove CultMesh Python mutation polling --- .../cultcache-py/src/cultmesh_py/__init__.py | 4 + .../cultcache-py/src/cultmesh_py/facade.py | 19 +- packages/cultcache-py/src/cultmesh_py/node.py | 201 ++++++++++++------ packages/cultcache-py/tests/test_cultcache.py | 85 ++++++-- 4 files changed, 225 insertions(+), 84 deletions(-) diff --git a/packages/cultcache-py/src/cultmesh_py/__init__.py b/packages/cultcache-py/src/cultmesh_py/__init__.py index 95aee189..54b68343 100644 --- a/packages/cultcache-py/src/cultmesh_py/__init__.py +++ b/packages/cultcache-py/src/cultmesh_py/__init__.py @@ -14,8 +14,10 @@ from .node import ( CultMeshDatabase, CultMeshDatabaseChange, CultMeshDocumentPublicationSource, + CultMeshDocumentWriter, CultMeshNode, CultMeshNodeOptions, + CultMeshObservedDocument, CultMeshPublicationDocumentBinding, CultMeshReactiveDocument, CultMeshReactiveDocumentOptions, @@ -68,8 +70,10 @@ __all__ = [ "CultMeshDatabase", "CultMeshDatabaseChange", "CultMeshDocumentPublicationSource", + "CultMeshDocumentWriter", "CultMesh", "CultMeshPublicationDocumentBinding", + "CultMeshObservedDocument", "CultMeshReactiveDocument", "CultMeshReactiveDocumentOptions", "CultMeshReactiveDocumentReconciliation", diff --git a/packages/cultcache-py/src/cultmesh_py/facade.py b/packages/cultcache-py/src/cultmesh_py/facade.py index 115259f3..4c9c34a0 100644 --- a/packages/cultcache-py/src/cultmesh_py/facade.py +++ b/packages/cultcache-py/src/cultmesh_py/facade.py @@ -24,11 +24,11 @@ from cultnet_py import ( from .client import CultMeshDocumentSubscription, CultMeshPeerExchangeClient, CultMeshVerseDiscoveryClient from .node import ( CultMeshDocumentPublicationSource, + CultMeshDocumentWriter, CultMeshNode, CultMeshNodeOptions, + CultMeshObservedDocument, CultMeshPublicationDocumentBinding, - CultMeshReactiveDocument, - CultMeshReactiveDocumentOptions, create_node, ) from .server import CultMeshLocalServer @@ -301,13 +301,20 @@ class CultMesh: ) @staticmethod - def reactive_document( + def authoritative_writer( node: CultMeshNode, document: DocumentDefinition[Any], key: str, - options: CultMeshReactiveDocumentOptions | None = None, - ) -> CultMeshReactiveDocument: - return node.reactive_document(document, key, options) + ) -> CultMeshDocumentWriter: + return node.authoritative_writer(document, key) + + @staticmethod + def observe_document( + node: CultMeshNode, + document: DocumentDefinition[Any], + key: str, + ) -> CultMeshObservedDocument: + return node.observe_document(document, key) @staticmethod def publication_source_from_peer_snapshot( diff --git a/packages/cultcache-py/src/cultmesh_py/node.py b/packages/cultcache-py/src/cultmesh_py/node.py index 142fe226..3afddd24 100644 --- a/packages/cultcache-py/src/cultmesh_py/node.py +++ b/packages/cultcache-py/src/cultmesh_py/node.py @@ -84,7 +84,6 @@ class CultMeshReactiveDocumentReconciliation: @dataclass(frozen=True) class CultMeshReactiveDocumentOptions: flush_delay_seconds: float = 0.016 - detect_local_changes: bool = True replace_dirty_current_on_canonical_snapshot: bool = False @@ -248,13 +247,19 @@ class CultMeshNode: shard_epoch=shard_epoch, ) - def reactive_document( + def authoritative_writer( self, document: DocumentDefinition[Any], key: str, - options: CultMeshReactiveDocumentOptions | None = None, - ) -> "CultMeshReactiveDocument": - return self.database.reactive_document(document, key, options) + ) -> "CultMeshDocumentWriter": + return self.database.authoritative_writer(document, key) + + def observe_document( + self, + document: DocumentDefinition[Any], + key: str, + ) -> "CultMeshObservedDocument": + return self.database.observe_document(document, key) def sync_document_from_publication( self, @@ -744,17 +749,27 @@ class CultMeshDatabase: ) return self.get_required(requested, key) - def reactive_document( + def authoritative_writer( self, document: DocumentDefinition[Any], key: str, - options: CultMeshReactiveDocumentOptions | None = None, - ) -> "CultMeshReactiveDocument": + ) -> "CultMeshDocumentWriter": if not key: raise ValueError("key must be non-empty") if not any(self._documents_alias(document, registered) for registered in self.documents): self.register_document(document) - return CultMeshReactiveDocument(self, document, key, options) + return CultMeshDocumentWriter(self, document, key) + + def observe_document( + self, + document: DocumentDefinition[Any], + key: str, + ) -> "CultMeshObservedDocument": + if not key: + raise ValueError("key must be non-empty") + if not any(self._documents_alias(document, registered) for registered in self.documents): + self.register_document(document) + return CultMeshObservedDocument(self, document, key) def sync_document_from_publication( self, @@ -1254,17 +1269,104 @@ def _document_matches_schema_id(document: DocumentDefinition[Any], schema_id: st return _infer_schema_name(schema_id) == entry.schema_name -class CultMeshReactiveDocument: +class CultMeshDocumentWriter: def __init__( self, database: CultMeshDatabase, document: DocumentDefinition[Any], key: str, + ) -> None: + self.database = database + self.document = document + self.key = key + + def write(self, value: Any) -> None: + self.database.put(self.document, self.key, self._clone(value)) + + def update(self, callback: Callable[[Any], Any | None]) -> Any: + draft = self._clone(self.database.get_required(self.document, self.key)) + replacement = callback(draft) + next_value = draft if replacement is None else replacement + self.write(next_value) + return self._clone(next_value) + + def reactive( + self, options: CultMeshReactiveDocumentOptions | None = None, + ) -> "CultMeshReactiveDocument": + return CultMeshReactiveDocument(self, options) + + def _clone(self, value: Any) -> Any: + return self.document.decode_payload(self.document.encode_payload(value)) + + +class CultMeshObservedDocument: + def __init__( + self, + database: CultMeshDatabase, + document: DocumentDefinition[Any], + key: str, ) -> None: self._database = database self._document = document self._key = key + self._lock = threading.RLock() + self._disposed = False + self._current = self._clone(database.get_required(document, key)) + self._unsubscribe = database.watch_record(document, key, self._apply_canonical_change) + + @property + def current(self) -> Any: + with self._lock: + self._raise_if_disposed() + return self._current + + def refresh(self) -> Any: + with self._lock: + self._raise_if_disposed() + self._current = self._clone( + self._database.get_required(self._document, self._key) + ) + return self._current + + def dispose(self) -> None: + with self._lock: + if self._disposed: + return + self._disposed = True + self._unsubscribe() + + def __enter__(self) -> "CultMeshObservedDocument": + return self + + def __exit__(self, _exc_type: Any, _exc: Any, _tb: Any) -> None: + self.dispose() + + def _apply_canonical_change(self, change: CultMeshDatabaseChange) -> None: + if change.value is None: + return + with self._lock: + if not self._disposed: + self._current = self._clone(change.value) + + def _clone(self, value: Any) -> Any: + return self._document.decode_payload(self._document.encode_payload(value)) + + def _raise_if_disposed(self) -> None: + if self._disposed: + raise RuntimeError("CultMeshObservedDocument has been disposed") + + +class CultMeshReactiveDocument: + def __init__( + self, + writer: CultMeshDocumentWriter, + options: CultMeshReactiveDocumentOptions | None = None, + ) -> None: + self.writer = writer + self._database = writer.database + self._document = writer.document + self._key = writer.key self._options = options or CultMeshReactiveDocumentOptions() self._lock = threading.RLock() self._disposed = False @@ -1272,14 +1374,14 @@ class CultMeshReactiveDocument: self._flushing = False self._flush_queued = False self._flush_timer: threading.Timer | None = None - self._detect_timer: threading.Timer | None = None self._reconciliation_version = 0 self.reconciliation: CultMeshReactiveDocumentReconciliation | None = None - self.current = self._clone(self._database.get_required(document, key)) - self._last_clean_payload = self._serialize(self.current) - self._unsubscribe = self._database.watch_record(document, key, self._apply_canonical_change) - if self._options.detect_local_changes: - self._schedule_detection() + self._current = self._clone(self._database.get_required(self._document, self._key)) + self._unsubscribe = self._database.watch_record( + self._document, + self._key, + self._apply_canonical_change, + ) @property def document(self) -> DocumentDefinition[Any]: @@ -1294,42 +1396,43 @@ class CultMeshReactiveDocument: with self._lock: return self._dirty - def update(self, callback: Callable[[Any], None]) -> Any: + @property + def snapshot(self) -> Any: with self._lock: self._raise_if_disposed() - callback(self.current) - self._dirty = True - self._schedule_flush_locked() - return self.current + return self._clone(self._current) - def set_current(self, value: Any) -> Any: + def update(self, callback: Callable[[Any], Any | None]) -> Any: with self._lock: self._raise_if_disposed() - self.current = self._clone(value) + draft = self._clone(self._current) + replacement = callback(draft) + self._current = self._clone(draft if replacement is None else replacement) self._dirty = True self._schedule_flush_locked() - return self.current + return self._clone(self._current) - def mark_dirty(self) -> None: + def replace_local(self, value: Any) -> Any: with self._lock: self._raise_if_disposed() + self._current = self._clone(value) self._dirty = True self._schedule_flush_locked() + return self._clone(self._current) def refresh(self) -> Any: with self._lock: self._raise_if_disposed() - self.current = self._clone(self._database.get_required(self._document, self._key)) - self._last_clean_payload = self._serialize(self.current) + self._current = self._clone( + self._database.get_required(self._document, self._key) + ) self._dirty = False self.reconciliation = None - return self.current + return self._clone(self._current) def flush(self) -> None: with self._lock: self._raise_if_disposed() - if not self._dirty: - self._detect_local_changes_locked() if not self._dirty: return if self._flushing: @@ -1340,16 +1443,14 @@ class CultMeshReactiveDocument: self._flush_timer = None self._flushing = True self._dirty = False - predicted = self._clone(self.current) - self._last_clean_payload = self._serialize(predicted) + predicted = self._clone(self._current) try: - self._database.put(self._document, self._key, predicted) + self.writer.write(predicted) finally: should_flush_again = False with self._lock: self._flushing = False - self._detect_local_changes_locked() should_flush_again = self._flush_queued or self._dirty self._flush_queued = False if should_flush_again: @@ -1367,8 +1468,6 @@ class CultMeshReactiveDocument: self._disposed = True if self._flush_timer is not None: self._flush_timer.cancel() - if self._detect_timer is not None: - self._detect_timer.cancel() self._unsubscribe() def __enter__(self) -> "CultMeshReactiveDocument": @@ -1385,7 +1484,7 @@ class CultMeshReactiveDocument: return canonical = self._clone(change.value) if self._dirty or self._flushing: - predicted = self._clone(self.current) + predicted = self._clone(self._current) delta = self._create_delta(predicted, canonical) if delta: self._reconciliation_version += 1 @@ -1400,32 +1499,9 @@ class CultMeshReactiveDocument: self.reconciliation = None if not self._options.replace_dirty_current_on_canonical_snapshot: return - self.current = canonical - self._last_clean_payload = self._serialize(self.current) + self._current = canonical self.reconciliation = None - def _schedule_detection(self) -> None: - delay = max(self._options.flush_delay_seconds, 0.001) - timer = threading.Timer(delay, self._detect_timer_elapsed) - timer.daemon = True - self._detect_timer = timer - timer.start() - - def _detect_timer_elapsed(self) -> None: - with self._lock: - if self._disposed: - return - if not self._dirty and not self._flushing: - self._detect_local_changes_locked() - if self._dirty: - self._schedule_flush_locked() - if not self._disposed and self._options.detect_local_changes: - self._schedule_detection() - - def _detect_local_changes_locked(self) -> None: - if self._serialize(self.current) != self._last_clean_payload: - self._dirty = True - def _schedule_flush_locked(self) -> None: if self._options.flush_delay_seconds <= 0: threading.Thread(target=self.flush, daemon=True).start() @@ -1437,9 +1513,6 @@ class CultMeshReactiveDocument: self._flush_timer = timer timer.start() - def _serialize(self, value: Any) -> bytes: - return self._document.encode_payload(value) - def _clone(self, value: Any) -> Any: return self._document.decode_payload(self._document.encode_payload(value)) diff --git a/packages/cultcache-py/tests/test_cultcache.py b/packages/cultcache-py/tests/test_cultcache.py index 3ecb763f..d00a05ab 100644 --- a/packages/cultcache-py/tests/test_cultcache.py +++ b/packages/cultcache-py/tests/test_cultcache.py @@ -9,6 +9,7 @@ import tempfile import threading import time import unittest +from unittest.mock import patch import hashlib import hmac import io @@ -2448,7 +2449,7 @@ class CultCacheTests(unittest.TestCase): self.assertIsNone(node.get(alias, "note:alias")) self.assertEqual(node.get_all(alias), []) - def test_cultmesh_reactive_document_coalesces_direct_alias_member_writes(self) -> None: + def test_cultmesh_reactive_document_coalesces_explicit_alias_updates(self) -> None: @dataclass class CanonicalNote: body: str @@ -2481,16 +2482,14 @@ class CultCacheTests(unittest.TestCase): seen: list[CultMeshDatabaseChange] = [] node.database.watch_record(alias, "note:reactive", seen.append) - reactive = node.reactive_document( - alias, - "note:reactive", - CultMeshReactiveDocumentOptions(flush_delay_seconds=0.02), + reactive = node.authoritative_writer(alias, "note:reactive").reactive( + CultMeshReactiveDocumentOptions(flush_delay_seconds=0.02) ) try: - self.assertIsInstance(reactive.current, UiNote) - reactive.current.body = "first-local-edit" - reactive.current.body = "second-local-edit" - reactive.current.revision = 2 + self.assertIsInstance(reactive.snapshot, UiNote) + reactive.update(lambda note: setattr(note, "body", "first-local-edit")) + reactive.update(lambda note: setattr(note, "body", "second-local-edit")) + reactive.update(lambda note: setattr(note, "revision", 2)) self._wait_until(lambda: node.get_required(alias, "note:reactive").body == "second-local-edit") @@ -2518,19 +2517,18 @@ class CultCacheTests(unittest.TestCase): node.register_document(document) node.put(document, "note:reconcile", Note("initial", 1)) - reactive = CultMesh.reactive_document( + reactive = CultMesh.authoritative_writer( node, document, "note:reconcile", - CultMeshReactiveDocumentOptions(flush_delay_seconds=60), - ) + ).reactive(CultMeshReactiveDocumentOptions(flush_delay_seconds=60)) try: reactive.update(lambda note: setattr(note, "body", "local-prediction")) - reactive.current.revision = 2 + reactive.update(lambda note: setattr(note, "revision", 2)) node.put(document, "note:reconcile", Note("authoritative", 7)) - self.assertEqual(reactive.current.body, "local-prediction") + self.assertEqual(reactive.snapshot.body, "local-prediction") self.assertIsNotNone(reactive.reconciliation) self.assertEqual(reactive.reconciliation.canonical.body, "authoritative") self.assertEqual(reactive.reconciliation.predicted.body, "local-prediction") @@ -2543,6 +2541,65 @@ class CultCacheTests(unittest.TestCase): finally: reactive.dispose() + def test_cultmesh_reactive_document_is_idle_until_explicit_nested_update(self) -> None: + document = define_document_type( + "mesh.nested_loadout", + encode=lambda value: value, + decode=lambda value: value, + ) + node = create_node(runtime_id="python-reactive-nested") + node.register_document(document) + node.put( + document, + "ship:nested", + {"loadout": {"weapon": {"tuning": {"damage": 10}}}}, + ) + + with patch("cultmesh_py.node.threading.Timer") as timer: + reactive = node.authoritative_writer(document, "ship:nested").reactive() + timer.assert_not_called() + + try: + borrowed = reactive.snapshot + borrowed["loadout"]["weapon"]["tuning"]["damage"] = 99 + self.assertEqual( + node.get_required(document, "ship:nested")["loadout"]["weapon"]["tuning"]["damage"], + 10, + ) + + reactive.update( + lambda draft: draft["loadout"]["weapon"]["tuning"].__setitem__("damage", 12) + ) + reactive.flush() + + self.assertEqual(reactive.snapshot["loadout"]["weapon"]["tuning"]["damage"], 12) + self.assertEqual( + node.get_required(document, "ship:nested")["loadout"]["weapon"]["tuning"]["damage"], + 12, + ) + finally: + reactive.dispose() + + def test_cultmesh_observed_document_cannot_publish_borrowed_mutation(self) -> None: + document = define_document_type( + "mesh.observed_note", + encode=lambda value: value, + decode=lambda value: value, + ) + node = create_node(runtime_id="python-observed") + node.register_document(document) + node.put(document, "note:observed", {"body": "initial"}) + + observed = node.observe_document(document, "note:observed") + try: + observed.current["body"] = "borrowed-local-edit" + self.assertEqual(node.get_required(document, "note:observed")["body"], "initial") + + node.put(document, "note:observed", {"body": "canonical"}) + self.assertEqual(observed.current["body"], "canonical") + finally: + observed.dispose() + def test_cultnet_document_delete_helper_matches_schema_v0_shape(self) -> None: message = document_delete( message_id="delete-1", From 32258f49c319f60766eadddb2f4cccd59910db96 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 17 Aug 2026 20:21:41 +0200 Subject: [PATCH 057/283] Add artifact-only Eve two-runtime sample --- samples/eve-two-runtime/sample.mjs | 184 ++++++++++++++++++ scripts/verify-eve-two-runtime-sample.ps1 | 115 +++++++++++ .../03-publish-an-eve-surface.md | 26 ++- 3 files changed, 320 insertions(+), 5 deletions(-) create mode 100644 samples/eve-two-runtime/sample.mjs create mode 100644 scripts/verify-eve-two-runtime-sample.ps1 diff --git a/samples/eve-two-runtime/sample.mjs b/samples/eve-two-runtime/sample.mjs new file mode 100644 index 00000000..a78b765f --- /dev/null +++ b/samples/eve-two-runtime/sample.mjs @@ -0,0 +1,184 @@ +import assert from "node:assert/strict"; +import { mkdtemp } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { JSDOM } from "jsdom"; +import { z } from "zod"; +import { defineDocumentType } from "cultcache-ts"; +import { CultMesh } from "cultmesh-ts"; +import { renderEveSurface } from "@gamecult/eve-browser-lowering"; + +const providerId = "sample.counter-provider"; +const surfaceId = "sample.counter"; +const stateKey = "counter:main"; + +const counterDocument = defineDocumentType({ + type: "sample.counter_state", + schemaId: "sample.counter_state.v1", + schema: z.object({ counterId: z.string(), count: z.number().int() }), + name: "counterId", +}); + +const surfaceDocument = defineDocumentType({ + type: "gamecult.eve.surface", + schemaId: "gamecult.eve.surface.v1", + schema: z.any(), +}); + +const receiptDocument = defineDocumentType({ + type: "sample.counter_receipt", + schemaId: "sample.counter_receipt.v1", + schema: z.object({ + receiptId: z.string(), + operationId: z.literal("sample.counter.increment"), + idempotencyKey: z.string(), + count: z.number().int(), + }), + name: "receiptId", +}); + +function counterSurface() { + return { + providerId, + title: "CultMesh two-runtime counter", + version: 1, + surface: { + id: surfaceId, + root: { + id: "counter.root", + kind: "column", + children: [ + { + id: "counter.value", + kind: "metric", + props: { label: "Canonical count", value: 0 }, + stateBindings: [{ + targetProp: "value", + pointerId: "sample.counter.count", + sourceId: `${counterDocument.type}:${stateKey}`, + schemaId: counterDocument.schemaId, + routeKind: "shared-memory", + }], + }, + { + id: "counter.increment", + kind: "control.button", + props: { label: "Increment", command: "sample.counter.increment" }, + }, + ], + }, + }, + }; +} + +function installDom() { + const dom = new JSDOM("
    ", { + url: "https://eve.sample/", + pretendToBeVisual: true, + }); + for (const name of [ + "document", + "window", + "Element", + "HTMLElement", + "HTMLButtonElement", + "HTMLInputElement", + "HTMLTextAreaElement", + "HTMLImageElement", + ]) globalThis[name] = dom.window[name]; + return dom; +} + +async function waitFor(predicate, description) { + const deadline = Date.now() + 2_000; + while (!predicate()) { + if (Date.now() >= deadline) throw new Error(`Timed out waiting for ${description}.`); + await new Promise(resolve => setTimeout(resolve, 5)); + } +} + +const statePath = join(await mkdtemp(join(tmpdir(), "cultmesh-eve-two-runtime-")), "state.ccmp"); +const node = await CultMesh.startNode(statePath, { + documents: [counterDocument, surfaceDocument, receiptDocument], +}); +await node.put(counterDocument, stateKey, { counterId: stateKey, count: 0 }); +await node.put(surfaceDocument, surfaceId, counterSurface()); +await node.flush(); + +const state = node.document(counterDocument, stateKey, { pollMs: 5 }); +const headless = state.observe({ context: "headless-client" }); +await headless.ready; +const receiptsByIdempotencyKey = new Map(); +const increment = CultMesh.operation("sample.counter.increment", async (_request, context) => { + const idempotencyKey = context.idempotencyKey || "missing"; + const existing = receiptsByIdempotencyKey.get(idempotencyKey) + || node.get(receiptDocument, `receipt:${idempotencyKey}`); + if (existing) return existing; + const next = await state.authoritativeWriter("provider-daemon").update(current => ({ + ...current, + count: current.count + 1, + })); + const receipt = { + receiptId: `receipt:${idempotencyKey}`, + operationId: "sample.counter.increment", + idempotencyKey, + count: next.count, + }; + receiptsByIdempotencyKey.set(idempotencyKey, receipt); + await node.put(receiptDocument, receipt.receiptId, receipt); + await node.flush(); + return receipt; +}); + +const dom = installDom(); +const host = document.querySelector("#surface"); +const browserVerse = CultMesh.verse("local", "browser-client"); +let browserReceipt; +renderEveSurface(await node.document(surfaceDocument, surfaceId).latest(), host, { + activeSurfaceId: surfaceId, + clientId: "browser-client", + commandSink: async intent => { + browserReceipt = await increment.bind(browserVerse).invoke(intent.payload, { + idempotencyKey: "browser-click-1", + }); + }, + stateBindingResolver: async binding => { + if (binding.pointerId !== "sample.counter.count") return undefined; + return { + latest: async () => (await state.latest("browser-client")).count, + watch: callback => state.watch("browser-client", value => callback(value.count)), + }; + }, +}); + +await waitFor(() => host.querySelector(".metric-value")?.textContent === "0", "initial browser binding"); +host.querySelector("button").click(); +await waitFor(() => browserReceipt?.count === 1, "typed command receipt"); +await waitFor(() => headless.current.count === 1, "headless convergence"); +await waitFor(() => host.querySelector(".metric-value")?.textContent === "1", "browser convergence"); + +const duplicate = await increment.bind(browserVerse).invoke({}, { idempotencyKey: "browser-click-1" }); +assert.equal(duplicate.receiptId, browserReceipt.receiptId); +assert.equal(headless.current.count, 1); + +headless.dispose(); +renderEveSurface({ providerId, surface: { id: "sample.closed" } }, host); +dom.window.close(); +await node.flush(); +const reopened = await CultMesh.startNode(statePath, { + documents: [counterDocument, surfaceDocument, receiptDocument], +}); +assert.equal(reopened.getRequired(counterDocument, stateKey).count, 1); +assert.equal( + reopened.getRequired(receiptDocument, "receipt:browser-click-1").receiptId, + browserReceipt.receiptId, +); + +console.log(JSON.stringify({ + providerId, + surfaceId, + receiptId: browserReceipt.receiptId, + browserCount: 1, + headlessCount: 1, + restartCount: 1, +})); diff --git a/scripts/verify-eve-two-runtime-sample.ps1 b/scripts/verify-eve-two-runtime-sample.ps1 new file mode 100644 index 00000000..f5545d5f --- /dev/null +++ b/scripts/verify-eve-two-runtime-sample.ps1 @@ -0,0 +1,115 @@ +param( + [string] $EveRoot = (Join-Path (Split-Path -Parent $PSScriptRoot) "..\Eve") +) + +$ErrorActionPreference = "Stop" + +$cultLibRoot = Split-Path -Parent $PSScriptRoot +$samplePath = Join-Path $cultLibRoot "samples\eve-two-runtime\sample.mjs" +$eveBrowserPackage = Join-Path $EveRoot "packages\eve-browser-lowering" +$packageRoots = @( + (Join-Path $cultLibRoot "packages\cultcache-ts"), + (Join-Path $cultLibRoot "packages\cultnet-ts"), + (Join-Path $cultLibRoot "packages\cultmesh-ts"), + $eveBrowserPackage +) + +$nodeCommand = Get-Command node.exe -ErrorAction SilentlyContinue +if (-not $nodeCommand) { + $standardNode = Join-Path $env:ProgramFiles "nodejs\node.exe" + if (Test-Path -LiteralPath $standardNode) { + $nodeCommand = Get-Item -LiteralPath $standardNode + } +} +if (-not $nodeCommand) { + throw "Node.js is required to verify the Eve two-runtime sample." +} +$nodePath = $nodeCommand.Source +$nodeDirectory = Split-Path -Parent $nodePath +$npmPath = Join-Path $nodeDirectory "npm.cmd" +if (-not (Test-Path -LiteralPath $npmPath)) { + throw "npm was not found beside Node.js: $npmPath" +} +$env:PATH = $nodeDirectory + [IO.Path]::PathSeparator + $env:PATH +if (-not (Test-Path -LiteralPath $samplePath)) { + throw "Sample not found: $samplePath" +} +foreach ($packageRoot in $packageRoots) { + if (-not (Test-Path -LiteralPath (Join-Path $packageRoot "package.json"))) { + throw "Package root not found: $packageRoot" + } +} + +$tempBase = [IO.Path]::GetFullPath([IO.Path]::GetTempPath()) +$workRoot = Join-Path $tempBase ("gamecult-eve-two-runtime-" + [guid]::NewGuid().ToString("N")) +$artifactRoot = Join-Path $workRoot "artifacts" +$consumerRoot = Join-Path $workRoot "consumer" +New-Item -ItemType Directory -Path $artifactRoot, $consumerRoot -Force | Out-Null + +try { + foreach ($packageRoot in $packageRoots) { + Push-Location $packageRoot + try { + if ((Split-Path -Leaf $packageRoot) -eq "cultnet-ts") { + & $nodePath (Join-Path $packageRoot "tools\generate-swarm-contracts.mjs") + if ($LASTEXITCODE -ne 0) { + throw "CultNet TypeScript contract generation failed: $packageRoot" + } + } + $typescriptPath = if ($packageRoot -eq $eveBrowserPackage) { + Join-Path $packageRoot "node_modules\typescript\bin\tsc" + } + else { + Join-Path $cultLibRoot "node_modules\typescript\bin\tsc" + } + & $nodePath $typescriptPath -p (Join-Path $packageRoot "tsconfig.json") --pretty false + if ($LASTEXITCODE -ne 0) { + throw "Package build failed: $packageRoot" + } + & $npmPath pack --ignore-scripts --silent --pack-destination $artifactRoot | Out-Null + if ($LASTEXITCODE -ne 0) { + throw "Package pack failed: $packageRoot" + } + } + finally { + Pop-Location + } + } + + Push-Location $consumerRoot + try { + & $npmPath init --yes --silent | Out-Null + $tarballs = Get-ChildItem -LiteralPath $artifactRoot -Filter "*.tgz" | + Sort-Object Name | + ForEach-Object FullName + $installArguments = @( + "install", + "--silent", + "--no-audit", + "--no-fund", + "@msgpack/msgpack@3", + "ajv@8", + "jsdom@30", + "zod@3" + ) + @($tarballs) + & $npmPath @installArguments + if ($LASTEXITCODE -ne 0) { + throw "Clean consumer package installation failed." + } + Copy-Item -LiteralPath $samplePath -Destination (Join-Path $consumerRoot "sample.mjs") + & $nodePath .\sample.mjs + if ($LASTEXITCODE -ne 0) { + throw "Eve two-runtime sample failed." + } + } + finally { + Pop-Location + } +} +finally { + $resolvedWorkRoot = [IO.Path]::GetFullPath($workRoot) + if ($resolvedWorkRoot.StartsWith($tempBase, [StringComparison]::OrdinalIgnoreCase) -and + (Test-Path -LiteralPath $resolvedWorkRoot)) { + Remove-Item -LiteralPath $resolvedWorkRoot -Recurse -Force + } +} diff --git a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md index 666acf1d..95048d3a 100644 --- a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md +++ b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md @@ -35,15 +35,31 @@ Run the same provider and connect at least two lowerers. Both must report the same provider id, surface id, surface version, and command receipt ids. Native pixels may differ; provider truth may not. -Current verification for the Unity consumer: +The package-artifact browser/headless checkpoint is executable from CultLib: + +```powershell +cd CultLib +powershell -ExecutionPolicy Bypass -File .\scripts\verify-eve-two-runtime-sample.ps1 ` + -EveRoot ..\Eve +``` + +The verifier builds and packs `cultcache-ts`, `cultnet-ts`, `cultmesh-ts`, and +`@gamecult/eve-browser-lowering`, installs the tarballs into an empty temporary +consumer, and runs `samples/eve-two-runtime/sample.mjs`. One provider-owned +counter surface is lowered by a browser runtime and observed by a headless +runtime. A browser command crosses the typed operation boundary, both runtimes +converge on the same state and receipt identity, a duplicate idempotency key is +not applied twice, and the state plus receipt survive reopening the `.ccmp` +store. + +Current verification for the Unity consumer remains: ```powershell cd E:\Projects\EveUnity powershell -ExecutionPolicy Bypass -File .\scripts\run-release-consumer-tests.ps1 ``` -The browser/Electron counterpart and a single command-driven two-runtime sample -remain required before this chapter can be considered complete. Their absence -is tracked as developer-experience debt rather than papered over with bespoke -setup instructions. +This checkpoint proves clean package consumption and two lowering/observation +runtimes. It does not claim an Odin-discovered network hop or cross-language +command execution; those remain separate public Verse conformance gates. From 376c08a155ae4b6ee879b73c2cd4f754fed301d7 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 17 Aug 2026 20:39:24 +0200 Subject: [PATCH 058/283] Make CultMesh client resources explicit --- src/GameCult.Mesh/CultMeshClient.cs | 273 +++++++++++++++--- .../getting-started/02-connect-by-identity.md | 7 +- .../CultMeshClientTests.cs | 84 +++++- 3 files changed, 313 insertions(+), 51 deletions(-) diff --git a/src/GameCult.Mesh/CultMeshClient.cs b/src/GameCult.Mesh/CultMeshClient.cs index 12ccd470..027cc68e 100644 --- a/src/GameCult.Mesh/CultMeshClient.cs +++ b/src/GameCult.Mesh/CultMeshClient.cs @@ -42,6 +42,40 @@ namespace GameCult.Mesh public TimeSpan SubscriptionResponseTimeout { get; set; } = TimeSpan.FromSeconds(2); } + /// Owns one shared live document subscription until disposed. + public sealed class CultMeshDocumentLease : IDisposable where TDocument : class + { + private Action? _release; + + internal CultMeshDocumentLease(CultMeshDocumentHandle handle, Action release) + { + Handle = handle ?? throw new ArgumentNullException(nameof(handle)); + _release = release ?? throw new ArgumentNullException(nameof(release)); + } + + /// Gets the live typed document handle owned by this lease. + public CultMeshDocumentHandle Handle { get; } + + public void Dispose() => Interlocked.Exchange(ref _release, null)?.Invoke(); + } + + /// Owns one shared live collection subscription until disposed. + public sealed class CultMeshCollectionLease : IDisposable where TDocument : class + { + private Action? _release; + + internal CultMeshCollectionLease(CultMeshCollectionHandle handle, Action release) + { + Handle = handle ?? throw new ArgumentNullException(nameof(handle)); + _release = release ?? throw new ArgumentNullException(nameof(release)); + } + + /// Gets the live typed collection handle owned by this lease. + public CultMeshCollectionHandle Handle { get; } + + public void Dispose() => Interlocked.Exchange(ref _release, null)?.Invoke(); + } + /// /// Owns discovery and reusable sessions for one application lifetime. /// Applications address stable identities; CultMesh owns physical routes and reconnection. @@ -51,9 +85,8 @@ namespace GameCult.Mesh private readonly CultMeshDiscoveryService _discovery; private readonly CultMeshSessionManager _sessions; private readonly TimeSpan _subscriptionResponseTimeout; - private readonly ConcurrentDictionary>> _documents = new(StringComparer.Ordinal); - private readonly ConcurrentDictionary>> _collections = new(StringComparer.Ordinal); - private readonly ConcurrentBag _documentResources = new(); + private readonly ConcurrentDictionary _documents = new(StringComparer.Ordinal); + private readonly ConcurrentDictionary _collections = new(StringComparer.Ordinal); private bool _disposed; public CultMeshClient(CultMeshClientOptions options) @@ -147,8 +180,8 @@ namespace GameCult.Mesh options); } - /// Opens one live typed document by stable provider identity and record key. - public async Task> DocumentAsync( + /// Leases one shared live typed document by stable provider identity and record key. + public async Task> LeaseDocumentAsync( string endpointId, string recordKey, CancellationToken cancellationToken = default) @@ -158,31 +191,40 @@ namespace GameCult.Mesh if (string.IsNullOrWhiteSpace(endpointId)) throw new ArgumentException("Endpoint identity is required.", nameof(endpointId)); if (string.IsNullOrWhiteSpace(recordKey)) throw new ArgumentException("Record key is required.", nameof(recordKey)); var key = endpointId.Trim() + "\u001f" + typeof(TDocument).AssemblyQualifiedName + "\u001f" + recordKey.Trim(); - var lazy = _documents.GetOrAdd(key, _ => new Lazy>( - async () => await OpenDocumentAsync(endpointId.Trim(), recordKey.Trim()).ConfigureAwait(false), - LazyThreadSafetyMode.ExecutionAndPublication)); - try + while (true) { - var binding = (RemoteDocumentBinding)await AwaitForCallerAsync(lazy.Value, cancellationToken) - .ConfigureAwait(false); - return binding.Handle; - } - catch - { - _documents.TryRemove(key, out _); - throw; + var resource = _documents.GetOrAdd(key, _ => new SharedResource( + async owner => await OpenDocumentAsync(endpointId.Trim(), recordKey.Trim(), owner).ConfigureAwait(false))); + if (!resource.TryAcquire()) + { + RemoveExact(_documents, key, resource); + continue; + } + try + { + var binding = (RemoteDocumentBinding)await AwaitForCallerAsync(resource.Value, cancellationToken) + .ConfigureAwait(false); + return new CultMeshDocumentLease( + binding.Handle, + () => Release(_documents, key, resource)); + } + catch + { + Release(_documents, key, resource); + throw; + } } } - /// Opens a live collection of one typed schema by stable provider identity. - public Task> CollectionAsync( + /// Leases a shared live collection of one typed schema by stable provider identity. + public Task> LeaseCollectionAsync( string endpointId, CancellationToken cancellationToken) where TDocument : class => - CollectionAsync(endpointId, includeInitialSnapshot: true, cancellationToken); + LeaseCollectionAsync(endpointId, includeInitialSnapshot: true, cancellationToken); - /// Opens a live collection and optionally skips replaying its initial snapshot. - public async Task> CollectionAsync( + /// Leases a live collection and optionally skips replaying its initial snapshot. + public async Task> LeaseCollectionAsync( string endpointId, bool includeInitialSnapshot = true, CancellationToken cancellationToken = default) @@ -192,22 +234,74 @@ namespace GameCult.Mesh if (string.IsNullOrWhiteSpace(endpointId)) throw new ArgumentException("Endpoint identity is required.", nameof(endpointId)); var identity = endpointId.Trim(); var key = identity + "\u001f" + typeof(TDocument).AssemblyQualifiedName + "\u001f" + includeInitialSnapshot; - var lazy = _collections.GetOrAdd(key, _ => new Lazy>( - async () => await OpenCollectionAsync(identity, includeInitialSnapshot).ConfigureAwait(false), - LazyThreadSafetyMode.ExecutionAndPublication)); - try + while (true) { - var binding = (RemoteCollectionBinding)await AwaitForCallerAsync(lazy.Value, cancellationToken) - .ConfigureAwait(false); - return binding.Handle; - } - catch - { - _collections.TryRemove(key, out _); - throw; + var resource = _collections.GetOrAdd(key, _ => new SharedResource( + async owner => await OpenCollectionAsync(identity, includeInitialSnapshot, owner).ConfigureAwait(false))); + if (!resource.TryAcquire()) + { + RemoveExact(_collections, key, resource); + continue; + } + try + { + var binding = (RemoteCollectionBinding)await AwaitForCallerAsync(resource.Value, cancellationToken) + .ConfigureAwait(false); + return new CultMeshCollectionLease( + binding.Handle, + () => Release(_collections, key, resource)); + } + catch + { + Release(_collections, key, resource); + throw; + } } } + /// + /// Submits one typed document to a provider by stable identity. Submission is uncommitted input; + /// only a provider-authored receipt or resulting state can establish acceptance. + /// + public async Task SubmitDocumentAsync( + string endpointId, + string recordKey, + TDocument document, + string sourceRuntimeId, + string sourceRole, + CancellationToken cancellationToken = default) + where TDocument : class + { + ThrowIfDisposed(); + if (string.IsNullOrWhiteSpace(endpointId)) throw new ArgumentException("Endpoint identity is required.", nameof(endpointId)); + if (string.IsNullOrWhiteSpace(recordKey)) throw new ArgumentException("Record key is required.", nameof(recordKey)); + if (document == null) throw new ArgumentNullException(nameof(document)); + if (string.IsNullOrWhiteSpace(sourceRuntimeId)) throw new ArgumentException("Source runtime identity is required.", nameof(sourceRuntimeId)); + if (string.IsNullOrWhiteSpace(sourceRole)) throw new ArgumentException("Source role is required.", nameof(sourceRole)); + + var cacheRegistry = CultMesh.CreateCultCacheDocumentRegistry(typeof(TDocument)); + var networkRegistry = CultMesh.CreateCultNetDocumentRegistry(new[] { typeof(TDocument) }, cacheRegistry); + var message = networkRegistry.CreateRawDocumentPutMessage( + "cultmesh-client-submit-" + Guid.NewGuid().ToString("N"), + new CultRecordHandle(new CultRecordKey(recordKey.Trim())), + document, + new CultNetDocumentMessageOptions + { + SourceRuntimeId = sourceRuntimeId.Trim(), + SourceRole = sourceRole.Trim() + }); + var session = await ConnectAsync(endpointId.Trim(), CultMeshProtocols.Documents, cancellationToken) + .ConfigureAwait(false); + cancellationToken.ThrowIfCancellationRequested(); + session.OpenSchemaClient().SendCultNet(message); + } + + /// Gets the number of currently leased shared document subscriptions. + public int ActiveDocumentResourceCount => _documents.Count; + + /// Gets the number of currently leased shared collection subscriptions. + public int ActiveCollectionResourceCount => _collections.Count; + /// Reads one typed record once through the reusable document session. public async Task ReadAsync( string endpointId, @@ -293,7 +387,7 @@ namespace GameCult.Mesh { if (_disposed) return; _disposed = true; - foreach (var resource in _documentResources) resource.Dispose(); + foreach (var resource in _documents.Values.Concat(_collections.Values).Distinct()) resource.Dispose(); _documents.Clear(); _collections.Clear(); _sessions.Dispose(); @@ -305,12 +399,15 @@ namespace GameCult.Mesh if (_disposed) throw new ObjectDisposedException(nameof(CultMeshClient)); } - private async Task OpenDocumentAsync(string endpointId, string recordKey) + private async Task OpenDocumentAsync( + string endpointId, + string recordKey, + SharedResource owner) where TDocument : class { var session = await ConnectAsync(endpointId, CultMeshProtocols.Documents).ConfigureAwait(false); var binding = new RemoteDocumentBinding(session, endpointId, recordKey, _subscriptionResponseTimeout); - _documentResources.Add(binding); + owner.Attach(binding); try { await binding.StartAsync().ConfigureAwait(false); @@ -318,17 +415,21 @@ namespace GameCult.Mesh } catch { + owner.Detach(binding); binding.Dispose(); throw; } } - private async Task OpenCollectionAsync(string endpointId, bool includeInitialSnapshot) + private async Task OpenCollectionAsync( + string endpointId, + bool includeInitialSnapshot, + SharedResource owner) where TDocument : class { var session = await ConnectAsync(endpointId, CultMeshProtocols.Documents).ConfigureAwait(false); var binding = new RemoteCollectionBinding(session, endpointId, includeInitialSnapshot, _subscriptionResponseTimeout); - _documentResources.Add(binding); + owner.Attach(binding); try { await binding.StartAsync().ConfigureAwait(false); @@ -336,6 +437,7 @@ namespace GameCult.Mesh } catch { + owner.Detach(binding); binding.Dispose(); throw; } @@ -353,6 +455,99 @@ namespace GameCult.Mesh return await shared.ConfigureAwait(false); } + private static void Release( + ConcurrentDictionary resources, + string key, + SharedResource resource) + { + if (!resource.Release()) return; + RemoveExact(resources, key, resource); + resource.Dispose(); + } + + private static void RemoveExact( + ConcurrentDictionary resources, + string key, + SharedResource resource) + { + ((ICollection>)resources) + .Remove(new KeyValuePair(key, resource)); + } + + private sealed class SharedResource : IDisposable + { + private readonly object _gate = new(); + private readonly Lazy> _value; + private IDisposable? _attached; + private int _leases; + private bool _retired; + + public SharedResource(Func> open) + { + if (open == null) throw new ArgumentNullException(nameof(open)); + _value = new Lazy>(() => open(this), LazyThreadSafetyMode.ExecutionAndPublication); + } + + public Task Value => _value.Value; + + public bool TryAcquire() + { + lock (_gate) + { + if (_retired) return false; + _leases++; + return true; + } + } + + public bool Release() + { + lock (_gate) + { + if (_leases <= 0) return false; + _leases--; + if (_leases != 0) return false; + _retired = true; + return true; + } + } + + public void Attach(IDisposable resource) + { + if (resource == null) throw new ArgumentNullException(nameof(resource)); + lock (_gate) + { + if (_retired) + { + resource.Dispose(); + throw new ObjectDisposedException(nameof(SharedResource)); + } + if (_attached != null) throw new InvalidOperationException("CultMesh shared resource already has a live binding."); + _attached = resource; + } + } + + public void Detach(IDisposable resource) + { + lock (_gate) + { + if (ReferenceEquals(_attached, resource)) _attached = null; + } + } + + public void Dispose() + { + IDisposable? attached; + lock (_gate) + { + _retired = true; + attached = _attached; + _attached = null; + } + attached?.Dispose(); + } + } + private sealed class RemoteDocumentBinding : IDisposable where TDocument : class { private readonly CultMeshSession _session; diff --git a/src/GameCult.Mesh/docs/getting-started/02-connect-by-identity.md b/src/GameCult.Mesh/docs/getting-started/02-connect-by-identity.md index 9301b49f..dd7a1abd 100644 --- a/src/GameCult.Mesh/docs/getting-started/02-connect-by-identity.md +++ b/src/GameCult.Mesh/docs/getting-started/02-connect-by-identity.md @@ -12,15 +12,18 @@ using var mesh = new CultMeshClient(new CultMeshClientOptions RendezvousEndpoints = new[] { "rudp://odin.gamecult.net:3076" } }); -var pilotSurface = await mesh.DocumentAsync( +using var pilotSurfaceLease = await mesh.LeaseDocumentAsync( "aetheria.daemon", "eve:surface:aetheria.pilot", cancellationToken); +var pilotSurface = pilotSurfaceLease.Handle; using var surfaceWatch = pilotSurface.Watch().Subscribe(Render); ``` -Keep `mesh` for the application lifetime. The document handle is stable: when +Keep `mesh` for the application lifetime and dispose each document lease when +the consuming screen or system closes. Leases for the same identity share one +subscription. The document handle is stable while leased: when Odin advertises a new physical route after a partition, CultMesh migrates the session, restores the server-side subscription, refreshes the typed snapshot, and continues the same watch. diff --git a/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs b/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs index 1596b93a..bf5de6a7 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs @@ -62,8 +62,10 @@ public sealed class CultMeshClientTests Connectors = new[] { connector } }); - var first = await mesh.DocumentAsync("aetheria", "surface:pilot"); - var second = await mesh.DocumentAsync("aetheria", "surface:pilot"); + using var firstLease = await mesh.LeaseDocumentAsync("aetheria", "surface:pilot"); + using var secondLease = await mesh.LeaseDocumentAsync("aetheria", "surface:pilot"); + var first = firstLease.Handle; + var second = secondLease.Handle; first.Should().BeSameAs(second); (await first.LatestAsync()).Text.Should().Be("pilot surface 1"); @@ -80,7 +82,8 @@ public sealed class CultMeshClientTests Discovery = new CultMeshVerseDiscoveryClientOptions { CreateClient = () => new RendezvousClient() }, Connectors = new[] { connector } }); - var document = await mesh.DocumentAsync("aetheria", "surface:pilot"); + using var lease = await mesh.LeaseDocumentAsync("aetheria", "surface:pilot"); + var document = lease.Handle; connector.Clients[0].Fail(new InvalidOperationException("path lost")); await WaitUntilAsync(() => connector.Clients.Count == 2 && connector.Clients[1].SubscribeCount == 1); @@ -102,11 +105,12 @@ public sealed class CultMeshClientTests Connectors = new[] { connector } }); - var opening = mesh.DocumentAsync("aetheria", "surface:pilot"); + var opening = mesh.LeaseDocumentAsync("aetheria", "surface:pilot"); await WaitUntilAsync(() => connector.Clients.Count == 1 && connector.Clients[0].SubscribeCount == 1); connector.Clients[0].Fail(new InvalidOperationException("path lost before initial snapshot")); - var document = await opening; + using var lease = await opening; + var document = lease.Handle; (await document.LatestAsync()).Text.Should().Be("pilot surface 2"); connector.Clients.Should().HaveCount(2); @@ -125,7 +129,8 @@ public sealed class CultMeshClientTests SubscriptionResponseTimeout = TimeSpan.FromMilliseconds(20) }); - var document = await mesh.DocumentAsync("aetheria", "surface:pilot"); + using var lease = await mesh.LeaseDocumentAsync("aetheria", "surface:pilot"); + var document = lease.Handle; (await document.LatestAsync()).Text.Should().Be("pilot surface 1"); connector.Clients.Should().ContainSingle(); @@ -143,7 +148,8 @@ public sealed class CultMeshClientTests Connectors = new[] { connector } }); - var collection = await mesh.CollectionAsync("aetheria"); + using var lease = await mesh.LeaseCollectionAsync("aetheria"); + var collection = lease.Handle; (await collection.LatestAsync()).Should().ContainSingle() .Which.Text.Should().Be("pilot surface 1"); @@ -161,11 +167,12 @@ public sealed class CultMeshClientTests Connectors = new[] { connector } }); - var opening = mesh.CollectionAsync("aetheria"); + var opening = mesh.LeaseCollectionAsync("aetheria"); await WaitUntilAsync(() => connector.Clients.Count == 1 && connector.Clients[0].SubscribeCount == 1); connector.Clients[0].Fail(new InvalidOperationException("path lost before initial collection snapshot")); - var collection = await opening; + using var lease = await opening; + var collection = lease.Handle; (await collection.LatestAsync()).Should().ContainSingle() .Which.Text.Should().Be("pilot surface 2"); @@ -173,6 +180,57 @@ public sealed class CultMeshClientTests connector.Clients[1].SubscribeCount.Should().Be(1); } + [Test] + public async Task Document_ResourceIsSharedAndReleasedWithLastLease() + { + var connector = new DocumentConnector(); + using var mesh = new CultMeshClient(new CultMeshClientOptions + { + RendezvousEndpoints = new[] { "rudp://odin:3076" }, + Discovery = new CultMeshVerseDiscoveryClientOptions { CreateClient = () => new RendezvousClient() }, + Connectors = new[] { connector } + }); + + var first = await mesh.LeaseDocumentAsync("aetheria", "surface:pilot"); + var second = await mesh.LeaseDocumentAsync("aetheria", "surface:pilot"); + mesh.ActiveDocumentResourceCount.Should().Be(1); + + first.Dispose(); + mesh.ActiveDocumentResourceCount.Should().Be(1); + second.Dispose(); + mesh.ActiveDocumentResourceCount.Should().Be(0); + + using var replacement = await mesh.LeaseDocumentAsync("aetheria", "surface:pilot"); + replacement.Handle.Should().NotBeSameAs(first.Handle); + connector.SubscribeCount.Should().Be(2); + } + + [Test] + public async Task SubmitDocument_SendsUncommittedInputThroughStableIdentitySession() + { + var connector = new DocumentConnector(); + using var mesh = new CultMeshClient(new CultMeshClientOptions + { + RendezvousEndpoints = new[] { "rudp://odin:3076" }, + Discovery = new CultMeshVerseDiscoveryClientOptions { CreateClient = () => new RendezvousClient() }, + Connectors = new[] { connector } + }); + var request = new ClientTestDocument { Id = "command:1", Text = "move" }; + + await mesh.SubmitDocumentAsync( + "aetheria", + request.Id, + request, + sourceRuntimeId: "pilot-one", + sourceRole: "pilot"); + + connector.Clients.Should().ContainSingle(); + var submitted = connector.Clients[0].Submitted.Should().ContainSingle().Subject; + submitted.Document.RecordKey.Should().Be("command:1"); + submitted.Document.SourceRuntimeId.Should().Be("pilot-one"); + submitted.Document.SourceRole.Should().Be("pilot"); + } + [Test] public async Task Dispose_TerminatesDocumentWaitingForInitialSnapshot() { @@ -183,7 +241,7 @@ public sealed class CultMeshClientTests Discovery = new CultMeshVerseDiscoveryClientOptions { CreateClient = () => new RendezvousClient() }, Connectors = new[] { connector } }); - var opening = mesh.DocumentAsync("aetheria", "surface:pilot"); + var opening = mesh.LeaseDocumentAsync("aetheria", "surface:pilot"); await WaitUntilAsync(() => connector.Clients.Count == 1 && connector.Clients[0].SubscribeCount == 1); mesh.Dispose(); @@ -290,9 +348,15 @@ public sealed class CultMeshClientTests public bool Connected => true; public Task BackgroundFailure => _failure.Task; public int SubscribeCount { get; private set; } + public List Submitted { get; } = new(); public void Connect(string host, int port) { } public void SendCultNet(T message) where T : ICultNetSchemaMessage { + if (message is CultNetDocumentPutRawMessage submitted) + { + Submitted.Add(submitted); + return; + } if (message is not CultNetDatabaseSubscribeMessage request) return; SubscribeCount++; if (_snapshotsToSuppress > 0) From ec292a6a0061cd8109b07471387b049bfe95a5f0 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 17 Aug 2026 21:26:44 +0200 Subject: [PATCH 059/283] Release CultLib Unity 1.0.45 --- unity/org.gamecult.cultlib/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unity/org.gamecult.cultlib/package.json b/unity/org.gamecult.cultlib/package.json index ec7807d9..6be0f3e1 100644 --- a/unity/org.gamecult.cultlib/package.json +++ b/unity/org.gamecult.cultlib/package.json @@ -1,7 +1,7 @@ { "name": "org.gamecult.cultlib", "displayName": "CultLib", - "version": "1.0.43", + "version": "1.0.45", "unity": "2021.3", "description": "CultCache, CultNet, and CultMesh managed runtime assemblies for Unity.", "license": "MIT", From 03840d0430bc727f1322861a1ab46b396eaca860 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 17 Aug 2026 21:30:32 +0200 Subject: [PATCH 060/283] Publish CultLib Unity 1.0.45 artifacts --- .../Plugins/GameCult.Caching.MessagePack.dll | Bin 43520 -> 43520 bytes .../Plugins/GameCult.Caching.MessagePack.pdb | Bin 19992 -> 19940 bytes .../Runtime/Plugins/GameCult.Caching.dll | Bin 84992 -> 84992 bytes .../Runtime/Plugins/GameCult.Caching.pdb | Bin 30032 -> 29976 bytes .../Runtime/Plugins/GameCult.Logging.dll | Bin 6656 -> 6656 bytes .../Runtime/Plugins/GameCult.Logging.pdb | Bin 9536 -> 9480 bytes .../Plugins/GameCult.Mesh.Quic.Native.dll | Bin 15360 -> 15360 bytes .../Plugins/GameCult.Mesh.Quic.Native.pdb | Bin 12268 -> 12216 bytes .../Runtime/Plugins/GameCult.Mesh.dll | Bin 594432 -> 599552 bytes .../Runtime/Plugins/GameCult.Mesh.pdb | Bin 192816 -> 193928 bytes .../Runtime/Plugins/GameCult.Networking.dll | Bin 456704 -> 457216 bytes .../Runtime/Plugins/GameCult.Networking.pdb | Bin 229976 -> 230056 bytes .../x86_64/gamecult_mesh_quic_native.dll | Bin 40448 -> 40448 bytes 13 files changed, 0 insertions(+), 0 deletions(-) diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.dll index faa15a8fe60674518a3d9777cb02d641fdad0eb3..3bdc5b9473584a3646a761d1786dcb70bc228719 100644 GIT binary patch delta 358 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 diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.dll index be07e455fb70e787c6dd92963eb89ee8c307b732..9246804a1364db804ea3b613d26f3ddb36f8e025 100644 GIT binary patch delta 364 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 Rn|4L>>dRi^fe-V|{{|*%32y)Z delta 3252 zcmaLYd0fru9>DSEIh`mmlI0GWG=(;CI-N=jS|&s@m&QwEnW$`vlLfw8xQdWuTTxyUJ5HTMJs%Q_V9ojgE~m@ z6%vtxbY$XN%t1DmV-51L1xD<}VVu+vF5w1BQGw^E!XL2gC`Ds9!5wM@AQXKNg?NlY zIwoT}7GVYQun9X*h{Gtx1zdyf9-#s+@D|cV3TrfjAHKjq496Di#C{yZ8C=3mJirtD zh8iecxpA~WTe!gs{s=(?`nyV<7)%k1WQ@fmWMK{#VFmKA2|wWq?w}mcP=yb$catIr zV~~L|v~_2>;EV3)iLJN~9}mVnSpQxWgRl_WaR+@nNwE~so>IJrWoQ1?NX0}<$5~uQ zDJt<2)lhViqEQ#NtND<^j=l|?;0`sqAsqd5ghBNtZ=}D5GPF`j;jA)UMG942?#fsn zL?H$vFcCT|!+Pw(5uCzJyn^tOLgQ6?t)A2yPywB#T8aT!jmJ*|6MKr#`2&7{& z7W!IPqJ9shpM|i29a_T?F6ay&1R)GDh{H&%#RhE0ZXCqVIIkmI!5zQa z4=Jbqw5w92p#WR46Z>!krKrGjRKdbuDO$n{{s=(?5|M$an2l_##&+z+Ib4QL5ug-4 zNJkOg!ah(bLNOeP7#(Q3Ii;8oXes^;y}37yNnr@&y?~u4!4v$38YqLLaD*#V=!z7K z#}v#6V*M9TEX8W%V=FG=2JYiAUf~@qy0Hh)9QJUA2fPu8F!aTj7y>Q+g*0Sh8sh~B!W=BZ3glrE zcAyZ4b%bJEz%|@M1zvYI-2lGh*`rHNRZ-#!BkOt}^#79@X{F>+&1ML~!j*1=Qsm zwYjfw4XOQu&YVrP>EQJm!gAmi9^z@;yx;#fkH@iIZ5hh%xw9MFG$K?f`eSft?X^r> zHG_b>D7uY=6kJUnAFwD$60mdQDDod9>xi+?GhUqp{`afIZ5ZNY5k}X13Fo;u-g*%-{2F-5b@K>Xw%G3*YO`#$FzLw&c>z>5;1{_PcB-nfuiK zMatO*kz0<;+%>c3+;i(@wLQB$C$ry+7P&2&7Vo?A!;9hDuKu!e^3|$wD7x z@&z8p{lY4fK7_w{WbIkz?VUMyz^Y~8{zGz-hj%(tGpV~r!TF?swaW{FR(qa!TvQd6 zo>;YL+m5`P1iPcD@zD#)V|K&@SY50Zb52Bf^c$Nxdx-Ux(sxa7f8lV{Ffiq)`g4!V zdrvoa{=E8hdYc}p{_T{r4vaalZ+&Tl!otjJJ3Q~MACVu~Xz$BGK4UBAAGck6waP*& zrG->TIW<4iDLz#@J|$r^n=>HODO}&ouZ8{p+nyc#{9Sw!{4{E<+BY^K-YYRaQSGNy z#l`z+HU4qxcvaT~l}3}OP4rS5XZUSWe7rTGs8CE5V)`ttuH%~nA$uOpPnww!BaA%* z9=COhmWJWdFj*RwOGBPCY?X$C(r`x_YGl5Z%x@?2RmLx)r`XD9{e=;inlPKGwexC> f|4F(dZR-u0&QKZiM&4I6`g_#4FlBB-(@Wt`(HRxS diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Logging.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Logging.dll index 3a97d2e0e21609c01fd8b19fbed9c2425d368712..446565f620b2dd8527e902c82c9a61d8f07557e1 100644 GIT binary patch delta 343 zcmZoLX)u}4!E&(s+4_k+GK|Y6t_)`knas#o&$woCBarOa%*b?{TYyDCF68+B2@V^& zRvEGUSX;RH2JZw$bz^h0WCM#tLsQelRFfpL)Km*|%OrE-WTWI1lQeTvleE+nV*|sK z$^HCydAoMUoMT}04PatmU?`kiDIm|PtIxooJ9(~vvbxjJ^4le@ulzbnPPc`wVeVlB zs&TW52`I|XN=+^)j&Ux{De=inn#?5VYXnuB=K)m-x(Nv1DF^X7}2^;b@nrd@6K(fdc$6%PHkcY zs&Tc72`I|XN=+^)j&Ux{De=in(oN1!Nv+UL2J&)Ki!*eKQgbpBlQMHMODZQn7x2}E z8Y6rRY7EHAZ0=pcFUl+$kFUQLIUQ&r3~Zd7C@9Uicyg_v=H#VYcVXy?UjetA@1`D7{1E7crP+c+* Y8!{MeRu_B7$aKVhv!KL##)$^(0JT4Je*gdg diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Logging.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Logging.pdb index 002a7b03173c220a83bb6dc71944cb58bed43ff3..a4e2d80c0c5cfef7ba5114c1e95d944e73a0c940 100644 GIT binary patch delta 922 zcmX@$)!{XvK;e!e1B0?tPJR*t1B27i^4le@ulzbnPPc`wVeaYL9dmBtgba0S21W*F z1}26gAYBEdmjUVZKw6rSkwJ@*iGh!akwKP;X|f`tupa|ZPF<0a!4io5fjAXtJ_Ar~ znIaRz3?N_}89uX31FH9C+y*4=n3x$^82BfzXQ~%=v*HLS z%FjwoE-7YrF3lr9LDycQOi`fK7r%XP`Y{()i*)V(ZH|8SF3qaPDhC2Oo<)8>|i& znVT%qCrRw$j=z>+$|}GvWUOt*!uxH(25y#|sh{Ufad0%POMcFn%juuPBf@fwm2q8} z$;!;tXBlnY9xkJG{_3`8 zp7c7t-1~a{mWeamiim5OhkBfCNFgaF$w`GDKi*S7K~ z*zY@R%Xw&4&W$hbmb>?s*!8&YU%tR*`~J`!kCvITtbMuV*r6lKvSn>kwV!B*uuT2D z;Z4t-Lc_SXZMJ)$(U-;qVnu73!^%7Lszv@N`7)_Zfaghv65A_lABdb3@k;(#K4l&40cO( zV{@})1B*mMQ`5v$lO(g$R10&pvwA2)11H+WfKiC(_FzQX7r4r4e M$GEV4@=p~P08sf@tpET3 delta 979 zcmeD1I^Z>-KtV)_fkD|RCqIdSfx+^n>g;C@-<{h|^@hDjo!XSJROtJ}2^s2P42%qM z3``8YKzb^WJ_w{w0ckTvMg~_#CI(F=Mg|Kerpbzo!hQ@uxfn%8hCCo{0peMTK!bs5 zS1U3xoCV^WK>PrRp9AqbupCGp2ACPXDl#+t0b*t)W(F>$$qkIJT(f{m85o#>n33U_ zA}f$)1G5JTdahO+ z0Y&*)smUe9O3tM@B|e!+y2<$|sTI1(KwfTYafWVDYEEWiQf5wON#$fmW^HBz6W7W4 z%qBp(e)2MALly&*hHaB?GZ%5b2D08ad~al%9LDmh9?EOtQ25|+vqOnH(d1xx{*0KE z5BB@hgGI{LuzE<=E-_sy@r$kToH@`7Yp0ygk~S1L_P%k?;RnIqlVfiezB1!%y`s8s zfl3)I`CdBnUV5M8N*#axU48whgw}1C zT#$9LKG;R^Z(8k)>&a(1LoTrR&q$DF2<7JxYSJ!xVOA5kc>5FwCXaI_Z#bmhI3`Z# zxUpJ5S+lV#>(41grYc_lH!>kCdMb=&(X*~>x%iA_;`_*g`IE}`w?{KDc;~-I=NlgVdVW{QM7RFezbKWWtDLsdrYb9xxK>~M ztlzA8Z^PT7un*R2*o#^^|FK{BHZfP%dcynr59YBXy4tP%y}0RqOxujM#rFe)Cf>fU z6;pKCs_9zkwWOy-m)D-1w@JKve6b?`~KudUVTrGtFa1Z$=u*ovVEB z+i~_*c*%dJeHP1q=G3oRra$q^kqqOxs|%Mt&-%7&)~k=&Qs>j$W}Ymui}~)%vnzOa z?vA5vn|P1jJ+|=S8h0^wcEz=P4>IPd_BK@~-)cJ|l=R5Z*OG&5Q)qXG`Z`tg}0LNsligE=YJU(nH?LJRx73C zCzs}?<^j`|Rkf0 pj8Y6NQVmQ@(vs5*jW!=1%6&md_0R~vd^AN z>~q$)T6b@j(O$@+XKZekY+#XSXlk06YLaA@nrdNgnPhI9Y?Pd0l4fpdl9rlcY+#sT z&cGnY$RIh{$3Sv3i@_5{-d`o}k1#O$1~4%&Ff>p8YADaTJAi><_hd;UW%V?JzW>I( z%e*GkedfJ>?Wh+cP>q{aOh8e7R%&udag1|mPKi%u(&Rd$cq6FVDwtZ3x!f%uT%YYz z|5YPYmc|tb)C>hGAhyCpMKMOP$!f;hlY@-+Og3PW+017W!s2VpV9sF1kj!AfV8M{c zV8~z!gozBP3?>XoK=D){v;eBG1oF%ojDhNmfH(yxn+D{Yg6UKs-x#RhkRfIBdW%R# QCJV#Of>!StCmOH=02K^q{Qv*} delta 386 zcmZpuXsDRb!BTkBW9h^m8OETAE5jN8PG)4RXN;KK2qX?zI2O zlsMa0OAR;6XfI^ZGfg!&F-kTvOH55MOiM{KGEX*0N-PBSzz zXJC+HWRRRZ*GO_Ri@_5{-lLB{H8U{!1~4%&FwC3$)li=GS^xvXwaJo3%3i`@ciUw) zzIK@Be7a(0>GfNTKsBybF#$#SS*gh-#WBvMIVC=sNxI4TDXA5@$v|FiYH@~cQEEQtFO9Ycujgm#78;?SKON z$?uJ%84V|M8*5KCHQu|K&m@G!*OVcZ!JNT_!H6Llh|L%hf&3H(LxwaUnFbUw2Z|do yBmsFKmI;F;kZlCy88BD?RT=_i+MT# diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.pdb index 3b20d8f143cd1afa12e976a83d1a1009fedce38f..3c87786360716d6305f694dc78f608046e62105f 100644 GIT binary patch delta 1253 zcmX|=dsNbA7{}ii5d)Q6-mR&L3N2PD-dBniEWDI-Oe=9-0Krm3q0(G|&3S24G1^&a znJIB*TT8*r~58LUV#l=-j;p z077V5Mlt{(#iR6ZN{KQ|c6!--=<(gKx8lX_a@hsj!vKP0fC3K@KaTkO5P}hil7~Rc z7=YBq+#q<4FpIE+phx)D9fAggW(18pG91zMAh9zMf+z$bLNp(6Eps}EsL`7oHEmFkRAQlVi)k|n&Xh#oR7nPN9gv%C-Om-bh6Gx;b8;P>m_VRiY zdwD2^>}qXKalV>pW^g+>kQL^--D9-7eG7>>#nj>38oh4cqV3ji;KVM+8^blW5jqnyMrD;`uAZ7@+ZT^_ReuHejXc`GN40k{#Z zJEEgnobuBQZ1#6Gx9Q|Unt`Wzbg{`rgMWTaaR=E6jw>@hzVF^V5g!dDW9$9`?S`3$}H_{(apmu25n$$52U z`1CHx?26U->DTRDwNnIKuqC-`y1<(3KnTZKXNMA4y#;aMVV4R!bFx+BbY3Te=168( zG&;0lo(vx>@8}a+^txeFv&JO43G*AF< zZ9plHqDVbW7Y9k?{lwW@1B1yyl{N}uZ9~<{(EF*&f=7ZUf(GRUo`X>&yY;2}yg^Y$ zF2INX5=iaI+~k8>h=M$$t^u@<(P% z%e`k6hk{y<4)gWT4)G_w$Fs>tRjB)k>r#JuhlNmjHrIud!9JGG6^KPHfw?a9Ko;x& zm1MEjc2Z8m1rRBIzHATwBu^ioB(8U|FPH1@7m(~nVSBMT-YI@Q-YHxT#lw@MzJ{wq z*%d2{yFmv8_lh=OiF^KnrfIxO5X^N~%6~Nfm=q#NO3OLP%@S?nq@^K;m!H;N52OIZ zX6HQczO3C_;*%KfJ5&56A|^;0T3)MHk5fNUf+;c+GOnpkue_f+EB-twoxA$IZ4ntf zUaEk%HtW}KUff)rg|={v?$yYs^=Gepq4hU1Kgc7wBL12-{!!HckYd4zs(MEaokhDL z<^-RZ%rtz^?&XT*k$Ak_q;)_INHhVTI3>N&;!t6wNi+NI+zHQDi|`(fmT0Ing-UCv U^oB|*R5GEGuWlmy8leFA2NI_42mk;8 delta 1259 zcmdlH|0aGyfx-_>1_ouPoctsP1_t4^=#Lt2F9T0z20~!ug z_Xo%hQ)gso1L9>sybg%Bse|M|fRSN8kpC5k*)>2$ivUG*H6St76uj$hK(8wESwDcH5`EKbj=1J zc>_ptGCbS-k%g5}&((?}peR2pHMyi%$+q|i5_R;t}Q!v@Gs?Ge0QSBhFhk) z7qip`)h~_@3(M>EjV?I&TVcYtGnVe@Z6`lpZl3p0;rv6P=#R@q>n*u7Qto||zg)S( zvgupf14-o^hJca=g?rIc7fAou;}#ys@=;;srWEfB3G7n0Jr4N&7VzK}33)91o8bkI z&E~BE0ul18JML`o^v%xg6Ub1$=Y1&kpZNLqzBG#r<=tHGc57UTd9!bowU%yX;(I-z zFWSdEd=qznwr70x>iXR~=Gyfocc*$hSR`t7N=oPoV{2*IpWJ-0@S>~BwBB#q@$Q6> z+b{V=q2fDMrFK6#ULG+)LFeSrefGC@e_hI7SpVv~Na=&C>kcn|qs(P5sPpLgG}AND z+T2~HEKb^Ymb6*BN7Xc3Vy`ICiOoOc?aL_RDN@4L+<0ME$i#yu3nm;>?bfosSAYAS zX>?Rj$8N^Hs~&UbuDtkff8}d0`C0n}Gyc0)e43PYxpUqgC!@!grc9nGCz`fwd45-? z zv02s5*BMv0&1u*svDmBBo{^EUVQIBeN`7)_ZfYJdQCd|ixmv}GRY{#z#`Sa#3U^_&CqCbKG#Yni68x2GOIu2=i9*Kx;- zo{YBCC^i`Zz|O$snk)6cGSPAWg_CD2*G--@c>|xw=0H9fIbkctWsZ!?ycw5eF)k}(T-MIG LY~JPu9W!PC+9m9w diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.dll index f6c5afc9503c12010b21dde16bfc1cd64c711f94..d31e5d59fe931ab366c7e8a65cbbb133436de353 100644 GIT binary patch literal 599552 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ऀW$wc}}I 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�d*e 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 z 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

    >T`@Hr8 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 delta 93307 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%0AZoq1_ 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⋙_DVC^Bd)6?pnLZWr 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 z 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 z%0A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 delta 69417 zcmZUc3A|0!`^MKf_qz8Y^E_qFMdo>)$vn#}WXO;ZQnH&%QgoZpga(o%MTjDrq@aT~mG6Dyl%a_{wt| z)<4nrV5bc|8oajP<|l(A1!ujxV1B`hFUOp_HO;wIIh;#J|2g1&vpM$-mU%v}bA|Eu z?gbx~D7F`gMG*XPIdLt9>sefYwyCk+_%vA*AZn)ax)P70rwQ8SM`yaJiV-v+(XE5&OWD6({OWs#v zx7xX}U1P2Y76$bcbG_A`t@gcYzozykwf|82V!8`3 zz&PA^F*g&8yKAzuJqe7vUvOi^+`nMl^)1BqSTOEJ;|4@M7y zc958R0*t#web`O*nSX7PT43B=x0&tPVBCGZmF+WN+zoh-?d!p~ z`+XGw+F(#P&!q?lKRv-3*MoYCp2w8pO>P{7QKo#K33R zo(;y`ma}Ys4#wTqi)`-&E8+r2>yJdW)Lz_`2i2DWbn<5{t^7Fl`Ia`Y_g#y=5r zW!owpqk@XR$Y!xQudxvKFM33PvIlb0@_=#S3EUV#afd z`Nd*l8L^UBU92ZI72AlN#Gc{+agO-0nCnUQTw1If=ua!LpEy#yS-e+#T3ji9CFXsK zU6c~D#0}yJvCh-XwiLUG{lw?Qcf=3G-A`lJiMf4}NzbtTjJQtR0><6n;=f{(XBlZN zb_7%0HR37pAF=Qf#+!)!#L41KVj$it&R-G>P`XgEPyAN=Q9LF7ExM)bG(*fQ78T2g znPN?`q1ag*D&8R8B;F?8C(Z|h6!(PWS#i1es`#e(j`)GNTXf4b6)~?^R4gNAiZ#WC z;uP^_@ec8R@nJG>izG|Mm&Dh^jp82hfOtf#_Z)|BCbkp1ihafV#1-N@;$bjxNpX#y z=dwM->09}$;`>&36czr_YG zYFV7Ru~>gdio0EWP+Tm&CH^8_1nnio)m_e|t`~0?=ZGuCkHqi9i(=Xe)|V5ji49i- z4E2$W6Ss=T#q^h$%>$;ovf``adU1=mL%blSu4H8o@nvy?_#S94sqUEKugGaqyKGj=IHyY%aE%<;BF>;!yD+G2>NctBdu;=3;xX8<^($f%cN-&MMvqk1x~Q zz2cXmdySFYVi_`URVA~<`Qj_$PH~@@Yb_TmB$g5@iq*t=Vl%NFnC`lYeZ)cH2=O}c z262WM%+{Z~#RtH|CEaBylKXXbS4b==mKUptjm19V94$^1Zxn9<$7gqUNalzu#J9!w z#9iWkvB*YFtF%~2tO43fcGp1hUgAXYVe!35U{3eF_$wK>KO`5#Y+IPl zB^DA(i510aVm+~$*iP&!_66-Fr<CLo)hD5bLu(7{9%=YM zd*UbJUh!-32l0gXr+86Jdne$mi@rma5i`Y_VneZ|c$L^g>@Qv;jumeZZxZhp9~Kvh zOU0MO*TjwDws&wZ%;`Ro92S2Pe-qD&v8|k3b}^q=Oe`x_7Hf%J#lGSYag;bwoF?8X zJ|sR4207g`k{89*;(GCI@iTG1cv$>N{7pP7#

    axy8cb<>D1$b+NwKTx>6PBLmk@ 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 S&t{pFVS%28j+9x<;{OLpseo4i diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/x86_64/gamecult_mesh_quic_native.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/x86_64/gamecult_mesh_quic_native.dll index 338750c003ac8ed89aa566e40e14cc89dcddb26e..91133b5a4a241023578fb9dce5cf395e49ce5be5 100644 GIT binary patch delta 27 fcmZqJ!_=^cX@dYGGk&e5?rY delta 27 fcmZqJ!_=^cX@dYGb3=FRW?{y}Bru~qxzh>&i9-qQ From 1fc68a4701b663ee8d4b575dc914377c7b67ee84 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 17 Aug 2026 22:42:08 +0200 Subject: [PATCH 061/283] Route CultMesh sessions by stable Verse identity --- src/GameCult.Mesh/CultMeshSessions.cs | 12 +++- .../CultMeshBodySessionTests.cs | 4 +- .../CultMeshContentSessionTests.cs | 4 +- .../CultMeshSessionManagerTests.cs | 69 ++++++++++++++++--- .../CultMeshTransportModularityTests.cs | 10 +-- unity/org.gamecult.cultlib/package.json | 2 +- 6 files changed, 80 insertions(+), 21 deletions(-) diff --git a/src/GameCult.Mesh/CultMeshSessions.cs b/src/GameCult.Mesh/CultMeshSessions.cs index 87f18158..5011a00a 100644 --- a/src/GameCult.Mesh/CultMeshSessions.cs +++ b/src/GameCult.Mesh/CultMeshSessions.cs @@ -520,7 +520,9 @@ namespace GameCult.Mesh CultMeshSessionFailureReason.UnsupportedPath, "No streaming content connectors are configured. Register the TCP content connector or the explicit legacy RUDP connector."); - var discovery = await _discovery.ResolveAsync(new CultMeshDiscoveryQuery(endpointId.Value)).ConfigureAwait(false); + var discovery = await _discovery.ResolveAsync(new CultMeshDiscoveryQuery( + endpointId.Value, + new[] { endpointId.Value })).ConfigureAwait(false); var candidates = discovery.Candidates .SelectMany(candidate => candidate.Descriptor.DiscoveryEndpoints) .Distinct(StringComparer.Ordinal) @@ -646,7 +648,9 @@ namespace GameCult.Mesh CultMeshSessionFailureReason.UnsupportedPath, "No realtime state connectors are configured. Register a QUIC connector explicitly."); - var discovery = await _discovery.ResolveAsync(new CultMeshDiscoveryQuery(endpointId.Value)).ConfigureAwait(false); + var discovery = await _discovery.ResolveAsync(new CultMeshDiscoveryQuery( + endpointId.Value, + new[] { endpointId.Value })).ConfigureAwait(false); var routes = discovery.Candidates .SelectMany(candidate => candidate.Descriptor.DiscoveryEndpoints) .Distinct(StringComparer.Ordinal) @@ -733,7 +737,9 @@ namespace GameCult.Mesh private async Task ResolveConnectedPathAsync(CultMeshEndpointId endpointId, CultMeshProtocolId protocol) { - var discovery = await _discovery.ResolveAsync(new CultMeshDiscoveryQuery(endpointId.Value)).ConfigureAwait(false); + var discovery = await _discovery.ResolveAsync(new CultMeshDiscoveryQuery( + endpointId.Value, + new[] { endpointId.Value })).ConfigureAwait(false); var candidates = discovery.Candidates.SelectMany(candidate => candidate.Descriptor.DiscoveryEndpoints) .Distinct(StringComparer.Ordinal) .Select(endpoint => new CultMeshTransportCandidate(endpoint)) diff --git a/tests/GameCult.Mesh.Tests/CultMeshBodySessionTests.cs b/tests/GameCult.Mesh.Tests/CultMeshBodySessionTests.cs index 57b8995a..c105ae06 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshBodySessionTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshBodySessionTests.cs @@ -28,7 +28,7 @@ public sealed class CultMeshBodySessionTests using var discovery = new CultMeshDiscoveryService(new[] { new RouteSource() }); using var sessions = new CultMeshSessionManager(discovery, new[] { connector }); var provider = new CultMeshSessionBodyProvider( - "aetheria.daemon", sessions, CultMeshEndpointId.Parse("service:aetheria.daemon")); + "aetheria.daemon", sessions, CultMeshEndpointId.Parse("aetheria")); var received = await provider.FetchAsync(descriptor); @@ -69,7 +69,7 @@ public sealed class CultMeshBodySessionTests using var sessions = new CultMeshSessionManager(discovery, new ICultMeshTransportConnector[] { new CultMeshSchemaTransportConnector() }); var provider = new CultMeshSessionBodyProvider("aetheria.daemon", sessions, - CultMeshEndpointId.Parse("service:aetheria.daemon"), + CultMeshEndpointId.Parse("aetheria"), new CultMeshSessionBodyProviderOptions { ResponseTimeout = TimeSpan.FromSeconds(10) }); var elapsed = Stopwatch.StartNew(); diff --git a/tests/GameCult.Mesh.Tests/CultMeshContentSessionTests.cs b/tests/GameCult.Mesh.Tests/CultMeshContentSessionTests.cs index 6bf5e88b..c1a4d04b 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshContentSessionTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshContentSessionTests.cs @@ -52,7 +52,7 @@ public sealed class CultMeshContentSessionTests var provider = new CultMeshSessionContentProvider( "aetheria.daemon", sessions, - CultMeshEndpointId.Parse("service:aetheria.daemon")); + CultMeshEndpointId.Parse("aetheria")); using var transferState = new CultCache(CultMesh.CreateCultCacheDocumentRegistry( typeof(CultMeshContentTransferStateDocument))); var transfer = new CultMeshContentTransferService( @@ -114,7 +114,7 @@ public sealed class CultMeshContentSessionTests var provider = new CultMeshSessionContentProvider( "aetheria.daemon", sessions, - CultMeshEndpointId.Parse("service:aetheria.daemon")); + CultMeshEndpointId.Parse("aetheria")); using var transferState = new CultCache(CultMesh.CreateCultCacheDocumentRegistry( typeof(CultMeshContentTransferStateDocument))); var transfer = new CultMeshContentTransferService( diff --git a/tests/GameCult.Mesh.Tests/CultMeshSessionManagerTests.cs b/tests/GameCult.Mesh.Tests/CultMeshSessionManagerTests.cs index b0aabd03..42e6d962 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshSessionManagerTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshSessionManagerTests.cs @@ -13,6 +13,27 @@ namespace GameCult.Mesh.Tests; public sealed class CultMeshSessionManagerTests { + [Test] + public async Task Connect_ResolvesOnlyTheRequestedVerseIdentity() + { + var clock = new ManualSessionClock(); + using var discovery = new CultMeshDiscoveryService( + new[] { new MultiVerseRouteSource(clock) }, + new CultMeshDiscoveryServiceOptions { Clock = clock }); + CultMeshTransportCandidate? connected = null; + var connector = new FakeConnector((candidate, _) => + { + connected = candidate; + return Task.FromResult(new FakeSchemaClient()); + }); + using var manager = new CultMeshSessionManager(discovery, new[] { connector }, new CultMeshSessionManagerOptions { Clock = clock }); + + await manager.ConnectAsync(CultMeshEndpointId.Parse("aetheria"), CultMeshProtocols.Documents); + + connected.Should().NotBeNull(); + connected!.Endpoint.Should().Be("rudp://aetheria:3076"); + } + [Test] public async Task Connect_ReusesInflightAndEstablishedSession() { @@ -21,7 +42,7 @@ public sealed class CultMeshSessionManagerTests var release = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var connector = new FakeConnector(async (_, _) => { await release.Task; return new FakeSchemaClient(); }); using var manager = new CultMeshSessionManager(discovery, new[] { connector }, new CultMeshSessionManagerOptions { Clock = clock }); - var endpoint = CultMeshEndpointId.Parse("odin:aetheria"); + var endpoint = CultMeshEndpointId.Parse("aetheria"); var first = manager.ConnectAsync(endpoint, CultMeshProtocols.Documents); var second = manager.ConnectAsync(endpoint, CultMeshProtocols.Documents); @@ -49,7 +70,7 @@ public sealed class CultMeshSessionManagerTests }); using var manager = new CultMeshSessionManager(discovery, new[] { connector }, new CultMeshSessionManagerOptions { Clock = clock }); - var session = await manager.ConnectAsync(CultMeshEndpointId.Parse("odin:aetheria"), CultMeshProtocols.Documents); + var session = await manager.ConnectAsync(CultMeshEndpointId.Parse("aetheria"), CultMeshProtocols.Documents); session.State.Path!.Endpoint.Should().Be("rudp://fast:3076"); slowRelease.TrySetResult(); await WaitUntilAsync(() => slowClient.DisposeCount == 1); @@ -70,7 +91,7 @@ public sealed class CultMeshSessionManagerTests }); using var manager = new CultMeshSessionManager(discovery, new[] { connector }, new CultMeshSessionManagerOptions { Clock = clock }); using var cancellation = new CancellationTokenSource(); - var endpoint = CultMeshEndpointId.Parse("odin:aetheria"); + var endpoint = CultMeshEndpointId.Parse("aetheria"); var cancelled = manager.ConnectAsync(endpoint, CultMeshProtocols.Documents, cancellation.Token); var survivor = manager.ConnectAsync(endpoint, CultMeshProtocols.Documents); @@ -97,7 +118,7 @@ public sealed class CultMeshSessionManagerTests return Task.FromResult(client); }); using var manager = new CultMeshSessionManager(discovery, new[] { connector }, new CultMeshSessionManagerOptions { Clock = clock }); - var endpoint = CultMeshEndpointId.Parse("odin:aetheria"); + var endpoint = CultMeshEndpointId.Parse("aetheria"); var first = await manager.ConnectAsync(endpoint, CultMeshProtocols.Documents); var states = new List(); using var stateWatch = first.WatchState().Subscribe(state => states.Add(state.Status)); @@ -129,7 +150,7 @@ public sealed class CultMeshSessionManagerTests using var manager = new CultMeshSessionManager(discovery, Array.Empty(), new CultMeshSessionManagerOptions { Clock = clock }); var error = Assert.ThrowsAsync(() => - manager.ConnectAsync(CultMeshEndpointId.Parse("odin:aetheria"), CultMeshProtocols.Documents)); + manager.ConnectAsync(CultMeshEndpointId.Parse("aetheria"), CultMeshProtocols.Documents)); error!.Failure.Reason.Should().Be(CultMeshSessionFailureReason.Transport); error.InnerException.Should().BeOfType() @@ -144,7 +165,7 @@ public sealed class CultMeshSessionManagerTests var client = new RespondingSchemaClient(); var connector = new FakeConnector((_, _) => Task.FromResult(client)); using var manager = new CultMeshSessionManager(discovery, new[] { connector }, new CultMeshSessionManagerOptions { Clock = clock }); - var endpoint = CultMeshEndpointId.Parse("odin:aetheria"); + var endpoint = CultMeshEndpointId.Parse("aetheria"); using var first = await CultMeshSnapshotSession.ConnectAsync(manager, endpoint, new CultMeshSnapshotRequestOptions()); using var second = await CultMeshSnapshotSession.ConnectAsync(manager, endpoint, new CultMeshSnapshotRequestOptions()); @@ -166,7 +187,7 @@ public sealed class CultMeshSessionManagerTests var connector = new FakeConnector((_, _) => Task.FromResult(client)); using var manager = new CultMeshSessionManager(discovery, new[] { connector }, new CultMeshSessionManagerOptions { Clock = clock }); var exchange = new CultMeshPeerExchangeClient(new CultMeshPeerExchangeClientOptions { Sessions = manager, Clock = clock }); - var endpoint = CultMeshEndpointId.Parse("odin:aetheria"); + var endpoint = CultMeshEndpointId.Parse("aetheria"); var first = await exchange.FetchAsync(endpoint, new CultMeshPeerExchangeRequestMessage { VerseId = "aetheria" }); var second = await exchange.FetchAsync(endpoint, new CultMeshPeerExchangeRequestMessage { VerseId = "aetheria" }); @@ -185,7 +206,7 @@ public sealed class CultMeshSessionManagerTests var client = new LeaseSchemaClient(); var connector = new FakeConnector((_, _) => Task.FromResult(client)); using var manager = new CultMeshSessionManager(discovery, new[] { connector }, new CultMeshSessionManagerOptions { Clock = clock }); - var session = await manager.ConnectAsync(CultMeshEndpointId.Parse("odin:aetheria"), CultMeshProtocols.Subscriptions); + var session = await manager.ConnectAsync(CultMeshEndpointId.Parse("aetheria"), CultMeshProtocols.Subscriptions); using var first = session.OpenSchemaClient(); using var second = session.OpenSchemaClient(); var firstCount = 0; @@ -237,6 +258,38 @@ public sealed class CultMeshSessionManagerTests }); } + private sealed class MultiVerseRouteSource : ICultMeshLookupSource + { + private readonly ManualSessionClock _clock; + public MultiVerseRouteSource(ManualSessionClock clock) => _clock = clock; + public string SourceId => "odin"; + + public Task> LookupAsync( + CultMeshDiscoveryQuery query, + CancellationToken cancellationToken = default) + { + var expires = _clock.UtcNow.AddMinutes(1); + return Task.FromResult>(new[] + { + Observation("norn", "rudp://norn:3076", expires), + Observation("aetheria", "rudp://aetheria:3076", expires) + }); + } + + private CultMeshDiscoveryObservation Observation(string verseId, string endpoint, DateTimeOffset expires) => + new( + new CultMeshVerseDescriptor( + verseId, + verseId, + CultMeshVerseAuthorityModel.OperatorCluster, + new CultMeshVerseCompatibility("cultmesh.v0", "rules"), + new[] { endpoint }), + SourceId, + _clock.UtcNow, + expires, + CultMeshDiscoveryTrust.Signed); + } + private sealed class FakeConnector : ICultMeshTransportConnector { private readonly Func> _connect; diff --git a/tests/GameCult.Mesh.Tests/CultMeshTransportModularityTests.cs b/tests/GameCult.Mesh.Tests/CultMeshTransportModularityTests.cs index a280c436..47eab18b 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshTransportModularityTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshTransportModularityTests.cs @@ -39,7 +39,7 @@ public sealed class CultMeshTransportModularityTests }); var session = await sessions.ConnectAsync( - CultMeshEndpointId.Parse("service:aetheria.daemon"), + CultMeshEndpointId.Parse("aetheria"), CultMeshProtocols.Documents); var response = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); using var subscription = session.OnCultNet(message => response.TrySetResult(message)); @@ -77,7 +77,7 @@ public sealed class CultMeshTransportModularityTests new CultMeshTcpContentTransportConnector() }); - var session = await sessions.ConnectContentAsync(CultMeshEndpointId.Parse("service:aetheria.daemon")); + var session = await sessions.ConnectContentAsync(CultMeshEndpointId.Parse("aetheria")); using var destination = new MemoryStream(); await session.CopyChunkToAsync(artifact.Manifest.Chunks[0], destination); @@ -98,7 +98,7 @@ public sealed class CultMeshTransportModularityTests Array.Empty()); Func connect = async () => await sessions.ConnectContentAsync( - CultMeshEndpointId.Parse("service:aetheria.daemon")); + CultMeshEndpointId.Parse("aetheria")); await connect.Should().ThrowAsync() .WithMessage("*No streaming content connectors are configured*"); @@ -118,7 +118,7 @@ public sealed class CultMeshTransportModularityTests Array.Empty(), new ICultMeshRealtimeTransportConnector[] { connector }); var session = await sessions.ConnectRealtimeAsync( - CultMeshEndpointId.Parse("service:aetheria.daemon")); + CultMeshEndpointId.Parse("aetheria")); var sent = new CultMeshRealtimeFrame { ChannelId = "aetheria.entities", @@ -150,7 +150,7 @@ public sealed class CultMeshTransportModularityTests Array.Empty()); Func connect = async () => await sessions.ConnectRealtimeAsync( - CultMeshEndpointId.Parse("service:aetheria.daemon")); + CultMeshEndpointId.Parse("aetheria")); await connect.Should().ThrowAsync() .WithMessage("*No realtime state connectors are configured*"); diff --git a/unity/org.gamecult.cultlib/package.json b/unity/org.gamecult.cultlib/package.json index 6be0f3e1..979cabc8 100644 --- a/unity/org.gamecult.cultlib/package.json +++ b/unity/org.gamecult.cultlib/package.json @@ -1,7 +1,7 @@ { "name": "org.gamecult.cultlib", "displayName": "CultLib", - "version": "1.0.45", + "version": "1.0.46", "unity": "2021.3", "description": "CultCache, CultNet, and CultMesh managed runtime assemblies for Unity.", "license": "MIT", From 54e4eacd137b23dcd3505b2335b7e7e6f69481b6 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 17 Aug 2026 23:18:15 +0200 Subject: [PATCH 062/283] Validate Eve getting-started contracts --- README.md | 10 ++- samples/eve-two-runtime/README.md | 32 ++++++++ samples/eve-two-runtime/sample.mjs | 74 ++++++++++++++++--- scripts/verify-eve-two-runtime-sample.ps1 | 4 +- .../getting-started/02-connect-by-identity.md | 15 ++-- .../03-publish-an-eve-surface.md | 28 ++++--- .../docs/getting-started/README.md | 12 +++ 7 files changed, 143 insertions(+), 32 deletions(-) create mode 100644 samples/eve-two-runtime/README.md diff --git a/README.md b/README.md index d6e3778c..013954e5 100644 --- a/README.md +++ b/README.md @@ -62,8 +62,14 @@ the stack. If a design needs another peer-to-peer category, first check whether it is really Verse policy, peer exchange, or shard authority wearing a fake mustache. -If you want the smallest durable "open node -> put typed doc -> get typed doc" -path, start with +If you want to build an application rather than tour the component drawer, +start with the maintained +[`CultMesh And Eve Getting Started`](src/GameCult.Mesh/docs/getting-started/README.md) +series. Its first executable package-consumer checkpoint is +[`samples/eve-two-runtime`](samples/eve-two-runtime/README.md). + +If you want only the smallest durable "open node -> put typed doc -> get typed doc" +path, use [`src/GameCult.Mesh/docs/durable-node-quickstart.md`](src/GameCult.Mesh/docs/durable-node-quickstart.md). If you want the lower-level "typed local document -> raw wire document -> mesh/runtime watch surface" handoff, follow it with diff --git a/samples/eve-two-runtime/README.md b/samples/eve-two-runtime/README.md new file mode 100644 index 00000000..9e9f1656 --- /dev/null +++ b/samples/eve-two-runtime/README.md @@ -0,0 +1,32 @@ +# Eve Two-Consumer Counter + +This is the smallest executable package-consumer checkpoint for CultMesh plus +Eve. It intentionally has one owner for each decision: + +- the provider node owns the counter document and command transaction; +- Eve owns the validated surface and command-receipt contracts; +- CultMesh owns typed observation and the operation boundary; +- the DOM lowerer owns HTML only; +- the headless observer owns no state. + +Run it from the CultLib repository: + +```powershell +powershell -ExecutionPolicy Bypass -File .\scripts\verify-eve-two-runtime-sample.ps1 ` + -EveRoot ..\Eve +``` + +The verifier builds package artifacts, installs them into a new empty temporary +consumer, and runs `sample.mjs`. Success proves: + +1. no source-tree import is required by the consumer; +2. the provider surface and receipt pass Eve's generated runtime validators; +3. a DOM click executes one idempotent provider operation; +4. the DOM binding and a separate headless observer converge on the same count; +5. the canonical receipt and state survive reopening the `.cc` store. + +This is not yet the promised networked multiplayer tutorial. The DOM lowerer is +hosted by jsdom in Node and both consumers share one local CultMesh node. A real +browser transport, Odin discovery, process separation, and a second language +runtime require distinct executable gates. Keeping that limitation visible is +part of the sample contract. diff --git a/samples/eve-two-runtime/sample.mjs b/samples/eve-two-runtime/sample.mjs index a78b765f..e3269618 100644 --- a/samples/eve-two-runtime/sample.mjs +++ b/samples/eve-two-runtime/sample.mjs @@ -6,6 +6,10 @@ import { JSDOM } from "jsdom"; import { z } from "zod"; import { defineDocumentType } from "cultcache-ts"; import { CultMesh } from "cultmesh-ts"; +import { + parseEveCommandReceipt, + parseEveSurfaceDocument, +} from "@gamecult/eve-contracts"; import { renderEveSurface } from "@gamecult/eve-browser-lowering"; const providerId = "sample.counter-provider"; @@ -22,36 +26,38 @@ const counterDocument = defineDocumentType({ const surfaceDocument = defineDocumentType({ type: "gamecult.eve.surface", schemaId: "gamecult.eve.surface.v1", - schema: z.any(), + schema: z.unknown().transform(value => parseEveSurfaceDocument(value)), }); const receiptDocument = defineDocumentType({ - type: "sample.counter_receipt", - schemaId: "sample.counter_receipt.v1", - schema: z.object({ - receiptId: z.string(), - operationId: z.literal("sample.counter.increment"), - idempotencyKey: z.string(), - count: z.number().int(), - }), + type: "gamecult.eve.command_receipt", + schemaId: "gamecult.eve.command_receipt.v1", + schema: z.unknown().transform(value => parseEveCommandReceipt(value)), name: "receiptId", }); function counterSurface() { return { + type: "surface-state", + schema: "gamecult.eve.surface.v1", providerId, + providerKind: "sample.daemon", title: "CultMesh two-runtime counter", version: 1, + updatedAtUtc: "2026-08-17T00:00:00Z", surface: { id: surfaceId, + title: "Counter", root: { id: "counter.root", kind: "column", + props: {}, children: [ { id: "counter.value", kind: "metric", props: { label: "Canonical count", value: 0 }, + children: [], stateBindings: [{ targetProp: "value", pointerId: "sample.counter.count", @@ -64,10 +70,21 @@ function counterSurface() { id: "counter.increment", kind: "control.button", props: { label: "Increment", command: "sample.counter.increment" }, + children: [], }, ], }, + styles: {}, }, + commands: [{ + schema: "gamecult.eve.command.v1", + command: "sample.counter.increment", + label: "Increment", + surfaceId, + transport: "cultmesh", + authority: "provider-daemon", + result: "gamecult.eve.command_receipt.v1", + }], }; } @@ -97,7 +114,16 @@ async function waitFor(predicate, description) { } } -const statePath = join(await mkdtemp(join(tmpdir(), "cultmesh-eve-two-runtime-")), "state.ccmp"); +assert.throws( + () => parseEveSurfaceDocument({ providerId, surface: { id: surfaceId } }), + /Invalid Eve surface/, +); +assert.throws( + () => parseEveCommandReceipt({ receiptId: "unowned" }), + /Invalid Eve commandReceipt/, +); + +const statePath = join(await mkdtemp(join(tmpdir(), "cultmesh-eve-two-runtime-")), "state.cc"); const node = await CultMesh.startNode(statePath, { documents: [counterDocument, surfaceDocument, receiptDocument], }); @@ -120,7 +146,16 @@ const increment = CultMesh.operation("sample.counter.increment", async (_request })); const receipt = { receiptId: `receipt:${idempotencyKey}`, - operationId: "sample.counter.increment", + schema: "gamecult.eve.command_receipt.v1", + commandId: idempotencyKey, + command: "sample.counter.increment", + state: "accepted", + ownerRepo: "CultLib", + authority: "provider-daemon", + providerId, + surfaceId, + issuedAtUtc: new Date().toISOString(), + sourceVersion: next.count, idempotencyKey, count: next.count, }; @@ -162,7 +197,21 @@ assert.equal(duplicate.receiptId, browserReceipt.receiptId); assert.equal(headless.current.count, 1); headless.dispose(); -renderEveSurface({ providerId, surface: { id: "sample.closed" } }, host); +renderEveSurface(parseEveSurfaceDocument({ + type: "surface-state", + schema: "gamecult.eve.surface.v1", + providerId, + providerKind: "sample.daemon", + title: "Closed counter", + version: 2, + updatedAtUtc: "2026-08-17T00:00:01Z", + surface: { + id: "sample.closed", + root: { id: "closed.root", kind: "column", props: {}, children: [] }, + styles: {}, + }, + commands: [], +}), host); dom.window.close(); await node.flush(); const reopened = await CultMesh.startNode(statePath, { @@ -178,6 +227,7 @@ console.log(JSON.stringify({ providerId, surfaceId, receiptId: browserReceipt.receiptId, + loweringRuntime: "jsdom", browserCount: 1, headlessCount: 1, restartCount: 1, diff --git a/scripts/verify-eve-two-runtime-sample.ps1 b/scripts/verify-eve-two-runtime-sample.ps1 index f5545d5f..f6d4ebce 100644 --- a/scripts/verify-eve-two-runtime-sample.ps1 +++ b/scripts/verify-eve-two-runtime-sample.ps1 @@ -7,10 +7,12 @@ $ErrorActionPreference = "Stop" $cultLibRoot = Split-Path -Parent $PSScriptRoot $samplePath = Join-Path $cultLibRoot "samples\eve-two-runtime\sample.mjs" $eveBrowserPackage = Join-Path $EveRoot "packages\eve-browser-lowering" +$eveContractsPackage = Join-Path $EveRoot "packages\eve-contracts" $packageRoots = @( (Join-Path $cultLibRoot "packages\cultcache-ts"), (Join-Path $cultLibRoot "packages\cultnet-ts"), (Join-Path $cultLibRoot "packages\cultmesh-ts"), + $eveContractsPackage, $eveBrowserPackage ) @@ -56,7 +58,7 @@ try { throw "CultNet TypeScript contract generation failed: $packageRoot" } } - $typescriptPath = if ($packageRoot -eq $eveBrowserPackage) { + $typescriptPath = if ($packageRoot -eq $eveBrowserPackage -or $packageRoot -eq $eveContractsPackage) { Join-Path $packageRoot "node_modules\typescript\bin\tsc" } else { diff --git a/src/GameCult.Mesh/docs/getting-started/02-connect-by-identity.md b/src/GameCult.Mesh/docs/getting-started/02-connect-by-identity.md index dd7a1abd..b7c636d4 100644 --- a/src/GameCult.Mesh/docs/getting-started/02-connect-by-identity.md +++ b/src/GameCult.Mesh/docs/getting-started/02-connect-by-identity.md @@ -12,15 +12,20 @@ using var mesh = new CultMeshClient(new CultMeshClientOptions RendezvousEndpoints = new[] { "rudp://odin.gamecult.net:3076" } }); -using var pilotSurfaceLease = await mesh.LeaseDocumentAsync( - "aetheria.daemon", - "eve:surface:aetheria.pilot", +using var counterLease = await mesh.LeaseDocumentAsync( + "sample.counter-provider", + "counter:main", cancellationToken); -var pilotSurface = pilotSurfaceLease.Handle; +var counter = counterLease.Handle; -using var surfaceWatch = pilotSurface.Watch().Subscribe(Render); +using var counterWatch = counter.Watch(value => + Console.WriteLine($"Count: {value.Count}")); ``` +`CounterState` is the application document from chapter 1. Eve documents enter +in chapter 3, where the sample installs the renderer-neutral Eve contract +package explicitly. This identity/session API does not depend on a UI runtime. + Keep `mesh` for the application lifetime and dispose each document lease when the consuming screen or system closes. Leases for the same identity share one subscription. The document handle is stable while leased: when diff --git a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md index 95048d3a..d28ef621 100644 --- a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md +++ b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md @@ -35,7 +35,7 @@ Run the same provider and connect at least two lowerers. Both must report the same provider id, surface id, surface version, and command receipt ids. Native pixels may differ; provider truth may not. -The package-artifact browser/headless checkpoint is executable from CultLib: +The package-artifact DOM-lowerer/headless checkpoint is executable from CultLib: ```powershell cd CultLib @@ -43,14 +43,16 @@ powershell -ExecutionPolicy Bypass -File .\scripts\verify-eve-two-runtime-sample -EveRoot ..\Eve ``` -The verifier builds and packs `cultcache-ts`, `cultnet-ts`, `cultmesh-ts`, and -`@gamecult/eve-browser-lowering`, installs the tarballs into an empty temporary -consumer, and runs `samples/eve-two-runtime/sample.mjs`. One provider-owned -counter surface is lowered by a browser runtime and observed by a headless -runtime. A browser command crosses the typed operation boundary, both runtimes -converge on the same state and receipt identity, a duplicate idempotency key is -not applied twice, and the state plus receipt survive reopening the `.ccmp` -store. +The verifier builds and packs `cultcache-ts`, `cultnet-ts`, `cultmesh-ts`, +`@gamecult/eve-contracts`, and `@gamecult/eve-browser-lowering`, installs the +tarballs into an empty temporary consumer, and runs +`samples/eve-two-runtime/sample.mjs`. Eve's generated runtime validators reject +an invalid surface or receipt before either enters the store. One provider-owned +counter surface is lowered into a jsdom DOM host and observed by an independent +headless CultMesh observer. A DOM command crosses the typed operation boundary, +both consumers converge on the same state and canonical receipt identity, a +duplicate idempotency key is not applied twice, and the state plus receipt +survive reopening the `.cc` store. Current verification for the Unity consumer remains: @@ -59,7 +61,9 @@ cd E:\Projects\EveUnity powershell -ExecutionPolicy Bypass -File .\scripts\run-release-consumer-tests.ps1 ``` -This checkpoint proves clean package consumption and two lowering/observation -runtimes. It does not claim an Odin-discovered network hop or cross-language -command execution; those remain separate public Verse conformance gates. +This checkpoint proves clean package consumption, canonical Eve contract +validation, and two independent lowering/observation consumers inside Node. It +does **not** claim a real browser process, an Odin-discovered network hop, or +cross-language command execution. Those are the next public Verse conformance +gates; do not cite this sample as evidence that they exist. diff --git a/src/GameCult.Mesh/docs/getting-started/README.md b/src/GameCult.Mesh/docs/getting-started/README.md index 7914247c..d5e91d74 100644 --- a/src/GameCult.Mesh/docs/getting-started/README.md +++ b/src/GameCult.Mesh/docs/getting-started/README.md @@ -4,6 +4,18 @@ This series builds one typed application state and presents it through multiple Eve runtimes. It is maintained as an API acceptance test: examples use public APIs, name the owner of each decision, and include a verification checkpoint. +Run the current clean-consumer checkpoint first: + +```powershell +powershell -ExecutionPolicy Bypass -File .\scripts\verify-eve-two-runtime-sample.ps1 ` + -EveRoot ..\Eve +``` + +It installs packed artifacts into an empty temporary project, validates the Eve +surface and receipt, executes one idempotent counter command, proves two local +consumers converge, and reopens the durable `.cc` store. It is deliberately not +called a networked-browser proof; chapter 3 names that remaining boundary. + Follow the chapters in order: 1. [Persist typed application state](01-persist-typed-state.md) From 3fe2e9be1bba474f054387bcbb7a920e7cdf1a26 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 17 Aug 2026 23:26:51 +0200 Subject: [PATCH 063/283] Publish browser subscription wire contracts --- README.md | 2 + .../cultnet.database-change-raw.schema.json | 25 +++ .../cultnet.database-subscribe.schema.json | 20 +++ .../cultnet.database-unsubscribe.schema.json | 14 ++ packages/cultnet-ts/src/contracts.ts | 89 +++++++++- packages/cultnet-ts/src/index.ts | 3 + packages/cultnet-ts/test/cultnet.test.ts | 58 +++++++ .../docs/browser-verse-transport.md | 156 ++++++++++++++++++ .../03-publish-an-eve-surface.md | 4 +- .../cultnet.database-change-raw.schema.json | 25 +++ .../cultnet.database-subscribe.schema.json | 20 +++ .../cultnet.database-unsubscribe.schema.json | 14 ++ .../CultNetSchemaRegistry.cs | 21 +++ .../NetworkingTests.cs | 13 ++ 14 files changed, 462 insertions(+), 2 deletions(-) create mode 100644 packages/cultnet-ts/contracts/cultnet.database-change-raw.schema.json create mode 100644 packages/cultnet-ts/contracts/cultnet.database-subscribe.schema.json create mode 100644 packages/cultnet-ts/contracts/cultnet.database-unsubscribe.schema.json create mode 100644 src/GameCult.Mesh/docs/browser-verse-transport.md create mode 100644 src/GameCult.Networking/Contracts/cultnet.database-change-raw.schema.json create mode 100644 src/GameCult.Networking/Contracts/cultnet.database-subscribe.schema.json create mode 100644 src/GameCult.Networking/Contracts/cultnet.database-unsubscribe.schema.json diff --git a/README.md b/README.md index 013954e5..aee7644d 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,8 @@ start with the maintained [`CultMesh And Eve Getting Started`](src/GameCult.Mesh/docs/getting-started/README.md) series. Its first executable package-consumer checkpoint is [`samples/eve-two-runtime`](samples/eve-two-runtime/README.md). +The missing real-browser/network boundary is mapped explicitly in +[`browser-verse-transport.md`](src/GameCult.Mesh/docs/browser-verse-transport.md). If you want only the smallest durable "open node -> put typed doc -> get typed doc" path, use diff --git a/packages/cultnet-ts/contracts/cultnet.database-change-raw.schema.json b/packages/cultnet-ts/contracts/cultnet.database-change-raw.schema.json new file mode 100644 index 00000000..9bedb72a --- /dev/null +++ b/packages/cultnet-ts/contracts/cultnet.database-change-raw.schema.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/GameCult/cultnet-ts/contracts/cultnet.database-change-raw.schema.json", + "title": "CultNet Raw Database Change Message", + "type": "object", + "required": ["schemaVersion", "messageId", "subscriptionId", "changeKind"], + "additionalProperties": false, + "properties": { + "schemaVersion": { "const": "cultnet.database_change_raw.v0" }, + "messageId": { "type": "string", "minLength": 1 }, + "subscriptionId": { "type": "string", "minLength": 1 }, + "changeKind": { "enum": ["added", "updated", "removed"] }, + "document": { "$ref": "./cultnet.raw-document-record.schema.json" }, + "recordKey": { "type": "string", "minLength": 1 }, + "schemaId": { "type": "string", "minLength": 1 } + }, + "allOf": [ + { + "if": { "properties": { "changeKind": { "const": "removed" } } }, + "then": { "required": ["recordKey", "schemaId"] }, + "else": { "required": ["document"] } + } + ] +} + diff --git a/packages/cultnet-ts/contracts/cultnet.database-subscribe.schema.json b/packages/cultnet-ts/contracts/cultnet.database-subscribe.schema.json new file mode 100644 index 00000000..d4b65fcc --- /dev/null +++ b/packages/cultnet-ts/contracts/cultnet.database-subscribe.schema.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/GameCult/cultnet-ts/contracts/cultnet.database-subscribe.schema.json", + "title": "CultNet Database Subscribe Message", + "type": "object", + "required": ["schemaVersion", "messageId", "subscriptionId", "includeSnapshot"], + "additionalProperties": false, + "properties": { + "schemaVersion": { "const": "cultnet.database_subscribe.v0" }, + "messageId": { "type": "string", "minLength": 1 }, + "subscriptionId": { "type": "string", "minLength": 1 }, + "schemaIds": { "type": "array", "items": { "type": "string", "minLength": 1 } }, + "recordKeys": { "type": "array", "items": { "type": "string", "minLength": 1 } }, + "includeSnapshot": { "type": "boolean" }, + "consumerRuntimeId": { "type": "string", "minLength": 1 }, + "bodyIds": { "type": "array", "items": { "type": "string", "minLength": 1 } }, + "supportedBodyTransports": { "type": "array", "items": { "type": "string", "minLength": 1 } } + } +} + diff --git a/packages/cultnet-ts/contracts/cultnet.database-unsubscribe.schema.json b/packages/cultnet-ts/contracts/cultnet.database-unsubscribe.schema.json new file mode 100644 index 00000000..04be3799 --- /dev/null +++ b/packages/cultnet-ts/contracts/cultnet.database-unsubscribe.schema.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/GameCult/cultnet-ts/contracts/cultnet.database-unsubscribe.schema.json", + "title": "CultNet Database Unsubscribe Message", + "type": "object", + "required": ["schemaVersion", "messageId", "subscriptionId"], + "additionalProperties": false, + "properties": { + "schemaVersion": { "const": "cultnet.database_unsubscribe.v0" }, + "messageId": { "type": "string", "minLength": 1 }, + "subscriptionId": { "type": "string", "minLength": 1 } + } +} + diff --git a/packages/cultnet-ts/src/contracts.ts b/packages/cultnet-ts/src/contracts.ts index 8795b06a..56ece383 100644 --- a/packages/cultnet-ts/src/contracts.ts +++ b/packages/cultnet-ts/src/contracts.ts @@ -18,6 +18,9 @@ import transportProfileSchema from "../contracts/cultnet.transport-profile.schem import snapshotRequestSchema from "../contracts/cultnet.snapshot-request.schema.json"; import snapshotResponseSchema from "../contracts/cultnet.snapshot-response.schema.json"; import snapshotResponseRawSchema from "../contracts/cultnet.snapshot-response-raw.schema.json"; +import databaseSubscribeSchema from "../contracts/cultnet.database-subscribe.schema.json"; +import databaseUnsubscribeSchema from "../contracts/cultnet.database-unsubscribe.schema.json"; +import databaseChangeRawSchema from "../contracts/cultnet.database-change-raw.schema.json"; import schemaDescriptorSchema from "../contracts/cultnet.schema-descriptor.schema.json"; import schemaCatalogRequestSchema from "../contracts/cultnet.schema-catalog-request.schema.json"; import schemaCatalogResponseSchema from "../contracts/cultnet.schema-catalog-response.schema.json"; @@ -44,6 +47,9 @@ export type CultNetSchemaVersion = | "cultnet.snapshot_request.v0" | "cultnet.snapshot_response.v0" | "cultnet.snapshot_response_raw.v0" + | "cultnet.database_subscribe.v0" + | "cultnet.database_unsubscribe.v0" + | "cultnet.database_change_raw.v0" | "cultnet.schema_catalog_request.v0" | "cultnet.schema_catalog_response.v0" | "cultnet.shard_catalog_request.v0" @@ -217,6 +223,34 @@ export interface CultNetSnapshotResponseRawMessage { documents: CultNetRawDocumentRecord[]; } +export interface CultNetDatabaseSubscribeMessage { + schemaVersion: "cultnet.database_subscribe.v0"; + messageId: string; + subscriptionId: string; + schemaIds?: string[]; + recordKeys?: string[]; + includeSnapshot: boolean; + consumerRuntimeId?: string; + bodyIds?: string[]; + supportedBodyTransports?: string[]; +} + +export interface CultNetDatabaseUnsubscribeMessage { + schemaVersion: "cultnet.database_unsubscribe.v0"; + messageId: string; + subscriptionId: string; +} + +export interface CultNetDatabaseChangeRawMessage { + schemaVersion: "cultnet.database_change_raw.v0"; + messageId: string; + subscriptionId: string; + changeKind: "added" | "updated" | "removed"; + document?: CultNetRawDocumentRecord; + recordKey?: string; + schemaId?: string; +} + export interface CultNetSchemaDescriptor { schemaId: string; kind: CultNetSchemaKind; @@ -535,6 +569,9 @@ export type CultNetMessage = | CultNetSnapshotRequestMessage | CultNetSnapshotResponseMessage | CultNetSnapshotResponseRawMessage + | CultNetDatabaseSubscribeMessage + | CultNetDatabaseUnsubscribeMessage + | CultNetDatabaseChangeRawMessage | CultNetSchemaCatalogRequestMessage | CultNetSchemaCatalogResponseMessage | CultNetShardCatalogRequestMessage @@ -562,6 +599,9 @@ const CULTNET_MESSAGE_SCHEMAS = [ snapshotRequestSchema, snapshotResponseSchema, snapshotResponseRawSchema, + databaseSubscribeSchema, + databaseUnsubscribeSchema, + databaseChangeRawSchema, schemaCatalogRequestSchema, schemaCatalogResponseSchema, shardCatalogRequestSchema, @@ -620,6 +660,11 @@ export function parseCultNetMessage(input: unknown, wireContract: CultNetWireCon return input as CultNetSnapshotResponseRawMessage; } + if (schemaVersion === "cultnet.database_change_raw.v0") { + validateDatabaseChangeRawMessage(input); + return input as CultNetDatabaseChangeRawMessage; + } + if (!validator(input)) { const keys = Object.keys(input as Record).join(","); throw new Error(`${renderValidationErrors(schemaVersion, validator)}; keys=${keys}`); @@ -951,9 +996,39 @@ function validateSnapshotResponseRawMessage( }); } +function validateDatabaseChangeRawMessage( + input: unknown, +): asserts input is CultNetDatabaseChangeRawMessage { + const candidate = validateBinaryMessageRoot(input, "cultnet.database_change_raw.v0"); + requireNonEmptyString(candidate.subscriptionId, "/subscriptionId"); + if (candidate.changeKind !== "added" && + candidate.changeKind !== "updated" && + candidate.changeKind !== "removed") { + throw new Error( + "Validation failed for cultnet.database_change_raw.v0: /changeKind: must be added, updated, or removed", + ); + } + + if (candidate.changeKind === "removed") { + requireNonEmptyString(candidate.recordKey, "/recordKey"); + requireNonEmptyString(candidate.schemaId, "/schemaId"); + return; + } + + if (!("document" in candidate)) { + throw new Error( + "Validation failed for cultnet.database_change_raw.v0: /document: is required for added or updated changes", + ); + } + validateRawDocumentRecord(candidate.document, "/document"); +} + function validateBinaryMessageRoot( input: unknown, - schemaVersion: "cultnet.document_put_raw.v0" | "cultnet.snapshot_response_raw.v0", + schemaVersion: + | "cultnet.document_put_raw.v0" + | "cultnet.snapshot_response_raw.v0" + | "cultnet.database_change_raw.v0", ): Record { if (!input || typeof input !== "object") { throw new Error(`Validation failed for ${schemaVersion}: /: must be an object`); @@ -1043,6 +1118,15 @@ function normalizeCultNetOptionalNulls( acceptLegacyPropertyName(candidate, "ShardEpoch", "shardEpoch"); stripNullProperties(candidate, ["schemaIds", "recordKeys", "shardId", "shardEpoch"]); return; + case "cultnet.database_subscribe.v0": + stripNullProperties(candidate, [ + "schemaIds", + "recordKeys", + "consumerRuntimeId", + "bodyIds", + "supportedBodyTransports", + ]); + return; case "cultnet.schema_catalog_request.v0": stripNullProperties(candidate, ["schemaIds", "kinds"]); return; @@ -1092,6 +1176,9 @@ export const cultNetSchemas = { snapshotRequestSchema, snapshotResponseSchema, snapshotResponseRawSchema, + databaseSubscribeSchema, + databaseUnsubscribeSchema, + databaseChangeRawSchema, schemaDescriptorSchema, schemaCatalogRequestSchema, schemaCatalogResponseSchema, diff --git a/packages/cultnet-ts/src/index.ts b/packages/cultnet-ts/src/index.ts index cd602952..64d9c2fd 100644 --- a/packages/cultnet-ts/src/index.ts +++ b/packages/cultnet-ts/src/index.ts @@ -8,6 +8,9 @@ export { type CultNetDocumentPutMessage, type CultNetDocumentPutRawMessage, type CultNetDocumentRecord, + type CultNetDatabaseSubscribeMessage, + type CultNetDatabaseUnsubscribeMessage, + type CultNetDatabaseChangeRawMessage, type CultNetRawDocumentRecord, type CultNetRawPayloadEncoding, type CultNetErrorMessage, diff --git a/packages/cultnet-ts/test/cultnet.test.ts b/packages/cultnet-ts/test/cultnet.test.ts index 46e7cb6f..1a2ba805 100644 --- a/packages/cultnet-ts/test/cultnet.test.ts +++ b/packages/cultnet-ts/test/cultnet.test.ts @@ -1261,6 +1261,64 @@ test("operation envelopes preserve typed service routing and payload correlation assert.equal(response.messageId, request.messageId); }); +test("database subscription contracts match the C# live document lane", () => { + const subscribe = parseCultNetMessage({ + schemaVersion: "cultnet.database_subscribe.v0", + messageId: "subscribe-counter", + subscriptionId: "counter:browser-1", + schemaIds: ["sample.counter_state.v1"], + recordKeys: ["counter:main"], + includeSnapshot: true, + consumerRuntimeId: "browser-1", + }); + assert.equal(subscribe.schemaVersion, "cultnet.database_subscribe.v0"); + assert.equal(subscribe.subscriptionId, "counter:browser-1"); + + const added = parseCultNetMessage({ + schemaVersion: "cultnet.database_change_raw.v0", + messageId: "change-counter-1", + subscriptionId: "counter:browser-1", + changeKind: "added", + document: { + schemaId: "sample.counter_state.v1", + recordKey: "counter:main", + storedAt: "2026-08-17T00:00:00Z", + payloadEncoding: "messagepack", + payload: new Uint8Array([0x81, 0xa5, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x01]), + }, + }); + assert.equal(added.schemaVersion, "cultnet.database_change_raw.v0"); + assert.equal(added.document?.recordKey, "counter:main"); + + const removed = parseCultNetMessage({ + schemaVersion: "cultnet.database_change_raw.v0", + messageId: "change-counter-2", + subscriptionId: "counter:browser-1", + changeKind: "removed", + recordKey: "counter:main", + schemaId: "sample.counter_state.v1", + }); + assert.equal(removed.schemaVersion, "cultnet.database_change_raw.v0"); + assert.equal(removed.recordKey, "counter:main"); + + const unsubscribe = parseCultNetMessage({ + schemaVersion: "cultnet.database_unsubscribe.v0", + messageId: "unsubscribe-counter", + subscriptionId: "counter:browser-1", + }); + assert.equal(unsubscribe.schemaVersion, "cultnet.database_unsubscribe.v0"); + + assert.throws( + () => parseCultNetMessage({ + schemaVersion: "cultnet.database_change_raw.v0", + messageId: "invalid-change", + subscriptionId: "counter:browser-1", + changeKind: "updated", + }), + /document: is required/, + ); +}); + test("RUDP operation service correlates typed payload envelopes", async () => { const server = await startCultNetOperationServer({ runtimeId: "sai-sidecar", diff --git a/src/GameCult.Mesh/docs/browser-verse-transport.md b/src/GameCult.Mesh/docs/browser-verse-transport.md new file mode 100644 index 00000000..c8586021 --- /dev/null +++ b/src/GameCult.Mesh/docs/browser-verse-transport.md @@ -0,0 +1,156 @@ +# Browser Verse Transport Boundary + +Date: 2026-08-17 + +## Status + +This is the implementation map for the missing real-browser checkpoint. The +current `samples/eve-two-runtime` proof uses jsdom and one local TypeScript +CultMesh node. It is a clean package-consumer and contract-validation proof, +not browser networking. + +The current substrate is incomplete: + +- `cultmesh-ts` is a Node package and imports `node:dgram` at its root; +- `cultnet-ts` mixes browser-safe schema contracts with Node transport, + filesystem, crypto, stream, and UDP modules; +- C# and TypeScript now share `cultnet.database_subscribe.v0`, + `cultnet.database_unsubscribe.v0`, and `cultnet.database_change_raw.v0`; + the browser-safe transport package that consumes them does not exist yet; +- Kotlin has a channel-aware WebSocket transport adapter; C# and TypeScript do + not expose the equivalent browser/server pair; +- Hermodr can lower Odin state into a browser, but it is an infrastructure + runtime, not the missing clean-consumer game API. + +## Authority Map + +Owner: + +- CultNet owns binary WebSocket framing and schema-v0 message validation. +- CultMesh owns stable Verse/provider identity, document leases, + subscriptions, route replacement, and command/receipt correlation. +- Odin owns discovery of the current `wss://` candidate for a stable Verse and + provider identity. +- The provider daemon owns application state, operations, receipts, and the Eve + surface. +- Eve owns surface and command contracts; the browser lowerer owns DOM only. + +Inputs: + +- an Odin-discovered WebSocket transport candidate; +- stable Verse and provider identities; +- authenticated session evidence; +- requested schema ids and record keys; +- typed operation invocations and idempotency keys; +- canonical CultNet schema-v0 MessagePack messages. + +Outputs: + +- leased typed document snapshots and live changes; +- typed operation receipts; +- explicit connection/session diagnostics; +- deterministic unsubscribe and disposal; +- route replacement without changing provider or document identity. + +Derived state: + +- browser caches, DOM trees, loading/error presentation, and optimistic visual + affordances are projections only; +- a socket URL is a disposable discovery candidate, never provider identity; +- reconnect status is observable session state, not application truth. + +Forbidden writers: + +- browser lowerers cannot mutate provider documents directly; +- Hermodr, service workers, renderer caches, and app-specific HTTP endpoints + cannot become alternate gameplay authorities; +- no JSON polling API may mirror the database as a second state system; +- `node:dgram`, Node streams, filesystem stores, and Node crypto cannot enter a + browser bundle; +- a late socket, stale subscription generation, or reconnect replay cannot + overwrite a newer session; +- application code cannot own reconnect sleeps, endpoint ranking, or + resubscription loops. + +Shared paths: + +- initial load, live update, reconnect, tab background/resume, command retry, + and provider route rotation all use one CultMesh document-lease/session path; +- browser, Unity, headless C#, and future native clients consume the same + provider-owned documents and receipts; +- every command crosses the same typed operation boundary regardless of which + Eve lowerer emitted it. + +Deletion line: + +- stop calling jsdom a browser runtime; +- split browser-safe CultNet contracts from the Node transport package; +- add the missing subscription messages to the shared generated contract + catalog instead of retyping them in a browser adapter; +- do not retain a sample-only WebSocket protocol after the canonical adapter + exists. + +## Required Runtime Shape + +The browser-facing package must be importable by a standards-mode browser or a +normal bundler without Node polyfills. It exposes a narrow API shaped like: + +```ts +const mesh = await CultMeshBrowser.connect({ + rendezvous: odin, + verseId: "sample.counter", + providerId: "sample.counter-provider", +}); + +using surface = await mesh.leaseDocument(eveSurface, "eve:surface:counter"); +surface.watch(render); + +const receipt = await mesh.invoke(incrementCounter, {}, { + idempotencyKey: crypto.randomUUID(), +}); +``` + +The names are illustrative. The ownership is not: application code supplies +identity and intent; CultMesh owns route/session continuity; the provider owns +the result. + +## Wire Contract + +WebSocket carries binary MessagePack CultNet schema-v0 messages. The first +implementation must support: + +- `cultnet.hello.v0`; +- authentication/session verification; +- `cultnet.snapshot_request.v0` and + `cultnet.snapshot_response_raw.v0`; +- `cultnet.database_subscribe.v0`, + `cultnet.database_unsubscribe.v0`, and + `cultnet.database_change_raw.v0`; +- `cultnet.operation_request.v0` and + `cultnet.operation_response.v0`; +- `cultnet.error.v0`. + +The WebSocket frame is a transport body, not a second message schema. Payload +size, queue depth, subscription count, and command rate are bounded. Schema, +identity, authority, and idempotency validation happen before provider code. + +## Acceptance Gate + +From an empty temporary consumer using packed/released artifacts only: + +1. start a provider daemon with one durable counter document and one validated + Eve surface; +2. advertise it by stable identity through a local Odin fixture or real Odin; +3. connect one real Chromium page and one C# headless client; +4. lease the same surface and counter document in both runtimes; +5. click the browser button and require one provider-authored canonical receipt; +6. observe the same state version and receipt id in both clients; +7. disconnect or rotate the physical WebSocket endpoint, then require both + leases to resume without application reconnect code; +8. restart the provider and prove state plus receipt persistence; +9. reject malformed schemas, direct document writes, duplicate command + effects, stale subscription generations, and unsupported authority; +10. inspect the browser bundle and fail if it contains Node builtin imports. + +The gate runs on Windows and Linux. A screenshot is useful presentation +evidence, but the receipt/state chronology is the authority proof. diff --git a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md index d28ef621..d16f21c1 100644 --- a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md +++ b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md @@ -65,5 +65,7 @@ This checkpoint proves clean package consumption, canonical Eve contract validation, and two independent lowering/observation consumers inside Node. It does **not** claim a real browser process, an Odin-discovered network hop, or cross-language command execution. Those are the next public Verse conformance -gates; do not cite this sample as evidence that they exist. +gates; do not cite this sample as evidence that they exist. Their owner map and +executable acceptance contract are recorded in +[`browser-verse-transport.md`](../browser-verse-transport.md). diff --git a/src/GameCult.Networking/Contracts/cultnet.database-change-raw.schema.json b/src/GameCult.Networking/Contracts/cultnet.database-change-raw.schema.json new file mode 100644 index 00000000..9bedb72a --- /dev/null +++ b/src/GameCult.Networking/Contracts/cultnet.database-change-raw.schema.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/GameCult/cultnet-ts/contracts/cultnet.database-change-raw.schema.json", + "title": "CultNet Raw Database Change Message", + "type": "object", + "required": ["schemaVersion", "messageId", "subscriptionId", "changeKind"], + "additionalProperties": false, + "properties": { + "schemaVersion": { "const": "cultnet.database_change_raw.v0" }, + "messageId": { "type": "string", "minLength": 1 }, + "subscriptionId": { "type": "string", "minLength": 1 }, + "changeKind": { "enum": ["added", "updated", "removed"] }, + "document": { "$ref": "./cultnet.raw-document-record.schema.json" }, + "recordKey": { "type": "string", "minLength": 1 }, + "schemaId": { "type": "string", "minLength": 1 } + }, + "allOf": [ + { + "if": { "properties": { "changeKind": { "const": "removed" } } }, + "then": { "required": ["recordKey", "schemaId"] }, + "else": { "required": ["document"] } + } + ] +} + diff --git a/src/GameCult.Networking/Contracts/cultnet.database-subscribe.schema.json b/src/GameCult.Networking/Contracts/cultnet.database-subscribe.schema.json new file mode 100644 index 00000000..d4b65fcc --- /dev/null +++ b/src/GameCult.Networking/Contracts/cultnet.database-subscribe.schema.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/GameCult/cultnet-ts/contracts/cultnet.database-subscribe.schema.json", + "title": "CultNet Database Subscribe Message", + "type": "object", + "required": ["schemaVersion", "messageId", "subscriptionId", "includeSnapshot"], + "additionalProperties": false, + "properties": { + "schemaVersion": { "const": "cultnet.database_subscribe.v0" }, + "messageId": { "type": "string", "minLength": 1 }, + "subscriptionId": { "type": "string", "minLength": 1 }, + "schemaIds": { "type": "array", "items": { "type": "string", "minLength": 1 } }, + "recordKeys": { "type": "array", "items": { "type": "string", "minLength": 1 } }, + "includeSnapshot": { "type": "boolean" }, + "consumerRuntimeId": { "type": "string", "minLength": 1 }, + "bodyIds": { "type": "array", "items": { "type": "string", "minLength": 1 } }, + "supportedBodyTransports": { "type": "array", "items": { "type": "string", "minLength": 1 } } + } +} + diff --git a/src/GameCult.Networking/Contracts/cultnet.database-unsubscribe.schema.json b/src/GameCult.Networking/Contracts/cultnet.database-unsubscribe.schema.json new file mode 100644 index 00000000..04be3799 --- /dev/null +++ b/src/GameCult.Networking/Contracts/cultnet.database-unsubscribe.schema.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/GameCult/cultnet-ts/contracts/cultnet.database-unsubscribe.schema.json", + "title": "CultNet Database Unsubscribe Message", + "type": "object", + "required": ["schemaVersion", "messageId", "subscriptionId"], + "additionalProperties": false, + "properties": { + "schemaVersion": { "const": "cultnet.database_unsubscribe.v0" }, + "messageId": { "type": "string", "minLength": 1 }, + "subscriptionId": { "type": "string", "minLength": 1 } + } +} + diff --git a/src/GameCult.Networking/CultNetSchemaRegistry.cs b/src/GameCult.Networking/CultNetSchemaRegistry.cs index 037c0d84..4fc68a13 100644 --- a/src/GameCult.Networking/CultNetSchemaRegistry.cs +++ b/src/GameCult.Networking/CultNetSchemaRegistry.cs @@ -370,6 +370,27 @@ namespace GameCult.Networking WireContracts = new[] { CultNetWireContracts.SchemaV0 } }, new SchemaResourceSpec + { + FileName = "cultnet.database-subscribe.schema.json", + Kind = "wire_message", + SchemaVersion = CultNetSchemaVersions.DatabaseSubscribe, + WireContracts = new[] { CultNetWireContracts.SchemaV0 } + }, + new SchemaResourceSpec + { + FileName = "cultnet.database-unsubscribe.schema.json", + Kind = "wire_message", + SchemaVersion = CultNetSchemaVersions.DatabaseUnsubscribe, + WireContracts = new[] { CultNetWireContracts.SchemaV0 } + }, + new SchemaResourceSpec + { + FileName = "cultnet.database-change-raw.schema.json", + Kind = "wire_message", + SchemaVersion = CultNetSchemaVersions.DatabaseChangeRaw, + WireContracts = new[] { CultNetWireContracts.SchemaV0 } + }, + new SchemaResourceSpec { FileName = "cultnet.schema-descriptor.schema.json", Kind = "shared_contract", diff --git a/tests/GameCult.Networking.Tests/NetworkingTests.cs b/tests/GameCult.Networking.Tests/NetworkingTests.cs index 9b1af662..44437cc3 100644 --- a/tests/GameCult.Networking.Tests/NetworkingTests.cs +++ b/tests/GameCult.Networking.Tests/NetworkingTests.cs @@ -5282,6 +5282,12 @@ namespace GameCult.Networking.Tests schema => schema.SchemaVersion == CultNetSchemaVersions.DocumentPutRaw); var rawSnapshot = Array.Find(response.Schemas, schema => schema.SchemaVersion == CultNetSchemaVersions.SnapshotResponseRaw); + var subscribe = Array.Find(response.Schemas, + schema => schema.SchemaVersion == CultNetSchemaVersions.DatabaseSubscribe); + var unsubscribe = Array.Find(response.Schemas, + schema => schema.SchemaVersion == CultNetSchemaVersions.DatabaseUnsubscribe); + var change = Array.Find(response.Schemas, + schema => schema.SchemaVersion == CultNetSchemaVersions.DatabaseChangeRaw); var ghostlight = Array.Find(response.Schemas, schema => schema.SchemaVersion == "ghostlight.agent_state.v0"); var transportProfile = Array.Find(response.Schemas, @@ -5295,6 +5301,13 @@ namespace GameCult.Networking.Tests Assert.That(rawSnapshot, Is.Not.Null); Assert.That(rawSnapshot!.SchemaJson, Does.Contain("cultnet.snapshot_response_raw.v0")); + Assert.That(subscribe, Is.Not.Null); + Assert.That(subscribe!.SchemaJson, Does.Contain("cultnet.database_subscribe.v0")); + Assert.That(unsubscribe, Is.Not.Null); + Assert.That(unsubscribe!.SchemaJson, Does.Contain("cultnet.database_unsubscribe.v0")); + Assert.That(change, Is.Not.Null); + Assert.That(change!.SchemaJson, Does.Contain("cultnet.database_change_raw.v0")); + Assert.That(ghostlight, Is.Not.Null); Assert.That(ghostlight!.DocumentType, Is.EqualTo("ghostlight.agent-state")); Assert.That(ghostlight.Kind, Is.EqualTo("document_payload")); From 4af73983722f89c25773012dad71539b1bd8bc1b Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 17 Aug 2026 23:27:07 +0200 Subject: [PATCH 064/283] Normalize CultNet schema files --- .../cultnet-ts/contracts/cultnet.database-change-raw.schema.json | 1 - .../cultnet-ts/contracts/cultnet.database-subscribe.schema.json | 1 - .../contracts/cultnet.database-unsubscribe.schema.json | 1 - .../Contracts/cultnet.database-change-raw.schema.json | 1 - .../Contracts/cultnet.database-subscribe.schema.json | 1 - .../Contracts/cultnet.database-unsubscribe.schema.json | 1 - 6 files changed, 6 deletions(-) diff --git a/packages/cultnet-ts/contracts/cultnet.database-change-raw.schema.json b/packages/cultnet-ts/contracts/cultnet.database-change-raw.schema.json index 9bedb72a..dd650fa0 100644 --- a/packages/cultnet-ts/contracts/cultnet.database-change-raw.schema.json +++ b/packages/cultnet-ts/contracts/cultnet.database-change-raw.schema.json @@ -22,4 +22,3 @@ } ] } - diff --git a/packages/cultnet-ts/contracts/cultnet.database-subscribe.schema.json b/packages/cultnet-ts/contracts/cultnet.database-subscribe.schema.json index d4b65fcc..08304199 100644 --- a/packages/cultnet-ts/contracts/cultnet.database-subscribe.schema.json +++ b/packages/cultnet-ts/contracts/cultnet.database-subscribe.schema.json @@ -17,4 +17,3 @@ "supportedBodyTransports": { "type": "array", "items": { "type": "string", "minLength": 1 } } } } - diff --git a/packages/cultnet-ts/contracts/cultnet.database-unsubscribe.schema.json b/packages/cultnet-ts/contracts/cultnet.database-unsubscribe.schema.json index 04be3799..7d4b0855 100644 --- a/packages/cultnet-ts/contracts/cultnet.database-unsubscribe.schema.json +++ b/packages/cultnet-ts/contracts/cultnet.database-unsubscribe.schema.json @@ -11,4 +11,3 @@ "subscriptionId": { "type": "string", "minLength": 1 } } } - diff --git a/src/GameCult.Networking/Contracts/cultnet.database-change-raw.schema.json b/src/GameCult.Networking/Contracts/cultnet.database-change-raw.schema.json index 9bedb72a..dd650fa0 100644 --- a/src/GameCult.Networking/Contracts/cultnet.database-change-raw.schema.json +++ b/src/GameCult.Networking/Contracts/cultnet.database-change-raw.schema.json @@ -22,4 +22,3 @@ } ] } - diff --git a/src/GameCult.Networking/Contracts/cultnet.database-subscribe.schema.json b/src/GameCult.Networking/Contracts/cultnet.database-subscribe.schema.json index d4b65fcc..08304199 100644 --- a/src/GameCult.Networking/Contracts/cultnet.database-subscribe.schema.json +++ b/src/GameCult.Networking/Contracts/cultnet.database-subscribe.schema.json @@ -17,4 +17,3 @@ "supportedBodyTransports": { "type": "array", "items": { "type": "string", "minLength": 1 } } } } - diff --git a/src/GameCult.Networking/Contracts/cultnet.database-unsubscribe.schema.json b/src/GameCult.Networking/Contracts/cultnet.database-unsubscribe.schema.json index 04be3799..7d4b0855 100644 --- a/src/GameCult.Networking/Contracts/cultnet.database-unsubscribe.schema.json +++ b/src/GameCult.Networking/Contracts/cultnet.database-unsubscribe.schema.json @@ -11,4 +11,3 @@ "subscriptionId": { "type": "string", "minLength": 1 } } } - From 8eb89e38ec6340a17cd82da9534aa909690a1606 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 00:05:57 +0200 Subject: [PATCH 065/283] Add real browser CultMesh transport proof --- CultLib.sln | 47 ++ README.md | 17 +- package-lock.json | 539 ++++++++++++++++- package.json | 12 +- packages/cultmesh-browser/README.md | 40 ++ packages/cultmesh-browser/package.json | 50 ++ packages/cultmesh-browser/src/index.ts | 545 ++++++++++++++++++ .../test/cultmesh-browser.test.ts | 304 ++++++++++ packages/cultmesh-browser/tsconfig.json | 16 + packages/cultmesh-browser/tsconfig.test.json | 12 + packages/cultnet-ts/package.json | 5 + packages/cultnet-ts/src/contracts.ts | 21 +- packages/cultnet-ts/test/cultnet.test.ts | 24 +- .../EveBrowserNetworkSample.csproj | 10 + samples/eve-browser-network/Program.cs | 319 ++++++++++ samples/eve-browser-network/README.md | 22 + .../eve-browser-network/browser/index.html | 13 + samples/eve-browser-network/browser/main.ts | 84 +++ scripts/run-typescript-workspaces.mjs | 2 +- scripts/test-typescript-package-closure.mjs | 44 +- scripts/verify-eve-browser-network.mjs | 198 +++++++ .../docs/browser-verse-transport.md | 80 ++- .../03-publish-an-eve-surface.md | 14 +- .../CultNetWebSocketSchemaClient.cs | 166 ++++++ .../CultNetWebSocketSchemaServer.cs | 260 +++++++++ .../GameCult.Networking.WebSockets.csproj | 12 + src/GameCult.Networking/README.md | 15 + .../CultNetWebSocketSchemaServerTests.cs | 95 +++ ...ameCult.Networking.WebSockets.Tests.csproj | 17 + 29 files changed, 2936 insertions(+), 47 deletions(-) create mode 100644 packages/cultmesh-browser/README.md create mode 100644 packages/cultmesh-browser/package.json create mode 100644 packages/cultmesh-browser/src/index.ts create mode 100644 packages/cultmesh-browser/test/cultmesh-browser.test.ts create mode 100644 packages/cultmesh-browser/tsconfig.json create mode 100644 packages/cultmesh-browser/tsconfig.test.json create mode 100644 samples/eve-browser-network/EveBrowserNetworkSample.csproj create mode 100644 samples/eve-browser-network/Program.cs create mode 100644 samples/eve-browser-network/README.md create mode 100644 samples/eve-browser-network/browser/index.html create mode 100644 samples/eve-browser-network/browser/main.ts create mode 100644 scripts/verify-eve-browser-network.mjs create mode 100644 src/GameCult.Networking.WebSockets/CultNetWebSocketSchemaClient.cs create mode 100644 src/GameCult.Networking.WebSockets/CultNetWebSocketSchemaServer.cs create mode 100644 src/GameCult.Networking.WebSockets/GameCult.Networking.WebSockets.csproj create mode 100644 tests/GameCult.Networking.WebSockets.Tests/CultNetWebSocketSchemaServerTests.cs create mode 100644 tests/GameCult.Networking.WebSockets.Tests/GameCult.Networking.WebSockets.Tests.csproj diff --git a/CultLib.sln b/CultLib.sln index 7bd7ae93..c40b6b41 100644 --- a/CultLib.sln +++ b/CultLib.sln @@ -35,6 +35,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCult.Mesh.Quic", "src\G EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCult.Mesh.Quic.Tests", "tests\GameCult.Mesh.Quic.Tests\GameCult.Mesh.Quic.Tests.csproj", "{21F26329-2119-4037-93CC-DD1801A1AB78}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCult.Networking.WebSockets", "src\GameCult.Networking.WebSockets\GameCult.Networking.WebSockets.csproj", "{7F32D96B-AB5D-4A72-9217-B5DCCFEFC7E5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCult.Networking.WebSockets.Tests", "tests\GameCult.Networking.WebSockets.Tests\GameCult.Networking.WebSockets.Tests.csproj", "{B9A441EC-DADE-4500-B092-C635F3EB296A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{5D20AA90-6969-D8BD-9DCD-8634F4692FDA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EveBrowserNetworkSample", "samples\eve-browser-network\EveBrowserNetworkSample.csproj", "{5FA81CC7-87B2-4585-9D8E-9BBEC0AD85FB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -213,6 +221,42 @@ Global {21F26329-2119-4037-93CC-DD1801A1AB78}.Release|x64.Build.0 = Release|Any CPU {21F26329-2119-4037-93CC-DD1801A1AB78}.Release|x86.ActiveCfg = Release|Any CPU {21F26329-2119-4037-93CC-DD1801A1AB78}.Release|x86.Build.0 = Release|Any CPU + {7F32D96B-AB5D-4A72-9217-B5DCCFEFC7E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7F32D96B-AB5D-4A72-9217-B5DCCFEFC7E5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7F32D96B-AB5D-4A72-9217-B5DCCFEFC7E5}.Debug|x64.ActiveCfg = Debug|Any CPU + {7F32D96B-AB5D-4A72-9217-B5DCCFEFC7E5}.Debug|x64.Build.0 = Debug|Any CPU + {7F32D96B-AB5D-4A72-9217-B5DCCFEFC7E5}.Debug|x86.ActiveCfg = Debug|Any CPU + {7F32D96B-AB5D-4A72-9217-B5DCCFEFC7E5}.Debug|x86.Build.0 = Debug|Any CPU + {7F32D96B-AB5D-4A72-9217-B5DCCFEFC7E5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7F32D96B-AB5D-4A72-9217-B5DCCFEFC7E5}.Release|Any CPU.Build.0 = Release|Any CPU + {7F32D96B-AB5D-4A72-9217-B5DCCFEFC7E5}.Release|x64.ActiveCfg = Release|Any CPU + {7F32D96B-AB5D-4A72-9217-B5DCCFEFC7E5}.Release|x64.Build.0 = Release|Any CPU + {7F32D96B-AB5D-4A72-9217-B5DCCFEFC7E5}.Release|x86.ActiveCfg = Release|Any CPU + {7F32D96B-AB5D-4A72-9217-B5DCCFEFC7E5}.Release|x86.Build.0 = Release|Any CPU + {B9A441EC-DADE-4500-B092-C635F3EB296A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B9A441EC-DADE-4500-B092-C635F3EB296A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B9A441EC-DADE-4500-B092-C635F3EB296A}.Debug|x64.ActiveCfg = Debug|Any CPU + {B9A441EC-DADE-4500-B092-C635F3EB296A}.Debug|x64.Build.0 = Debug|Any CPU + {B9A441EC-DADE-4500-B092-C635F3EB296A}.Debug|x86.ActiveCfg = Debug|Any CPU + {B9A441EC-DADE-4500-B092-C635F3EB296A}.Debug|x86.Build.0 = Debug|Any CPU + {B9A441EC-DADE-4500-B092-C635F3EB296A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B9A441EC-DADE-4500-B092-C635F3EB296A}.Release|Any CPU.Build.0 = Release|Any CPU + {B9A441EC-DADE-4500-B092-C635F3EB296A}.Release|x64.ActiveCfg = Release|Any CPU + {B9A441EC-DADE-4500-B092-C635F3EB296A}.Release|x64.Build.0 = Release|Any CPU + {B9A441EC-DADE-4500-B092-C635F3EB296A}.Release|x86.ActiveCfg = Release|Any CPU + {B9A441EC-DADE-4500-B092-C635F3EB296A}.Release|x86.Build.0 = Release|Any CPU + {5FA81CC7-87B2-4585-9D8E-9BBEC0AD85FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5FA81CC7-87B2-4585-9D8E-9BBEC0AD85FB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5FA81CC7-87B2-4585-9D8E-9BBEC0AD85FB}.Debug|x64.ActiveCfg = Debug|Any CPU + {5FA81CC7-87B2-4585-9D8E-9BBEC0AD85FB}.Debug|x64.Build.0 = Debug|Any CPU + {5FA81CC7-87B2-4585-9D8E-9BBEC0AD85FB}.Debug|x86.ActiveCfg = Debug|Any CPU + {5FA81CC7-87B2-4585-9D8E-9BBEC0AD85FB}.Debug|x86.Build.0 = Debug|Any CPU + {5FA81CC7-87B2-4585-9D8E-9BBEC0AD85FB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5FA81CC7-87B2-4585-9D8E-9BBEC0AD85FB}.Release|Any CPU.Build.0 = Release|Any CPU + {5FA81CC7-87B2-4585-9D8E-9BBEC0AD85FB}.Release|x64.ActiveCfg = Release|Any CPU + {5FA81CC7-87B2-4585-9D8E-9BBEC0AD85FB}.Release|x64.Build.0 = Release|Any CPU + {5FA81CC7-87B2-4585-9D8E-9BBEC0AD85FB}.Release|x86.ActiveCfg = Release|Any CPU + {5FA81CC7-87B2-4585-9D8E-9BBEC0AD85FB}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -232,5 +276,8 @@ Global {F8A5060A-FB0B-4B8B-AE06-5147BB4CA127} = {39D316AB-ABB5-49A2-8E83-CAF4C75B48F4} {B67042B8-1135-4E54-B1EB-D45342C720D7} = {E733CBFF-42AE-4B6A-B5B9-0071ECFB45F1} {21F26329-2119-4037-93CC-DD1801A1AB78} = {39D316AB-ABB5-49A2-8E83-CAF4C75B48F4} + {7F32D96B-AB5D-4A72-9217-B5DCCFEFC7E5} = {E733CBFF-42AE-4B6A-B5B9-0071ECFB45F1} + {B9A441EC-DADE-4500-B092-C635F3EB296A} = {39D316AB-ABB5-49A2-8E83-CAF4C75B48F4} + {5FA81CC7-87B2-4585-9D8E-9BBEC0AD85FB} = {5D20AA90-6969-D8BD-9DCD-8634F4692FDA} EndGlobalSection EndGlobal diff --git a/README.md b/README.md index aee7644d..6df5d940 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,9 @@ The stack is less a single product than a set of capabilities: - logging primitives and implementations - CultCache typed documents, `.cc` persistence, and SoA memory access -- CultNet schema-v0 messages over TCP, WebSocket, LiteNetLib adapters, and - CultLib's native cross-runtime RUDP pipe +- CultNet schema-v0 messages over TCP and LiteNetLib adapters, a bounded + ASP.NET Core WebSocket host adapter, and CultLib's native cross-runtime RUDP + pipe - CultMesh distributed realtime database, Verse discovery, authority leases, shard replication, and witness-authoritative simulation consensus - typed geometry domain/chunk documents for distributed CSG and LOD streaming @@ -38,7 +39,7 @@ and pretending the label makes it furniture. | --- | --- | --- | --- | --- | | 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 | Native RUDP sessions, LiteNetLib/TCP/WebSocket adapters, authentication, schema-v0 wire contracts, shard authority, raw document replication, snapshots, and subscriptions | You need a client/server pipe, login/session flow, schema discovery, reliable UDP, or a low-level distributed CultCache lane | Gameplay-facing mesh ergonomics, Verse policy, mod branches, or simulation consensus composition | +| Network transport and database plumbing | `GameCult.Networking` / CultNet | Native RUDP sessions, LiteNetLib/TCP adapters, an authenticated WebSocket host adapter, schema-v0 wire contracts, shard authority, raw document replication, snapshots, and subscriptions | You need a client/server pipe, login/session flow, schema discovery, reliable UDP, 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 | | Realtime media/frame streams | `GameCult.Mesh` / CultMesh streaming mode | Stream identity, authority, clock metadata, body transport negotiation, frame cursors, and backpressure state | Audio/video/tensor frames need to move between runtimes through shared memory, GPU handles, platform buffers, or CultCache page refs | Durable document mutation, mesh consensus facts, or pretending inline bytes are zero-copy | | Daemon-published UI | Eve / CultUI | Typed operator and user-facing surfaces over CultMesh state | A daemon should expose controls, inspection, or workflow UI that can lower into GUI, TUI, web, native, overlay, or agent clients | One-off vendor dashboards, untyped debug panels, or runtime-local UI that cannot travel with the daemon | @@ -67,7 +68,10 @@ start with the maintained [`CultMesh And Eve Getting Started`](src/GameCult.Mesh/docs/getting-started/README.md) series. Its first executable package-consumer checkpoint is [`samples/eve-two-runtime`](samples/eve-two-runtime/README.md). -The missing real-browser/network boundary is mapped explicitly in +The real-process browser continuation is +[`samples/eve-browser-network`](samples/eve-browser-network/README.md). +The implemented browser client boundary and remaining real-network gate are +mapped explicitly in [`browser-verse-transport.md`](src/GameCult.Mesh/docs/browser-verse-transport.md). If you want only the smallest durable "open node -> put typed doc -> get typed doc" @@ -89,6 +93,7 @@ The solution includes: - `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, schema-v0 contracts, transport adapters, and native RUDP sessions +- `GameCult.Networking.WebSockets`: bounded ASP.NET Core binary WebSocket host adapter for browser CultMesh clients - `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 - `GameCult.Networking.Tests`: NUnit tests for networking behavior @@ -96,6 +101,7 @@ The solution includes: - `packages/cultcache-ts`: TypeScript CultCache with MessagePack persistence and inspector tooling - `packages/cultnet-ts`: TypeScript CultNet schema-v0 contracts, framing, discovery, raw document replication, and interop tests - `packages/cultmesh-ts`: TypeScript CultMesh local node and mesh catalog surface for local runtimes such as VoidBot +- `packages/cultmesh-browser`: browser-safe, read-only CultMesh document leases and typed operations over an Odin-resolved WebSocket route - `packages/cultcache-py`: Python CultCache/CultNet/CultMesh package with CultCache v1 wire parity - `packages/cultcache-rs`: Rust CultCache and derive macro - `packages/cultnet-rs`: Rust CultNet contracts, framing, discovery, and interop peer @@ -114,6 +120,7 @@ src/ GameCult.Caching.MessagePack.Analyzers/ GameCult.Geometry/ GameCult.Networking/ + GameCult.Networking.WebSockets/ GameCult.Mesh/ GameCult.Unity/ tests/ @@ -124,6 +131,7 @@ packages/ cultcache-ts/ cultnet-ts/ cultmesh-ts/ + cultmesh-browser/ cultmesh-kotlin/ cultcache-py/ cultcache-rs/ @@ -149,6 +157,7 @@ npm test --workspace packages/cultcache-ts npm test --workspace packages/cultnet-ts npm run test:interop --workspace packages/cultnet-ts npm test --workspace packages/cultmesh-ts +npm test --workspace packages/cultmesh-browser ``` Rust package tests: diff --git a/package-lock.json b/package-lock.json index bc42f617..0b8aae8b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,8 +8,15 @@ "workspaces": [ "packages/cultcache-ts", "packages/cultnet-ts", - "packages/cultmesh-ts" - ] + "packages/cultmesh-ts", + "packages/cultmesh-browser" + ], + "devDependencies": { + "esbuild": "^0.28.1", + "fast-uri": "3.1.5", + "js-yaml": "4.3.1", + "playwright-core": "^1.62.1" + } }, "node_modules/@apidevtools/json-schema-ref-parser": { "version": "11.9.3", @@ -29,6 +36,448 @@ "url": "https://github.com/sponsors/philsturgeon" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@jsdevtools/ono": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", @@ -96,6 +545,10 @@ "resolved": "packages/cultcache-ts", "link": true }, + "node_modules/cultmesh-browser": { + "resolved": "packages/cultmesh-browser", + "link": true + }, "node_modules/cultmesh-ts": { "resolved": "packages/cultmesh-ts", "link": true @@ -104,6 +557,48 @@ "resolved": "packages/cultnet-ts", "link": true }, + "node_modules/esbuild": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -111,9 +606,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.3.tgz", - "integrity": "sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", + "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", "funding": [ { "type": "github", @@ -168,9 +663,9 @@ } }, "node_modules/js-yaml": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", - "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", + "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", "dev": true, "funding": [ { @@ -250,6 +745,19 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/playwright-core": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.62.1.tgz", + "integrity": "sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/prettier": { "version": "3.9.5", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.5.tgz", @@ -337,6 +845,21 @@ "node": ">=18" } }, + "packages/cultmesh-browser": { + "version": "0.1.0", + "license": "MIT", + "dependencies": { + "@msgpack/msgpack": "^3.1.3", + "cultnet-ts": "^0.1.1" + }, + "devDependencies": { + "@types/node": "^24.0.0", + "typescript": "^5.9.0" + }, + "engines": { + "node": ">=18" + } + }, "packages/cultmesh-ts": { "version": "0.1.1", "license": "MIT", diff --git a/package.json b/package.json index 2723b934..c9b79e47 100644 --- a/package.json +++ b/package.json @@ -4,11 +4,19 @@ "workspaces": [ "packages/cultcache-ts", "packages/cultnet-ts", - "packages/cultmesh-ts" + "packages/cultmesh-ts", + "packages/cultmesh-browser" ], "scripts": { "build:ts": "node scripts/run-typescript-workspaces.mjs build", "test:ts": "node scripts/run-typescript-workspaces.mjs test", - "test:pack:ts": "node scripts/test-typescript-package-closure.mjs" + "test:pack:ts": "node scripts/test-typescript-package-closure.mjs", + "test:eve-browser-network": "node scripts/verify-eve-browser-network.mjs" + }, + "devDependencies": { + "esbuild": "^0.28.1", + "fast-uri": "3.1.5", + "js-yaml": "4.3.1", + "playwright-core": "^1.62.1" } } diff --git a/packages/cultmesh-browser/README.md b/packages/cultmesh-browser/README.md new file mode 100644 index 00000000..4866196c --- /dev/null +++ b/packages/cultmesh-browser/README.md @@ -0,0 +1,40 @@ +# CultMesh Browser + +`cultmesh-browser` is the browser-safe CultMesh client boundary. It owns one +WebSocket session for a stable Verse/provider identity, retains explicit raw +document leases across route replacement, and correlates typed CultNet +operations with provider receipts. + +It does not own application state and it does not expose direct document +writes. A renderer watches provider-owned records and invokes provider-owned +operations. + +```ts +const mesh = await CultMeshBrowserClient.connect({ + verseId: "sample.counter", + providerId: "sample.counter-provider", + runtimeId: "counter-browser", + rendezvous: { + resolve: async identity => discoverWebSocketRoute(identity), + }, +}); + +const counter = await mesh.leaseRawDocument({ + schemaId: "sample.counter_state.v1", + recordKey: "counter:main", +}); + +counter.watch(record => renderCounter(decodeCultNetPayload(record))); +``` + +The rendezvous port may call Odin, but application code does not own reconnect +or resubscription. The physical socket endpoint is a replaceable route, not the +provider identity. + +The browser handshake carries authentication through the host application's +ordinary secure cookie or equivalent upgrade credential. The C# host adapter +rejects endpoints without an authorization predicate unless anonymous local +development is explicitly enabled. + +Run `scripts/verify-eve-browser-network.mjs --eve-root ` for the +real Chromium + C# headless chronology. diff --git a/packages/cultmesh-browser/package.json b/packages/cultmesh-browser/package.json new file mode 100644 index 00000000..7f110506 --- /dev/null +++ b/packages/cultmesh-browser/package.json @@ -0,0 +1,50 @@ +{ + "name": "cultmesh-browser", + "version": "0.1.0", + "description": "Browser-safe CultMesh document leases and typed operations over CultNet WebSocket transport.", + "type": "module", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" + } + }, + "files": [ + "dist", + "README.md" + ], + "scripts": { + "build": "node ../../node_modules/typescript/bin/tsc -p tsconfig.json", + "prepack": "node ../../node_modules/typescript/bin/tsc -p tsconfig.json", + "typecheck": "node ../../node_modules/typescript/bin/tsc -p tsconfig.json --pretty false", + "test": "node ../../node_modules/typescript/bin/tsc -p tsconfig.json && node ../../node_modules/typescript/bin/tsc -p tsconfig.test.json && node --test dist-test/test/*.test.js" + }, + "keywords": [ + "cultmesh", + "cultnet", + "browser", + "websocket", + "gamecult" + ], + "author": "metacratic", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/GameCult/CultLib.git", + "directory": "packages/cultmesh-browser" + }, + "engines": { + "node": ">=18" + }, + "dependencies": { + "@msgpack/msgpack": "^3.1.3", + "cultnet-ts": "^0.1.1" + }, + "devDependencies": { + "@types/node": "^24.0.0", + "typescript": "^5.9.0" + } +} diff --git a/packages/cultmesh-browser/src/index.ts b/packages/cultmesh-browser/src/index.ts new file mode 100644 index 00000000..1f259422 --- /dev/null +++ b/packages/cultmesh-browser/src/index.ts @@ -0,0 +1,545 @@ +import { decode, encode } from "@msgpack/msgpack"; +import { + encodeCultNetMessageForWire, + parseCultNetMessage, + type CultNetDatabaseChangeRawMessage, + type CultNetDatabaseSubscribeMessage, + type CultNetDatabaseUnsubscribeMessage, + type CultNetMessage, + type CultNetOperationRequestMessage, + type CultNetOperationResponseMessage, + type CultNetRawDocumentRecord, + type CultNetSnapshotResponseRawMessage, +} from "cultnet-ts/contracts"; + +export interface CultMeshBrowserIdentity { + verseId: string; + providerId: string; +} + +export interface CultMeshBrowserRoute extends CultMeshBrowserIdentity { + endpoint: string; + generation?: string; +} + +export interface CultMeshBrowserRendezvous { + resolve(identity: CultMeshBrowserIdentity): Promise; +} + +export interface CultMeshBrowserSocket { + binaryType: BinaryType; + readonly readyState: number; + onopen: ((event: Event) => void) | null; + onmessage: ((event: MessageEvent) => void) | null; + onerror: ((event: Event) => void) | null; + onclose: ((event: CloseEvent) => void) | null; + send(data: ArrayBuffer | ArrayBufferView): void; + close(code?: number, reason?: string): void; +} + +export interface CultMeshBrowserClientOptions extends CultMeshBrowserIdentity { + runtimeId: string; + rendezvous: CultMeshBrowserRendezvous; + socketFactory?: (endpoint: string) => CultMeshBrowserSocket; + reconnectDelayMs?: number; + connectTimeoutMs?: number; + requestTimeoutMs?: number; + maxFrameBytes?: number; + createId?: () => string; +} + +export interface CultMeshRawDocumentLeaseOptions { + schemaId: string; + recordKey: string; + subscriptionId?: string; +} + +export interface CultMeshOperationOptions { + serviceId: string; + operation: string; + payloadSchema: string; + payload: unknown; + idempotencyKey?: string; + targetRuntimeId?: string; +} + +export type CultMeshConnectionState = "connecting" | "connected" | "reconnecting" | "disposed"; + +type DocumentWatcher = (record: CultNetRawDocumentRecord | undefined) => void; + +interface PendingSnapshot { + lease: CultMeshRawDocumentLease; + resolve: () => void; + reject: (error: Error) => void; + timer: ReturnType; +} + +interface PendingOperation { + resolve: (response: CultNetOperationResponseMessage) => void; + reject: (error: Error) => void; + timer: ReturnType; +} + +export class CultMeshRawDocumentLease implements Disposable { + readonly schemaId: string; + readonly recordKey: string; + readonly subscriptionId: string; + #client: CultMeshBrowserClient | undefined; + #current: CultNetRawDocumentRecord | undefined; + #watchers = new Set(); + + constructor( + client: CultMeshBrowserClient, + options: Required, + ) { + this.#client = client; + this.schemaId = options.schemaId; + this.recordKey = options.recordKey; + this.subscriptionId = options.subscriptionId; + } + + get current(): CultNetRawDocumentRecord | undefined { + return this.#current; + } + + watch(watcher: DocumentWatcher): () => void { + if (!this.#client) throw new Error("CultMesh document lease is disposed."); + this.#watchers.add(watcher); + watcher(this.#current); + return () => this.#watchers.delete(watcher); + } + + dispose(): void { + this.#client?.releaseLease(this); + this.#client = undefined; + this.#watchers.clear(); + } + + [Symbol.dispose](): void { + this.dispose(); + } + + apply(record: CultNetRawDocumentRecord | undefined): void { + this.#current = record; + for (const watcher of this.#watchers) watcher(record); + } +} + +export class CultMeshBrowserClient implements AsyncDisposable { + readonly identity: CultMeshBrowserIdentity; + readonly runtimeId: string; + #options: Required> & { + socketFactory: (endpoint: string) => CultMeshBrowserSocket; + }; + #socket: CultMeshBrowserSocket | undefined; + #socketGeneration = 0; + #state: CultMeshConnectionState = "connecting"; + #disposed = false; + #reconnectTimer: ReturnType | undefined; + #connectPromise: Promise | undefined; + #leases = new Map(); + #openingLeases = new Map(); + #pendingSnapshots = new Map(); + #pendingOperations = new Map(); + #stateWatchers = new Set<(state: CultMeshConnectionState) => void>(); + + private constructor(options: CultMeshBrowserClientOptions) { + requireText(options.verseId, "verseId"); + requireText(options.providerId, "providerId"); + requireText(options.runtimeId, "runtimeId"); + this.identity = { verseId: options.verseId, providerId: options.providerId }; + this.runtimeId = options.runtimeId; + this.#options = { + ...options, + reconnectDelayMs: options.reconnectDelayMs ?? 250, + connectTimeoutMs: options.connectTimeoutMs ?? 10_000, + requestTimeoutMs: options.requestTimeoutMs ?? 10_000, + maxFrameBytes: options.maxFrameBytes ?? 4 * 1024 * 1024, + createId: options.createId ?? (() => crypto.randomUUID()), + socketFactory: options.socketFactory ?? (endpoint => new WebSocket(endpoint)), + }; + } + + static async connect(options: CultMeshBrowserClientOptions): Promise { + const client = new CultMeshBrowserClient(options); + await client.connectSocket(); + return client; + } + + get state(): CultMeshConnectionState { + return this.#state; + } + + watchState(watcher: (state: CultMeshConnectionState) => void): () => void { + this.#stateWatchers.add(watcher); + watcher(this.#state); + return () => this.#stateWatchers.delete(watcher); + } + + async leaseRawDocument(options: CultMeshRawDocumentLeaseOptions): Promise { + this.throwIfDisposed(); + requireText(options.schemaId, "schemaId"); + requireText(options.recordKey, "recordKey"); + const subscriptionId = options.subscriptionId ?? `lease:${this.#options.createId()}`; + if (this.#leases.has(subscriptionId) || this.#openingLeases.has(subscriptionId)) { + throw new Error(`CultMesh subscription '${subscriptionId}' is already leased.`); + } + const lease = new CultMeshRawDocumentLease(this, { ...options, subscriptionId }); + this.#openingLeases.set(subscriptionId, lease); + try { + await this.subscribe(lease); + this.#openingLeases.delete(subscriptionId); + this.#leases.set(subscriptionId, lease); + return lease; + } catch (error) { + this.#openingLeases.delete(subscriptionId); + throw error; + } + } + + async invoke(options: CultMeshOperationOptions): Promise { + this.throwIfDisposed(); + requireText(options.serviceId, "serviceId"); + requireText(options.operation, "operation"); + requireText(options.payloadSchema, "payloadSchema"); + await this.ensureConnected(); + const messageId = options.idempotencyKey ?? this.#options.createId(); + requireText(messageId, "operation idempotencyKey"); + if (this.#pendingOperations.has(messageId)) { + throw new Error(`CultMesh operation '${messageId}' is already in flight.`); + } + const request: CultNetOperationRequestMessage = { + schemaVersion: "cultnet.operation_request.v0", + messageId, + serviceId: options.serviceId, + operation: options.operation, + payloadSchema: options.payloadSchema, + payloadEncoding: "messagepack-base64", + payload: bytesToBase64(encode(options.payload)), + sourceRuntimeId: this.runtimeId, + ...(options.targetRuntimeId ? { targetRuntimeId: options.targetRuntimeId } : {}), + }; + const response = new Promise((resolve, reject) => { + const timer = setTimeout(() => { + if (!this.#pendingOperations.delete(messageId)) return; + reject(new Error(`CultMesh operation '${messageId}' timed out.`)); + }, this.#options.requestTimeoutMs); + this.#pendingOperations.set(messageId, { resolve, reject, timer }); + }); + try { + this.send(request); + } catch (error) { + const pending = this.#pendingOperations.get(messageId); + if (pending) clearTimeout(pending.timer); + this.#pendingOperations.delete(messageId); + throw error; + } + return response; + } + + async refreshRoute(): Promise { + this.throwIfDisposed(); + this.#socketGeneration++; + const socket = this.#socket; + this.#socket = undefined; + socket?.close(1012, "CultMesh route refresh"); + await this.connectSocket(); + } + + releaseLease(lease: CultMeshRawDocumentLease): void { + if (this.#leases.get(lease.subscriptionId) !== lease) return; + this.#leases.delete(lease.subscriptionId); + for (const [messageId, pending] of this.#pendingSnapshots) { + if (pending.lease !== lease) continue; + this.#pendingSnapshots.delete(messageId); + clearTimeout(pending.timer); + pending.reject(new Error("CultMesh document lease was disposed before its snapshot arrived.")); + } + if (this.#state === "connected") { + const message: CultNetDatabaseUnsubscribeMessage = { + schemaVersion: "cultnet.database_unsubscribe.v0", + messageId: this.#options.createId(), + subscriptionId: lease.subscriptionId, + }; + this.send(message); + } + } + + async dispose(): Promise { + if (this.#disposed) return; + this.#disposed = true; + this.setState("disposed"); + if (this.#reconnectTimer) clearTimeout(this.#reconnectTimer); + this.#reconnectTimer = undefined; + const error = new Error("CultMesh browser client was disposed."); + for (const pending of this.#pendingSnapshots.values()) { + clearTimeout(pending.timer); + pending.reject(error); + } + for (const pending of this.#pendingOperations.values()) { + clearTimeout(pending.timer); + pending.reject(error); + } + this.#pendingSnapshots.clear(); + this.#pendingOperations.clear(); + this.#leases.clear(); + this.#openingLeases.clear(); + const socket = this.#socket; + this.#socket = undefined; + socket?.close(1000, "CultMesh client disposed"); + } + + async [Symbol.asyncDispose](): Promise { + await this.dispose(); + } + + private async subscribe(lease: CultMeshRawDocumentLease): Promise { + await this.ensureConnected(); + const messageId = this.#options.createId(); + const ready = new Promise((resolve, reject) => { + const timer = setTimeout(() => { + if (!this.#pendingSnapshots.delete(messageId)) return; + reject(new Error(`CultMesh subscription '${lease.subscriptionId}' timed out.`)); + }, this.#options.requestTimeoutMs); + this.#pendingSnapshots.set(messageId, { lease, resolve, reject, timer }); + }); + const request: CultNetDatabaseSubscribeMessage = { + schemaVersion: "cultnet.database_subscribe.v0", + messageId, + subscriptionId: lease.subscriptionId, + schemaIds: [lease.schemaId], + recordKeys: [lease.recordKey], + includeSnapshot: true, + consumerRuntimeId: this.runtimeId, + }; + try { + this.send(request); + } catch (error) { + const pending = this.#pendingSnapshots.get(messageId); + if (pending) clearTimeout(pending.timer); + this.#pendingSnapshots.delete(messageId); + throw error; + } + return ready; + } + + private ensureConnected(): Promise { + if (this.#state === "connected" && this.#socket?.readyState === 1) return Promise.resolve(); + return this.connectSocket(); + } + + private connectSocket(): Promise { + this.throwIfDisposed(); + if (this.#connectPromise) return this.#connectPromise; + const generation = ++this.#socketGeneration; + this.setState(this.#socket ? "reconnecting" : "connecting"); + this.#connectPromise = this.openSocket(generation).finally(() => { + this.#connectPromise = undefined; + }); + return this.#connectPromise; + } + + private async openSocket(generation: number): Promise { + const route = await this.#options.rendezvous.resolve(this.identity); + if (route.verseId !== this.identity.verseId || route.providerId !== this.identity.providerId) { + throw new Error("CultMesh rendezvous returned a route for the wrong stable identity."); + } + const endpoint = new URL(route.endpoint); + if (endpoint.protocol !== "ws:" && endpoint.protocol !== "wss:") { + throw new Error(`CultMesh browser route must use ws:// or wss://, got '${route.endpoint}'.`); + } + const socket = this.#options.socketFactory(route.endpoint); + socket.binaryType = "arraybuffer"; + try { + await new Promise((resolve, reject) => { + const timer = setTimeout( + () => reject(new Error(`CultMesh WebSocket open timed out for '${route.endpoint}'.`)), + this.#options.connectTimeoutMs, + ); + socket.onopen = () => { clearTimeout(timer); resolve(); }; + socket.onerror = () => { clearTimeout(timer); reject(new Error(`CultMesh WebSocket could not open '${route.endpoint}'.`)); }; + socket.onclose = () => { clearTimeout(timer); reject(new Error(`CultMesh WebSocket closed while opening '${route.endpoint}'.`)); }; + }); + } catch (error) { + socket.close(1000, "CultMesh route open failed"); + throw error; + } + if (this.#disposed || generation !== this.#socketGeneration) { + socket.close(1000, "Stale CultMesh route"); + return; + } + this.#socket = socket; + socket.onmessage = event => { void this.receive(event, generation); }; + socket.onerror = () => undefined; + socket.onclose = () => this.handleClosed(generation); + this.setState("connected"); + try { + this.send({ + schemaVersion: "cultnet.hello.v0", + runtimeId: this.runtimeId, + runtimeKind: "browser", + supportedMessageVersions: [ + "cultnet.database_subscribe.v0", + "cultnet.database_unsubscribe.v0", + "cultnet.database_change_raw.v0", + "cultnet.operation_request.v0", + "cultnet.operation_response.v0", + ], + }); + await Promise.all([...this.#leases.values()].map(lease => this.subscribe(lease))); + } catch (error) { + if (this.#socket === socket) this.#socket = undefined; + socket.onclose = null; + socket.close(1000, "CultMesh session initialization failed"); + throw error; + } + } + + private handleClosed(generation: number): void { + if (this.#disposed || generation !== this.#socketGeneration) return; + this.#socket = undefined; + const error = new Error("CultMesh route closed before the provider response arrived."); + for (const pending of this.#pendingSnapshots.values()) { + clearTimeout(pending.timer); + pending.reject(error); + } + for (const pending of this.#pendingOperations.values()) { + clearTimeout(pending.timer); + pending.reject(error); + } + this.#pendingSnapshots.clear(); + this.#pendingOperations.clear(); + this.setState("reconnecting"); + this.#reconnectTimer = setTimeout(() => { + this.#reconnectTimer = undefined; + void this.connectSocket().catch(() => this.handleClosed(this.#socketGeneration)); + }, this.#options.reconnectDelayMs); + } + + private async receive(event: MessageEvent, generation: number): Promise { + if (this.#disposed || generation !== this.#socketGeneration) return; + let payload: Uint8Array; + if (event.data instanceof ArrayBuffer) { + payload = new Uint8Array(event.data); + } else if (ArrayBuffer.isView(event.data)) { + payload = new Uint8Array(event.data.buffer, event.data.byteOffset, event.data.byteLength); + } else if (event.data instanceof Blob) { + payload = new Uint8Array(await event.data.arrayBuffer()); + } else { + this.#socket?.close(1003, "CultNet requires binary WebSocket frames"); + return; + } + if (payload.byteLength > this.#options.maxFrameBytes) { + this.#socket?.close(1009, "CultNet frame exceeds configured maximum"); + return; + } + const message = parseCultNetMessage(decode(payload)); + switch (message.schemaVersion) { + case "cultnet.snapshot_response_raw.v0": + this.applySnapshot(message); + return; + case "cultnet.database_change_raw.v0": + this.applyChange(message); + return; + case "cultnet.operation_response.v0": { + const pending = this.#pendingOperations.get(message.messageId); + if (!pending) return; + this.#pendingOperations.delete(message.messageId); + clearTimeout(pending.timer); + pending.resolve(message); + return; + } + case "cultnet.error.v0": + this.rejectCorrelated(message.error); + return; + default: + return; + } + } + + private applySnapshot(message: CultNetSnapshotResponseRawMessage): void { + const pending = this.#pendingSnapshots.get(message.messageId); + if (!pending) return; + this.#pendingSnapshots.delete(message.messageId); + clearTimeout(pending.timer); + const matches = message.documents.filter(record => + record.schemaId === pending.lease.schemaId && record.recordKey === pending.lease.recordKey); + if (matches.length > 1) { + pending.reject(new Error(`CultMesh snapshot returned duplicate record '${pending.lease.recordKey}'.`)); + return; + } + pending.lease.apply(matches[0]); + pending.resolve(); + } + + private applyChange(message: CultNetDatabaseChangeRawMessage): void { + const lease = this.#leases.get(message.subscriptionId) ?? this.#openingLeases.get(message.subscriptionId); + if (!lease) return; + if (message.changeKind === "removed") { + if (message.recordKey === lease.recordKey && message.schemaId === lease.schemaId) lease.apply(undefined); + return; + } + const record = message.document; + if (record?.recordKey === lease.recordKey && record.schemaId === lease.schemaId) lease.apply(record); + } + + private rejectCorrelated(reason: string): void { + if (this.#pendingOperations.size === 1) { + const [messageId, pending] = this.#pendingOperations.entries().next().value!; + this.#pendingOperations.delete(messageId); + clearTimeout(pending.timer); + pending.reject(new Error(reason)); + } + } + + private send(message: CultNetMessage): void { + const socket = this.#socket; + if (!socket || socket.readyState !== 1) throw new Error("CultMesh browser route is not connected."); + const payload = encode(encodeCultNetMessageForWire(message)); + if (payload.byteLength > this.#options.maxFrameBytes) { + throw new Error(`CultMesh message exceeds the ${this.#options.maxFrameBytes}-byte limit.`); + } + socket.send(payload); + } + + private setState(state: CultMeshConnectionState): void { + if (this.#state === state) return; + this.#state = state; + for (const watcher of this.#stateWatchers) watcher(state); + } + + private throwIfDisposed(): void { + if (this.#disposed) throw new Error("CultMesh browser client is disposed."); + } +} + +export function decodeCultNetPayload(record: CultNetRawDocumentRecord): T { + if (record.payloadEncoding !== "messagepack") { + throw new Error(`Unsupported CultNet document payload '${record.payloadEncoding}'.`); + } + return decode(record.payload) as T; +} + +export function decodeCultNetOperationPayload(response: CultNetOperationResponseMessage): T { + if (response.payloadEncoding !== "messagepack-base64") { + throw new Error(`Unsupported CultNet operation payload '${response.payloadEncoding ?? "unspecified"}'.`); + } + return decode(base64ToBytes(response.payload)) as T; +} + +function bytesToBase64(bytes: Uint8Array): string { + let binary = ""; + for (let offset = 0; offset < bytes.length; offset += 0x8000) { + binary += String.fromCharCode(...bytes.subarray(offset, offset + 0x8000)); + } + return btoa(binary); +} + +function base64ToBytes(value: string): Uint8Array { + const binary = atob(value); + return Uint8Array.from(binary, character => character.charCodeAt(0)); +} + +function requireText(value: string, field: string): void { + if (!value || value.trim().length === 0) throw new Error(`CultMesh browser ${field} is required.`); +} diff --git a/packages/cultmesh-browser/test/cultmesh-browser.test.ts b/packages/cultmesh-browser/test/cultmesh-browser.test.ts new file mode 100644 index 00000000..8c3ae1b5 --- /dev/null +++ b/packages/cultmesh-browser/test/cultmesh-browser.test.ts @@ -0,0 +1,304 @@ +import assert from "node:assert/strict"; +import test from "node:test"; + +import { decode, encode } from "@msgpack/msgpack"; +import { + encodeCultNetMessageForWire, + parseCultNetMessage, + type CultNetDatabaseSubscribeMessage, + type CultNetMessage, + type CultNetOperationRequestMessage, + type CultNetRawDocumentRecord, +} from "cultnet-ts/contracts"; + +import { + CultMeshBrowserClient, + decodeCultNetOperationPayload, + decodeCultNetPayload, + type CultMeshBrowserRoute, + type CultMeshBrowserSocket, +} from "../src/index.js"; + +test("browser client leases provider state, invokes an operation, and follows route replacement", async () => { + const first = new FakeProvider("ws://127.0.0.1:4101/mesh", 4); + const second = new FakeProvider("ws://127.0.0.1:4102/mesh", 9); + let route = first.route; + let id = 0; + const client = await CultMeshBrowserClient.connect({ + verseId: route.verseId, + providerId: route.providerId, + runtimeId: "browser-test", + rendezvous: { resolve: async () => route }, + createId: () => `id-${++id}`, + socketFactory: endpoint => endpoint === first.route.endpoint ? first.open() : second.open(), + }); + + const lease = await client.leaseRawDocument({ + schemaId: "sample.counter_state.v1", + recordKey: "counter:main", + }); + assert.deepEqual(decodeCultNetPayload<{ count: number }>(lease.current!).count, 4); + + const observed: number[] = []; + const unwatch = lease.watch(record => { + if (record) observed.push(decodeCultNetPayload<{ count: number }>(record).count); + }); + const response = await client.invoke({ + serviceId: "sample.counter", + operation: "increment", + payloadSchema: "sample.increment.v1", + payload: { amount: 2 }, + }); + assert.equal(response.status, "accepted"); + assert.deepEqual(decodeCultNetOperationPayload<{ count: number }>(response), { count: 6 }); + assert.deepEqual(observed, [4, 6]); + + route = second.route; + await client.refreshRoute(); + assert.equal(client.state, "connected"); + assert.deepEqual(decodeCultNetPayload<{ count: number }>(lease.current!).count, 9); + assert.deepEqual(observed, [4, 6, 9]); + assert.equal(first.activeSubscriptionCount, 0); + assert.equal(second.activeSubscriptionCount, 1); + + unwatch(); + lease.dispose(); + assert.equal(second.activeSubscriptionCount, 0); + await client.dispose(); +}); + +test("browser client rejects wrong rendezvous identity and has no document write API", async () => { + const provider = new FakeProvider("ws://127.0.0.1:4201/mesh", 1); + await assert.rejects( + CultMeshBrowserClient.connect({ + verseId: "sample.counter", + providerId: "sample.counter-provider", + runtimeId: "browser-test", + rendezvous: { + resolve: async () => ({ + ...provider.route, + providerId: "intruder-provider", + }), + }, + socketFactory: () => provider.open(), + }), + /wrong stable identity/, + ); + assert.equal("putDocument" in CultMeshBrowserClient.prototype, false); + assert.equal("setDocument" in CultMeshBrowserClient.prototype, false); +}); + +test("browser client bounds unanswered provider operations", async () => { + const route = { + verseId: "sample.counter", + providerId: "sample.counter-provider", + endpoint: "ws://127.0.0.1:4301/mesh", + }; + const client = await CultMeshBrowserClient.connect({ + ...route, + runtimeId: "browser-timeout-test", + rendezvous: { resolve: async () => route }, + requestTimeoutMs: 5, + socketFactory: () => new FakeSocket(() => undefined, () => undefined), + }); + await assert.rejects( + client.invoke({ + serviceId: "sample.counter", + operation: "increment", + payloadSchema: "sample.increment.v1", + payload: { amount: 1 }, + idempotencyKey: "timeout-1", + }), + /timed out/, + ); + await client.dispose(); +}); + +test("browser client rejects oversized outbound schema messages", async () => { + const route = { + verseId: "sample.counter", + providerId: "sample.counter-provider", + endpoint: "ws://127.0.0.1:4401/mesh", + }; + await assert.rejects( + CultMeshBrowserClient.connect({ + ...route, + runtimeId: "browser-size-test", + rendezvous: { resolve: async () => route }, + maxFrameBytes: 8, + socketFactory: () => new FakeSocket(() => undefined, () => undefined), + }), + /exceeds the 8-byte limit/, + ); +}); + +test("browser client reserves subscription identity while the initial lease opens", async () => { + const provider = new FakeProvider("ws://127.0.0.1:4501/mesh", 3); + const client = await CultMeshBrowserClient.connect({ + ...provider.route, + runtimeId: "browser-lease-race-test", + rendezvous: { resolve: async () => provider.route }, + socketFactory: () => provider.open(), + }); + const first = client.leaseRawDocument({ + schemaId: "sample.counter_state.v1", + recordKey: "counter:main", + subscriptionId: "one-owner", + }); + await assert.rejects( + client.leaseRawDocument({ + schemaId: "sample.counter_state.v1", + recordKey: "counter:main", + subscriptionId: "one-owner", + }), + /already leased/, + ); + (await first).dispose(); + await client.dispose(); +}); + +class FakeProvider { + readonly route: CultMeshBrowserRoute; + #count: number; + #subscriptions = new Map>(); + + constructor(endpoint: string, count: number) { + this.route = { + verseId: "sample.counter", + providerId: "sample.counter-provider", + endpoint, + generation: endpoint, + }; + this.#count = count; + } + + get activeSubscriptionCount(): number { + let count = 0; + for (const subscriptions of this.#subscriptions.values()) count += subscriptions.size; + return count; + } + + open(): FakeSocket { + const socket = new FakeSocket( + wire => this.receive(socket, wire), + () => this.#subscriptions.delete(socket), + ); + this.#subscriptions.set(socket, new Map()); + return socket; + } + + private receive(socket: FakeSocket, wire: Uint8Array): void { + const message = parseCultNetMessage(decode(wire)); + switch (message.schemaVersion) { + case "cultnet.database_subscribe.v0": + this.subscribe(socket, message); + return; + case "cultnet.database_unsubscribe.v0": + this.#subscriptions.get(socket)?.delete(message.subscriptionId); + return; + case "cultnet.operation_request.v0": + this.invoke(socket, message); + return; + default: + return; + } + } + + private subscribe(socket: FakeSocket, message: CultNetDatabaseSubscribeMessage): void { + this.#subscriptions.get(socket)!.set(message.subscriptionId, message); + socket.deliver({ + schemaVersion: "cultnet.snapshot_response_raw.v0", + messageId: message.messageId, + documents: [this.record()], + }); + } + + private invoke(socket: FakeSocket, message: CultNetOperationRequestMessage): void { + const payload = decode(base64ToBytes(message.payload)) as { amount: number }; + this.#count += payload.amount; + for (const [peer, subscriptions] of this.#subscriptions) { + for (const subscriptionId of subscriptions.keys()) { + peer.deliver({ + schemaVersion: "cultnet.database_change_raw.v0", + messageId: `change-${message.messageId}`, + subscriptionId, + changeKind: "updated", + document: this.record(), + }); + } + } + socket.deliver({ + schemaVersion: "cultnet.operation_response.v0", + messageId: message.messageId, + serviceId: message.serviceId, + operation: message.operation, + status: "accepted", + payloadSchema: "sample.increment_receipt.v1", + payloadEncoding: "messagepack-base64", + payload: bytesToBase64(encode({ count: this.#count })), + sourceRuntimeId: "sample.counter-provider", + }); + } + + private record(): CultNetRawDocumentRecord { + return { + schemaId: "sample.counter_state.v1", + recordKey: "counter:main", + storedAt: "2026-08-17T00:00:00Z", + payloadEncoding: "messagepack", + payload: encode({ count: this.#count }), + sourceRuntimeId: "sample.counter-provider", + }; + } +} + +class FakeSocket implements CultMeshBrowserSocket { + binaryType: BinaryType = "arraybuffer"; + readyState = 0; + onopen: ((event: Event) => void) | null = null; + onmessage: ((event: MessageEvent) => void) | null = null; + onerror: ((event: Event) => void) | null = null; + onclose: ((event: CloseEvent) => void) | null = null; + #receive: (wire: Uint8Array) => void; + #closed: () => void; + + constructor(receive: (wire: Uint8Array) => void, closed: () => void) { + this.#receive = receive; + this.#closed = closed; + queueMicrotask(() => { + this.readyState = 1; + this.onopen?.({} as Event); + }); + } + + send(data: ArrayBuffer | ArrayBufferView): void { + if (this.readyState !== 1) throw new Error("Fake socket is not open."); + const wire = data instanceof ArrayBuffer + ? new Uint8Array(data) + : new Uint8Array(data.buffer, data.byteOffset, data.byteLength); + this.#receive(wire); + } + + close(code = 1000, reason = ""): void { + if (this.readyState === 3) return; + this.readyState = 3; + this.#closed(); + this.onclose?.({ code, reason } as CloseEvent); + } + + deliver(message: CultNetMessage): void { + const wire = encode(encodeCultNetMessageForWire(message)); + queueMicrotask(() => this.onmessage?.({ data: wire.slice().buffer } as MessageEvent)); + } +} + +function bytesToBase64(bytes: Uint8Array): string { + let binary = ""; + for (const byte of bytes) binary += String.fromCharCode(byte); + return btoa(binary); +} + +function base64ToBytes(value: string): Uint8Array { + const binary = atob(value); + return Uint8Array.from(binary, character => character.charCodeAt(0)); +} diff --git a/packages/cultmesh-browser/tsconfig.json b/packages/cultmesh-browser/tsconfig.json new file mode 100644 index 00000000..b9b7caba --- /dev/null +++ b/packages/cultmesh-browser/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ES2022", + "moduleResolution": "Bundler", + "lib": ["ES2022", "DOM"], + "strict": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "outDir": "dist", + "rootDir": "src", + "skipLibCheck": true + }, + "include": ["src/**/*.ts"] +} diff --git a/packages/cultmesh-browser/tsconfig.test.json b/packages/cultmesh-browser/tsconfig.test.json new file mode 100644 index 00000000..4d148683 --- /dev/null +++ b/packages/cultmesh-browser/tsconfig.test.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "types": ["node"], + "declaration": false, + "declarationMap": false, + "sourceMap": false, + "outDir": "dist-test", + "rootDir": "." + }, + "include": ["src/**/*.ts", "test/**/*.ts"] +} diff --git a/packages/cultnet-ts/package.json b/packages/cultnet-ts/package.json index f0a3e396..6ff29340 100644 --- a/packages/cultnet-ts/package.json +++ b/packages/cultnet-ts/package.json @@ -9,6 +9,11 @@ "types": "./dist/index.d.ts", "require": "./dist/index.js", "default": "./dist/index.js" + }, + "./contracts": { + "types": "./dist/contracts.d.ts", + "require": "./dist/contracts.js", + "default": "./dist/contracts.js" } }, "files": [ diff --git a/packages/cultnet-ts/src/contracts.ts b/packages/cultnet-ts/src/contracts.ts index 56ece383..c97a0d8d 100644 --- a/packages/cultnet-ts/src/contracts.ts +++ b/packages/cultnet-ts/src/contracts.ts @@ -951,8 +951,11 @@ function encodeLegacySchemaDescriptor(schema: CultNetSchemaDescriptor): Record character.charCodeAt(0)); } function validateDocumentPutRawMessage(input: unknown): asserts input is CultNetDocumentPutRawMessage { @@ -1127,6 +1136,12 @@ function normalizeCultNetOptionalNulls( "supportedBodyTransports", ]); return; + case "cultnet.operation_request.v0": + stripNullProperties(candidate, ["payloadEncoding", "sourceRuntimeId", "targetRuntimeId"]); + return; + case "cultnet.operation_response.v0": + stripNullProperties(candidate, ["payloadEncoding", "diagnostics", "sourceRuntimeId"]); + return; case "cultnet.schema_catalog_request.v0": stripNullProperties(candidate, ["schemaIds", "kinds"]); return; diff --git a/packages/cultnet-ts/test/cultnet.test.ts b/packages/cultnet-ts/test/cultnet.test.ts index 1a2ba805..c5ca69da 100644 --- a/packages/cultnet-ts/test/cultnet.test.ts +++ b/packages/cultnet-ts/test/cultnet.test.ts @@ -821,9 +821,9 @@ test("CultNet can round-trip gamecult.networking.v0 auth messages through the ex assert.deepEqual(wireValue, [ 0, [ - Buffer.from("nonce", "utf8"), - Buffer.from("auth", "utf8"), - Buffer.from("password", "utf8"), + new TextEncoder().encode("nonce"), + new TextEncoder().encode("auth"), + new TextEncoder().encode("password"), ], ]); @@ -1261,6 +1261,24 @@ test("operation envelopes preserve typed service routing and payload correlation assert.equal(response.messageId, request.messageId); }); +test("CultNet contracts encode legacy bytes without Node Buffer authority", () => { + const originalBuffer = globalThis.Buffer; + try { + Object.defineProperty(globalThis, "Buffer", { configurable: true, value: undefined }); + const message = parseCultNetMessage({ + schemaVersion: "cultnet.login.v0", + nonce: "AQID", + auth: "BAUG", + password: "BwgJ", + }); + const wire = encodeCultNetMessageForWire(message, "gamecult.networking.v0") as [number, Uint8Array[]]; + assert.equal(wire[0], 0); + assert.deepEqual([...wire[1][0]], [1, 2, 3]); + } finally { + Object.defineProperty(globalThis, "Buffer", { configurable: true, value: originalBuffer }); + } +}); + test("database subscription contracts match the C# live document lane", () => { const subscribe = parseCultNetMessage({ schemaVersion: "cultnet.database_subscribe.v0", diff --git a/samples/eve-browser-network/EveBrowserNetworkSample.csproj b/samples/eve-browser-network/EveBrowserNetworkSample.csproj new file mode 100644 index 00000000..4fe900dd --- /dev/null +++ b/samples/eve-browser-network/EveBrowserNetworkSample.csproj @@ -0,0 +1,10 @@ + + + net10.0 + enable + enable + + + + + diff --git a/samples/eve-browser-network/Program.cs b/samples/eve-browser-network/Program.cs new file mode 100644 index 00000000..962baee3 --- /dev/null +++ b/samples/eve-browser-network/Program.cs @@ -0,0 +1,319 @@ +using System.Net; +using System.Text.Json; +using GameCult.Caching; +using GameCult.Caching.MessagePack; +using GameCult.Networking; +using GameCult.Networking.WebSockets; +using MessagePack; +using Microsoft.AspNetCore.Hosting.Server; +using Microsoft.AspNetCore.Hosting.Server.Features; +using Microsoft.Extensions.DependencyInjection; + +const string counterKey = "counter:main"; +const string surfaceKey = "sample.counter"; +var arguments = Args.Parse(args); +if (arguments.Mode == "provider") +{ + await RunProviderAsync(arguments); + return; +} +if (arguments.Mode == "headless") +{ + await RunHeadlessAsync(arguments); + return; +} +throw new InvalidOperationException("Use 'provider' or 'headless'."); + +static async Task RunProviderAsync(Args arguments) +{ + var registry = CultDocumentRegistry.ForTypes([typeof(CounterState), typeof(CounterSurfaceDocument)]); + using var cache = await CultCacheMessagePack.OpenAsync(arguments.StatePath, new CultCacheOpenOptions + { + Registry = registry, + FlushOnDispose = true, + StoreFlushOnDispose = true + }); + var documents = new CultNetDocumentRegistry(registry) + .Register(CultNetDocumentBinding.ForDocument(registry, "sample.counter_state.v1")) + .Register(CultNetDocumentBinding.ForDocument(registry, "gamecult.eve.surface.v1")); + using var database = new CultNetDatabase(cache, new CultNetDatabaseOptions + { + RuntimeId = "sample.counter-provider", + DocumentRegistry = documents + }); + if (cache.Get(new CultRecordKey(counterKey)) == null) + await database.PutAsync(new CultRecordKey(counterKey), CounterState.Initial(counterKey)); + if (cache.Get(new CultRecordKey(surfaceKey)) == null) + await database.PutAsync(new CultRecordKey(surfaceKey), CounterSurfaceDocument.Create()); + await cache.FlushAsync(); + + await using var schemaServer = new CultNetWebSocketSchemaServer(); + using var subscriptions = new CultNetDatabaseSubscriptionServer(schemaServer, database); + var operationGate = new SemaphoreSlim(1, 1); + schemaServer.OnCultNet(async (request, peer) => + { + if (request.ServiceId != "sample.counter" || request.Operation != "sample.counter.increment") + { + peer.SendCultNet(new CultNetErrorMessage { Error = "Unsupported sample operation." }); + return; + } + await operationGate.WaitAsync(); + try + { + var current = cache.Get(new CultRecordKey(counterKey)) + ?? throw new InvalidOperationException("Counter state is unavailable."); + if (!current.Receipts.TryGetValue(request.MessageId, out var receipt)) + { + var input = MessagePackSerializer.Deserialize( + Convert.FromBase64String(request.Payload)); + receipt = IncrementReceipt.Accepted(request.MessageId, current.Count + input.Amount); + var receipts = new Dictionary(current.Receipts, StringComparer.Ordinal) + { + [request.MessageId] = receipt + }; + await database.PutAsync(new CultRecordKey(counterKey), new CounterState + { + CounterId = counterKey, + Count = receipt.Count, + Receipts = receipts + }); + await cache.FlushAsync(); + } + peer.SendCultNet(new CultNetOperationResponseMessage + { + MessageId = request.MessageId, + ServiceId = request.ServiceId, + Operation = request.Operation, + Status = "accepted", + PayloadSchema = "gamecult.eve.command_receipt.v1", + Payload = Convert.ToBase64String(MessagePackSerializer.Serialize(receipt)), + SourceRuntimeId = "sample.counter-provider" + }); + } + finally + { + operationGate.Release(); + } + }); + + var builder = WebApplication.CreateSlimBuilder(); + builder.WebHost.ConfigureKestrel(options => options.Listen(IPAddress.Loopback, arguments.Port)); + var app = builder.Build(); + app.UseWebSockets(); + app.MapCultNetWebSocket("/cultmesh", schemaServer, new CultNetWebSocketEndpointOptions + { + AuthorizeAsync = context => ValueTask.FromResult( + context.Request.Cookies.TryGetValue("cultnet_session", out var token) && + string.Equals(token, arguments.Token, StringComparison.Ordinal)) + }); + await app.StartAsync(); + var address = app.Services.GetRequiredService() + .Features.Get()!.Addresses.Single(); + Console.WriteLine("PROVIDER_READY " + address.Replace("http://", "ws://", StringComparison.Ordinal) + "/cultmesh"); + await app.WaitForShutdownAsync(); + await app.DisposeAsync(); +} + +static async Task RunHeadlessAsync(Args arguments) +{ + var registry = CultDocumentRegistry.ForTypes([typeof(CounterState)]); + using var cache = new CultCache(registry); + var documents = new CultNetDocumentRegistry(registry) + .Register(CultNetDocumentBinding.ForDocument(registry, "sample.counter_state.v1")); + using var transport = new CultNetWebSocketSchemaClient(options => + options.SetRequestHeader("Cookie", $"cultnet_session={arguments.Token}")); + using var subscriptions = new CultNetDatabaseSubscriptionClient(transport, cache, documents); + var changed = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + subscriptions.Changed += change => + { + if (change.Document is CounterState counter) changed.TrySetResult(counter); + }; + await transport.ConnectAsync(new Uri(arguments.Endpoint)); + var initial = await subscriptions.SubscribeAsync( + "headless-counter", + recordKeys: [counterKey], + schemaIds: ["sample.counter_state.v1"], + deliveryMode: CultNetDatabaseSubscriptionDeliveryMode.Live); + var counter = initial.OfType().Single(); + Console.WriteLine("HEADLESS_READY " + JsonSerializer.Serialize(new { count = counter.Count })); + var update = await changed.Task.WaitAsync(TimeSpan.FromSeconds(15)); + Console.WriteLine("HEADLESS_UPDATE " + JsonSerializer.Serialize(new { count = update.Count })); +} + +sealed class Args +{ + public string Mode { get; private init; } = ""; + public int Port { get; private init; } + public string StatePath { get; private init; } = "sample-counter.cc"; + public string Endpoint { get; private init; } = ""; + public string Token { get; private init; } = "sample-session"; + + public static Args Parse(string[] values) + { + if (values.Length == 0) return new Args(); + var named = new Dictionary(StringComparer.Ordinal); + for (var index = 1; index + 1 < values.Length; index += 2) + named[values[index]] = values[index + 1]; + return new Args + { + Mode = values[0], + Port = named.TryGetValue("--port", out var port) ? int.Parse(port) : 0, + StatePath = named.GetValueOrDefault("--state", "sample-counter.cc"), + Endpoint = named.GetValueOrDefault("--endpoint", ""), + Token = named.GetValueOrDefault("--token", "sample-session") + }; + } +} + +[CultDocument("sample.counter_state", "sample.counter_state.v1")] +[MessagePackObject] +public sealed class CounterState +{ + [Key("counterId")] public string CounterId { get; set; } = ""; + [Key("count")] public int Count { get; set; } + [Key("receipts")] public Dictionary Receipts { get; set; } = new(StringComparer.Ordinal); + public static CounterState Initial(string counterId) => new() { CounterId = counterId }; +} + +[MessagePackObject] +public sealed class IncrementRequest +{ + [Key("amount")] public int Amount { get; set; } = 1; +} + +[MessagePackObject] +public sealed class IncrementReceipt +{ + [Key("receiptId")] public string ReceiptId { get; set; } = ""; + [Key("schema")] public string Schema { get; set; } = "gamecult.eve.command_receipt.v1"; + [Key("commandId")] public string CommandId { get; set; } = ""; + [Key("command")] public string Command { get; set; } = "sample.counter.increment"; + [Key("state")] public string State { get; set; } = "accepted"; + [Key("ownerRepo")] public string OwnerRepo { get; set; } = "CultLib"; + [Key("authority")] public string Authority { get; set; } = "provider-daemon"; + [Key("providerId")] public string ProviderId { get; set; } = "sample.counter-provider"; + [Key("surfaceId")] public string SurfaceId { get; set; } = "sample.counter"; + [Key("issuedAtUtc")] public string IssuedAtUtc { get; set; } = ""; + [Key("sourceVersion")] public int SourceVersion { get; set; } + [Key("idempotencyKey")] public string IdempotencyKey { get; set; } = ""; + [Key("count")] public int Count { get; set; } + + public static IncrementReceipt Accepted(string id, int count) => new() + { + ReceiptId = $"receipt:{id}", + CommandId = id, + IssuedAtUtc = DateTimeOffset.UtcNow.ToString("O"), + SourceVersion = count, + IdempotencyKey = id, + Count = count + }; +} + +[CultDocument("gamecult.eve.surface", "gamecult.eve.surface.v1")] +[MessagePackObject] +public sealed class CounterSurfaceDocument +{ + [Key("type")] public string Type { get; set; } = "surface-state"; + [Key("schema")] public string Schema { get; set; } = "gamecult.eve.surface.v1"; + [Key("providerId")] public string ProviderId { get; set; } = "sample.counter-provider"; + [Key("providerKind")] public string ProviderKind { get; set; } = "sample.daemon"; + [Key("title")] public string Title { get; set; } = "CultMesh browser counter"; + [Key("version")] public int Version { get; set; } = 1; + [Key("updatedAtUtc")] public string UpdatedAtUtc { get; set; } = "2026-08-17T00:00:00Z"; + [Key("surface")] public EveSurface Surface { get; set; } = new(); + [Key("commands")] public EveCommand[] Commands { get; set; } = []; + + public static CounterSurfaceDocument Create() => new() + { + Surface = new EveSurface + { + Id = "sample.counter", + Title = "Counter", + Root = new EveComponent + { + Id = "counter.root", + Kind = "column", + Children = + [ + new EveComponent + { + Id = "counter.value", + Kind = "metric", + Props = new Dictionary { ["label"] = "Canonical count", ["value"] = 0 }, + StateBindings = + [ + new EveStateBinding + { + TargetProp = "value", + PointerId = "sample.counter.count", + SourceId = "sample.counter_state:counter:main", + SchemaId = "sample.counter_state.v1", + RouteKind = "cultmesh" + } + ] + }, + new EveComponent + { + Id = "counter.increment", + Kind = "control.button", + Props = new Dictionary + { + ["label"] = "Increment", + ["command"] = "sample.counter.increment" + } + } + ] + } + }, + Commands = + [ + new EveCommand + { + Command = "sample.counter.increment", + Label = "Increment", + SurfaceId = "sample.counter" + } + ] + }; +} + +[MessagePackObject] +public sealed class EveSurface +{ + [Key("id")] public string Id { get; set; } = ""; + [Key("title")] public string Title { get; set; } = ""; + [Key("root")] public EveComponent Root { get; set; } = new(); + [Key("styles")] public Dictionary Styles { get; set; } = []; +} + +[MessagePackObject] +public sealed class EveComponent +{ + [Key("id")] public string Id { get; set; } = ""; + [Key("kind")] public string Kind { get; set; } = ""; + [Key("props")] public Dictionary Props { get; set; } = []; + [Key("children")] public EveComponent[] Children { get; set; } = []; + [Key("stateBindings")] public EveStateBinding[] StateBindings { get; set; } = []; +} + +[MessagePackObject] +public sealed class EveStateBinding +{ + [Key("targetProp")] public string TargetProp { get; set; } = ""; + [Key("pointerId")] public string PointerId { get; set; } = ""; + [Key("sourceId")] public string SourceId { get; set; } = ""; + [Key("schemaId")] public string SchemaId { get; set; } = ""; + [Key("routeKind")] public string RouteKind { get; set; } = ""; +} + +[MessagePackObject] +public sealed class EveCommand +{ + [Key("schema")] public string Schema { get; set; } = "gamecult.eve.command.v1"; + [Key("command")] public string Command { get; set; } = ""; + [Key("label")] public string Label { get; set; } = ""; + [Key("surfaceId")] public string SurfaceId { get; set; } = ""; + [Key("transport")] public string Transport { get; set; } = "cultmesh"; + [Key("authority")] public string Authority { get; set; } = "provider-daemon"; + [Key("result")] public string Result { get; set; } = "gamecult.eve.command_receipt.v1"; +} diff --git a/samples/eve-browser-network/README.md b/samples/eve-browser-network/README.md new file mode 100644 index 00000000..2d6c7034 --- /dev/null +++ b/samples/eve-browser-network/README.md @@ -0,0 +1,22 @@ +# Eve Browser + Headless Counter + +This is the real-process continuation of `samples/eve-two-runtime`: + +- one C# provider owns a durable `.cc` counter, the Eve surface, command + idempotency, and canonical receipts; +- one real Chromium page leases both documents through `cultmesh-browser` and + lowers the provider-owned Eve surface; +- one independent C# headless client observes the same typed counter; +- the browser and C# clients speak the same binary CultNet schema-v0 WebSocket + messages through the authenticated host adapter. + +Run the proof from the CultLib repository: + +```powershell +node scripts/verify-eve-browser-network.mjs --eve-root ..\Eve +``` + +The verifier clicks the Eve button twice with one idempotency key, requires one +state transition, restarts the provider, and requires the browser to rehydrate +the persisted count. Odin route discovery is represented by the browser +client's rendezvous port; a live Odin process remains the next discovery gate. diff --git a/samples/eve-browser-network/browser/index.html b/samples/eve-browser-network/browser/index.html new file mode 100644 index 00000000..d23ad8ab --- /dev/null +++ b/samples/eve-browser-network/browser/index.html @@ -0,0 +1,13 @@ + + + + + + CultMesh Eve browser counter + + +

    Connecting to the Verse…
    + + + + diff --git a/samples/eve-browser-network/browser/main.ts b/samples/eve-browser-network/browser/main.ts new file mode 100644 index 00000000..7bcb6887 --- /dev/null +++ b/samples/eve-browser-network/browser/main.ts @@ -0,0 +1,84 @@ +import { parseEveCommandReceipt, parseEveSurfaceDocument } from "@gamecult/eve-contracts"; +import { renderEveSurface } from "@gamecult/eve-browser-lowering"; +import { + CultMeshBrowserClient, + decodeCultNetOperationPayload, + decodeCultNetPayload, +} from "cultmesh-browser"; + +declare global { + interface Window { + __sampleReady?: boolean; + __sampleCount?: number; + __sampleReceipt?: { receiptId: string; count: number }; + __sampleError?: string; + } +} + +const params = new URLSearchParams(location.search); +const endpoint = params.get("endpoint"); +const token = params.get("token") || "sample-session"; +if (!endpoint) throw new Error("The sample requires an endpoint query parameter."); +document.cookie = `cultnet_session=${encodeURIComponent(token)}; Path=/; SameSite=Strict`; + +const host = document.querySelector("#surface")!; +const receiptOutput = document.querySelector("#receipt")!; + +try { + const mesh = await CultMeshBrowserClient.connect({ + verseId: "sample.counter", + providerId: "sample.counter-provider", + runtimeId: "sample.chromium", + rendezvous: { + resolve: async identity => ({ ...identity, endpoint }), + }, + }); + const counter = await mesh.leaseRawDocument({ + schemaId: "sample.counter_state.v1", + recordKey: "counter:main", + subscriptionId: "browser-counter", + }); + const surface = await mesh.leaseRawDocument({ + schemaId: "gamecult.eve.surface.v1", + recordKey: "sample.counter", + subscriptionId: "browser-surface", + }); + const currentSurface = parseEveSurfaceDocument(decodeCultNetPayload(surface.current!)); + renderEveSurface(currentSurface, host, { + activeSurfaceId: "sample.counter", + clientId: "sample.chromium", + commandSink: async intent => { + const response = await mesh.invoke({ + serviceId: "sample.counter", + operation: intent.command, + payloadSchema: "sample.increment.v1", + payload: { amount: 1 }, + idempotencyKey: "browser-click-1", + }); + const receipt = parseEveCommandReceipt(decodeCultNetOperationPayload(response)) as { + receiptId: string; + count: number; + }; + window.__sampleReceipt = receipt; + receiptOutput.textContent = receipt.receiptId; + }, + stateBindingResolver: async binding => { + if (binding.pointerId !== "sample.counter.count") return undefined; + return { + latest: async () => decodeCultNetPayload<{ count: number }>(counter.current!).count, + watch: callback => counter.watch(record => { + if (!record) return; + const count = decodeCultNetPayload<{ count: number }>(record).count; + window.__sampleCount = count; + callback(count); + }), + }; + }, + }); + window.__sampleCount = decodeCultNetPayload<{ count: number }>(counter.current!).count; + window.__sampleReady = true; +} catch (error) { + window.__sampleError = error instanceof Error ? error.stack || error.message : String(error); + host.textContent = window.__sampleError; + throw error; +} diff --git a/scripts/run-typescript-workspaces.mjs b/scripts/run-typescript-workspaces.mjs index f2cf74bc..933079da 100644 --- a/scripts/run-typescript-workspaces.mjs +++ b/scripts/run-typescript-workspaces.mjs @@ -6,7 +6,7 @@ if (!command) throw new Error("Usage: node scripts/run-typescript-workspaces.mjs const npmCli = process.env.npm_execpath ?? join(dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js"); -const workspaces = ["cultcache-ts", "cultnet-ts", "cultmesh-ts"]; +const workspaces = ["cultcache-ts", "cultnet-ts", "cultmesh-ts", "cultmesh-browser"]; const childEnv = process.platform === "win32" ? { ...process.env, diff --git a/scripts/test-typescript-package-closure.mjs b/scripts/test-typescript-package-closure.mjs index c56a13a6..e5648c9c 100644 --- a/scripts/test-typescript-package-closure.mjs +++ b/scripts/test-typescript-package-closure.mjs @@ -6,7 +6,7 @@ import { dirname, join, resolve } from "node:path"; import { fileURLToPath } from "node:url"; const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), ".."); -const workspacePackages = ["cultcache-ts", "cultnet-ts", "cultmesh-ts"]; +const workspacePackages = ["cultcache-ts", "cultnet-ts", "cultmesh-ts", "cultmesh-browser"]; const npmCli = process.env.npm_execpath ?? join(dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js"); const childEnv = process.platform === "win32" @@ -69,6 +69,17 @@ assert.deepEqual(mesh.CultMesh.vec2(3, 4), { x: 3, y: 4 }); `); execFileSync(process.execPath, ["runtime-smoke.cjs"], { cwd: consumerRoot, stdio: "inherit" }); + writeFileSync(join(consumerRoot, "browser-runtime-smoke.mjs"), ` +import assert from "node:assert/strict"; +import { CultMeshBrowserClient, decodeCultNetPayload } from "cultmesh-browser"; +import { parseCultNetMessage } from "cultnet-ts/contracts"; +assert.equal(typeof CultMeshBrowserClient.connect, "function"); +assert.equal(typeof decodeCultNetPayload, "function"); +assert.equal(typeof parseCultNetMessage, "function"); +assert.equal("putDocument" in CultMeshBrowserClient.prototype, false); +`); + execFileSync(process.execPath, ["browser-runtime-smoke.mjs"], { cwd: consumerRoot, stdio: "inherit" }); + writeFileSync(join(consumerRoot, "types-smoke.ts"), ` import { defineDocumentType } from "cultcache-ts"; import { CultNetPeer } from "cultnet-ts"; @@ -111,6 +122,37 @@ void providerTransport; "types-smoke.ts", ], { cwd: consumerRoot, stdio: "inherit" }); + writeFileSync(join(consumerRoot, "browser-types-smoke.mts"), ` +import { + CultMeshBrowserClient, + type CultMeshBrowserIdentity, + type CultMeshRawDocumentLeaseOptions, +} from "cultmesh-browser"; + +const identity: CultMeshBrowserIdentity = { + verseId: "smoke", + providerId: "smoke.provider", +}; +const lease: CultMeshRawDocumentLeaseOptions = { + schemaId: "smoke.document.v1", + recordKey: "smoke:main", +}; +const clientType: typeof CultMeshBrowserClient = CultMeshBrowserClient; +void identity; +void lease; +void clientType; +`); + execFileSync(process.execPath, [ + tsc, + "--noEmit", + "--strict", + "--target", "ES2022", + "--module", "NodeNext", + "--moduleResolution", "NodeNext", + "--skipLibCheck", + "browser-types-smoke.mts", + ], { cwd: consumerRoot, stdio: "inherit" }); + console.log("TypeScript package closure smoke: passed"); for (const tarball of tarballs) console.log(`Packed: ${tarball}`); } finally { diff --git a/scripts/verify-eve-browser-network.mjs b/scripts/verify-eve-browser-network.mjs new file mode 100644 index 00000000..d4e9fa2c --- /dev/null +++ b/scripts/verify-eve-browser-network.mjs @@ -0,0 +1,198 @@ +import assert from "node:assert/strict"; +import { spawn } from "node:child_process"; +import { createServer as createHttpServer } from "node:http"; +import { mkdtemp, readFile, rm } from "node:fs/promises"; +import { createServer as createNetServer } from "node:net"; +import { tmpdir } from "node:os"; +import { dirname, join, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +import { build } from "esbuild"; +import { chromium } from "playwright-core"; + +const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), ".."); +const eveFlag = process.argv.indexOf("--eve-root"); +const eveRoot = resolve(eveFlag >= 0 ? process.argv[eveFlag + 1] : join(repoRoot, "..", "Eve")); +const sampleRoot = join(repoRoot, "samples", "eve-browser-network"); +const workRoot = await mkdtemp(join(tmpdir(), "cultmesh-browser-network-")); +const statePath = join(workRoot, "counter.cc"); +const bundlePath = join(workRoot, "bundle.js"); +const token = "sample-session"; +let provider; +let headless; +let httpServer; +let browser; + +try { + const tsc = join(repoRoot, "node_modules", "typescript", "bin", "tsc"); + await run(process.execPath, [tsc, "-p", join(repoRoot, "packages", "cultnet-ts", "tsconfig.json"), "--pretty", "false"]); + await run(process.execPath, [tsc, "-p", join(repoRoot, "packages", "cultmesh-browser", "tsconfig.json"), "--pretty", "false"]); + await build({ + entryPoints: [join(sampleRoot, "browser", "main.ts")], + outfile: bundlePath, + bundle: true, + format: "esm", + platform: "browser", + target: "es2022", + sourcemap: true, + alias: { + "@gamecult/eve-contracts": join(eveRoot, "packages", "eve-contracts", "src", "index.ts"), + "@gamecult/eve-browser-lowering": join(eveRoot, "packages", "eve-browser-lowering", "src", "index.ts"), + }, + logLevel: "warning", + }); + const bundle = await readFile(bundlePath, "utf8"); + assert.doesNotMatch(bundle, /(?:from\s*["']node:|require\(["']node:)/u, "browser bundle contains a Node builtin import"); + + await run("dotnet", ["build", join(sampleRoot, "EveBrowserNetworkSample.csproj"), "--verbosity", "quiet"]); + const providerPort = await freePort(); + const httpPort = await freePort(); + provider = await startProvider(providerPort); + const endpoint = await provider.waitFor("PROVIDER_READY "); + headless = startDotnet(["headless", "--endpoint", endpoint, "--token", token]); + await headless.waitFor("HEADLESS_READY "); + httpServer = await serve(httpPort, sampleRoot, bundlePath); + + const executablePath = process.env.CHROME_PATH || "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe"; + browser = await chromium.launch({ executablePath, headless: true }); + let page = await browser.newPage(); + const url = `http://127.0.0.1:${httpPort}/?endpoint=${encodeURIComponent(endpoint)}&token=${token}`; + await page.goto(url); + await page.waitForFunction(() => window.__sampleReady || window.__sampleError); + assert.equal(await page.evaluate(() => window.__sampleError), undefined); + assert.equal(await page.evaluate(() => window.__sampleCount), 0); + await page.locator("button").click(); + await page.waitForFunction(() => window.__sampleReceipt?.count === 1 && window.__sampleCount === 1); + const firstReceipt = await page.evaluate(() => window.__sampleReceipt?.receiptId); + assert.equal(JSON.parse(await headless.waitFor("HEADLESS_UPDATE ")).count, 1); + await page.locator("button").click(); + await page.waitForFunction(receipt => window.__sampleReceipt?.receiptId === receipt, firstReceipt); + assert.equal(await page.evaluate(() => window.__sampleCount), 1, "duplicate idempotency key changed canonical state"); + + await page.close(); + await stop(provider.process); + provider = await startProvider(providerPort); + const restartedEndpoint = await provider.waitFor("PROVIDER_READY "); + assert.equal(restartedEndpoint, endpoint); + page = await browser.newPage(); + await page.goto(url); + await page.waitForFunction(() => window.__sampleReady || window.__sampleError); + assert.equal(await page.evaluate(() => window.__sampleError), undefined); + assert.equal(await page.evaluate(() => window.__sampleCount), 1, "provider restart lost durable counter state"); + + console.log(JSON.stringify({ + providerEndpoint: endpoint, + browserRuntime: "chromium", + headlessRuntime: "csharp", + receiptId: firstReceipt, + count: 1, + restartCount: 1, + })); +} finally { + if (browser) await browser.close().catch(() => undefined); + if (headless) await stop(headless.process); + if (provider) await stop(provider.process); + if (httpServer) await new Promise(resolve => httpServer.close(resolve)); + await rm(workRoot, { recursive: true, force: true }); +} + +async function startProvider(port) { + return startDotnet(["provider", "--port", String(port), "--state", statePath, "--token", token]); +} + +function startDotnet(arguments_) { + const process = spawn("dotnet", [ + "run", "--no-build", "--project", join(sampleRoot, "EveBrowserNetworkSample.csproj"), "--", ...arguments_, + ], { cwd: repoRoot, stdio: ["ignore", "pipe", "pipe"] }); + let output = ""; + let error = ""; + const waiters = []; + process.stdout.setEncoding("utf8"); + process.stderr.setEncoding("utf8"); + process.stdout.on("data", chunk => { output += chunk; settle(); }); + process.stderr.on("data", chunk => { error += chunk; }); + process.on("exit", code => { + for (const waiter of waiters.splice(0)) { + clearTimeout(waiter.timer); + waiter.reject(new Error(`dotnet sample exited ${code}\n${output}\n${error}`)); + } + }); + function settle() { + for (let index = waiters.length - 1; index >= 0; index--) { + const waiter = waiters[index]; + const line = output.split(/\r?\n/u).find(value => value.startsWith(waiter.prefix)); + if (!line) continue; + waiters.splice(index, 1); + clearTimeout(waiter.timer); + waiter.resolve(line.slice(waiter.prefix.length)); + } + } + return { + process, + waitFor(prefix, timeoutMs = 30_000) { + const existing = output.split(/\r?\n/u).find(value => value.startsWith(prefix)); + if (existing) return Promise.resolve(existing.slice(prefix.length)); + return new Promise((resolve, reject) => { + const waiter = { + prefix, + resolve, + reject, + timer: setTimeout(() => { + const index = waiters.indexOf(waiter); + if (index >= 0) waiters.splice(index, 1); + reject(new Error(`Timed out waiting for '${prefix}'.\n${output}\n${error}`)); + }, timeoutMs), + }; + waiters.push(waiter); + }); + }, + }; +} + +function run(command, arguments_) { + return new Promise((resolvePromise, reject) => { + const process = spawn(command, arguments_, { cwd: repoRoot, stdio: "inherit" }); + process.on("error", reject); + process.on("exit", code => code === 0 ? resolvePromise() : reject(new Error(`${command} exited ${code}`))); + }); +} + +async function serve(port, root, builtBundle) { + const index = await readFile(join(root, "browser", "index.html")); + const server = createHttpServer(async (request, response) => { + if (request.url?.startsWith("/bundle.js")) { + response.setHeader("Content-Type", "text/javascript; charset=utf-8"); + response.end(await readFile(builtBundle)); + return; + } + response.setHeader("Content-Type", "text/html; charset=utf-8"); + response.end(index); + }); + await new Promise((resolvePromise, reject) => { + server.once("error", reject); + server.listen(port, "127.0.0.1", resolvePromise); + }); + return server; +} + +async function freePort() { + const server = createNetServer(); + await new Promise((resolvePromise, reject) => { + server.once("error", reject); + server.listen(0, "127.0.0.1", resolvePromise); + }); + const address = server.address(); + const port = typeof address === "object" && address ? address.port : 0; + await new Promise(resolvePromise => server.close(resolvePromise)); + return port; +} + +async function stop(process) { + if (!process || process.exitCode !== null) return; + process.kill(); + await Promise.race([ + new Promise(resolvePromise => process.once("exit", resolvePromise)), + new Promise(resolvePromise => setTimeout(resolvePromise, 2_000)), + ]); + if (process.exitCode === null) process.kill("SIGKILL"); +} diff --git a/src/GameCult.Mesh/docs/browser-verse-transport.md b/src/GameCult.Mesh/docs/browser-verse-transport.md index c8586021..81934139 100644 --- a/src/GameCult.Mesh/docs/browser-verse-transport.md +++ b/src/GameCult.Mesh/docs/browser-verse-transport.md @@ -4,23 +4,38 @@ Date: 2026-08-17 ## Status -This is the implementation map for the missing real-browser checkpoint. The -current `samples/eve-two-runtime` proof uses jsdom and one local TypeScript -CultMesh node. It is a clean package-consumer and contract-validation proof, -not browser networking. +This is the implementation map for the browser Verse boundary. +`samples/eve-two-runtime` remains the clean package-consumer/jsdom checkpoint. +`samples/eve-browser-network` runs a durable C# provider, a real Chromium Eve +lowerer, and an independent C# headless observer over the same authenticated +binary CultNet WebSocket route. It proves one canonical command effect, +idempotent retry, shared observation, and provider restart. -The current substrate is incomplete: +The current substrate has a browser client boundary and local live proof, but +not a complete public Verse proof: - `cultmesh-ts` is a Node package and imports `node:dgram` at its root; -- `cultnet-ts` mixes browser-safe schema contracts with Node transport, - filesystem, crypto, stream, and UDP modules; +- `cultnet-ts/contracts` is the browser-safe contract entrypoint; the package + root still includes Node transport, filesystem, crypto, stream, and UDP + modules and must not enter browser bundles; - C# and TypeScript now share `cultnet.database_subscribe.v0`, `cultnet.database_unsubscribe.v0`, and `cultnet.database_change_raw.v0`; - the browser-safe transport package that consumes them does not exist yet; -- Kotlin has a channel-aware WebSocket transport adapter; C# and TypeScript do - not expose the equivalent browser/server pair; + `cultmesh-browser` consumes those messages as explicit document leases; +- `cultmesh-browser` owns stable identity, route refresh, resubscription, and + typed operation correlation without exposing direct document writes; +- Kotlin has a channel-aware WebSocket transport adapter, TypeScript has the + browser client, and `GameCult.Networking.WebSockets` provides the bounded C# + schema server host adapter; - Hermodr can lower Odin state into a browser, but it is an infrastructure - runtime, not the missing clean-consumer game API. + runtime, not the clean-consumer game API; +- the sample rendezvous port currently returns one configured local route; + discovery from a live Odin and automatic route rotation are not yet in the + executable cross-runtime gate. +- the sample validates its surface against Eve's canonical TypeScript contract, + but its provider still carries a minimal local C# DTO mirror. The + released-artifact gate requires the renderer-neutral C# Eve surface contract + as an independently consumable Eve artifact; Unity must not be that contract's + package owner. ## Authority Map @@ -83,12 +98,13 @@ Shared paths: Deletion line: -- stop calling jsdom a browser runtime; -- split browser-safe CultNet contracts from the Node transport package; -- add the missing subscription messages to the shared generated contract - catalog instead of retyping them in a browser adapter; -- do not retain a sample-only WebSocket protocol after the canonical adapter - exists. +- the jsdom checkpoint remains labeled as a Node-hosted DOM proof; +- browser applications import `cultmesh-browser` and + `cultnet-ts/contracts`, never the Node-only package roots; +- subscription messages remain one shared schema contract across the C# and + TypeScript catalogs; +- the real provider adapter must consume the canonical WebSocket message lane; + no sample-only WebSocket protocol is permitted. ## Required Runtime Shape @@ -96,16 +112,24 @@ The browser-facing package must be importable by a standards-mode browser or a normal bundler without Node polyfills. It exposes a narrow API shaped like: ```ts -const mesh = await CultMeshBrowser.connect({ +const mesh = await CultMeshBrowserClient.connect({ rendezvous: odin, verseId: "sample.counter", providerId: "sample.counter-provider", + runtimeId: "sample.browser", }); -using surface = await mesh.leaseDocument(eveSurface, "eve:surface:counter"); -surface.watch(render); +using surface = await mesh.leaseRawDocument({ + schemaId: "gamecult.eve.surface.v1", + recordKey: "eve:surface:counter", +}); +surface.watch(record => render(decodeCultNetPayload(record))); -const receipt = await mesh.invoke(incrementCounter, {}, { +const receipt = await mesh.invoke({ + serviceId: "sample.counter", + operation: "increment", + payloadSchema: "sample.increment.v1", + payload: {}, idempotencyKey: crypto.randomUUID(), }); ``` @@ -136,6 +160,20 @@ identity, authority, and idempotency validation happen before provider code. ## Acceptance Gate +Current executable coverage from `scripts/verify-eve-browser-network.mjs`: + +- authenticated binary C# WebSocket provider; +- real Chromium and independent C# headless consumers; +- shared surface and counter document leases; +- Eve button to typed operation to provider receipt to shared state; +- duplicate idempotency key produces one effect; +- provider restart rehydrates the `.cc` state; +- generated browser bundle contains no `node:` builtin import. + +The full public Verse gate still requires live Odin discovery, physical route +rotation during retained leases, released-artifact-only .NET consumption, and +Windows/Linux CI. + From an empty temporary consumer using packed/released artifacts only: 1. start a provider daemon with one durable counter document and one validated diff --git a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md index d16f21c1..e38aa8c3 100644 --- a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md +++ b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md @@ -61,11 +61,17 @@ cd E:\Projects\EveUnity powershell -ExecutionPolicy Bypass -File .\scripts\run-release-consumer-tests.ps1 ``` -This checkpoint proves clean package consumption, canonical Eve contract +This first checkpoint proves clean package consumption, canonical Eve contract validation, and two independent lowering/observation consumers inside Node. It does **not** claim a real browser process, an Odin-discovered network hop, or -cross-language command execution. Those are the next public Verse conformance -gates; do not cite this sample as evidence that they exist. Their owner map and -executable acceptance contract are recorded in +cross-language command execution. Do not cite it as evidence for those layers. + +The next executable checkpoint is +[`samples/eve-browser-network`](../../../../samples/eve-browser-network/README.md). +It runs a durable C# provider, a real Chromium Eve lowerer, and an independent +C# headless observer over the same authenticated binary CultNet WebSocket lane. +It proves command idempotency and provider restart. Live Odin discovery and +route rotation remain separate gates. Their owner map and full acceptance +contract are recorded in [`browser-verse-transport.md`](../browser-verse-transport.md). diff --git a/src/GameCult.Networking.WebSockets/CultNetWebSocketSchemaClient.cs b/src/GameCult.Networking.WebSockets/CultNetWebSocketSchemaClient.cs new file mode 100644 index 00000000..2e778a0a --- /dev/null +++ b/src/GameCult.Networking.WebSockets/CultNetWebSocketSchemaClient.cs @@ -0,0 +1,166 @@ +using System.Collections.Concurrent; +using System.Net.WebSockets; +using GameCult.Networking; + +namespace GameCult.Networking.WebSockets; + +/// Schema-v0 client over a binary WebSocket route. +public sealed class CultNetWebSocketSchemaClient : ICultNetSchemaClient, ICultNetSchemaClientHealth +{ + private readonly ConcurrentDictionary> _handlers = new(); + private readonly object _handlerGate = new(); + private readonly SemaphoreSlim _sendGate = new(1, 1); + private readonly CancellationTokenSource _shutdown = new(); + private readonly TaskCompletionSource _backgroundFailure = new( + TaskCreationOptions.RunContinuationsAsynchronously); + private readonly Action? _configure; + private readonly int _maxMessageBytes; + private ClientWebSocket? _socket; + private bool _disposed; + + /// Creates a binary WebSocket schema client. + public CultNetWebSocketSchemaClient( + Action? configure = null, + int maxMessageBytes = 4 * 1024 * 1024) + { + if (maxMessageBytes <= 0) throw new ArgumentOutOfRangeException(nameof(maxMessageBytes)); + _configure = configure; + _maxMessageBytes = maxMessageBytes; + } + + /// + public bool Connected => !_disposed && _socket?.State == WebSocketState.Open; + + /// + public Task BackgroundFailure => _backgroundFailure.Task; + + /// + public void Connect(string host, int port) + { + ArgumentException.ThrowIfNullOrWhiteSpace(host); + if (port <= 0 || port > 65535) throw new ArgumentOutOfRangeException(nameof(port)); + ConnectAsync(new Uri($"ws://{host}:{port}/cultmesh"), CancellationToken.None) + .GetAwaiter().GetResult(); + } + + /// Connects to an exact WebSocket route. + public async Task ConnectAsync(Uri endpoint, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(endpoint); + if (endpoint.Scheme is not ("ws" or "wss")) + throw new ArgumentException("CultNet WebSocket endpoint must use ws:// or wss://.", nameof(endpoint)); + ThrowIfDisposed(); + if (_socket != null) throw new InvalidOperationException("CultNet WebSocket client is already connected."); + var socket = new ClientWebSocket(); + _configure?.Invoke(socket.Options); + try + { + await socket.ConnectAsync(endpoint, cancellationToken).ConfigureAwait(false); + _socket = socket; + _ = ReceiveLoopAsync(socket, _shutdown.Token); + } + catch + { + socket.Dispose(); + throw; + } + } + + /// + public void SendCultNet(T message) where T : ICultNetSchemaMessage + { + ArgumentNullException.ThrowIfNull(message); + ThrowIfDisposed(); + var socket = _socket; + if (socket?.State != WebSocketState.Open) + throw new InvalidOperationException("CultNet WebSocket client is not connected."); + var payload = CultNetSchemaMessageSerialization.Serialize(message); + if (payload.Length > _maxMessageBytes) + throw new InvalidOperationException( + $"CultNet message exceeds the {_maxMessageBytes}-byte WebSocket limit."); + _sendGate.Wait(); + try + { + CultNetWebSocketMessageIO.SendAsync(socket, payload, _shutdown.Token).GetAwaiter().GetResult(); + } + finally + { + _sendGate.Release(); + } + } + + /// + public void OnCultNet(Action callback) where T : ICultNetSchemaMessage + { + ArgumentNullException.ThrowIfNull(callback); + ThrowIfDisposed(); + lock (_handlerGate) + { + if (!_handlers.TryGetValue(typeof(T), out var handlers)) + _handlers[typeof(T)] = handlers = new List(); + handlers.Add(callback); + } + } + + /// + public void Dispose() + { + if (_disposed) return; + _disposed = true; + _shutdown.Cancel(); + var socket = _socket; + _socket = null; + try + { + if (socket?.State is WebSocketState.Open or WebSocketState.CloseReceived) + { + using var closeTimeout = new CancellationTokenSource(TimeSpan.FromSeconds(1)); + socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "CultNet client disposed", closeTimeout.Token) + .GetAwaiter().GetResult(); + } + } + catch (Exception error) when (error is WebSocketException or OperationCanceledException) + { + socket?.Abort(); + } + socket?.Dispose(); + _sendGate.Dispose(); + _shutdown.Dispose(); + } + + private async Task ReceiveLoopAsync(WebSocket socket, CancellationToken cancellationToken) + { + try + { + while (!_disposed && socket.State == WebSocketState.Open && !cancellationToken.IsCancellationRequested) + { + var payload = await CultNetWebSocketMessageIO.ReceiveAsync(socket, _maxMessageBytes, cancellationToken) + .ConfigureAwait(false); + if (payload == null) return; + Dispatch(CultNetSchemaMessageSerialization.Deserialize(payload)); + } + } + catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) + { + } + catch (Exception error) when (!_disposed) + { + _backgroundFailure.TrySetResult(error); + } + } + + private void Dispatch(ICultNetSchemaMessage message) + { + Delegate[] handlers; + lock (_handlerGate) + handlers = _handlers.TryGetValue(message.GetType(), out var registered) + ? registered.ToArray() + : Array.Empty(); + foreach (var handler in handlers) handler.DynamicInvoke(message); + } + + private void ThrowIfDisposed() + { + ObjectDisposedException.ThrowIf(_disposed, this); + } +} diff --git a/src/GameCult.Networking.WebSockets/CultNetWebSocketSchemaServer.cs b/src/GameCult.Networking.WebSockets/CultNetWebSocketSchemaServer.cs new file mode 100644 index 00000000..240311a1 --- /dev/null +++ b/src/GameCult.Networking.WebSockets/CultNetWebSocketSchemaServer.cs @@ -0,0 +1,260 @@ +using System.Collections.Concurrent; +using System.Net; +using System.Net.WebSockets; +using GameCult.Networking; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace GameCult.Networking.WebSockets; + +/// Controls the bounded CultNet schema-v0 WebSocket endpoint. +public sealed class CultNetWebSocketEndpointOptions +{ + /// Maximum accepted binary CultNet message size. + public int MaxMessageBytes { get; init; } = 4 * 1024 * 1024; + + /// + /// Authorizes the HTTP upgrade before it can become a CultNet peer. Production hosts + /// should bind this to their authenticated session middleware. + /// + public Func>? AuthorizeAsync { get; init; } + + /// Allows an unauthenticated endpoint for explicit local development only. + public bool AllowAnonymousDevelopment { get; init; } +} + +/// +/// Adapts one binary WebSocket endpoint to the transport-neutral CultNet schema server port. +/// The host owns HTTP, TLS, and authentication; this adapter owns bounded binary message +/// assembly, schema validation, handler dispatch, peer lifetime, and serialized sends. +/// +public sealed class CultNetWebSocketSchemaServer : + ICultNetSchemaServer, + ICultNetSchemaServerPeerLifecycle, + IAsyncDisposable +{ + private readonly ConcurrentDictionary _handlers = new(); + private readonly ConcurrentDictionary _peers = new(); + private bool _disposed; + + /// + public event Action? PeerDisconnected; + + /// Gets the active upgraded peer count. + public int PeerCount => _peers.Count; + + /// + public void OnCultNet(Func callback) + where TMessage : ICultNetSchemaMessage + { + ArgumentNullException.ThrowIfNull(callback); + ThrowIfDisposed(); + _handlers[typeof(TMessage)] = callback; + } + + /// + public void RemoveCultNetMessageListener(Delegate callback) + where TMessage : ICultNetSchemaMessage + { + if (_handlers.TryGetValue(typeof(TMessage), out var existing) && existing == callback) + _handlers.TryRemove(typeof(TMessage), out _); + } + + /// Serves one already-authorized WebSocket until it closes. + public async Task AcceptAsync( + WebSocket socket, + EndPoint? remoteEndPoint = null, + int maxMessageBytes = 4 * 1024 * 1024, + CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(socket); + ThrowIfDisposed(); + if (maxMessageBytes <= 0) throw new ArgumentOutOfRangeException(nameof(maxMessageBytes)); + var peer = new WebSocketPeer(socket, remoteEndPoint, maxMessageBytes); + if (!_peers.TryAdd(peer, 0)) throw new InvalidOperationException("CultNet WebSocket peer already exists."); + try + { + while (!_disposed && socket.State == WebSocketState.Open && !cancellationToken.IsCancellationRequested) + { + var payload = await CultNetWebSocketMessageIO.ReceiveAsync(socket, maxMessageBytes, cancellationToken) + .ConfigureAwait(false); + if (payload == null) break; + var message = CultNetSchemaMessageSerialization.Deserialize(payload); + if (!_handlers.TryGetValue(message.GetType(), out var handler)) continue; + if (handler.DynamicInvoke(message, peer) is Task task) await task.ConfigureAwait(false); + } + } + catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) + { + } + finally + { + if (_peers.TryRemove(peer, out _)) PeerDisconnected?.Invoke(peer); + await peer.DisposeAsync().ConfigureAwait(false); + } + } + + /// + public async ValueTask DisposeAsync() + { + if (_disposed) return; + _disposed = true; + var peers = _peers.Keys.ToArray(); + _peers.Clear(); + foreach (var peer in peers) + { + PeerDisconnected?.Invoke(peer); + await peer.DisposeAsync().ConfigureAwait(false); + } + _handlers.Clear(); + } + + private void ThrowIfDisposed() + { + ObjectDisposedException.ThrowIf(_disposed, this); + } + + private sealed class WebSocketPeer : + ICultNetSchemaServerPeer, + ICultNetSchemaServerPeerLocation, + IAsyncDisposable + { + private readonly WebSocket _socket; + private readonly SemaphoreSlim _sendGate = new(1, 1); + private readonly int _maxMessageBytes; + private bool _disposed; + + public WebSocketPeer(WebSocket socket, EndPoint? remoteEndPoint, int maxMessageBytes) + { + _socket = socket; + RemoteEndPoint = remoteEndPoint; + _maxMessageBytes = maxMessageBytes; + } + + public EndPoint? RemoteEndPoint { get; } + + public void SendCultNet(TMessage message) where TMessage : ICultNetSchemaMessage + { + ArgumentNullException.ThrowIfNull(message); + if (_disposed || _socket.State != WebSocketState.Open) + throw new InvalidOperationException("CultNet WebSocket peer is not open."); + var payload = CultNetSchemaMessageSerialization.Serialize(message); + if (payload.Length > _maxMessageBytes) + throw new InvalidOperationException( + $"CultNet message exceeds the {_maxMessageBytes}-byte WebSocket limit."); + _sendGate.Wait(); + try + { + CultNetWebSocketMessageIO.SendAsync(_socket, payload, CancellationToken.None) + .GetAwaiter().GetResult(); + } + finally + { + _sendGate.Release(); + } + } + + public async ValueTask DisposeAsync() + { + if (_disposed) return; + _disposed = true; + try + { + if (_socket.State is WebSocketState.Open or WebSocketState.CloseReceived) + { + using var closeTimeout = new CancellationTokenSource(TimeSpan.FromSeconds(1)); + await _socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "CultNet peer closed", closeTimeout.Token) + .ConfigureAwait(false); + } + } + catch (Exception error) when (error is WebSocketException or OperationCanceledException) + { + _socket.Abort(); + } + _socket.Dispose(); + _sendGate.Dispose(); + } + } +} + +internal static class CultNetWebSocketMessageIO +{ + public static Task SendAsync(WebSocket socket, byte[] payload, CancellationToken cancellationToken) => + socket.SendAsync(payload, WebSocketMessageType.Binary, true, cancellationToken); + + public static async Task ReceiveAsync( + WebSocket socket, + int maxMessageBytes, + CancellationToken cancellationToken) + { + var segment = new byte[Math.Min(16 * 1024, maxMessageBytes)]; + using var message = new MemoryStream(); + while (true) + { + var result = await socket.ReceiveAsync(segment, cancellationToken).ConfigureAwait(false); + if (result.MessageType == WebSocketMessageType.Close) return null; + if (result.MessageType != WebSocketMessageType.Binary) + { + await socket.CloseAsync( + WebSocketCloseStatus.InvalidMessageType, + "CultNet requires binary MessagePack WebSocket messages.", + cancellationToken).ConfigureAwait(false); + return null; + } + if (message.Length + result.Count > maxMessageBytes) + { + await socket.CloseAsync( + WebSocketCloseStatus.MessageTooBig, + "CultNet message exceeds the configured maximum.", + cancellationToken).ConfigureAwait(false); + return null; + } + message.Write(segment, 0, result.Count); + if (result.EndOfMessage) return message.ToArray(); + } + } +} + +/// ASP.NET Core endpoint mapping for the CultNet WebSocket schema server. +public static class CultNetWebSocketEndpointRouteBuilderExtensions +{ + /// Maps one authenticated binary CultNet WebSocket endpoint. + public static IEndpointConventionBuilder MapCultNetWebSocket( + this IEndpointRouteBuilder endpoints, + string pattern, + CultNetWebSocketSchemaServer server, + CultNetWebSocketEndpointOptions options) + { + ArgumentNullException.ThrowIfNull(endpoints); + ArgumentException.ThrowIfNullOrWhiteSpace(pattern); + ArgumentNullException.ThrowIfNull(server); + ArgumentNullException.ThrowIfNull(options); + if (options.MaxMessageBytes <= 0) throw new ArgumentOutOfRangeException(nameof(options.MaxMessageBytes)); + if (options.AuthorizeAsync == null && !options.AllowAnonymousDevelopment) + throw new InvalidOperationException( + "CultNet WebSocket endpoints require AuthorizeAsync unless AllowAnonymousDevelopment is explicitly enabled."); + + return endpoints.Map(pattern, async context => + { + if (!context.WebSockets.IsWebSocketRequest) + { + context.Response.StatusCode = StatusCodes.Status426UpgradeRequired; + return; + } + if (options.AuthorizeAsync != null && !await options.AuthorizeAsync(context).ConfigureAwait(false)) + { + context.Response.StatusCode = StatusCodes.Status401Unauthorized; + return; + } + using var socket = await context.WebSockets.AcceptWebSocketAsync().ConfigureAwait(false); + await server.AcceptAsync( + socket, + context.Connection.RemoteIpAddress == null + ? null + : new IPEndPoint(context.Connection.RemoteIpAddress, context.Connection.RemotePort), + options.MaxMessageBytes, + context.RequestAborted).ConfigureAwait(false); + }); + } +} diff --git a/src/GameCult.Networking.WebSockets/GameCult.Networking.WebSockets.csproj b/src/GameCult.Networking.WebSockets/GameCult.Networking.WebSockets.csproj new file mode 100644 index 00000000..40214247 --- /dev/null +++ b/src/GameCult.Networking.WebSockets/GameCult.Networking.WebSockets.csproj @@ -0,0 +1,12 @@ + + + net10.0 + enable + enable + CultNet schema-v0 WebSocket host adapter for browser and web runtimes + + + + + + diff --git a/src/GameCult.Networking/README.md b/src/GameCult.Networking/README.md index c7c4792f..cf463e72 100644 --- a/src/GameCult.Networking/README.md +++ b/src/GameCult.Networking/README.md @@ -390,6 +390,21 @@ peer lookup and handshake before returning the same RUDP transport. Packet semantics, schema-channel send/receive helpers, and reconnect state still live in `GameCult.Networking`. +## Browser WebSocket Host + +`GameCult.Networking.WebSockets` keeps ASP.NET Core hosting out of the +netstandard CultNet core while adapting an authenticated binary WebSocket to +the same `ICultNetSchemaServer` and `ICultNetSchemaClient` ports. A host calls +`UseWebSockets()` and maps `MapCultNetWebSocket(...)` with an authorization +predicate. Anonymous use requires the explicit `AllowAnonymousDevelopment` +opt-in. Text frames and messages over the configured size bound are closed +before schema dispatch. + +The matching `CultNetWebSocketSchemaClient` is suitable for C# headless and +service consumers. Browser applications use `cultmesh-browser`, which owns +stable Verse/provider identity, document leases, resubscription, and operation +correlation above the raw WebSocket route. + ## Important Constraints - `Server` currently centers on `PlayerData` as the built-in account model. diff --git a/tests/GameCult.Networking.WebSockets.Tests/CultNetWebSocketSchemaServerTests.cs b/tests/GameCult.Networking.WebSockets.Tests/CultNetWebSocketSchemaServerTests.cs new file mode 100644 index 00000000..74fc2f59 --- /dev/null +++ b/tests/GameCult.Networking.WebSockets.Tests/CultNetWebSocketSchemaServerTests.cs @@ -0,0 +1,95 @@ +using System.Net; +using GameCult.Networking.WebSockets; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Hosting.Server; +using Microsoft.AspNetCore.Hosting.Server.Features; +using Microsoft.Extensions.DependencyInjection; +using NUnit.Framework; + +namespace GameCult.Networking.Tests; + +[TestFixture] +public sealed class CultNetWebSocketSchemaServerTests +{ + [Test] + public async Task BinarySchemaMessage_RoundTrips_ThroughAuthenticatedHostAdapter() + { + var builder = WebApplication.CreateSlimBuilder(); + builder.WebHost.ConfigureKestrel(options => options.Listen(IPAddress.Loopback, 0)); + await using var server = new CultNetWebSocketSchemaServer(); + server.OnCultNet((message, peer) => + { + peer.SendCultNet(new CultNetHelloMessage + { + RuntimeId = "csharp-websocket-provider", + RuntimeKind = "provider", + DisplayName = message.RuntimeId + }); + return Task.CompletedTask; + }); + var app = builder.Build(); + app.UseWebSockets(); + app.MapCultNetWebSocket("/cultmesh", server, new CultNetWebSocketEndpointOptions + { + AuthorizeAsync = context => ValueTask.FromResult( + string.Equals(context.Request.Headers.Authorization, "Bearer test-session", StringComparison.Ordinal)) + }); + await app.StartAsync(); + try + { + var address = app.Services.GetRequiredService() + .Features.Get()!.Addresses.Single(); + var endpoint = new Uri(address.Replace("http://", "ws://", StringComparison.Ordinal) + "/cultmesh"); + using var client = new CultNetWebSocketSchemaClient(options => + options.SetRequestHeader("Authorization", "Bearer test-session")); + var received = new TaskCompletionSource( + TaskCreationOptions.RunContinuationsAsynchronously); + client.OnCultNet(message => received.TrySetResult(message)); + await client.ConnectAsync(endpoint); + client.SendCultNet(new CultNetHelloMessage + { + RuntimeId = "browser-consumer", + RuntimeKind = "browser" + }); + var response = await received.Task.WaitAsync(TimeSpan.FromSeconds(2)); + Assert.Multiple(() => + { + Assert.That(response.RuntimeId, Is.EqualTo("csharp-websocket-provider")); + Assert.That(response.DisplayName, Is.EqualTo("browser-consumer")); + Assert.That(server.PeerCount, Is.EqualTo(1)); + }); + client.Dispose(); + await WaitUntilAsync(() => server.PeerCount == 0); + } + finally + { + await app.StopAsync(); + await app.DisposeAsync(); + } + } + + [Test] + public void Endpoint_Requires_Explicit_Authentication_Or_Development_OptIn() + { + var builder = WebApplication.CreateSlimBuilder(); + var app = builder.Build(); + using var server = new AsyncDisposableScope(new CultNetWebSocketSchemaServer()); + Assert.That( + () => app.MapCultNetWebSocket("/cultmesh", server.Value, new CultNetWebSocketEndpointOptions()), + Throws.InvalidOperationException.With.Message.Contains("AuthorizeAsync")); + } + + private static async Task WaitUntilAsync(Func condition) + { + using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(2)); + while (!condition()) await Task.Delay(10, timeout.Token); + } + + private sealed class AsyncDisposableScope : IDisposable + { + public AsyncDisposableScope(CultNetWebSocketSchemaServer value) => Value = value; + public CultNetWebSocketSchemaServer Value { get; } + public void Dispose() => Value.DisposeAsync().AsTask().GetAwaiter().GetResult(); + } +} diff --git a/tests/GameCult.Networking.WebSockets.Tests/GameCult.Networking.WebSockets.Tests.csproj b/tests/GameCult.Networking.WebSockets.Tests/GameCult.Networking.WebSockets.Tests.csproj new file mode 100644 index 00000000..eec44ecd --- /dev/null +++ b/tests/GameCult.Networking.WebSockets.Tests/GameCult.Networking.WebSockets.Tests.csproj @@ -0,0 +1,17 @@ + + + net10.0 + false + enable + enable + + + + + + + + + + + From d563a1ac645aadeb87cce23b264b64ef8c821ebc Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 00:34:44 +0200 Subject: [PATCH 066/283] Discover browser providers through Odin --- packages/cultmesh-browser/README.md | 15 +- packages/cultmesh-browser/src/index.ts | 204 ++++++++++++++++-- .../test/cultmesh-browser.test.ts | 62 ++++++ ...cultmesh.verse-catalog-request.schema.json | 14 ++ ...ultmesh.verse-catalog-response.schema.json | 42 ++++ packages/cultnet-ts/src/contracts.ts | 54 ++++- packages/cultnet-ts/test/cultnet.test.ts | 36 ++++ .../EveBrowserNetworkSample.csproj | 1 + samples/eve-browser-network/Program.cs | 48 ++++- samples/eve-browser-network/README.md | 10 +- samples/eve-browser-network/browser/main.ts | 20 +- scripts/verify-eve-browser-network.mjs | 47 +++- src/GameCult.Mesh/CultMeshVerseDiscovery.cs | 46 ++-- .../docs/browser-verse-transport.md | 31 ++- .../03-publish-an-eve-surface.md | 12 +- 15 files changed, 567 insertions(+), 75 deletions(-) create mode 100644 packages/cultnet-ts/contracts/cultmesh.verse-catalog-request.schema.json create mode 100644 packages/cultnet-ts/contracts/cultmesh.verse-catalog-response.schema.json diff --git a/packages/cultmesh-browser/README.md b/packages/cultmesh-browser/README.md index 4866196c..acf349e6 100644 --- a/packages/cultmesh-browser/README.md +++ b/packages/cultmesh-browser/README.md @@ -10,13 +10,16 @@ writes. A renderer watches provider-owned records and invokes provider-owned operations. ```ts +const odin = new CultMeshBrowserOdinRendezvous({ + endpoints: ["wss://odin.example/verse"], + runtimeId: "counter-browser.discovery", +}); + const mesh = await CultMeshBrowserClient.connect({ verseId: "sample.counter", providerId: "sample.counter-provider", runtimeId: "counter-browser", - rendezvous: { - resolve: async identity => discoverWebSocketRoute(identity), - }, + rendezvous: odin, }); const counter = await mesh.leaseRawDocument({ @@ -27,8 +30,10 @@ const counter = await mesh.leaseRawDocument({ counter.watch(record => renderCounter(decodeCultNetPayload(record))); ``` -The rendezvous port may call Odin, but application code does not own reconnect -or resubscription. The physical socket endpoint is a replaceable route, not the +`CultMeshBrowserOdinRendezvous` speaks the canonical CultNet Verse-catalog +messages to one or more configured Odin WebSocket endpoints. Application code +supplies stable identity; it does not own endpoint selection, reconnect, or +resubscription. The physical provider socket is a replaceable route, not the provider identity. The browser handshake carries authentication through the host application's diff --git a/packages/cultmesh-browser/src/index.ts b/packages/cultmesh-browser/src/index.ts index 1f259422..717f89a9 100644 --- a/packages/cultmesh-browser/src/index.ts +++ b/packages/cultmesh-browser/src/index.ts @@ -10,6 +10,8 @@ import { type CultNetOperationResponseMessage, type CultNetRawDocumentRecord, type CultNetSnapshotResponseRawMessage, + type CultMeshVerseCatalogRequestMessage, + type CultMeshVerseCatalogResponseMessage, } from "cultnet-ts/contracts"; export interface CultMeshBrowserIdentity { @@ -26,6 +28,16 @@ export interface CultMeshBrowserRendezvous { resolve(identity: CultMeshBrowserIdentity): Promise; } +export interface CultMeshBrowserOdinRendezvousOptions { + endpoints: readonly string[]; + runtimeId: string; + transportVersion?: string; + timeoutMs?: number; + maxFrameBytes?: number; + createId?: () => string; + socketFactory?: (endpoint: string) => CultMeshBrowserSocket; +} + export interface CultMeshBrowserSocket { binaryType: BinaryType; readonly readyState: number; @@ -37,6 +49,107 @@ export interface CultMeshBrowserSocket { close(code?: number, reason?: string): void; } +/** Resolves stable Verse/provider identity through Odin's canonical CultNet Verse catalog. */ +export class CultMeshBrowserOdinRendezvous implements CultMeshBrowserRendezvous { + #options: Required> & { + transportVersion?: string; + socketFactory: (endpoint: string) => CultMeshBrowserSocket; + }; + + constructor(options: CultMeshBrowserOdinRendezvousOptions) { + requireText(options.runtimeId, "runtimeId"); + const endpoints = [...new Set(options.endpoints.map(value => value.trim()).filter(Boolean))]; + if (endpoints.length === 0) throw new Error("At least one Odin WebSocket endpoint is required."); + for (const endpoint of endpoints) requireWebSocketEndpoint(endpoint, "Odin rendezvous endpoint"); + this.#options = { + ...options, + endpoints, + timeoutMs: options.timeoutMs ?? 10_000, + maxFrameBytes: options.maxFrameBytes ?? 4 * 1024 * 1024, + createId: options.createId ?? (() => crypto.randomUUID()), + socketFactory: options.socketFactory ?? (endpoint => new WebSocket(endpoint)), + }; + if (this.#options.timeoutMs <= 0) throw new Error("Odin rendezvous timeoutMs must be positive."); + if (this.#options.maxFrameBytes <= 0) throw new Error("Odin rendezvous maxFrameBytes must be positive."); + } + + async resolve(identity: CultMeshBrowserIdentity): Promise { + requireText(identity.verseId, "verseId"); + requireText(identity.providerId, "providerId"); + const failures: Error[] = []; + for (const endpoint of this.#options.endpoints) { + try { + return await this.resolveFrom(endpoint, identity); + } catch (error) { + failures.push(error instanceof Error ? error : new Error(String(error))); + } + } + throw new AggregateError( + failures, + `Odin could not resolve Verse '${identity.verseId}' provider '${identity.providerId}'.`, + ); + } + + private resolveFrom(endpoint: string, identity: CultMeshBrowserIdentity): Promise { + const socket = this.#options.socketFactory(endpoint); + socket.binaryType = "arraybuffer"; + const messageId = this.#options.createId(); + const request: CultMeshVerseCatalogRequestMessage = { + schemaVersion: "cultmesh.verse_catalog_request.v0", + messageId, + verseIds: [identity.verseId], + ...(this.#options.transportVersion ? { transportVersion: this.#options.transportVersion } : {}), + }; + return new Promise((resolve, reject) => { + let settled = false; + const finish = (error?: Error, route?: CultMeshBrowserRoute) => { + if (settled) return; + settled = true; + clearTimeout(timer); + socket.onopen = null; + socket.onmessage = null; + socket.onerror = null; + socket.onclose = null; + socket.close(1000, error ? "Odin resolution failed" : "Odin resolution complete"); + if (error) reject(error); + else resolve(route!); + }; + const timer = setTimeout( + () => finish(new Error(`Odin resolution timed out at '${endpoint}'.`)), + this.#options.timeoutMs, + ); + socket.onopen = () => { + try { + sendSocketMessage(socket, { + schemaVersion: "cultnet.hello.v0", + runtimeId: this.#options.runtimeId, + runtimeKind: "browser", + supportedMessageVersions: [ + "cultmesh.verse_catalog_request.v0", + "cultmesh.verse_catalog_response.v0", + ], + }, this.#options.maxFrameBytes); + sendSocketMessage(socket, request, this.#options.maxFrameBytes); + } catch (error) { + finish(error instanceof Error ? error : new Error(String(error))); + } + }; + socket.onmessage = event => { + void decodeSocketMessage(event, this.#options.maxFrameBytes).then(message => { + if (message.schemaVersion === "cultnet.error.v0") { + finish(new Error(message.error)); + return; + } + if (message.schemaVersion !== "cultmesh.verse_catalog_response.v0" || message.messageId !== messageId) return; + finish(undefined, selectOdinRoute(message, identity)); + }).catch(error => finish(error instanceof Error ? error : new Error(String(error)))); + }; + socket.onerror = () => finish(new Error(`Odin WebSocket could not open '${endpoint}'.`)); + socket.onclose = () => finish(new Error(`Odin WebSocket closed before resolving '${identity.verseId}'.`)); + }); + } +} + export interface CultMeshBrowserClientOptions extends CultMeshBrowserIdentity { runtimeId: string; rendezvous: CultMeshBrowserRendezvous; @@ -418,22 +531,17 @@ export class CultMeshBrowserClient implements AsyncDisposable { private async receive(event: MessageEvent, generation: number): Promise { if (this.#disposed || generation !== this.#socketGeneration) return; - let payload: Uint8Array; - if (event.data instanceof ArrayBuffer) { - payload = new Uint8Array(event.data); - } else if (ArrayBuffer.isView(event.data)) { - payload = new Uint8Array(event.data.buffer, event.data.byteOffset, event.data.byteLength); - } else if (event.data instanceof Blob) { - payload = new Uint8Array(await event.data.arrayBuffer()); - } else { - this.#socket?.close(1003, "CultNet requires binary WebSocket frames"); + let message: CultNetMessage; + try { + message = await decodeSocketMessage(event, this.#options.maxFrameBytes); + } catch (error) { + const oversized = error instanceof Error && error.message.includes("exceeds"); + this.#socket?.close( + oversized ? 1009 : 1003, + oversized ? "CultNet frame exceeds configured maximum" : "CultNet requires binary WebSocket frames", + ); return; } - if (payload.byteLength > this.#options.maxFrameBytes) { - this.#socket?.close(1009, "CultNet frame exceeds configured maximum"); - return; - } - const message = parseCultNetMessage(decode(payload)); switch (message.schemaVersion) { case "cultnet.snapshot_response_raw.v0": this.applySnapshot(message); @@ -540,6 +648,74 @@ function base64ToBytes(value: string): Uint8Array { return Uint8Array.from(binary, character => character.charCodeAt(0)); } +function requireWebSocketEndpoint(value: string, field: string): URL { + let endpoint: URL; + try { + endpoint = new URL(value); + } catch { + throw new Error(`${field} '${value}' is not a valid URL.`); + } + if (endpoint.protocol !== "ws:" && endpoint.protocol !== "wss:") { + throw new Error(`${field} must use ws:// or wss://, got '${value}'.`); + } + return endpoint; +} + +function sendSocketMessage(socket: CultMeshBrowserSocket, message: CultNetMessage, maxFrameBytes: number): void { + const payload = encode(encodeCultNetMessageForWire(message)); + if (payload.byteLength > maxFrameBytes) { + throw new Error(`CultNet message exceeds the ${maxFrameBytes}-byte limit.`); + } + socket.send(payload); +} + +async function decodeSocketMessage(event: MessageEvent, maxFrameBytes: number): Promise { + let payload: Uint8Array; + if (event.data instanceof ArrayBuffer) { + payload = new Uint8Array(event.data); + } else if (ArrayBuffer.isView(event.data)) { + payload = new Uint8Array(event.data.buffer, event.data.byteOffset, event.data.byteLength); + } else if (event.data instanceof Blob) { + payload = new Uint8Array(await event.data.arrayBuffer()); + } else { + throw new Error("CultNet requires binary WebSocket frames."); + } + if (payload.byteLength > maxFrameBytes) { + throw new Error(`CultNet frame exceeds the ${maxFrameBytes}-byte limit.`); + } + return parseCultNetMessage(decode(payload)); +} + +function selectOdinRoute( + response: CultMeshVerseCatalogResponseMessage, + identity: CultMeshBrowserIdentity, +): CultMeshBrowserRoute { + const matchingVerses = response.verses.filter(verse => + verse.verseId === identity.verseId && verse.authorityRuntimeIds.includes(identity.providerId)); + if (matchingVerses.length !== 1) { + throw new Error( + `Odin returned ${matchingVerses.length} routes for Verse '${identity.verseId}' provider '${identity.providerId}'.`, + ); + } + const verse = matchingVerses[0]; + const endpoints = verse.discoveryEndpoints.filter(endpoint => { + try { + requireWebSocketEndpoint(endpoint, "Odin provider route"); + return true; + } catch { + return false; + } + }); + if (endpoints.length === 0) { + throw new Error(`Odin advertised no browser-compatible route for '${identity.providerId}'.`); + } + return { + ...identity, + endpoint: endpoints[0], + generation: [verse.compatibility.transportVersion, verse.compatibility.rulesHash, endpoints[0]].join(":"), + }; +} + function requireText(value: string, field: string): void { if (!value || value.trim().length === 0) throw new Error(`CultMesh browser ${field} is required.`); } diff --git a/packages/cultmesh-browser/test/cultmesh-browser.test.ts b/packages/cultmesh-browser/test/cultmesh-browser.test.ts index 8c3ae1b5..3836790d 100644 --- a/packages/cultmesh-browser/test/cultmesh-browser.test.ts +++ b/packages/cultmesh-browser/test/cultmesh-browser.test.ts @@ -13,12 +13,40 @@ import { import { CultMeshBrowserClient, + CultMeshBrowserOdinRendezvous, decodeCultNetOperationPayload, decodeCultNetPayload, type CultMeshBrowserRoute, type CultMeshBrowserSocket, } from "../src/index.js"; +test("Odin rendezvous resolves stable provider identity and observes route rotation", async () => { + const odin = new FakeOdin("ws://127.0.0.1:4050/mesh"); + let id = 0; + const rendezvous = new CultMeshBrowserOdinRendezvous({ + endpoints: ["ws://127.0.0.1:4040/odin"], + runtimeId: "browser-odin-test", + createId: () => `odin-${++id}`, + socketFactory: () => odin.open(), + }); + + assert.equal((await rendezvous.resolve({ + verseId: "sample.counter", + providerId: "sample.counter-provider", + })).endpoint, "ws://127.0.0.1:4050/mesh"); + + odin.providerEndpoint = "ws://127.0.0.1:4060/mesh"; + assert.equal((await rendezvous.resolve({ + verseId: "sample.counter", + providerId: "sample.counter-provider", + })).endpoint, "ws://127.0.0.1:4060/mesh"); + + await assert.rejects( + rendezvous.resolve({ verseId: "sample.counter", providerId: "other-provider" }), + /could not resolve/, + ); +}); + test("browser client leases provider state, invokes an operation, and follows route replacement", async () => { const first = new FakeProvider("ws://127.0.0.1:4101/mesh", 4); const second = new FakeProvider("ws://127.0.0.1:4102/mesh", 9); @@ -252,6 +280,40 @@ class FakeProvider { } } +class FakeOdin { + providerEndpoint: string; + + constructor(providerEndpoint: string) { + this.providerEndpoint = providerEndpoint; + } + + open(): FakeSocket { + const socket = new FakeSocket(wire => { + const message = parseCultNetMessage(decode(wire)); + if (message.schemaVersion !== "cultmesh.verse_catalog_request.v0") return; + socket.deliver({ + schemaVersion: "cultmesh.verse_catalog_response.v0", + messageId: message.messageId, + verses: [{ + verseId: "sample.counter", + displayName: "Counter", + authorityModel: "ServerAuthoritative", + compatibility: { + transportVersion: "cultmesh.v1", + rulesHash: "counter-v1", + compatibleVerseIds: [], + requiredPluginIds: [], + optionalPluginIds: [], + }, + discoveryEndpoints: [this.providerEndpoint], + authorityRuntimeIds: ["sample.counter-provider"], + }], + }); + }, () => undefined); + return socket; + } +} + class FakeSocket implements CultMeshBrowserSocket { binaryType: BinaryType = "arraybuffer"; readyState = 0; diff --git a/packages/cultnet-ts/contracts/cultmesh.verse-catalog-request.schema.json b/packages/cultnet-ts/contracts/cultmesh.verse-catalog-request.schema.json new file mode 100644 index 00000000..e99b9dea --- /dev/null +++ b/packages/cultnet-ts/contracts/cultmesh.verse-catalog-request.schema.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/GameCult/cultnet-ts/contracts/cultmesh.verse-catalog-request.schema.json", + "title": "CultMesh Verse Catalog Request", + "type": "object", + "required": ["schemaVersion", "messageId"], + "additionalProperties": false, + "properties": { + "schemaVersion": { "const": "cultmesh.verse_catalog_request.v0" }, + "messageId": { "type": "string", "minLength": 1 }, + "verseIds": { "type": "array", "items": { "type": "string", "minLength": 1 }, "uniqueItems": true }, + "transportVersion": { "type": "string", "minLength": 1 } + } +} diff --git a/packages/cultnet-ts/contracts/cultmesh.verse-catalog-response.schema.json b/packages/cultnet-ts/contracts/cultmesh.verse-catalog-response.schema.json new file mode 100644 index 00000000..21367d09 --- /dev/null +++ b/packages/cultnet-ts/contracts/cultmesh.verse-catalog-response.schema.json @@ -0,0 +1,42 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/GameCult/cultnet-ts/contracts/cultmesh.verse-catalog-response.schema.json", + "title": "CultMesh Verse Catalog Response", + "type": "object", + "required": ["schemaVersion", "messageId", "verses"], + "additionalProperties": false, + "$defs": { + "compatibility": { + "type": "object", + "required": ["transportVersion", "rulesHash", "compatibleVerseIds", "requiredPluginIds", "optionalPluginIds"], + "additionalProperties": false, + "properties": { + "transportVersion": { "type": "string", "minLength": 1 }, + "rulesHash": { "type": "string", "minLength": 1 }, + "compatibleVerseIds": { "type": "array", "items": { "type": "string", "minLength": 1 }, "uniqueItems": true }, + "requiredPluginIds": { "type": "array", "items": { "type": "string", "minLength": 1 }, "uniqueItems": true }, + "optionalPluginIds": { "type": "array", "items": { "type": "string", "minLength": 1 }, "uniqueItems": true } + } + }, + "verse": { + "type": "object", + "required": ["verseId", "displayName", "authorityModel", "compatibility", "discoveryEndpoints", "authorityRuntimeIds"], + "additionalProperties": false, + "properties": { + "verseId": { "type": "string", "minLength": 1 }, + "displayName": { "type": "string", "minLength": 1 }, + "authorityModel": { "type": "string", "minLength": 1 }, + "compatibility": { "$ref": "#/$defs/compatibility" }, + "discoveryEndpoints": { "type": "array", "items": { "type": "string", "minLength": 1 }, "uniqueItems": true }, + "authorityRuntimeIds": { "type": "array", "items": { "type": "string", "minLength": 1 }, "uniqueItems": true }, + "parentVerseId": { "type": "string", "minLength": 1 }, + "description": { "type": "string" } + } + } + }, + "properties": { + "schemaVersion": { "const": "cultmesh.verse_catalog_response.v0" }, + "messageId": { "type": "string", "minLength": 1 }, + "verses": { "type": "array", "items": { "$ref": "#/$defs/verse" } } + } +} diff --git a/packages/cultnet-ts/src/contracts.ts b/packages/cultnet-ts/src/contracts.ts index c97a0d8d..ffdbcf6e 100644 --- a/packages/cultnet-ts/src/contracts.ts +++ b/packages/cultnet-ts/src/contracts.ts @@ -28,6 +28,8 @@ import shardCatalogRequestSchema from "../contracts/cultnet.shard-catalog-reques import shardCatalogResponseSchema from "../contracts/cultnet.shard-catalog-response.schema.json"; import operationRequestSchema from "../contracts/cultnet.operation-request.schema.json"; import operationResponseSchema from "../contracts/cultnet.operation-response.schema.json"; +import verseCatalogRequestSchema from "../contracts/cultmesh.verse-catalog-request.schema.json"; +import verseCatalogResponseSchema from "../contracts/cultmesh.verse-catalog-response.schema.json"; import ghostlightAgentStateSchema from "../contracts/ghostlight.agent-state.schema.json"; export type CultNetWireContract = "cultnet.schema.v0" | "gamecult.networking.v0"; @@ -55,7 +57,9 @@ export type CultNetSchemaVersion = | "cultnet.shard_catalog_request.v0" | "cultnet.shard_catalog_response.v0" | "cultnet.operation_request.v0" - | "cultnet.operation_response.v0"; + | "cultnet.operation_response.v0" + | "cultmesh.verse_catalog_request.v0" + | "cultmesh.verse_catalog_response.v0"; export type CultNetSchemaKind = "wire_message" | "document_payload" | "shared_contract"; export type CultNetRawPayloadEncoding = "messagepack"; @@ -328,6 +332,38 @@ export interface CultNetOperationResponseMessage { sourceRuntimeId?: string; } +export interface CultMeshVerseCompatibilityMessage { + transportVersion: string; + rulesHash: string; + compatibleVerseIds: string[]; + requiredPluginIds: string[]; + optionalPluginIds: string[]; +} + +export interface CultMeshVerseDescriptorMessage { + verseId: string; + displayName: string; + authorityModel: string; + compatibility: CultMeshVerseCompatibilityMessage; + discoveryEndpoints: string[]; + authorityRuntimeIds: string[]; + parentVerseId?: string; + description?: string; +} + +export interface CultMeshVerseCatalogRequestMessage { + schemaVersion: "cultmesh.verse_catalog_request.v0"; + messageId: string; + verseIds?: string[]; + transportVersion?: string; +} + +export interface CultMeshVerseCatalogResponseMessage { + schemaVersion: "cultmesh.verse_catalog_response.v0"; + messageId: string; + verses: CultMeshVerseDescriptorMessage[]; +} + export interface GhostlightPressure { pressure_id: string; label: string; @@ -577,7 +613,9 @@ export type CultNetMessage = | CultNetShardCatalogRequestMessage | CultNetShardCatalogResponseMessage | CultNetOperationRequestMessage - | CultNetOperationResponseMessage; + | CultNetOperationResponseMessage + | CultMeshVerseCatalogRequestMessage + | CultMeshVerseCatalogResponseMessage; const ajv = new Ajv2020({ allErrors: true, @@ -608,6 +646,8 @@ const CULTNET_MESSAGE_SCHEMAS = [ shardCatalogResponseSchema, operationRequestSchema, operationResponseSchema, + verseCatalogRequestSchema, + verseCatalogResponseSchema, ] as const; const cultNetValidators = new Map(); @@ -1142,6 +1182,16 @@ function normalizeCultNetOptionalNulls( case "cultnet.operation_response.v0": stripNullProperties(candidate, ["payloadEncoding", "diagnostics", "sourceRuntimeId"]); return; + case "cultmesh.verse_catalog_request.v0": + stripNullProperties(candidate, ["verseIds", "transportVersion"]); + return; + case "cultmesh.verse_catalog_response.v0": + for (const verse of Array.isArray(candidate.verses) ? candidate.verses : []) { + if (verse && typeof verse === "object") { + stripNullProperties(verse as Record, ["parentVerseId", "description"]); + } + } + return; case "cultnet.schema_catalog_request.v0": stripNullProperties(candidate, ["schemaIds", "kinds"]); return; diff --git a/packages/cultnet-ts/test/cultnet.test.ts b/packages/cultnet-ts/test/cultnet.test.ts index c5ca69da..945e0a3b 100644 --- a/packages/cultnet-ts/test/cultnet.test.ts +++ b/packages/cultnet-ts/test/cultnet.test.ts @@ -58,6 +58,42 @@ import { type InteropNote, } from "./interop/cultnet-interop-shared"; +test("CultNet validates the canonical CultMesh Verse catalog messages", () => { + const request = parseCultNetMessage({ + schemaVersion: "cultmesh.verse_catalog_request.v0", + messageId: "catalog-1", + verseIds: ["sample.counter"], + transportVersion: "cultmesh.v1", + }); + assert.equal(request.schemaVersion, "cultmesh.verse_catalog_request.v0"); + + const response = parseCultNetMessage({ + schemaVersion: "cultmesh.verse_catalog_response.v0", + messageId: "catalog-1", + verses: [{ + verseId: "sample.counter", + displayName: "Counter", + authorityModel: "OperatorCluster", + compatibility: { + transportVersion: "cultmesh.v1", + rulesHash: "counter-v1", + compatibleVerseIds: [], + requiredPluginIds: [], + optionalPluginIds: [], + }, + discoveryEndpoints: ["wss://provider.example/cultmesh"], + authorityRuntimeIds: ["sample.counter-provider"], + }], + }); + assert.equal(response.schemaVersion, "cultmesh.verse_catalog_response.v0"); + assert.equal(response.verses[0].authorityRuntimeIds[0], "sample.counter-provider"); + + assert.throws(() => parseCultNetMessage({ + ...response, + verses: [{ ...response.verses[0], compatibility: { ...response.verses[0].compatibility, rulesHash: "" } }], + }), /rulesHash/); +}); + class FakeRudpReconnectTransport extends EventEmitter { public connectCalls = 0; public closeCalls = 0; diff --git a/samples/eve-browser-network/EveBrowserNetworkSample.csproj b/samples/eve-browser-network/EveBrowserNetworkSample.csproj index 4fe900dd..a0a0bf32 100644 --- a/samples/eve-browser-network/EveBrowserNetworkSample.csproj +++ b/samples/eve-browser-network/EveBrowserNetworkSample.csproj @@ -6,5 +6,6 @@ + diff --git a/samples/eve-browser-network/Program.cs b/samples/eve-browser-network/Program.cs index 962baee3..9686b36c 100644 --- a/samples/eve-browser-network/Program.cs +++ b/samples/eve-browser-network/Program.cs @@ -2,6 +2,7 @@ using System.Net; using System.Text.Json; using GameCult.Caching; using GameCult.Caching.MessagePack; +using GameCult.Mesh; using GameCult.Networking; using GameCult.Networking.WebSockets; using MessagePack; @@ -22,7 +23,50 @@ if (arguments.Mode == "headless") await RunHeadlessAsync(arguments); return; } -throw new InvalidOperationException("Use 'provider' or 'headless'."); +if (arguments.Mode == "odin") +{ + await RunOdinAsync(arguments); + return; +} +throw new InvalidOperationException("Use 'provider', 'headless', or 'odin'."); + +static async Task RunOdinAsync(Args arguments) +{ + if (string.IsNullOrWhiteSpace(arguments.ProviderEndpoint)) + throw new ArgumentException("The Odin fixture requires --provider-endpoint."); + using var catalog = new CultMeshVerseCatalog(); + catalog.Upsert(new CultMeshVerseDescriptor( + "sample.counter", + "CultMesh browser counter", + CultMeshVerseAuthorityModel.OperatorCluster, + new CultMeshVerseCompatibility("cultmesh.v1", "sample-counter-v1"), + discoveryEndpoints: [arguments.ProviderEndpoint], + authorityRuntimeIds: ["sample.counter-provider"], + description: "Local executable Odin fixture for the browser/network onboarding witness.")); + + await using var schemaServer = new CultNetWebSocketSchemaServer(); + schemaServer.OnCultNet((request, peer) => + { + peer.SendCultNet(CultMeshVerseMessages.CreateCatalogResponse(catalog, request)); + return Task.CompletedTask; + }); + var builder = WebApplication.CreateSlimBuilder(); + builder.WebHost.ConfigureKestrel(options => options.Listen(IPAddress.Loopback, arguments.Port)); + var app = builder.Build(); + app.UseWebSockets(); + app.MapCultNetWebSocket("/odin", schemaServer, new CultNetWebSocketEndpointOptions + { + AuthorizeAsync = context => ValueTask.FromResult( + context.Request.Cookies.TryGetValue("cultnet_session", out var token) && + string.Equals(token, arguments.Token, StringComparison.Ordinal)) + }); + await app.StartAsync(); + var address = app.Services.GetRequiredService() + .Features.Get()!.Addresses.Single(); + Console.WriteLine("ODIN_READY " + address.Replace("http://", "ws://", StringComparison.Ordinal) + "/odin"); + await app.WaitForShutdownAsync(); + await app.DisposeAsync(); +} static async Task RunProviderAsync(Args arguments) { @@ -146,6 +190,7 @@ sealed class Args public int Port { get; private init; } public string StatePath { get; private init; } = "sample-counter.cc"; public string Endpoint { get; private init; } = ""; + public string ProviderEndpoint { get; private init; } = ""; public string Token { get; private init; } = "sample-session"; public static Args Parse(string[] values) @@ -160,6 +205,7 @@ sealed class Args Port = named.TryGetValue("--port", out var port) ? int.Parse(port) : 0, StatePath = named.GetValueOrDefault("--state", "sample-counter.cc"), Endpoint = named.GetValueOrDefault("--endpoint", ""), + ProviderEndpoint = named.GetValueOrDefault("--provider-endpoint", ""), Token = named.GetValueOrDefault("--token", "sample-session") }; } diff --git a/samples/eve-browser-network/README.md b/samples/eve-browser-network/README.md index 2d6c7034..33de2dbe 100644 --- a/samples/eve-browser-network/README.md +++ b/samples/eve-browser-network/README.md @@ -7,6 +7,8 @@ This is the real-process continuation of `samples/eve-two-runtime`: - one real Chromium page leases both documents through `cultmesh-browser` and lowers the provider-owned Eve surface; - one independent C# headless client observes the same typed counter; +- one separate local Odin fixture answers the canonical CultMesh Verse catalog + over binary CultNet WebSocket messages; - the browser and C# clients speak the same binary CultNet schema-v0 WebSocket messages through the authenticated host adapter. @@ -17,6 +19,8 @@ node scripts/verify-eve-browser-network.mjs --eve-root ..\Eve ``` The verifier clicks the Eve button twice with one idempotency key, requires one -state transition, restarts the provider, and requires the browser to rehydrate -the persisted count. Odin route discovery is represented by the browser -client's rendezvous port; a live Odin process remains the next discovery gate. +state transition, restarts the provider on a different physical port, updates +the local Odin fixture, and requires the still-open browser to rediscover the +route, resubscribe, execute a second command, and preserve the durable count. +The fixture speaks the production Verse-catalog contract; a deployment smoke +against the full Odin daemon remains a separate infrastructure gate. diff --git a/samples/eve-browser-network/browser/main.ts b/samples/eve-browser-network/browser/main.ts index 7bcb6887..9c7f1cd1 100644 --- a/samples/eve-browser-network/browser/main.ts +++ b/samples/eve-browser-network/browser/main.ts @@ -2,6 +2,7 @@ import { parseEveCommandReceipt, parseEveSurfaceDocument } from "@gamecult/eve-c import { renderEveSurface } from "@gamecult/eve-browser-lowering"; import { CultMeshBrowserClient, + CultMeshBrowserOdinRendezvous, decodeCultNetOperationPayload, decodeCultNetPayload, } from "cultmesh-browser"; @@ -11,14 +12,16 @@ declare global { __sampleReady?: boolean; __sampleCount?: number; __sampleReceipt?: { receiptId: string; count: number }; + __sampleCommandId?: string; + __sampleConnectionStates?: string[]; __sampleError?: string; } } const params = new URLSearchParams(location.search); -const endpoint = params.get("endpoint"); +const odinEndpoint = params.get("odin"); const token = params.get("token") || "sample-session"; -if (!endpoint) throw new Error("The sample requires an endpoint query parameter."); +if (!odinEndpoint) throw new Error("The sample requires an Odin endpoint query parameter."); document.cookie = `cultnet_session=${encodeURIComponent(token)}; Path=/; SameSite=Strict`; const host = document.querySelector("#surface")!; @@ -29,10 +32,15 @@ try { verseId: "sample.counter", providerId: "sample.counter-provider", runtimeId: "sample.chromium", - rendezvous: { - resolve: async identity => ({ ...identity, endpoint }), - }, + rendezvous: new CultMeshBrowserOdinRendezvous({ + endpoints: [odinEndpoint], + runtimeId: "sample.chromium.discovery", + transportVersion: "cultmesh.v1", + }), }); + window.__sampleConnectionStates = []; + mesh.watchState(state => window.__sampleConnectionStates!.push(state)); + window.__sampleCommandId = "browser-click-1"; const counter = await mesh.leaseRawDocument({ schemaId: "sample.counter_state.v1", recordKey: "counter:main", @@ -53,7 +61,7 @@ try { operation: intent.command, payloadSchema: "sample.increment.v1", payload: { amount: 1 }, - idempotencyKey: "browser-click-1", + idempotencyKey: window.__sampleCommandId, }); const receipt = parseEveCommandReceipt(decodeCultNetOperationPayload(response)) as { receiptId: string; diff --git a/scripts/verify-eve-browser-network.mjs b/scripts/verify-eve-browser-network.mjs index d4e9fa2c..9e047930 100644 --- a/scripts/verify-eve-browser-network.mjs +++ b/scripts/verify-eve-browser-network.mjs @@ -19,6 +19,7 @@ const statePath = join(workRoot, "counter.cc"); const bundlePath = join(workRoot, "bundle.js"); const token = "sample-session"; let provider; +let odin; let headless; let httpServer; let browser; @@ -46,9 +47,13 @@ try { await run("dotnet", ["build", join(sampleRoot, "EveBrowserNetworkSample.csproj"), "--verbosity", "quiet"]); const providerPort = await freePort(); + const replacementProviderPort = await freePort(); + const odinPort = await freePort(); const httpPort = await freePort(); provider = await startProvider(providerPort); const endpoint = await provider.waitFor("PROVIDER_READY "); + odin = await startOdin(odinPort, endpoint); + const odinEndpoint = await odin.waitFor("ODIN_READY "); headless = startDotnet(["headless", "--endpoint", endpoint, "--token", token]); await headless.waitFor("HEADLESS_READY "); httpServer = await serve(httpPort, sampleRoot, bundlePath); @@ -56,7 +61,7 @@ try { const executablePath = process.env.CHROME_PATH || "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe"; browser = await chromium.launch({ executablePath, headless: true }); let page = await browser.newPage(); - const url = `http://127.0.0.1:${httpPort}/?endpoint=${encodeURIComponent(endpoint)}&token=${token}`; + const url = `http://127.0.0.1:${httpPort}/?odin=${encodeURIComponent(odinEndpoint)}&token=${token}`; await page.goto(url); await page.waitForFunction(() => window.__sampleReady || window.__sampleError); assert.equal(await page.evaluate(() => window.__sampleError), undefined); @@ -69,29 +74,40 @@ try { await page.waitForFunction(receipt => window.__sampleReceipt?.receiptId === receipt, firstReceipt); assert.equal(await page.evaluate(() => window.__sampleCount), 1, "duplicate idempotency key changed canonical state"); - await page.close(); await stop(provider.process); - provider = await startProvider(providerPort); + await stop(odin.process); + provider = await startProvider(replacementProviderPort); const restartedEndpoint = await provider.waitFor("PROVIDER_READY "); - assert.equal(restartedEndpoint, endpoint); - page = await browser.newPage(); - await page.goto(url); - await page.waitForFunction(() => window.__sampleReady || window.__sampleError); - assert.equal(await page.evaluate(() => window.__sampleError), undefined); - assert.equal(await page.evaluate(() => window.__sampleCount), 1, "provider restart lost durable counter state"); + assert.notEqual(restartedEndpoint, endpoint); + odin = await startOdin(odinPort, restartedEndpoint); + assert.equal(await odin.waitFor("ODIN_READY "), odinEndpoint); + headless = startDotnet(["headless", "--endpoint", restartedEndpoint, "--token", token]); + await headless.waitFor("HEADLESS_READY "); + await page.evaluate(() => { window.__sampleCommandId = "browser-click-2"; }); + await page.locator("button").click(); + await page.waitForFunction(() => window.__sampleReceipt?.count === 2 && window.__sampleCount === 2); + assert.equal(JSON.parse(await headless.waitFor("HEADLESS_UPDATE ")).count, 2); + const connectionStates = await page.evaluate(() => window.__sampleConnectionStates); + assert.equal(connectionStates[0], "connected"); + assert.equal(connectionStates.at(-1), "connected"); + assert.ok(connectionStates.includes("reconnecting")); + assert.ok(!connectionStates.includes("disposed")); console.log(JSON.stringify({ providerEndpoint: endpoint, + replacementProviderEndpoint: restartedEndpoint, + odinEndpoint, browserRuntime: "chromium", headlessRuntime: "csharp", receiptId: firstReceipt, - count: 1, - restartCount: 1, + count: 2, + routeRotationCount: 1, })); } finally { if (browser) await browser.close().catch(() => undefined); if (headless) await stop(headless.process); if (provider) await stop(provider.process); + if (odin) await stop(odin.process); if (httpServer) await new Promise(resolve => httpServer.close(resolve)); await rm(workRoot, { recursive: true, force: true }); } @@ -100,6 +116,15 @@ async function startProvider(port) { return startDotnet(["provider", "--port", String(port), "--state", statePath, "--token", token]); } +async function startOdin(port, providerEndpoint) { + return startDotnet([ + "odin", + "--port", String(port), + "--provider-endpoint", providerEndpoint, + "--token", token, + ]); +} + function startDotnet(arguments_) { const process = spawn("dotnet", [ "run", "--no-build", "--project", join(sampleRoot, "EveBrowserNetworkSample.csproj"), "--", ...arguments_, diff --git a/src/GameCult.Mesh/CultMeshVerseDiscovery.cs b/src/GameCult.Mesh/CultMeshVerseDiscovery.cs index 69cc9e12..ca3655e9 100644 --- a/src/GameCult.Mesh/CultMeshVerseDiscovery.cs +++ b/src/GameCult.Mesh/CultMeshVerseDiscovery.cs @@ -65,6 +65,33 @@ namespace GameCult.Mesh message.ParentVerseId, message.Description); } + + /// Creates the canonical filtered Verse catalog response for any CultNet transport adapter. + public static CultMeshVerseCatalogResponseMessage CreateCatalogResponse( + CultMeshVerseCatalog catalog, + CultMeshVerseCatalogRequestMessage request) + { + if (catalog == null) throw new ArgumentNullException(nameof(catalog)); + if (request == null) throw new ArgumentNullException(nameof(request)); + var verseIds = request.VerseIds == null || request.VerseIds.Length == 0 + ? null + : new HashSet(request.VerseIds, StringComparer.Ordinal); + return new CultMeshVerseCatalogResponseMessage + { + MessageId = string.IsNullOrWhiteSpace(request.MessageId) + ? Guid.NewGuid().ToString("N") + : request.MessageId, + Verses = catalog.Verses + .Where(verse => verseIds == null || verseIds.Contains(verse.VerseId)) + .Where(verse => string.IsNullOrWhiteSpace(request.TransportVersion) || + string.Equals( + verse.Compatibility.TransportVersion, + request.TransportVersion, + StringComparison.Ordinal)) + .Select(verse => verse.ToMessage()) + .ToArray() + }; + } } /// @@ -93,24 +120,7 @@ namespace GameCult.Mesh /// public CultMeshVerseCatalogResponseMessage CreateResponse(CultMeshVerseCatalogRequestMessage request) { - if (request == null) throw new ArgumentNullException(nameof(request)); - var verseIds = request.VerseIds == null || request.VerseIds.Length == 0 - ? null - : new HashSet(request.VerseIds, StringComparer.Ordinal); - var verses = _catalog.Verses - .Where(verse => verseIds == null || verseIds.Contains(verse.VerseId)) - .Where(verse => string.IsNullOrWhiteSpace(request.TransportVersion) || - string.Equals(verse.Compatibility.TransportVersion, request.TransportVersion, StringComparison.Ordinal)) - .Select(verse => verse.ToMessage()) - .ToArray(); - - return new CultMeshVerseCatalogResponseMessage - { - MessageId = string.IsNullOrWhiteSpace(request.MessageId) - ? Guid.NewGuid().ToString("N") - : request.MessageId, - Verses = verses - }; + return CultMeshVerseMessages.CreateCatalogResponse(_catalog, request); } /// diff --git a/src/GameCult.Mesh/docs/browser-verse-transport.md b/src/GameCult.Mesh/docs/browser-verse-transport.md index 81934139..c6748b28 100644 --- a/src/GameCult.Mesh/docs/browser-verse-transport.md +++ b/src/GameCult.Mesh/docs/browser-verse-transport.md @@ -7,9 +7,11 @@ Date: 2026-08-17 This is the implementation map for the browser Verse boundary. `samples/eve-two-runtime` remains the clean package-consumer/jsdom checkpoint. `samples/eve-browser-network` runs a durable C# provider, a real Chromium Eve -lowerer, and an independent C# headless observer over the same authenticated -binary CultNet WebSocket route. It proves one canonical command effect, -idempotent retry, shared observation, and provider restart. +lowerer, an independent C# headless observer, and a separate local Odin fixture +over authenticated binary CultNet WebSocket routes. It proves one canonical +command effect, idempotent retry, shared observation, provider restart on a new +physical route, browser rediscovery, retained lease resubscription, and a second +canonical command after reconnection. The current substrate has a browser client boundary and local live proof, but not a complete public Verse proof: @@ -23,14 +25,18 @@ not a complete public Verse proof: `cultmesh-browser` consumes those messages as explicit document leases; - `cultmesh-browser` owns stable identity, route refresh, resubscription, and typed operation correlation without exposing direct document writes; +- `CultMeshBrowserOdinRendezvous` resolves stable Verse/provider identity with + `cultmesh.verse_catalog_request.v0` and + `cultmesh.verse_catalog_response.v0`; application callbacks no longer need to + smuggle provider URLs into the browser client; - Kotlin has a channel-aware WebSocket transport adapter, TypeScript has the browser client, and `GameCult.Networking.WebSockets` provides the bounded C# schema server host adapter; - Hermodr can lower Odin state into a browser, but it is an infrastructure runtime, not the clean-consumer game API; -- the sample rendezvous port currently returns one configured local route; - discovery from a live Odin and automatic route rotation are not yet in the - executable cross-runtime gate. +- the sample's separate local Odin fixture serves the production Verse-catalog + contract and is restarted with a changed provider route; the same Chromium + client automatically rediscovers that route. - the sample validates its surface against Eve's canonical TypeScript contract, but its provider still carries a minimal local C# DTO mirror. The released-artifact gate requires the renderer-neutral C# Eve surface contract @@ -152,6 +158,8 @@ implementation must support: `cultnet.database_change_raw.v0`; - `cultnet.operation_request.v0` and `cultnet.operation_response.v0`; +- `cultmesh.verse_catalog_request.v0` and + `cultmesh.verse_catalog_response.v0` on the Odin route; - `cultnet.error.v0`. The WebSocket frame is a transport body, not a second message schema. Payload @@ -163,16 +171,19 @@ identity, authority, and idempotency validation happen before provider code. Current executable coverage from `scripts/verify-eve-browser-network.mjs`: - authenticated binary C# WebSocket provider; +- separate local Odin fixture using the canonical Verse-catalog messages; - real Chromium and independent C# headless consumers; - shared surface and counter document leases; - Eve button to typed operation to provider receipt to shared state; - duplicate idempotency key produces one effect; -- provider restart rehydrates the `.cc` state; +- provider restart on a different physical port rehydrates the `.cc` state; +- the retained browser lease rediscovers through Odin, resubscribes, and + commits a second provider-authored receipt; - generated browser bundle contains no `node:` builtin import. -The full public Verse gate still requires live Odin discovery, physical route -rotation during retained leases, released-artifact-only .NET consumption, and -Windows/Linux CI. +The full public Verse gate still requires the deployed Odin daemon rather than +the local contract fixture, retained C# lease reconnection through the same +identity path, released-artifact-only .NET consumption, and Windows/Linux CI. From an empty temporary consumer using packed/released artifacts only: diff --git a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md index e38aa8c3..65a2895b 100644 --- a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md +++ b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md @@ -68,10 +68,12 @@ cross-language command execution. Do not cite it as evidence for those layers. The next executable checkpoint is [`samples/eve-browser-network`](../../../../samples/eve-browser-network/README.md). -It runs a durable C# provider, a real Chromium Eve lowerer, and an independent -C# headless observer over the same authenticated binary CultNet WebSocket lane. -It proves command idempotency and provider restart. Live Odin discovery and -route rotation remain separate gates. Their owner map and full acceptance -contract are recorded in +It runs a durable C# provider, a separate local Odin fixture, a real Chromium +Eve lowerer, and an independent C# headless observer over authenticated binary +CultNet WebSocket lanes. The still-open browser resolves stable identity through +the canonical Verse catalog, survives a provider restart on a different +physical route, resubscribes, and commits another canonical receipt. A smoke +against the deployed Odin daemon and retained C# lease reconnection remain +separate infrastructure gates. Their owner map and full acceptance contract are recorded in [`browser-verse-transport.md`](../browser-verse-transport.md). From ba680020b9e645f979a74fcadc1eb138f67afbef Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 00:44:41 +0200 Subject: [PATCH 067/283] Prove reactive scheduling scales with edits --- packages/cultcache-py/tests/test_cultcache.py | 67 +++++++++++++++- packages/cultmesh-ts/src/index.ts | 29 ++++--- packages/cultmesh-ts/test/cultmesh.test.ts | 76 ++++++++++++++++++ scripts/verify-reactive-document-scaling.ps1 | 75 ++++++++++++++++++ src/GameCult.Mesh/CultMeshPrimitives.cs | 56 +++++++++++-- .../docs/document-write-authority.md | 14 ++++ .../CultMeshStreamingTests.cs | 79 +++++++++++++++++++ 7 files changed, 378 insertions(+), 18 deletions(-) create mode 100644 scripts/verify-reactive-document-scaling.ps1 diff --git a/packages/cultcache-py/tests/test_cultcache.py b/packages/cultcache-py/tests/test_cultcache.py index d00a05ab..f753b12e 100644 --- a/packages/cultcache-py/tests/test_cultcache.py +++ b/packages/cultcache-py/tests/test_cultcache.py @@ -16,7 +16,7 @@ import io from dataclasses import asdict, dataclass from datetime import UTC, datetime, timedelta from pathlib import Path -from typing import Callable +from typing import Any, Callable from uuid import uuid4 from cultcache_py import ( @@ -2580,6 +2580,71 @@ class CultCacheTests(unittest.TestCase): finally: reactive.dispose() + def test_cultmesh_reactive_scheduling_scales_with_changed_documents_only(self) -> None: + document = define_document_type( + "mesh.reactive_scale_note", + encode=lambda value: value, + decode=lambda value: value, + ) + + for document_count in (1, 100, 1000): + node = create_node(runtime_id=f"python-reactive-scale-{document_count}") + node.register_document(document) + for index in range(document_count): + node.put(document, f"note:{index}", {"body": "initial", "revision": 1}) + + scheduled_timers: list[Any] = [] + + class FakeTimer: + def __init__(self, interval: float, callback: Callable[[], None]) -> None: + self.interval = interval + self.callback = callback + self.daemon = False + self.cancelled = False + self.started = False + scheduled_timers.append(self) + + def start(self) -> None: + self.started = True + + def cancel(self) -> None: + self.cancelled = True + + reactive_documents: list[Any] = [] + with patch("cultmesh_py.node.threading.Timer", FakeTimer): + try: + for index in range(document_count): + reactive_documents.append( + node.authoritative_writer(document, f"note:{index}").reactive() + ) + + self.assertEqual( + len(scheduled_timers), + 0, + f"{document_count} idle documents must schedule no timers", + ) + + changed_document_count = max(1, document_count // 100) + for index in range(changed_document_count): + reactive_documents[index].update( + lambda draft, changed=index: draft.update( + body=f"changed-{changed}", + revision=2, + ) + ) + + self.assertEqual(len(scheduled_timers), changed_document_count) + self.assertTrue(all(timer.started for timer in scheduled_timers)) + self.assertEqual( + sum(reactive.is_dirty for reactive in reactive_documents), + changed_document_count, + ) + finally: + for reactive in reactive_documents: + reactive.dispose() + + self.assertTrue(all(timer.cancelled for timer in scheduled_timers)) + def test_cultmesh_observed_document_cannot_publish_borrowed_mutation(self) -> None: document = define_document_type( "mesh.observed_note", diff --git a/packages/cultmesh-ts/src/index.ts b/packages/cultmesh-ts/src/index.ts index 5d81425e..7300ad01 100644 --- a/packages/cultmesh-ts/src/index.ts +++ b/packages/cultmesh-ts/src/index.ts @@ -1140,7 +1140,7 @@ class CultMeshReactiveDocumentHandle #disposed = false; #pendingSet: Promise = Promise.resolve(); #flushScheduled = false; - #flushTimer: ReturnType | undefined; + #cancelScheduledFlush: (() => void) | undefined; #unsubscribe: CultMeshUnsubscribe | undefined; #dirty = false; #lastPredicted: TDocument | undefined; @@ -1238,10 +1238,8 @@ class CultMeshReactiveDocumentHandle public dispose(): void { this.#disposed = true; - if (this.#flushTimer !== undefined) { - clearTimeout(this.#flushTimer); - this.#flushTimer = undefined; - } + this.#cancelScheduledFlush?.(); + this.#cancelScheduledFlush = undefined; this.#flushScheduled = false; this.#unsubscribe?.(); this.#unsubscribe = undefined; @@ -1294,28 +1292,35 @@ class CultMeshReactiveDocumentHandle const debounceMs = this.#debounceMs; if (debounceMs > 0) { - this.#flushTimer = setTimeout(flush, debounceMs); + const timer = setTimeout(flush, debounceMs); + this.#cancelScheduledFlush = () => clearTimeout(timer); return; } const requestFrame = (globalThis as { requestAnimationFrame?: (callback: FrameRequestCallback) => number; + cancelAnimationFrame?: (handle: number) => void; }).requestAnimationFrame; if (typeof requestFrame === "function") { - requestFrame(() => flush()); + const frame = requestFrame(() => flush()); + const cancelFrame = (globalThis as { + cancelAnimationFrame?: (handle: number) => void; + }).cancelAnimationFrame; + this.#cancelScheduledFlush = typeof cancelFrame === "function" + ? () => cancelFrame(frame) + : undefined; return; } - this.#flushTimer = setTimeout(flush, 0); + const timer = setTimeout(flush, 0); + this.#cancelScheduledFlush = () => clearTimeout(timer); } private flushNow(): void { if (!this.#flushScheduled && !this.#dirty) return; this.#flushScheduled = false; - if (this.#flushTimer !== undefined) { - clearTimeout(this.#flushTimer); - this.#flushTimer = undefined; - } + this.#cancelScheduledFlush?.(); + this.#cancelScheduledFlush = undefined; if (this.#disposed || !this.#dirty) return; const snapshot = cloneCultMeshDocument(this.#current); this.#dirty = false; diff --git a/packages/cultmesh-ts/test/cultmesh.test.ts b/packages/cultmesh-ts/test/cultmesh.test.ts index 709dc5b8..18e40a32 100644 --- a/packages/cultmesh-ts/test/cultmesh.test.ts +++ b/packages/cultmesh-ts/test/cultmesh.test.ts @@ -572,6 +572,82 @@ test("CultMesh TS reactive documents coalesce same-frame explicit updates", asyn } }); +test("CultMesh TS reactive scheduling scales with changed documents only", async () => { + const previousRequestAnimationFrame = globalThis.requestAnimationFrame; + const previousCancelAnimationFrame = globalThis.cancelAnimationFrame; + const frameCallbacks = new Map(); + let nextFrame = 1; + globalThis.requestAnimationFrame = callback => { + const frame = nextFrame++; + frameCallbacks.set(frame, callback); + return frame; + }; + globalThis.cancelAnimationFrame = frame => { + frameCallbacks.delete(frame); + }; + + try { + for (const documentCount of [1, 100, 1000]) { + const reactiveDocuments = []; + for (let index = 0; index < documentCount; index++) { + let current = { + noteId: `note:scale:${index}`, + body: "initial", + }; + const document = CultMesh.document( + `cultmesh.note:scale:${index}`, + noteDocument, + async () => current, + { + submitPrediction: async (_context, value) => { + current = value; + }, + }, + ); + reactiveDocuments.push(document.predictionWriter().reactive({ watch: false })); + } + + await Promise.all(reactiveDocuments.map(document => document.ready)); + assert.equal(frameCallbacks.size, 0, `${documentCount} idle documents scheduled no work`); + + const changedDocumentCount = Math.max(1, Math.floor(documentCount / 100)); + for (let index = 0; index < changedDocumentCount; index++) { + reactiveDocuments[index].update(value => { + value.body = `changed-${index}`; + }); + } + + assert.equal( + frameCallbacks.size, + changedDocumentCount, + `${documentCount} documents scheduled only the ${changedDocumentCount} changed documents`, + ); + assert.equal( + reactiveDocuments.filter(document => document.dirty).length, + changedDocumentCount, + ); + + for (const reactive of reactiveDocuments) reactive.dispose(); + assert.equal(frameCallbacks.size, 0, "dispose cancels every scheduled frame flush"); + } + } finally { + if (previousRequestAnimationFrame) { + globalThis.requestAnimationFrame = previousRequestAnimationFrame; + } else { + delete (globalThis as unknown as { + requestAnimationFrame?: (callback: FrameRequestCallback) => number; + }).requestAnimationFrame; + } + if (previousCancelAnimationFrame) { + globalThis.cancelAnimationFrame = previousCancelAnimationFrame; + } else { + delete (globalThis as unknown as { + cancelAnimationFrame?: (handle: number) => void; + }).cancelAnimationFrame; + } + } +}); + test("CultMesh TS reactive documents queue edits made while a prediction is in flight", async () => { let current = { noteId: "note:reactive-in-flight", diff --git a/scripts/verify-reactive-document-scaling.ps1 b/scripts/verify-reactive-document-scaling.ps1 new file mode 100644 index 00000000..1729ed4d --- /dev/null +++ b/scripts/verify-reactive-document-scaling.ps1 @@ -0,0 +1,75 @@ +param( + [string] $PythonPath = "" +) + +$ErrorActionPreference = "Stop" + +$root = Split-Path -Parent $PSScriptRoot +$dotnet = Get-Command dotnet -ErrorAction Stop +$node = Get-Command node -ErrorAction Stop +$pythonExecutable = if ([string]::IsNullOrWhiteSpace($PythonPath)) { + (Get-Command python -ErrorAction Stop).Source +} +else { + [IO.Path]::GetFullPath($PythonPath) +} +if (-not (Test-Path -LiteralPath $pythonExecutable)) { + throw "Python executable not found: $pythonExecutable" +} +$typescript = Join-Path $root "node_modules\typescript\bin\tsc" +if (-not (Test-Path -LiteralPath $typescript)) { + throw "TypeScript compiler not found: $typescript" +} + +& $dotnet.Source test (Join-Path $root "tests\GameCult.Mesh.Tests\GameCult.Mesh.Tests.csproj") ` + --filter "FullyQualifiedName~ReactiveDocument_SchedulingScalesWithChangedDocumentsOnly" ` + --nologo ` + --verbosity minimal +if ($LASTEXITCODE -ne 0) { + throw "CultMesh C# reactive scaling verification failed." +} + +Push-Location (Join-Path $root "packages\cultmesh-ts") +try { + & $node.Source $typescript -p tsconfig.json --pretty false + if ($LASTEXITCODE -ne 0) { + throw "CultMesh TypeScript source build failed." + } + & $node.Source $typescript -p tsconfig.test.json --pretty false + if ($LASTEXITCODE -ne 0) { + throw "CultMesh TypeScript test build failed." + } + $testFiles = Get-ChildItem -LiteralPath .\dist-test\test -Filter "*.test.js" | + Sort-Object Name | + ForEach-Object FullName + & $node.Source --test @testFiles + if ($LASTEXITCODE -ne 0) { + throw "CultMesh TypeScript reactive scaling verification failed." + } +} +finally { + Pop-Location +} + +$pythonPath = Join-Path $root "packages\cultcache-py\src" +$previousPythonPath = $env:PYTHONPATH +$env:PYTHONPATH = if ([string]::IsNullOrWhiteSpace($previousPythonPath)) { + $pythonPath +} +else { + $pythonPath + [IO.Path]::PathSeparator + $previousPythonPath +} +try { + & $pythonExecutable -m unittest discover ` + -s (Join-Path $root "packages\cultcache-py\tests") ` + -p "test_cultcache.py" ` + -k "reactive_scheduling_scales_with_changed_documents_only" + if ($LASTEXITCODE -ne 0) { + throw "CultMesh Python reactive scaling verification failed." + } +} +finally { + $env:PYTHONPATH = $previousPythonPath +} + +Write-Output '{"runtimes":["csharp","typescript","python"],"documentCounts":[1,100,1000],"changedFraction":0.01,"idleSchedules":0,"invariant":"scheduling is proportional to explicitly changed documents"}' diff --git a/src/GameCult.Mesh/CultMeshPrimitives.cs b/src/GameCult.Mesh/CultMeshPrimitives.cs index 00ba60b7..d31f8397 100644 --- a/src/GameCult.Mesh/CultMeshPrimitives.cs +++ b/src/GameCult.Mesh/CultMeshPrimitives.cs @@ -1371,6 +1371,12 @@ namespace GameCult.Mesh /// public TimeSpan FlushDelay { get; set; } = TimeSpan.FromMilliseconds(16); + /// + /// Gets or sets the clock that owns delayed flush scheduling. Tests and deterministic hosts may + /// replace the system clock without introducing a second scheduler abstraction. + /// + public ICultMeshClock Clock { get; set; } = CultMeshSystemClock.Instance; + /// Gets or sets whether canonical snapshots replace dirty local predictions immediately. public bool ReplaceDirtyCurrentOnCanonicalSnapshot { get; set; } } @@ -1425,7 +1431,7 @@ namespace GameCult.Mesh private readonly CultMeshReactiveDocumentOptions _options; private readonly object _gate = new(); private IDisposable? _subscription; - private Timer? _flushTimer; + private CancellationTokenSource? _flushDelayCancellation; private TDocument _current; private bool _dirty; private bool _flushQueued; @@ -1542,7 +1548,7 @@ namespace GameCult.Mesh return; } - _flushTimer?.Change(Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan); + CancelScheduledFlushLocked(); _flushing = true; _dirty = false; predicted = CultMeshDocumentHandle.CloneDocument(_current); @@ -1582,10 +1588,10 @@ namespace GameCult.Mesh if (_disposed) return; _disposed = true; + CancelScheduledFlushLocked(); } _subscription?.Dispose(); - _flushTimer?.Dispose(); } private void ApplyCanonicalSnapshot(TDocument canonical) @@ -1634,8 +1640,48 @@ namespace GameCult.Mesh return; } - _flushTimer ??= new Timer(_ => _ = Task.Run(FlushAsync)); - _flushTimer.Change(_options.FlushDelay, Timeout.InfiniteTimeSpan); + CancelScheduledFlushLocked(); + var cancellation = new CancellationTokenSource(); + _flushDelayCancellation = cancellation; + _ = FlushAfterDelayAsync(cancellation); + } + + private async Task FlushAfterDelayAsync(CancellationTokenSource cancellation) + { + try + { + await _options.Clock.DelayAsync(_options.FlushDelay, cancellation.Token).ConfigureAwait(false); + lock (_gate) + { + if (_disposed || cancellation.IsCancellationRequested) + return; + } + + await FlushAsync().ConfigureAwait(false); + } + catch (OperationCanceledException) when (cancellation.IsCancellationRequested) + { + } + finally + { + lock (_gate) + { + if (ReferenceEquals(_flushDelayCancellation, cancellation)) + _flushDelayCancellation = null; + } + + cancellation.Dispose(); + } + } + + private void CancelScheduledFlushLocked() + { + var cancellation = _flushDelayCancellation; + _flushDelayCancellation = null; + if (cancellation == null) + return; + + cancellation.Cancel(); } private static IReadOnlyDictionary CreateReconciliationDelta( diff --git a/src/GameCult.Mesh/docs/document-write-authority.md b/src/GameCult.Mesh/docs/document-write-authority.md index 19cc4bb3..0d8d8a68 100644 --- a/src/GameCult.Mesh/docs/document-write-authority.md +++ b/src/GameCult.Mesh/docs/document-write-authority.md @@ -69,4 +69,18 @@ Cut line: - nested edits made through `Update` are coalesced and published; - direct mutation of a returned snapshot cannot publish; - an idle reactive document creates no periodic detection work; +- scheduling 1, 100, or 1,000 reactive documents creates zero idle work, and + editing one percent schedules only that one percent; - canonical reconciliation and in-flight edits remain deterministic. + +Run the cross-runtime scheduling gate from a CultLib checkout: + +```powershell +powershell -ExecutionPolicy Bypass -File scripts/verify-reactive-document-scaling.ps1 +``` + +The gate runs the C#, TypeScript, and Python implementations against the same +1/100/1,000-document cases. It proves ownership and scheduling proportionality; +it does not claim allocation, payload-size, or end-to-end latency budgets. Those +need a separate measured benchmark against representative document bodies and +real transports. diff --git a/tests/GameCult.Mesh.Tests/CultMeshStreamingTests.cs b/tests/GameCult.Mesh.Tests/CultMeshStreamingTests.cs index 6fafbf16..273d1e87 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshStreamingTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshStreamingTests.cs @@ -3,6 +3,7 @@ using System.Buffers; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Threading; using System.Threading.Tasks; using FluentAssertions; using GameCult.Caching; @@ -1991,6 +1992,69 @@ public sealed class CultMeshStreamingTests reactive.IsDirty.Should().BeFalse(); } + [TestCase(1)] + [TestCase(100)] + [TestCase(1000)] + public async Task ReactiveDocument_SchedulingScalesWithChangedDocumentsOnly(int documentCount) + { + var clock = new BlockingCountClock(); + var reactiveDocuments = new List>(documentCount); + + try + { + for (var index = 0; index < documentCount; index++) + { + var subject = new Subject(); + var current = new MeshNoteDocument + { + Schema = "tests.mesh_note.v1", + Text = $"initial-{index}", + Revision = 1 + }; + var handle = CultMesh.Document( + $"mesh.note.reactive.scale.{index}", + CultMesh.Verse("scale", "test"), + _ => Task.FromResult(current), + _ => subject, + value => + { + current = value; + subject.OnNext(value); + return Task.CompletedTask; + }); + + reactiveDocuments.Add(await handle.AuthoritativeWriter().ReactiveAsync( + new CultMeshReactiveDocumentOptions + { + Clock = clock, + FlushDelay = TimeSpan.FromSeconds(1) + })); + } + + clock.DelayCount.Should().Be(0, "idle reactive documents must not schedule background work"); + + var changedDocumentCount = Math.Max(1, documentCount / 100); + for (var index = 0; index < changedDocumentCount; index++) + { + reactiveDocuments[index].Update(document => + { + document.Text = $"changed-{index}"; + document.Revision++; + }); + } + + clock.DelayCount.Should().Be( + changedDocumentCount, + "flush scheduling must be proportional to explicitly changed documents"); + reactiveDocuments.Count(document => document.IsDirty).Should().Be(changedDocumentCount); + } + finally + { + foreach (var reactiveDocument in reactiveDocuments) + reactiveDocument.Dispose(); + } + } + [Test] public async Task ReactiveDocument_ReplaceLocalFlushesWholeDocument() { @@ -4001,3 +4065,18 @@ internal sealed class FailedBackgroundSchemaClient : ICultNetSchemaClient, ICult { } } + +internal sealed class BlockingCountClock : ICultMeshClock +{ + private int _delayCount; + + public DateTimeOffset UtcNow => DateTimeOffset.UnixEpoch; + + public int DelayCount => Volatile.Read(ref _delayCount); + + public Task DelayAsync(TimeSpan delay, CancellationToken cancellationToken = default) + { + Interlocked.Increment(ref _delayCount); + return Task.Delay(Timeout.InfiniteTimeSpan, cancellationToken); + } +} From be846415d487e0c10b71235f4e4c60a41940bb53 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 01:07:25 +0200 Subject: [PATCH 068/283] Index CultCache records by document type --- src/GameCult.Caching/CultCache.cs | 30 ++++++++++++++++-- .../BackingStoreTests.cs | 31 +++++++++++++++++++ 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/src/GameCult.Caching/CultCache.cs b/src/GameCult.Caching/CultCache.cs index d3da3096..21b437af 100644 --- a/src/GameCult.Caching/CultCache.cs +++ b/src/GameCult.Caching/CultCache.cs @@ -1271,6 +1271,7 @@ namespace GameCult.Caching private readonly CultDocumentRegistry _registry; private readonly List _backingStores = new(); private readonly ConcurrentDictionary _entries = new(StringComparer.Ordinal); + private readonly ConcurrentDictionary> _typeMaps = new(); private readonly ConcurrentDictionary> _nameMaps = new(); private readonly ConcurrentDictionary<(Type Type, string Alias), ConcurrentDictionary> _indexMaps = new(); private readonly ConcurrentDictionary _globalKeys = new(); @@ -1597,11 +1598,26 @@ namespace GameCult.Caching /// Gets all cached documents assignable to the requested type. /// public IEnumerable GetAll() where T : class + { + return GetStoredDocuments().Select(entry => (T)entry.Document); + } + + /// + /// Gets typed cached records with their stable CultCache identities without scanning unrelated documents. + /// + public IEnumerable GetStoredDocuments() where T : class { var type = typeof(T); - return _entries.Values - .Where(entry => type.IsAssignableFrom(entry.Descriptor.DocumentType)) - .Select(entry => (T)entry.Document); + if (type.IsSealed) + { + return _typeMaps.TryGetValue(type, out var exact) + ? exact.Values + : Enumerable.Empty(); + } + + return _typeMaps + .Where(pair => type.IsAssignableFrom(pair.Key)) + .SelectMany(pair => pair.Value.Values); } /// @@ -1867,6 +1883,11 @@ namespace GameCult.Caching private void AddIndexes(CultStoredDocument stored) { + var typeMap = _typeMaps.GetOrAdd( + stored.Descriptor.DocumentType, + _ => new ConcurrentDictionary(StringComparer.Ordinal)); + typeMap[stored.Key.Value] = stored; + if (stored.Descriptor.IsGlobal) { _globalKeys[stored.Descriptor.DocumentType] = stored.Key.Value; @@ -1897,6 +1918,9 @@ namespace GameCult.Caching private void RemoveIndexes(CultStoredDocument stored) { + if (_typeMaps.TryGetValue(stored.Descriptor.DocumentType, out var typeMap)) + typeMap.TryRemove(stored.Key.Value, out _); + if (stored.Descriptor.IsGlobal) { _globalKeys.TryRemove(stored.Descriptor.DocumentType, out _); diff --git a/tests/GameCult.Caching.Tests/BackingStoreTests.cs b/tests/GameCult.Caching.Tests/BackingStoreTests.cs index 15d6d718..3910946a 100644 --- a/tests/GameCult.Caching.Tests/BackingStoreTests.cs +++ b/tests/GameCult.Caching.Tests/BackingStoreTests.cs @@ -806,6 +806,37 @@ namespace GameCult.Caching.Tests Assert.That(cache.Remove(key), Is.False); } + [Test] + public async Task CultCache_TypedStoredDocumentIndex_Tracks_Upsert_Replacement_And_Removal() + { + var cache = new CultCache(); + var key = new CultRecordKey("typed-index:named"); + await cache.UpsertAsync(typeof(NamedTestEntry), new NamedTestEntry + { + Name = "indexed", + Value = "first" + }, key); + await cache.UpsertAsync(typeof(AlternateNamedTestEntry), new AlternateNamedTestEntry + { + Name = "unrelated" + }, new CultRecordKey("typed-index:unrelated")); + + var initial = cache.GetStoredDocuments().Single(); + Assert.That(initial.Key, Is.EqualTo(key)); + Assert.That(((NamedTestEntry)initial.Document).Value, Is.EqualTo("first")); + + await cache.UpsertAsync(typeof(NamedTestEntry), new NamedTestEntry + { + Name = "indexed", + Value = "second" + }, key); + var replaced = cache.GetStoredDocuments().Single(); + Assert.That(((NamedTestEntry)replaced.Document).Value, Is.EqualTo("second")); + + Assert.That(cache.Remove(key), Is.True); + Assert.That(cache.GetStoredDocuments(), Is.Empty); + } + [Test] public async Task CultCache_FlushOnDispose_Persists_When_Enabled() { From a2301b6b09396bba6d070b679d807e1347a463ac Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 01:31:04 +0200 Subject: [PATCH 069/283] Share CultNet handlers across transports --- .../CultNetSchemaServerGroup.cs | 97 +++++++++++++++++ .../CultNetSchemaServerGroupTests.cs | 101 ++++++++++++++++++ 2 files changed, 198 insertions(+) create mode 100644 src/GameCult.Networking/CultNetSchemaServerGroup.cs create mode 100644 tests/GameCult.Networking.Tests/CultNetSchemaServerGroupTests.cs diff --git a/src/GameCult.Networking/CultNetSchemaServerGroup.cs b/src/GameCult.Networking/CultNetSchemaServerGroup.cs new file mode 100644 index 00000000..91a8484d --- /dev/null +++ b/src/GameCult.Networking/CultNetSchemaServerGroup.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace GameCult.Networking +{ + /// + /// Presents one logical CultNet schema server over several physical transports. + /// It owns handler fan-out and peer-lifecycle aggregation, but never owns or + /// disposes the transport servers themselves. + /// + public sealed class CultNetSchemaServerGroup : + ICultNetSchemaServer, + ICultNetSchemaServerPeerLifecycle, + IDisposable + { + private readonly IReadOnlyList _servers; + private readonly IReadOnlyList _lifecycles; + private bool _disposed; + + /// Creates one logical server from two or more transport servers. + public CultNetSchemaServerGroup(params ICultNetSchemaServer[] servers) + { + if (servers == null) throw new ArgumentNullException(nameof(servers)); + if (servers.Length < 2) + throw new ArgumentException("A CultNet schema server group requires at least two transports.", nameof(servers)); + if (servers.Any(server => server == null)) + throw new ArgumentException("A CultNet schema server group cannot contain a null transport.", nameof(servers)); + for (var left = 0; left < servers.Length; left++) + for (var right = left + 1; right < servers.Length; right++) + { + if (ReferenceEquals(servers[left], servers[right])) + throw new ArgumentException("A CultNet schema server group cannot contain the same transport twice.", nameof(servers)); + } + + _servers = Array.AsReadOnly(servers.ToArray()); + _lifecycles = Array.AsReadOnly(servers.OfType().ToArray()); + foreach (var lifecycle in _lifecycles) lifecycle.PeerDisconnected += ForwardPeerDisconnected; + } + + /// + public event Action? PeerDisconnected; + + /// + public void OnCultNet(Func callback) + where TMessage : ICultNetSchemaMessage + { + if (callback == null) throw new ArgumentNullException(nameof(callback)); + ThrowIfDisposed(); + var registered = 0; + try + { + foreach (var server in _servers) + { + server.OnCultNet(callback); + registered++; + } + } + catch + { + for (var index = 0; index < registered; index++) + _servers[index].RemoveCultNetMessageListener(callback); + throw; + } + } + + /// + public void RemoveCultNetMessageListener(Delegate callback) + where TMessage : ICultNetSchemaMessage + { + if (callback == null) throw new ArgumentNullException(nameof(callback)); + if (_disposed) return; + foreach (var server in _servers) server.RemoveCultNetMessageListener(callback); + } + + /// + /// Detaches lifecycle forwarding. The physical transports retain their + /// independent ownership and must be disposed by their creator. + /// + public void Dispose() + { + if (_disposed) return; + _disposed = true; + foreach (var lifecycle in _lifecycles) lifecycle.PeerDisconnected -= ForwardPeerDisconnected; + PeerDisconnected = null; + } + + private void ForwardPeerDisconnected(ICultNetSchemaServerPeer peer) => + PeerDisconnected?.Invoke(peer); + + private void ThrowIfDisposed() + { + if (_disposed) throw new ObjectDisposedException(nameof(CultNetSchemaServerGroup)); + } + } +} diff --git a/tests/GameCult.Networking.Tests/CultNetSchemaServerGroupTests.cs b/tests/GameCult.Networking.Tests/CultNetSchemaServerGroupTests.cs new file mode 100644 index 00000000..79e7e14f --- /dev/null +++ b/tests/GameCult.Networking.Tests/CultNetSchemaServerGroupTests.cs @@ -0,0 +1,101 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using NUnit.Framework; + +namespace GameCult.Networking.Tests +{ + [TestFixture] + public sealed class CultNetSchemaServerGroupTests + { + [Test] + public async Task RegistersAndRemovesTheSameLogicalHandlerAcrossTransports() + { + var tcp = new FakeServer(); + var webSocket = new FakeServer(); + using var group = new CultNetSchemaServerGroup(tcp, webSocket); + var received = new List(); + Func handler = (message, _) => + { + received.Add(message.RuntimeId); + return Task.CompletedTask; + }; + + group.OnCultNet(handler); + await tcp.DispatchAsync(new CultNetHelloMessage { RuntimeId = "tcp" }); + await webSocket.DispatchAsync(new CultNetHelloMessage { RuntimeId = "websocket" }); + group.RemoveCultNetMessageListener(handler); + + Assert.That(received, Is.EqualTo(new[] { "tcp", "websocket" })); + Assert.That(tcp.HasHandler(), Is.False); + Assert.That(webSocket.HasHandler(), Is.False); + } + + [Test] + public void AggregatesPeerLifetimeWithoutTakingTransportOwnership() + { + var tcp = new FakeServer(); + var webSocket = new FakeServer(); + var group = new CultNetSchemaServerGroup(tcp, webSocket); + var peer = new FakePeer(); + var disconnected = new List(); + group.PeerDisconnected += disconnected.Add; + + tcp.Disconnect(peer); + webSocket.Disconnect(peer); + group.Dispose(); + tcp.Disconnect(peer); + + Assert.That(disconnected, Is.EqualTo(new[] { peer, peer })); + Assert.That(tcp.Disposed, Is.False); + Assert.That(webSocket.Disposed, Is.False); + } + + [Test] + public void RejectsAGroupThatDoesNotActuallyAddASecondTransport() + { + var server = new FakeServer(); + Assert.Multiple(() => + { + Assert.That(() => new CultNetSchemaServerGroup(server), Throws.ArgumentException); + Assert.That(() => new CultNetSchemaServerGroup(server, server), Throws.ArgumentException); + }); + } + + private sealed class FakeServer : + ICultNetSchemaServer, + ICultNetSchemaServerPeerLifecycle + { + private readonly Dictionary _handlers = new(); + public bool Disposed { get; private set; } + public event Action? PeerDisconnected; + + public void OnCultNet(Func callback) + where TMessage : ICultNetSchemaMessage => + _handlers[typeof(TMessage)] = callback; + + public void RemoveCultNetMessageListener(Delegate callback) + where TMessage : ICultNetSchemaMessage + { + if (_handlers.TryGetValue(typeof(TMessage), out var current) && current == callback) + _handlers.Remove(typeof(TMessage)); + } + + public bool HasHandler() where TMessage : ICultNetSchemaMessage => + _handlers.ContainsKey(typeof(TMessage)); + + public Task DispatchAsync(TMessage message) where TMessage : ICultNetSchemaMessage => + ((Func)_handlers[typeof(TMessage)])(message, new FakePeer()); + + public void Disconnect(ICultNetSchemaServerPeer peer) => PeerDisconnected?.Invoke(peer); + } + + private sealed class FakePeer : ICultNetSchemaServerPeer + { + public void SendCultNet(TMessage message) where TMessage : ICultNetSchemaMessage + { + } + } + } +} From c5d9435deb36f386e469aee0009fe984a832423f Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 02:08:49 +0200 Subject: [PATCH 070/283] Carry portable schema identity on raw records --- packages/cultmesh-browser/src/index.ts | 12 +++++++++--- .../cultmesh-browser/test/cultmesh-browser.test.ts | 5 ++++- packages/cultnet-ts/src/contracts.ts | 6 ++++++ src/GameCult.Networking/CultNetDocumentRegistry.cs | 6 ++++++ src/GameCult.Networking/CultNetSchemaMessages.cs | 12 ++++++++++++ tests/GameCult.Networking.Tests/NetworkingTests.cs | 3 +++ 6 files changed, 40 insertions(+), 4 deletions(-) diff --git a/packages/cultmesh-browser/src/index.ts b/packages/cultmesh-browser/src/index.ts index 717f89a9..eb2420e3 100644 --- a/packages/cultmesh-browser/src/index.ts +++ b/packages/cultmesh-browser/src/index.ts @@ -571,7 +571,7 @@ export class CultMeshBrowserClient implements AsyncDisposable { this.#pendingSnapshots.delete(message.messageId); clearTimeout(pending.timer); const matches = message.documents.filter(record => - record.schemaId === pending.lease.schemaId && record.recordKey === pending.lease.recordKey); + record.recordKey === pending.lease.recordKey && recordMatchesSchema(record, pending.lease.schemaId)); if (matches.length > 1) { pending.reject(new Error(`CultMesh snapshot returned duplicate record '${pending.lease.recordKey}'.`)); return; @@ -584,11 +584,11 @@ export class CultMeshBrowserClient implements AsyncDisposable { const lease = this.#leases.get(message.subscriptionId) ?? this.#openingLeases.get(message.subscriptionId); if (!lease) return; if (message.changeKind === "removed") { - if (message.recordKey === lease.recordKey && message.schemaId === lease.schemaId) lease.apply(undefined); + if (message.recordKey === lease.recordKey) lease.apply(undefined); return; } const record = message.document; - if (record?.recordKey === lease.recordKey && record.schemaId === lease.schemaId) lease.apply(record); + if (record?.recordKey === lease.recordKey && recordMatchesSchema(record, lease.schemaId)) lease.apply(record); } private rejectCorrelated(reason: string): void { @@ -628,6 +628,12 @@ export function decodeCultNetPayload(record: CultNetRawDocumentRecord): T { return decode(record.payload) as T; } +function recordMatchesSchema(record: CultNetRawDocumentRecord, requestedSchema: string): boolean { + return record.schemaId === requestedSchema || + record.schemaName === requestedSchema || + record.schemaVersion === requestedSchema; +} + export function decodeCultNetOperationPayload(response: CultNetOperationResponseMessage): T { if (response.payloadEncoding !== "messagepack-base64") { throw new Error(`Unsupported CultNet operation payload '${response.payloadEncoding ?? "unspecified"}'.`); diff --git a/packages/cultmesh-browser/test/cultmesh-browser.test.ts b/packages/cultmesh-browser/test/cultmesh-browser.test.ts index 3836790d..b05b184b 100644 --- a/packages/cultmesh-browser/test/cultmesh-browser.test.ts +++ b/packages/cultmesh-browser/test/cultmesh-browser.test.ts @@ -270,7 +270,10 @@ class FakeProvider { private record(): CultNetRawDocumentRecord { return { - schemaId: "sample.counter_state.v1", + schemaId: "sha256:sample-counter-state", + schemaName: "sample.counter_state", + schemaVersion: "sample.counter_state.v1", + schemaContentHash: "sha256:sample-counter-state-content", recordKey: "counter:main", storedAt: "2026-08-17T00:00:00Z", payloadEncoding: "messagepack", diff --git a/packages/cultnet-ts/src/contracts.ts b/packages/cultnet-ts/src/contracts.ts index ffdbcf6e..1c3998ae 100644 --- a/packages/cultnet-ts/src/contracts.ts +++ b/packages/cultnet-ts/src/contracts.ts @@ -190,6 +190,9 @@ export interface CultNetDocumentDeleteMessage { export interface CultNetRawDocumentRecord { schemaId: string; + schemaName?: string; + schemaVersion?: string; + schemaContentHash?: string; recordKey: string; storedAt: string; payloadEncoding: CultNetRawPayloadEncoding; @@ -1104,6 +1107,9 @@ function validateRawDocumentRecord( const candidate = input as Record; requireNonEmptyString(candidate.schemaId, `${instancePath}/schemaId`); + requireOptionalNonEmptyString(candidate.schemaName, `${instancePath}/schemaName`); + requireOptionalNonEmptyString(candidate.schemaVersion, `${instancePath}/schemaVersion`); + requireOptionalNonEmptyString(candidate.schemaContentHash, `${instancePath}/schemaContentHash`); requireNonEmptyString(candidate.recordKey, `${instancePath}/recordKey`); requireNonEmptyString(candidate.storedAt, `${instancePath}/storedAt`); if (candidate.payloadEncoding !== "messagepack") { diff --git a/src/GameCult.Networking/CultNetDocumentRegistry.cs b/src/GameCult.Networking/CultNetDocumentRegistry.cs index 8017ad2f..cc4b319a 100644 --- a/src/GameCult.Networking/CultNetDocumentRegistry.cs +++ b/src/GameCult.Networking/CultNetDocumentRegistry.cs @@ -224,6 +224,9 @@ namespace GameCult.Networking Document = new CultNetRawDocumentRecord { SchemaId = binding.SchemaId, + SchemaName = descriptor.SchemaName, + SchemaVersion = descriptor.SchemaVersion, + SchemaContentHash = descriptor.ContentHash, RecordKey = handle.Key.Value, StoredAt = storedAt, PayloadEncoding = "messagepack", @@ -292,6 +295,9 @@ namespace GameCult.Networking documents.Add(new CultNetRawDocumentRecord { SchemaId = binding.SchemaId, + SchemaName = descriptor.SchemaName, + SchemaVersion = descriptor.SchemaVersion, + SchemaContentHash = descriptor.ContentHash, RecordKey = key, StoredAt = storedAt, PayloadEncoding = "messagepack", diff --git a/src/GameCult.Networking/CultNetSchemaMessages.cs b/src/GameCult.Networking/CultNetSchemaMessages.cs index 9a8800fc..764238ff 100644 --- a/src/GameCult.Networking/CultNetSchemaMessages.cs +++ b/src/GameCult.Networking/CultNetSchemaMessages.cs @@ -608,6 +608,18 @@ namespace GameCult.Networking /// [Key("schemaId")] public string SchemaId { get; set; } = string.Empty; /// + /// Gets or sets the stable schema family name when the publisher has a typed descriptor. + /// + [Key("schemaName")] public string? SchemaName { get; set; } + /// + /// Gets or sets the portable versioned schema contract when the publisher has a typed descriptor. + /// + [Key("schemaVersion")] public string? SchemaVersion { get; set; } + /// + /// Gets or sets the canonical schema content hash when the publisher has a typed descriptor. + /// + [Key("schemaContentHash")] public string? SchemaContentHash { get; set; } + /// /// Gets or sets the record key. /// [Key("recordKey")] public string RecordKey { get; set; } = string.Empty; diff --git a/tests/GameCult.Networking.Tests/NetworkingTests.cs b/tests/GameCult.Networking.Tests/NetworkingTests.cs index 44437cc3..dd4a63c9 100644 --- a/tests/GameCult.Networking.Tests/NetworkingTests.cs +++ b/tests/GameCult.Networking.Tests/NetworkingTests.cs @@ -1982,6 +1982,9 @@ namespace GameCult.Networking.Tests Assert.That(message, Is.Not.Null); Assert.That(message!.Document!.SchemaId, Is.EqualTo(descriptor.SchemaId)); + Assert.That(message.Document.SchemaName, Is.EqualTo(descriptor.SchemaName)); + Assert.That(message.Document.SchemaVersion, Is.EqualTo(descriptor.SchemaVersion)); + Assert.That(message.Document.SchemaContentHash, Is.EqualTo(descriptor.ContentHash)); } [Test] From 989253a208643edaabc2cbd84b54b867afd036ee Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 02:18:56 +0200 Subject: [PATCH 071/283] Reuse Odin fixture for product route witnesses --- samples/eve-browser-network/Program.cs | 20 +++++++++++++++----- samples/eve-browser-network/README.md | 6 ++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/samples/eve-browser-network/Program.cs b/samples/eve-browser-network/Program.cs index 9686b36c..21ef3c32 100644 --- a/samples/eve-browser-network/Program.cs +++ b/samples/eve-browser-network/Program.cs @@ -36,12 +36,12 @@ static async Task RunOdinAsync(Args arguments) throw new ArgumentException("The Odin fixture requires --provider-endpoint."); using var catalog = new CultMeshVerseCatalog(); catalog.Upsert(new CultMeshVerseDescriptor( - "sample.counter", - "CultMesh browser counter", + arguments.VerseId, + arguments.VerseName, CultMeshVerseAuthorityModel.OperatorCluster, - new CultMeshVerseCompatibility("cultmesh.v1", "sample-counter-v1"), + new CultMeshVerseCompatibility(arguments.TransportVersion, arguments.RulesHash), discoveryEndpoints: [arguments.ProviderEndpoint], - authorityRuntimeIds: ["sample.counter-provider"], + authorityRuntimeIds: [arguments.AuthorityRuntimeId], description: "Local executable Odin fixture for the browser/network onboarding witness.")); await using var schemaServer = new CultNetWebSocketSchemaServer(); @@ -192,6 +192,11 @@ sealed class Args public string Endpoint { get; private init; } = ""; public string ProviderEndpoint { get; private init; } = ""; public string Token { get; private init; } = "sample-session"; + public string VerseId { get; private init; } = "sample.counter"; + public string VerseName { get; private init; } = "CultMesh browser counter"; + public string AuthorityRuntimeId { get; private init; } = "sample.counter-provider"; + public string TransportVersion { get; private init; } = "cultmesh.v1"; + public string RulesHash { get; private init; } = "sample-counter-v1"; public static Args Parse(string[] values) { @@ -206,7 +211,12 @@ sealed class Args StatePath = named.GetValueOrDefault("--state", "sample-counter.cc"), Endpoint = named.GetValueOrDefault("--endpoint", ""), ProviderEndpoint = named.GetValueOrDefault("--provider-endpoint", ""), - Token = named.GetValueOrDefault("--token", "sample-session") + Token = named.GetValueOrDefault("--token", "sample-session"), + VerseId = named.GetValueOrDefault("--verse-id", "sample.counter"), + VerseName = named.GetValueOrDefault("--verse-name", "CultMesh browser counter"), + AuthorityRuntimeId = named.GetValueOrDefault("--authority-runtime-id", "sample.counter-provider"), + TransportVersion = named.GetValueOrDefault("--transport-version", "cultmesh.v1"), + RulesHash = named.GetValueOrDefault("--rules-hash", "sample-counter-v1") }; } } diff --git a/samples/eve-browser-network/README.md b/samples/eve-browser-network/README.md index 33de2dbe..3b85dbbc 100644 --- a/samples/eve-browser-network/README.md +++ b/samples/eve-browser-network/README.md @@ -24,3 +24,9 @@ the local Odin fixture, and requires the still-open browser to rediscover the route, resubscribe, execute a second command, and preserve the durable count. The fixture speaks the production Verse-catalog contract; a deployment smoke against the full Odin daemon remains a separate infrastructure gate. + +The `odin` fixture defaults to this sample's Verse, but its `--verse-id`, +`--verse-name`, `--authority-runtime-id`, `--transport-version`, and +`--rules-hash` arguments can advertise another real provider during a product +route-rotation witness. The provider endpoint remains data owned by Odin; the +consumer still connects only by stable Verse and provider identity. From 669f63811108f6b524ce3b58b41de92139894bc6 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 02:25:22 +0200 Subject: [PATCH 072/283] Share one scheduler across Python reactive documents --- packages/cultcache-py/src/cultmesh_py/node.py | 97 +++++++++++++++++-- packages/cultcache-py/tests/test_cultcache.py | 65 ++++++++++--- scripts/verify-reactive-document-scaling.ps1 | 20 +++- 3 files changed, 158 insertions(+), 24 deletions(-) diff --git a/packages/cultcache-py/src/cultmesh_py/node.py b/packages/cultcache-py/src/cultmesh_py/node.py index 3afddd24..fb302c8c 100644 --- a/packages/cultcache-py/src/cultmesh_py/node.py +++ b/packages/cultcache-py/src/cultmesh_py/node.py @@ -1,6 +1,9 @@ from __future__ import annotations import threading +import heapq +import time +import traceback from dataclasses import dataclass, field from datetime import UTC, datetime from pathlib import Path @@ -87,6 +90,87 @@ class CultMeshReactiveDocumentOptions: replace_dirty_current_on_canonical_snapshot: bool = False +class _CultMeshScheduledCall: + def __init__(self, callback: Callable[[], None], wake: Callable[[], None]) -> None: + self._callback: Callable[[], None] | None = callback + self._wake = wake + self._lock = threading.Lock() + + def cancel(self) -> None: + with self._lock: + self._callback = None + self._wake() + + def take(self) -> Callable[[], None] | None: + with self._lock: + callback = self._callback + self._callback = None + return callback + + @property + def cancelled(self) -> bool: + with self._lock: + return self._callback is None + + +class _CultMeshReactiveScheduler: + """One lazy daemon worker owns delayed reactive flushes for the process.""" + + def __init__(self) -> None: + self._condition = threading.Condition() + self._queue: list[tuple[float, int, _CultMeshScheduledCall]] = [] + self._sequence = 0 + self._worker: threading.Thread | None = None + + def schedule(self, delay_seconds: float, callback: Callable[[], None]) -> _CultMeshScheduledCall: + call = _CultMeshScheduledCall(callback, self._wake) + with self._condition: + self._sequence += 1 + heapq.heappush( + self._queue, + (time.monotonic() + max(0.0, delay_seconds), self._sequence, call), + ) + if self._worker is None: + self._worker = threading.Thread( + target=self._run, + name="cultmesh-reactive-scheduler", + daemon=True, + ) + self._worker.start() + self._condition.notify() + return call + + def _wake(self) -> None: + with self._condition: + self._condition.notify() + + def _run(self) -> None: + while True: + callback: Callable[[], None] | None = None + with self._condition: + while callback is None: + while self._queue and self._queue[0][2].cancelled: + heapq.heappop(self._queue) + if not self._queue: + self._condition.wait() + continue + deadline, _, call = self._queue[0] + remaining = deadline - time.monotonic() + if remaining > 0: + self._condition.wait(remaining) + continue + heapq.heappop(self._queue) + callback = call.take() + if callback is not None: + try: + callback() + except Exception: + traceback.print_exc() + + +_REACTIVE_SCHEDULER = _CultMeshReactiveScheduler() + + @dataclass class CultMeshNode: cache: CultCache = field(default_factory=CultCache) @@ -1373,7 +1457,7 @@ class CultMeshReactiveDocument: self._dirty = False self._flushing = False self._flush_queued = False - self._flush_timer: threading.Timer | None = None + self._flush_timer: _CultMeshScheduledCall | None = None self._reconciliation_version = 0 self.reconciliation: CultMeshReactiveDocumentReconciliation | None = None self._current = self._clone(self._database.get_required(self._document, self._key)) @@ -1503,15 +1587,12 @@ class CultMeshReactiveDocument: self.reconciliation = None def _schedule_flush_locked(self) -> None: - if self._options.flush_delay_seconds <= 0: - threading.Thread(target=self.flush, daemon=True).start() - return if self._flush_timer is not None: self._flush_timer.cancel() - timer = threading.Timer(self._options.flush_delay_seconds, self.flush) - timer.daemon = True - self._flush_timer = timer - timer.start() + self._flush_timer = _REACTIVE_SCHEDULER.schedule( + self._options.flush_delay_seconds, + self.flush, + ) def _clone(self, value: Any) -> Any: return self._document.decode_payload(self._document.encode_payload(value)) diff --git a/packages/cultcache-py/tests/test_cultcache.py b/packages/cultcache-py/tests/test_cultcache.py index f753b12e..82a00845 100644 --- a/packages/cultcache-py/tests/test_cultcache.py +++ b/packages/cultcache-py/tests/test_cultcache.py @@ -2595,23 +2595,27 @@ class CultCacheTests(unittest.TestCase): scheduled_timers: list[Any] = [] - class FakeTimer: - def __init__(self, interval: float, callback: Callable[[], None]) -> None: - self.interval = interval + class FakeScheduledCall: + def __init__(self, delay_seconds: float, callback: Callable[[], None]) -> None: + self.delay_seconds = delay_seconds self.callback = callback - self.daemon = False self.cancelled = False - self.started = False - scheduled_timers.append(self) - - def start(self) -> None: - self.started = True def cancel(self) -> None: self.cancelled = True + class FakeScheduler: + def schedule( + self, + delay_seconds: float, + callback: Callable[[], None], + ) -> FakeScheduledCall: + call = FakeScheduledCall(delay_seconds, callback) + scheduled_timers.append(call) + return call + reactive_documents: list[Any] = [] - with patch("cultmesh_py.node.threading.Timer", FakeTimer): + with patch("cultmesh_py.node._REACTIVE_SCHEDULER", FakeScheduler()): try: for index in range(document_count): reactive_documents.append( @@ -2634,7 +2638,6 @@ class CultCacheTests(unittest.TestCase): ) self.assertEqual(len(scheduled_timers), changed_document_count) - self.assertTrue(all(timer.started for timer in scheduled_timers)) self.assertEqual( sum(reactive.is_dirty for reactive in reactive_documents), changed_document_count, @@ -2645,6 +2648,46 @@ class CultCacheTests(unittest.TestCase): self.assertTrue(all(timer.cancelled for timer in scheduled_timers)) + def test_cultmesh_reactive_documents_share_one_lazy_scheduler_thread(self) -> None: + document = define_document_type( + "mesh.reactive_shared_scheduler_note", + encode=lambda value: value, + decode=lambda value: value, + ) + node = create_node(runtime_id="python-reactive-shared-scheduler") + node.register_document(document) + reactive_documents: list[Any] = [] + try: + for index in range(100): + node.put(document, f"note:{index}", {"body": "initial", "revision": 1}) + reactive_documents.append( + node.authoritative_writer(document, f"note:{index}").reactive( + CultMeshReactiveDocumentOptions(flush_delay_seconds=60.0) + ) + ) + + before = sum( + thread.name == "cultmesh-reactive-scheduler" + for thread in threading.enumerate() + ) + for index, reactive in enumerate(reactive_documents): + reactive.update( + lambda draft, changed=index: draft.update( + body=f"changed-{changed}", + revision=2, + ) + ) + after = sum( + thread.name == "cultmesh-reactive-scheduler" + for thread in threading.enumerate() + ) + + self.assertLessEqual(before, 1) + self.assertEqual(after, 1) + finally: + for reactive in reactive_documents: + reactive.dispose() + def test_cultmesh_observed_document_cannot_publish_borrowed_mutation(self) -> None: document = define_document_type( "mesh.observed_note", diff --git a/scripts/verify-reactive-document-scaling.ps1 b/scripts/verify-reactive-document-scaling.ps1 index 1729ed4d..e3555ae2 100644 --- a/scripts/verify-reactive-document-scaling.ps1 +++ b/scripts/verify-reactive-document-scaling.ps1 @@ -1,12 +1,22 @@ param( - [string] $PythonPath = "" + [string] $PythonPath = "", + [string] $NodePath = "" ) $ErrorActionPreference = "Stop" $root = Split-Path -Parent $PSScriptRoot $dotnet = Get-Command dotnet -ErrorAction Stop -$node = Get-Command node -ErrorAction Stop +$nodeExecutable = if ([string]::IsNullOrWhiteSpace($NodePath)) { + $node = Get-Command node -ErrorAction SilentlyContinue + if ($node) { $node.Source } else { Join-Path $env:ProgramFiles "nodejs\node.exe" } +} +else { + [IO.Path]::GetFullPath($NodePath) +} +if (-not (Test-Path -LiteralPath $nodeExecutable -PathType Leaf)) { + throw "Node.js executable not found: $nodeExecutable" +} $pythonExecutable = if ([string]::IsNullOrWhiteSpace($PythonPath)) { (Get-Command python -ErrorAction Stop).Source } @@ -31,18 +41,18 @@ if ($LASTEXITCODE -ne 0) { Push-Location (Join-Path $root "packages\cultmesh-ts") try { - & $node.Source $typescript -p tsconfig.json --pretty false + & $nodeExecutable $typescript -p tsconfig.json --pretty false if ($LASTEXITCODE -ne 0) { throw "CultMesh TypeScript source build failed." } - & $node.Source $typescript -p tsconfig.test.json --pretty false + & $nodeExecutable $typescript -p tsconfig.test.json --pretty false if ($LASTEXITCODE -ne 0) { throw "CultMesh TypeScript test build failed." } $testFiles = Get-ChildItem -LiteralPath .\dist-test\test -Filter "*.test.js" | Sort-Object Name | ForEach-Object FullName - & $node.Source --test @testFiles + & $nodeExecutable --test @testFiles if ($LASTEXITCODE -ne 0) { throw "CultMesh TypeScript reactive scaling verification failed." } From f38966b4b95013396987622bc58be99955cfc34b Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 02:29:14 +0200 Subject: [PATCH 073/283] Bound retained session callback resources --- src/GameCult.Mesh/CultMeshSessions.cs | 92 ++++++++++++++----- .../CultMeshClientTests.cs | 33 ++++++- 2 files changed, 100 insertions(+), 25 deletions(-) diff --git a/src/GameCult.Mesh/CultMeshSessions.cs b/src/GameCult.Mesh/CultMeshSessions.cs index 5011a00a..0a655ae8 100644 --- a/src/GameCult.Mesh/CultMeshSessions.cs +++ b/src/GameCult.Mesh/CultMeshSessions.cs @@ -222,7 +222,6 @@ namespace GameCult.Mesh public sealed class CultMeshSession : IDisposable { private readonly Subject _states = new(); - private readonly ConcurrentBag _subscriptions = new(); private readonly ManagedSchemaChannel _channel; private long _physicalGeneration; private bool _disposed; @@ -244,10 +243,7 @@ namespace GameCult.Mesh public IDisposable OnCultNet(Action callback) where T : ICultNetSchemaMessage { if (callback == null) throw new ArgumentNullException(nameof(callback)); - var subscription = new SessionSubscription(callback); - Channel.OnCultNet(subscription.Invoke); - _subscriptions.Add(subscription); - return subscription; + return _channel.Subscribe(callback); } internal void Transition(CultMeshSessionState state) { State = state; _states.OnNext(state); } internal void ReplacePhysicalChannel(ICultNetSchemaClient channel) @@ -259,7 +255,6 @@ namespace GameCult.Mesh { if (_disposed) return; _disposed = true; - foreach (var subscription in _subscriptions) subscription.Dispose(); _channel.Dispose(); _states.Dispose(); } @@ -267,7 +262,7 @@ namespace GameCult.Mesh private sealed class ManagedSchemaChannel : ICultNetSchemaClient { private readonly object _gate = new(); - private readonly List _registrations = new(); + private readonly Dictionary _registrations = new(); private ICultNetSchemaClient _physical; private bool _disposed; @@ -292,14 +287,23 @@ namespace GameCult.Mesh } } public void OnCultNet(Action callback) where T : ICultNetSchemaMessage + { + _ = Subscribe(callback); + } + public IDisposable Subscribe(Action callback) where T : ICultNetSchemaMessage { if (callback == null) throw new ArgumentNullException(nameof(callback)); lock (_gate) { ThrowIfDisposed(); - var registration = new ChannelRegistration(callback); - registration.Attach(_physical); - _registrations.Add(registration); + if (!_registrations.TryGetValue(typeof(T), out var existing)) + { + var created = new ChannelRegistration(); + created.Attach(_physical); + _registrations.Add(typeof(T), created); + existing = created; + } + return ((ChannelRegistration)existing).Subscribe(callback); } } public void Replace(ICultNetSchemaClient physical) @@ -310,7 +314,7 @@ namespace GameCult.Mesh { ThrowIfDisposed(); previous = _physical; - foreach (var registration in _registrations) registration.Attach(physical); + foreach (var registration in _registrations.Values) registration.Attach(physical); _physical = physical; } previous.Dispose(); @@ -323,27 +327,69 @@ namespace GameCult.Mesh if (_disposed) return; _disposed = true; physical = _physical; + foreach (var registration in _registrations.Values) registration.Dispose(); _registrations.Clear(); } physical.Dispose(); } private void ThrowIfDisposed() { if (_disposed) throw new ObjectDisposedException(nameof(ManagedSchemaChannel)); } - private interface IChannelRegistration { void Attach(ICultNetSchemaClient physical); } + private interface IChannelRegistration : IDisposable { void Attach(ICultNetSchemaClient physical); } private sealed class ChannelRegistration : IChannelRegistration where T : ICultNetSchemaMessage { - private readonly Action _callback; - public ChannelRegistration(Action callback) => _callback = callback; - public void Attach(ICultNetSchemaClient physical) => physical.OnCultNet(_callback); - } - } + private readonly object _gate = new(); + private readonly Dictionary> _callbacks = new(); + private long _nextId; + private bool _disposed; - private sealed class SessionSubscription : IDisposable where T : ICultNetSchemaMessage - { - private Action? _callback; - public SessionSubscription(Action callback) { _callback = callback; } - public void Invoke(T message) => Volatile.Read(ref _callback)?.Invoke(message); - public void Dispose() => Interlocked.Exchange(ref _callback, null); + public IDisposable Subscribe(Action callback) + { + lock (_gate) + { + if (_disposed) throw new ObjectDisposedException(nameof(ChannelRegistration)); + var id = ++_nextId; + _callbacks.Add(id, callback); + return new Subscription(this, id); + } + } + + public void Attach(ICultNetSchemaClient physical) => physical.OnCultNet(Dispatch); + + public void Dispose() + { + lock (_gate) + { + _disposed = true; + _callbacks.Clear(); + } + } + + private void Dispatch(T message) + { + Action[] callbacks; + lock (_gate) callbacks = _callbacks.Values.ToArray(); + foreach (var callback in callbacks) callback(message); + } + + private void Unsubscribe(long id) + { + lock (_gate) _callbacks.Remove(id); + } + + private sealed class Subscription : IDisposable + { + private ChannelRegistration? _owner; + private readonly long _id; + + public Subscription(ChannelRegistration owner, long id) + { + _owner = owner; + _id = id; + } + + public void Dispose() => Interlocked.Exchange(ref _owner, null)?.Unsubscribe(_id); + } + } } private sealed class SessionSchemaClient : ICultNetSchemaClient diff --git a/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs b/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs index bf5de6a7..f16ee060 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs @@ -205,6 +205,32 @@ public sealed class CultMeshClientTests connector.SubscribeCount.Should().Be(2); } + [Test] + public async Task Document_OneHundredThousandDistinctLeaseCyclesLeaveNoResourcesOrCallbacks() + { + const int leaseCount = 100_000; + var connector = new DocumentConnector(); + using var mesh = new CultMeshClient(new CultMeshClientOptions + { + RendezvousEndpoints = new[] { "rudp://odin:3076" }, + Discovery = new CultMeshVerseDiscoveryClientOptions { CreateClient = () => new RendezvousClient() }, + Connectors = new[] { connector } + }); + + for (var index = 0; index < leaseCount; index++) + { + var recordKey = "surface:churn:" + index; + using var lease = await mesh.LeaseDocumentAsync("aetheria", recordKey); + (await lease.Handle.LatestAsync()).Id.Should().Be(recordKey); + } + + mesh.ActiveDocumentResourceCount.Should().Be(0); + mesh.ActiveCollectionResourceCount.Should().Be(0); + connector.Clients.Should().ContainSingle(); + connector.Clients[0].HandlerRegistrationCount.Should().Be(2, + "one physical handler per message type must serve every logical lease"); + } + [Test] public async Task SubmitDocument_SendsUncommittedInputThroughStableIdentitySession() { @@ -348,6 +374,7 @@ public sealed class CultMeshClientTests public bool Connected => true; public Task BackgroundFailure => _failure.Task; public int SubscribeCount { get; private set; } + public int HandlerRegistrationCount { get; private set; } public List Submitted { get; } = new(); public void Connect(string host, int port) { } public void SendCultNet(T message) where T : ICultNetSchemaMessage @@ -364,10 +391,11 @@ public sealed class CultMeshClientTests _snapshotsToSuppress--; return; } + var recordKey = request.RecordKeys?.SingleOrDefault() ?? "surface:pilot"; var put = _documents.CreateRawDocumentPutMessage( "test-put", - new CultRecordHandle(new CultRecordKey("surface:pilot")), - new ClientTestDocument { Id = "surface:pilot", Text = _text }); + new CultRecordHandle(new CultRecordKey(recordKey)), + new ClientTestDocument { Id = recordKey, Text = _text }); var response = new CultNetSnapshotResponseRawMessage { MessageId = request.MessageId, @@ -377,6 +405,7 @@ public sealed class CultMeshClientTests } public void OnCultNet(Action callback) where T : ICultNetSchemaMessage { + HandlerRegistrationCount++; if (typeof(T) == typeof(CultNetSnapshotResponseRawMessage)) _snapshots.Add(response => callback((T)(object)response)); } From fbf93f3570008c7c3d9aa2010c9de487523a4129 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 02:37:13 +0200 Subject: [PATCH 074/283] Measure and bound reactive document cost --- packages/cultcache-py/src/cultmesh_py/node.py | 14 +- .../measure-reactive-document-performance.ps1 | 28 +++ src/GameCult.Mesh/CultMeshPrimitives.cs | 21 +- .../GameCult.Mesh.PerformanceProbe.csproj | 11 + .../GameCult.Mesh.PerformanceProbe/Program.cs | 211 ++++++++++++++++++ 5 files changed, 273 insertions(+), 12 deletions(-) create mode 100644 scripts/measure-reactive-document-performance.ps1 create mode 100644 tools/GameCult.Mesh.PerformanceProbe/GameCult.Mesh.PerformanceProbe.csproj create mode 100644 tools/GameCult.Mesh.PerformanceProbe/Program.cs diff --git a/packages/cultcache-py/src/cultmesh_py/node.py b/packages/cultcache-py/src/cultmesh_py/node.py index fb302c8c..09ac2012 100644 --- a/packages/cultcache-py/src/cultmesh_py/node.py +++ b/packages/cultcache-py/src/cultmesh_py/node.py @@ -1566,11 +1566,13 @@ class CultMeshReactiveDocument: with self._lock: if self._disposed: return - canonical = self._clone(change.value) + replacement = None if self._dirty or self._flushing: - predicted = self._clone(self._current) - delta = self._create_delta(predicted, canonical) + delta = self._create_delta(self._current, change.value) if delta: + canonical = self._clone(change.value) + predicted = self._clone(self._current) + replacement = canonical self._reconciliation_version += 1 self.reconciliation = CultMeshReactiveDocumentReconciliation( canonical=canonical, @@ -1583,7 +1585,11 @@ class CultMeshReactiveDocument: self.reconciliation = None if not self._options.replace_dirty_current_on_canonical_snapshot: return - self._current = canonical + self._current = ( + replacement + if replacement is not None + else self._clone(change.value) + ) self.reconciliation = None def _schedule_flush_locked(self) -> None: diff --git a/scripts/measure-reactive-document-performance.ps1 b/scripts/measure-reactive-document-performance.ps1 new file mode 100644 index 00000000..45598ed0 --- /dev/null +++ b/scripts/measure-reactive-document-performance.ps1 @@ -0,0 +1,28 @@ +param( + [switch] $Quick +) + +$ErrorActionPreference = "Stop" +$root = Split-Path -Parent $PSScriptRoot +$project = Join-Path $root "tools\GameCult.Mesh.PerformanceProbe\GameCult.Mesh.PerformanceProbe.csproj" +$buildArguments = @( + "build", + $project, + "--configuration", "Release", + "--verbosity", "quiet", + "/p:NoWarn=1591%3BCS8632" +) +& dotnet @buildArguments +if ($LASTEXITCODE -ne 0) { + throw "CultMesh reactive document performance probe build failed." +} + +$arguments = @("run", "--project", $project, "--configuration", "Release", "--no-build") +if ($Quick) { + $arguments += @("--", "--quick") +} + +& dotnet @arguments +if ($LASTEXITCODE -ne 0) { + throw "CultMesh reactive document performance probe failed." +} diff --git a/src/GameCult.Mesh/CultMeshPrimitives.cs b/src/GameCult.Mesh/CultMeshPrimitives.cs index d31f8397..d136595f 100644 --- a/src/GameCult.Mesh/CultMeshPrimitives.cs +++ b/src/GameCult.Mesh/CultMeshPrimitives.cs @@ -1426,6 +1426,8 @@ namespace GameCult.Mesh public sealed class CultMeshReactiveDocument : IDisposable where TDocument : class { + private static readonly CultMeshComparableMember[] ComparableMembers = + GetComparableMembers(typeof(TDocument)).ToArray(); private readonly CultMeshDocumentWriter _writer; private readonly CultMeshDocumentHandle _document; private readonly CultMeshReactiveDocumentOptions _options; @@ -1604,30 +1606,33 @@ namespace GameCult.Mesh if (_disposed) return; - var nextCanonical = CultMeshDocumentHandle.CloneDocument(canonical); + TDocument? replacement = null; if (_dirty || _flushing) { - var predicted = CultMeshDocumentHandle.CloneDocument(_current); - var delta = CreateReconciliationDelta(predicted, nextCanonical); + var delta = CreateReconciliationDelta(_current, canonical); if (delta.Count == 0) { Reconciliation = null; + if (!_options.ReplaceDirtyCurrentOnCanonicalSnapshot) + return; } else { + var nextCanonical = CultMeshDocumentHandle.CloneDocument(canonical); + var predicted = CultMeshDocumentHandle.CloneDocument(_current); + replacement = nextCanonical; Reconciliation = new CultMeshReactiveDocumentReconciliation( nextCanonical, predicted, delta, ++_reconciliationVersion, DateTimeOffset.UtcNow); + if (!_options.ReplaceDirtyCurrentOnCanonicalSnapshot) + return; } - - if (!_options.ReplaceDirtyCurrentOnCanonicalSnapshot) - return; } - _current = nextCanonical; + _current = replacement ?? CultMeshDocumentHandle.CloneDocument(canonical); Reconciliation = null; } } @@ -1689,7 +1694,7 @@ namespace GameCult.Mesh TDocument canonical) { var delta = new Dictionary(StringComparer.Ordinal); - foreach (var member in GetComparableMembers(typeof(TDocument))) + foreach (var member in ComparableMembers) { var predictedValue = member.GetValue(predicted); var canonicalValue = member.GetValue(canonical); diff --git a/tools/GameCult.Mesh.PerformanceProbe/GameCult.Mesh.PerformanceProbe.csproj b/tools/GameCult.Mesh.PerformanceProbe/GameCult.Mesh.PerformanceProbe.csproj new file mode 100644 index 00000000..4a073fe7 --- /dev/null +++ b/tools/GameCult.Mesh.PerformanceProbe/GameCult.Mesh.PerformanceProbe.csproj @@ -0,0 +1,11 @@ + + + Exe + net10.0 + enable + enable + + + + + diff --git a/tools/GameCult.Mesh.PerformanceProbe/Program.cs b/tools/GameCult.Mesh.PerformanceProbe/Program.cs new file mode 100644 index 00000000..948d8e90 --- /dev/null +++ b/tools/GameCult.Mesh.PerformanceProbe/Program.cs @@ -0,0 +1,211 @@ +using System.Diagnostics; +using System.Text.Json; +using GameCult.Caching; +using GameCult.Caching.MessagePack; +using GameCult.Mesh; +using MessagePack; +using R3; + +var quick = args.Contains("--quick", StringComparer.OrdinalIgnoreCase); +var idleDuration = quick ? TimeSpan.FromMilliseconds(250) : TimeSpan.FromSeconds(10); +var activeDuration = quick ? TimeSpan.FromMilliseconds(500) : TimeSpan.FromSeconds(10); +var documentCounts = quick ? new[] { 1, 100, 1_000 } : new[] { 1, 100, 1_000 }; +var results = new List(); + +foreach (var documentCount in documentCounts) + results.Add(await MeasureAsync(documentCount, idleDuration, activeDuration)); + +Console.WriteLine(JsonSerializer.Serialize(new +{ + workload = new + { + documentCounts, + payloadBytes = 16 * 1024, + idleSeconds = idleDuration.TotalSeconds, + activeSeconds = activeDuration.TotalSeconds, + updateRateHz = 60, + changedFraction = 0.01 + }, + results +}, new JsonSerializerOptions { WriteIndented = true })); + +return results.All(result => + result.ActualPublishes == result.ExpectedPublishes && + result.PayloadBytesPublished > 0 && + result.AllocationToPayloadRatio < 10 && + result.P99PublishLatencyMilliseconds < 250) + ? 0 + : 1; + +static async Task MeasureAsync( + int documentCount, + TimeSpan idleDuration, + TimeSpan activeDuration) +{ + var payload = new string('x', 16 * 1024); + var changedDocumentCount = Math.Max(1, documentCount / 100); + var subjects = new Subject[documentCount]; + var reactive = new CultMeshReactiveDocument[documentCount]; + var publishSignals = new TaskCompletionSource?[documentCount]; + var updateStartedAt = new long[documentCount]; + var latencies = new List(); + var measurementClock = Stopwatch.StartNew(); + long payloadBytesPublished = 0; + var publishes = 0; + + for (var index = 0; index < documentCount; index++) + { + var documentIndex = index; + var current = new PerformanceDocument + { + Id = "performance:" + index, + Payload = payload, + Revision = 1 + }; + var subject = new Subject(); + subjects[index] = subject; + var handle = CultMesh.Document( + "performance:" + index, + CultMesh.Verse("performance", "probe"), + _ => Task.FromResult(current), + _ => subject, + value => + { + Interlocked.Add( + ref payloadBytesPublished, + CultDocumentMessagePackSerialization.SerializeUntyped(value, typeof(PerformanceDocument)).Length); + lock (latencies) + { + latencies.Add(Stopwatch.GetElapsedTime(updateStartedAt[documentIndex]).TotalMilliseconds); + } + Interlocked.Increment(ref publishes); + current = value; + subject.OnNext(value); + publishSignals[documentIndex]?.TrySetResult(true); + return Task.CompletedTask; + }); + reactive[index] = await handle.AuthoritativeWriter().ReactiveAsync( + new CultMeshReactiveDocumentOptions { FlushDelay = TimeSpan.Zero }); + } + + try + { + ForceCollection(); + var process = Process.GetCurrentProcess(); + var idleAllocatedStart = GC.GetTotalAllocatedBytes(precise: true); + var idleCpuStart = process.TotalProcessorTime; + var idleThreadsStart = process.Threads.Count; + await Task.Delay(idleDuration); + process.Refresh(); + var idleAllocatedBytes = GC.GetTotalAllocatedBytes(precise: true) - idleAllocatedStart; + var idleCpu = process.TotalProcessorTime - idleCpuStart; + var idleThreadsEnd = process.Threads.Count; + + ForceCollection(); + var activeAllocatedStart = GC.GetTotalAllocatedBytes(precise: true); + var activeCpuStart = process.TotalProcessorTime; + var activeThreadsStart = process.Threads.Count; + var activeClock = Stopwatch.StartNew(); + var frameInterval = TimeSpan.FromSeconds(1.0 / 60.0); + var frames = 0; + while (activeClock.Elapsed < activeDuration) + { + var completions = new Task[changedDocumentCount]; + for (var index = 0; index < changedDocumentCount; index++) + { + var completion = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + publishSignals[index] = completion; + updateStartedAt[index] = Stopwatch.GetTimestamp(); + reactive[index].Update(document => document.Revision++); + completions[index] = completion.Task; + } + await Task.WhenAll(completions); + frames++; + var nextFrameAt = frameInterval * frames; + var remaining = nextFrameAt - activeClock.Elapsed; + if (remaining > TimeSpan.Zero) await Task.Delay(remaining); + } + + process.Refresh(); + var activeAllocatedBytes = GC.GetTotalAllocatedBytes(precise: true) - activeAllocatedStart; + var activeCpu = process.TotalProcessorTime - activeCpuStart; + var measuredActiveSeconds = activeClock.Elapsed.TotalSeconds; + var activeThreadsEnd = process.Threads.Count; + double[] orderedLatencies; + lock (latencies) orderedLatencies = latencies.OrderBy(value => value).ToArray(); + + return new ProbeResult( + documentCount, + changedDocumentCount, + frames, + frames * changedDocumentCount, + publishes, + payloadBytesPublished, + idleAllocatedBytes, + idleCpu.TotalMilliseconds, + idleThreadsStart, + idleThreadsEnd, + activeAllocatedBytes, + activeCpu.TotalMilliseconds, + activeThreadsStart, + activeThreadsEnd, + activeAllocatedBytes / measuredActiveSeconds, + payloadBytesPublished / measuredActiveSeconds, + (double)activeAllocatedBytes / payloadBytesPublished, + Percentile(orderedLatencies, 0.50), + Percentile(orderedLatencies, 0.95), + Percentile(orderedLatencies, 0.99), + measurementClock.Elapsed.TotalSeconds); + } + finally + { + foreach (var document in reactive) document.Dispose(); + foreach (var subject in subjects) subject.Dispose(); + } +} + +static double Percentile(double[] ordered, double percentile) +{ + if (ordered.Length == 0) return 0; + var index = (int)Math.Ceiling(percentile * ordered.Length) - 1; + return ordered[Math.Clamp(index, 0, ordered.Length - 1)]; +} + +static void ForceCollection() +{ + GC.Collect(); + GC.WaitForPendingFinalizers(); + GC.Collect(); +} + +internal sealed record ProbeResult( + int DocumentCount, + int ChangedDocumentCount, + int Frames, + int ExpectedPublishes, + int ActualPublishes, + long PayloadBytesPublished, + long IdleAllocatedBytes, + double IdleCpuMilliseconds, + int IdleThreadsStart, + int IdleThreadsEnd, + long ActiveAllocatedBytes, + double ActiveCpuMilliseconds, + int ActiveThreadsStart, + int ActiveThreadsEnd, + double ActiveAllocatedBytesPerSecond, + double PublishedPayloadBytesPerSecond, + double AllocationToPayloadRatio, + double P50PublishLatencyMilliseconds, + double P95PublishLatencyMilliseconds, + double P99PublishLatencyMilliseconds, + double ScenarioWallSeconds); + +[CultDocument("gamecult.mesh.performance_probe", "gamecult.mesh.performance_probe.v1")] +[MessagePackObject] +public sealed class PerformanceDocument +{ + [Key(0), CultName] public string Id { get; set; } = string.Empty; + [Key(1)] public string Payload { get; set; } = string.Empty; + [Key(2)] public int Revision { get; set; } +} From 913ed627c6460eb5f85cf3d762262e7e1b31e5a2 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 02:42:57 +0200 Subject: [PATCH 075/283] Gate CultMesh portability on Windows and Linux --- .github/workflows/cultmesh-portability.yml | 55 ++++++++++++++++++++++ scripts/verify-eve-two-runtime-sample.ps1 | 17 +++++-- 2 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/cultmesh-portability.yml diff --git a/.github/workflows/cultmesh-portability.yml b/.github/workflows/cultmesh-portability.yml new file mode 100644 index 00000000..b8d29e5d --- /dev/null +++ b/.github/workflows/cultmesh-portability.yml @@ -0,0 +1,55 @@ +name: CultMesh portability and performance + +on: + pull_request: + workflow_dispatch: + +jobs: + reactive-and-resource-lifetime: + name: ${{ matrix.os }} reactive semantics and leases + runs-on: ${{ matrix.os }} + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + os: [windows-latest, ubuntu-latest] + + steps: + - name: Check out CultLib + uses: actions/checkout@v4 + + - name: Set up .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 10.0.x + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 24 + cache: npm + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install TypeScript workspace dependencies + run: npm install --no-package-lock + + - name: Install Python CultCache package + run: python -m pip install -e packages/cultcache-py + + - name: Verify explicit reactive scheduling across runtimes + shell: pwsh + run: ./scripts/verify-reactive-document-scaling.ps1 + + - name: Measure representative reactive workload + shell: pwsh + run: ./scripts/measure-reactive-document-performance.ps1 -Quick + + - name: Churn 100,000 distinct document leases + run: >- + dotnet test tests/GameCult.Mesh.Tests/GameCult.Mesh.Tests.csproj + --filter FullyQualifiedName~Document_OneHundredThousandDistinctLeaseCyclesLeaveNoResourcesOrCallbacks + --logger "console;verbosity=minimal" diff --git a/scripts/verify-eve-two-runtime-sample.ps1 b/scripts/verify-eve-two-runtime-sample.ps1 index f6d4ebce..8dfef6dd 100644 --- a/scripts/verify-eve-two-runtime-sample.ps1 +++ b/scripts/verify-eve-two-runtime-sample.ps1 @@ -15,10 +15,16 @@ $packageRoots = @( $eveContractsPackage, $eveBrowserPackage ) +$onWindows = [System.Environment]::OSVersion.Platform -eq [System.PlatformID]::Win32NT -$nodeCommand = Get-Command node.exe -ErrorAction SilentlyContinue +$nodeCommand = Get-Command node -ErrorAction SilentlyContinue if (-not $nodeCommand) { - $standardNode = Join-Path $env:ProgramFiles "nodejs\node.exe" + $standardNode = if ($onWindows -and $env:ProgramFiles) { + Join-Path $env:ProgramFiles "nodejs\node.exe" + } + else { + "" + } if (Test-Path -LiteralPath $standardNode) { $nodeCommand = Get-Item -LiteralPath $standardNode } @@ -28,7 +34,12 @@ if (-not $nodeCommand) { } $nodePath = $nodeCommand.Source $nodeDirectory = Split-Path -Parent $nodePath -$npmPath = Join-Path $nodeDirectory "npm.cmd" +$npmPath = if ($onWindows) { + Join-Path $nodeDirectory "npm.cmd" +} +else { + (Get-Command npm -ErrorAction Stop).Source +} if (-not (Test-Path -LiteralPath $npmPath)) { throw "npm was not found beside Node.js: $npmPath" } From d2a76936110d90bd667eb8f009eb819296e7eed0 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 02:47:34 +0200 Subject: [PATCH 076/283] Make Eve artifact onboarding one command --- samples/eve-two-runtime/README.md | 8 +++---- scripts/verify-eve-two-runtime-sample.ps1 | 23 ++++++++++++++++++- .../03-publish-an-eve-surface.md | 7 +++--- .../docs/getting-started/README.md | 7 +++--- 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/samples/eve-two-runtime/README.md b/samples/eve-two-runtime/README.md index 9e9f1656..6f7fe349 100644 --- a/samples/eve-two-runtime/README.md +++ b/samples/eve-two-runtime/README.md @@ -12,12 +12,12 @@ Eve. It intentionally has one owner for each decision: Run it from the CultLib repository: ```powershell -powershell -ExecutionPolicy Bypass -File .\scripts\verify-eve-two-runtime-sample.ps1 ` - -EveRoot ..\Eve +pwsh -File ./scripts/verify-eve-two-runtime-sample.ps1 -EveRoot ../Eve ``` -The verifier builds package artifacts, installs them into a new empty temporary -consumer, and runs `sample.mjs`. Success proves: +From clean CultLib and Eve checkouts, the verifier installs missing build +dependencies, builds package artifacts, installs them into a new empty +temporary consumer, and runs `sample.mjs`. Success proves: 1. no source-tree import is required by the consumer; 2. the provider surface and receipt pass Eve's generated runtime validators; diff --git a/scripts/verify-eve-two-runtime-sample.ps1 b/scripts/verify-eve-two-runtime-sample.ps1 index 8dfef6dd..98e81cb9 100644 --- a/scripts/verify-eve-two-runtime-sample.ps1 +++ b/scripts/verify-eve-two-runtime-sample.ps1 @@ -1,5 +1,6 @@ param( - [string] $EveRoot = (Join-Path (Split-Path -Parent $PSScriptRoot) "..\Eve") + [string] $EveRoot = (Join-Path (Split-Path -Parent $PSScriptRoot) "..\Eve"), + [switch] $SkipDependencyInstall ) $ErrorActionPreference = "Stop" @@ -53,6 +54,26 @@ foreach ($packageRoot in $packageRoots) { } } +if (-not $SkipDependencyInstall) { + $dependencyRoots = @($cultLibRoot, $eveContractsPackage, $eveBrowserPackage) + foreach ($dependencyRoot in $dependencyRoots) { + $typescript = Join-Path $dependencyRoot "node_modules\typescript\bin\tsc" + if (Test-Path -LiteralPath $typescript -PathType Leaf) { + continue + } + Push-Location $dependencyRoot + try { + & $npmPath ci --no-audit --no-fund + if ($LASTEXITCODE -ne 0) { + throw "Dependency installation failed: $dependencyRoot" + } + } + finally { + Pop-Location + } + } +} + $tempBase = [IO.Path]::GetFullPath([IO.Path]::GetTempPath()) $workRoot = Join-Path $tempBase ("gamecult-eve-two-runtime-" + [guid]::NewGuid().ToString("N")) $artifactRoot = Join-Path $workRoot "artifacts" diff --git a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md index 65a2895b..1a94cce8 100644 --- a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md +++ b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md @@ -39,8 +39,7 @@ The package-artifact DOM-lowerer/headless checkpoint is executable from CultLib: ```powershell cd CultLib -powershell -ExecutionPolicy Bypass -File .\scripts\verify-eve-two-runtime-sample.ps1 ` - -EveRoot ..\Eve +pwsh -File ./scripts/verify-eve-two-runtime-sample.ps1 -EveRoot ../Eve ``` The verifier builds and packs `cultcache-ts`, `cultnet-ts`, `cultmesh-ts`, @@ -57,8 +56,8 @@ survive reopening the `.cc` store. Current verification for the Unity consumer remains: ```powershell -cd E:\Projects\EveUnity -powershell -ExecutionPolicy Bypass -File .\scripts\run-release-consumer-tests.ps1 +cd ../EveUnity +pwsh -File ./scripts/run-release-consumer-tests.ps1 ``` This first checkpoint proves clean package consumption, canonical Eve contract diff --git a/src/GameCult.Mesh/docs/getting-started/README.md b/src/GameCult.Mesh/docs/getting-started/README.md index d5e91d74..ebc38057 100644 --- a/src/GameCult.Mesh/docs/getting-started/README.md +++ b/src/GameCult.Mesh/docs/getting-started/README.md @@ -7,11 +7,12 @@ APIs, name the owner of each decision, and include a verification checkpoint. Run the current clean-consumer checkpoint first: ```powershell -powershell -ExecutionPolicy Bypass -File .\scripts\verify-eve-two-runtime-sample.ps1 ` - -EveRoot ..\Eve +pwsh -File ./scripts/verify-eve-two-runtime-sample.ps1 -EveRoot ../Eve ``` -It installs packed artifacts into an empty temporary project, validates the Eve +From clean CultLib and Eve checkouts, the command installs the package build +dependencies when absent, packs the five TypeScript packages, installs only +those artifacts into an empty temporary project, validates the Eve surface and receipt, executes one idempotent counter command, proves two local consumers converge, and reopens the durable `.cc` store. It is deliberately not called a networked-browser proof; chapter 3 names that remaining boundary. From 5e86427a648646949719c6a161f507f86b7287ad Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 02:49:52 +0200 Subject: [PATCH 077/283] Run portability gates on branch pushes --- .github/workflows/cultmesh-portability.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/cultmesh-portability.yml b/.github/workflows/cultmesh-portability.yml index b8d29e5d..9c59c2ce 100644 --- a/.github/workflows/cultmesh-portability.yml +++ b/.github/workflows/cultmesh-portability.yml @@ -1,6 +1,10 @@ name: CultMesh portability and performance on: + push: + branches: + - main + - "codex/**" pull_request: workflow_dispatch: From af4efb8784cbd179f44ef510bb98c4f98547e047 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 02:54:10 +0200 Subject: [PATCH 078/283] Build TypeScript dependencies before reactive verification --- scripts/verify-reactive-document-scaling.ps1 | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/scripts/verify-reactive-document-scaling.ps1 b/scripts/verify-reactive-document-scaling.ps1 index e3555ae2..a60c9dee 100644 --- a/scripts/verify-reactive-document-scaling.ps1 +++ b/scripts/verify-reactive-document-scaling.ps1 @@ -31,6 +31,26 @@ if (-not (Test-Path -LiteralPath $typescript)) { throw "TypeScript compiler not found: $typescript" } +foreach ($dependency in @("cultcache-ts", "cultnet-ts")) { + $dependencyRoot = Join-Path $root "packages\$dependency" + Push-Location $dependencyRoot + try { + if ($dependency -eq "cultnet-ts") { + & $nodeExecutable (Join-Path $dependencyRoot "tools\generate-swarm-contracts.mjs") + if ($LASTEXITCODE -ne 0) { + throw "CultNet TypeScript contract generation failed." + } + } + & $nodeExecutable $typescript -p tsconfig.json --pretty false + if ($LASTEXITCODE -ne 0) { + throw "TypeScript dependency build failed: $dependency" + } + } + finally { + Pop-Location + } +} + & $dotnet.Source test (Join-Path $root "tests\GameCult.Mesh.Tests\GameCult.Mesh.Tests.csproj") ` --filter "FullyQualifiedName~ReactiveDocument_SchedulingScalesWithChangedDocumentsOnly" ` --nologo ` From 44abedfc9f185595fedc35f0037b21de65a1e9bb Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 03:08:01 +0200 Subject: [PATCH 079/283] Measure reactive performance across runtimes --- .github/workflows/cultmesh-portability.yml | 2 +- .../tools/reactive_performance_probe.py | 145 ++++++++++++++++++ packages/cultmesh-ts/src/index.ts | 7 +- packages/cultmesh-ts/test/cultmesh.test.ts | 36 +++++ .../measure-reactive-document-performance.mjs | 141 +++++++++++++++++ .../measure-reactive-document-performance.ps1 | 64 +++++++- 6 files changed, 390 insertions(+), 5 deletions(-) create mode 100644 packages/cultcache-py/tools/reactive_performance_probe.py create mode 100644 scripts/measure-reactive-document-performance.mjs diff --git a/.github/workflows/cultmesh-portability.yml b/.github/workflows/cultmesh-portability.yml index 9c59c2ce..42d3237a 100644 --- a/.github/workflows/cultmesh-portability.yml +++ b/.github/workflows/cultmesh-portability.yml @@ -50,7 +50,7 @@ jobs: - name: Measure representative reactive workload shell: pwsh - run: ./scripts/measure-reactive-document-performance.ps1 -Quick + run: ./scripts/measure-reactive-document-performance.ps1 -Quick -SkipRuntimeBuild - name: Churn 100,000 distinct document leases run: >- diff --git a/packages/cultcache-py/tools/reactive_performance_probe.py b/packages/cultcache-py/tools/reactive_performance_probe.py new file mode 100644 index 00000000..86ab9441 --- /dev/null +++ b/packages/cultcache-py/tools/reactive_performance_probe.py @@ -0,0 +1,145 @@ +from __future__ import annotations + +import argparse +import json +import threading +import time +import tracemalloc +from typing import Any + +from cultcache_py import define_document_type +from cultmesh_py import CultMeshReactiveDocumentOptions, create_node + + +def percentile(ordered: list[float], ratio: float) -> float: + if not ordered: + return 0.0 + index = max(0, min(len(ordered) - 1, int(len(ordered) * ratio + 0.999999) - 1)) + return ordered[index] + + +def measure(document_count: int, idle_seconds: float, active_seconds: float) -> dict[str, Any]: + payload = "x" * (16 * 1024) + changed_document_count = max(1, document_count // 100) + document = define_document_type( + f"gamecult.mesh.python_performance_probe_{document_count}", + encode=lambda value: value, + decode=lambda value: value, + ) + node = create_node(runtime_id=f"python-performance-{document_count}") + node.register_document(document) + reactive_documents = [] + publish_events = [threading.Event() for _ in range(document_count)] + update_started_at = [0.0] * document_count + latencies: list[float] = [] + payload_bytes_published = 0 + publishes = 0 + measurement_lock = threading.Lock() + + for index in range(document_count): + key = f"performance:{index}" + node.put(document, key, {"id": key, "payload": payload, "revision": 1}) + writer = node.authoritative_writer(document, key) + original_write = writer.write + + def measured_write(value: Any, document_index: int = index, write=original_write) -> None: + nonlocal payload_bytes_published, publishes + encoded_bytes = len(document.encode_payload(value)) + latency_ms = (time.perf_counter() - update_started_at[document_index]) * 1000 + with measurement_lock: + payload_bytes_published += encoded_bytes + publishes += 1 + latencies.append(latency_ms) + write(value) + publish_events[document_index].set() + + writer.write = measured_write # type: ignore[method-assign] + reactive_documents.append( + writer.reactive(CultMeshReactiveDocumentOptions(flush_delay_seconds=0.0)) + ) + + tracemalloc.start() + idle_cpu_start = time.process_time() + time.sleep(idle_seconds) + idle_current_bytes, idle_peak_bytes = tracemalloc.get_traced_memory() + idle_cpu_ms = (time.process_time() - idle_cpu_start) * 1000 + tracemalloc.reset_peak() + active_current_start, _ = tracemalloc.get_traced_memory() + active_cpu_start = time.process_time() + active_started_at = time.perf_counter() + frames = 0 + while time.perf_counter() - active_started_at < active_seconds: + for index in range(changed_document_count): + publish_events[index].clear() + update_started_at[index] = time.perf_counter() + reactive_documents[index].update( + lambda draft: draft.__setitem__("revision", draft["revision"] + 1) + ) + for index in range(changed_document_count): + if not publish_events[index].wait(timeout=1.0): + raise RuntimeError(f"Python reactive publication timed out for document {index}") + frames += 1 + remaining = frames / 60 - (time.perf_counter() - active_started_at) + if remaining > 0: + time.sleep(remaining) + + active_elapsed_seconds = time.perf_counter() - active_started_at + active_cpu_ms = (time.process_time() - active_cpu_start) * 1000 + active_current_bytes, active_peak_bytes = tracemalloc.get_traced_memory() + tracemalloc.stop() + for reactive in reactive_documents: + reactive.dispose() + ordered = sorted(latencies) + return { + "documentCount": document_count, + "changedDocumentCount": changed_document_count, + "frames": frames, + "expectedPublishes": frames * changed_document_count, + "actualPublishes": publishes, + "payloadBytesPublished": payload_bytes_published, + "idleTracedCurrentBytes": idle_current_bytes, + "idleTracedPeakBytes": idle_peak_bytes, + "idleCpuMilliseconds": idle_cpu_ms, + "activeTracedRetainedGrowthBytes": active_current_bytes - active_current_start, + "activeTracedPeakGrowthBytes": active_peak_bytes - active_current_start, + "activeCpuMilliseconds": active_cpu_ms, + "publishedPayloadBytesPerSecond": payload_bytes_published / active_elapsed_seconds, + "p50PublishLatencyMilliseconds": percentile(ordered, 0.50), + "p95PublishLatencyMilliseconds": percentile(ordered, 0.95), + "p99PublishLatencyMilliseconds": percentile(ordered, 0.99), + "schedulerThreads": sum( + thread.name == "cultmesh-reactive-scheduler" for thread in threading.enumerate() + ), + } + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument("--quick", action="store_true") + args = parser.parse_args() + idle_seconds = 0.25 if args.quick else 10.0 + active_seconds = 0.5 if args.quick else 10.0 + results = [measure(count, idle_seconds, active_seconds) for count in (1, 100, 1000)] + print(json.dumps({ + "runtime": "python", + "workload": { + "documentCounts": [1, 100, 1000], + "payloadBytes": 16 * 1024, + "idleSeconds": idle_seconds, + "activeSeconds": active_seconds, + "updateRateHz": 60, + "changedFraction": 0.01, + }, + "results": results, + }, indent=2)) + return 0 if all( + result["actualPublishes"] == result["expectedPublishes"] + and result["p99PublishLatencyMilliseconds"] < 250 + and result["activeTracedPeakGrowthBytes"] < 128 * 1024 * 1024 + and result["schedulerThreads"] == 1 + for result in results + ) else 1 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/packages/cultmesh-ts/src/index.ts b/packages/cultmesh-ts/src/index.ts index 7300ad01..76177269 100644 --- a/packages/cultmesh-ts/src/index.ts +++ b/packages/cultmesh-ts/src/index.ts @@ -1312,8 +1312,11 @@ class CultMeshReactiveDocumentHandle return; } - const timer = setTimeout(flush, 0); - this.#cancelScheduledFlush = () => clearTimeout(timer); + let cancelled = false; + queueMicrotask(() => { + if (!cancelled) flush(); + }); + this.#cancelScheduledFlush = () => { cancelled = true; }; } private flushNow(): void { diff --git a/packages/cultmesh-ts/test/cultmesh.test.ts b/packages/cultmesh-ts/test/cultmesh.test.ts index 18e40a32..653a1e95 100644 --- a/packages/cultmesh-ts/test/cultmesh.test.ts +++ b/packages/cultmesh-ts/test/cultmesh.test.ts @@ -572,6 +572,42 @@ test("CultMesh TS reactive documents coalesce same-frame explicit updates", asyn } }); +test("CultMesh TS headless reactive documents coalesce on one microtask", async () => { + const previousRequestAnimationFrame = globalThis.requestAnimationFrame; + delete (globalThis as unknown as { + requestAnimationFrame?: (callback: FrameRequestCallback) => number; + }).requestAnimationFrame; + let current = { noteId: "note:reactive-headless", body: "initial" }; + const predictions: string[] = []; + const document = CultMesh.document( + "cultmesh.note:reactive-headless", + noteDocument, + async () => current, + { + submitPrediction: async (_context, value) => { + predictions.push(value.body); + current = value; + }, + }, + ); + const reactive = document.predictionWriter().reactive({ watch: false }); + try { + await reactive.ready; + reactive.update(value => { value.body = "microtask-1"; }); + reactive.update(value => { value.body = "microtask-2"; }); + reactive.update(value => { value.body = "microtask-3"; }); + assert.equal(predictions.length, 0, "the current turn remains coalesced"); + + await waitFor(() => predictions.length === 1, "headless microtask prediction"); + assert.deepEqual(predictions, ["microtask-3"]); + } finally { + reactive.dispose(); + if (previousRequestAnimationFrame) { + globalThis.requestAnimationFrame = previousRequestAnimationFrame; + } + } +}); + test("CultMesh TS reactive scheduling scales with changed documents only", async () => { const previousRequestAnimationFrame = globalThis.requestAnimationFrame; const previousCancelAnimationFrame = globalThis.cancelAnimationFrame; diff --git a/scripts/measure-reactive-document-performance.mjs b/scripts/measure-reactive-document-performance.mjs new file mode 100644 index 00000000..786cb3ed --- /dev/null +++ b/scripts/measure-reactive-document-performance.mjs @@ -0,0 +1,141 @@ +import { monitorEventLoopDelay, performance } from "node:perf_hooks"; +import process from "node:process"; + +import { CultMesh } from "../packages/cultmesh-ts/dist/index.js"; + +const quick = process.argv.includes("--quick"); +const idleMs = quick ? 250 : 10_000; +const activeMs = quick ? 500 : 10_000; +const results = []; + +for (const documentCount of [1, 100, 1000]) { + results.push(await measure(documentCount)); +} + +console.log(JSON.stringify({ + runtime: "typescript", + workload: { + documentCounts: [1, 100, 1000], + payloadBytes: 16 * 1024, + idleSeconds: idleMs / 1000, + activeSeconds: activeMs / 1000, + updateRateHz: 60, + changedFraction: 0.01, + }, + results, +}, undefined, 2)); + +if (results.some(result => + result.actualPublishes !== result.expectedPublishes || + result.p99PublishLatencyMilliseconds >= 250 || + result.activeHeapPeakGrowthBytes >= 128 * 1024 * 1024)) { + process.exitCode = 1; +} + +async function measure(documentCount) { + const payload = "x".repeat(16 * 1024); + const changedDocumentCount = Math.max(1, Math.floor(documentCount / 100)); + const reactiveDocuments = []; + const publishSignals = new Array(documentCount); + const updateStartedAt = new Float64Array(documentCount); + const latencies = []; + let payloadBytesPublished = 0; + let publishes = 0; + + for (let index = 0; index < documentCount; index++) { + let current = { id: `performance:${index}`, payload, revision: 1 }; + let watcher; + const document = CultMesh.document( + `performance:${index}`, + { schemaId: "gamecult.mesh.performance_probe.v1" }, + async () => current, + { + submitPrediction: async (_context, value) => { + payloadBytesPublished += Buffer.byteLength(JSON.stringify(value)); + latencies.push(performance.now() - updateStartedAt[index]); + publishes++; + current = value; + watcher?.(value); + publishSignals[index]?.(); + }, + watchDocument: (_context, callback) => { + watcher = callback; + return () => { watcher = undefined; }; + }, + }, + ); + const reactive = document.predictionWriter().reactive(); + reactiveDocuments.push(reactive); + } + + await Promise.all(reactiveDocuments.map(document => document.ready)); + collect(); + const idleHeapStart = process.memoryUsage().heapUsed; + const idleCpuStart = process.cpuUsage(); + await delay(idleMs); + collect(); + const idleHeapGrowthBytes = process.memoryUsage().heapUsed - idleHeapStart; + const idleCpu = process.cpuUsage(idleCpuStart); + + collect(); + const activeHeapStart = process.memoryUsage().heapUsed; + let activeHeapPeak = activeHeapStart; + const activeCpuStart = process.cpuUsage(); + const eventLoop = monitorEventLoopDelay({ resolution: 10 }); + eventLoop.enable(); + const activeStartedAt = performance.now(); + let frames = 0; + while (performance.now() - activeStartedAt < activeMs) { + const completions = []; + for (let index = 0; index < changedDocumentCount; index++) { + completions.push(new Promise(resolve => { publishSignals[index] = resolve; })); + updateStartedAt[index] = performance.now(); + reactiveDocuments[index].update(value => { value.revision++; }); + } + await Promise.all(completions); + frames++; + activeHeapPeak = Math.max(activeHeapPeak, process.memoryUsage().heapUsed); + const remaining = frames * (1000 / 60) - (performance.now() - activeStartedAt); + if (remaining > 0) await delay(remaining); + } + eventLoop.disable(); + const activeElapsedSeconds = (performance.now() - activeStartedAt) / 1000; + const activeCpu = process.cpuUsage(activeCpuStart); + const ordered = latencies.toSorted((left, right) => left - right); + + for (const document of reactiveDocuments) document.dispose(); + + return { + documentCount, + changedDocumentCount, + frames, + expectedPublishes: frames * changedDocumentCount, + actualPublishes: publishes, + payloadBytesPublished, + idleHeapGrowthBytes, + idleCpuMilliseconds: (idleCpu.user + idleCpu.system) / 1000, + activeHeapPeakGrowthBytes: activeHeapPeak - activeHeapStart, + activeCpuMilliseconds: (activeCpu.user + activeCpu.system) / 1000, + publishedPayloadBytesPerSecond: payloadBytesPublished / activeElapsedSeconds, + p50PublishLatencyMilliseconds: percentile(ordered, 0.50), + p95PublishLatencyMilliseconds: percentile(ordered, 0.95), + p99PublishLatencyMilliseconds: percentile(ordered, 0.99), + p99EventLoopDelayMilliseconds: eventLoop.percentile(99) / 1_000_000, + }; +} + +function percentile(ordered, ratio) { + if (ordered.length === 0) return 0; + return ordered[Math.max(0, Math.ceil(ordered.length * ratio) - 1)]; +} + +function collect() { + if (typeof globalThis.gc !== "function") { + throw new Error("Run this probe with node --expose-gc."); + } + globalThis.gc(); +} + +function delay(milliseconds) { + return new Promise(resolve => setTimeout(resolve, milliseconds)); +} diff --git a/scripts/measure-reactive-document-performance.ps1 b/scripts/measure-reactive-document-performance.ps1 index 45598ed0..7b410e41 100644 --- a/scripts/measure-reactive-document-performance.ps1 +++ b/scripts/measure-reactive-document-performance.ps1 @@ -1,9 +1,43 @@ param( - [switch] $Quick + [switch] $Quick, + [switch] $SkipRuntimeBuild, + [string] $PythonPath = "", + [string] $NodePath = "" ) $ErrorActionPreference = "Stop" $root = Split-Path -Parent $PSScriptRoot +$nodeExecutable = if ([string]::IsNullOrWhiteSpace($NodePath)) { + (Get-Command node -ErrorAction Stop).Source +} +else { + [IO.Path]::GetFullPath($NodePath) +} +$pythonExecutable = if ([string]::IsNullOrWhiteSpace($PythonPath)) { + (Get-Command python -ErrorAction Stop).Source +} +else { + [IO.Path]::GetFullPath($PythonPath) +} +foreach ($executable in @($nodeExecutable, $pythonExecutable)) { + if (-not (Test-Path -LiteralPath $executable -PathType Leaf)) { + throw "Performance probe runtime not found: $executable" + } +} + +if (-not $SkipRuntimeBuild) { + $typescript = Join-Path $root "node_modules\typescript\bin\tsc" + foreach ($dependency in @("cultcache-ts", "cultnet-ts", "cultmesh-ts")) { + $dependencyRoot = Join-Path $root "packages\$dependency" + if ($dependency -eq "cultnet-ts") { + & $nodeExecutable (Join-Path $dependencyRoot "tools\generate-swarm-contracts.mjs") + if ($LASTEXITCODE -ne 0) { throw "CultNet TypeScript contract generation failed." } + } + & $nodeExecutable $typescript -p (Join-Path $dependencyRoot "tsconfig.json") --pretty false + if ($LASTEXITCODE -ne 0) { throw "TypeScript performance dependency build failed: $dependency" } + } +} + $project = Join-Path $root "tools\GameCult.Mesh.PerformanceProbe\GameCult.Mesh.PerformanceProbe.csproj" $buildArguments = @( "build", @@ -24,5 +58,31 @@ if ($Quick) { & dotnet @arguments if ($LASTEXITCODE -ne 0) { - throw "CultMesh reactive document performance probe failed." + throw "CultMesh C# reactive document performance probe failed." +} + +$runtimeArguments = @() +if ($Quick) { $runtimeArguments += "--quick" } + +& $nodeExecutable --expose-gc (Join-Path $root "scripts\measure-reactive-document-performance.mjs") @runtimeArguments +if ($LASTEXITCODE -ne 0) { + throw "CultMesh TypeScript reactive document performance probe failed." +} + +$pythonSource = Join-Path $root "packages\cultcache-py\src" +$previousPythonPath = $env:PYTHONPATH +$env:PYTHONPATH = if ([string]::IsNullOrWhiteSpace($previousPythonPath)) { + $pythonSource +} +else { + $pythonSource + [IO.Path]::PathSeparator + $previousPythonPath +} +try { + & $pythonExecutable (Join-Path $root "packages\cultcache-py\tools\reactive_performance_probe.py") @runtimeArguments + if ($LASTEXITCODE -ne 0) { + throw "CultMesh Python reactive document performance probe failed." + } +} +finally { + $env:PYTHONPATH = $previousPythonPath } From 3c19e54d91cdb8c39aa5ea53dcbf441793b3b0f8 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 03:17:52 +0200 Subject: [PATCH 080/283] Make Eve onboarding one executable path --- .github/workflows/cultmesh-portability.yml | 36 +++++++++++++++ README.md | 10 ++++- samples/eve-browser-network/README.md | 8 +++- samples/eve-two-runtime/README.md | 6 ++- scripts/verify-eve-browser-network.mjs | 44 +++++++++++++++++-- scripts/verify-eve-getting-started.ps1 | 29 ++++++++++++ .../03-publish-an-eve-surface.md | 33 ++++++++------ .../docs/getting-started/README.md | 20 +++++---- 8 files changed, 157 insertions(+), 29 deletions(-) create mode 100644 scripts/verify-eve-getting-started.ps1 diff --git a/.github/workflows/cultmesh-portability.yml b/.github/workflows/cultmesh-portability.yml index 42d3237a..9c7b3005 100644 --- a/.github/workflows/cultmesh-portability.yml +++ b/.github/workflows/cultmesh-portability.yml @@ -9,6 +9,42 @@ on: workflow_dispatch: jobs: + getting-started: + name: ${{ matrix.os }} one-command multiplayer onboarding + runs-on: ${{ matrix.os }} + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + os: [windows-latest, ubuntu-latest] + + steps: + - name: Check out CultLib + uses: actions/checkout@v4 + with: + path: CultLib + + - name: Check out the matching Eve contract + uses: actions/checkout@v4 + with: + repository: GameCult/Eve + ref: ${{ vars.EVE_INTEGRATION_REF || 'codex/eve-browser-host-isolation' }} + path: Eve + + - name: Set up .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 10.0.x + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 24 + + - name: Run the documented one-command checkpoint + shell: pwsh + run: ./CultLib/scripts/verify-eve-getting-started.ps1 -EveRoot ./Eve + reactive-and-resource-lifetime: name: ${{ matrix.os }} reactive semantics and leases runs-on: ${{ matrix.os }} diff --git a/README.md b/README.md index 6df5d940..68ee88d6 100644 --- a/README.md +++ b/README.md @@ -70,8 +70,14 @@ series. Its first executable package-consumer checkpoint is [`samples/eve-two-runtime`](samples/eve-two-runtime/README.md). The real-process browser continuation is [`samples/eve-browser-network`](samples/eve-browser-network/README.md). -The implemented browser client boundary and remaining real-network gate are -mapped explicitly in +One documented command runs both layers: + +```powershell +pwsh -File ./scripts/verify-eve-getting-started.ps1 +``` + +The implemented browser client boundary and remaining deployed-infrastructure +gates are mapped explicitly in [`browser-verse-transport.md`](src/GameCult.Mesh/docs/browser-verse-transport.md). If you want only the smallest durable "open node -> put typed doc -> get typed doc" diff --git a/samples/eve-browser-network/README.md b/samples/eve-browser-network/README.md index 3b85dbbc..a78197a7 100644 --- a/samples/eve-browser-network/README.md +++ b/samples/eve-browser-network/README.md @@ -15,9 +15,15 @@ This is the real-process continuation of `samples/eve-two-runtime`: Run the proof from the CultLib repository: ```powershell -node scripts/verify-eve-browser-network.mjs --eve-root ..\Eve +pwsh -File ./scripts/verify-eve-getting-started.ps1 ``` +The wrapper first proves clean package consumption, then runs this real-process +checkpoint. Run `node scripts/verify-eve-browser-network.mjs --eve-root ../Eve` +directly only to diagnose the network layer. Browser discovery is portable: +`CHROME_PATH` wins when configured, then common Chrome/Chromium/Edge locations +and Playwright's installed Chromium are checked. + The verifier clicks the Eve button twice with one idempotency key, requires one state transition, restarts the provider on a different physical port, updates the local Odin fixture, and requires the still-open browser to rediscover the diff --git a/samples/eve-two-runtime/README.md b/samples/eve-two-runtime/README.md index 6f7fe349..c149e14e 100644 --- a/samples/eve-two-runtime/README.md +++ b/samples/eve-two-runtime/README.md @@ -12,9 +12,13 @@ Eve. It intentionally has one owner for each decision: Run it from the CultLib repository: ```powershell -pwsh -File ./scripts/verify-eve-two-runtime-sample.ps1 -EveRoot ../Eve +pwsh -File ./scripts/verify-eve-getting-started.ps1 ``` +That command continues into the real Chromium/C# network checkpoint after this +artifact layer passes. Run `verify-eve-two-runtime-sample.ps1` directly only to +diagnose clean package consumption in isolation. + From clean CultLib and Eve checkouts, the verifier installs missing build dependencies, builds package artifacts, installs them into a new empty temporary consumer, and runs `sample.mjs`. Success proves: diff --git a/scripts/verify-eve-browser-network.mjs b/scripts/verify-eve-browser-network.mjs index 9e047930..401a8dde 100644 --- a/scripts/verify-eve-browser-network.mjs +++ b/scripts/verify-eve-browser-network.mjs @@ -1,5 +1,6 @@ import assert from "node:assert/strict"; import { spawn } from "node:child_process"; +import { existsSync } from "node:fs"; import { createServer as createHttpServer } from "node:http"; import { mkdtemp, readFile, rm } from "node:fs/promises"; import { createServer as createNetServer } from "node:net"; @@ -45,7 +46,12 @@ try { const bundle = await readFile(bundlePath, "utf8"); assert.doesNotMatch(bundle, /(?:from\s*["']node:|require\(["']node:)/u, "browser bundle contains a Node builtin import"); - await run("dotnet", ["build", join(sampleRoot, "EveBrowserNetworkSample.csproj"), "--verbosity", "quiet"]); + await run("dotnet", [ + "build", + join(sampleRoot, "EveBrowserNetworkSample.csproj"), + "--verbosity", "quiet", + "-p:NoWarn=1591%3BCS8632", + ]); const providerPort = await freePort(); const replacementProviderPort = await freePort(); const odinPort = await freePort(); @@ -58,8 +64,7 @@ try { await headless.waitFor("HEADLESS_READY "); httpServer = await serve(httpPort, sampleRoot, bundlePath); - const executablePath = process.env.CHROME_PATH || "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe"; - browser = await chromium.launch({ executablePath, headless: true }); + browser = await chromium.launch({ executablePath: resolveChromiumExecutable(), headless: true }); let page = await browser.newPage(); const url = `http://127.0.0.1:${httpPort}/?odin=${encodeURIComponent(odinEndpoint)}&token=${token}`; await page.goto(url); @@ -221,3 +226,36 @@ async function stop(process) { ]); if (process.exitCode === null) process.kill("SIGKILL"); } + +function resolveChromiumExecutable() { + const candidates = [process.env.CHROME_PATH]; + if (process.platform === "win32") { + for (const root of [process.env.ProgramFiles, process.env["ProgramFiles(x86)"], process.env.LOCALAPPDATA]) { + if (!root) continue; + candidates.push( + join(root, "Google", "Chrome", "Application", "chrome.exe"), + join(root, "Microsoft", "Edge", "Application", "msedge.exe"), + ); + } + } else if (process.platform === "darwin") { + candidates.push( + "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", + "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge", + ); + } else { + candidates.push( + "/usr/bin/google-chrome", + "/usr/bin/google-chrome-stable", + "/usr/bin/chromium", + "/usr/bin/chromium-browser", + "/opt/google/chrome/chrome", + ); + } + candidates.push(chromium.executablePath()); + const executablePath = candidates.find(candidate => candidate && existsSync(candidate)); + if (executablePath) return executablePath; + throw new Error( + "No Chromium-family browser was found. Set CHROME_PATH or run " + + "'node node_modules/playwright-core/cli.js install chromium'.", + ); +} diff --git a/scripts/verify-eve-getting-started.ps1 b/scripts/verify-eve-getting-started.ps1 new file mode 100644 index 00000000..57dd0a61 --- /dev/null +++ b/scripts/verify-eve-getting-started.ps1 @@ -0,0 +1,29 @@ +param( + [string] $EveRoot = (Join-Path (Split-Path -Parent $PSScriptRoot) "..\Eve"), + [switch] $SkipDependencyInstall +) + +$ErrorActionPreference = "Stop" +$cultLibRoot = Split-Path -Parent $PSScriptRoot +$EveRoot = [IO.Path]::GetFullPath($EveRoot) + +& (Join-Path $PSScriptRoot "verify-eve-two-runtime-sample.ps1") ` + -EveRoot $EveRoot ` + -SkipDependencyInstall:$SkipDependencyInstall +if ($LASTEXITCODE -ne 0) { + throw "The clean package-consumer checkpoint failed." +} + +$nodeCommand = Get-Command node -ErrorAction Stop +$playwrightCli = Join-Path $cultLibRoot "node_modules\playwright-core\cli.js" +if (-not (Test-Path -LiteralPath $playwrightCli -PathType Leaf)) { + throw "playwright-core is missing after dependency setup: $playwrightCli" +} + +& $nodeCommand.Source (Join-Path $PSScriptRoot "verify-eve-browser-network.mjs") ` + --eve-root $EveRoot +if ($LASTEXITCODE -ne 0) { + throw "The real browser/C# network checkpoint failed." +} + +Write-Host "Eve getting-started verification passed: clean artifacts, DOM and headless convergence, real Chromium and C# clients, Odin discovery, receipts, persistence, and route replacement." diff --git a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md index 1a94cce8..91f742ac 100644 --- a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md +++ b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md @@ -35,14 +35,18 @@ Run the same provider and connect at least two lowerers. Both must report the same provider id, surface id, surface version, and command receipt ids. Native pixels may differ; provider truth may not. -The package-artifact DOM-lowerer/headless checkpoint is executable from CultLib: +The complete checkpoint is executable from CultLib: ```powershell cd CultLib -pwsh -File ./scripts/verify-eve-two-runtime-sample.ps1 -EveRoot ../Eve +pwsh -File ./scripts/verify-eve-getting-started.ps1 ``` -The verifier builds and packs `cultcache-ts`, `cultnet-ts`, `cultmesh-ts`, +This one command runs the clean package-artifact checkpoint and then the real +browser/C# network checkpoint. They remain separate programs because they prove +different boundaries; the developer should not have to orchestrate them. + +The first layer builds and packs `cultcache-ts`, `cultnet-ts`, `cultmesh-ts`, `@gamecult/eve-contracts`, and `@gamecult/eve-browser-lowering`, installs the tarballs into an empty temporary consumer, and runs `samples/eve-two-runtime/sample.mjs`. Eve's generated runtime validators reject @@ -53,6 +57,12 @@ both consumers converge on the same state and canonical receipt identity, a duplicate idempotency key is not applied twice, and the state plus receipt survive reopening the `.cc` store. +The second layer runs a durable C# provider, a separate local Odin fixture, a +real Chromium Eve lowerer, and an independent C# headless observer over binary +CultNet WebSocket lanes. The open browser resolves provider identity through +the canonical Verse catalog, survives a provider restart on a different route, +resubscribes, and commits another canonical receipt. + Current verification for the Unity consumer remains: ```powershell @@ -60,19 +70,14 @@ cd ../EveUnity pwsh -File ./scripts/run-release-consumer-tests.ps1 ``` -This first checkpoint proves clean package consumption, canonical Eve contract +The artifact layer proves clean package consumption, canonical Eve contract validation, and two independent lowering/observation consumers inside Node. It -does **not** claim a real browser process, an Odin-discovered network hop, or -cross-language command execution. Do not cite it as evidence for those layers. +does **not** prove the network layer; the second program owns that evidence. -The next executable checkpoint is +The network program is [`samples/eve-browser-network`](../../../../samples/eve-browser-network/README.md). -It runs a durable C# provider, a separate local Odin fixture, a real Chromium -Eve lowerer, and an independent C# headless observer over authenticated binary -CultNet WebSocket lanes. The still-open browser resolves stable identity through -the canonical Verse catalog, survives a provider restart on a different -physical route, resubscribes, and commits another canonical receipt. A smoke -against the deployed Odin daemon and retained C# lease reconnection remain -separate infrastructure gates. Their owner map and full acceptance contract are recorded in +Run it separately only while diagnosing that layer. A smoke against the +deployed Odin daemon and retained C# lease reconnection remain separate +infrastructure gates. Their owner map and full acceptance contract are recorded in [`browser-verse-transport.md`](../browser-verse-transport.md). diff --git a/src/GameCult.Mesh/docs/getting-started/README.md b/src/GameCult.Mesh/docs/getting-started/README.md index ebc38057..44bd5e2c 100644 --- a/src/GameCult.Mesh/docs/getting-started/README.md +++ b/src/GameCult.Mesh/docs/getting-started/README.md @@ -4,18 +4,22 @@ This series builds one typed application state and presents it through multiple Eve runtimes. It is maintained as an API acceptance test: examples use public APIs, name the owner of each decision, and include a verification checkpoint. -Run the current clean-consumer checkpoint first: +Run the complete getting-started checkpoint: ```powershell -pwsh -File ./scripts/verify-eve-two-runtime-sample.ps1 -EveRoot ../Eve +pwsh -File ./scripts/verify-eve-getting-started.ps1 ``` -From clean CultLib and Eve checkouts, the command installs the package build -dependencies when absent, packs the five TypeScript packages, installs only -those artifacts into an empty temporary project, validates the Eve -surface and receipt, executes one idempotent counter command, proves two local -consumers converge, and reopens the durable `.cc` store. It is deliberately not -called a networked-browser proof; chapter 3 names that remaining boundary. +With clean sibling CultLib and Eve checkouts, the command installs missing build +dependencies and runs two explicit evidence layers. First it packs the five +TypeScript packages into an empty temporary consumer, validates the Eve surface +and receipt, executes one idempotent counter command, proves a DOM lowerer and +headless observer converge, and reopens the durable `.cc` store. Then it boots a +durable C# provider, local Odin fixture, real Chromium lowerer, and independent +C# observer; it proves discovery by identity, commands, canonical receipts, +provider restart on another route, resubscription, and durable convergence. +Set `CHROME_PATH` only when no installed Chrome, Chromium, Edge, or Playwright +Chromium can be found automatically. Follow the chapters in order: From cb7f9e8fa2308c8eec24b941bbd76090c038862b Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 03:34:59 +0200 Subject: [PATCH 081/283] Retain native clients across provider routes --- .../EveBrowserNetworkSample.csproj | 3 + samples/eve-browser-network/Program.cs | 251 ++++++++---------- samples/eve-browser-network/README.md | 6 +- samples/eve-browser-network/browser/main.ts | 2 +- scripts/verify-eve-browser-network.mjs | 35 ++- scripts/verify-eve-two-runtime-sample.ps1 | 2 +- src/GameCult.Mesh/CultMeshClient.cs | 2 +- src/GameCult.Mesh/CultMeshDiscoveryService.cs | 15 ++ src/GameCult.Mesh/CultMeshSessions.cs | 63 +++++ src/GameCult.Mesh/CultMeshVerseDiscovery.cs | 12 +- .../docs/browser-verse-transport.md | 9 +- .../03-publish-an-eve-surface.md | 4 +- .../CultNetWebSocketSchemaClient.cs | 2 +- .../CultNetSchemaClient.cs | 11 + .../CultMeshDiscoveryServiceTests.cs | 27 ++ .../CultMeshSessionManagerTests.cs | 33 ++- 16 files changed, 317 insertions(+), 160 deletions(-) diff --git a/samples/eve-browser-network/EveBrowserNetworkSample.csproj b/samples/eve-browser-network/EveBrowserNetworkSample.csproj index a0a0bf32..7de0bdbd 100644 --- a/samples/eve-browser-network/EveBrowserNetworkSample.csproj +++ b/samples/eve-browser-network/EveBrowserNetworkSample.csproj @@ -3,9 +3,12 @@ net10.0 enable enable + $(MSBuildThisFileDirectory)..\..\..\Eve + diff --git a/samples/eve-browser-network/Program.cs b/samples/eve-browser-network/Program.cs index 21ef3c32..21933bda 100644 --- a/samples/eve-browser-network/Program.cs +++ b/samples/eve-browser-network/Program.cs @@ -2,6 +2,7 @@ using System.Net; using System.Text.Json; using GameCult.Caching; using GameCult.Caching.MessagePack; +using GameCult.Eve.Surface; using GameCult.Mesh; using GameCult.Networking; using GameCult.Networking.WebSockets; @@ -70,7 +71,7 @@ static async Task RunOdinAsync(Args arguments) static async Task RunProviderAsync(Args arguments) { - var registry = CultDocumentRegistry.ForTypes([typeof(CounterState), typeof(CounterSurfaceDocument)]); + var registry = CultDocumentRegistry.ForTypes([typeof(CounterState), typeof(EveSurfaceDocument)]); using var cache = await CultCacheMessagePack.OpenAsync(arguments.StatePath, new CultCacheOpenOptions { Registry = registry, @@ -79,7 +80,7 @@ static async Task RunProviderAsync(Args arguments) }); var documents = new CultNetDocumentRegistry(registry) .Register(CultNetDocumentBinding.ForDocument(registry, "sample.counter_state.v1")) - .Register(CultNetDocumentBinding.ForDocument(registry, "gamecult.eve.surface.v1")); + .Register(CultNetDocumentBinding.ForDocument(registry, EveSurfaceDocument.SchemaId)); using var database = new CultNetDatabase(cache, new CultNetDatabaseOptions { RuntimeId = "sample.counter-provider", @@ -87,8 +88,8 @@ static async Task RunProviderAsync(Args arguments) }); if (cache.Get(new CultRecordKey(counterKey)) == null) await database.PutAsync(new CultRecordKey(counterKey), CounterState.Initial(counterKey)); - if (cache.Get(new CultRecordKey(surfaceKey)) == null) - await database.PutAsync(new CultRecordKey(surfaceKey), CounterSurfaceDocument.Create()); + if (cache.Get(new CultRecordKey(surfaceKey)) == null) + await database.PutAsync(new CultRecordKey(surfaceKey), CreateCounterSurface()); await cache.FlushAsync(); await using var schemaServer = new CultNetWebSocketSchemaServer(); @@ -160,28 +161,107 @@ static async Task RunProviderAsync(Args arguments) static async Task RunHeadlessAsync(Args arguments) { - var registry = CultDocumentRegistry.ForTypes([typeof(CounterState)]); - using var cache = new CultCache(registry); - var documents = new CultNetDocumentRegistry(registry) - .Register(CultNetDocumentBinding.ForDocument(registry, "sample.counter_state.v1")); - using var transport = new CultNetWebSocketSchemaClient(options => + if (string.IsNullOrWhiteSpace(arguments.OdinEndpoint)) + throw new ArgumentException("The headless client requires --odin."); + CultNetWebSocketSchemaClient CreateClient() => new(options => options.SetRequestHeader("Cookie", $"cultnet_session={arguments.Token}")); - using var subscriptions = new CultNetDatabaseSubscriptionClient(transport, cache, documents); - var changed = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - subscriptions.Changed += change => + using var mesh = new CultMeshClient(new CultMeshClientOptions { - if (change.Document is CounterState counter) changed.TrySetResult(counter); - }; - await transport.ConnectAsync(new Uri(arguments.Endpoint)); - var initial = await subscriptions.SubscribeAsync( - "headless-counter", - recordKeys: [counterKey], - schemaIds: ["sample.counter_state.v1"], - deliveryMode: CultNetDatabaseSubscriptionDeliveryMode.Live); - var counter = initial.OfType().Single(); - Console.WriteLine("HEADLESS_READY " + JsonSerializer.Serialize(new { count = counter.Count })); - var update = await changed.Task.WaitAsync(TimeSpan.FromSeconds(15)); - Console.WriteLine("HEADLESS_UPDATE " + JsonSerializer.Serialize(new { count = update.Count })); + RendezvousEndpoints = [arguments.OdinEndpoint], + Discovery = new CultMeshVerseDiscoveryClientOptions + { + CreateClient = CreateClient, + TransportVersion = arguments.TransportVersion + }, + Connectors = + [ + new CultMeshUriSchemaTransportConnector( + "cultnet-websocket", + ["ws", "wss"], + _ => CreateClient()) + ] + }); + using var lease = await mesh.LeaseDocumentAsync(arguments.VerseId, counterKey); + var completion = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var lastCount = -1; + using var watch = lease.Handle.Watch(counter => + { + if (counter.Count <= lastCount) return; + lastCount = counter.Count; + if (counter.Count == 0) + Console.WriteLine("HEADLESS_READY " + JsonSerializer.Serialize(new { count = counter.Count })); + else + Console.WriteLine($"HEADLESS_UPDATE_{counter.Count} " + JsonSerializer.Serialize(new + { + count = counter.Count, + receiptIds = counter.Receipts.Values + .Select(receipt => receipt.ReceiptId) + .OrderBy(value => value, StringComparer.Ordinal) + .ToArray() + })); + if (counter.Count >= arguments.ExpectedCount) completion.TrySetResult(); + }); + var initial = await lease.Handle.LatestAsync(); + if (lastCount < 0) + { + lastCount = initial.Count; + Console.WriteLine("HEADLESS_READY " + JsonSerializer.Serialize(new { count = initial.Count })); + } + if (initial.Count >= arguments.ExpectedCount) completion.TrySetResult(); + await completion.Task.WaitAsync(TimeSpan.FromSeconds(45)); +} + +static EveSurfaceDocument CreateCounterSurface() +{ + var networkRoute = new CultMeshRouteHint(CultMeshLocalityKind.Network, "cultmesh"); + return new EveSurfaceDocument( + providerId: "sample.counter-provider", + providerKind: "sample.daemon", + title: "CultMesh browser counter", + version: 1, + updatedAtUtc: "2026-08-17T00:00:00Z", + surface: new EveSurfaceTree( + surfaceKey, + new EveSurfaceComponent( + "counter.root", + "column", + new Dictionary(StringComparer.Ordinal), + [ + new EveSurfaceComponent( + "counter.value", + "metric", + new Dictionary(StringComparer.Ordinal) + { + ["label"] = "Canonical count", + ["value"] = "0" + }, + [], + [ + new CultMeshStateBindingDescriptor( + "value", + "sample.counter.count", + "sample.counter_state:counter:main", + "sample.counter_state.v1", + networkRoute) + ]), + new EveSurfaceComponent( + "counter.increment", + "control.button", + new Dictionary(StringComparer.Ordinal) + { + ["label"] = "Increment", + ["command"] = "sample.counter.increment" + }, + []) + ]), + []), + commands: + [ + new EveCommandTemplate(new CultMeshOperationBindingDescriptor( + "sample.counter.increment", + "Increment", + routeHint: networkRoute)) + ]); } sealed class Args @@ -189,14 +269,15 @@ sealed class Args public string Mode { get; private init; } = ""; public int Port { get; private init; } public string StatePath { get; private init; } = "sample-counter.cc"; - public string Endpoint { get; private init; } = ""; + public string OdinEndpoint { get; private init; } = ""; public string ProviderEndpoint { get; private init; } = ""; public string Token { get; private init; } = "sample-session"; public string VerseId { get; private init; } = "sample.counter"; public string VerseName { get; private init; } = "CultMesh browser counter"; public string AuthorityRuntimeId { get; private init; } = "sample.counter-provider"; - public string TransportVersion { get; private init; } = "cultmesh.v1"; + public string TransportVersion { get; private init; } = "cultmesh.v0"; public string RulesHash { get; private init; } = "sample-counter-v1"; + public int ExpectedCount { get; private init; } = 2; public static Args Parse(string[] values) { @@ -209,14 +290,17 @@ sealed class Args Mode = values[0], Port = named.TryGetValue("--port", out var port) ? int.Parse(port) : 0, StatePath = named.GetValueOrDefault("--state", "sample-counter.cc"), - Endpoint = named.GetValueOrDefault("--endpoint", ""), + OdinEndpoint = named.GetValueOrDefault("--odin", ""), ProviderEndpoint = named.GetValueOrDefault("--provider-endpoint", ""), Token = named.GetValueOrDefault("--token", "sample-session"), VerseId = named.GetValueOrDefault("--verse-id", "sample.counter"), VerseName = named.GetValueOrDefault("--verse-name", "CultMesh browser counter"), AuthorityRuntimeId = named.GetValueOrDefault("--authority-runtime-id", "sample.counter-provider"), - TransportVersion = named.GetValueOrDefault("--transport-version", "cultmesh.v1"), - RulesHash = named.GetValueOrDefault("--rules-hash", "sample-counter-v1") + TransportVersion = named.GetValueOrDefault("--transport-version", "cultmesh.v0"), + RulesHash = named.GetValueOrDefault("--rules-hash", "sample-counter-v1"), + ExpectedCount = named.TryGetValue("--expected-count", out var expectedCount) + ? int.Parse(expectedCount) + : 2 }; } } @@ -264,112 +348,3 @@ public sealed class IncrementReceipt Count = count }; } - -[CultDocument("gamecult.eve.surface", "gamecult.eve.surface.v1")] -[MessagePackObject] -public sealed class CounterSurfaceDocument -{ - [Key("type")] public string Type { get; set; } = "surface-state"; - [Key("schema")] public string Schema { get; set; } = "gamecult.eve.surface.v1"; - [Key("providerId")] public string ProviderId { get; set; } = "sample.counter-provider"; - [Key("providerKind")] public string ProviderKind { get; set; } = "sample.daemon"; - [Key("title")] public string Title { get; set; } = "CultMesh browser counter"; - [Key("version")] public int Version { get; set; } = 1; - [Key("updatedAtUtc")] public string UpdatedAtUtc { get; set; } = "2026-08-17T00:00:00Z"; - [Key("surface")] public EveSurface Surface { get; set; } = new(); - [Key("commands")] public EveCommand[] Commands { get; set; } = []; - - public static CounterSurfaceDocument Create() => new() - { - Surface = new EveSurface - { - Id = "sample.counter", - Title = "Counter", - Root = new EveComponent - { - Id = "counter.root", - Kind = "column", - Children = - [ - new EveComponent - { - Id = "counter.value", - Kind = "metric", - Props = new Dictionary { ["label"] = "Canonical count", ["value"] = 0 }, - StateBindings = - [ - new EveStateBinding - { - TargetProp = "value", - PointerId = "sample.counter.count", - SourceId = "sample.counter_state:counter:main", - SchemaId = "sample.counter_state.v1", - RouteKind = "cultmesh" - } - ] - }, - new EveComponent - { - Id = "counter.increment", - Kind = "control.button", - Props = new Dictionary - { - ["label"] = "Increment", - ["command"] = "sample.counter.increment" - } - } - ] - } - }, - Commands = - [ - new EveCommand - { - Command = "sample.counter.increment", - Label = "Increment", - SurfaceId = "sample.counter" - } - ] - }; -} - -[MessagePackObject] -public sealed class EveSurface -{ - [Key("id")] public string Id { get; set; } = ""; - [Key("title")] public string Title { get; set; } = ""; - [Key("root")] public EveComponent Root { get; set; } = new(); - [Key("styles")] public Dictionary Styles { get; set; } = []; -} - -[MessagePackObject] -public sealed class EveComponent -{ - [Key("id")] public string Id { get; set; } = ""; - [Key("kind")] public string Kind { get; set; } = ""; - [Key("props")] public Dictionary Props { get; set; } = []; - [Key("children")] public EveComponent[] Children { get; set; } = []; - [Key("stateBindings")] public EveStateBinding[] StateBindings { get; set; } = []; -} - -[MessagePackObject] -public sealed class EveStateBinding -{ - [Key("targetProp")] public string TargetProp { get; set; } = ""; - [Key("pointerId")] public string PointerId { get; set; } = ""; - [Key("sourceId")] public string SourceId { get; set; } = ""; - [Key("schemaId")] public string SchemaId { get; set; } = ""; - [Key("routeKind")] public string RouteKind { get; set; } = ""; -} - -[MessagePackObject] -public sealed class EveCommand -{ - [Key("schema")] public string Schema { get; set; } = "gamecult.eve.command.v1"; - [Key("command")] public string Command { get; set; } = ""; - [Key("label")] public string Label { get; set; } = ""; - [Key("surfaceId")] public string SurfaceId { get; set; } = ""; - [Key("transport")] public string Transport { get; set; } = "cultmesh"; - [Key("authority")] public string Authority { get; set; } = "provider-daemon"; - [Key("result")] public string Result { get; set; } = "gamecult.eve.command_receipt.v1"; -} diff --git a/samples/eve-browser-network/README.md b/samples/eve-browser-network/README.md index a78197a7..5068ce0d 100644 --- a/samples/eve-browser-network/README.md +++ b/samples/eve-browser-network/README.md @@ -6,7 +6,9 @@ This is the real-process continuation of `samples/eve-two-runtime`: idempotency, and canonical receipts; - one real Chromium page leases both documents through `cultmesh-browser` and lowers the provider-owned Eve surface; -- one independent C# headless client observes the same typed counter; +- one retained C# headless client discovers the provider through the same Odin + identity, observes the typed counter and canonical receipt ids, and survives + the provider route replacement without application reconnect code; - one separate local Odin fixture answers the canonical CultMesh Verse catalog over binary CultNet WebSocket messages; - the browser and C# clients speak the same binary CultNet schema-v0 WebSocket @@ -28,6 +30,8 @@ The verifier clicks the Eve button twice with one idempotency key, requires one state transition, restarts the provider on a different physical port, updates the local Odin fixture, and requires the still-open browser to rediscover the route, resubscribe, execute a second command, and preserve the durable count. +The retained C# lease independently rediscovers the same replacement route and +observes both canonical receipt ids. The fixture speaks the production Verse-catalog contract; a deployment smoke against the full Odin daemon remains a separate infrastructure gate. diff --git a/samples/eve-browser-network/browser/main.ts b/samples/eve-browser-network/browser/main.ts index 9c7f1cd1..9e30504d 100644 --- a/samples/eve-browser-network/browser/main.ts +++ b/samples/eve-browser-network/browser/main.ts @@ -35,7 +35,7 @@ try { rendezvous: new CultMeshBrowserOdinRendezvous({ endpoints: [odinEndpoint], runtimeId: "sample.chromium.discovery", - transportVersion: "cultmesh.v1", + transportVersion: "cultmesh.v0", }), }); window.__sampleConnectionStates = []; diff --git a/scripts/verify-eve-browser-network.mjs b/scripts/verify-eve-browser-network.mjs index 401a8dde..b0f63200 100644 --- a/scripts/verify-eve-browser-network.mjs +++ b/scripts/verify-eve-browser-network.mjs @@ -20,6 +20,7 @@ const statePath = join(workRoot, "counter.cc"); const bundlePath = join(workRoot, "bundle.js"); const token = "sample-session"; let provider; +let replacementProvider; let odin; let headless; let httpServer; @@ -51,6 +52,7 @@ try { join(sampleRoot, "EveBrowserNetworkSample.csproj"), "--verbosity", "quiet", "-p:NoWarn=1591%3BCS8632", + `-p:EveRoot=${eveRoot}`, ]); const providerPort = await freePort(); const replacementProviderPort = await freePort(); @@ -60,7 +62,10 @@ try { const endpoint = await provider.waitFor("PROVIDER_READY "); odin = await startOdin(odinPort, endpoint); const odinEndpoint = await odin.waitFor("ODIN_READY "); - headless = startDotnet(["headless", "--endpoint", endpoint, "--token", token]); + headless = startDotnet([ + "headless", "--odin", odinEndpoint, "--verse-id", "sample.counter", + "--expected-count", "2", "--token", token, + ]); await headless.waitFor("HEADLESS_READY "); httpServer = await serve(httpPort, sampleRoot, bundlePath); @@ -74,24 +79,33 @@ try { await page.locator("button").click(); await page.waitForFunction(() => window.__sampleReceipt?.count === 1 && window.__sampleCount === 1); const firstReceipt = await page.evaluate(() => window.__sampleReceipt?.receiptId); - assert.equal(JSON.parse(await headless.waitFor("HEADLESS_UPDATE ")).count, 1); + const firstHeadlessUpdate = JSON.parse(await headless.waitFor("HEADLESS_UPDATE_1 ")); + assert.equal(firstHeadlessUpdate.count, 1); + assert.ok(firstHeadlessUpdate.receiptIds.includes(firstReceipt)); await page.locator("button").click(); await page.waitForFunction(receipt => window.__sampleReceipt?.receiptId === receipt, firstReceipt); assert.equal(await page.evaluate(() => window.__sampleCount), 1, "duplicate idempotency key changed canonical state"); - await stop(provider.process); - await stop(odin.process); - provider = await startProvider(replacementProviderPort); - const restartedEndpoint = await provider.waitFor("PROVIDER_READY "); + replacementProvider = await startProvider(replacementProviderPort); + const restartedEndpoint = await replacementProvider.waitFor("PROVIDER_READY "); assert.notEqual(restartedEndpoint, endpoint); + await stop(odin.process); odin = await startOdin(odinPort, restartedEndpoint); assert.equal(await odin.waitFor("ODIN_READY "), odinEndpoint); - headless = startDotnet(["headless", "--endpoint", restartedEndpoint, "--token", token]); - await headless.waitFor("HEADLESS_READY "); + await stop(provider.process); + provider = replacementProvider; + replacementProvider = undefined; + await page.waitForFunction(() => + window.__sampleConnectionStates?.includes("reconnecting") + && window.__sampleConnectionStates.at(-1) === "connected"); await page.evaluate(() => { window.__sampleCommandId = "browser-click-2"; }); await page.locator("button").click(); await page.waitForFunction(() => window.__sampleReceipt?.count === 2 && window.__sampleCount === 2); - assert.equal(JSON.parse(await headless.waitFor("HEADLESS_UPDATE ")).count, 2); + const secondReceipt = await page.evaluate(() => window.__sampleReceipt?.receiptId); + const secondHeadlessUpdate = JSON.parse(await headless.waitFor("HEADLESS_UPDATE_2 ")); + assert.equal(secondHeadlessUpdate.count, 2); + assert.ok(secondHeadlessUpdate.receiptIds.includes(firstReceipt)); + assert.ok(secondHeadlessUpdate.receiptIds.includes(secondReceipt)); const connectionStates = await page.evaluate(() => window.__sampleConnectionStates); assert.equal(connectionStates[0], "connected"); assert.equal(connectionStates.at(-1), "connected"); @@ -105,13 +119,16 @@ try { browserRuntime: "chromium", headlessRuntime: "csharp", receiptId: firstReceipt, + secondReceiptId: secondReceipt, count: 2, routeRotationCount: 1, + retainedHeadlessLease: true, })); } finally { if (browser) await browser.close().catch(() => undefined); if (headless) await stop(headless.process); if (provider) await stop(provider.process); + if (replacementProvider) await stop(replacementProvider.process); if (odin) await stop(odin.process); if (httpServer) await new Promise(resolve => httpServer.close(resolve)); await rm(workRoot, { recursive: true, force: true }); diff --git a/scripts/verify-eve-two-runtime-sample.ps1 b/scripts/verify-eve-two-runtime-sample.ps1 index 98e81cb9..e33a0622 100644 --- a/scripts/verify-eve-two-runtime-sample.ps1 +++ b/scripts/verify-eve-two-runtime-sample.ps1 @@ -131,7 +131,7 @@ try { throw "Clean consumer package installation failed." } Copy-Item -LiteralPath $samplePath -Destination (Join-Path $consumerRoot "sample.mjs") - & $nodePath .\sample.mjs + & $nodePath (Join-Path $consumerRoot "sample.mjs") if ($LASTEXITCODE -ne 0) { throw "Eve two-runtime sample failed." } diff --git a/src/GameCult.Mesh/CultMeshClient.cs b/src/GameCult.Mesh/CultMeshClient.cs index 027cc68e..783bb3e0 100644 --- a/src/GameCult.Mesh/CultMeshClient.cs +++ b/src/GameCult.Mesh/CultMeshClient.cs @@ -782,7 +782,7 @@ namespace GameCult.Mesh new CultMeshVerseCatalogRequestMessage { VerseIds = query.VerseIds.Count == 0 ? null : query.VerseIds.ToArray(), - TransportVersion = "cultmesh.v0" + TransportVersion = _options.TransportVersion }).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); var observedAt = _options.Clock.UtcNow; diff --git a/src/GameCult.Mesh/CultMeshDiscoveryService.cs b/src/GameCult.Mesh/CultMeshDiscoveryService.cs index 964477e3..5e8c43b8 100644 --- a/src/GameCult.Mesh/CultMeshDiscoveryService.cs +++ b/src/GameCult.Mesh/CultMeshDiscoveryService.cs @@ -161,6 +161,7 @@ namespace GameCult.Mesh private readonly CultMeshDiscoveryServiceOptions _options; private readonly ConcurrentDictionary>> _inFlight = new(StringComparer.Ordinal); private readonly ConcurrentDictionary _states = new(StringComparer.Ordinal); + private readonly ConcurrentDictionary _invalidated = new(StringComparer.Ordinal); private readonly Subject _updates = new(); private long _diagnosticSequence; private bool _disposed; @@ -183,6 +184,19 @@ namespace GameCult.Mesh return state == null ? null : EvaluateAt(state, _options.Clock.UtcNow); } + /// + /// Invalidates one resolved identity so a transport failure must consult the + /// configured rendezvous sources again instead of retrying a fresh-but-dead route. + /// + public void Invalidate(CultMeshDiscoveryQuery query) + { + if (query == null) throw new ArgumentNullException(nameof(query)); + ThrowIfDisposed(); + var key = QueryKey(query); + _states.TryRemove(key, out _); + _invalidated[key] = 0; + } + public async Task ResolveAsync( CultMeshDiscoveryQuery query, CancellationToken cancellationToken = default) @@ -315,6 +329,7 @@ namespace GameCult.Mesh private async Task LoadPreviousAsync(string queryKey, CancellationToken cancellationToken) { if (_states.TryGetValue(queryKey, out var current)) return current; + if (_invalidated.TryRemove(queryKey, out _)) return null; if (_options.Store == null) return null; var stored = await _options.Store.LoadAsync(queryKey, cancellationToken).ConfigureAwait(false); if (stored != null) _states[queryKey] = stored; diff --git a/src/GameCult.Mesh/CultMeshSessions.cs b/src/GameCult.Mesh/CultMeshSessions.cs index 0a655ae8..54a19fe8 100644 --- a/src/GameCult.Mesh/CultMeshSessions.cs +++ b/src/GameCult.Mesh/CultMeshSessions.cs @@ -110,6 +110,66 @@ namespace GameCult.Mesh CancellationToken cancellationToken = default); } + /// + /// Connects exact URI routes through a caller-supplied URI-capable CultNet client. + /// This keeps transport packages outside CultMesh while preserving advertised paths. + /// + public sealed class CultMeshUriSchemaTransportConnector : ICultMeshTransportConnector + { + private readonly HashSet _schemes; + private readonly Func _createClient; + + public CultMeshUriSchemaTransportConnector( + string connectorId, + IEnumerable schemes, + Func createClient, + int priority = 0) + { + if (string.IsNullOrWhiteSpace(connectorId)) + throw new ArgumentException("Connector identity is required.", nameof(connectorId)); + ConnectorId = connectorId.Trim(); + _schemes = new HashSet( + (schemes ?? throw new ArgumentNullException(nameof(schemes))) + .Where(value => !string.IsNullOrWhiteSpace(value)) + .Select(value => value.Trim()), + StringComparer.OrdinalIgnoreCase); + if (_schemes.Count == 0) + throw new ArgumentException("At least one URI scheme is required.", nameof(schemes)); + _createClient = createClient ?? throw new ArgumentNullException(nameof(createClient)); + Priority = priority; + } + + public string ConnectorId { get; } + public int Priority { get; } + + public bool CanConnect(CultMeshTransportCandidate candidate) => + candidate != null && + Uri.TryCreate(candidate.Endpoint, UriKind.Absolute, out var uri) && + _schemes.Contains(uri.Scheme); + + public async Task ConnectAsync( + CultMeshTransportCandidate candidate, + CultMeshProtocolId protocol, + CancellationToken cancellationToken = default) + { + if (!CanConnect(candidate)) + throw new NotSupportedException($"Connector '{ConnectorId}' does not support '{candidate?.Endpoint}'."); + var endpoint = new Uri(candidate.Endpoint, UriKind.Absolute); + var client = _createClient(candidate.Endpoint) + ?? throw new InvalidOperationException($"Connector '{ConnectorId}' returned no schema client."); + try + { + await client.ConnectAsync(endpoint, cancellationToken).ConfigureAwait(false); + return client; + } + catch + { + client.Dispose(); + throw; + } + } + } + /// /// Explicit compatibility connector for the previous RUDP/LiteNetLib schema lanes. /// Prefer for registered schemas. @@ -862,6 +922,9 @@ namespace GameCult.Mesh Emit(session.EndpointId, session.Protocol, "reconnecting", failedPath.Candidate.Endpoint); try { + _discovery.Invalidate(new CultMeshDiscoveryQuery( + session.EndpointId.Value, + new[] { session.EndpointId.Value })); var replacement = await ResolveConnectedPathAsync(session.EndpointId, session.Protocol).ConfigureAwait(false); session.ReplacePhysicalChannel(replacement.Client); session.Transition(new CultMeshSessionState( diff --git a/src/GameCult.Mesh/CultMeshVerseDiscovery.cs b/src/GameCult.Mesh/CultMeshVerseDiscovery.cs index ca3655e9..801e4716 100644 --- a/src/GameCult.Mesh/CultMeshVerseDiscovery.cs +++ b/src/GameCult.Mesh/CultMeshVerseDiscovery.cs @@ -182,6 +182,9 @@ namespace GameCult.Mesh /// Gets or sets the identity of this bootstrap lookup source. public string SourceId { get; set; } = "configured-bootstrap"; + /// Gets or sets the CultMesh transport contract requested from rendezvous. + public string TransportVersion { get; set; } = "cultmesh.v0"; + /// Gets or sets how long a successful compatibility observation remains fresh. public TimeSpan ObservationTtl { get; set; } = TimeSpan.FromMinutes(5); @@ -215,7 +218,6 @@ namespace GameCult.Mesh CultMeshVerseCatalogRequestMessage? request = null) { if (string.IsNullOrWhiteSpace(endpoint)) throw new ArgumentException("Value must be non-empty.", nameof(endpoint)); - var (host, port) = CultNetSchemaWriteForwarder.ParseEndpoint(endpoint); var messageId = Guid.NewGuid().ToString("N"); var completion = new TaskCompletionSource( TaskCreationOptions.RunContinuationsAsynchronously); @@ -234,7 +236,13 @@ namespace GameCult.Mesh Emit(CultMeshDiagnosticKind.ConnectionAttempt, messageId, endpoint, "connecting"); try { - client.Connect(host, port); + if (client is ICultNetUriSchemaClient uriClient) + await uriClient.ConnectAsync(new Uri(endpoint)).ConfigureAwait(false); + else + { + var (host, port) = CultNetSchemaWriteForwarder.ParseEndpoint(endpoint); + client.Connect(host, port); + } var backgroundFailure = (client as ICultNetSchemaClientHealth)?.BackgroundFailure; await WaitForConnectionAsync(client, endpoint, backgroundFailure).ConfigureAwait(false); client.SendCultNet(new CultMeshVerseCatalogRequestMessage diff --git a/src/GameCult.Mesh/docs/browser-verse-transport.md b/src/GameCult.Mesh/docs/browser-verse-transport.md index c6748b28..92c10844 100644 --- a/src/GameCult.Mesh/docs/browser-verse-transport.md +++ b/src/GameCult.Mesh/docs/browser-verse-transport.md @@ -172,18 +172,21 @@ Current executable coverage from `scripts/verify-eve-browser-network.mjs`: - authenticated binary C# WebSocket provider; - separate local Odin fixture using the canonical Verse-catalog messages; -- real Chromium and independent C# headless consumers; +- real Chromium and retained C# headless consumers, both discovered through + the same Odin identity; - shared surface and counter document leases; - Eve button to typed operation to provider receipt to shared state; - duplicate idempotency key produces one effect; - provider restart on a different physical port rehydrates the `.cc` state; - the retained browser lease rediscovers through Odin, resubscribes, and commits a second provider-authored receipt; +- the retained C# lease independently rediscovers, resubscribes, and observes + both canonical receipt ids without application reconnect code; - generated browser bundle contains no `node:` builtin import. The full public Verse gate still requires the deployed Odin daemon rather than -the local contract fixture, retained C# lease reconnection through the same -identity path, released-artifact-only .NET consumption, and Windows/Linux CI. +the local contract fixture and released-artifact-only .NET consumption. The +source-contract gate runs on Windows and Linux CI. From an empty temporary consumer using packed/released artifacts only: diff --git a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md index 91f742ac..06547e74 100644 --- a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md +++ b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md @@ -77,7 +77,7 @@ does **not** prove the network layer; the second program owns that evidence. The network program is [`samples/eve-browser-network`](../../../../samples/eve-browser-network/README.md). Run it separately only while diagnosing that layer. A smoke against the -deployed Odin daemon and retained C# lease reconnection remain separate -infrastructure gates. Their owner map and full acceptance contract are recorded in +deployed Odin daemon remains a separate infrastructure gate. Its owner map +and full acceptance contract are recorded in [`browser-verse-transport.md`](../browser-verse-transport.md). diff --git a/src/GameCult.Networking.WebSockets/CultNetWebSocketSchemaClient.cs b/src/GameCult.Networking.WebSockets/CultNetWebSocketSchemaClient.cs index 2e778a0a..0a233ab7 100644 --- a/src/GameCult.Networking.WebSockets/CultNetWebSocketSchemaClient.cs +++ b/src/GameCult.Networking.WebSockets/CultNetWebSocketSchemaClient.cs @@ -5,7 +5,7 @@ using GameCult.Networking; namespace GameCult.Networking.WebSockets; /// Schema-v0 client over a binary WebSocket route. -public sealed class CultNetWebSocketSchemaClient : ICultNetSchemaClient, ICultNetSchemaClientHealth +public sealed class CultNetWebSocketSchemaClient : ICultNetUriSchemaClient, ICultNetSchemaClientHealth { private readonly ConcurrentDictionary> _handlers = new(); private readonly object _handlerGate = new(); diff --git a/src/GameCult.Networking/CultNetSchemaClient.cs b/src/GameCult.Networking/CultNetSchemaClient.cs index 4071cd1b..5c6117aa 100644 --- a/src/GameCult.Networking/CultNetSchemaClient.cs +++ b/src/GameCult.Networking/CultNetSchemaClient.cs @@ -38,6 +38,17 @@ namespace GameCult.Networking where T : ICultNetSchemaMessage; } + /// + /// Schema client that connects to one exact advertised URI, including its path. + /// Host/port-only connection is retained for legacy transports; rendezvous and + /// route-aware clients should prefer this contract when available. + /// + public interface ICultNetUriSchemaClient : ICultNetSchemaClient + { + /// Connects to the exact advertised schema endpoint. + Task ConnectAsync(Uri endpoint, CancellationToken cancellationToken = default); + } + /// /// Exposes terminal failure of a schema client's background transport work. /// diff --git a/tests/GameCult.Mesh.Tests/CultMeshDiscoveryServiceTests.cs b/tests/GameCult.Mesh.Tests/CultMeshDiscoveryServiceTests.cs index 1b0061d6..af6334f8 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshDiscoveryServiceTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshDiscoveryServiceTests.cs @@ -236,6 +236,33 @@ public sealed class CultMeshDiscoveryServiceTests } } + [Test] + public async Task Invalidate_BypassesFreshMemoryAndPersistedRoutesForTheNextLookup() + { + var clock = new ManualClock(new DateTimeOffset(2026, 8, 18, 0, 0, 0, TimeSpan.Zero)); + var route = "rudp://first:3076"; + var source = new DelegateSource("odin", _ => Task.FromResult>( + new[] { Observation("aetheria", "odin", clock, TimeSpan.FromMinutes(5), CultMeshDiscoveryTrust.Signed, route) })); + using var cache = new CultCache(); + using var service = new CultMeshDiscoveryService( + new[] { source }, + new CultMeshDiscoveryServiceOptions + { + Clock = clock, + Store = new CultMeshCultCacheDiscoveryStore(cache) + }); + var query = new CultMeshDiscoveryQuery("aetheria", new[] { "aetheria" }); + + var first = await service.ResolveAsync(query); + route = "rudp://second:3076"; + service.Invalidate(query); + var second = await service.ResolveAsync(query); + + first.Candidates.Single().Descriptor.DiscoveryEndpoints.Should().Equal("rudp://first:3076"); + second.Candidates.Single().Descriptor.DiscoveryEndpoints.Should().Equal("rudp://second:3076"); + source.LookupCount.Should().Be(2); + } + private static CultMeshDiscoveryObservation Observation( string verseId, string sourceId, diff --git a/tests/GameCult.Mesh.Tests/CultMeshSessionManagerTests.cs b/tests/GameCult.Mesh.Tests/CultMeshSessionManagerTests.cs index 42e6d962..4621c76b 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshSessionManagerTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshSessionManagerTests.cs @@ -128,7 +128,6 @@ public sealed class CultMeshSessionManagerTests clients[0].Emit(new CultNetErrorMessage { Error = "before rotation" }); route = "rudp://second:3076"; - clock.Advance(TimeSpan.FromSeconds(6)); clients[0].Fail(new IOException("partition")); await WaitUntilAsync(() => first.State.Status == CultMeshSessionStatus.Online && connector.ConnectCount == 2); var second = await manager.ConnectAsync(endpoint, CultMeshProtocols.Documents); @@ -142,6 +141,22 @@ public sealed class CultMeshSessionManagerTests deliveries.Should().Be(2); } + [Test] + public async Task UriConnectorPreservesTheAdvertisedPath() + { + var client = new FakeUriSchemaClient(); + var connector = new CultMeshUriSchemaTransportConnector( + "websocket", + new[] { "ws", "wss" }, + _ => client); + var candidate = new CultMeshTransportCandidate("wss://odin.example/game/cultmesh?generation=7"); + + var connected = await connector.ConnectAsync(candidate, CultMeshProtocols.Documents); + + connected.Should().BeSameAs(client); + client.Endpoint.Should().Be(new Uri(candidate.Endpoint)); + } + [Test] public void Connect_ReportsUnsupportedPathPrecisely() { @@ -326,6 +341,22 @@ public sealed class CultMeshSessionManagerTests public void Emit(CultNetErrorMessage message) { foreach (var handler in _handlers.ToArray()) handler(message); } } + private sealed class FakeUriSchemaClient : ICultNetUriSchemaClient + { + public bool Connected => Endpoint != null; + public Uri? Endpoint { get; private set; } + public void Connect(string host, int port) => throw new AssertionException("URI connection was not used."); + public Task ConnectAsync(Uri endpoint, CancellationToken cancellationToken = default) + { + cancellationToken.ThrowIfCancellationRequested(); + Endpoint = endpoint; + return Task.CompletedTask; + } + public void SendCultNet(T message) where T : ICultNetSchemaMessage { } + public void OnCultNet(Action callback) where T : ICultNetSchemaMessage { } + public void Dispose() { } + } + private sealed class RespondingSchemaClient : ICultNetSchemaClient { private readonly List> _handlers = new(); From 0943128365d301681502ef16826195a22f671f54 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 03:41:47 +0200 Subject: [PATCH 082/283] Serialize the onboarding sample build --- scripts/verify-eve-browser-network.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/verify-eve-browser-network.mjs b/scripts/verify-eve-browser-network.mjs index b0f63200..7f80cb96 100644 --- a/scripts/verify-eve-browser-network.mjs +++ b/scripts/verify-eve-browser-network.mjs @@ -50,6 +50,7 @@ try { await run("dotnet", [ "build", join(sampleRoot, "EveBrowserNetworkSample.csproj"), + "-m:1", "--verbosity", "quiet", "-p:NoWarn=1591%3BCS8632", `-p:EveRoot=${eveRoot}`, From e49f93f56df4b4362a767bb05507095008e36075 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 03:49:33 +0200 Subject: [PATCH 083/283] Invoke typed operations through retained clients --- samples/eve-browser-network/Program.cs | 24 +++- samples/eve-browser-network/README.md | 17 +-- scripts/verify-eve-browser-network.mjs | 15 +- src/GameCult.Mesh/CultMeshClient.cs | 136 ++++++++++++++++++ .../docs/browser-verse-transport.md | 17 ++- .../03-publish-an-eve-surface.md | 4 +- .../docs/getting-started/README.md | 5 +- .../CultMeshClientTests.cs | 74 ++++++++++ 8 files changed, 268 insertions(+), 24 deletions(-) diff --git a/samples/eve-browser-network/Program.cs b/samples/eve-browser-network/Program.cs index 21933bda..25809744 100644 --- a/samples/eve-browser-network/Program.cs +++ b/samples/eve-browser-network/Program.cs @@ -208,7 +208,29 @@ static async Task RunHeadlessAsync(Args arguments) Console.WriteLine("HEADLESS_READY " + JsonSerializer.Serialize(new { count = initial.Count })); } if (initial.Count >= arguments.ExpectedCount) completion.TrySetResult(); - await completion.Task.WaitAsync(TimeSpan.FromSeconds(45)); + var commandTask = Task.Run(async () => + { + var line = await Console.In.ReadLineAsync(); + if (line == null || !line.StartsWith("INVOKE ", StringComparison.Ordinal)) + throw new InvalidOperationException("The headless sample expected 'INVOKE ' on stdin."); + var commandId = line["INVOKE ".Length..].Trim(); + var result = await mesh.InvokeAsync( + arguments.VerseId, + "sample.counter", + "sample.counter.increment", + "sample.increment.v1", + "gamecult.eve.command_receipt.v1", + new IncrementRequest { Amount = 1 }, + sourceRuntimeId: "sample.csharp", + idempotencyKey: commandId); + Console.WriteLine("HEADLESS_RECEIPT " + JsonSerializer.Serialize(new + { + receiptId = result.Value.ReceiptId, + count = result.Value.Count, + status = result.Status + })); + }); + await Task.WhenAll(completion.Task, commandTask).WaitAsync(TimeSpan.FromSeconds(45)); } static EveSurfaceDocument CreateCounterSurface() diff --git a/samples/eve-browser-network/README.md b/samples/eve-browser-network/README.md index 5068ce0d..69720f7e 100644 --- a/samples/eve-browser-network/README.md +++ b/samples/eve-browser-network/README.md @@ -7,8 +7,9 @@ This is the real-process continuation of `samples/eve-two-runtime`: - one real Chromium page leases both documents through `cultmesh-browser` and lowers the provider-owned Eve surface; - one retained C# headless client discovers the provider through the same Odin - identity, observes the typed counter and canonical receipt ids, and survives - the provider route replacement without application reconnect code; + identity, observes the typed counter and canonical receipt ids, survives the + provider route replacement, and invokes through the generic CultMesh client + without application transport or reconnect code; - one separate local Odin fixture answers the canonical CultMesh Verse catalog over binary CultNet WebSocket messages; - the browser and C# clients speak the same binary CultNet schema-v0 WebSocket @@ -26,12 +27,12 @@ directly only to diagnose the network layer. Browser discovery is portable: `CHROME_PATH` wins when configured, then common Chrome/Chromium/Edge locations and Playwright's installed Chromium are checked. -The verifier clicks the Eve button twice with one idempotency key, requires one -state transition, restarts the provider on a different physical port, updates -the local Odin fixture, and requires the still-open browser to rediscover the -route, resubscribe, execute a second command, and preserve the durable count. -The retained C# lease independently rediscovers the same replacement route and -observes both canonical receipt ids. +The verifier clicks the Eve button twice with one idempotency key and requires +one state transition. It then restarts the provider on a different physical +port, updates the local Odin fixture, and requires both retained clients to +rediscover and resubscribe. The C# client invokes the second command through +`CultMeshClient.InvokeAsync`; Chromium observes the resulting count and both +clients observe both canonical receipt ids. The fixture speaks the production Verse-catalog contract; a deployment smoke against the full Odin daemon remains a separate infrastructure gate. diff --git a/scripts/verify-eve-browser-network.mjs b/scripts/verify-eve-browser-network.mjs index 7f80cb96..c82b7c50 100644 --- a/scripts/verify-eve-browser-network.mjs +++ b/scripts/verify-eve-browser-network.mjs @@ -99,10 +99,12 @@ try { await page.waitForFunction(() => window.__sampleConnectionStates?.includes("reconnecting") && window.__sampleConnectionStates.at(-1) === "connected"); - await page.evaluate(() => { window.__sampleCommandId = "browser-click-2"; }); - await page.locator("button").click(); - await page.waitForFunction(() => window.__sampleReceipt?.count === 2 && window.__sampleCount === 2); - const secondReceipt = await page.evaluate(() => window.__sampleReceipt?.receiptId); + headless.sendLine("INVOKE headless-command-2"); + const headlessReceipt = JSON.parse(await headless.waitFor("HEADLESS_RECEIPT ")); + assert.equal(headlessReceipt.status, "accepted"); + assert.equal(headlessReceipt.count, 2); + await page.waitForFunction(() => window.__sampleCount === 2); + const secondReceipt = headlessReceipt.receiptId; const secondHeadlessUpdate = JSON.parse(await headless.waitFor("HEADLESS_UPDATE_2 ")); assert.equal(secondHeadlessUpdate.count, 2); assert.ok(secondHeadlessUpdate.receiptIds.includes(firstReceipt)); @@ -151,7 +153,7 @@ async function startOdin(port, providerEndpoint) { function startDotnet(arguments_) { const process = spawn("dotnet", [ "run", "--no-build", "--project", join(sampleRoot, "EveBrowserNetworkSample.csproj"), "--", ...arguments_, - ], { cwd: repoRoot, stdio: ["ignore", "pipe", "pipe"] }); + ], { cwd: repoRoot, stdio: ["pipe", "pipe", "pipe"] }); let output = ""; let error = ""; const waiters = []; @@ -177,6 +179,9 @@ function startDotnet(arguments_) { } return { process, + sendLine(line) { + process.stdin.write(`${line}\n`); + }, waitFor(prefix, timeoutMs = 30_000) { const existing = output.split(/\r?\n/u).find(value => value.startsWith(prefix)); if (existing) return Promise.resolve(existing.slice(prefix.length)); diff --git a/src/GameCult.Mesh/CultMeshClient.cs b/src/GameCult.Mesh/CultMeshClient.cs index 783bb3e0..970e0f2f 100644 --- a/src/GameCult.Mesh/CultMeshClient.cs +++ b/src/GameCult.Mesh/CultMeshClient.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using GameCult.Caching; using GameCult.Networking; +using MessagePack; using R3; namespace GameCult.Mesh @@ -40,6 +41,45 @@ namespace GameCult.Mesh /// Gets or sets the deadline before an unanswered subscription intent is replayed. public TimeSpan SubscriptionResponseTimeout { get; set; } = TimeSpan.FromSeconds(2); + + /// Gets or sets the deadline for one correlated typed operation response. + public TimeSpan OperationResponseTimeout { get; set; } = TimeSpan.FromSeconds(10); + } + + /// + /// Carries one provider-authored operation response. Transport delivery does not by itself + /// establish that the provider accepted or committed the requested gameplay change. + /// + public sealed class CultMeshOperationResult + { + internal CultMeshOperationResult(CultNetOperationResponseMessage envelope, TResponse value) + { + MessageId = envelope.MessageId; + ServiceId = envelope.ServiceId; + Operation = envelope.Operation; + Status = envelope.Status; + PayloadSchema = envelope.PayloadSchema; + SourceRuntimeId = envelope.SourceRuntimeId; + Diagnostics = envelope.Diagnostics ?? Array.Empty(); + Value = value; + } + + /// Gets the durable caller-supplied idempotency key. + public string MessageId { get; } + /// Gets the provider service that answered. + public string ServiceId { get; } + /// Gets the operation that answered. + public string Operation { get; } + /// Gets the provider-authored operation status. + public string Status { get; } + /// Gets the portable response payload schema. + public string PayloadSchema { get; } + /// Gets the responding runtime identity, when supplied. + public string? SourceRuntimeId { get; } + /// Gets provider or transport diagnostics carried by the response. + public IReadOnlyList Diagnostics { get; } + /// Gets the decoded typed response payload. + public TResponse Value { get; } } /// Owns one shared live document subscription until disposed. @@ -85,6 +125,7 @@ namespace GameCult.Mesh private readonly CultMeshDiscoveryService _discovery; private readonly CultMeshSessionManager _sessions; private readonly TimeSpan _subscriptionResponseTimeout; + private readonly TimeSpan _operationResponseTimeout; private readonly ConcurrentDictionary _documents = new(StringComparer.Ordinal); private readonly ConcurrentDictionary _collections = new(StringComparer.Ordinal); private bool _disposed; @@ -94,6 +135,8 @@ namespace GameCult.Mesh if (options == null) throw new ArgumentNullException(nameof(options)); if (options.SubscriptionResponseTimeout <= TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(options.SubscriptionResponseTimeout)); + if (options.OperationResponseTimeout <= TimeSpan.Zero) + throw new ArgumentOutOfRangeException(nameof(options.OperationResponseTimeout)); var endpoints = options.RendezvousEndpoints .Where(endpoint => !string.IsNullOrWhiteSpace(endpoint)) .Distinct(StringComparer.Ordinal) @@ -123,6 +166,7 @@ namespace GameCult.Mesh options.RealtimeConnectors, options.Sessions); _subscriptionResponseTimeout = options.SubscriptionResponseTimeout; + _operationResponseTimeout = options.OperationResponseTimeout; } /// Connects to a stable endpoint identity using one application protocol. @@ -296,6 +340,98 @@ namespace GameCult.Mesh session.OpenSchemaClient().SendCultNet(message); } + /// + /// Invokes one typed provider operation through the reusable identity-owned session. + /// The caller supplies a durable idempotency key; the returned status and payload remain + /// provider-authored evidence rather than client-side authority over canonical state. + /// + public async Task> InvokeAsync( + string endpointId, + string serviceId, + string operation, + string requestSchema, + string responseSchema, + TRequest request, + string sourceRuntimeId, + string idempotencyKey, + CancellationToken cancellationToken = default) + { + ThrowIfDisposed(); + if (string.IsNullOrWhiteSpace(endpointId)) throw new ArgumentException("Endpoint identity is required.", nameof(endpointId)); + if (string.IsNullOrWhiteSpace(serviceId)) throw new ArgumentException("Service identity is required.", nameof(serviceId)); + if (string.IsNullOrWhiteSpace(operation)) throw new ArgumentException("Operation identity is required.", nameof(operation)); + if (string.IsNullOrWhiteSpace(requestSchema)) throw new ArgumentException("Request schema is required.", nameof(requestSchema)); + if (string.IsNullOrWhiteSpace(responseSchema)) throw new ArgumentException("Response schema is required.", nameof(responseSchema)); + if (request is null) throw new ArgumentNullException(nameof(request)); + if (string.IsNullOrWhiteSpace(sourceRuntimeId)) throw new ArgumentException("Source runtime identity is required.", nameof(sourceRuntimeId)); + if (string.IsNullOrWhiteSpace(idempotencyKey)) throw new ArgumentException("A durable idempotency key is required.", nameof(idempotencyKey)); + + var identity = endpointId.Trim(); + var expectedService = serviceId.Trim(); + var expectedOperation = operation.Trim(); + var expectedResponseSchema = responseSchema.Trim(); + var messageId = idempotencyKey.Trim(); + var session = await ConnectAsync(identity, CultMeshProtocols.Documents, cancellationToken).ConfigureAwait(false); + var completion = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + using var subscription = session.OnCultNet(response => + { + if (string.Equals(response.MessageId, messageId, StringComparison.Ordinal)) + completion.TrySetResult(response); + }); + using var timeout = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + timeout.CancelAfter(_operationResponseTimeout); + using var cancellation = timeout.Token.Register(() => completion.TrySetCanceled(timeout.Token)); + + session.SendCultNet(new CultNetOperationRequestMessage + { + MessageId = messageId, + ServiceId = expectedService, + Operation = expectedOperation, + PayloadSchema = requestSchema.Trim(), + PayloadEncoding = "messagepack-base64", + Payload = Convert.ToBase64String(MessagePackSerializer.Serialize(request, CultNetSchemaMessageSerialization.Options)), + SourceRuntimeId = sourceRuntimeId.Trim() + }); + + CultNetOperationResponseMessage envelope; + try + { + envelope = await completion.Task.ConfigureAwait(false); + } + catch (TaskCanceledException) when (!cancellationToken.IsCancellationRequested) + { + throw new TimeoutException( + $"CultMesh operation '{expectedService}/{expectedOperation}' did not answer idempotency key '{messageId}' " + + $"within {_operationResponseTimeout}."); + } + cancellationToken.ThrowIfCancellationRequested(); + if (!string.Equals(envelope.ServiceId, expectedService, StringComparison.Ordinal) || + !string.Equals(envelope.Operation, expectedOperation, StringComparison.Ordinal)) + throw new InvalidOperationException("CultMesh operation response did not match the requested service and operation."); + if (!string.Equals(envelope.PayloadSchema, expectedResponseSchema, StringComparison.Ordinal)) + throw new InvalidOperationException( + $"CultMesh operation returned payload schema '{envelope.PayloadSchema}', expected '{expectedResponseSchema}'."); + if (!string.Equals(envelope.PayloadEncoding, "messagepack-base64", StringComparison.Ordinal)) + throw new InvalidOperationException( + $"CultMesh operation returned unsupported payload encoding '{envelope.PayloadEncoding}'."); + if (string.IsNullOrWhiteSpace(envelope.Status)) + throw new InvalidOperationException("CultMesh operation response omitted its provider-authored status."); + + TResponse value; + try + { + value = MessagePackSerializer.Deserialize( + Convert.FromBase64String(envelope.Payload), + CultNetSchemaMessageSerialization.Options); + } + catch (FormatException error) + { + throw new InvalidOperationException("CultMesh operation response payload was not valid base64.", error); + } + if (value is null) throw new InvalidOperationException("CultMesh operation response decoded to null."); + return new CultMeshOperationResult(envelope, value); + } + /// Gets the number of currently leased shared document subscriptions. public int ActiveDocumentResourceCount => _documents.Count; diff --git a/src/GameCult.Mesh/docs/browser-verse-transport.md b/src/GameCult.Mesh/docs/browser-verse-transport.md index 92c10844..58a00cae 100644 --- a/src/GameCult.Mesh/docs/browser-verse-transport.md +++ b/src/GameCult.Mesh/docs/browser-verse-transport.md @@ -178,10 +178,11 @@ Current executable coverage from `scripts/verify-eve-browser-network.mjs`: - Eve button to typed operation to provider receipt to shared state; - duplicate idempotency key produces one effect; - provider restart on a different physical port rehydrates the `.cc` state; -- the retained browser lease rediscovers through Odin, resubscribes, and - commits a second provider-authored receipt; -- the retained C# lease independently rediscovers, resubscribes, and observes - both canonical receipt ids without application reconnect code; +- the retained browser lease rediscovers through Odin and resubscribes; +- the retained C# client independently rediscovers, resubscribes, invokes the + second command through `CultMeshClient.InvokeAsync`, and receives the + provider-authored receipt without application transport or reconnect code; +- Chromium observes the C# command's canonical state and receipt chronology; - generated browser bundle contains no `node:` builtin import. The full public Verse gate still requires the deployed Odin daemon rather than @@ -199,10 +200,12 @@ From an empty temporary consumer using packed/released artifacts only: 6. observe the same state version and receipt id in both clients; 7. disconnect or rotate the physical WebSocket endpoint, then require both leases to resume without application reconnect code; -8. restart the provider and prove state plus receipt persistence; -9. reject malformed schemas, direct document writes, duplicate command +8. invoke from C# after route replacement and require Chromium to observe the + same provider-authored state and receipt; +9. restart the provider and prove state plus receipt persistence; +10. reject malformed schemas, direct document writes, duplicate command effects, stale subscription generations, and unsupported authority; -10. inspect the browser bundle and fail if it contains Node builtin imports. +11. inspect the browser bundle and fail if it contains Node builtin imports. The gate runs on Windows and Linux. A screenshot is useful presentation evidence, but the receipt/state chronology is the authority proof. diff --git a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md index 06547e74..8e7a8869 100644 --- a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md +++ b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md @@ -61,7 +61,9 @@ The second layer runs a durable C# provider, a separate local Odin fixture, a real Chromium Eve lowerer, and an independent C# headless observer over binary CultNet WebSocket lanes. The open browser resolves provider identity through the canonical Verse catalog, survives a provider restart on a different route, -resubscribes, and commits another canonical receipt. +and resubscribes. The retained C# client then invokes a second typed operation +through `CultMeshClient.InvokeAsync`; Chromium and C# observe the same +provider-authored state and receipt chronology. Current verification for the Unity consumer remains: diff --git a/src/GameCult.Mesh/docs/getting-started/README.md b/src/GameCult.Mesh/docs/getting-started/README.md index 44bd5e2c..e0bd2074 100644 --- a/src/GameCult.Mesh/docs/getting-started/README.md +++ b/src/GameCult.Mesh/docs/getting-started/README.md @@ -16,8 +16,9 @@ TypeScript packages into an empty temporary consumer, validates the Eve surface and receipt, executes one idempotent counter command, proves a DOM lowerer and headless observer converge, and reopens the durable `.cc` store. Then it boots a durable C# provider, local Odin fixture, real Chromium lowerer, and independent -C# observer; it proves discovery by identity, commands, canonical receipts, -provider restart on another route, resubscription, and durable convergence. +C# client. Chromium invokes before provider replacement; C# invokes afterward. +Both retained clients prove discovery by identity, canonical receipts, provider +restart on another route, resubscription, and durable convergence. Set `CHROME_PATH` only when no installed Chrome, Chromium, Edge, or Playwright Chromium can be found automatically. diff --git a/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs b/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs index f16ee060..10af2417 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs @@ -257,6 +257,37 @@ public sealed class CultMeshClientTests submitted.Document.SourceRole.Should().Be("pilot"); } + [Test] + public async Task InvokeOperation_CorrelatesProviderReceiptThroughStableIdentitySession() + { + var connector = new DocumentConnector(); + using var mesh = new CultMeshClient(new CultMeshClientOptions + { + RendezvousEndpoints = new[] { "rudp://odin:3076" }, + Discovery = new CultMeshVerseDiscoveryClientOptions { CreateClient = () => new RendezvousClient() }, + Connectors = new[] { connector } + }); + + var result = await mesh.InvokeAsync( + "aetheria", + "tests.counter", + "tests.counter.increment", + "tests.counter.increment_request.v1", + "tests.counter.increment_receipt.v1", + new ClientOperationRequest { Amount = 2 }, + sourceRuntimeId: "pilot-one", + idempotencyKey: "pilot-command-1"); + + result.MessageId.Should().Be("pilot-command-1"); + result.Status.Should().Be("accepted"); + result.SourceRuntimeId.Should().Be("provider-daemon"); + result.Value.ReceiptId.Should().Be("receipt:pilot-command-1"); + result.Value.Count.Should().Be(2); + connector.Clients.Should().ContainSingle(); + connector.Clients[0].Operations.Should().ContainSingle() + .Which.SourceRuntimeId.Should().Be("pilot-one"); + } + [Test] public async Task Dispose_TerminatesDocumentWaitingForInitialSnapshot() { @@ -360,6 +391,7 @@ public sealed class CultMeshClientTests private sealed class DocumentClient : ICultNetSchemaClient, ICultNetSchemaClientHealth { private readonly List> _snapshots = new(); + private readonly List> _operationResponses = new(); private readonly CultNetDocumentRegistry _documents; private readonly string _text; private readonly TaskCompletionSource _failure = new(TaskCreationOptions.RunContinuationsAsynchronously); @@ -376,6 +408,7 @@ public sealed class CultMeshClientTests public int SubscribeCount { get; private set; } public int HandlerRegistrationCount { get; private set; } public List Submitted { get; } = new(); + public List Operations { get; } = new(); public void Connect(string host, int port) { } public void SendCultNet(T message) where T : ICultNetSchemaMessage { @@ -384,6 +417,32 @@ public sealed class CultMeshClientTests Submitted.Add(submitted); return; } + if (message is CultNetOperationRequestMessage operation) + { + Operations.Add(operation); + var decodedRequest = MessagePackSerializer.Deserialize( + Convert.FromBase64String(operation.Payload), + CultNetSchemaMessageSerialization.Options); + var receipt = new ClientOperationReceipt + { + ReceiptId = "receipt:" + operation.MessageId, + Count = decodedRequest.Amount + }; + var operationResponse = new CultNetOperationResponseMessage + { + MessageId = operation.MessageId, + ServiceId = operation.ServiceId, + Operation = operation.Operation, + Status = "accepted", + PayloadSchema = "tests.counter.increment_receipt.v1", + Payload = Convert.ToBase64String(MessagePackSerializer.Serialize( + receipt, + CultNetSchemaMessageSerialization.Options)), + SourceRuntimeId = "provider-daemon" + }; + foreach (var handler in _operationResponses.ToArray()) handler(operationResponse); + return; + } if (message is not CultNetDatabaseSubscribeMessage request) return; SubscribeCount++; if (_snapshotsToSuppress > 0) @@ -408,6 +467,8 @@ public sealed class CultMeshClientTests HandlerRegistrationCount++; if (typeof(T) == typeof(CultNetSnapshotResponseRawMessage)) _snapshots.Add(response => callback((T)(object)response)); + if (typeof(T) == typeof(CultNetOperationResponseMessage)) + _operationResponses.Add(response => callback((T)(object)response)); } public void Dispose() { } public void Fail(Exception error) => _failure.TrySetResult(error); @@ -440,4 +501,17 @@ public sealed class CultMeshClientTests [Key(0), CultName] public string Id { get; set; } = string.Empty; [Key(1)] public string Text { get; set; } = string.Empty; } + + [MessagePackObject] + public sealed class ClientOperationRequest + { + [Key("amount")] public int Amount { get; set; } + } + + [MessagePackObject] + public sealed class ClientOperationReceipt + { + [Key("receiptId")] public string ReceiptId { get; set; } = string.Empty; + [Key("count")] public int Count { get; set; } + } } From bfaf7a84563115713bea47f0eaffd14f08b045e3 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 03:56:24 +0200 Subject: [PATCH 084/283] Gate retained operation session growth --- samples/eve-browser-network/Program.cs | 143 ++++++++++++++++-- samples/eve-browser-network/README.md | 5 + scripts/verify-eve-browser-network.mjs | 5 + .../docs/browser-verse-transport.md | 9 +- .../03-publish-an-eve-surface.md | 4 +- .../docs/getting-started/README.md | 4 +- 6 files changed, 153 insertions(+), 17 deletions(-) diff --git a/samples/eve-browser-network/Program.cs b/samples/eve-browser-network/Program.cs index 25809744..5b8e132f 100644 --- a/samples/eve-browser-network/Program.cs +++ b/samples/eve-browser-network/Program.cs @@ -1,4 +1,5 @@ using System.Net; +using System.Diagnostics; using System.Text.Json; using GameCult.Caching; using GameCult.Caching.MessagePack; @@ -97,7 +98,24 @@ static async Task RunProviderAsync(Args arguments) var operationGate = new SemaphoreSlim(1, 1); schemaServer.OnCultNet(async (request, peer) => { - if (request.ServiceId != "sample.counter" || request.Operation != "sample.counter.increment") + if (request.ServiceId != "sample.counter") + { + peer.SendCultNet(new CultNetErrorMessage { Error = "Unsupported sample operation." }); + return; + } + if (request.Operation == "sample.counter.ping") + { + var ping = MessagePackSerializer.Deserialize( + Convert.FromBase64String(request.Payload), + CultNetSchemaMessageSerialization.Options); + SendOperationResponse( + peer, + request, + "sample.ping_receipt.v1", + new PingReceipt { Sequence = ping.Sequence }); + return; + } + if (request.Operation != "sample.counter.increment") { peer.SendCultNet(new CultNetErrorMessage { Error = "Unsupported sample operation." }); return; @@ -110,7 +128,8 @@ static async Task RunProviderAsync(Args arguments) if (!current.Receipts.TryGetValue(request.MessageId, out var receipt)) { var input = MessagePackSerializer.Deserialize( - Convert.FromBase64String(request.Payload)); + Convert.FromBase64String(request.Payload), + CultNetSchemaMessageSerialization.Options); receipt = IncrementReceipt.Accepted(request.MessageId, current.Count + input.Amount); var receipts = new Dictionary(current.Receipts, StringComparer.Ordinal) { @@ -124,16 +143,7 @@ static async Task RunProviderAsync(Args arguments) }); await cache.FlushAsync(); } - peer.SendCultNet(new CultNetOperationResponseMessage - { - MessageId = request.MessageId, - ServiceId = request.ServiceId, - Operation = request.Operation, - Status = "accepted", - PayloadSchema = "gamecult.eve.command_receipt.v1", - Payload = Convert.ToBase64String(MessagePackSerializer.Serialize(receipt)), - SourceRuntimeId = "sample.counter-provider" - }); + SendOperationResponse(peer, request, "gamecult.eve.command_receipt.v1", receipt); } finally { @@ -229,10 +239,101 @@ static async Task RunHeadlessAsync(Args arguments) count = result.Value.Count, status = result.Status })); + Console.WriteLine("HEADLESS_NETWORK_BENCHMARK " + JsonSerializer.Serialize( + await MeasureOperationSessionAsync(mesh, arguments))); }); await Task.WhenAll(completion.Task, commandTask).WaitAsync(TimeSpan.FromSeconds(45)); } +static void SendOperationResponse( + ICultNetSchemaServerPeer peer, + CultNetOperationRequestMessage request, + string payloadSchema, + T payload) +{ + peer.SendCultNet(new CultNetOperationResponseMessage + { + MessageId = request.MessageId, + ServiceId = request.ServiceId, + Operation = request.Operation, + Status = "accepted", + PayloadSchema = payloadSchema, + Payload = Convert.ToBase64String(MessagePackSerializer.Serialize( + payload, + CultNetSchemaMessageSerialization.Options)), + SourceRuntimeId = "sample.counter-provider" + }); +} + +static async Task MeasureOperationSessionAsync(CultMeshClient mesh, Args arguments) +{ + const int warmupOperations = 100; + if (arguments.BenchmarkOperations <= 0) + throw new ArgumentOutOfRangeException(nameof(arguments.BenchmarkOperations)); + for (var index = 0; index < warmupOperations; index++) + await PingAsync(mesh, arguments, "warmup:" + index, index); + + ForceCollection(); + using var process = Process.GetCurrentProcess(); + process.Refresh(); + var managedHeapBefore = GC.GetTotalMemory(forceFullCollection: false); + var privateBytesBefore = process.PrivateMemorySize64; + var latencies = new double[arguments.BenchmarkOperations]; + var clock = Stopwatch.StartNew(); + for (var index = 0; index < arguments.BenchmarkOperations; index++) + { + var started = Stopwatch.GetTimestamp(); + await PingAsync(mesh, arguments, "benchmark:" + index, index); + latencies[index] = Stopwatch.GetElapsedTime(started).TotalMilliseconds; + } + clock.Stop(); + ForceCollection(); + process.Refresh(); + var managedHeapAfter = GC.GetTotalMemory(forceFullCollection: false); + var privateBytesAfter = process.PrivateMemorySize64; + Array.Sort(latencies); + var p99 = latencies[Math.Clamp((int)Math.Ceiling(latencies.Length * 0.99) - 1, 0, latencies.Length - 1)]; + var managedHeapGrowth = managedHeapAfter - managedHeapBefore; + if (managedHeapGrowth > 8 * 1024 * 1024) + throw new InvalidOperationException($"Retained operation session grew the managed heap by {managedHeapGrowth} bytes."); + if (p99 > 250) + throw new InvalidOperationException($"Retained operation session p99 was {p99:F2} ms."); + return new + { + operations = arguments.BenchmarkOperations, + p99Milliseconds = p99, + operationsPerSecond = arguments.BenchmarkOperations / clock.Elapsed.TotalSeconds, + managedHeapBefore, + managedHeapAfter, + managedHeapGrowth, + privateBytesBefore, + privateBytesAfter, + privateBytesGrowth = privateBytesAfter - privateBytesBefore + }; +} + +static async Task PingAsync(CultMeshClient mesh, Args arguments, string idempotencyKey, int sequence) +{ + var result = await mesh.InvokeAsync( + arguments.VerseId, + "sample.counter", + "sample.counter.ping", + "sample.ping_request.v1", + "sample.ping_receipt.v1", + new PingRequest { Sequence = sequence }, + sourceRuntimeId: "sample.csharp", + idempotencyKey: idempotencyKey); + if (result.Status != "accepted" || result.Value.Sequence != sequence) + throw new InvalidOperationException("The typed ping receipt did not match its request."); +} + +static void ForceCollection() +{ + GC.Collect(); + GC.WaitForPendingFinalizers(); + GC.Collect(); +} + static EveSurfaceDocument CreateCounterSurface() { var networkRoute = new CultMeshRouteHint(CultMeshLocalityKind.Network, "cultmesh"); @@ -300,6 +401,7 @@ sealed class Args public string TransportVersion { get; private init; } = "cultmesh.v0"; public string RulesHash { get; private init; } = "sample-counter-v1"; public int ExpectedCount { get; private init; } = 2; + public int BenchmarkOperations { get; private init; } = 10_000; public static Args Parse(string[] values) { @@ -322,7 +424,10 @@ sealed class Args RulesHash = named.GetValueOrDefault("--rules-hash", "sample-counter-v1"), ExpectedCount = named.TryGetValue("--expected-count", out var expectedCount) ? int.Parse(expectedCount) - : 2 + : 2, + BenchmarkOperations = named.TryGetValue("--benchmark-operations", out var benchmarkOperations) + ? int.Parse(benchmarkOperations) + : 10_000 }; } } @@ -370,3 +475,15 @@ public sealed class IncrementReceipt Count = count }; } + +[MessagePackObject] +public sealed class PingRequest +{ + [Key("sequence")] public int Sequence { get; set; } +} + +[MessagePackObject] +public sealed class PingReceipt +{ + [Key("sequence")] public int Sequence { get; set; } +} diff --git a/samples/eve-browser-network/README.md b/samples/eve-browser-network/README.md index 69720f7e..c039cd42 100644 --- a/samples/eve-browser-network/README.md +++ b/samples/eve-browser-network/README.md @@ -33,6 +33,11 @@ port, updates the local Odin fixture, and requires both retained clients to rediscover and resubscribe. The C# client invokes the second command through `CultMeshClient.InvokeAsync`; Chromium observes the resulting count and both clients observe both canonical receipt ids. +The retained C# client then sends 10,000 typed no-op operations over the same +real WebSocket session. The gate records p99 latency, throughput, managed heap, +and private memory, and rejects more than 8 MiB of post-GC managed growth or a +250 ms p99. The no-op provider handler stores no receipt history, so persistence +growth cannot impersonate a client leak. The fixture speaks the production Verse-catalog contract; a deployment smoke against the full Odin daemon remains a separate infrastructure gate. diff --git a/scripts/verify-eve-browser-network.mjs b/scripts/verify-eve-browser-network.mjs index c82b7c50..3f633dc9 100644 --- a/scripts/verify-eve-browser-network.mjs +++ b/scripts/verify-eve-browser-network.mjs @@ -109,6 +109,10 @@ try { assert.equal(secondHeadlessUpdate.count, 2); assert.ok(secondHeadlessUpdate.receiptIds.includes(firstReceipt)); assert.ok(secondHeadlessUpdate.receiptIds.includes(secondReceipt)); + const networkBenchmark = JSON.parse(await headless.waitFor("HEADLESS_NETWORK_BENCHMARK ", 60_000)); + assert.equal(networkBenchmark.operations, 10_000); + assert.ok(networkBenchmark.p99Milliseconds < 250); + assert.ok(networkBenchmark.managedHeapGrowth <= 8 * 1024 * 1024); const connectionStates = await page.evaluate(() => window.__sampleConnectionStates); assert.equal(connectionStates[0], "connected"); assert.equal(connectionStates.at(-1), "connected"); @@ -126,6 +130,7 @@ try { count: 2, routeRotationCount: 1, retainedHeadlessLease: true, + networkBenchmark, })); } finally { if (browser) await browser.close().catch(() => undefined); diff --git a/src/GameCult.Mesh/docs/browser-verse-transport.md b/src/GameCult.Mesh/docs/browser-verse-transport.md index 58a00cae..ecec20ef 100644 --- a/src/GameCult.Mesh/docs/browser-verse-transport.md +++ b/src/GameCult.Mesh/docs/browser-verse-transport.md @@ -183,6 +183,9 @@ Current executable coverage from `scripts/verify-eve-browser-network.mjs`: second command through `CultMeshClient.InvokeAsync`, and receives the provider-authored receipt without application transport or reconnect code; - Chromium observes the C# command's canonical state and receipt chronology; +- 10,000 typed no-op operations traverse the retained C# WebSocket session; + the gate records throughput, p99, post-GC managed growth, and private-memory + movement without growing provider state; - generated browser bundle contains no `node:` builtin import. The full public Verse gate still requires the deployed Odin daemon rather than @@ -203,9 +206,11 @@ From an empty temporary consumer using packed/released artifacts only: 8. invoke from C# after route replacement and require Chromium to observe the same provider-authored state and receipt; 9. restart the provider and prove state plus receipt persistence; -10. reject malformed schemas, direct document writes, duplicate command +10. run a non-persistent operation workload long enough to falsify retained + callback or managed-heap growth; +11. reject malformed schemas, direct document writes, duplicate command effects, stale subscription generations, and unsupported authority; -11. inspect the browser bundle and fail if it contains Node builtin imports. +12. inspect the browser bundle and fail if it contains Node builtin imports. The gate runs on Windows and Linux. A screenshot is useful presentation evidence, but the receipt/state chronology is the authority proof. diff --git a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md index 8e7a8869..a9126cd7 100644 --- a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md +++ b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md @@ -63,7 +63,9 @@ CultNet WebSocket lanes. The open browser resolves provider identity through the canonical Verse catalog, survives a provider restart on a different route, and resubscribes. The retained C# client then invokes a second typed operation through `CultMeshClient.InvokeAsync`; Chromium and C# observe the same -provider-authored state and receipt chronology. +provider-authored state and receipt chronology. The same retained C# session +then completes 10,000 typed no-op operations under explicit p99 and post-GC +managed-memory gates, so the tutorial pressure-tests the API it teaches. Current verification for the Unity consumer remains: diff --git a/src/GameCult.Mesh/docs/getting-started/README.md b/src/GameCult.Mesh/docs/getting-started/README.md index e0bd2074..5251c7ca 100644 --- a/src/GameCult.Mesh/docs/getting-started/README.md +++ b/src/GameCult.Mesh/docs/getting-started/README.md @@ -18,7 +18,9 @@ headless observer converge, and reopens the durable `.cc` store. Then it boots a durable C# provider, local Odin fixture, real Chromium lowerer, and independent C# client. Chromium invokes before provider replacement; C# invokes afterward. Both retained clients prove discovery by identity, canonical receipts, provider -restart on another route, resubscription, and durable convergence. +restart on another route, resubscription, and durable convergence. The retained +C# session also completes 10,000 non-persistent typed operations under p99 and +post-GC managed-memory gates. Set `CHROME_PATH` only when no installed Chrome, Chromium, Edge, or Playwright Chromium can be found automatically. From f65352fa733034a299a798cffa64abf571021810 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 04:03:06 +0200 Subject: [PATCH 085/283] Measure mapped hot-body copy cost --- README.md | 12 +++ src/GameCult.Mesh/CultMeshFrameBodies.cs | 55 +++++++++- src/GameCult.Mesh/docs/public-api.md | 7 ++ .../CultMeshFrameBodyTests.cs | 16 +++ .../GameCult.Mesh.PerformanceProbe/Program.cs | 100 +++++++++++++++++- 5 files changed, 184 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 68ee88d6..2d787739 100644 --- a/README.md +++ b/README.md @@ -166,6 +166,18 @@ npm test --workspace packages/cultmesh-ts npm test --workspace packages/cultmesh-browser ``` +Measured reactive, retained-session, and shared-memory hot-body gates: + +```powershell +pwsh -File ./scripts/measure-reactive-document-performance.ps1 -Quick +pwsh -File ./scripts/verify-eve-getting-started.ps1 +``` + +The first command measures the same 16 KiB document workload in C#, +TypeScript, and Python and includes a mapped hot-body probe with explicit copy +telemetry. The second includes 10,000 real WebSocket operations on one retained +identity-owned C# session after provider route replacement. + Rust package tests: ```powershell diff --git a/src/GameCult.Mesh/CultMeshFrameBodies.cs b/src/GameCult.Mesh/CultMeshFrameBodies.cs index 5c4d26d0..9f8464fd 100644 --- a/src/GameCult.Mesh/CultMeshFrameBodies.cs +++ b/src/GameCult.Mesh/CultMeshFrameBodies.cs @@ -12,6 +12,27 @@ using Microsoft.Win32.SafeHandles; namespace GameCult.Mesh { + /// Reports bounded shared-memory frame publication and explicit copy telemetry. + public sealed class CultMeshFrameBodyPublisherStats + { + internal CultMeshFrameBodyPublisherStats( + ulong publishedFrames, + ulong blockedWrites, + ulong unavoidableCopyCount) + { + PublishedFrames = publishedFrames; + BlockedWrites = blockedWrites; + UnavoidableCopyCount = unavoidableCopyCount; + } + + /// Gets the number of atomically committed generations. + public ulong PublishedFrames { get; } + /// Gets the number of write reservations refused by bounded slots. + public ulong BlockedWrites { get; } + /// Gets copies explicitly declared by copy-fallback publication. + public ulong UnavoidableCopyCount { get; } + } + // Owner: this publisher owns mapping lifetime, logical generation, and slot commit. // Consumers own only read leases; mappings, capabilities, and slot selection remain CultMesh state. public sealed class CultMeshFrameBodyPublisher : IDisposable @@ -34,6 +55,9 @@ namespace GameCult.Mesh private readonly string _token; private int _cursor; private long _nextSequence; + private ulong _publishedFrames; + private ulong _blockedWrites; + private ulong _unavoidableCopyCount; private CultMeshFrameBodyWriteLease? _activeWrite; private bool _disposed; @@ -88,7 +112,7 @@ namespace GameCult.Mesh using (write) { body.CopyTo(write.Span); - descriptor = write.Commit(body.Length, nowUtc); + descriptor = write.Commit(body.Length, nowUtc, unavoidableCopyCount: 1); return true; } } @@ -103,6 +127,7 @@ namespace GameCult.Mesh ThrowIfDisposed(); if (_activeWrite != null) { + _blockedWrites++; lease = null!; return false; } @@ -124,6 +149,7 @@ namespace GameCult.Mesh }); if (slot < 0) { + _blockedWrites++; lease = null!; return false; } @@ -149,7 +175,8 @@ namespace GameCult.Mesh internal CultMeshBodyDescriptor Commit( CultMeshFrameBodyWriteLease lease, int byteLength, - DateTimeOffset nowUtc) + DateTimeOffset nowUtc, + int unavoidableCopyCount) { lock (_gate) { @@ -158,6 +185,8 @@ namespace GameCult.Mesh throw new InvalidOperationException("The CultMesh frame write lease is stale or is not owned by this publisher."); if (byteLength < 0 || byteLength > SlotByteLength) throw new ArgumentOutOfRangeException(nameof(byteLength)); + if (unavoidableCopyCount < 0) + throw new ArgumentOutOfRangeException(nameof(unavoidableCopyCount)); var semanticHash = CultMeshBodyDescriptorValidator.ComputeSemanticHash(lease.Span[..byteLength]); WithMutex(() => { @@ -174,6 +203,8 @@ namespace GameCult.Mesh }); var descriptor = Descriptor(lease.SlotIndex, byteLength, lease.Sequence, semanticHash, nowUtc); _nextSequence++; + _publishedFrames++; + _unavoidableCopyCount += (ulong)Math.Max(0, unavoidableCopyCount); _activeWrite = null; lease.Complete(); return descriptor; @@ -194,6 +225,19 @@ namespace GameCult.Mesh } } + /// Gets current publication, backpressure, and explicit fallback-copy counters. + public CultMeshFrameBodyPublisherStats Stats() + { + lock (_gate) + { + ThrowIfDisposed(); + return new CultMeshFrameBodyPublisherStats( + _publishedFrames, + _blockedWrites, + _unavoidableCopyCount); + } + } + private CultMeshBodyDescriptor Descriptor( int slot, int byteLength, @@ -514,9 +558,12 @@ namespace GameCult.Mesh public Memory Memory => _memory.Memory; public Span Span => Memory.Span; - public CultMeshBodyDescriptor Commit(int byteLength, DateTimeOffset nowUtc) => + public CultMeshBodyDescriptor Commit( + int byteLength, + DateTimeOffset nowUtc, + int unavoidableCopyCount = 0) => (_owner ?? throw new ObjectDisposedException(nameof(CultMeshFrameBodyWriteLease))) - .Commit(this, byteLength, nowUtc); + .Commit(this, byteLength, nowUtc, unavoidableCopyCount); internal void Complete() { diff --git a/src/GameCult.Mesh/docs/public-api.md b/src/GameCult.Mesh/docs/public-api.md index 174ff84a..e5706595 100644 --- a/src/GameCult.Mesh/docs/public-api.md +++ b/src/GameCult.Mesh/docs/public-api.md @@ -208,6 +208,13 @@ portable machinery that makes it feel native. slices, or browser typed arrays. `CultMesh.DescribeNativeSliceView(...)` exposes the full view id, schema id, row count, columns, route, native handle, and dense stride for tools and adapters. +- `CultMeshFrameBodyPublisher` and `CultMeshMappedFrameBodyCursor` carry + fixed-layout hot bodies through a triple-buffered memory mapping. Producers + reserve a writable slot and commit in place; consumers retain one bootstrap + capability and acquire only newer read leases. `Stats()` reports committed + frames, blocked writes, and unavoidable copies. Direct slot writes report + zero copies; the convenience `TryPublish(ReadOnlySpan)` path reports + one explicit fallback copy instead of laundering it as zero-copy transport. - `CultMeshRouteHint`, `CultMeshRouteRecord`, and `CultMeshLocalityKind` name locality choices without forcing application code to choose transport-specific APIs. `CultMesh.RouteRecord(...)` is the shared way to flatten and rehydrate diff --git a/tests/GameCult.Mesh.Tests/CultMeshFrameBodyTests.cs b/tests/GameCult.Mesh.Tests/CultMeshFrameBodyTests.cs index 2d69015d..ede0e3c4 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshFrameBodyTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshFrameBodyTests.cs @@ -30,6 +30,22 @@ public sealed class CultMeshFrameBodyTests lease.ReadByte(0).Should().Be(1); } + [Test] + public void PublisherTelemetryDistinguishesDirectWritesFromCopyFallback() + { + using var publisher = Publisher(); + publisher.TryPublish(new byte[] { 1, 2, 3 }, DateTimeOffset.UtcNow, out _).Should().BeTrue(); + + publisher.TryAcquireWrite(out var direct).Should().BeTrue(); + direct.Span[..3].Fill(7); + direct.Commit(3, DateTimeOffset.UtcNow); + + var stats = publisher.Stats(); + stats.PublishedFrames.Should().Be(2); + stats.BlockedWrites.Should().Be(0); + stats.UnavoidableCopyCount.Should().Be(1); + } + [Test] public void MappedCursorObservesNewGenerationsWithoutNewControlDescriptors() { diff --git a/tools/GameCult.Mesh.PerformanceProbe/Program.cs b/tools/GameCult.Mesh.PerformanceProbe/Program.cs index 948d8e90..0a367d36 100644 --- a/tools/GameCult.Mesh.PerformanceProbe/Program.cs +++ b/tools/GameCult.Mesh.PerformanceProbe/Program.cs @@ -14,6 +14,7 @@ var results = new List(); foreach (var documentCount in documentCounts) results.Add(await MeasureAsync(documentCount, idleDuration, activeDuration)); +var hotBody = await MeasureHotBodyAsync(activeDuration); Console.WriteLine(JsonSerializer.Serialize(new { @@ -26,17 +27,98 @@ Console.WriteLine(JsonSerializer.Serialize(new updateRateHz = 60, changedFraction = 0.01 }, - results + results, + hotBody }, new JsonSerializerOptions { WriteIndented = true })); return results.All(result => result.ActualPublishes == result.ExpectedPublishes && result.PayloadBytesPublished > 0 && result.AllocationToPayloadRatio < 10 && - result.P99PublishLatencyMilliseconds < 250) + result.P99PublishLatencyMilliseconds < 250) && + hotBody.ActualFrames == hotBody.ExpectedFrames && + hotBody.UnavoidableCopyCount == 0 && + hotBody.BlockedWrites == 0 && + hotBody.P99RoundTripMilliseconds < 250 ? 0 : 1; +static async Task MeasureHotBodyAsync(TimeSpan activeDuration) +{ + const int payloadBytes = 16 * 1024; + using var publisher = new CultMeshFrameBodyPublisher( + "performance:hot-body", + "gamecult.mesh.performance_hot_body.v1", + layoutVersion: 1, + capacity: payloadBytes, + producerEpoch: 1, + slotByteLength: payloadBytes, + leaseDuration: TimeSpan.FromMinutes(1)); + if (!publisher.TryAcquireWrite(out var bootstrapWrite)) + throw new InvalidOperationException("Hot-body probe could not reserve its bootstrap slot."); + CultMeshBodyDescriptor bootstrap; + using (bootstrapWrite) + { + bootstrapWrite.Span[..payloadBytes].Fill(1); + bootstrap = bootstrapWrite.Commit(payloadBytes, DateTimeOffset.UtcNow); + } + using var cursor = new CultMeshMappedFrameBodyCursor(bootstrap); + if (!cursor.TryAcquireLatest(out var bootstrapRead)) + throw new InvalidOperationException("Hot-body probe could not acquire its bootstrap generation."); + bootstrapRead.Dispose(); + + ForceCollection(); + using var process = Process.GetCurrentProcess(); + process.Refresh(); + var allocatedStart = GC.GetTotalAllocatedBytes(precise: true); + var privateBytesStart = process.PrivateMemorySize64; + var cpuStart = process.TotalProcessorTime; + var clock = Stopwatch.StartNew(); + var frameInterval = TimeSpan.FromSeconds(1.0 / 60.0); + var latencies = new List(); + var frames = 0; + while (clock.Elapsed < activeDuration) + { + var started = Stopwatch.GetTimestamp(); + if (!publisher.TryAcquireWrite(out var write)) + throw new InvalidOperationException("Hot-body probe encountered unexpected write backpressure."); + var marker = (byte)(frames % 251 + 1); + using (write) + { + write.Span[..payloadBytes].Fill(marker); + write.Commit(payloadBytes, DateTimeOffset.UtcNow); + } + if (!cursor.TryAcquireLatest(out var read)) + throw new InvalidOperationException("Hot-body cursor missed a committed generation."); + using (read) + { + if (read.Descriptor.ByteSize != payloadBytes || read.ReadByte(0) != marker || read.ReadByte(payloadBytes - 1) != marker) + throw new InvalidOperationException("Hot-body cursor observed torn or mismatched bytes."); + } + latencies.Add(Stopwatch.GetElapsedTime(started).TotalMilliseconds); + frames++; + var remaining = frameInterval * frames - clock.Elapsed; + if (remaining > TimeSpan.Zero) await Task.Delay(remaining); + } + + process.Refresh(); + var stats = publisher.Stats(); + var ordered = latencies.OrderBy(value => value).ToArray(); + return new HotBodyProbeResult( + ExpectedFrames: frames + 1, + ActualFrames: checked((int)stats.PublishedFrames), + PayloadBytes: payloadBytes, + P50RoundTripMilliseconds: Percentile(ordered, 0.50), + P95RoundTripMilliseconds: Percentile(ordered, 0.95), + P99RoundTripMilliseconds: Percentile(ordered, 0.99), + AllocatedBytes: GC.GetTotalAllocatedBytes(precise: true) - allocatedStart, + PrivateBytesBefore: privateBytesStart, + PrivateBytesAfter: process.PrivateMemorySize64, + CpuMilliseconds: (process.TotalProcessorTime - cpuStart).TotalMilliseconds, + BlockedWrites: stats.BlockedWrites, + UnavoidableCopyCount: stats.UnavoidableCopyCount); +} + static async Task MeasureAsync( int documentCount, TimeSpan idleDuration, @@ -201,6 +283,20 @@ internal sealed record ProbeResult( double P99PublishLatencyMilliseconds, double ScenarioWallSeconds); +internal sealed record HotBodyProbeResult( + int ExpectedFrames, + int ActualFrames, + int PayloadBytes, + double P50RoundTripMilliseconds, + double P95RoundTripMilliseconds, + double P99RoundTripMilliseconds, + long AllocatedBytes, + long PrivateBytesBefore, + long PrivateBytesAfter, + double CpuMilliseconds, + ulong BlockedWrites, + ulong UnavoidableCopyCount); + [CultDocument("gamecult.mesh.performance_probe", "gamecult.mesh.performance_probe.v1")] [MessagePackObject] public sealed class PerformanceDocument From 35d31ae90832dea2f747a1c0162a2b8d304158d7 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 04:18:46 +0200 Subject: [PATCH 086/283] Support mapped frame bodies on Unix --- README.md | 3 +- src/GameCult.Mesh/CultMeshFrameBodies.cs | 41 +++++++++++++++---- src/GameCult.Mesh/README.md | 5 +++ src/GameCult.Mesh/docs/public-api.md | 5 ++- .../CultMeshFrameBodyTests.cs | 17 ++++++++ 5 files changed, 60 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 2d787739..df4dd6f0 100644 --- a/README.md +++ b/README.md @@ -175,7 +175,8 @@ pwsh -File ./scripts/verify-eve-getting-started.ps1 The first command measures the same 16 KiB document workload in C#, TypeScript, and Python and includes a mapped hot-body probe with explicit copy -telemetry. The second includes 10,000 real WebSocket operations on one retained +telemetry on Windows named maps and Unix file-backed maps. The second includes +10,000 real WebSocket operations on one retained identity-owned C# session after provider route replacement. Rust package tests: diff --git a/src/GameCult.Mesh/CultMeshFrameBodies.cs b/src/GameCult.Mesh/CultMeshFrameBodies.cs index 9f8464fd..dbf2e235 100644 --- a/src/GameCult.Mesh/CultMeshFrameBodies.cs +++ b/src/GameCult.Mesh/CultMeshFrameBodies.cs @@ -3,6 +3,7 @@ using System.Buffers; using System.Collections.Generic; using System.IO; using System.IO.MemoryMappedFiles; +using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Text; using System.Threading; @@ -53,6 +54,7 @@ namespace GameCult.Mesh private readonly Mutex _mutex; private readonly TimeSpan _leaseDuration; private readonly string _token; + private readonly string? _mappingPath; private int _cursor; private long _nextSequence; private ulong _publishedFrames; @@ -83,7 +85,21 @@ namespace GameCult.Mesh _leaseDuration = leaseDuration ?? TimeSpan.FromSeconds(5); if (_leaseDuration <= TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(leaseDuration)); _token = CapabilityPrefix + RandomToken(); - _mapping = MemoryMappedFile.CreateNew(MappingName(_token), checked(HeaderSize + CultMeshFrameRegion.SlotCount * slotByteLength)); + var mappingByteLength = checked(HeaderSize + CultMeshFrameRegion.SlotCount * slotByteLength); + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + _mapping = MemoryMappedFile.CreateNew(MappingName(_token), mappingByteLength); + } + else + { + _mappingPath = MappingPath(_token); + _mapping = MemoryMappedFile.CreateFromFile( + _mappingPath, + FileMode.CreateNew, + null, + mappingByteLength, + MemoryMappedFileAccess.ReadWrite); + } _control = _mapping.CreateViewAccessor(0, HeaderSize, MemoryMappedFileAccess.ReadWrite); _control.Write(0, slotByteLength); _control.Write(4, CultMeshFrameRegion.SlotCount); @@ -263,7 +279,7 @@ namespace GameCult.Mesh Mutex mutex; try { - mapping = MemoryMappedFile.OpenExisting(MappingName(token), MemoryMappedFileRights.ReadWrite); + mapping = OpenMapping(token); mutex = Mutex.OpenExisting(MutexName(token)); } catch (Exception error) when (error is FileNotFoundException || error is WaitHandleCannotBeOpenedException) @@ -307,7 +323,7 @@ namespace GameCult.Mesh { try { - using var mapping = MemoryMappedFile.OpenExisting(MappingName(token), MemoryMappedFileRights.ReadWrite); + using var mapping = OpenMapping(token); using var mutex = Mutex.OpenExisting(MutexName(token)); WithMutex(mutex, () => { @@ -331,6 +347,12 @@ namespace GameCult.Mesh _control.Dispose(); _mapping.Dispose(); _mutex.Dispose(); + if (_mappingPath != null) + { + try { File.Delete(_mappingPath); } + catch (IOException) { } + catch (UnauthorizedAccessException) { } + } } } @@ -343,6 +365,11 @@ namespace GameCult.Mesh } internal static long SlotOffset(int slot, int slotByteLength) => HeaderSize + (long)slot * slotByteLength; internal static string MappingName(string token) => "cultmesh-map-" + token; + internal static string MappingPath(string token) => Path.Combine(Path.GetTempPath(), MappingName(token) + ".map"); + internal static MemoryMappedFile OpenMapping(string token) => + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? MemoryMappedFile.OpenExisting(MappingName(token), MemoryMappedFileRights.ReadWrite) + : MemoryMappedFile.CreateFromFile(MappingPath(token), FileMode.Open, null, 0, MemoryMappedFileAccess.ReadWrite); internal static string MutexName(string token) => "cultmesh-lock-" + token; internal static void ParseCapability(string capability, out string token, out int slot) { @@ -393,9 +420,7 @@ namespace GameCult.Mesh CultMeshFrameBodyPublisher.ParseCapability(descriptor.CapabilityToken, out _token, out _); try { - _mapping = MemoryMappedFile.OpenExisting( - CultMeshFrameBodyPublisher.MappingName(_token), - MemoryMappedFileRights.ReadWrite); + _mapping = CultMeshFrameBodyPublisher.OpenMapping(_token); _mutex = Mutex.OpenExisting(CultMeshFrameBodyPublisher.MutexName(_token)); } catch (Exception error) when (error is FileNotFoundException || error is WaitHandleCannotBeOpenedException) @@ -503,9 +528,7 @@ namespace GameCult.Mesh }; try { - var mapping = MemoryMappedFile.OpenExisting( - CultMeshFrameBodyPublisher.MappingName(_token), - MemoryMappedFileRights.ReadWrite); + var mapping = CultMeshFrameBodyPublisher.OpenMapping(_token); lease = new CultMeshMappedBodyLease( descriptor, mapping, diff --git a/src/GameCult.Mesh/README.md b/src/GameCult.Mesh/README.md index f6e0ea30..6b9be603 100644 --- a/src/GameCult.Mesh/README.md +++ b/src/GameCult.Mesh/README.md @@ -388,6 +388,11 @@ receives one shared-memory bootstrap descriptor, then observes later commits through the mapped ring header. Per-frame CultNet documents are neither needed nor desirable. +The mapped ring uses a named memory map on Windows and a capability-named, +publisher-owned temporary backing file on Unix. This distinction belongs to +the CultMesh adapter; providers and consumers use the same descriptor/cursor +contract on both platforms. + ```csharp using var entities = await CultMesh.SubscribeLiveBodyAsync( subscriptions, diff --git a/src/GameCult.Mesh/docs/public-api.md b/src/GameCult.Mesh/docs/public-api.md index e5706595..88074704 100644 --- a/src/GameCult.Mesh/docs/public-api.md +++ b/src/GameCult.Mesh/docs/public-api.md @@ -211,7 +211,10 @@ portable machinery that makes it feel native. - `CultMeshFrameBodyPublisher` and `CultMeshMappedFrameBodyCursor` carry fixed-layout hot bodies through a triple-buffered memory mapping. Producers reserve a writable slot and commit in place; consumers retain one bootstrap - capability and acquire only newer read leases. `Stats()` reports committed + capability and acquire only newer read leases. Windows uses a named memory + map; Unix uses a private file-backed map because .NET does not support named + maps there. The capability and cursor API is identical, and publisher + disposal revokes new opens and removes the Unix backing file. `Stats()` reports committed frames, blocked writes, and unavoidable copies. Direct slot writes report zero copies; the convenience `TryPublish(ReadOnlySpan)` path reports one explicit fallback copy instead of laundering it as zero-copy transport. diff --git a/tests/GameCult.Mesh.Tests/CultMeshFrameBodyTests.cs b/tests/GameCult.Mesh.Tests/CultMeshFrameBodyTests.cs index ede0e3c4..2c6114bd 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshFrameBodyTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshFrameBodyTests.cs @@ -167,6 +167,23 @@ public sealed class CultMeshFrameBodyTests reopen.Should().Throw(); } + [Test] + public void UnixPublisherOwnsAndDeletesItsFileBackedMap() + { + if (OperatingSystem.IsWindows()) + Assert.Ignore("Windows uses a named memory map rather than a backing file."); + + var publisher = Publisher(); + publisher.TryPublish(new byte[] { 42 }, DateTimeOffset.UtcNow, out var descriptor).Should().BeTrue(); + var token = descriptor.CapabilityToken[..descriptor.CapabilityToken.LastIndexOf('.')]; + var path = Path.Combine(Path.GetTempPath(), "cultmesh-map-" + token + ".map"); + File.Exists(path).Should().BeTrue(); + + publisher.Dispose(); + + File.Exists(path).Should().BeFalse(); + } + [Test] public void PublishesOneAtomicSchemaVersionedGenerationPerCommit() { From b0a876a22022c8c35b007348ea045c2640ed567c Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 05:59:11 +0200 Subject: [PATCH 087/283] Add typed CultNet operation dispatch --- packages/cultmesh-browser/README.md | 6 + packages/cultmesh-browser/src/index.ts | 36 ++ .../test/cultmesh-browser.test.ts | 52 ++- samples/eve-browser-network/Program.cs | 182 ++++----- samples/eve-browser-network/README.md | 6 + scripts/verify-eve-getting-started.ps1 | 11 + src/GameCult.Mesh/CultMeshClient.cs | 41 +++ src/GameCult.Mesh/README.md | 14 +- .../03-publish-an-eve-surface.md | 52 +++ .../CultNetOperationServer.cs | 348 ++++++++++++++++++ src/GameCult.Networking/README.md | 27 ++ .../CultMeshClientTests.cs | 61 ++- .../CultNetOperationServerTests.cs | 205 +++++++++++ 13 files changed, 913 insertions(+), 128 deletions(-) create mode 100644 src/GameCult.Networking/CultNetOperationServer.cs create mode 100644 tests/GameCult.Networking.Tests/CultNetOperationServerTests.cs diff --git a/packages/cultmesh-browser/README.md b/packages/cultmesh-browser/README.md index acf349e6..62f70585 100644 --- a/packages/cultmesh-browser/README.md +++ b/packages/cultmesh-browser/README.md @@ -30,6 +30,12 @@ const counter = await mesh.leaseRawDocument({ counter.watch(record => renderCounter(decodeCultNetPayload(record))); ``` +`invoke(...)` returns the correlated provider response. Routing, schema, and +envelope failures reject immediately with `CultMeshBrowserOperationError`; +callers can branch on its stable `status` and `code` without parsing prose or +waiting for the request timeout. Domain rejections remain typed provider +responses because the domain still owns their receipt schema. + `CultMeshBrowserOdinRendezvous` speaks the canonical CultNet Verse-catalog messages to one or more configured Odin WebSocket endpoints. Application code supplies stable identity; it does not own endpoint selection, reconnect, or diff --git a/packages/cultmesh-browser/src/index.ts b/packages/cultmesh-browser/src/index.ts index eb2420e3..b14e05ec 100644 --- a/packages/cultmesh-browser/src/index.ts +++ b/packages/cultmesh-browser/src/index.ts @@ -176,6 +176,29 @@ export interface CultMeshOperationOptions { targetRuntimeId?: string; } +/** Portable schema returned when routing or envelope validation fails before a domain reply exists. */ +export const cultNetOperationFailureSchema = "gamecult.cultnet.operation_failure.v1"; + +export interface CultNetOperationFailure { + code: string; + message: string; +} + +/** Correlated framework-level failure returned by a CultMesh operation provider. */ +export class CultMeshBrowserOperationError extends Error { + readonly status: string; + readonly code: string; + readonly diagnostics: readonly string[]; + + constructor(response: CultNetOperationResponseMessage, failure: CultNetOperationFailure) { + super(failure.message || "CultMesh operation failed."); + this.name = "CultMeshBrowserOperationError"; + this.status = response.status || "error"; + this.code = failure.code || "operation-error"; + this.diagnostics = response.diagnostics ?? []; + } +} + export type CultMeshConnectionState = "connecting" | "connected" | "reconnecting" | "disposed"; type DocumentWatcher = (record: CultNetRawDocumentRecord | undefined) => void; @@ -554,6 +577,19 @@ export class CultMeshBrowserClient implements AsyncDisposable { if (!pending) return; this.#pendingOperations.delete(message.messageId); clearTimeout(pending.timer); + if (message.payloadSchema === cultNetOperationFailureSchema) { + try { + pending.reject(new CultMeshBrowserOperationError( + message, + decodeCultNetOperationPayload(message), + )); + } catch (error) { + pending.reject(error instanceof Error + ? error + : new Error("CultMesh operation failure payload was malformed.")); + } + return; + } pending.resolve(message); return; } diff --git a/packages/cultmesh-browser/test/cultmesh-browser.test.ts b/packages/cultmesh-browser/test/cultmesh-browser.test.ts index b05b184b..23f6f5a6 100644 --- a/packages/cultmesh-browser/test/cultmesh-browser.test.ts +++ b/packages/cultmesh-browser/test/cultmesh-browser.test.ts @@ -13,6 +13,7 @@ import { import { CultMeshBrowserClient, + CultMeshBrowserOperationError, CultMeshBrowserOdinRendezvous, decodeCultNetOperationPayload, decodeCultNetPayload, @@ -142,6 +143,35 @@ test("browser client bounds unanswered provider operations", async () => { await client.dispose(); }); +test("browser client rejects a correlated framework failure without waiting for timeout", async () => { + const provider = new FakeProvider("ws://127.0.0.1:4351/mesh", 1, true); + const client = await CultMeshBrowserClient.connect({ + ...provider.route, + runtimeId: "browser-failure-test", + rendezvous: { resolve: async () => provider.route }, + requestTimeoutMs: 60_000, + socketFactory: () => provider.open(), + }); + + await assert.rejects( + client.invoke({ + serviceId: "sample.counter", + operation: "increment", + payloadSchema: "wrong.request.v1", + payload: { amount: 1 }, + idempotencyKey: "failure-1", + }), + (error: unknown) => { + assert.ok(error instanceof CultMeshBrowserOperationError); + assert.equal(error.status, "invalid"); + assert.equal(error.code, "request-schema-mismatch"); + assert.match(error.message, /expected payload schema/i); + return true; + }, + ); + await client.dispose(); +}); + test("browser client rejects oversized outbound schema messages", async () => { const route = { verseId: "sample.counter", @@ -189,8 +219,9 @@ class FakeProvider { readonly route: CultMeshBrowserRoute; #count: number; #subscriptions = new Map>(); + #rejectOperations: boolean; - constructor(endpoint: string, count: number) { + constructor(endpoint: string, count: number, rejectOperations = false) { this.route = { verseId: "sample.counter", providerId: "sample.counter-provider", @@ -198,6 +229,7 @@ class FakeProvider { generation: endpoint, }; this.#count = count; + this.#rejectOperations = rejectOperations; } get activeSubscriptionCount(): number { @@ -242,6 +274,24 @@ class FakeProvider { } private invoke(socket: FakeSocket, message: CultNetOperationRequestMessage): void { + if (this.#rejectOperations) { + socket.deliver({ + schemaVersion: "cultnet.operation_response.v0", + messageId: message.messageId, + serviceId: message.serviceId, + operation: message.operation, + status: "invalid", + payloadSchema: "gamecult.cultnet.operation_failure.v1", + payloadEncoding: "messagepack-base64", + payload: bytesToBase64(encode({ + code: "request-schema-mismatch", + message: "Expected payload schema 'sample.increment.v1'.", + })), + diagnostics: ["Request schema did not match."], + sourceRuntimeId: "sample.counter-provider", + }); + return; + } const payload = decode(base64ToBytes(message.payload)) as { amount: number }; this.#count += payload.amount; for (const [peer, subscriptions] of this.#subscriptions) { diff --git a/samples/eve-browser-network/Program.cs b/samples/eve-browser-network/Program.cs index 5b8e132f..82c09c19 100644 --- a/samples/eve-browser-network/Program.cs +++ b/samples/eve-browser-network/Program.cs @@ -95,61 +95,50 @@ static async Task RunProviderAsync(Args arguments) await using var schemaServer = new CultNetWebSocketSchemaServer(); using var subscriptions = new CultNetDatabaseSubscriptionServer(schemaServer, database); - var operationGate = new SemaphoreSlim(1, 1); - schemaServer.OnCultNet(async (request, peer) => - { - if (request.ServiceId != "sample.counter") - { - peer.SendCultNet(new CultNetErrorMessage { Error = "Unsupported sample operation." }); - return; - } - if (request.Operation == "sample.counter.ping") - { - var ping = MessagePackSerializer.Deserialize( - Convert.FromBase64String(request.Payload), - CultNetSchemaMessageSerialization.Options); - SendOperationResponse( - peer, - request, - "sample.ping_receipt.v1", - new PingReceipt { Sequence = ping.Sequence }); - return; - } - if (request.Operation != "sample.counter.increment") - { - peer.SendCultNet(new CultNetErrorMessage { Error = "Unsupported sample operation." }); - return; - } - await operationGate.WaitAsync(); - try - { - var current = cache.Get(new CultRecordKey(counterKey)) - ?? throw new InvalidOperationException("Counter state is unavailable."); - if (!current.Receipts.TryGetValue(request.MessageId, out var receipt)) + using var operationGate = new SemaphoreSlim(1, 1); + using var operations = new CultNetOperationServer(schemaServer, "sample.counter-provider") + .Register( + "sample.counter", + "sample.counter.ping", + "sample.ping_request.v1", + "sample.ping_receipt.v1", + context => Task.FromResult(new PingReceipt { Sequence = context.Value.Sequence })) + .Register( + "sample.counter", + "sample.counter.increment", + "sample.increment.v1", + "gamecult.eve.command_receipt.v1", + async context => { - var input = MessagePackSerializer.Deserialize( - Convert.FromBase64String(request.Payload), - CultNetSchemaMessageSerialization.Options); - receipt = IncrementReceipt.Accepted(request.MessageId, current.Count + input.Amount); - var receipts = new Dictionary(current.Receipts, StringComparer.Ordinal) + await operationGate.WaitAsync(); + try { - [request.MessageId] = receipt - }; - await database.PutAsync(new CultRecordKey(counterKey), new CounterState + var current = cache.Get(new CultRecordKey(counterKey)) + ?? throw new InvalidOperationException("Counter state is unavailable."); + if (current.Receipts.TryGetValue(context.IdempotencyKey, out var existing)) + return existing; + + var receipt = IncrementReceipt.Accepted( + context.IdempotencyKey, + current.Count + context.Value.Amount); + var receipts = new Dictionary(current.Receipts, StringComparer.Ordinal) + { + [context.IdempotencyKey] = receipt + }; + await database.PutAsync(new CultRecordKey(counterKey), new CounterState + { + CounterId = counterKey, + Count = receipt.Count, + Receipts = receipts + }); + await cache.FlushAsync(); + return receipt; + } + finally { - CounterId = counterKey, - Count = receipt.Count, - Receipts = receipts - }); - await cache.FlushAsync(); - } - SendOperationResponse(peer, request, "gamecult.eve.command_receipt.v1", receipt); - } - finally - { - operationGate.Release(); - } - }); + operationGate.Release(); + } + }); var builder = WebApplication.CreateSlimBuilder(); builder.WebHost.ConfigureKestrel(options => options.Listen(IPAddress.Loopback, arguments.Port)); @@ -245,26 +234,6 @@ static async Task RunHeadlessAsync(Args arguments) await Task.WhenAll(completion.Task, commandTask).WaitAsync(TimeSpan.FromSeconds(45)); } -static void SendOperationResponse( - ICultNetSchemaServerPeer peer, - CultNetOperationRequestMessage request, - string payloadSchema, - T payload) -{ - peer.SendCultNet(new CultNetOperationResponseMessage - { - MessageId = request.MessageId, - ServiceId = request.ServiceId, - Operation = request.Operation, - Status = "accepted", - PayloadSchema = payloadSchema, - Payload = Convert.ToBase64String(MessagePackSerializer.Serialize( - payload, - CultNetSchemaMessageSerialization.Options)), - SourceRuntimeId = "sample.counter-provider" - }); -} - static async Task MeasureOperationSessionAsync(CultMeshClient mesh, Args arguments) { const int warmupOperations = 100; @@ -337,54 +306,27 @@ static void ForceCollection() static EveSurfaceDocument CreateCounterSurface() { var networkRoute = new CultMeshRouteHint(CultMeshLocalityKind.Network, "cultmesh"); - return new EveSurfaceDocument( - providerId: "sample.counter-provider", - providerKind: "sample.daemon", - title: "CultMesh browser counter", - version: 1, - updatedAtUtc: "2026-08-17T00:00:00Z", - surface: new EveSurfaceTree( - surfaceKey, - new EveSurfaceComponent( - "counter.root", - "column", - new Dictionary(StringComparer.Ordinal), - [ - new EveSurfaceComponent( - "counter.value", - "metric", - new Dictionary(StringComparer.Ordinal) - { - ["label"] = "Canonical count", - ["value"] = "0" - }, - [], - [ - new CultMeshStateBindingDescriptor( - "value", - "sample.counter.count", - "sample.counter_state:counter:main", - "sample.counter_state.v1", - networkRoute) - ]), - new EveSurfaceComponent( - "counter.increment", - "control.button", - new Dictionary(StringComparer.Ordinal) - { - ["label"] = "Increment", - ["command"] = "sample.counter.increment" - }, - []) - ]), - []), - commands: - [ - new EveCommandTemplate(new CultMeshOperationBindingDescriptor( - "sample.counter.increment", - "Increment", - routeHint: networkRoute)) - ]); + var count = new CultMeshStateBindingDescriptor( + "value", + "sample.counter.count", + "sample.counter_state:counter:main", + "sample.counter_state.v1", + networkRoute); + var increment = CultMesh.OperationBinding( + "sample.counter.increment", + "Increment", + "sample.increment.v1", + networkRoute); + return EveSurface.Create(surfaceKey) + .Provider("sample.counter-provider", "sample.daemon") + .Title("CultMesh browser counter") + .Version(1) + .UpdatedAtUtc("2026-08-17T00:00:00Z") + .RootColumn("counter.root", root => root + .Title("counter.title", "CultMesh browser counter") + .Metric("counter.value", "Canonical count", "0", count) + .Button("counter.increment", "Increment", increment)) + .Build(); } sealed class Args diff --git a/samples/eve-browser-network/README.md b/samples/eve-browser-network/README.md index c039cd42..bbcc95ca 100644 --- a/samples/eve-browser-network/README.md +++ b/samples/eve-browser-network/README.md @@ -15,6 +15,12 @@ This is the real-process continuation of `samples/eve-two-runtime`: - the browser and C# clients speak the same binary CultNet schema-v0 WebSocket messages through the authenticated host adapter. +The provider registers typed commands through `CultNetOperationServer`. +Application code receives `CultNetOperationContext` and returns a +typed receipt; it does not parse base64, switch on wire envelopes, or construct +correlation responses. The counter's durable transaction still owns +idempotency and state mutation. + Run the proof from the CultLib repository: ```powershell diff --git a/scripts/verify-eve-getting-started.ps1 b/scripts/verify-eve-getting-started.ps1 index 57dd0a61..be49aafe 100644 --- a/scripts/verify-eve-getting-started.ps1 +++ b/scripts/verify-eve-getting-started.ps1 @@ -6,6 +6,17 @@ param( $ErrorActionPreference = "Stop" $cultLibRoot = Split-Path -Parent $PSScriptRoot $EveRoot = [IO.Path]::GetFullPath($EveRoot) +$networkSample = Join-Path $cultLibRoot "samples\eve-browser-network\Program.cs" +$networkSampleSource = Get-Content -LiteralPath $networkSample -Raw +if ($networkSampleSource -match 'OnCultNet\s*<\s*CultNetOperationRequestMessage' -or + $networkSampleSource -match 'Convert\.FromBase64String\s*\(\s*request\.Payload') { + throw "The getting-started provider has regressed to hand-written CultNet operation envelope dispatch." +} +foreach ($requiredPrimitive in @("CultNetOperationServer", "EveSurface.Create")) { + if ($networkSampleSource -notmatch [regex]::Escape($requiredPrimitive)) { + throw "The getting-started provider is missing the public primitive '$requiredPrimitive'." + } +} & (Join-Path $PSScriptRoot "verify-eve-two-runtime-sample.ps1") ` -EveRoot $EveRoot ` diff --git a/src/GameCult.Mesh/CultMeshClient.cs b/src/GameCult.Mesh/CultMeshClient.cs index 970e0f2f..1d33c3ec 100644 --- a/src/GameCult.Mesh/CultMeshClient.cs +++ b/src/GameCult.Mesh/CultMeshClient.cs @@ -82,6 +82,29 @@ namespace GameCult.Mesh public TResponse Value { get; } } + /// Correlated framework-level failure returned before a typed domain reply exists. + public sealed class CultMeshRemoteOperationException : Exception + { + internal CultMeshRemoteOperationException( + CultNetOperationResponseMessage envelope, + CultNetOperationFailure failure) + : base(failure?.Message ?? "CultMesh operation failed.") + { + Status = envelope?.Status ?? "error"; + Code = failure?.Code ?? "operation-error"; + Diagnostics = envelope?.Diagnostics ?? Array.Empty(); + } + + /// Gets the provider-authored failure status. + public string Status { get; } + + /// Gets the stable machine-readable failure code. + public string Code { get; } + + /// Gets provider diagnostics carried by the response. + public IReadOnlyList Diagnostics { get; } + } + /// Owns one shared live document subscription until disposed. public sealed class CultMeshDocumentLease : IDisposable where TDocument : class { @@ -408,6 +431,24 @@ namespace GameCult.Mesh if (!string.Equals(envelope.ServiceId, expectedService, StringComparison.Ordinal) || !string.Equals(envelope.Operation, expectedOperation, StringComparison.Ordinal)) throw new InvalidOperationException("CultMesh operation response did not match the requested service and operation."); + if (string.Equals(envelope.PayloadSchema, CultNetOperationServer.FailureSchemaId, StringComparison.Ordinal)) + { + if (!string.Equals(envelope.PayloadEncoding, "messagepack-base64", StringComparison.Ordinal)) + throw new InvalidOperationException( + $"CultMesh operation failure returned unsupported payload encoding '{envelope.PayloadEncoding}'."); + CultNetOperationFailure failure; + try + { + failure = MessagePackSerializer.Deserialize( + Convert.FromBase64String(envelope.Payload), + CultNetSchemaMessageSerialization.Options); + } + catch (Exception error) when (error is FormatException || error is MessagePackSerializationException) + { + throw new InvalidOperationException("CultMesh operation failure payload was malformed.", error); + } + throw new CultMeshRemoteOperationException(envelope, failure); + } if (!string.Equals(envelope.PayloadSchema, expectedResponseSchema, StringComparison.Ordinal)) throw new InvalidOperationException( $"CultMesh operation returned payload schema '{envelope.PayloadSchema}', expected '{expectedResponseSchema}'."); diff --git a/src/GameCult.Mesh/README.md b/src/GameCult.Mesh/README.md index 6b9be603..b0ff9e06 100644 --- a/src/GameCult.Mesh/README.md +++ b/src/GameCult.Mesh/README.md @@ -34,13 +34,17 @@ wire, see [docs/typed-document-path.md](docs/typed-document-path.md). ## Eve / CultUI Surfaces -CultMesh includes the portable Eve/CultUI surface document contract and a fluent -builder for daemon-published UI. The builder is deliberately shaped like the -legacy CultUI/Unity properties panel API: compose menus and forms in readable -imperative code, while the emitted document carries typed CultMesh operation -bindings, state bindings, style tokens, and embedded surface slots. +CultMesh supplies the typed state and operation binding descriptors used by Eve. +The renderer-neutral `GameCult.Eve.Surface` package in the Eve repository owns +the portable surface document and fluent builder. Add that package when a daemon +publishes UI; do not add EveUnity to the provider. The emitted document carries +typed CultMesh operation bindings, state bindings, style tokens, and embedded +surface slots while remaining independent of any lowering runtime. ```csharp +using GameCult.Eve.Surface; +using GameCult.Mesh; + var menu = EveSurface.Create("aetheria.main_menu.root") .Provider("aetheria", "game.menu") .TitleSubtitle("AETHERIA", "TERMINUS") diff --git a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md index a9126cd7..a910cf97 100644 --- a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md +++ b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md @@ -29,6 +29,58 @@ CultMesh document session. Other runtime lowerers must preserve the same boundary: they may reject or report unsupported capabilities, but they may not import provider internals. +## The Application-Owned Part + +Install the renderer-neutral `GameCult.Eve.Surface` package in the provider. +Do not install EveUnity or the browser lowerer there. A provider defines typed +state, one typed operation transaction, and one Eve surface. CultNet envelope +encoding is framework work: + +```csharp +using GameCult.Eve.Surface; +using GameCult.Mesh; +using GameCult.Networking; + +using var operations = new CultNetOperationServer(schemaServer, "sample.counter-provider") + .Register( + "sample.counter", + "sample.counter.increment", + "sample.increment.v1", + "gamecult.eve.command_receipt.v1", + async command => await IncrementExactlyOnceAsync( + command.IdempotencyKey, + command.Value)); + +var route = new CultMeshRouteHint(CultMeshLocalityKind.Network, "cultmesh"); +var count = new CultMeshStateBindingDescriptor( + "value", + "sample.counter.count", + "sample.counter_state:counter:main", + "sample.counter_state.v1", + route); +var increment = CultMesh.OperationBinding( + "sample.counter.increment", + "Increment", + "sample.increment.v1", + route); + +var surface = EveSurface.Create("sample.counter") + .Provider("sample.counter-provider", "sample.daemon") + .Title("CultMesh browser counter") + .RootColumn("counter.root", root => root + .Metric("counter.value", "Canonical count", "0", count) + .Button("counter.increment", "Increment", increment)) + .Build(); +``` + +`schemaServer` is a transport-neutral CultNet server port. WebSocket, RUDP, and +test transports attach the same dispatcher. The handler owns validation, +idempotency, state mutation, and its durable receipt. `CultNetOperationServer` +owns only route/schema checks and typed envelope serialization. The complete +provider transaction is in +[`samples/eve-browser-network/Program.cs`](../../../../samples/eve-browser-network/Program.cs); +it contains no hand-written operation base64 or MessagePack dispatch switch. + ## Multi-Runtime Checkpoint Run the same provider and connect at least two lowerers. Both must report the diff --git a/src/GameCult.Networking/CultNetOperationServer.cs b/src/GameCult.Networking/CultNetOperationServer.cs new file mode 100644 index 00000000..6261328e --- /dev/null +++ b/src/GameCult.Networking/CultNetOperationServer.cs @@ -0,0 +1,348 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using MessagePack; + +namespace GameCult.Networking +{ + /// Portable failure payload for operation routing and envelope validation. + [MessagePackObject] + public sealed class CultNetOperationFailure + { + /// Gets or sets the stable machine-readable failure code. + [Key("code")] public string Code { get; set; } = "operation-error"; + + /// Gets or sets the human-readable failure description. + [Key("message")] public string Message { get; set; } = "CultNet operation failed."; + } + + /// + /// Typed application input delivered through one CultNet operation envelope. + /// The message id is the caller's idempotency key; the application transaction + /// remains responsible for applying it exactly once. + /// + public sealed class CultNetOperationContext + { + internal CultNetOperationContext(CultNetOperationRequestMessage envelope, TRequest value) + { + Envelope = envelope ?? throw new ArgumentNullException(nameof(envelope)); + Value = value; + } + + /// Gets the decoded application request. + public TRequest Value { get; } + + /// Gets the durable caller-supplied idempotency key. + public string IdempotencyKey => Envelope.MessageId; + + /// Gets the calling runtime identity, when supplied. + public string? SourceRuntimeId => Envelope.SourceRuntimeId; + + /// Gets the optional target runtime identity. + public string? TargetRuntimeId => Envelope.TargetRuntimeId; + + /// Gets the original transport-neutral envelope for diagnostics. + public CultNetOperationRequestMessage Envelope { get; } + } + + /// Provider-authored typed result for one CultNet operation. + public sealed class CultNetOperationReply + { + /// Creates one provider-authored typed reply. + public CultNetOperationReply( + string status, + TResponse value, + IEnumerable? diagnostics = null) + { + Status = RequireNonEmpty(status, nameof(status)); + Value = value; + Diagnostics = diagnostics == null ? Array.Empty() : new List(diagnostics).ToArray(); + } + + /// Gets the provider-authored operation status. + public string Status { get; } + + /// Gets the typed response payload. + public TResponse Value { get; } + + /// Gets provider-authored diagnostics. + public IReadOnlyList Diagnostics { get; } + + /// Creates an accepted typed reply. + public static CultNetOperationReply Accepted(TResponse value) => new("accepted", value); + + /// Creates a rejected typed reply whose payload remains schema-valid. + public static CultNetOperationReply Rejected( + TResponse value, + params string[] diagnostics) => new("rejected", value, diagnostics); + + private static string RequireNonEmpty(string value, string paramName) => + string.IsNullOrWhiteSpace(value) + ? throw new ArgumentException("Value must be non-empty.", paramName) + : value.Trim(); + } + + /// + /// Transport-neutral typed dispatcher for CultNet application operations. + /// It owns envelope validation and serialization only; registered handlers own + /// domain validation, idempotency, state mutation, and durable receipts. + /// + public sealed class CultNetOperationServer : IDisposable + { + /// Schema used by correlated framework-level operation failures. + public const string FailureSchemaId = "gamecult.cultnet.operation_failure.v1"; + + private const string PayloadEncoding = "messagepack-base64"; + private readonly ICultNetSchemaServer _server; + private readonly string? _sourceRuntimeId; + private readonly Dictionary _bindings = new(); + private readonly Func _handler; + private bool _disposed; + + /// Attaches one typed operation dispatcher to a schema server. + public CultNetOperationServer(ICultNetSchemaServer server, string? sourceRuntimeId = null) + { + _server = server ?? throw new ArgumentNullException(nameof(server)); + _sourceRuntimeId = string.IsNullOrWhiteSpace(sourceRuntimeId) ? null : sourceRuntimeId!.Trim(); + _handler = HandleAsync; + _server.OnCultNet(_handler); + } + + /// + /// Registers one typed operation. Duplicate service/operation routes are rejected. + /// + public CultNetOperationServer Register( + string serviceId, + string operation, + string requestSchema, + string responseSchema, + Func, Task>> handler) + { + ThrowIfDisposed(); + var route = new Route(serviceId, operation); + if (_bindings.ContainsKey(route)) + throw new InvalidOperationException($"CultNet operation '{route}' is already registered."); + _bindings.Add(route, new Binding( + route, + requestSchema, + responseSchema, + handler ?? throw new ArgumentNullException(nameof(handler)), + _sourceRuntimeId)); + return this; + } + + /// + /// Registers one typed operation whose successful handler result is always accepted. + /// + public CultNetOperationServer Register( + string serviceId, + string operation, + string requestSchema, + string responseSchema, + Func, Task> handler) + { + if (handler == null) throw new ArgumentNullException(nameof(handler)); + return Register( + serviceId, + operation, + requestSchema, + responseSchema, + async context => CultNetOperationReply.Accepted(await handler(context).ConfigureAwait(false))); + } + + /// + public void Dispose() + { + if (_disposed) return; + _disposed = true; + _server.RemoveCultNetMessageListener(_handler); + _bindings.Clear(); + } + + private async Task HandleAsync(CultNetOperationRequestMessage request, ICultNetSchemaServerPeer peer) + { + if (_disposed) return; + if (request == null) throw new ArgumentNullException(nameof(request)); + if (peer == null) throw new ArgumentNullException(nameof(peer)); + + Route route; + try + { + route = new Route(request.ServiceId, request.Operation); + } + catch (ArgumentException error) + { + peer.SendCultNet(Failure(request, "invalid", "invalid-route", error.Message)); + return; + } + + if (!_bindings.TryGetValue(route, out var binding)) + { + peer.SendCultNet(Failure( + request, + "unsupported", + "operation-not-registered", + $"CultNet operation '{route}' is not registered.")); + return; + } + + try + { + peer.SendCultNet(await binding.InvokeAsync(request).ConfigureAwait(false)); + } + catch (RequestException error) + { + peer.SendCultNet(Failure(request, "invalid", error.Code, error.Message)); + } + catch (Exception error) + { + peer.SendCultNet(Failure( + request, + "error", + "handler-failed", + $"CultNet operation '{route}' failed: {error.Message}")); + } + } + + private CultNetOperationResponseMessage Failure( + CultNetOperationRequestMessage request, + string status, + string code, + string message) + { + return new CultNetOperationResponseMessage + { + MessageId = request.MessageId ?? "", + ServiceId = request.ServiceId ?? "", + Operation = request.Operation ?? "", + Status = status, + PayloadSchema = FailureSchemaId, + PayloadEncoding = PayloadEncoding, + Payload = Convert.ToBase64String(MessagePackSerializer.Serialize( + new CultNetOperationFailure { Code = code, Message = message }, + CultNetSchemaMessageSerialization.Options)), + Diagnostics = new[] { message }, + SourceRuntimeId = _sourceRuntimeId + }; + } + + private void ThrowIfDisposed() + { + if (_disposed) throw new ObjectDisposedException(nameof(CultNetOperationServer)); + } + + private interface IBinding + { + Task InvokeAsync(CultNetOperationRequestMessage request); + } + + private sealed class Binding : IBinding + { + private readonly Route _route; + private readonly string _requestSchema; + private readonly string _responseSchema; + private readonly Func, Task>> _handler; + private readonly string? _sourceRuntimeId; + + public Binding( + Route route, + string requestSchema, + string responseSchema, + Func, Task>> handler, + string? sourceRuntimeId) + { + _route = route; + _requestSchema = RequireNonEmpty(requestSchema, nameof(requestSchema)); + _responseSchema = RequireNonEmpty(responseSchema, nameof(responseSchema)); + _handler = handler; + _sourceRuntimeId = sourceRuntimeId; + } + + public async Task InvokeAsync(CultNetOperationRequestMessage request) + { + if (string.IsNullOrWhiteSpace(request.MessageId)) + throw new RequestException("missing-idempotency-key", "CultNet operation omitted its idempotency key."); + if (!string.Equals(request.PayloadSchema, _requestSchema, StringComparison.Ordinal)) + throw new RequestException( + "request-schema-mismatch", + $"CultNet operation '{_route}' expected payload schema '{_requestSchema}', got '{request.PayloadSchema}'."); + if (!string.Equals(request.PayloadEncoding, PayloadEncoding, StringComparison.Ordinal)) + throw new RequestException( + "request-encoding-mismatch", + $"CultNet operation '{_route}' expected payload encoding '{PayloadEncoding}', got '{request.PayloadEncoding}'."); + + TRequest value; + try + { + value = MessagePackSerializer.Deserialize( + Convert.FromBase64String(request.Payload), + CultNetSchemaMessageSerialization.Options); + } + catch (FormatException error) + { + throw new RequestException("request-payload-invalid", "CultNet operation payload was not valid base64.", error); + } + catch (MessagePackSerializationException error) + { + throw new RequestException("request-payload-invalid", "CultNet operation payload was not valid MessagePack.", error); + } + if (value == null) throw new RequestException("request-payload-null", "CultNet operation payload decoded to null."); + + var reply = await _handler(new CultNetOperationContext(request, value)).ConfigureAwait(false) + ?? throw new InvalidOperationException("CultNet operation handler returned no reply."); + if (reply.Value == null) throw new InvalidOperationException("CultNet operation handler returned a null payload."); + return new CultNetOperationResponseMessage + { + MessageId = request.MessageId, + ServiceId = _route.ServiceId, + Operation = _route.Operation, + Status = reply.Status, + PayloadSchema = _responseSchema, + PayloadEncoding = PayloadEncoding, + Payload = Convert.ToBase64String(MessagePackSerializer.Serialize( + reply.Value, + CultNetSchemaMessageSerialization.Options)), + Diagnostics = new List(reply.Diagnostics).ToArray(), + SourceRuntimeId = _sourceRuntimeId + }; + } + } + + private sealed class RequestException : Exception + { + public RequestException(string code, string message, Exception? inner = null) + : base(message, inner) + { + Code = code; + } + + public string Code { get; } + } + + private readonly struct Route : IEquatable + { + public Route(string serviceId, string operation) + { + ServiceId = RequireNonEmpty(serviceId, nameof(serviceId)); + Operation = RequireNonEmpty(operation, nameof(operation)); + } + + public string ServiceId { get; } + public string Operation { get; } + + public bool Equals(Route other) => + string.Equals(ServiceId, other.ServiceId, StringComparison.Ordinal) && + string.Equals(Operation, other.Operation, StringComparison.Ordinal); + + public override bool Equals(object? value) => value is Route route && Equals(route); + public override int GetHashCode() => + (StringComparer.Ordinal.GetHashCode(ServiceId) * 397) ^ StringComparer.Ordinal.GetHashCode(Operation); + public override string ToString() => ServiceId + "/" + Operation; + } + + private static string RequireNonEmpty(string value, string paramName) => + string.IsNullOrWhiteSpace(value) + ? throw new ArgumentException("Value must be non-empty.", paramName) + : value.Trim(); + } +} diff --git a/src/GameCult.Networking/README.md b/src/GameCult.Networking/README.md index cf463e72..de8496d3 100644 --- a/src/GameCult.Networking/README.md +++ b/src/GameCult.Networking/README.md @@ -390,6 +390,33 @@ peer lookup and handshake before returning the same RUDP transport. Packet semantics, schema-channel send/receive helpers, and reconnect state still live in `GameCult.Networking`. +## Typed Operations + +`CultNetOperationServer` attaches typed application handlers to any +`ICultNetSchemaServer`. It owns route/schema validation, MessagePack envelope +encoding, correlation, and framework failure replies. The application handler +owns domain validation, state mutation, idempotency, and durable receipts: + +```csharp +using var operations = new CultNetOperationServer(schemaServer, "counter.provider") + .Register( + "counter", + "counter.increment", + "counter.increment_request.v1", + "counter.increment_receipt.v1", + command => IncrementExactlyOnceAsync( + command.IdempotencyKey, + command.Value)); +``` + +Returning `CultNetOperationReply.Rejected(...)` preserves a schema-valid +domain receipt and status. Unknown routes, malformed payloads, and schema +mismatches return the correlated `gamecult.cultnet.operation_failure.v1` +payload; `CultMeshClient.InvokeAsync` raises +`CultMeshRemoteOperationException` immediately instead of timing out. The +browser client raises the equivalent `CultMeshBrowserOperationError` with the +same status and failure code. + ## Browser WebSocket Host `GameCult.Networking.WebSockets` keeps ASP.NET Core hosting out of the diff --git a/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs b/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs index 10af2417..82934a54 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs @@ -288,6 +288,36 @@ public sealed class CultMeshClientTests .Which.SourceRuntimeId.Should().Be("pilot-one"); } + [Test] + public async Task InvokeOperation_ThrowsCorrelatedFrameworkFailureWithoutTimingOut() + { + var connector = new DocumentConnector { RejectOperations = true }; + using var mesh = new CultMeshClient(new CultMeshClientOptions + { + RendezvousEndpoints = new[] { "rudp://odin:3076" }, + Discovery = new CultMeshVerseDiscoveryClientOptions { CreateClient = () => new RendezvousClient() }, + Connectors = new[] { connector }, + OperationResponseTimeout = TimeSpan.FromSeconds(5) + }); + + Func invoke = async () => await mesh.InvokeAsync( + "aetheria", + "tests.counter", + "tests.counter.increment", + "wrong.request.v1", + "tests.counter.increment_receipt.v1", + new ClientOperationRequest { Amount = 2 }, + sourceRuntimeId: "pilot-one", + idempotencyKey: "pilot-command-invalid"); + + var failure = await invoke.Should().ThrowAsync(); + failure.Which.Status.Should().Be("invalid"); + failure.Which.Code.Should().Be("request-schema-mismatch"); + failure.Which.Message.Should().Contain("expected payload schema"); + connector.Clients.Should().ContainSingle(); + connector.Clients[0].Operations.Should().ContainSingle(); + } + [Test] public async Task Dispose_TerminatesDocumentWaitingForInitialSnapshot() { @@ -369,6 +399,7 @@ public sealed class CultMeshClientTests public List Clients { get; } = new(); public bool SuppressFirstSnapshot { get; set; } public bool SuppressFirstSubscriptionSnapshot { get; set; } + public bool RejectOperations { get; set; } public string ConnectorId => "document-test"; public int Priority => 0; public int SubscribeCount => Clients.Sum(client => client.SubscribeCount); @@ -382,7 +413,8 @@ public sealed class CultMeshClientTests "pilot surface " + (Clients.Count + 1), snapshotsToSuppress: SuppressFirstSnapshot && Clients.Count == 0 ? int.MaxValue - : SuppressFirstSubscriptionSnapshot && Clients.Count == 0 ? 1 : 0); + : SuppressFirstSubscriptionSnapshot && Clients.Count == 0 ? 1 : 0, + rejectOperations: RejectOperations); Clients.Add(client); return Task.FromResult(client); } @@ -395,11 +427,13 @@ public sealed class CultMeshClientTests private readonly CultNetDocumentRegistry _documents; private readonly string _text; private readonly TaskCompletionSource _failure = new(TaskCreationOptions.RunContinuationsAsynchronously); + private readonly bool _rejectOperations; private int _snapshotsToSuppress; - public DocumentClient(string text, int snapshotsToSuppress = 0) + public DocumentClient(string text, int snapshotsToSuppress = 0, bool rejectOperations = false) { _text = text; _snapshotsToSuppress = snapshotsToSuppress; + _rejectOperations = rejectOperations; var cache = CultMesh.CreateCultCacheDocumentRegistry(typeof(ClientTestDocument)); _documents = CultMesh.CreateCultNetDocumentRegistry(new[] { typeof(ClientTestDocument) }, cache); } @@ -420,6 +454,29 @@ public sealed class CultMeshClientTests if (message is CultNetOperationRequestMessage operation) { Operations.Add(operation); + if (_rejectOperations) + { + var failure = new CultNetOperationFailure + { + Code = "request-schema-mismatch", + Message = "CultNet operation expected payload schema tests.counter.increment_request.v1." + }; + var rejected = new CultNetOperationResponseMessage + { + MessageId = operation.MessageId, + ServiceId = operation.ServiceId, + Operation = operation.Operation, + Status = "invalid", + PayloadSchema = CultNetOperationServer.FailureSchemaId, + Payload = Convert.ToBase64String(MessagePackSerializer.Serialize( + failure, + CultNetSchemaMessageSerialization.Options)), + Diagnostics = new[] { failure.Message }, + SourceRuntimeId = "provider-daemon" + }; + foreach (var handler in _operationResponses.ToArray()) handler(rejected); + return; + } var decodedRequest = MessagePackSerializer.Deserialize( Convert.FromBase64String(operation.Payload), CultNetSchemaMessageSerialization.Options); diff --git a/tests/GameCult.Networking.Tests/CultNetOperationServerTests.cs b/tests/GameCult.Networking.Tests/CultNetOperationServerTests.cs new file mode 100644 index 00000000..f82456fb --- /dev/null +++ b/tests/GameCult.Networking.Tests/CultNetOperationServerTests.cs @@ -0,0 +1,205 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using MessagePack; +using NUnit.Framework; + +namespace GameCult.Networking.Tests +{ + [TestFixture] + public sealed class CultNetOperationServerTests + { + [Test] + public async Task DispatchesTypedRequestAndCorrelatedReplyWithoutEnvelopePlumbing() + { + var transport = new FakeServer(); + var peer = new FakePeer(); + CultNetOperationContext? observed = null; + using var operations = new CultNetOperationServer(transport, "sample.provider") + .Register( + "sample.counter", + "sample.counter.add", + "sample.add.v1", + "sample.add_receipt.v1", + context => + { + observed = context; + return Task.FromResult(new AddReceipt { Count = context.Value.Amount + 4 }); + }); + + await transport.DispatchAsync(Request(new AddRequest { Amount = 3 }), peer); + + var response = peer.Messages.OfType().Single(); + var receipt = MessagePackSerializer.Deserialize( + Convert.FromBase64String(response.Payload), + CultNetSchemaMessageSerialization.Options); + Assert.Multiple(() => + { + Assert.That(observed!.Value.Amount, Is.EqualTo(3)); + Assert.That(observed.IdempotencyKey, Is.EqualTo("command-7")); + Assert.That(observed.SourceRuntimeId, Is.EqualTo("sample.browser")); + Assert.That(response.MessageId, Is.EqualTo("command-7")); + Assert.That(response.ServiceId, Is.EqualTo("sample.counter")); + Assert.That(response.Operation, Is.EqualTo("sample.counter.add")); + Assert.That(response.Status, Is.EqualTo("accepted")); + Assert.That(response.PayloadSchema, Is.EqualTo("sample.add_receipt.v1")); + Assert.That(response.SourceRuntimeId, Is.EqualTo("sample.provider")); + Assert.That(receipt.Count, Is.EqualTo(7)); + }); + } + + [Test] + public async Task PreservesTypedRejectionAndDiagnostics() + { + var transport = new FakeServer(); + var peer = new FakePeer(); + using var operations = new CultNetOperationServer(transport) + .Register( + "sample.counter", + "sample.counter.add", + "sample.add.v1", + "sample.add_receipt.v1", + _ => Task.FromResult(CultNetOperationReply.Rejected( + new AddReceipt { Count = 4 }, + "counter is locked"))); + + await transport.DispatchAsync(Request(new AddRequest { Amount = 3 }), peer); + + var response = peer.Messages.OfType().Single(); + Assert.That(response.Status, Is.EqualTo("rejected")); + Assert.That(response.Diagnostics, Is.EqualTo(new[] { "counter is locked" })); + Assert.That( + MessagePackSerializer.Deserialize( + Convert.FromBase64String(response.Payload), + CultNetSchemaMessageSerialization.Options).Count, + Is.EqualTo(4)); + } + + [Test] + public async Task RejectsWrongSchemaBeforeApplicationHandler() + { + var transport = new FakeServer(); + var peer = new FakePeer(); + var calls = 0; + using var operations = new CultNetOperationServer(transport) + .Register( + "sample.counter", + "sample.counter.add", + "sample.add.v1", + "sample.add_receipt.v1", + context => + { + calls++; + return Task.FromResult(new AddReceipt { Count = context.Value.Amount }); + }); + var request = Request(new AddRequest { Amount = 3 }); + request.PayloadSchema = "wrong.v1"; + + await transport.DispatchAsync(request, peer); + + Assert.That(calls, Is.Zero); + var response = peer.Messages.OfType().Single(); + var failure = MessagePackSerializer.Deserialize( + Convert.FromBase64String(response.Payload), + CultNetSchemaMessageSerialization.Options); + Assert.Multiple(() => + { + Assert.That(response.MessageId, Is.EqualTo("command-7")); + Assert.That(response.Status, Is.EqualTo("invalid")); + Assert.That(response.PayloadSchema, Is.EqualTo(CultNetOperationServer.FailureSchemaId)); + Assert.That(failure.Code, Is.EqualTo("request-schema-mismatch")); + Assert.That(failure.Message, Does.Contain("expected payload schema 'sample.add.v1'")); + }); + } + + [Test] + public void RejectsDuplicateRouteAndDetachesOnDispose() + { + var transport = new FakeServer(); + var operations = new CultNetOperationServer(transport); + operations.Register( + "sample.counter", + "sample.counter.add", + "sample.add.v1", + "sample.add_receipt.v1", + context => Task.FromResult(new AddReceipt { Count = context.Value.Amount })); + + Assert.That(() => operations.Register( + "sample.counter", + "sample.counter.add", + "sample.add.v1", + "sample.add_receipt.v1", + context => Task.FromResult(new AddReceipt { Count = context.Value.Amount })), + Throws.InvalidOperationException); + Assert.That(transport.HasHandler(), Is.True); + + operations.Dispose(); + + Assert.That(transport.HasHandler(), Is.False); + Assert.That(() => operations.Register( + "sample.counter", + "sample.counter.add", + "sample.add.v1", + "sample.add_receipt.v1", + context => Task.FromResult(new AddReceipt { Count = context.Value.Amount })), + Throws.TypeOf()); + } + + private static CultNetOperationRequestMessage Request(AddRequest value) => new() + { + MessageId = "command-7", + ServiceId = "sample.counter", + Operation = "sample.counter.add", + PayloadSchema = "sample.add.v1", + PayloadEncoding = "messagepack-base64", + Payload = Convert.ToBase64String(MessagePackSerializer.Serialize( + value, + CultNetSchemaMessageSerialization.Options)), + SourceRuntimeId = "sample.browser" + }; + + [MessagePackObject] + public sealed class AddRequest + { + [Key(0)] public int Amount { get; set; } + } + + [MessagePackObject] + public sealed class AddReceipt + { + [Key(0)] public int Count { get; set; } + } + + private sealed class FakeServer : ICultNetSchemaServer + { + private readonly Dictionary _handlers = new(); + + public void OnCultNet(Func callback) + where TMessage : ICultNetSchemaMessage => _handlers[typeof(TMessage)] = callback; + + public void RemoveCultNetMessageListener(Delegate callback) + where TMessage : ICultNetSchemaMessage + { + if (_handlers.TryGetValue(typeof(TMessage), out var current) && current == callback) + _handlers.Remove(typeof(TMessage)); + } + + public bool HasHandler() where TMessage : ICultNetSchemaMessage => + _handlers.ContainsKey(typeof(TMessage)); + + public Task DispatchAsync(TMessage message, ICultNetSchemaServerPeer peer) + where TMessage : ICultNetSchemaMessage => + ((Func)_handlers[typeof(TMessage)])(message, peer); + } + + private sealed class FakePeer : ICultNetSchemaServerPeer + { + public List Messages { get; } = new(); + + public void SendCultNet(TMessage message) where TMessage : ICultNetSchemaMessage => + Messages.Add(message); + } + } +} From e74ba6e94c26c6b4ba13dbbfd320914aa498ea93 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 06:05:15 +0200 Subject: [PATCH 088/283] Make Eve onboarding one coherent game --- samples/eve-two-runtime/README.md | 11 +- src/GameCult.Mesh/README.md | 23 +++- .../docs/durable-node-quickstart.md | 8 +- .../getting-started/01-persist-typed-state.md | 71 ++++++++-- .../getting-started/02-connect-by-identity.md | 12 +- .../04-keep-a-typescript-provider-alive.md | 122 ------------------ .../04-run-the-multiruntime-game.md | 60 +++++++++ .../docs/getting-started/README.md | 4 +- src/GameCult.Mesh/docs/typed-document-path.md | 2 +- 9 files changed, 161 insertions(+), 152 deletions(-) delete mode 100644 src/GameCult.Mesh/docs/getting-started/04-keep-a-typescript-provider-alive.md create mode 100644 src/GameCult.Mesh/docs/getting-started/04-run-the-multiruntime-game.md diff --git a/samples/eve-two-runtime/README.md b/samples/eve-two-runtime/README.md index c149e14e..0981ad1a 100644 --- a/samples/eve-two-runtime/README.md +++ b/samples/eve-two-runtime/README.md @@ -29,8 +29,9 @@ temporary consumer, and runs `sample.mjs`. Success proves: 4. the DOM binding and a separate headless observer converge on the same count; 5. the canonical receipt and state survive reopening the `.cc` store. -This is not yet the promised networked multiplayer tutorial. The DOM lowerer is -hosted by jsdom in Node and both consumers share one local CultMesh node. A real -browser transport, Odin discovery, process separation, and a second language -runtime require distinct executable gates. Keeping that limitation visible is -part of the sample contract. +This artifact checkpoint is deliberately not the network proof. The DOM lowerer +is hosted by jsdom in Node and both consumers share one local CultMesh node. The +same wrapper continues into a separate real Chromium/C# process chronology with +Odin discovery, route replacement, and persistent provider state. Keeping those +evidence layers separate prevents a fast package test from impersonating the +network. diff --git a/src/GameCult.Mesh/README.md b/src/GameCult.Mesh/README.md index b0ff9e06..8acb6c9d 100644 --- a/src/GameCult.Mesh/README.md +++ b/src/GameCult.Mesh/README.md @@ -18,12 +18,25 @@ simulation observations. ## First Node ```csharp +using GameCult.Caching; using GameCult.Mesh; +using GameCult.Networking; -using var node = await CultMesh.StartNodeAsync("world.ccmp"); +// CounterState is the typed document defined in the getting-started tutorial. +var documents = new CultNetDocumentRegistry() + .Register(CultNetDocumentBinding.ForDocument()); +using var node = await CultMesh.StartNodeAsync("world.cc", new CultMeshNodeOptions +{ + DatabaseOptions = new CultNetDatabaseOptions + { + RuntimeId = "counter-provider", + DocumentRegistry = documents + } +}); -var player = await node.Database.GetAsync(playerKey); -await node.Database.PutAsync(playerKey, player); +var key = new CultRecordKey("counter:main"); +await node.Database.PutAsync(key, new CounterState { CounterId = key.Value }); +var counter = await node.Database.GetAsync(key); ``` If you want one inspectable path that starts with a durable local cache file and @@ -88,7 +101,7 @@ Enable durable authoritative shard logs when a node should serve replica catch-up after restart: ```csharp -using var node = await CultMesh.StartNodeAsync("world.ccmp", new CultMeshNodeOptions +using var node = await CultMesh.StartNodeAsync("world.cc", new CultMeshNodeOptions { EnableDurableShardLogs = true }); @@ -240,7 +253,7 @@ shape without local store plumbing: ```csharp var health = CultMesh.DocumentFromSingleFile( - "daemon-publication.ccmp", + "daemon-publication.cc", new CultRecordKey("daemon:aetheria.health.v1"), verse); diff --git a/src/GameCult.Mesh/docs/durable-node-quickstart.md b/src/GameCult.Mesh/docs/durable-node-quickstart.md index 3d08ae0f..f85fac97 100644 --- a/src/GameCult.Mesh/docs/durable-node-quickstart.md +++ b/src/GameCult.Mesh/docs/durable-node-quickstart.md @@ -55,7 +55,7 @@ var key = new CultRecordKey("note:intro"); var documents = new CultNetDocumentRegistry() .Register(CultNetDocumentBinding.ForDocument()); -using (var node = await CultMesh.CreateNodeAsync("world.ccmp", new CultMeshNodeOptions +using (var node = await CultMesh.CreateNodeAsync("world.cc", new CultMeshNodeOptions { DatabaseOptions = new CultNetDatabaseOptions { @@ -76,7 +76,7 @@ using (var node = await CultMesh.CreateNodeAsync("world.ccmp", new CultMeshNodeO await node.FlushAsync(); } -using (var reopened = await CultMesh.CreateNodeAsync("world.ccmp", new CultMeshNodeOptions +using (var reopened = await CultMesh.CreateNodeAsync("world.cc", new CultMeshNodeOptions { DatabaseOptions = new CultNetDatabaseOptions { @@ -92,7 +92,7 @@ using (var reopened = await CultMesh.CreateNodeAsync("world.ccmp", new CultMeshN What happened: -1. `CultMesh.CreateNodeAsync("world.ccmp", ...)` opened a durable CultCache +1. `CultMesh.CreateNodeAsync("world.cc", ...)` opened a durable CultCache snapshot file and wrapped it in a CultMesh node. 2. `node.Database.PutAsync(...)` wrote a typed document through the public CultMesh database surface. @@ -105,7 +105,7 @@ What happened: If you peel this path apart, the authority split stays simple: -- CultCache: `world.ccmp`, schema ids, record keys, typed document payloads, +- CultCache: `world.cc`, schema ids, record keys, typed document payloads, local indexes, flush/load - CultNet: `CultNetDocumentRegistry`, raw document puts/snapshots, subscriptions, shard routing, transport-facing replication diff --git a/src/GameCult.Mesh/docs/getting-started/01-persist-typed-state.md b/src/GameCult.Mesh/docs/getting-started/01-persist-typed-state.md index b2fce2a0..6e2d2b3b 100644 --- a/src/GameCult.Mesh/docs/getting-started/01-persist-typed-state.md +++ b/src/GameCult.Mesh/docs/getting-started/01-persist-typed-state.md @@ -1,22 +1,71 @@ -# 1. Persist Typed Application State +# 1. Persist The Counter -Start with a typed CultCache document and a durable CultMesh node. The complete -sample is [the durable node quickstart](../durable-node-quickstart.md). +The tutorial builds one application all the way through: a provider-owned +counter, an Increment operation, one browser lowerer, and one C# headless +client. Start with the state the provider actually owns. -At the end of that guide you should have: +```csharp +using GameCult.Caching; +using GameCult.Caching.MessagePack; +using GameCult.Networking; +using MessagePack; -- a document type with a stable schema id; -- a `CultMeshNode` whose database owns the live local document; -- a `.cc`/CultCache-backed durable state path; -- a restart proof that reads the same typed document. +[CultDocument("sample.counter_state", "sample.counter_state.v1")] +[MessagePackObject] +public sealed class CounterState +{ + [Key("counterId")] public string CounterId { get; set; } = ""; + [Key("count")] public int Count { get; set; } +} +``` -Do not create an Eve-shaped copy of this state. The Eve surface published in -chapter 3 points at typed records and commands owned by the provider. +Open a `.cc` store, register the document once, and write through the CultMesh +database boundary: -Verification: +```csharp +var key = new CultRecordKey("counter:main"); +var registry = CultDocumentRegistry.ForTypes([typeof(CounterState)]); + +using var cache = await CultCacheMessagePack.OpenAsync("counter.cc", new CultCacheOpenOptions +{ + Registry = registry, + FlushOnDispose = true, + StoreFlushOnDispose = true +}); +var documents = new CultNetDocumentRegistry(registry) + .Register(CultNetDocumentBinding.ForDocument( + registry, + "sample.counter_state.v1")); +using var database = new CultNetDatabase(cache, new CultNetDatabaseOptions +{ + RuntimeId = "sample.counter-provider", + DocumentRegistry = documents +}); + +await database.PutAsync(key, new CounterState +{ + CounterId = key.Value, + Count = 0 +}); +await cache.FlushAsync(); +``` + +CultCache owns durable local truth. CultNet owns the portable schema mapping. +CultMesh exposes the database and later carries subscriptions and operations. +The renderer owns none of them. + +The executable provider adds its receipt index to this document so the counter +mutation and idempotency decision are committed together. See +[`samples/eve-browser-network/Program.cs`](../../../../samples/eve-browser-network/Program.cs) +for the exact running type and transaction. + +Fast persistence check: ```powershell dotnet test tests/GameCult.Networking.Tests/GameCult.Networking.Tests.csproj --filter FullyQualifiedName~CultMeshNode_CanRoundTrip_DurableTypedDocument_Through_PublicDatabaseSurface ``` +This check proves the local typed state boundary. Chapter 4 boots the real +provider and proves the same state across Chromium and C# after restart. + Next: [connect a client by stable identity](02-connect-by-identity.md). diff --git a/src/GameCult.Mesh/docs/getting-started/02-connect-by-identity.md b/src/GameCult.Mesh/docs/getting-started/02-connect-by-identity.md index b7c636d4..8dffffaa 100644 --- a/src/GameCult.Mesh/docs/getting-started/02-connect-by-identity.md +++ b/src/GameCult.Mesh/docs/getting-started/02-connect-by-identity.md @@ -1,6 +1,8 @@ # 2. Connect A Client By Stable Identity -Clients address a provider or Verse by stable identity. Discovery owns the +Clients address a Verse session by stable identity. In this tutorial, +`sample.counter-provider` is the sole authority runtime Odin advertises for the +`sample.counter` Verse; neither identity is a socket address. Discovery owns current physical candidates and the session manager owns connection reuse, path rotation, and transport failure state. @@ -13,7 +15,7 @@ using var mesh = new CultMeshClient(new CultMeshClientOptions }); using var counterLease = await mesh.LeaseDocumentAsync( - "sample.counter-provider", + "sample.counter", "counter:main", cancellationToken); var counter = counterLease.Handle; @@ -49,7 +51,8 @@ using var stateWatch = session.WatchState().Subscribe(state => Application code does not reconnect, sleep, rank endpoints, or replace the session. Those decisions belong to CultMesh. -Verification: +Fast session-management check (this uses controlled transports; it is not the +network proof): ```powershell dotnet test tests/GameCult.Mesh.Tests/GameCult.Mesh.Tests.csproj --filter FullyQualifiedName~CultMeshSessionManagerTests @@ -59,4 +62,7 @@ Advanced hosts may inject lookup sources, connectors, clocks, persistence, and diagnostics through the lower-level discovery and session APIs. Application features should not need them. +Chapter 4 runs the real network chronology and proves that the retained lease +survives Odin moving `sample.counter` to a new physical provider route. + Next: [publish one Eve surface to multiple runtimes](03-publish-an-eve-surface.md). diff --git a/src/GameCult.Mesh/docs/getting-started/04-keep-a-typescript-provider-alive.md b/src/GameCult.Mesh/docs/getting-started/04-keep-a-typescript-provider-alive.md deleted file mode 100644 index 15f10a3a..00000000 --- a/src/GameCult.Mesh/docs/getting-started/04-keep-a-typescript-provider-alive.md +++ /dev/null @@ -1,122 +0,0 @@ -# 4. Keep A TypeScript Provider Alive - -A provider process should declare desired typed publications and domain command -handlers once. It should not rebuild discovery registration, lease renewal, -reconnect, republish, receipt delivery, and withdrawal loops in a renderer or -scheduled export script. - -`CultMeshProviderSession` owns that lifecycle. The application still owns its -state and command transaction. A transport connector owns the physical CultNet -route. Eve advertisements and surfaces are ordinary typed publications; the -session does not import Eve or learn provider gameplay. - -```ts -import { - CultMeshProviderSession, - type CultMeshProviderReceiptStore, - type CultMeshProviderTransport, -} from "cultmesh-ts"; - -export async function runProvider( - transport: CultMeshProviderTransport, - receipts: CultMeshProviderReceiptStore, -) { - const provider = new CultMeshProviderSession({ - identity: { - providerId: "voidbot.swarm", - serviceInstanceId: "voidbot-worker-7", - endpointId: "odin:voidbot-worker-7", - verseId: "voidbot.local", - }, - transport, - receiptStore: receipts, - publications: [ - { - publicationId: "voidbot.swarm.advertisement", - documentType: "gamecult.eve.provider_advertisement", - schemaId: "gamecult.eve.provider_advertisement.v1", - recordKey: "voidbot.swarm", - value: providerAdvertisement, - }, - { - publicationId: "voidbot.swarm.surface", - documentType: "gamecult.eve.surface_state", - schemaId: "gamecult.eve.surface_state.v1", - recordKey: "voidbot.swarm", - value: currentSurface, - }, - ], - commandHandlers: { - "swarm.set_heat": async command => - applyHeatCommandTransaction(command.commandId, command.payload), - }, - }); - - await provider.start(); - - await provider.upsertPublication({ - publicationId: "voidbot.swarm.surface", - documentType: "gamecult.eve.surface_state", - schemaId: "gamecult.eve.surface_state.v1", - recordKey: "voidbot.swarm", - value: nextSurface, - }); - - process.once("SIGTERM", () => { - provider.stop().catch(error => { - console.error("CultMesh provider shutdown completed with cleanup failures.", error); - process.exitCode = 1; - }); - }); -} -``` - -The four identities are deliberately distinct: - -- `providerId` names the product capability clients select; -- `serviceInstanceId` names the running owner incarnation; -- `endpointId` names the stable discovery/session route. -- `verseId` names the discovery and state-sharing domain. - -Do not replace any of them with a process id, socket address, body producer id, -or renderer id. - -## Receipt Rule - -The receipt store is required and must be durable in a daemon. The in-memory -store exported by the package is for tests and disposable tools only. The -domain command handler must apply its mutation idempotently using `commandId`; -the provider session deduplicates delivery and republishes the stored typed -receipt, but it cannot make an unrelated database mutation atomic by wishing -at it harder. `commandId` is the idempotency key: later delivery of the same -provider, service-instance, and command kind returns the original receipt even -if a sender incorrectly changes the payload. Reusing the ID for another kind -or identity is rejected as a conflict. - -The store is also the receipt outbox. `put` commits the receipt before any wire -publication. `listPending` supplies receipts after startup or reconnect, and -`markPublished` removes one only after the active connection accepts it. Scope -the store to the provider and service-instance identity. If the store is -unavailable, the session enters `degraded` and stops accepting commands until a -renewal can drain the outbox again; a store failure is not a transport failure. - -## Verification Checkpoint - -Use an injected scheduler and transport fault double to prove the actual -lifecycle: - -1. initial registration publishes every desired document in stable order; -2. lease renewal occurs before expiry; -3. a failed route produces `reconnecting`, then republishes current desired - state on the replacement connection; -4. duplicate command delivery runs one handler transaction and republishes the - same receipt; -5. failed receipt transport reconnects and replays the durable outbox exactly - until `markPublished` succeeds; -6. shutdown drains command persistence, withdraws the lease and remaining - publications, and closes even when cleanup reports failures; -7. stopping during registration cannot let the stale connection publish; -8. observers and conflicting command IDs cannot become lifecycle authorities. - -The package suite contains this timeline in -`packages/cultmesh-ts/test/provider-session.test.ts`. diff --git a/src/GameCult.Mesh/docs/getting-started/04-run-the-multiruntime-game.md b/src/GameCult.Mesh/docs/getting-started/04-run-the-multiruntime-game.md new file mode 100644 index 00000000..cb921ea1 --- /dev/null +++ b/src/GameCult.Mesh/docs/getting-started/04-run-the-multiruntime-game.md @@ -0,0 +1,60 @@ +# 4. Run The Multi-Runtime Game + +The counter is now one small multiplayer game: + +- a C# provider owns `CounterState`, Increment, idempotency, receipts, the + `.cc` store, and the Eve surface; +- Chromium discovers that provider through Odin, lowers the surface, and + invokes Increment; +- an independent C# client leases the same counter and invokes through the same + typed operation boundary; +- both clients remain attached when Odin moves the provider identity to a new + physical route. + +Run the whole chronology from the CultLib checkout: + +```powershell +pwsh -File ./scripts/verify-eve-getting-started.ps1 +``` + +The command owns setup and teardown. Do not start Odin, the provider, or the +browser by hand. A successful run prints two JSON records followed by: + +```text +Eve getting-started verification passed: clean artifacts, DOM and headless convergence, real Chromium and C# clients, Odin discovery, receipts, persistence, and route replacement. +``` + +## What The Command Proves + +The first checkpoint packs the TypeScript CultCache, CultNet, CultMesh, and Eve +packages, installs those artifacts into an empty temporary consumer, and proves +DOM/headless convergence plus `.cc` reopen. This rejects a sample that only +works through repository-relative source imports. + +The second checkpoint boots separate Odin, provider, Chromium, and C# headless +processes. Chromium performs the first increment. The provider then restarts on +a different route, Odin advertises the replacement, and the retained clients +resubscribe without application reconnect code. C# performs the second +increment. Both clients must observe count 2 and both canonical receipt ids. + +Finally, the retained C# session sends 10,000 typed no-op operations. The gate +records throughput, p99 latency, managed-heap growth, and private-memory growth. +It fails at 250 ms p99 or more than 8 MiB post-GC managed growth. + +## What It Does Not Prove + +The included Odin is a real CultNet Verse-catalog provider but still a local +fixture. It does not prove deployed GameCult infrastructure. The package layer +uses packed checkout artifacts until the package owners publish the named npm +packages. Those are explicit release gates, not reasons to put endpoint or +source-tree fallbacks into application code. + +The process harness lives in +[`samples/eve-browser-network`](../../../../samples/eve-browser-network/README.md). +Application code should copy the typed state, operation, and Eve composition +shape—not its benchmark flags or fixture orchestration. + +For a TypeScript provider daemon, continue with the +[`CultMeshProviderSession` guide](../../../../packages/cultmesh-ts/README.md#long-lived-providers). +That lifecycle is an alternative provider runtime for the same ownership +model, not a fifth chapter that changes this tutorial into a different product. diff --git a/src/GameCult.Mesh/docs/getting-started/README.md b/src/GameCult.Mesh/docs/getting-started/README.md index 5251c7ca..d09d10e2 100644 --- a/src/GameCult.Mesh/docs/getting-started/README.md +++ b/src/GameCult.Mesh/docs/getting-started/README.md @@ -29,7 +29,7 @@ Follow the chapters in order: 1. [Persist typed application state](01-persist-typed-state.md) 2. [Connect a client by stable identity](02-connect-by-identity.md) 3. [Publish one Eve surface to multiple runtimes](03-publish-an-eve-surface.md) -4. [Keep a TypeScript provider alive](04-keep-a-typescript-provider-alive.md) +4. [Run the multi-runtime game](04-run-the-multiruntime-game.md) The intended application shape is small: @@ -39,6 +39,8 @@ provider daemon -> typed CultCache documents -> CultMesh advertisement +------------------------+--------------------+ | | | Eve browser EveUnity another lowerer + | | | + player input player input headless / AI ``` The provider owns live truth. Eve owns the surface contract. Each runtime owns diff --git a/src/GameCult.Mesh/docs/typed-document-path.md b/src/GameCult.Mesh/docs/typed-document-path.md index 3ee3183c..aab47930 100644 --- a/src/GameCult.Mesh/docs/typed-document-path.md +++ b/src/GameCult.Mesh/docs/typed-document-path.md @@ -109,7 +109,7 @@ messages directly. ```csharp using GameCult.Mesh; -using var node = await CultMesh.CreateNodeAsync("world.ccmp", new CultMeshNodeOptions +using var node = await CultMesh.CreateNodeAsync("world.cc", new CultMeshNodeOptions { DatabaseOptions = new CultNetDatabaseOptions { From 22bb9afaa4b2261fa05317f1a4b7743e2e96cb04 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 06:23:26 +0200 Subject: [PATCH 089/283] Use one CultMesh node in Eve onboarding --- samples/eve-browser-network/Program.cs | 47 ++++++++++--------- samples/eve-browser-network/README.md | 3 +- .../getting-started/01-persist-typed-state.md | 35 +++++++------- 3 files changed, 43 insertions(+), 42 deletions(-) diff --git a/samples/eve-browser-network/Program.cs b/samples/eve-browser-network/Program.cs index 82c09c19..fe6a74b9 100644 --- a/samples/eve-browser-network/Program.cs +++ b/samples/eve-browser-network/Program.cs @@ -72,29 +72,32 @@ static async Task RunOdinAsync(Args arguments) static async Task RunProviderAsync(Args arguments) { - var registry = CultDocumentRegistry.ForTypes([typeof(CounterState), typeof(EveSurfaceDocument)]); - using var cache = await CultCacheMessagePack.OpenAsync(arguments.StatePath, new CultCacheOpenOptions + var documentTypes = new[] { typeof(CounterState), typeof(EveSurfaceDocument) }; + var registry = CultMesh.CreateCultCacheDocumentRegistry(documentTypes); + var documents = CultMesh.CreateCultNetDocumentRegistry(documentTypes, registry); + using var node = await CultMesh.CreateNodeAsync(arguments.StatePath, new CultMeshNodeOptions { - Registry = registry, - FlushOnDispose = true, - StoreFlushOnDispose = true + StartServer = false, + CacheOptions = new CultCacheOpenOptions + { + Registry = registry, + FlushOnDispose = true, + StoreFlushOnDispose = true + }, + DatabaseOptions = new CultNetDatabaseOptions + { + RuntimeId = "sample.counter-provider", + DocumentRegistry = documents + } }); - var documents = new CultNetDocumentRegistry(registry) - .Register(CultNetDocumentBinding.ForDocument(registry, "sample.counter_state.v1")) - .Register(CultNetDocumentBinding.ForDocument(registry, EveSurfaceDocument.SchemaId)); - using var database = new CultNetDatabase(cache, new CultNetDatabaseOptions - { - RuntimeId = "sample.counter-provider", - DocumentRegistry = documents - }); - if (cache.Get(new CultRecordKey(counterKey)) == null) - await database.PutAsync(new CultRecordKey(counterKey), CounterState.Initial(counterKey)); - if (cache.Get(new CultRecordKey(surfaceKey)) == null) - await database.PutAsync(new CultRecordKey(surfaceKey), CreateCounterSurface()); - await cache.FlushAsync(); + if (node.Cache.Get(new CultRecordKey(counterKey)) == null) + await node.Database.PutAsync(new CultRecordKey(counterKey), CounterState.Initial(counterKey)); + if (node.Cache.Get(new CultRecordKey(surfaceKey)) == null) + await node.Database.PutAsync(new CultRecordKey(surfaceKey), CreateCounterSurface()); + await node.FlushAsync(); await using var schemaServer = new CultNetWebSocketSchemaServer(); - using var subscriptions = new CultNetDatabaseSubscriptionServer(schemaServer, database); + using var subscriptions = new CultNetDatabaseSubscriptionServer(schemaServer, node.Database); using var operationGate = new SemaphoreSlim(1, 1); using var operations = new CultNetOperationServer(schemaServer, "sample.counter-provider") .Register( @@ -113,7 +116,7 @@ static async Task RunProviderAsync(Args arguments) await operationGate.WaitAsync(); try { - var current = cache.Get(new CultRecordKey(counterKey)) + var current = node.Cache.Get(new CultRecordKey(counterKey)) ?? throw new InvalidOperationException("Counter state is unavailable."); if (current.Receipts.TryGetValue(context.IdempotencyKey, out var existing)) return existing; @@ -125,13 +128,13 @@ static async Task RunProviderAsync(Args arguments) { [context.IdempotencyKey] = receipt }; - await database.PutAsync(new CultRecordKey(counterKey), new CounterState + await node.Database.PutAsync(new CultRecordKey(counterKey), new CounterState { CounterId = counterKey, Count = receipt.Count, Receipts = receipts }); - await cache.FlushAsync(); + await node.FlushAsync(); return receipt; } finally diff --git a/samples/eve-browser-network/README.md b/samples/eve-browser-network/README.md index bbcc95ca..7ad20a00 100644 --- a/samples/eve-browser-network/README.md +++ b/samples/eve-browser-network/README.md @@ -19,7 +19,8 @@ The provider registers typed commands through `CultNetOperationServer`. Application code receives `CultNetOperationContext` and returns a typed receipt; it does not parse base64, switch on wire envelopes, or construct correlation responses. The counter's durable transaction still owns -idempotency and state mutation. +idempotency and state mutation. The provider opens one public `CultMeshNode`; +it does not assemble a parallel CultCache/CultNet database host by hand. Run the proof from the CultLib repository: diff --git a/src/GameCult.Mesh/docs/getting-started/01-persist-typed-state.md b/src/GameCult.Mesh/docs/getting-started/01-persist-typed-state.md index 6e2d2b3b..c2667e9b 100644 --- a/src/GameCult.Mesh/docs/getting-started/01-persist-typed-state.md +++ b/src/GameCult.Mesh/docs/getting-started/01-persist-typed-state.md @@ -7,6 +7,7 @@ client. Start with the state the provider actually owns. ```csharp using GameCult.Caching; using GameCult.Caching.MessagePack; +using GameCult.Mesh; using GameCult.Networking; using MessagePack; @@ -19,35 +20,31 @@ public sealed class CounterState } ``` -Open a `.cc` store, register the document once, and write through the CultMesh -database boundary: +Open a `.cc` node, register the document once, and write through its database +boundary: ```csharp var key = new CultRecordKey("counter:main"); -var registry = CultDocumentRegistry.ForTypes([typeof(CounterState)]); - -using var cache = await CultCacheMessagePack.OpenAsync("counter.cc", new CultCacheOpenOptions +var documentTypes = new[] { typeof(CounterState) }; +var registry = CultMesh.CreateCultCacheDocumentRegistry(documentTypes); +var documents = CultMesh.CreateCultNetDocumentRegistry(documentTypes, registry); +using var node = await CultMesh.CreateNodeAsync("counter.cc", new CultMeshNodeOptions { - Registry = registry, - FlushOnDispose = true, - StoreFlushOnDispose = true -}); -var documents = new CultNetDocumentRegistry(registry) - .Register(CultNetDocumentBinding.ForDocument( - registry, - "sample.counter_state.v1")); -using var database = new CultNetDatabase(cache, new CultNetDatabaseOptions -{ - RuntimeId = "sample.counter-provider", - DocumentRegistry = documents + StartServer = false, + CacheOptions = new CultCacheOpenOptions { Registry = registry }, + DatabaseOptions = new CultNetDatabaseOptions + { + RuntimeId = "sample.counter-provider", + DocumentRegistry = documents + } }); -await database.PutAsync(key, new CounterState +await node.Database.PutAsync(key, new CounterState { CounterId = key.Value, Count = 0 }); -await cache.FlushAsync(); +await node.FlushAsync(); ``` CultCache owns durable local truth. CultNet owns the portable schema mapping. From d4d24385d1f8cfbf2c0289a7025cd3090348280e Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 06:33:40 +0200 Subject: [PATCH 090/283] Prove clean .NET Eve package onboarding --- docs/nuget-packaging.md | 2 +- scripts/pack-nuget.ps1 | 6 ++++-- scripts/verify-eve-getting-started.ps1 | 17 ++++++++++++++++- .../03-publish-an-eve-surface.md | 13 ++++++++++--- .../04-run-the-multiruntime-game.md | 9 ++++++--- .../docs/getting-started/README.md | 6 ++++-- 6 files changed, 41 insertions(+), 12 deletions(-) diff --git a/docs/nuget-packaging.md b/docs/nuget-packaging.md index a269090a..afc94570 100644 --- a/docs/nuget-packaging.md +++ b/docs/nuget-packaging.md @@ -19,5 +19,5 @@ closure through UPM rather than NuGet restore. Install the Unity package from the immutable release tag: ```text -https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-v1.0.8 +https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-v1.0.46 ``` diff --git a/scripts/pack-nuget.ps1 b/scripts/pack-nuget.ps1 index b027c492..14fa7340 100644 --- a/scripts/pack-nuget.ps1 +++ b/scripts/pack-nuget.ps1 @@ -27,7 +27,8 @@ if (Test-Path -LiteralPath $outputRoot) { New-Item -ItemType Directory -Force -Path $outputRoot | Out-Null foreach ($project in $projects) { - dotnet pack (Join-Path $repoRoot $project) -c $Configuration -o $outputRoot + dotnet pack (Join-Path $repoRoot $project) -c $Configuration -o $outputRoot ` + --nologo --verbosity quiet -p:NoWarn=1591%3BCS8632 if ($LASTEXITCODE -ne 0) { throw "NuGet pack failed for $project with exit code $LASTEXITCODE" } @@ -82,7 +83,8 @@ Console.WriteLine(verse.Context.VerseId); "@ [IO.File]::WriteAllText((Join-Path $smokeRoot "Consumer.csproj"), $projectDocument, [Text.UTF8Encoding]::new($false)) [IO.File]::WriteAllText((Join-Path $smokeRoot "Program.cs"), $program, [Text.UTF8Encoding]::new($false)) - dotnet run --project (Join-Path $smokeRoot "Consumer.csproj") -c Release + dotnet run --project (Join-Path $smokeRoot "Consumer.csproj") -c Release ` + --nologo --verbosity quiet if ($LASTEXITCODE -ne 0) { throw "GameCult.Mesh NuGet consumer smoke failed with exit code $LASTEXITCODE" } diff --git a/scripts/verify-eve-getting-started.ps1 b/scripts/verify-eve-getting-started.ps1 index be49aafe..1805b070 100644 --- a/scripts/verify-eve-getting-started.ps1 +++ b/scripts/verify-eve-getting-started.ps1 @@ -18,6 +18,21 @@ foreach ($requiredPrimitive in @("CultNetOperationServer", "EveSurface.Create")) } } +$dotnetPackageRoot = Join-Path ([IO.Path]::GetTempPath()) ` + ("eve-getting-started-nuget-" + [guid]::NewGuid().ToString("N")) +try { + & (Join-Path $EveRoot "scripts\pack-dotnet-surface.ps1") ` + -CultLibRoot $cultLibRoot ` + -OutputDirectory $dotnetPackageRoot + if ($LASTEXITCODE -ne 0) { + throw "The clean .NET package-consumer checkpoint failed." + } +} finally { + if (Test-Path -LiteralPath $dotnetPackageRoot) { + Remove-Item -LiteralPath $dotnetPackageRoot -Recurse -Force + } +} + & (Join-Path $PSScriptRoot "verify-eve-two-runtime-sample.ps1") ` -EveRoot $EveRoot ` -SkipDependencyInstall:$SkipDependencyInstall @@ -37,4 +52,4 @@ if ($LASTEXITCODE -ne 0) { throw "The real browser/C# network checkpoint failed." } -Write-Host "Eve getting-started verification passed: clean artifacts, DOM and headless convergence, real Chromium and C# clients, Odin discovery, receipts, persistence, and route replacement." +Write-Host "Eve getting-started verification passed: clean .NET and TypeScript artifacts, DOM and headless convergence, real Chromium and C# clients, Odin discovery, receipts, persistence, and route replacement." diff --git a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md index a910cf97..4d5af0dc 100644 --- a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md +++ b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md @@ -94,9 +94,16 @@ cd CultLib pwsh -File ./scripts/verify-eve-getting-started.ps1 ``` -This one command runs the clean package-artifact checkpoint and then the real -browser/C# network checkpoint. They remain separate programs because they prove -different boundaries; the developer should not have to orchestrate them. +This one command runs clean .NET and TypeScript package-artifact checkpoints, +then the real browser/C# network checkpoint. They remain separate programs +because they prove different boundaries; the developer should not have to +orchestrate them. + +The .NET layer packs CultLib's managed dependency graph and +`GameCult.Eve.Surface`, then restores and runs an empty project whose only +GameCult dependency is `PackageReference Include="GameCult.Eve.Surface"`. +This proves the renderer-neutral provider contract does not require a sibling +Eve or CultLib source tree after packaging. The first layer builds and packs `cultcache-ts`, `cultnet-ts`, `cultmesh-ts`, `@gamecult/eve-contracts`, and `@gamecult/eve-browser-lowering`, installs the diff --git a/src/GameCult.Mesh/docs/getting-started/04-run-the-multiruntime-game.md b/src/GameCult.Mesh/docs/getting-started/04-run-the-multiruntime-game.md index cb921ea1..a748368b 100644 --- a/src/GameCult.Mesh/docs/getting-started/04-run-the-multiruntime-game.md +++ b/src/GameCult.Mesh/docs/getting-started/04-run-the-multiruntime-game.md @@ -21,17 +21,20 @@ The command owns setup and teardown. Do not start Odin, the provider, or the browser by hand. A successful run prints two JSON records followed by: ```text -Eve getting-started verification passed: clean artifacts, DOM and headless convergence, real Chromium and C# clients, Odin discovery, receipts, persistence, and route replacement. +Eve getting-started verification passed: clean .NET and TypeScript artifacts, DOM and headless convergence, real Chromium and C# clients, Odin discovery, receipts, persistence, and route replacement. ``` ## What The Command Proves -The first checkpoint packs the TypeScript CultCache, CultNet, CultMesh, and Eve +The first checkpoint packs the CultLib managed dependency closure and Eve's C# +surface contract, then restores and runs an empty .NET project using only the +resulting `GameCult.Eve.Surface` package. The second checkpoint packs the +TypeScript CultCache, CultNet, CultMesh, and Eve packages, installs those artifacts into an empty temporary consumer, and proves DOM/headless convergence plus `.cc` reopen. This rejects a sample that only works through repository-relative source imports. -The second checkpoint boots separate Odin, provider, Chromium, and C# headless +The third checkpoint boots separate Odin, provider, Chromium, and C# headless processes. Chromium performs the first increment. The provider then restarts on a different route, Odin advertises the replacement, and the retained clients resubscribe without application reconnect code. C# performs the second diff --git a/src/GameCult.Mesh/docs/getting-started/README.md b/src/GameCult.Mesh/docs/getting-started/README.md index d09d10e2..b32052a7 100644 --- a/src/GameCult.Mesh/docs/getting-started/README.md +++ b/src/GameCult.Mesh/docs/getting-started/README.md @@ -11,8 +11,10 @@ pwsh -File ./scripts/verify-eve-getting-started.ps1 ``` With clean sibling CultLib and Eve checkouts, the command installs missing build -dependencies and runs two explicit evidence layers. First it packs the five -TypeScript packages into an empty temporary consumer, validates the Eve surface +dependencies and runs three explicit evidence layers. First it packs the +CultLib managed dependency closure plus `GameCult.Eve.Surface`, then restores +and runs an empty .NET consumer using only `PackageReference`. Next it packs the five +TypeScript packages into another empty temporary consumer, validates the Eve surface and receipt, executes one idempotent counter command, proves a DOM lowerer and headless observer converge, and reopens the durable `.cc` store. Then it boots a durable C# provider, local Odin fixture, real Chromium lowerer, and independent From c75051017dd6e9123be8d440d24109b672c7e581 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 07:26:55 +0200 Subject: [PATCH 091/283] Make CultMesh session identity explicit --- samples/eve-browser-network/Program.cs | 24 ++- scripts/verify-eve-getting-started.ps1 | 12 ++ src/GameCult.Mesh/CultMeshBodySessions.cs | 8 +- src/GameCult.Mesh/CultMeshClient.cs | 117 ++++++-------- .../CultMeshContentTransports.cs | 14 +- src/GameCult.Mesh/CultMeshDiscoveryService.cs | 19 ++- src/GameCult.Mesh/CultMeshPeerExchange.cs | 14 +- .../CultMeshRealtimeTransports.cs | 6 +- src/GameCult.Mesh/CultMeshSessions.cs | 152 +++++++++++------- src/GameCult.Mesh/CultMeshSnapshots.cs | 10 +- src/GameCult.Mesh/docs/content-sessions.md | 5 +- .../getting-started/02-connect-by-identity.md | 23 ++- .../03-publish-an-eve-surface.md | 4 +- .../04-run-the-multiruntime-game.md | 4 +- .../docs/reliability-migration-plan.md | 7 +- src/GameCult.Mesh/docs/transport-planes.md | 6 +- .../CultMeshQuicRealtimeTransportTests.cs | 12 +- .../CultMeshBodySessionTests.cs | 6 +- .../CultMeshClientTests.cs | 62 ++++--- .../CultMeshContentSessionTests.cs | 7 +- .../CultMeshDiscoveryServiceTests.cs | 22 ++- .../CultMeshSessionManagerTests.cs | 47 +++--- .../CultMeshTransportModularityTests.cs | 13 +- tools/GameCult.TransportParity/Program.cs | 6 +- 24 files changed, 364 insertions(+), 236 deletions(-) diff --git a/samples/eve-browser-network/Program.cs b/samples/eve-browser-network/Program.cs index fe6a74b9..e06c235a 100644 --- a/samples/eve-browser-network/Program.cs +++ b/samples/eve-browser-network/Program.cs @@ -183,7 +183,8 @@ static async Task RunHeadlessAsync(Args arguments) _ => CreateClient()) ] }); - using var lease = await mesh.LeaseDocumentAsync(arguments.VerseId, counterKey); + var target = new CultMeshSessionTarget(arguments.VerseId, arguments.AuthorityRuntimeId); + using var lease = await mesh.LeaseDocumentAsync(target, counterKey); var completion = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var lastCount = -1; using var watch = lease.Handle.Watch(counter => @@ -217,7 +218,7 @@ static async Task RunHeadlessAsync(Args arguments) throw new InvalidOperationException("The headless sample expected 'INVOKE ' on stdin."); var commandId = line["INVOKE ".Length..].Trim(); var result = await mesh.InvokeAsync( - arguments.VerseId, + target, "sample.counter", "sample.counter.increment", "sample.increment.v1", @@ -232,18 +233,21 @@ static async Task RunHeadlessAsync(Args arguments) status = result.Status })); Console.WriteLine("HEADLESS_NETWORK_BENCHMARK " + JsonSerializer.Serialize( - await MeasureOperationSessionAsync(mesh, arguments))); + await MeasureOperationSessionAsync(mesh, target, arguments))); }); await Task.WhenAll(completion.Task, commandTask).WaitAsync(TimeSpan.FromSeconds(45)); } -static async Task MeasureOperationSessionAsync(CultMeshClient mesh, Args arguments) +static async Task MeasureOperationSessionAsync( + CultMeshClient mesh, + CultMeshSessionTarget target, + Args arguments) { const int warmupOperations = 100; if (arguments.BenchmarkOperations <= 0) throw new ArgumentOutOfRangeException(nameof(arguments.BenchmarkOperations)); for (var index = 0; index < warmupOperations; index++) - await PingAsync(mesh, arguments, "warmup:" + index, index); + await PingAsync(mesh, target, "warmup:" + index, index); ForceCollection(); using var process = Process.GetCurrentProcess(); @@ -255,7 +259,7 @@ static async Task MeasureOperationSessionAsync(CultMeshClient mesh, Args for (var index = 0; index < arguments.BenchmarkOperations; index++) { var started = Stopwatch.GetTimestamp(); - await PingAsync(mesh, arguments, "benchmark:" + index, index); + await PingAsync(mesh, target, "benchmark:" + index, index); latencies[index] = Stopwatch.GetElapsedTime(started).TotalMilliseconds; } clock.Stop(); @@ -284,10 +288,14 @@ static async Task MeasureOperationSessionAsync(CultMeshClient mesh, Args }; } -static async Task PingAsync(CultMeshClient mesh, Args arguments, string idempotencyKey, int sequence) +static async Task PingAsync( + CultMeshClient mesh, + CultMeshSessionTarget target, + string idempotencyKey, + int sequence) { var result = await mesh.InvokeAsync( - arguments.VerseId, + target, "sample.counter", "sample.counter.ping", "sample.ping_request.v1", diff --git a/scripts/verify-eve-getting-started.ps1 b/scripts/verify-eve-getting-started.ps1 index 1805b070..0a690712 100644 --- a/scripts/verify-eve-getting-started.ps1 +++ b/scripts/verify-eve-getting-started.ps1 @@ -17,6 +17,18 @@ foreach ($requiredPrimitive in @("CultNetOperationServer", "EveSurface.Create")) throw "The getting-started provider is missing the public primitive '$requiredPrimitive'." } } +if ($networkSampleSource -notmatch 'new\s+CultMeshSessionTarget\s*\(') { + throw "The getting-started client must address one explicit Verse/provider target." +} +$cultMeshClientSource = Get-Content -LiteralPath (Join-Path $cultLibRoot "src\GameCult.Mesh\CultMeshClient.cs") -Raw +if ($cultMeshClientSource -match 'ConnectAsync\s*\(\s*string\s+(endpointId|verseId)' -or + $cultMeshClientSource -match 'Lease(Document|Collection)Async[^\(]*\(\s*string\s+(endpointId|verseId)') { + throw "CultMeshClient must not expose an ambiguous one-string session identity." +} +$discoverySource = Get-Content -LiteralPath (Join-Path $cultLibRoot "src\GameCult.Mesh\CultMeshDiscoveryService.cs") -Raw +if ($discoverySource -notmatch 'AuthorityRuntimeIds\.Contains\(query\.AuthorityRuntimeId') { + throw "CultMesh discovery must prove that a selected Verse route advertises the requested provider runtime." +} $dotnetPackageRoot = Join-Path ([IO.Path]::GetTempPath()) ` ("eve-getting-started-nuget-" + [guid]::NewGuid().ToString("N")) diff --git a/src/GameCult.Mesh/CultMeshBodySessions.cs b/src/GameCult.Mesh/CultMeshBodySessions.cs index cc45277e..ee946201 100644 --- a/src/GameCult.Mesh/CultMeshBodySessions.cs +++ b/src/GameCult.Mesh/CultMeshBodySessions.cs @@ -278,15 +278,15 @@ namespace GameCult.Mesh public sealed class CultMeshSessionBodyProvider { private readonly CultMeshSessionManager _sessions; - private readonly CultMeshEndpointId _endpointId; + private readonly CultMeshSessionTarget _target; private readonly CultMeshSessionBodyProviderOptions _options; public CultMeshSessionBodyProvider(string providerId, CultMeshSessionManager sessions, - CultMeshEndpointId endpointId, CultMeshSessionBodyProviderOptions? options = null) + CultMeshSessionTarget target, CultMeshSessionBodyProviderOptions? options = null) { ProviderId = string.IsNullOrWhiteSpace(providerId) ? throw new ArgumentException("Provider identity is required.", nameof(providerId)) : providerId; _sessions = sessions ?? throw new ArgumentNullException(nameof(sessions)); - _endpointId = endpointId ?? throw new ArgumentNullException(nameof(endpointId)); + _target = target ?? throw new ArgumentNullException(nameof(target)); _options = options ?? new CultMeshSessionBodyProviderOptions(); if (_options.ResponseTimeout <= TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(options)); } @@ -300,7 +300,7 @@ namespace GameCult.Mesh if (descriptor == null) throw new ArgumentNullException(nameof(descriptor)); if (descriptor.TransportKind != CultMeshBodyTransportKind.Network) throw new NotSupportedException("Direct body provider requires a network descriptor."); - var session = await _sessions.ConnectAsync(_endpointId, CultMeshProtocols.Bodies, cancellationToken).ConfigureAwait(false); + var session = await _sessions.ConnectAsync(_target, CultMeshProtocols.Bodies, cancellationToken).ConfigureAwait(false); var messageId = Guid.NewGuid().ToString("N"); var completion = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); using var responseSubscription = session.OnCultNet(response => diff --git a/src/GameCult.Mesh/CultMeshClient.cs b/src/GameCult.Mesh/CultMeshClient.cs index 1d33c3ec..99746a5c 100644 --- a/src/GameCult.Mesh/CultMeshClient.cs +++ b/src/GameCult.Mesh/CultMeshClient.cs @@ -192,76 +192,66 @@ namespace GameCult.Mesh _operationResponseTimeout = options.OperationResponseTimeout; } - /// Connects to a stable endpoint identity using one application protocol. + /// Connects to one stable Verse/provider target using one application protocol. public Task ConnectAsync( - string endpointId, + CultMeshSessionTarget target, CultMeshProtocolId protocol, CancellationToken cancellationToken = default) { ThrowIfDisposed(); - return _sessions.ConnectAsync(CultMeshEndpointId.Parse(endpointId), protocol, cancellationToken); + return _sessions.ConnectAsync(target, protocol, cancellationToken); } - /// Connects the reusable realtime state plane by stable endpoint identity. + /// Connects the reusable realtime state plane for one stable Verse/provider target. public Task ConnectRealtimeAsync( - string endpointId, + CultMeshSessionTarget target, CancellationToken cancellationToken = default) { ThrowIfDisposed(); - return _sessions.ConnectRealtimeAsync(CultMeshEndpointId.Parse(endpointId), cancellationToken); - } - - /// Connects to a stable endpoint identity using one application protocol. - public Task ConnectAsync( - CultMeshEndpointId endpointId, - CultMeshProtocolId protocol, - CancellationToken cancellationToken = default) - { - ThrowIfDisposed(); - return _sessions.ConnectAsync(endpointId, protocol, cancellationToken); + return _sessions.ConnectRealtimeAsync(target, cancellationToken); } /// Creates a verified-transfer provider over this client's reusable content session owner. public CultMeshSessionContentProvider ContentProvider( string providerId, - string endpointId) + CultMeshSessionTarget target) { ThrowIfDisposed(); return new CultMeshSessionContentProvider( providerId, _sessions, - CultMeshEndpointId.Parse(endpointId)); + target); } /// Creates a direct body provider over this client's reusable negotiated session owner. public CultMeshSessionBodyProvider BodyProvider( string providerId, - string endpointId, + CultMeshSessionTarget target, CultMeshSessionBodyProviderOptions? options = null) { ThrowIfDisposed(); return new CultMeshSessionBodyProvider( providerId, _sessions, - CultMeshEndpointId.Parse(endpointId), + target, options); } - /// Leases one shared live typed document by stable provider identity and record key. + /// Leases one shared live typed document by stable Verse/provider identity and record key. public async Task> LeaseDocumentAsync( - string endpointId, + CultMeshSessionTarget target, string recordKey, CancellationToken cancellationToken = default) where TDocument : class { ThrowIfDisposed(); - if (string.IsNullOrWhiteSpace(endpointId)) throw new ArgumentException("Endpoint identity is required.", nameof(endpointId)); + if (target == null) throw new ArgumentNullException(nameof(target)); if (string.IsNullOrWhiteSpace(recordKey)) throw new ArgumentException("Record key is required.", nameof(recordKey)); - var key = endpointId.Trim() + "\u001f" + typeof(TDocument).AssemblyQualifiedName + "\u001f" + recordKey.Trim(); + var key = target.SessionKey + "\u001f" + typeof(TDocument).AssemblyQualifiedName + "\u001f" + recordKey.Trim(); while (true) { var resource = _documents.GetOrAdd(key, _ => new SharedResource( - async owner => await OpenDocumentAsync(endpointId.Trim(), recordKey.Trim(), owner).ConfigureAwait(false))); + async owner => await OpenDocumentAsync(target, recordKey.Trim(), owner).ConfigureAwait(false))); if (!resource.TryAcquire()) { RemoveExact(_documents, key, resource); @@ -283,28 +273,28 @@ namespace GameCult.Mesh } } - /// Leases a shared live collection of one typed schema by stable provider identity. + /// Leases a shared live collection by stable Verse/provider identity. public Task> LeaseCollectionAsync( - string endpointId, + CultMeshSessionTarget target, CancellationToken cancellationToken) where TDocument : class => - LeaseCollectionAsync(endpointId, includeInitialSnapshot: true, cancellationToken); + LeaseCollectionAsync(target, includeInitialSnapshot: true, cancellationToken); /// Leases a live collection and optionally skips replaying its initial snapshot. public async Task> LeaseCollectionAsync( - string endpointId, + CultMeshSessionTarget target, bool includeInitialSnapshot = true, CancellationToken cancellationToken = default) where TDocument : class { ThrowIfDisposed(); - if (string.IsNullOrWhiteSpace(endpointId)) throw new ArgumentException("Endpoint identity is required.", nameof(endpointId)); - var identity = endpointId.Trim(); + if (target == null) throw new ArgumentNullException(nameof(target)); + var identity = target.SessionKey; var key = identity + "\u001f" + typeof(TDocument).AssemblyQualifiedName + "\u001f" + includeInitialSnapshot; while (true) { var resource = _collections.GetOrAdd(key, _ => new SharedResource( - async owner => await OpenCollectionAsync(identity, includeInitialSnapshot, owner).ConfigureAwait(false))); + async owner => await OpenCollectionAsync(target, includeInitialSnapshot, owner).ConfigureAwait(false))); if (!resource.TryAcquire()) { RemoveExact(_collections, key, resource); @@ -331,7 +321,7 @@ namespace GameCult.Mesh /// only a provider-authored receipt or resulting state can establish acceptance. /// public async Task SubmitDocumentAsync( - string endpointId, + CultMeshSessionTarget target, string recordKey, TDocument document, string sourceRuntimeId, @@ -340,7 +330,7 @@ namespace GameCult.Mesh where TDocument : class { ThrowIfDisposed(); - if (string.IsNullOrWhiteSpace(endpointId)) throw new ArgumentException("Endpoint identity is required.", nameof(endpointId)); + if (target == null) throw new ArgumentNullException(nameof(target)); if (string.IsNullOrWhiteSpace(recordKey)) throw new ArgumentException("Record key is required.", nameof(recordKey)); if (document == null) throw new ArgumentNullException(nameof(document)); if (string.IsNullOrWhiteSpace(sourceRuntimeId)) throw new ArgumentException("Source runtime identity is required.", nameof(sourceRuntimeId)); @@ -357,7 +347,7 @@ namespace GameCult.Mesh SourceRuntimeId = sourceRuntimeId.Trim(), SourceRole = sourceRole.Trim() }); - var session = await ConnectAsync(endpointId.Trim(), CultMeshProtocols.Documents, cancellationToken) + var session = await ConnectAsync(target, CultMeshProtocols.Documents, cancellationToken) .ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); session.OpenSchemaClient().SendCultNet(message); @@ -369,7 +359,7 @@ namespace GameCult.Mesh /// provider-authored evidence rather than client-side authority over canonical state. /// public async Task> InvokeAsync( - string endpointId, + CultMeshSessionTarget target, string serviceId, string operation, string requestSchema, @@ -380,7 +370,7 @@ namespace GameCult.Mesh CancellationToken cancellationToken = default) { ThrowIfDisposed(); - if (string.IsNullOrWhiteSpace(endpointId)) throw new ArgumentException("Endpoint identity is required.", nameof(endpointId)); + if (target == null) throw new ArgumentNullException(nameof(target)); if (string.IsNullOrWhiteSpace(serviceId)) throw new ArgumentException("Service identity is required.", nameof(serviceId)); if (string.IsNullOrWhiteSpace(operation)) throw new ArgumentException("Operation identity is required.", nameof(operation)); if (string.IsNullOrWhiteSpace(requestSchema)) throw new ArgumentException("Request schema is required.", nameof(requestSchema)); @@ -389,12 +379,11 @@ namespace GameCult.Mesh if (string.IsNullOrWhiteSpace(sourceRuntimeId)) throw new ArgumentException("Source runtime identity is required.", nameof(sourceRuntimeId)); if (string.IsNullOrWhiteSpace(idempotencyKey)) throw new ArgumentException("A durable idempotency key is required.", nameof(idempotencyKey)); - var identity = endpointId.Trim(); var expectedService = serviceId.Trim(); var expectedOperation = operation.Trim(); var expectedResponseSchema = responseSchema.Trim(); var messageId = idempotencyKey.Trim(); - var session = await ConnectAsync(identity, CultMeshProtocols.Documents, cancellationToken).ConfigureAwait(false); + var session = await ConnectAsync(target, CultMeshProtocols.Documents, cancellationToken).ConfigureAwait(false); var completion = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); using var subscription = session.OnCultNet(response => { @@ -481,69 +470,69 @@ namespace GameCult.Mesh /// Reads one typed record once through the reusable document session. public async Task ReadAsync( - string endpointId, + CultMeshSessionTarget target, string recordKey, CancellationToken cancellationToken = default) where TDocument : class { ThrowIfDisposed(); - if (string.IsNullOrWhiteSpace(endpointId)) throw new ArgumentException("Endpoint identity is required.", nameof(endpointId)); + if (target == null) throw new ArgumentNullException(nameof(target)); if (string.IsNullOrWhiteSpace(recordKey)) throw new ArgumentException("Record key is required.", nameof(recordKey)); - var documents = await ReadManyAsync(endpointId, new[] { recordKey }, cancellationToken) + var documents = await ReadManyAsync(target, new[] { recordKey }, cancellationToken) .ConfigureAwait(false); return documents.FirstOrDefault() ?? throw new InvalidOperationException( - $"CultMesh endpoint '{endpointId}' did not publish {typeof(TDocument).FullName} record '{recordKey}'."); + $"CultMesh target '{target}' did not publish {typeof(TDocument).FullName} record '{recordKey}'."); } /// Reads one typed record once with an explicit response deadline. public async Task ReadAsync( - string endpointId, + CultMeshSessionTarget target, string recordKey, TimeSpan responseTimeout, CancellationToken cancellationToken = default) where TDocument : class { var documents = await ReadManyCoreAsync( - endpointId, + target, new[] { recordKey }, responseTimeout, cancellationToken) .ConfigureAwait(false); return documents.FirstOrDefault() ?? throw new InvalidOperationException( - $"CultMesh endpoint '{endpointId}' did not publish {typeof(TDocument).FullName} record '{recordKey}'."); + $"CultMesh target '{target}' did not publish {typeof(TDocument).FullName} record '{recordKey}'."); } /// Reads typed records once in one request through the reusable document session. public async Task> ReadManyAsync( - string endpointId, + CultMeshSessionTarget target, IReadOnlyList recordKeys, CancellationToken cancellationToken = default) where TDocument : class => await ReadManyCoreAsync( - endpointId, + target, recordKeys, TimeSpan.FromSeconds(10), cancellationToken) .ConfigureAwait(false); private async Task> ReadManyCoreAsync( - string endpointId, + CultMeshSessionTarget target, IReadOnlyList recordKeys, TimeSpan responseTimeout, CancellationToken cancellationToken) where TDocument : class { ThrowIfDisposed(); - if (string.IsNullOrWhiteSpace(endpointId)) throw new ArgumentException("Endpoint identity is required.", nameof(endpointId)); + if (target == null) throw new ArgumentNullException(nameof(target)); if (recordKeys == null || recordKeys.Count == 0 || recordKeys.Any(string.IsNullOrWhiteSpace)) throw new ArgumentException("At least one non-empty record key is required.", nameof(recordKeys)); var cacheRegistry = CultMesh.CreateCultCacheDocumentRegistry(typeof(TDocument)); var networkRegistry = CultMesh.CreateCultNetDocumentRegistry(new[] { typeof(TDocument) }, cacheRegistry); using var snapshot = await CultMeshSnapshotSession.ConnectAsync( _sessions, - CultMeshEndpointId.Parse(endpointId), + target, CultMeshProtocols.Content, new CultMeshSnapshotRequestOptions { @@ -577,13 +566,13 @@ namespace GameCult.Mesh } private async Task OpenDocumentAsync( - string endpointId, + CultMeshSessionTarget target, string recordKey, SharedResource owner) where TDocument : class { - var session = await ConnectAsync(endpointId, CultMeshProtocols.Documents).ConfigureAwait(false); - var binding = new RemoteDocumentBinding(session, endpointId, recordKey, _subscriptionResponseTimeout); + var session = await ConnectAsync(target, CultMeshProtocols.Documents).ConfigureAwait(false); + var binding = new RemoteDocumentBinding(session, target, recordKey, _subscriptionResponseTimeout); owner.Attach(binding); try { @@ -599,13 +588,13 @@ namespace GameCult.Mesh } private async Task OpenCollectionAsync( - string endpointId, + CultMeshSessionTarget target, bool includeInitialSnapshot, SharedResource owner) where TDocument : class { - var session = await ConnectAsync(endpointId, CultMeshProtocols.Documents).ConfigureAwait(false); - var binding = new RemoteCollectionBinding(session, endpointId, includeInitialSnapshot, _subscriptionResponseTimeout); + var session = await ConnectAsync(target, CultMeshProtocols.Documents).ConfigureAwait(false); + var binding = new RemoteCollectionBinding(session, target, includeInitialSnapshot, _subscriptionResponseTimeout); owner.Attach(binding); try { @@ -743,14 +732,14 @@ namespace GameCult.Mesh public RemoteDocumentBinding( CultMeshSession session, - string endpointId, + CultMeshSessionTarget target, string recordKey, TimeSpan responseTimeout) { _session = session; _responseTimeout = responseTimeout; _recordKey = recordKey; - _subscriptionId = "cultmesh-document:" + endpointId + ":" + recordKey; + _subscriptionId = "cultmesh-document:" + target.SessionKey + ":" + recordKey; var cacheRegistry = CultMesh.CreateCultCacheDocumentRegistry(typeof(TDocument)); var networkRegistry = CultMesh.CreateCultNetDocumentRegistry(new[] { typeof(TDocument) }, cacheRegistry); _cache = new CultCache(cacheRegistry); @@ -758,8 +747,8 @@ namespace GameCult.Mesh Handle = CultMesh.Document( _cache, new CultRecordKey(recordKey), - CultMesh.Verse(endpointId, "cultmesh-client").Context, - routeHint: new CultMeshRouteHint(CultMeshLocalityKind.Network, endpointId)); + CultMesh.Verse(target.VerseId, "cultmesh-client").Context, + routeHint: new CultMeshRouteHint(CultMeshLocalityKind.Network, target.ProviderRuntimeId)); } public CultMeshDocumentHandle Handle { get; } @@ -847,13 +836,13 @@ namespace GameCult.Mesh public RemoteCollectionBinding( CultMeshSession session, - string endpointId, + CultMeshSessionTarget target, bool includeInitialSnapshot, TimeSpan responseTimeout) { _session = session; _responseTimeout = responseTimeout; - _subscriptionId = "cultmesh-collection:" + endpointId + ":" + typeof(TDocument).FullName; + _subscriptionId = "cultmesh-collection:" + target.SessionKey + ":" + typeof(TDocument).FullName; _includeInitialSnapshot = includeInitialSnapshot; var cacheRegistry = CultMesh.CreateCultCacheDocumentRegistry(typeof(TDocument)); var networkRegistry = CultMesh.CreateCultNetDocumentRegistry(new[] { typeof(TDocument) }, cacheRegistry); @@ -861,7 +850,7 @@ namespace GameCult.Mesh _subscription = new CultNetDatabaseSubscriptionClient(session.OpenSchemaClient(), _cache, networkRegistry); Handle = CultMesh.Collection( _cache, - routeHint: new CultMeshRouteHint(CultMeshLocalityKind.Network, endpointId)); + routeHint: new CultMeshRouteHint(CultMeshLocalityKind.Network, target.ProviderRuntimeId)); } public CultMeshCollectionHandle Handle { get; } diff --git a/src/GameCult.Mesh/CultMeshContentTransports.cs b/src/GameCult.Mesh/CultMeshContentTransports.cs index f1814b2c..3e2c54b1 100644 --- a/src/GameCult.Mesh/CultMeshContentTransports.cs +++ b/src/GameCult.Mesh/CultMeshContentTransports.cs @@ -52,18 +52,18 @@ namespace GameCult.Mesh private bool _disposed; internal CultMeshContentSession( - CultMeshEndpointId endpointId, + CultMeshSessionTarget target, ICultMeshContentTransport transport, CultMeshSessionState state, Action onTransportFailure) { - EndpointId = endpointId ?? throw new ArgumentNullException(nameof(endpointId)); + Target = target ?? throw new ArgumentNullException(nameof(target)); _transport = transport ?? throw new ArgumentNullException(nameof(transport)); State = state ?? throw new ArgumentNullException(nameof(state)); _onTransportFailure = onTransportFailure ?? throw new ArgumentNullException(nameof(onTransportFailure)); } - public CultMeshEndpointId EndpointId { get; } + public CultMeshSessionTarget Target { get; } public CultMeshSessionState State { get; private set; } public string TransportId { get { lock (_gate) return _transport.TransportId; } } @@ -138,18 +138,18 @@ namespace GameCult.Mesh public sealed class CultMeshSessionContentProvider : ICultMeshContentProvider { private readonly CultMeshSessionManager _sessions; - private readonly CultMeshEndpointId _endpointId; + private readonly CultMeshSessionTarget _target; public CultMeshSessionContentProvider( string providerId, CultMeshSessionManager sessions, - CultMeshEndpointId endpointId) + CultMeshSessionTarget target) { ProviderId = string.IsNullOrWhiteSpace(providerId) ? throw new ArgumentException("Provider identity is required.", nameof(providerId)) : providerId; _sessions = sessions ?? throw new ArgumentNullException(nameof(sessions)); - _endpointId = endpointId ?? throw new ArgumentNullException(nameof(endpointId)); + _target = target ?? throw new ArgumentNullException(nameof(target)); } public string ProviderId { get; } @@ -159,7 +159,7 @@ namespace GameCult.Mesh Stream destination, CancellationToken cancellationToken = default) { - var session = await _sessions.ConnectContentAsync(_endpointId, cancellationToken).ConfigureAwait(false); + var session = await _sessions.ConnectContentAsync(_target, cancellationToken).ConfigureAwait(false); await session.CopyChunkToAsync(chunk, destination, cancellationToken).ConfigureAwait(false); } } diff --git a/src/GameCult.Mesh/CultMeshDiscoveryService.cs b/src/GameCult.Mesh/CultMeshDiscoveryService.cs index 5e8c43b8..93ea6a84 100644 --- a/src/GameCult.Mesh/CultMeshDiscoveryService.cs +++ b/src/GameCult.Mesh/CultMeshDiscoveryService.cs @@ -33,16 +33,25 @@ namespace GameCult.Mesh public sealed class CultMeshDiscoveryQuery { - public CultMeshDiscoveryQuery(string endpointId, IEnumerable? verseIds = null) + /// Stable lookup identity used for caching and diagnostics, never a physical route. + /// Optional Verse filter. + /// Optional provider runtime that each accepted Verse must advertise. + public CultMeshDiscoveryQuery( + string endpointId, + IEnumerable? verseIds = null, + string? authorityRuntimeId = null) { EndpointId = Require(endpointId, nameof(endpointId)); VerseIds = verseIds?.Where(value => !string.IsNullOrWhiteSpace(value)) .Distinct(StringComparer.Ordinal).OrderBy(value => value, StringComparer.Ordinal).ToArray() ?? Array.Empty(); + AuthorityRuntimeId = string.IsNullOrWhiteSpace(authorityRuntimeId) ? null : authorityRuntimeId.Trim(); } public string EndpointId { get; } public IReadOnlyList VerseIds { get; } + /// Gets the optional provider runtime constraint for authority-sensitive resolution. + public string? AuthorityRuntimeId { get; } private static string Require(string value, string name) => string.IsNullOrWhiteSpace(value) ? throw new ArgumentException("Value must be non-empty.", name) : value; @@ -219,9 +228,11 @@ namespace GameCult.Mesh } private static string QueryKey(CultMeshDiscoveryQuery query) => - query.VerseIds.Count == 0 + query.AuthorityRuntimeId == null && query.VerseIds.Count == 0 ? query.EndpointId - : query.EndpointId + "\u001f" + string.Join("\u001f", query.VerseIds); + : string.Join( + "\u001f", + new[] { query.EndpointId, query.AuthorityRuntimeId ?? "" }.Concat(query.VerseIds)); private static async Task AwaitForCallerAsync(Task shared, CancellationToken cancellationToken) { @@ -255,6 +266,8 @@ namespace GameCult.Mesh var failures = results.Where(result => result.Error != null).Select(result => result.SourceId).ToArray(); var observations = results.SelectMany(result => result.Observations) .Where(observation => query.VerseIds.Count == 0 || query.VerseIds.Contains(observation.Candidate.VerseId, StringComparer.Ordinal)) + .Where(observation => query.AuthorityRuntimeId == null || + observation.Candidate.AuthorityRuntimeIds.Contains(query.AuthorityRuntimeId, StringComparer.Ordinal)) .ToArray(); foreach (var rejected in observations.Where(observation => observation.Trust == CultMeshDiscoveryTrust.Rejected)) diff --git a/src/GameCult.Mesh/CultMeshPeerExchange.cs b/src/GameCult.Mesh/CultMeshPeerExchange.cs index 2489ebac..c3045c0d 100644 --- a/src/GameCult.Mesh/CultMeshPeerExchange.cs +++ b/src/GameCult.Mesh/CultMeshPeerExchange.cs @@ -446,15 +446,17 @@ namespace GameCult.Mesh /// Fetches peer cards through the shared session owner. public async Task FetchAsync( - CultMeshEndpointId endpointId, + CultMeshSessionTarget target, CultMeshPeerExchangeRequestMessage request, CancellationToken cancellationToken = default) { - if (endpointId == null) throw new ArgumentNullException(nameof(endpointId)); + if (target == null) throw new ArgumentNullException(nameof(target)); if (request == null) throw new ArgumentNullException(nameof(request)); if (string.IsNullOrWhiteSpace(request.VerseId)) throw new ArgumentException("Peer exchange requires a verseId.", nameof(request)); + if (!string.Equals(request.VerseId, target.VerseId, StringComparison.Ordinal)) + throw new ArgumentException("Peer exchange request Verse must match its session target.", nameof(request)); var sessions = _options.Sessions ?? throw new InvalidOperationException("Managed peer exchange requires a CultMeshSessionManager."); - var session = await sessions.ConnectAsync(endpointId, CultMeshProtocols.PeerExchange, cancellationToken).ConfigureAwait(false); + var session = await sessions.ConnectAsync(target, CultMeshProtocols.PeerExchange, cancellationToken).ConfigureAwait(false); var messageId = Guid.NewGuid().ToString("N"); var completion = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); using var responseSubscription = session.OnCultNet(response => @@ -471,7 +473,7 @@ namespace GameCult.Mesh KnownPeerIds = request.KnownPeerIds, Limit = request.Limit }); - return await WaitForManagedResponseAsync(completion.Task, endpointId, cancellationToken).ConfigureAwait(false); + return await WaitForManagedResponseAsync(completion.Task, target, cancellationToken).ConfigureAwait(false); } /// @@ -541,7 +543,7 @@ namespace GameCult.Mesh private async Task WaitForManagedResponseAsync( Task responseTask, - CultMeshEndpointId endpointId, + CultMeshSessionTarget target, CancellationToken cancellationToken) { var timeout = _options.Clock.DelayAsync(_options.ResponseTimeout, cancellationToken); @@ -549,7 +551,7 @@ namespace GameCult.Mesh if (completed != responseTask) { cancellationToken.ThrowIfCancellationRequested(); - throw new TimeoutException($"Timed out waiting for peer exchange response from {endpointId}."); + throw new TimeoutException($"Timed out waiting for peer exchange response from {target}."); } return await responseTask.ConfigureAwait(false); } diff --git a/src/GameCult.Mesh/CultMeshRealtimeTransports.cs b/src/GameCult.Mesh/CultMeshRealtimeTransports.cs index d087b304..7b32ad6a 100644 --- a/src/GameCult.Mesh/CultMeshRealtimeTransports.cs +++ b/src/GameCult.Mesh/CultMeshRealtimeTransports.cs @@ -72,18 +72,18 @@ namespace GameCult.Mesh private bool _disposed; internal CultMeshRealtimeSession( - CultMeshEndpointId endpointId, + CultMeshSessionTarget target, ICultMeshRealtimeTransport transport, CultMeshSessionState state, Action onTransportFailure) { - EndpointId = endpointId ?? throw new ArgumentNullException(nameof(endpointId)); + Target = target ?? throw new ArgumentNullException(nameof(target)); _transport = transport ?? throw new ArgumentNullException(nameof(transport)); State = state ?? throw new ArgumentNullException(nameof(state)); _onTransportFailure = onTransportFailure ?? throw new ArgumentNullException(nameof(onTransportFailure)); } - public CultMeshEndpointId EndpointId { get; } + public CultMeshSessionTarget Target { get; } public CultMeshSessionState State { get; private set; } public string TransportId { get { lock (_gate) return _transport.TransportId; } } diff --git a/src/GameCult.Mesh/CultMeshSessions.cs b/src/GameCult.Mesh/CultMeshSessions.cs index 54a19fe8..c562de83 100644 --- a/src/GameCult.Mesh/CultMeshSessions.cs +++ b/src/GameCult.Mesh/CultMeshSessions.cs @@ -21,6 +21,40 @@ namespace GameCult.Mesh public override string ToString() => Value; } + /// + /// Identifies one provider inside one Verse. Odin resolves this stable pair to + /// disposable physical routes; neither value is a socket address. + /// + public sealed class CultMeshSessionTarget : IEquatable + { + /// Creates one stable provider target inside one Verse. + public CultMeshSessionTarget(string verseId, string providerRuntimeId) + { + VerseId = string.IsNullOrWhiteSpace(verseId) + ? throw new ArgumentException("Verse identity is required.", nameof(verseId)) + : verseId.Trim(); + ProviderEndpointId = CultMeshEndpointId.Parse(providerRuntimeId); + ProviderRuntimeId = ProviderEndpointId.Value; + } + + /// Gets the stable Verse identity. + public string VerseId { get; } + /// Gets the stable provider runtime identity advertised by that Verse. + public string ProviderRuntimeId { get; } + internal CultMeshEndpointId ProviderEndpointId { get; } + internal string SessionKey => VerseId + "\u001f" + ProviderRuntimeId; + + public bool Equals(CultMeshSessionTarget? other) => + other != null && + string.Equals(VerseId, other.VerseId, StringComparison.Ordinal) && + string.Equals(ProviderRuntimeId, other.ProviderRuntimeId, StringComparison.Ordinal); + public override bool Equals(object? obj) => Equals(obj as CultMeshSessionTarget); + public override int GetHashCode() => HashCode.Combine( + StringComparer.Ordinal.GetHashCode(VerseId), + StringComparer.Ordinal.GetHashCode(ProviderRuntimeId)); + public override string ToString() => VerseId + "/" + ProviderRuntimeId; + } + public sealed class CultMeshProtocolId : IEquatable { public CultMeshProtocolId(string value) { Value = string.IsNullOrWhiteSpace(value) ? throw new ArgumentException("Protocol identity is required.", nameof(value)) : value; } @@ -285,14 +319,14 @@ namespace GameCult.Mesh private readonly ManagedSchemaChannel _channel; private long _physicalGeneration; private bool _disposed; - internal CultMeshSession(CultMeshEndpointId endpointId, CultMeshProtocolId protocol, ICultNetSchemaClient channel, CultMeshSessionState state) + internal CultMeshSession(CultMeshSessionTarget target, CultMeshProtocolId protocol, ICultNetSchemaClient channel, CultMeshSessionState state) { - EndpointId = endpointId; + Target = target; Protocol = protocol; _channel = new ManagedSchemaChannel(channel); State = state; } - public CultMeshEndpointId EndpointId { get; } + public CultMeshSessionTarget Target { get; } public CultMeshProtocolId Protocol { get; } internal ICultNetSchemaClient Channel => _channel; public CultMeshSessionState State { get; private set; } @@ -550,18 +584,18 @@ namespace GameCult.Mesh } public async Task ConnectAsync( - CultMeshEndpointId endpointId, + CultMeshSessionTarget target, CultMeshProtocolId protocol, CancellationToken cancellationToken = default) { - if (endpointId == null) throw new ArgumentNullException(nameof(endpointId)); + if (target == null) throw new ArgumentNullException(nameof(target)); if (protocol == null) throw new ArgumentNullException(nameof(protocol)); ThrowIfDisposed(); - var key = endpointId.Value + "\u001f" + protocol.Value; + var key = target.SessionKey + "\u001f" + protocol.Value; while (true) { var lazy = _sessions.GetOrAdd(key, _ => new Lazy>( - () => ConnectOwnedAsync(key, endpointId, protocol), LazyThreadSafetyMode.ExecutionAndPublication)); + () => ConnectOwnedAsync(key, target, protocol), LazyThreadSafetyMode.ExecutionAndPublication)); try { var session = await AwaitForCallerAsync(lazy.Value, cancellationToken).ConfigureAwait(false); @@ -577,20 +611,20 @@ namespace GameCult.Mesh } /// - /// Connects one reusable streaming content plane by stable endpoint identity. + /// Connects one reusable streaming content plane by stable Verse/provider identity. /// Preferred connector tiers are exhausted before legacy fallback tiers are attempted. /// public async Task ConnectContentAsync( - CultMeshEndpointId endpointId, + CultMeshSessionTarget target, CancellationToken cancellationToken = default) { - if (endpointId == null) throw new ArgumentNullException(nameof(endpointId)); + if (target == null) throw new ArgumentNullException(nameof(target)); ThrowIfDisposed(); - var key = endpointId.Value; + var key = target.SessionKey; while (true) { var lazy = _contentSessions.GetOrAdd(key, _ => new Lazy>( - () => ConnectContentOwnedAsync(key, endpointId), LazyThreadSafetyMode.ExecutionAndPublication)); + () => ConnectContentOwnedAsync(key, target), LazyThreadSafetyMode.ExecutionAndPublication)); try { var session = await AwaitForCallerAsync(lazy.Value, cancellationToken).ConfigureAwait(false); @@ -607,19 +641,19 @@ namespace GameCult.Mesh private async Task ConnectContentOwnedAsync( string key, - CultMeshEndpointId endpointId) + CultMeshSessionTarget target) { - var result = await ResolveContentPathAsync(endpointId).ConfigureAwait(false); + var result = await ResolveContentPathAsync(target).ConfigureAwait(false); var session = new CultMeshContentSession( - endpointId, + target, result.Transport, new CultMeshSessionState(CultMeshSessionStatus.Online, _options.Clock.UtcNow, result.Candidate), failed => InvalidateContentSession(key, failed)); - Emit(endpointId, CultMeshProtocols.Content, "online", result.Candidate.Endpoint); + Emit(target, CultMeshProtocols.Content, "online", result.Candidate.Endpoint); return session; } - private async Task ResolveContentPathAsync(CultMeshEndpointId endpointId) + private async Task ResolveContentPathAsync(CultMeshSessionTarget target) { if (_contentConnectors.Length == 0) throw Failure( @@ -627,8 +661,9 @@ namespace GameCult.Mesh "No streaming content connectors are configured. Register the TCP content connector or the explicit legacy RUDP connector."); var discovery = await _discovery.ResolveAsync(new CultMeshDiscoveryQuery( - endpointId.Value, - new[] { endpointId.Value })).ConfigureAwait(false); + target.ProviderRuntimeId, + new[] { target.VerseId }, + target.ProviderRuntimeId)).ConfigureAwait(false); var candidates = discovery.Candidates .SelectMany(candidate => candidate.Descriptor.DiscoveryEndpoints) .Distinct(StringComparer.Ordinal) @@ -644,13 +679,13 @@ namespace GameCult.Mesh if (routes.Length == 0) throw Failure( CultMeshSessionFailureReason.UnsupportedPath, - $"No streaming content connector supports an advertised route for '{endpointId}'."); + $"No streaming content connector supports an advertised route for '{target}'."); var failures = new List(); foreach (var tier in routes.GroupBy(route => route.Connector.Priority).OrderBy(group => group.Key)) { var attempts = tier.Take(_options.MaxRacedCandidates) - .Select(route => ConnectContentCandidateAsync(endpointId, route)) + .Select(route => ConnectContentCandidateAsync(target.ProviderEndpointId, route)) .ToList(); while (attempts.Count > 0) { @@ -676,7 +711,7 @@ namespace GameCult.Mesh var last = failures.LastOrDefault(); throw Failure( last is TimeoutException ? CultMeshSessionFailureReason.Timeout : CultMeshSessionFailureReason.Transport, - $"No streaming content path connected for '{endpointId}'.", + $"No streaming content path connected for '{target}'.", last); } @@ -701,7 +736,7 @@ namespace GameCult.Mesh if (_contentSessions.TryRemove(key, out var removed) && removed.IsValueCreated && removed.Value.Status == TaskStatus.RanToCompletion) removed.Value.Result.Dispose(); - Emit(session.EndpointId, CultMeshProtocols.Content, "offline", session.State.Path?.Endpoint ?? string.Empty); + Emit(session.Target, CultMeshProtocols.Content, "offline", session.State.Path?.Endpoint ?? string.Empty); } /// @@ -709,16 +744,16 @@ namespace GameCult.Mesh /// register QUIC explicitly, while RUDP compatibility remains opt-in. /// public async Task ConnectRealtimeAsync( - CultMeshEndpointId endpointId, + CultMeshSessionTarget target, CancellationToken cancellationToken = default) { - if (endpointId == null) throw new ArgumentNullException(nameof(endpointId)); + if (target == null) throw new ArgumentNullException(nameof(target)); ThrowIfDisposed(); - var key = endpointId.Value; + var key = target.SessionKey; while (true) { var lazy = _realtimeSessions.GetOrAdd(key, _ => new Lazy>( - () => ConnectRealtimeOwnedAsync(key, endpointId), LazyThreadSafetyMode.ExecutionAndPublication)); + () => ConnectRealtimeOwnedAsync(key, target), LazyThreadSafetyMode.ExecutionAndPublication)); try { var session = await AwaitForCallerAsync(lazy.Value, cancellationToken).ConfigureAwait(false); @@ -735,19 +770,19 @@ namespace GameCult.Mesh private async Task ConnectRealtimeOwnedAsync( string key, - CultMeshEndpointId endpointId) + CultMeshSessionTarget target) { - var result = await ResolveRealtimePathAsync(endpointId).ConfigureAwait(false); + var result = await ResolveRealtimePathAsync(target).ConfigureAwait(false); var session = new CultMeshRealtimeSession( - endpointId, + target, result.Transport, new CultMeshSessionState(CultMeshSessionStatus.Online, _options.Clock.UtcNow, result.Candidate), failed => InvalidateRealtimeSession(key, failed)); - Emit(endpointId, CultMeshProtocols.RealtimeState, "online", result.Candidate.Endpoint); + Emit(target, CultMeshProtocols.RealtimeState, "online", result.Candidate.Endpoint); return session; } - private async Task ResolveRealtimePathAsync(CultMeshEndpointId endpointId) + private async Task ResolveRealtimePathAsync(CultMeshSessionTarget target) { if (_realtimeConnectors.Length == 0) throw Failure( @@ -755,8 +790,9 @@ namespace GameCult.Mesh "No realtime state connectors are configured. Register a QUIC connector explicitly."); var discovery = await _discovery.ResolveAsync(new CultMeshDiscoveryQuery( - endpointId.Value, - new[] { endpointId.Value })).ConfigureAwait(false); + target.ProviderRuntimeId, + new[] { target.VerseId }, + target.ProviderRuntimeId)).ConfigureAwait(false); var routes = discovery.Candidates .SelectMany(candidate => candidate.Descriptor.DiscoveryEndpoints) .Distinct(StringComparer.Ordinal) @@ -770,13 +806,13 @@ namespace GameCult.Mesh if (routes.Length == 0) throw Failure( CultMeshSessionFailureReason.UnsupportedPath, - $"No realtime connector supports an advertised route for '{endpointId}'."); + $"No realtime connector supports an advertised route for '{target}'."); var failures = new List(); foreach (var tier in routes.GroupBy(route => route.Connector.Priority).OrderBy(group => group.Key)) { var attempts = tier.Take(_options.MaxRacedCandidates) - .Select(route => ConnectRealtimeCandidateAsync(endpointId, route)) + .Select(route => ConnectRealtimeCandidateAsync(target.ProviderEndpointId, route)) .ToList(); while (attempts.Count > 0) { @@ -802,7 +838,7 @@ namespace GameCult.Mesh var last = failures.LastOrDefault(); throw Failure( last is TimeoutException ? CultMeshSessionFailureReason.Timeout : CultMeshSessionFailureReason.Transport, - $"No realtime state path connected for '{endpointId}'.", + $"No realtime state path connected for '{target}'.", last); } @@ -828,24 +864,25 @@ namespace GameCult.Mesh if (_realtimeSessions.TryRemove(key, out var removed) && removed.IsValueCreated && removed.Value.Status == TaskStatus.RanToCompletion) removed.Value.Result.Dispose(); - Emit(session.EndpointId, CultMeshProtocols.RealtimeState, "offline", endpoint); + Emit(session.Target, CultMeshProtocols.RealtimeState, "offline", endpoint); } - private async Task ConnectOwnedAsync(string key, CultMeshEndpointId endpointId, CultMeshProtocolId protocol) + private async Task ConnectOwnedAsync(string key, CultMeshSessionTarget target, CultMeshProtocolId protocol) { - var result = await ResolveConnectedPathAsync(endpointId, protocol).ConfigureAwait(false); - var session = new CultMeshSession(endpointId, protocol, result.Client, + var result = await ResolveConnectedPathAsync(target, protocol).ConfigureAwait(false); + var session = new CultMeshSession(target, protocol, result.Client, new CultMeshSessionState(CultMeshSessionStatus.Online, _options.Clock.UtcNow, result.Candidate)); ObservePhysicalFailure(key, session, result); - Emit(endpointId, protocol, "online", result.Candidate.Endpoint); + Emit(target, protocol, "online", result.Candidate.Endpoint); return session; } - private async Task ResolveConnectedPathAsync(CultMeshEndpointId endpointId, CultMeshProtocolId protocol) + private async Task ResolveConnectedPathAsync(CultMeshSessionTarget target, CultMeshProtocolId protocol) { var discovery = await _discovery.ResolveAsync(new CultMeshDiscoveryQuery( - endpointId.Value, - new[] { endpointId.Value })).ConfigureAwait(false); + target.ProviderRuntimeId, + new[] { target.VerseId }, + target.ProviderRuntimeId)).ConfigureAwait(false); var candidates = discovery.Candidates.SelectMany(candidate => candidate.Descriptor.DiscoveryEndpoints) .Distinct(StringComparer.Ordinal) .Select(endpoint => new CultMeshTransportCandidate(endpoint)) @@ -858,14 +895,14 @@ namespace GameCult.Mesh .ThenBy(route => route.Candidate.Priority) .ToArray(); if (candidates.Length == 0) - throw Failure(CultMeshSessionFailureReason.Resolution, $"No route candidates for '{endpointId}'."); + throw Failure(CultMeshSessionFailureReason.Resolution, $"No route candidates for '{target}'."); if (routes.Length == 0) throw Failure( CultMeshSessionFailureReason.Transport, - $"No transport path connected for '{endpointId}' and protocol '{protocol}'.", + $"No transport path connected for '{target}' and protocol '{protocol}'.", Failure( CultMeshSessionFailureReason.UnsupportedPath, - $"No registered connector supports an advertised route for '{endpointId}'.")); + $"No registered connector supports an advertised route for '{target}'.")); var failures = new List(); foreach (var tier in routes.GroupBy(route => route.Connector.Priority).OrderBy(group => group.Key)) @@ -889,7 +926,7 @@ namespace GameCult.Mesh } var last = failures.LastOrDefault(); throw Failure(last is TimeoutException ? CultMeshSessionFailureReason.Timeout : CultMeshSessionFailureReason.Transport, - $"No transport path connected for '{endpointId}' and protocol '{protocol}'.", last); + $"No transport path connected for '{target}' and protocol '{protocol}'.", last); } private void ObservePhysicalFailure(string key, CultMeshSession session, ConnectedPath path) @@ -919,20 +956,21 @@ namespace GameCult.Mesh _options.Clock.UtcNow, failedPath.Candidate, failure)); - Emit(session.EndpointId, session.Protocol, "reconnecting", failedPath.Candidate.Endpoint); + Emit(session.Target, session.Protocol, "reconnecting", failedPath.Candidate.Endpoint); try { _discovery.Invalidate(new CultMeshDiscoveryQuery( - session.EndpointId.Value, - new[] { session.EndpointId.Value })); - var replacement = await ResolveConnectedPathAsync(session.EndpointId, session.Protocol).ConfigureAwait(false); + session.Target.ProviderRuntimeId, + new[] { session.Target.VerseId }, + session.Target.ProviderRuntimeId)); + var replacement = await ResolveConnectedPathAsync(session.Target, session.Protocol).ConfigureAwait(false); session.ReplacePhysicalChannel(replacement.Client); session.Transition(new CultMeshSessionState( CultMeshSessionStatus.Online, _options.Clock.UtcNow, replacement.Candidate)); ObservePhysicalFailure(key, session, replacement); - Emit(session.EndpointId, session.Protocol, "online", replacement.Candidate.Endpoint); + Emit(session.Target, session.Protocol, "online", replacement.Candidate.Endpoint); } catch (Exception reconnectError) { @@ -945,7 +983,7 @@ namespace GameCult.Mesh reconnectError.Message, failedPath.Candidate.Endpoint))); _sessions.TryRemove(key, out _); - Emit(session.EndpointId, session.Protocol, "offline", failedPath.Candidate.Endpoint); + Emit(session.Target, session.Protocol, "offline", failedPath.Candidate.Endpoint); } } @@ -970,12 +1008,12 @@ namespace GameCult.Mesh private CultMeshSessionException Failure(CultMeshSessionFailureReason reason, string message, Exception? inner = null) => new CultMeshSessionException(new CultMeshSessionFailure(reason, message), inner); - private void Emit(CultMeshEndpointId endpoint, CultMeshProtocolId protocol, string state, string path) + private void Emit(CultMeshSessionTarget target, CultMeshProtocolId protocol, string state, string path) { _options.Diagnostics.Emit(new CultMeshDiagnosticEvent( Interlocked.Increment(ref _diagnosticSequence), _options.Clock.UtcNow, CultMeshReliabilityOrgan.Session, CultMeshDiagnosticKind.PathChanged, - endpoint.Value + ":" + protocol.Value, endpoint.Value, state, + target.SessionKey + ":" + protocol.Value, target.ProviderRuntimeId, state, sourceId: "session-manager", endpoint: path)); } diff --git a/src/GameCult.Mesh/CultMeshSnapshots.cs b/src/GameCult.Mesh/CultMeshSnapshots.cs index 03fc4aad..cff94fa4 100644 --- a/src/GameCult.Mesh/CultMeshSnapshots.cs +++ b/src/GameCult.Mesh/CultMeshSnapshots.cs @@ -102,7 +102,7 @@ namespace GameCult.Mesh CultNetDocumentRegistry? registry) { _sharedSession = session ?? throw new ArgumentNullException(nameof(session)); - _endpoint = session.State.Path?.Endpoint ?? session.EndpointId.Value; + _endpoint = session.State.Path?.Endpoint ?? session.Target.ProviderRuntimeId; _defaults = CultMesh.CloneSnapshotRequestOptions(options); _registry = registry ?? new CultNetDocumentRegistry(); _client = session.Channel; @@ -112,26 +112,26 @@ namespace GameCult.Mesh public static async Task ConnectAsync( CultMeshSessionManager sessions, - CultMeshEndpointId endpointId, + CultMeshSessionTarget target, CultMeshSnapshotRequestOptions options, CultNetDocumentRegistry? registry = null, CancellationToken cancellationToken = default) { if (sessions == null) throw new ArgumentNullException(nameof(sessions)); - var session = await sessions.ConnectAsync(endpointId, CultMeshProtocols.Documents, cancellationToken).ConfigureAwait(false); + var session = await sessions.ConnectAsync(target, CultMeshProtocols.Documents, cancellationToken).ConfigureAwait(false); return new CultMeshSnapshotSession(session, options ?? new CultMeshSnapshotRequestOptions(), registry); } public static async Task ConnectAsync( CultMeshSessionManager sessions, - CultMeshEndpointId endpointId, + CultMeshSessionTarget target, CultMeshProtocolId protocol, CultMeshSnapshotRequestOptions options, CultNetDocumentRegistry? registry = null, CancellationToken cancellationToken = default) { if (sessions == null) throw new ArgumentNullException(nameof(sessions)); - var session = await sessions.ConnectAsync(endpointId, protocol, cancellationToken).ConfigureAwait(false); + var session = await sessions.ConnectAsync(target, protocol, cancellationToken).ConfigureAwait(false); return new CultMeshSnapshotSession(session, options ?? new CultMeshSnapshotRequestOptions(), registry); } diff --git a/src/GameCult.Mesh/docs/content-sessions.md b/src/GameCult.Mesh/docs/content-sessions.md index 1eae6b6c..313a21cf 100644 --- a/src/GameCult.Mesh/docs/content-sessions.md +++ b/src/GameCult.Mesh/docs/content-sessions.md @@ -15,9 +15,12 @@ The consumer creates a provider over its existing identity-first session manager, then gives that provider to the transfer owner: ```csharp +var target = new CultMeshSessionTarget( + "aetheria.public", + "service:aetheria.daemon"); var provider = mesh.ContentProvider( "aetheria.daemon", - "service:aetheria.daemon"); + target); var transfer = new CultMeshContentTransferService( transferStateCache, diff --git a/src/GameCult.Mesh/docs/getting-started/02-connect-by-identity.md b/src/GameCult.Mesh/docs/getting-started/02-connect-by-identity.md index 8dffffaa..5cf90a0e 100644 --- a/src/GameCult.Mesh/docs/getting-started/02-connect-by-identity.md +++ b/src/GameCult.Mesh/docs/getting-started/02-connect-by-identity.md @@ -1,21 +1,28 @@ # 2. Connect A Client By Stable Identity -Clients address a Verse session by stable identity. In this tutorial, -`sample.counter-provider` is the sole authority runtime Odin advertises for the -`sample.counter` Verse; neither identity is a socket address. Discovery owns -current physical candidates and the session manager owns connection reuse, -path rotation, and transport failure state. +Clients address a live session by stable Verse/provider identity. In this tutorial, +`sample.counter` is the Verse id and `sample.counter-provider` is the authority +runtime Odin currently advertises for it. Application clients pass that typed +pair, never a socket address and never one ambiguous string that might mean +either identity. A product may expose only a Verse choice to its user; its +selection owner then resolves the provider runtime from Odin's descriptor before +opening the session. Discovery owns the current physical routes, and the session +manager owns connection reuse, path rotation, and transport failure state. ```csharp using GameCult.Mesh; +var odinEndpoint = Environment.GetEnvironmentVariable("ODIN_ENDPOINT") + ?? throw new InvalidOperationException("Set ODIN_ENDPOINT to the configured rendezvous route."); +const string verseId = "sample.counter"; +var target = new CultMeshSessionTarget(verseId, "sample.counter-provider"); using var mesh = new CultMeshClient(new CultMeshClientOptions { - RendezvousEndpoints = new[] { "rudp://odin.gamecult.net:3076" } + RendezvousEndpoints = new[] { odinEndpoint } }); using var counterLease = await mesh.LeaseDocumentAsync( - "sample.counter", + target, "counter:main", cancellationToken); var counter = counterLease.Handle; @@ -40,7 +47,7 @@ protocol-level state or diagnostics: ```csharp var session = await mesh.ConnectAsync( - "aetheria.daemon", + target, CultMeshProtocols.Documents, cancellationToken); diff --git a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md index 4d5af0dc..265247b2 100644 --- a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md +++ b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md @@ -118,8 +118,8 @@ survive reopening the `.cc` store. The second layer runs a durable C# provider, a separate local Odin fixture, a real Chromium Eve lowerer, and an independent C# headless observer over binary -CultNet WebSocket lanes. The open browser resolves provider identity through -the canonical Verse catalog, survives a provider restart on a different route, +CultNet WebSocket lanes. The open browser resolves the `sample.counter` Verse +through the canonical catalog, survives its provider restarting on a different route, and resubscribes. The retained C# client then invokes a second typed operation through `CultMeshClient.InvokeAsync`; Chromium and C# observe the same provider-authored state and receipt chronology. The same retained C# session diff --git a/src/GameCult.Mesh/docs/getting-started/04-run-the-multiruntime-game.md b/src/GameCult.Mesh/docs/getting-started/04-run-the-multiruntime-game.md index a748368b..ba9888c3 100644 --- a/src/GameCult.Mesh/docs/getting-started/04-run-the-multiruntime-game.md +++ b/src/GameCult.Mesh/docs/getting-started/04-run-the-multiruntime-game.md @@ -8,8 +8,8 @@ The counter is now one small multiplayer game: invokes Increment; - an independent C# client leases the same counter and invokes through the same typed operation boundary; -- both clients remain attached when Odin moves the provider identity to a new - physical route. +- both clients remain attached when Odin moves the Verse to a replacement + physical provider route. Run the whole chronology from the CultLib checkout: diff --git a/src/GameCult.Mesh/docs/reliability-migration-plan.md b/src/GameCult.Mesh/docs/reliability-migration-plan.md index 658d5e0a..47e1b190 100644 --- a/src/GameCult.Mesh/docs/reliability-migration-plan.md +++ b/src/GameCult.Mesh/docs/reliability-migration-plan.md @@ -101,8 +101,9 @@ state for inspection and compatibility. **Owner:** `CultMeshSessionManager`. -**Inputs:** stable endpoint identity, application protocol identity, discovery -candidate stream, transport connectors, path policy, clock, and retry policy. +**Inputs:** stable Verse/provider identity, application protocol identity, +discovery candidate stream, transport connectors, path policy, clock, and retry +policy. **Outputs:** a reusable `CultMeshSession` with typed connection state, chosen path, protocol channel, diagnostics, and watches for state/path changes. @@ -249,7 +250,7 @@ The target API is identity-first and watchable: ```csharp await using var session = await mesh.ConnectAsync( - CultMeshEndpointId.Parse("odin:yggdrasil"), + new CultMeshSessionTarget("yggdrasil.public", "odin:yggdrasil"), CultMeshProtocols.Documents, cancellationToken); diff --git a/src/GameCult.Mesh/docs/transport-planes.md b/src/GameCult.Mesh/docs/transport-planes.md index 314c55b4..39be9c59 100644 --- a/src/GameCult.Mesh/docs/transport-planes.md +++ b/src/GameCult.Mesh/docs/transport-planes.md @@ -9,9 +9,9 @@ be equally good at files, realtime state, and same-machine memory access. registered connector for each traffic class. A connector owns only its physical connection and byte movement. -**Inputs:** stable endpoint identity, advertised physical candidates, connector -support and priority, caller cancellation, and locality evidence for body -negotiation. +**Inputs:** stable Verse/provider identity, advertised physical candidates, +connector support and priority, caller cancellation, and locality evidence for +body negotiation. **Outputs:** diff --git a/tests/GameCult.Mesh.Quic.Tests/CultMeshQuicRealtimeTransportTests.cs b/tests/GameCult.Mesh.Quic.Tests/CultMeshQuicRealtimeTransportTests.cs index 1b481d28..8d90f147 100644 --- a/tests/GameCult.Mesh.Quic.Tests/CultMeshQuicRealtimeTransportTests.cs +++ b/tests/GameCult.Mesh.Quic.Tests/CultMeshQuicRealtimeTransportTests.cs @@ -79,11 +79,12 @@ public sealed class CultMeshQuicRealtimeTransportTests ServerCertificate = certificate }); var endpointId = CultMeshEndpointId.Parse("service:aetheria.daemon"); + var target = new CultMeshSessionTarget("aetheria", endpointId.Value); using var sessions = CreateSessions(server, out var validatedIdentity); CultMeshRealtimeSession session; try { - session = await sessions.ConnectRealtimeAsync(endpointId); + session = await sessions.ConnectRealtimeAsync(target); } catch when (server.BackgroundFailure.IsCompleted) { @@ -118,8 +119,9 @@ public sealed class CultMeshQuicRealtimeTransportTests ServerCertificate = certificate }); var endpointId = CultMeshEndpointId.Parse("service:aetheria.daemon"); + var target = new CultMeshSessionTarget("aetheria", endpointId.Value); using var sessions = CreateSessions(server, out _); - var session = await sessions.ConnectRealtimeAsync(endpointId); + var session = await sessions.ConnectRealtimeAsync(target); await WaitUntilAsync(() => server.ConnectionCount == 1); await server.BroadcastAsync(Frame(100, CultMeshRealtimeDelivery.LatestOnly, producerEpoch: 7)); @@ -147,8 +149,9 @@ public sealed class CultMeshQuicRealtimeTransportTests ServerCertificate = certificate }); var endpointId = CultMeshEndpointId.Parse("service:aetheria.daemon"); + var target = new CultMeshSessionTarget("aetheria", endpointId.Value); using var sessions = CreateSessions(server, out _); - var session = await sessions.ConnectRealtimeAsync(endpointId); + var session = await sessions.ConnectRealtimeAsync(target); Func send = () => session.SendAsync(Frame(1, CultMeshRealtimeDelivery.Unreliable)); @@ -244,7 +247,8 @@ public sealed class CultMeshQuicRealtimeTransportTests "Aetheria", CultMeshVerseAuthorityModel.OperatorCluster, new CultMeshVerseCompatibility("cultmesh.v1", "test"), - new[] { endpoint }), + new[] { endpoint }, + new[] { "service:aetheria.daemon" }), SourceId, now, now.AddMinutes(1), diff --git a/tests/GameCult.Mesh.Tests/CultMeshBodySessionTests.cs b/tests/GameCult.Mesh.Tests/CultMeshBodySessionTests.cs index c105ae06..bdf9928f 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshBodySessionTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshBodySessionTests.cs @@ -28,7 +28,7 @@ public sealed class CultMeshBodySessionTests using var discovery = new CultMeshDiscoveryService(new[] { new RouteSource() }); using var sessions = new CultMeshSessionManager(discovery, new[] { connector }); var provider = new CultMeshSessionBodyProvider( - "aetheria.daemon", sessions, CultMeshEndpointId.Parse("aetheria")); + "aetheria.daemon", sessions, new CultMeshSessionTarget("aetheria", "aetheria.daemon")); var received = await provider.FetchAsync(descriptor); @@ -69,7 +69,7 @@ public sealed class CultMeshBodySessionTests using var sessions = new CultMeshSessionManager(discovery, new ICultMeshTransportConnector[] { new CultMeshSchemaTransportConnector() }); var provider = new CultMeshSessionBodyProvider("aetheria.daemon", sessions, - CultMeshEndpointId.Parse("aetheria"), + new CultMeshSessionTarget("aetheria", "aetheria.daemon"), new CultMeshSessionBodyProviderOptions { ResponseTimeout = TimeSpan.FromSeconds(10) }); var elapsed = Stopwatch.StartNew(); @@ -146,7 +146,7 @@ public sealed class CultMeshBodySessionTests { new CultMeshDiscoveryObservation(new CultMeshVerseDescriptor("aetheria", "Aetheria", CultMeshVerseAuthorityModel.OperatorCluster, new CultMeshVerseCompatibility("cultmesh.v1", "rules"), - new[] { _endpoint }), SourceId, now, now.AddMinutes(1), CultMeshDiscoveryTrust.Signed) + new[] { _endpoint }, new[] { "aetheria.daemon" }), SourceId, now, now.AddMinutes(1), CultMeshDiscoveryTrust.Signed) }); } } diff --git a/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs b/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs index 82934a54..94194abd 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs @@ -13,6 +13,8 @@ namespace GameCult.Mesh.Tests; public sealed class CultMeshClientTests { + private static CultMeshSessionTarget Target => new("aetheria", "aetheria-daemon"); + [Test] public void Construction_RequiresOneRendezvousEndpoint() { @@ -41,16 +43,37 @@ public sealed class CultMeshClientTests Connectors = new[] { connector } }); - var first = await mesh.ConnectAsync("aetheria", CultMeshProtocols.Documents); - var second = await mesh.ConnectAsync("aetheria", CultMeshProtocols.Documents); + var first = await mesh.ConnectAsync(Target, CultMeshProtocols.Documents); + var second = await mesh.ConnectAsync(Target, CultMeshProtocols.Documents); first.Should().BeSameAs(second); - first.EndpointId.Value.Should().Be("aetheria"); + first.Target.Should().Be(Target); first.State.Path!.Endpoint.Should().Be("rudp://aetheria:3081"); discoveryClients.Should().Be(1); connector.ConnectCount.Should().Be(1); } + [Test] + public async Task Connect_RejectsProviderNotAdvertisedBySelectedVerseBeforeTransport() + { + var connector = new RecordingConnector(); + using var mesh = new CultMeshClient(new CultMeshClientOptions + { + RendezvousEndpoints = new[] { "rudp://odin:3076" }, + Discovery = new CultMeshVerseDiscoveryClientOptions { CreateClient = () => new RendezvousClient() }, + Connectors = new[] { connector } + }); + + Func connect = async () => await mesh.ConnectAsync( + new CultMeshSessionTarget("aetheria", "forged-provider"), + CultMeshProtocols.Documents); + + var failure = await connect.Should().ThrowAsync(); + failure.Which.Failure.Reason.Should().Be(CultMeshSessionFailureReason.Resolution); + connector.ConnectCount.Should().Be(0, + "a valid Verse route must not authorize an unadvertised provider identity"); + } + [Test] public async Task Document_ReplicatesTypedRecordBehindOneIntentDeclaration() { @@ -62,8 +85,8 @@ public sealed class CultMeshClientTests Connectors = new[] { connector } }); - using var firstLease = await mesh.LeaseDocumentAsync("aetheria", "surface:pilot"); - using var secondLease = await mesh.LeaseDocumentAsync("aetheria", "surface:pilot"); + using var firstLease = await mesh.LeaseDocumentAsync(Target, "surface:pilot"); + using var secondLease = await mesh.LeaseDocumentAsync(Target, "surface:pilot"); var first = firstLease.Handle; var second = secondLease.Handle; @@ -82,7 +105,7 @@ public sealed class CultMeshClientTests Discovery = new CultMeshVerseDiscoveryClientOptions { CreateClient = () => new RendezvousClient() }, Connectors = new[] { connector } }); - using var lease = await mesh.LeaseDocumentAsync("aetheria", "surface:pilot"); + using var lease = await mesh.LeaseDocumentAsync(Target, "surface:pilot"); var document = lease.Handle; connector.Clients[0].Fail(new InvalidOperationException("path lost")); @@ -105,7 +128,7 @@ public sealed class CultMeshClientTests Connectors = new[] { connector } }); - var opening = mesh.LeaseDocumentAsync("aetheria", "surface:pilot"); + var opening = mesh.LeaseDocumentAsync(Target, "surface:pilot"); await WaitUntilAsync(() => connector.Clients.Count == 1 && connector.Clients[0].SubscribeCount == 1); connector.Clients[0].Fail(new InvalidOperationException("path lost before initial snapshot")); @@ -129,7 +152,7 @@ public sealed class CultMeshClientTests SubscriptionResponseTimeout = TimeSpan.FromMilliseconds(20) }); - using var lease = await mesh.LeaseDocumentAsync("aetheria", "surface:pilot"); + using var lease = await mesh.LeaseDocumentAsync(Target, "surface:pilot"); var document = lease.Handle; (await document.LatestAsync()).Text.Should().Be("pilot surface 1"); @@ -148,7 +171,7 @@ public sealed class CultMeshClientTests Connectors = new[] { connector } }); - using var lease = await mesh.LeaseCollectionAsync("aetheria"); + using var lease = await mesh.LeaseCollectionAsync(Target); var collection = lease.Handle; (await collection.LatestAsync()).Should().ContainSingle() @@ -167,7 +190,7 @@ public sealed class CultMeshClientTests Connectors = new[] { connector } }); - var opening = mesh.LeaseCollectionAsync("aetheria"); + var opening = mesh.LeaseCollectionAsync(Target); await WaitUntilAsync(() => connector.Clients.Count == 1 && connector.Clients[0].SubscribeCount == 1); connector.Clients[0].Fail(new InvalidOperationException("path lost before initial collection snapshot")); @@ -191,8 +214,8 @@ public sealed class CultMeshClientTests Connectors = new[] { connector } }); - var first = await mesh.LeaseDocumentAsync("aetheria", "surface:pilot"); - var second = await mesh.LeaseDocumentAsync("aetheria", "surface:pilot"); + var first = await mesh.LeaseDocumentAsync(Target, "surface:pilot"); + var second = await mesh.LeaseDocumentAsync(Target, "surface:pilot"); mesh.ActiveDocumentResourceCount.Should().Be(1); first.Dispose(); @@ -200,7 +223,7 @@ public sealed class CultMeshClientTests second.Dispose(); mesh.ActiveDocumentResourceCount.Should().Be(0); - using var replacement = await mesh.LeaseDocumentAsync("aetheria", "surface:pilot"); + using var replacement = await mesh.LeaseDocumentAsync(Target, "surface:pilot"); replacement.Handle.Should().NotBeSameAs(first.Handle); connector.SubscribeCount.Should().Be(2); } @@ -220,7 +243,7 @@ public sealed class CultMeshClientTests for (var index = 0; index < leaseCount; index++) { var recordKey = "surface:churn:" + index; - using var lease = await mesh.LeaseDocumentAsync("aetheria", recordKey); + using var lease = await mesh.LeaseDocumentAsync(Target, recordKey); (await lease.Handle.LatestAsync()).Id.Should().Be(recordKey); } @@ -244,7 +267,7 @@ public sealed class CultMeshClientTests var request = new ClientTestDocument { Id = "command:1", Text = "move" }; await mesh.SubmitDocumentAsync( - "aetheria", + Target, request.Id, request, sourceRuntimeId: "pilot-one", @@ -269,7 +292,7 @@ public sealed class CultMeshClientTests }); var result = await mesh.InvokeAsync( - "aetheria", + Target, "tests.counter", "tests.counter.increment", "tests.counter.increment_request.v1", @@ -301,7 +324,7 @@ public sealed class CultMeshClientTests }); Func invoke = async () => await mesh.InvokeAsync( - "aetheria", + Target, "tests.counter", "tests.counter.increment", "wrong.request.v1", @@ -328,7 +351,7 @@ public sealed class CultMeshClientTests Discovery = new CultMeshVerseDiscoveryClientOptions { CreateClient = () => new RendezvousClient() }, Connectors = new[] { connector } }); - var opening = mesh.LeaseDocumentAsync("aetheria", "surface:pilot"); + var opening = mesh.LeaseDocumentAsync(Target, "surface:pilot"); await WaitUntilAsync(() => connector.Clients.Count == 1 && connector.Clients[0].SubscribeCount == 1); mesh.Dispose(); @@ -355,7 +378,8 @@ public sealed class CultMeshClientTests "Aetheria", CultMeshVerseAuthorityModel.OperatorCluster, new CultMeshVerseCompatibility("cultmesh.v0", "rules"), - new[] { "rudp://aetheria:3081" }).ToMessage() + new[] { "rudp://aetheria:3081" }, + new[] { "aetheria-daemon" }).ToMessage() } }; foreach (var handler in _handlers.ToArray()) handler(response); diff --git a/tests/GameCult.Mesh.Tests/CultMeshContentSessionTests.cs b/tests/GameCult.Mesh.Tests/CultMeshContentSessionTests.cs index c1a4d04b..d63254d1 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshContentSessionTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshContentSessionTests.cs @@ -52,7 +52,7 @@ public sealed class CultMeshContentSessionTests var provider = new CultMeshSessionContentProvider( "aetheria.daemon", sessions, - CultMeshEndpointId.Parse("aetheria")); + new CultMeshSessionTarget("aetheria", "aetheria.daemon")); using var transferState = new CultCache(CultMesh.CreateCultCacheDocumentRegistry( typeof(CultMeshContentTransferStateDocument))); var transfer = new CultMeshContentTransferService( @@ -114,7 +114,7 @@ public sealed class CultMeshContentSessionTests var provider = new CultMeshSessionContentProvider( "aetheria.daemon", sessions, - CultMeshEndpointId.Parse("aetheria")); + new CultMeshSessionTarget("aetheria", "aetheria.daemon")); using var transferState = new CultCache(CultMesh.CreateCultCacheDocumentRegistry( typeof(CultMeshContentTransferStateDocument))); var transfer = new CultMeshContentTransferService( @@ -196,7 +196,8 @@ public sealed class CultMeshContentSessionTests "Aetheria", CultMeshVerseAuthorityModel.OperatorCluster, new CultMeshVerseCompatibility("cultmesh.v1", "rules"), - new[] { _endpoint }), + new[] { _endpoint }, + new[] { "aetheria.daemon" }), SourceId, now, now.AddMinutes(1), diff --git a/tests/GameCult.Mesh.Tests/CultMeshDiscoveryServiceTests.cs b/tests/GameCult.Mesh.Tests/CultMeshDiscoveryServiceTests.cs index af6334f8..7d2938e4 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshDiscoveryServiceTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshDiscoveryServiceTests.cs @@ -263,6 +263,25 @@ public sealed class CultMeshDiscoveryServiceTests source.LookupCount.Should().Be(2); } + [Test] + public async Task Resolve_RejectsVerseRouteThatDoesNotAdvertiseRequestedProvider() + { + var clock = new ManualClock(new DateTimeOffset(2026, 8, 18, 0, 0, 0, TimeSpan.Zero)); + var source = new DelegateSource("odin", _ => Task.FromResult>( + new[] { Observation("aetheria", "odin", clock, TimeSpan.FromMinutes(1), CultMeshDiscoveryTrust.Signed) })); + using var service = new CultMeshDiscoveryService( + new[] { source }, + new CultMeshDiscoveryServiceOptions { Clock = clock }); + + var state = await service.ResolveAsync(new CultMeshDiscoveryQuery( + "forged-provider", + new[] { "aetheria" }, + "forged-provider")); + + state.Freshness.Should().Be(CultMeshDiscoveryFreshness.Unavailable); + state.Candidates.Should().BeEmpty(); + } + private static CultMeshDiscoveryObservation Observation( string verseId, string sourceId, @@ -275,7 +294,8 @@ public sealed class CultMeshDiscoveryServiceTests "Aetheria", CultMeshVerseAuthorityModel.OperatorCluster, new CultMeshVerseCompatibility("cultmesh.v0", "rules"), - new[] { endpoint }), + new[] { endpoint }, + new[] { "odin:aetheria", "odin:games", "aetheria" }), sourceId, clock.UtcNow, clock.UtcNow + ttl, diff --git a/tests/GameCult.Mesh.Tests/CultMeshSessionManagerTests.cs b/tests/GameCult.Mesh.Tests/CultMeshSessionManagerTests.cs index 4621c76b..fe9ec370 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshSessionManagerTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshSessionManagerTests.cs @@ -13,6 +13,8 @@ namespace GameCult.Mesh.Tests; public sealed class CultMeshSessionManagerTests { + private static CultMeshSessionTarget Target => new("aetheria", "aetheria-daemon"); + [Test] public async Task Connect_ResolvesOnlyTheRequestedVerseIdentity() { @@ -28,7 +30,7 @@ public sealed class CultMeshSessionManagerTests }); using var manager = new CultMeshSessionManager(discovery, new[] { connector }, new CultMeshSessionManagerOptions { Clock = clock }); - await manager.ConnectAsync(CultMeshEndpointId.Parse("aetheria"), CultMeshProtocols.Documents); + await manager.ConnectAsync(Target, CultMeshProtocols.Documents); connected.Should().NotBeNull(); connected!.Endpoint.Should().Be("rudp://aetheria:3076"); @@ -42,14 +44,14 @@ public sealed class CultMeshSessionManagerTests var release = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var connector = new FakeConnector(async (_, _) => { await release.Task; return new FakeSchemaClient(); }); using var manager = new CultMeshSessionManager(discovery, new[] { connector }, new CultMeshSessionManagerOptions { Clock = clock }); - var endpoint = CultMeshEndpointId.Parse("aetheria"); + var target = Target; - var first = manager.ConnectAsync(endpoint, CultMeshProtocols.Documents); - var second = manager.ConnectAsync(endpoint, CultMeshProtocols.Documents); + var first = manager.ConnectAsync(target, CultMeshProtocols.Documents); + var second = manager.ConnectAsync(target, CultMeshProtocols.Documents); await WaitUntilAsync(() => connector.ConnectCount == 1); release.TrySetResult(); var sessions = await Task.WhenAll(first, second); - var third = await manager.ConnectAsync(endpoint, CultMeshProtocols.Documents); + var third = await manager.ConnectAsync(target, CultMeshProtocols.Documents); sessions[0].Should().BeSameAs(sessions[1]).And.BeSameAs(third); connector.ConnectCount.Should().Be(1); @@ -70,7 +72,7 @@ public sealed class CultMeshSessionManagerTests }); using var manager = new CultMeshSessionManager(discovery, new[] { connector }, new CultMeshSessionManagerOptions { Clock = clock }); - var session = await manager.ConnectAsync(CultMeshEndpointId.Parse("aetheria"), CultMeshProtocols.Documents); + var session = await manager.ConnectAsync(Target, CultMeshProtocols.Documents); session.State.Path!.Endpoint.Should().Be("rudp://fast:3076"); slowRelease.TrySetResult(); await WaitUntilAsync(() => slowClient.DisposeCount == 1); @@ -91,10 +93,10 @@ public sealed class CultMeshSessionManagerTests }); using var manager = new CultMeshSessionManager(discovery, new[] { connector }, new CultMeshSessionManagerOptions { Clock = clock }); using var cancellation = new CancellationTokenSource(); - var endpoint = CultMeshEndpointId.Parse("aetheria"); + var target = Target; - var cancelled = manager.ConnectAsync(endpoint, CultMeshProtocols.Documents, cancellation.Token); - var survivor = manager.ConnectAsync(endpoint, CultMeshProtocols.Documents); + var cancelled = manager.ConnectAsync(target, CultMeshProtocols.Documents, cancellation.Token); + var survivor = manager.ConnectAsync(target, CultMeshProtocols.Documents); await WaitUntilAsync(() => connector.ConnectCount == 1); cancellation.Cancel(); Assert.ThrowsAsync(async () => await cancelled); @@ -118,8 +120,8 @@ public sealed class CultMeshSessionManagerTests return Task.FromResult(client); }); using var manager = new CultMeshSessionManager(discovery, new[] { connector }, new CultMeshSessionManagerOptions { Clock = clock }); - var endpoint = CultMeshEndpointId.Parse("aetheria"); - var first = await manager.ConnectAsync(endpoint, CultMeshProtocols.Documents); + var target = Target; + var first = await manager.ConnectAsync(target, CultMeshProtocols.Documents); var states = new List(); using var stateWatch = first.WatchState().Subscribe(state => states.Add(state.Status)); using var schemaLease = first.OpenSchemaClient(); @@ -130,7 +132,7 @@ public sealed class CultMeshSessionManagerTests route = "rudp://second:3076"; clients[0].Fail(new IOException("partition")); await WaitUntilAsync(() => first.State.Status == CultMeshSessionStatus.Online && connector.ConnectCount == 2); - var second = await manager.ConnectAsync(endpoint, CultMeshProtocols.Documents); + var second = await manager.ConnectAsync(target, CultMeshProtocols.Documents); clients[1].Emit(new CultNetErrorMessage { Error = "after rotation" }); second.Should().BeSameAs(first); @@ -165,7 +167,7 @@ public sealed class CultMeshSessionManagerTests using var manager = new CultMeshSessionManager(discovery, Array.Empty(), new CultMeshSessionManagerOptions { Clock = clock }); var error = Assert.ThrowsAsync(() => - manager.ConnectAsync(CultMeshEndpointId.Parse("aetheria"), CultMeshProtocols.Documents)); + manager.ConnectAsync(Target, CultMeshProtocols.Documents)); error!.Failure.Reason.Should().Be(CultMeshSessionFailureReason.Transport); error.InnerException.Should().BeOfType() @@ -180,9 +182,9 @@ public sealed class CultMeshSessionManagerTests var client = new RespondingSchemaClient(); var connector = new FakeConnector((_, _) => Task.FromResult(client)); using var manager = new CultMeshSessionManager(discovery, new[] { connector }, new CultMeshSessionManagerOptions { Clock = clock }); - var endpoint = CultMeshEndpointId.Parse("aetheria"); - using var first = await CultMeshSnapshotSession.ConnectAsync(manager, endpoint, new CultMeshSnapshotRequestOptions()); - using var second = await CultMeshSnapshotSession.ConnectAsync(manager, endpoint, new CultMeshSnapshotRequestOptions()); + var target = Target; + using var first = await CultMeshSnapshotSession.ConnectAsync(manager, target, new CultMeshSnapshotRequestOptions()); + using var second = await CultMeshSnapshotSession.ConnectAsync(manager, target, new CultMeshSnapshotRequestOptions()); (await first.FetchSnapshotAsync()).MessageId.Should().NotBeEmpty(); first.Dispose(); @@ -202,10 +204,10 @@ public sealed class CultMeshSessionManagerTests var connector = new FakeConnector((_, _) => Task.FromResult(client)); using var manager = new CultMeshSessionManager(discovery, new[] { connector }, new CultMeshSessionManagerOptions { Clock = clock }); var exchange = new CultMeshPeerExchangeClient(new CultMeshPeerExchangeClientOptions { Sessions = manager, Clock = clock }); - var endpoint = CultMeshEndpointId.Parse("aetheria"); + var target = Target; - var first = await exchange.FetchAsync(endpoint, new CultMeshPeerExchangeRequestMessage { VerseId = "aetheria" }); - var second = await exchange.FetchAsync(endpoint, new CultMeshPeerExchangeRequestMessage { VerseId = "aetheria" }); + var first = await exchange.FetchAsync(target, new CultMeshPeerExchangeRequestMessage { VerseId = "aetheria" }); + var second = await exchange.FetchAsync(target, new CultMeshPeerExchangeRequestMessage { VerseId = "aetheria" }); first.Peers.Single().PeerId.Should().Be("peer-a"); second.Peers.Single().PeerId.Should().Be("peer-a"); @@ -221,7 +223,7 @@ public sealed class CultMeshSessionManagerTests var client = new LeaseSchemaClient(); var connector = new FakeConnector((_, _) => Task.FromResult(client)); using var manager = new CultMeshSessionManager(discovery, new[] { connector }, new CultMeshSessionManagerOptions { Clock = clock }); - var session = await manager.ConnectAsync(CultMeshEndpointId.Parse("aetheria"), CultMeshProtocols.Subscriptions); + var session = await manager.ConnectAsync(Target, CultMeshProtocols.Subscriptions); using var first = session.OpenSchemaClient(); using var second = session.OpenSchemaClient(); var firstCount = 0; @@ -268,7 +270,7 @@ public sealed class CultMeshSessionManagerTests { new CultMeshDiscoveryObservation( new CultMeshVerseDescriptor("aetheria", "Aetheria", CultMeshVerseAuthorityModel.OperatorCluster, - new CultMeshVerseCompatibility("cultmesh.v0", "rules"), _endpoints()), + new CultMeshVerseCompatibility("cultmesh.v0", "rules"), _endpoints(), new[] { "aetheria-daemon" }), SourceId, _clock.UtcNow, _clock.UtcNow + _ttl, CultMeshDiscoveryTrust.Signed) }); } @@ -298,7 +300,8 @@ public sealed class CultMeshSessionManagerTests verseId, CultMeshVerseAuthorityModel.OperatorCluster, new CultMeshVerseCompatibility("cultmesh.v0", "rules"), - new[] { endpoint }), + new[] { endpoint }, + new[] { "aetheria-daemon" }), SourceId, _clock.UtcNow, expires, diff --git a/tests/GameCult.Mesh.Tests/CultMeshTransportModularityTests.cs b/tests/GameCult.Mesh.Tests/CultMeshTransportModularityTests.cs index 47eab18b..5fe32fed 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshTransportModularityTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshTransportModularityTests.cs @@ -39,7 +39,7 @@ public sealed class CultMeshTransportModularityTests }); var session = await sessions.ConnectAsync( - CultMeshEndpointId.Parse("aetheria"), + new CultMeshSessionTarget("aetheria", "aetheria.daemon"), CultMeshProtocols.Documents); var response = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); using var subscription = session.OnCultNet(message => response.TrySetResult(message)); @@ -77,7 +77,7 @@ public sealed class CultMeshTransportModularityTests new CultMeshTcpContentTransportConnector() }); - var session = await sessions.ConnectContentAsync(CultMeshEndpointId.Parse("aetheria")); + var session = await sessions.ConnectContentAsync(new CultMeshSessionTarget("aetheria", "aetheria.daemon")); using var destination = new MemoryStream(); await session.CopyChunkToAsync(artifact.Manifest.Chunks[0], destination); @@ -98,7 +98,7 @@ public sealed class CultMeshTransportModularityTests Array.Empty()); Func connect = async () => await sessions.ConnectContentAsync( - CultMeshEndpointId.Parse("aetheria")); + new CultMeshSessionTarget("aetheria", "aetheria.daemon")); await connect.Should().ThrowAsync() .WithMessage("*No streaming content connectors are configured*"); @@ -118,7 +118,7 @@ public sealed class CultMeshTransportModularityTests Array.Empty(), new ICultMeshRealtimeTransportConnector[] { connector }); var session = await sessions.ConnectRealtimeAsync( - CultMeshEndpointId.Parse("aetheria")); + new CultMeshSessionTarget("aetheria", "aetheria.daemon")); var sent = new CultMeshRealtimeFrame { ChannelId = "aetheria.entities", @@ -150,7 +150,7 @@ public sealed class CultMeshTransportModularityTests Array.Empty()); Func connect = async () => await sessions.ConnectRealtimeAsync( - CultMeshEndpointId.Parse("aetheria")); + new CultMeshSessionTarget("aetheria", "aetheria.daemon")); await connect.Should().ThrowAsync() .WithMessage("*No realtime state connectors are configured*"); @@ -176,7 +176,8 @@ public sealed class CultMeshTransportModularityTests "Aetheria", CultMeshVerseAuthorityModel.OperatorCluster, new CultMeshVerseCompatibility("cultmesh.v1", "rules"), - _endpoints), + _endpoints, + new[] { "aetheria.daemon" }), SourceId, now, now.AddMinutes(1), diff --git a/tools/GameCult.TransportParity/Program.cs b/tools/GameCult.TransportParity/Program.cs index 1d724631..04d7aafc 100644 --- a/tools/GameCult.TransportParity/Program.cs +++ b/tools/GameCult.TransportParity/Program.cs @@ -202,7 +202,8 @@ static async Task MeasureCultMeshQuicStateAsync(int payloadBytes, i { ValidateProviderCertificate = (_, _, _, _) => true })]); - var session = await sessions.ConnectRealtimeAsync(CultMeshEndpointId.Parse("service:parity.provider")); + var session = await sessions.ConnectRealtimeAsync( + new CultMeshSessionTarget("parity", "service:parity.provider")); var deadline = DateTime.UtcNow.AddSeconds(5); while (server.ConnectionCount == 0) { @@ -478,7 +479,8 @@ internal sealed class RouteSource(string endpoint) : ICultMeshLookupSource new( new CultMeshVerseDescriptor( "parity", "Transport parity", CultMeshVerseAuthorityModel.OperatorCluster, - new CultMeshVerseCompatibility("cultmesh.v1", "parity"), [endpoint]), + new CultMeshVerseCompatibility("cultmesh.v1", "parity"), [endpoint], + ["service:parity.provider"]), SourceId, now, now.AddMinutes(1), CultMeshDiscoveryTrust.Signed) ]; return Task.FromResult(observations); From b542f4b644dd792e1a00daefd6979429da68c4df Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 10:24:20 +0200 Subject: [PATCH 092/283] Publish the actual CultLib Unity 1.0.46 runtime --- .../Plugins/GameCult.Caching.MessagePack.dll | Bin 43520 -> 43520 bytes .../Plugins/GameCult.Caching.MessagePack.pdb | Bin 19940 -> 19940 bytes .../Runtime/Plugins/GameCult.Caching.dll | Bin 84992 -> 86016 bytes .../Runtime/Plugins/GameCult.Caching.pdb | Bin 29976 -> 30144 bytes .../Runtime/Plugins/GameCult.Logging.dll | Bin 6656 -> 6656 bytes .../Runtime/Plugins/GameCult.Logging.pdb | Bin 9480 -> 9480 bytes .../Plugins/GameCult.Mesh.Quic.Native.dll | Bin 15360 -> 15360 bytes .../Plugins/GameCult.Mesh.Quic.Native.pdb | Bin 12216 -> 12216 bytes .../Runtime/Plugins/GameCult.Mesh.dll | Bin 599552 -> 653312 bytes .../Runtime/Plugins/GameCult.Mesh.pdb | Bin 193928 -> 197240 bytes .../Runtime/Plugins/GameCult.Networking.dll | Bin 457216 -> 496128 bytes .../Runtime/Plugins/GameCult.Networking.pdb | Bin 230056 -> 235008 bytes 12 files changed, 0 insertions(+), 0 deletions(-) diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.dll index 3bdc5b9473584a3646a761d1786dcb70bc228719..d99d9ea668925dd8f9ce26829a8572d19106604f 100644 GIT binary patch delta 248 zcmZp;!qjkuX+j5!Q)t+MjXfHj0ztNOq}8}WOGvkQ$qto z^OO{`R7*o61_nh&2ARnl7RYSQp4ZFBa?)h= z+R1$}3p1P4ydDq>^F$-!Gpn@haL7-~g_DRoE(?gy;&N~;rVDpa! zUabDf4CV}`3wkm#u@Rz;o%Qy6=CVbd_vA(itnFXKZekY+#XS zXlk06YLaA@nrdNgnPhI9Y?Pd0l4fpdl9rlcY+#sT&cL9^$RIO$!vdMj+4FiCS(cqL zJUjW%`~ZQ?sSEg{it0QUZFik1Q7TzEIc7nP0#xwiBd8!yweJFzJqy|Wv*zc=p4hSZ z#{w@_e`5x71~Z0a1_K5QhC~KK22&tRWJqN&VMqdsrvjk`P=zIsXU<>@RA&UlDL~mY XAm0>BrvmxLK>db5+I;iGW%F%X9D19^wRS1pbA;6t1fh14Y> zP(w&k_oDP-R+`-v(Mm=$+pv$+*XWZKZBk?R01j9e3oHHe{n9TnX*%5NI6O#GxWHEY zup&nRh4lM=GLDDZe=sPo37(K)Er6l}1o7S`QM#7TYjhPchzE(4rLhDJcA&6j0^^hq zfs{Z&HGVff06Gm%##$%{tY-mJu4z)!v$tUgv^MW8;UfLVp7$Ni;X%vBRdC<2P;lGemml|D3mwrKwce5Yp9 zY?^2JOzUGhf6YhZf=={glIhVT&rXZu*+|W3dXn$%dmFrN)#g=PV?!~BBqm{8m270T zJNLnerM**^dq_IIGmU~e|rI5D$#9;gBst6e9G0KfqNC7c0LO9(SXnTngU zF%p6wZwE%zs04-=jjwN9AOuNr8K7wsgWk+FcWkYprbS_M9XJ=_{XD(!H kYybcO3lryo0Du4hq#_62;E?n}lYwQ#!c$B^v#TLFEU3>%Hvj+t delta 702 zcmV;v0zv)cn*rpT0g!wYvt^(UT5^6#qPInv7tDMts zjgXHU3NZ_ez!s26FJr7+HgHuQB7xac1pol8l-+6@F%X6C19^wRS1qk~?b?phBotDY zgg^r!N!^Rmi;;GAcZgOpn%RbZq`pRtU>L_lA_BRdC%zy(p@a!u2kp1fHg(%QVYgtPn~d){|6hX<{&ui&l|rRH?| zH@l_MkyQ@fe~_Y$sB8x>zwS)&C0A{# z3VwriOO8tK^Y<}TBi%N^)n8W*h`AC?KsXx*<_N9cIRCAGQ_6O7Ty1VuO{;& zJ37YkY=$&7e@8^e^S5R`v2ScKE$6doNyTI|F6O)Y-o#L}cJnGOv7r=1mXcs!WgD68 z&b?=Kw0G)q4@swYR-oe66J7;j4YB(a-QYD0YSopTB)K zT^sH$*vqbEac!)M72Dd771u86s#q7}@AEk`FL?p=x8Lu7-|R9opL5QfnK^T&+_`g~ z(+<8wIZCMj{{8fmQuiU|-vkMNJ?I2GH~v7bx+n5%?S0nNXKQC3H!oQ;zs*0kZSF}m zN6kI?WPd@;k;l}uEj+nq-pMsn_MK64l7I9ugK~1B{f+AByDBx+a@5U-4LCnt+S{sc zO_tTH)NYniVNG3rG}1LlcOq6QPtvxoHwmo2{5=dl==^ikoU2oI5)#bcb(YFTa{5u0nwh5kFL6zG)kQiCyhld9K?{yKbpi0@Q&3;Uhzhihz?TyzkW))hO~q@X&`FvifG9U*Lx$%StQpsXET z6KLpbJ1I$k5KI#!0Rjx8B_shtC{2(A2yi7WAqfy7X@Vp`h^7gWC}_63``qrRMYE)I zlVrIj$r4SHWtk*Pu|2dlk)nRvL(>u|YPP+8+D7eJK+-Hppa$qaO^^f#Icb6YDNq`Vb6C?pbewrYOMW(_m(j-|}Pb~}5;*voA!Zbk=AQYtuk^rGN zO_0QMMlJK3By*Z1^VlAGI+3DuPq`&PVjW39YiXJw2@uNC1WDXrx53==Qxvy7cuFEg zLEA%LB~ldW(Os3!DG8{mP7@@Nwh6hWnxyySkEg{Yf&6fLU0F$h0Ef{8Nr2EdO^^f# z@B%F%2@v|H36cPzE=`aG2=!@#B$WCYA7zD1m01;&WF<_J#oHd7Hj!dECdm?P5B{4- zQMYO7EFELu4InX)@(^)A5;7L7>v5vef8ALI>MRY6f~f?f+(4>P;$W&tVmCEN;!tX^ z#Nkx4#F5kxiKD5Z5@)4`Nt~S;E^$t31Y*{Jr7&hOj9Ct2mcy9kFlIT7Sq@{C!|>a_Nbk=y1~=0)n8s*g`T(XeRGFT| zGzO*XmRvMjrbDgc20vd59EPalcPO{6sieMR6%t+U0hV%;=%;91CpjL**T$0=NbSNXn3}){zBUmtn?f#QvKf=lSoniFCIR~Jn`pyIJ9!|C*;SC544R$9 z$c(0@Fe!7k?X|;n4LAI{l+%dL7C}|f?5IOwcZYUw%4)-~nV*DbMo%kFo(fe_+r!kK z@Zp@%tVF+%5ATd-yWzT~SbZC+Fkk0@uSQSvmmouZ$S(zGdS!Do)aZtM%yrRCZi5B4 zvQ@1bJYAvRmHN`|DrjdD{Ml%Z4{Lo|6avSy2+a>7aUOf>ZdH4I=;m4F3-L_;j#mr>)nsB}Rv z5(|3ESp9H2MPosKKOi5D6s?D(H0jyR*|9)l2v8d3?FV(?_BSD3*Hl^`4tKe?u*&HE zXk9@lMMf;-VX4yQD{vDfF;@&&5RSyc-Z>~i7YeeJ@HR?tQG%;Wup_3Q#g?uIAB}Em zP!{GiTMbtuPte;bTdh(3pG~JD>dkkxjSJAXhrvcc+9=c9PQLQTLRTY(ljEI@YDC?} zuHQwGt+uVbcUvNU4EZ|#EG zWQ+KiW8M6KzdLk|z79PR3oM^kGAt_+3ly&sH4PPJl5cw+mA;{_MCZAouC(nZA(XXE zv(@}qpyQ$5)xVh4*8`Ir4^2#TJltF663Xl$O(aJTUN}j@+Y`ha>dM<@K=%#aUO?KX zx@+?e8JV@2>X1;TEzGPlNyx|=3!C|6qiS(2OcC@EN6keXqVMlGKcxL6J1n!0BV#?^ z(PJVQDF|+E2qzCh3km|UfFnaR$BqTeU?iV&n;DO>Am<}JzeUvEGt*>GNpo_(ZzKkgKUy)#7^ZH9)>7*^nOF23B!#C zh6{ql1#U?!xP0D07h%xa1)=;f=6g&pQ6xf1Of1oYNPYxkE$mGP@KC2Hw@lG)(m@4o z3=^}~d_ydh=u;xP>WU4?hn>>)<$lId$DnKYXUojuNLbEIS+sFqo8s8qFf_EWw#-J3 zgoZZ2_PIfGBs8=F+n*&ghMLw;Odl-3nh1B1zpC`uUaNc9X1_kH`&G~B?9ym}Bda1H zll%>Jm2LZw&@;01JdUM8VK#{+?-W0_Q=8$tZaYKPE9&7P(uHr{g(!(iMZH4!W>%;% z6q41op^$oV6pko3IIzFt0#nyiSuabB{j*C9HXawDeRUm=pqPwZ!3q{~AQaVglH(Pz zsJf0vdrMu~BSnr^45^OCddpl!nS(?VIUVbJvo9xmwy??3GZ+^BM0UqNdP`nG$wNev z91lx*!o%Jok>mQ`q7AP99m0rrK0?kY-X%-~do#}iO*33OlM{1e!5DUT<Of4o#S}$>zdqpIq>PtI!M1ArUv;D5j`)+b&MaWf-dM`W_-}m7(@8JsjFBgY$F`$Jp*uP++_7 z(~LI9HC7C>Dm3p-B1LJD`mj$EH|4r*yL8hMHEz7G=|pmSiZ^65XwPoxuz&KeY9ROL zG#s1O5cW@`f}N`wPigaoN)E~j1^jui>n_)H{q&RDmP+TXcTKlq&czQG0qD)% z>&RqBZ-{L_1eV?q>&3^H4Y4g-NUq>+onE~Boi@Z;#`ZDIa56yH@pSJ&^E(b2m<;nZ zIbJoVkT`mesa8;Uion@a3L~b!+$*Fn%d&g^t#7A zId+k{f?WKj>cvmDmW$sqSPYAwt^yZ7Em5Uya6?^n+w&q3kF>ptM94n@MR@3#XvPY8 zTJj_iFzL~TnM-%mjBpYQr<)ULdy8E&3h7Aq9=E%8%*NUkgjkufblK(dP^8Q8@z{s` zJe&rz?vA~fQOq=`*rAxDXoV4&jm6xZE{3}b8ew0WNf!K!V!|Q+M6}iSQRM%nla$C) zQ(eeE35q(N?cJxp2Q4`t%IiAG@oL$peGzcC>mt+1%=BFEOn>OfL{3JgJ((%&p8|#c z-bm|bH9iBl>Q+Z7Z24lzHgKcTSy{;>(%BMXRXPlM;d%)5UaD!V+uco{r0qwxbW_-L zlO|+tiv0!9YWqh(vg7&QRlgRre}{2(uiD$Wz9nRNaW|KQB*ud{BhKAEG6V)XXnPk5*Z^lxNU`z9aLxmBhGVzsMrhy zyyRhiMuRHdw!?SG>7_DckI}M>DEsGMll_gBWn}8r>bAYJLk<*70j{ZSCDiLGfLNoL}ThP-|uivq&?}y-rjKo z)EKWLC(}C;N2FZ?=U%ah_Jj@?xoNj>8fH4im#DOHjM6MvNaxUw5&1dCNFQij)w`mu ze>w^&?y_9J6N!+F*|5J9>4=2Md8l-QQflIG?n#vT5B_a|lf3|tjWqvA&&9aLRIE-z zoTl>({8BLUINr~I&Zr$P^p_za4}giolXpWqMgz`DV(zNczhISEsGX6w9P>ugNIc>R zG?9NM^2S14?maZ+Spu~9#Sr(-0o6a7RJVkWhuEnvpEqR)s(pqCDwJ4@D-h9(CmOsLOW!i%?1uT@uX+EpHqc>Ugzx)<5-RCC3|pN|YRwu!;);p@Jx^o@k7r zQ&tsZ#qd9WA;b%^^RxMU67^37ih$ayx};85Q>h1 zXTj^PKpLB#m5B7y^Pey*y(!A2ofnr{yguJT(av}>koj1lJH!;o*Cs%=5 z5ZFA^Wc%P}vn`y>Ou6~NuA-5sTr7wjea(DyvOHF}I1tkZkUc^;W9L}b&llP1>YMcQ z1<&rWPOE&h&HEjS$1d&~M7IBXg#I58WVQVl^$2;_BHfmit>){eo$JWI9)WiQg6z#W zwoaECPCv)EYVsp%lMr25?M$kD4W^Smrof7Xdm=YD_Sq+l%XD4rhOlmjC z*z)L@{39{;C3xBLCnoohKl$?&39&w_eBX6mQtg7SUw4f`)(E?bE?&O4#kJc*nmH z$l!hli7xkVZ2xU2uC9|DZy;T)gs+$O1C%#tk^o`V}5>3yELMcjvF=Lj_p>hDYso8r;7N!X57-mC=}WY|P!# z7;?OX9xtpX4l3j?GxvMFb3e%3_egGX^x;4wRCK)GTk!8ag5+qyCYFUtvVYJ>K3`!z zRE4lj@~=>ebA;5rh;h_=AER~&yWIN$k`IuA&R}{S0$a1aK`b3Z9pe-)2>y;lm-`Tf z9wv>izM|e>$~;QkBl8$#;24l0$7_a6@^PdZXbX6X{MqevJf7?5yiX$0f6Ynf*#^Q_2_;|+z3J`b#e<|4NFIndeI=Ml?jNuYrn0i^Cy>xQ9rJN?}s zF4^Vmr3ijg%=~Y_$h6sZ2tdt`jM^FEMPwfgdi^3&leE?SO&AG=;9(MU{TI3kKITsz zL%zwb13Aiffr)x8?Z2U!n|_x0re?m?o0;iHAD~tlUic6twI7kw<468WC^#!o5b|F} zB3l<8_TNSU=EdlHnMW|%;Y}4^K@N@`Jzu_|;@|h2$6(e~C9qk(^8N|26wdYn`N~f9 zk+>+8Bk>YV_FB;Jd?m=kG6b!BzrG7}lxFC_Nu21w5gcMCg|j@wMJb%qAzq@{9!jPz zBBP7%R%St08Fc9e(Dc!0A`i8LougScW(Z7xE-*|RZTetyZocX&J^=HDd9&%k$uPlP ziLfcp_Ry`-Q%i|u%rXkBkJgk!M&( z(2vk^ytEAXm=94Xi+21M5&lfkxWgp{HLyg?+@?g@Z+DbduI=|W6sEQyU>`s$Vkd>k z6>%Vic?oe*3NsAiC0fiIrR_-M!Dpgef&$)XP}%3y&oNt}^?wL~6b?eAf666xQaBO? z4y14>ia406khmy?V^j8*7UxT1_7{=&G0Ty;crtWXLbr2aJ_>yL~ELSTpc) z_7mi3isoBgMF&GN)ZqH}(b>0xocy#~UmW_Xr2k=+Kp)GqAcWkXF}GcaTnk~lhP_}! z%;N4smU1EE6}5E&wJ?9HW1u)hW^(G8vEPrd!VYClyCXpfY{{nB~+pzYzUcKt*ByDI$O>sDmvfKcQHD!e|%d&M@;f6&)y6~iQVZq*gImU)t z1fWW{kYxvyhqC)h*~V{z5Xi#4jST;3jM#2rv4;iDgEnGd3 zo+e};jcJEEu#a8^m5qJ$w9^=}i)Ezi3B#L$Y<>u}iQ<9A4|$e=r+|~+R4p=BUfXhK{hmsTuo6s;ClZ+Z4x1nvOvnk@={PQ6Jd6~ z-F6O!rfdZBmy32^F+ zWg$CJkZ;SfkP`_E3PoIh3$lYGE5o~38SKoJAoubS=K-*X8qnPjJneEjK8Es)wfs>|Zy2o@%;b2x z(Gjo~;$iDvSj6Qks%Td7ZHQ%u+b%%Igya>iJcG!%NMUFP^ll-%glX|+AN!nW({HsY za5-oT%ejry#XywMba+VKe0N~>hNmGY^f1BW1V+<6%<_0zYaD5Z+eIap$bvwApvN^r z5pfMT|D&uXmI)kmp){j z&;AVo|3DPcSS-yC?9luMuM#D~Q`&w1s)ureIG#R=%0XsbOb9LLX)@1g? zW3*5;ve$KzB+nKnaf?;L(@PlnkjSU(MCIpR|0Zeip8uHP48 z#Y6Vg6K;mK4lI0`bzILn_JeR;Cpmt9B(a;w94mfZPmzbRt@Xg!iPOUV03>qq9lkI} z!|2pf19>S7Yek!8+3kDvZVjXdLRzNg4y?bKb@>PD(g1E9W$tn%DL|)`U83$NSVVRr>xB*8of;@@Jdba1g50 z*r-7VHcFXY`FMJAsOuz0rU*=c@?0;oAyrA{37=7kb9k z4gO#hRen){FoI2yK%-NV2oxu*(hD)c<1R>v?!XHx1(gPy!rC1ZRw3R(1#a+~p#Y~V z*?OtN1x?_Fw)9a&Y9{K4+pGsL3a0QdAh%UX!%-41_1TeIuiuH~k47gYK* zvJWw02Qlt-sv#6ez(w@=gd{*fFKdD%KsYQ-kOT+^lYsbe6CYvXIgAhI(Fy7i%Sk_6 zrdYRzS$u@(*G;tjw=gst_OU%Y*}7(PE7N(y`!=7yWE1fsV{9VKQ^o6m{!o}n7Q1v3 zi=0kM|LJ`}Bl<5n7!15t<-CC{mtHV10h1<^8*J(N$V5VtY2LVCZ^W;?uU z;yT{$@Hjb}!t9+$iG7d6)(H=~SfDqdGxdYpE5Q0W6I$fY)<;zAOxx?uoO!H953rLX zP@5F{%Ou%lCdppYPRHK(kVQJl7Rt{Bhy5%u=dGY>vXvS{+kSjBJ`zmyGkLWU#%@_ETI zP?+t?IYDwP(kUzs|#7%P7tfhLY3C zU>w+XET~C#U03KcP?O_9_1;6O06jz(#=J#GD+uF$n{2d0@}Sn(f_HCpF7O%Yw^WTa zpe_KEWge{Vw0Vm)?&p<4l8bXJ)Px;2M*|4EfRM=1Bf`K~fM@ElKm_k1qF9i$GVU7j zxQ5jfGev1V&vCYKO2n=lm#L#EGGbA=Da#wAiGm2MmPlZ7hRw1}g|hOqWgWu95qFnv zEL$p&E-{88hdyhEd-Xl+&beEuv8rsQ8i_gE;&UaQQ546i*4%rX>P?7UB11sNwZpx> zey$OFYxy1a&h_aWoX6qwydNFo?R2-!*x)WSwgdYgy)a-Og~Qv=XoZO|PF*KCd{v+5 zz{V(3=5xwS5*c#zX%u!vi4Jr~rr>|Xq#{U;Hcb{K;g0|I|kZT)(`P=sPqz>*!FC2}ol=s!%UVu@zq_nt(?*?m- ztuwhdXgJ6&c9zfcry?CH@uwl`bvWnk14<)KC=0!P$ty(#rZdsU)ht|n+Ygv`^0|_# zF{*GMy{ESEBsDF`s|R`yjBZv#Sl6N z{dp>{CapiJY8rHUmhEupV+)Aumr&!qtBpiI##oWR^yiFv>*F|yytWyzSKGy0^kBs3 zX{jSQ*9MG000K8r;Da84qs){`K~B8}do{=otmB>!CyzE_65~59is3u0W2BhWZw!}^ z$^@HDKu0Y^Q^y*PiDlwy*dJdk!o$p(tS2N4L3uVVL(DPjEM#Xi_Hk}v31$Q|#`9p4Lt=?xM5-WdqZvyNJ~B z#!M2!4i3Hs(SPaPn&cSRlj8*B=+)7a!OQf76Dbfho)Cm5ETuq(C!9n9e7 zmcW=LFlGsishF|o`yt)(3~&DjoA51-puK$|GT4~7up4yxr28wi$fzNg>IBoKr|w|W z49!Kz-Zq0ewC3N6<`i=DHsUh zDrU_5jG3P?^D}0C#>~%H^0N(?bmh-GlsB$?9s90>i<>Y-h7I*&S8s(+D(|u<8pg-FlHY+*XQ%LZhZkdf_W3hP8pip~p9As6Vw-nN zaPk4Uw!gpza(L2!Yq#W{V)N<{rf7MWUDp)C>BXU#0?QbYD()JJwJ`NHncpUVzBwI?t__Ngw zsPk~v*_#KMM%#uM*05;ucmz>9t2jHcC=}*3z-SIGa!2Bk*}DdjXAu6?;onH}50iz8 z#QP4)jl>Tf*3|YGO2vmgO>G-=qJP`-I#JQ~icaLWy{QusJnf$d^#!={jolt5T5SGG z4$8)bJXU1rQggTS(zJu8P68PZVka}gIAjEunva-WPcCD!8I#Xg_%c^uRLWns!c!n( z#>Ey?O22|jwUHW>(egte{m zT&FR@h+}S;gH*;Oqr%=2#D0nZ^$e;QEwC!e{)zz0gIC}Ka zRZv`)3Lg@Qik{a6hEv)0Y)?`0wC#kFolwv)9*fsfBw&Iwh|y+3#)8rIWx)IpIMJ}& z&Nx!=CSi2xZLN6(#Xe4+_Z*(D()VGXOEBeRWP+v6g1W|Rlhelr&uut3^J_t><=G-% zg3%}Hd+Rb9nhKrd6iA}qr3hTRf?mE}N}hv6ibU7K=M2$FB4hJ zP0{4}#4Ee=!Z<4k9Pakqjv+F&;C(ojX3UKN8`H}L$Whlxj^5ZFgqo)=XC}Lyk$({c zI)?Vn8SKePPRFp`Y?tiiqL>`5cs3PZ0gc8kScudpu`%o0^S{>|O~EM^s}u6CKpFnZ?m|Il*&+W*(phs|SCdP`@hU|2d#2(cmwS0+%xIH; z6>`?6%ecB*eaK&hH2r~R(AyA?LEU=>i`~x7_J0SVrojeqQD}PsgQrJK#*_>wSvmCS zl`c&iSo$k@4b)`W?d&oC_ef_a_CeMEfK-n549x7;0{Pb=K>B(_3uf?PGr;E#JV@LC zik|mf??$9UCI{Am)y!jiHz8_TqhFZ7a_Lv;+U$P>QybL75lzCw(Mlqe{4=QLy~sRu z$olkqk$}1y_82RD+3mLe8VE-dC*m|}EmEd6AwC_s{>`9BeeuoYEl4|qr#R(0S$eQ{ zD<~4=grqeQ-I_o+7SJ-%B5fY65a0bttCV*e@-|(dF9=-O-75B*K2wdU#pkE%t-oh( z{n>gq|9ZVc{yu0&z`vc9_wPUmc`5seUn_guK0Re)u&bXh8!yv-&1N{lyAuTldKLT3 zPQ|9%J8Dl|W?T2747>2S^(sce6#7m!cBFFZCYiC&xf{#EjDp?RSj;B0Blk9MBIcj% z--Vitd5+1AXprSifX{n(lX$-n&*)8DEkrzOXG&fy#4~#ln^N{hJj`W?HJxB@JgYZl zw!QJ}-jv<#jpy{HjIcMJ+ndtQ-iW0#Q*+GTcz!Pm?z74I0h`EQ#vXS=gf;|HP`Q_(|AsEeQbi=hNq0zChtX~Qol!~%!%)P#DD0)_Y+^sN~3nH z=M-H{yw`wI92Lly(#Z$9)j0Bfv7T@L)~(EuFMc(3UAIaM2Num?!6F$;Q9WboI@TnR zx}H%mb%PNimBJ)57P{2W-l=}68<{td!VsZ~n;2p9{YQy|sXs~Vrtl~PdMJg*a>U`( zTEtY%+>Du>G4nHKe#XqtnE4qqKV!*%SK3Ian?Xh;ZebKmVU3nb+$M1_bvt5aq7-9_ zF{T`2$}vvM-9gMV4oQGcTHDN@)*!XXdCpw7}C z)8gCNF8Hm7%^}|J>ksYC2g>{bnxOYBxH;S_VovqvGr~StqX*${KAvdYx}c9|7`LvE zQ{?@fL_C=ASod(0gL_Rro-7El7j=C+UEp)2Lhm8SHMt?M6IKZyDe&b}lT(~Pg?{2_ z!j9doi}+_S!f|*d=Yxl-`%FWr>ZV{fEPHWF_Tsy6Zt;#l(NS05#oEpWVwgpn@Is#e zPqvuXq7DCabUhkvC;c#9qaVgMR%38i|0ncvoq|Ef`OwZGFJnXnWj+#hkJ$xK9G0h6_ zYd5Jy4M6XC)6^kODN{U!(#6*@ZA$LT^s!oNKc-E|{h2l;*D-BMu4g)3awP!mP-S9H z)D3SqelcQ)ukaC;OIRr(x(JjS3HwUeA7OG1vm+a`>lxnRXUa%(R(IqRSVul`)pNMR zZ@El1^pWnSxuy<38*{$47euOAh4ICzh;*oL68B`U0{nXp9nerV>CuuBdBjUE)Dp?A*?Gb{J1DN_+HUcf(Ngd@X~l$4-sX4{eZSKUiYKbU*wI4>n9|O~(ha zltFqO#S(Or7&FC_l--ai+u$rb1N(g~ zwtz{9Jw>snGsV#0g{YbwnnU0j3Ot)B(1NGo=Rol9Vy)8#-^*@)9z?r+BSLQuCPO*n z!`!GQ!d5WSKOvra0bJhUeNkd3^^(Lzsh1^QqS+n>J@3mA={wNrQpBH&pi|rU6$nsW z`#&k^uot=|*;fI1uQ-YGbNhC>gDuzHOL{JFvG*#Fxn9P=|B3wmJE(k2ye94JcKfT) z3QN6)NFI8-Yu18VV8IFS#x#c>_NcDPvy_@F^?V%}V8%BPWx1n&2fp3@CP4bkt>+?f zDAaQTmLX#=*#z-A?=6H)IraQJ2oof}Axac@n?WmZ^Idt2)4snjVjCu$+s=|aZeESTltJzRG+~o>m&H#l!#oi{AF2_AInfQBv3W= zpd6;8A#Xz*{5QdGdUbQYTRb=i9i4gOUve}>Lg~w$A-RWdii^lylZeOa7t1|QyFCjf zGT}-1zlBLP~CZeT;l?5k+r!o&u^D%h zNQDb5Vcb;&m$$@Um>;_ngtYX=C#E-g-Lehod>tR6^E0l(J`4viUy6|o{MKQP7+0eW}f1 z-hiqeE%Ms{_E3jn__fj+SFAE*mO7X$6~NxQy7^x{kzz-6rfN)Gi0^(ymiKJ z;er8U_pBHAy_lhba;q>d6FLHC$t zquBo%+T?cXH%QQBzomNZvaB?$i_JEyTY``-i=A;|GY+gtg>@Nq6=55sR}W@^lJB8J zrfg0IL3*g@5+(ROu^+(JlR*zT?EM$i^qEbr`uxXkyRvA<+fMeN>|yQ1M~II6I7`o7`{(v}X6?rg7*8VDdSYFY9q^#!H!Q6_vot)A{bbm` z>E4`rkgz>vW1rMOVe~J*OGe+DcM%kby7BF^OIiYM$*?Mg^dS6t>>zt{Ol{7!**bTV zO&cI8Of^wqVQLT~SdZDERQq3C*|q$+K8#CzZCd2%G|N-)x823xm;o1rb3-L#Z-iiR z^sVHe=*p&cILuKP1yoleNcK;(LJyEDOS0ju1bycf9mM zF=9VNw+_pXR`8md+c?G!%Q26pg>grW&!qB07QFxFrbZzfoRwNiqHleLD$;GFVp^s6 z>vh^bX`^&k`5ZV}M+@?1R5{8jqbE^ia=hbNWwaw|EV*4*`8W6(Ww3pSb3cAAG!=Sy zZ4qsp8u7CcFK?P0@h<>bx1_l$wTYZsMrZt&mcr6&LBgHGQfF z7E0p4Lc1s8M1^CEf2+|y{KszNAIDjbO*oXq+%lAUcr1xLDKS0FXyA-tCQzOkInMU# z_7gqM=*d0fOiGk-#@9I0r@pWu{hMQa zzwsd2wzstHWw;ym2Yk5BavNud%p*A;vP1Glk8gXY&!8 zb(_lUa0>0lW8Vt^`M7qC2fV~)Jo=J~pCVw?RfMBzy>2rLloWzmpWbVV8p+>lThv2N zZ;Q-(mRxnlCEaT_i|yWDPMWdTB#Vm^{y3K`8a}9b(6HuVLq?Mll;5XO7y$h`@LM&A zCtx4bZ^nYQc_$y6q{J&2eeIRc_>iq0kT^{m=Q-{6iLN{!yIiS#i?Who5i$RylZN zbk%uM^9veDU)OJMgmWctP7^7Q<}la(i6AtTH89Na7?w)-Ue-McSM4qRb+5GUaH-Et zt!(v>LH`=&su5KTXAAei_#MsXn0k(Bo$8&VP8z7x3`^I1${oFcVdD&e+9a!(T*9y}OV`qjC^n72*r=_bfMTez_()04&W1MAs4Gd$YAp=m0n zsW-){!^JBejZx1yNqXP_rdL%m+&rA& zmo*HlC0#8RyR(Xv`^D=XmKqLjVDH>Jj5=!uFuYFMeseCh8Mfb`feOLu^U~1(LuzKpQpm;JtB-#pg8(< zA~-=oXTT>Xg5%<}AWt=qn_NE)>sd(9EJ0bA3&^{#g1iE}DI!`shNwg}11U8Zy!|jI zj1=C<_2g9<QFDYheH3}))hU8jOI;?Z zMS|X`ByU%Bsi4t)h-Rv%)Kbia{cDL1RL==&0h+1is*gl6Qa8DNqB>H2Bj}2LL`SRd z1r0Ii2SKAm@@SmBu%7?uOUYx@kN7S)Pfc%~T>q)U(q<8T5+*uMxq`X`&4V2C&FIg3 z$EzIcderRb#>to>Pf&e?w{9Toc>+#MDH$9@v`|$DS}DBWs%onfya~uRO`Wa=2%0lQ zqk)jb`HoorbUa&A%N&$G4c|9t^i+iC9Mvqm(}Z_{YLR;O2k%p?0N5KKpDi}KL}5Pw z^u1Vjg__y_pN$Sbbc?A->X*yZ4vZe^_rkgsmpfthM<__>r$Hq{Y`j3 zska3U1n*P$)jNU)pw^$luih23A%`f(dSB4~82z8BnDwEc!?2C`R25qvOU-nzR9Rbv z_la1kpY@fs3^uc*$Lg%FGbHPYz+R>2Vvv#soK@5w(HfoL$?&xtAhIX5Dp&L5Vh2+`R73Mx00? z^(bmptBx-%K(22}DiHQ9?T>IpSrfuJWn)l^Zo9U_|Gx!lVS$fBwTf*|*Xoe+Nkv1{ z+2eMFw$q1BgXRxwCn3Cl+)RX}Lk~jOJY+7y;locr*f4wv!tui|M7W^k288<#xdmZY z^Sua%_jw3<-fvuw@X2Ac{H^&LkWQjSmg?X4CCIQB(yi9Lz_QZ0TEdy(MkW)#&S5Wr>}?E2kx|7u)K#o3MzzuybGRZ298~ zX!-LCwBSc~IGhPsA_l$W7~3nd&HyC3w$BOgWhT>Z1%GE;{|@@iFa`S+mQS!N;qN3p}8 zvS~=~KEx`nRgcxMrJXG~NbfbG7-9SHYJ@uP!q$OE>s+^pO?E3ETHK9>~i{8W2;=D6N@)Nd{+D6-UXg#|@y%UNheJa9h3@|?>ME_RuI zFZw%#6RaB%7P$mzjwe<@Zt8=r85dJae*f1%dAU#?A z8{yHxK!lW)(PFjMxiHG~#H?bqTc|$ERgVvSKjf;;){nbGO*x|WZq!-VUvu~C+km#* z(U^_!yisKcwd9ReRp{%Dp%3z1m6o{|c{O)X{=-NwtfaO;U(OX9L+g=FOD;h!O8y*u z(%=n7&yL&|L0>PnJ#W+`*jbm=+4^P)CEpdBdsp{178&{DI;v?5&IuY`>A+*%Dk=+nZ$=(O@ z6*UJ+-Z@DBXdi>{6_;U2mM`?hNXJwM!aaiLW@x^&TeEJWbiG)W0Ok@Fhimd%bRG@s9Rf3afrrS0?>(P2uz!Ed1*1(h-C4^q>yvh30gl z$5862-RMc6bGi|EE4vZ4o9ZTw!pG-%Hb%NZzs=(=?|8F#;;o9D@}4uR_f;s1$u$ zsZKGd5xh!unnA-VekiR{XBgC4@e|Mm2F)80EUQ+R8Fc!HD9|+q{RzCdT5ZrH;KkLg z2HiL`udGJ>#h^Qe76U!3k+il})$~t$NL5*_YSAcsyFu1uYA&8QxJgOw|}PWB7$Y{OM-Q z6KeNyR{(ved1|D$3aE@nq?kiE-iNDNgE-!Ys|JHOPmEAQ4dOg8LX9A;#@FFooo>2g3)S`L7WRltJ4kQTrftRV-V+p zG3pY7I2VjnR~f{)V63`cBkA{6^-wpuwyagXYa}PMzMnNgZ8eDFeS+F%5Pf2T+HO$Q zr~}jl6&S$Qt_=SWTLWI6Aid^HP%VO%qPz{c6Vx0nsjeS#TiHbQnwAVdJ^cQ%NjTZ0 zma|pP09Q>?t#X2Pwkpkk6ug_d(T1|g>OO=1o%cM@R|b{!d8KTMvU$u6E&Gq%Qns7I zf1V0|%ha2(Ps{dDqi~9$)Kc}p;P1=!Quhg30i??JR`(4eZ-x4PaI}1yYQ%{y(Jlk? z%lB2C2Awjvs(gR-q(K(}%~Yd?XvvEP_b)#{&BXZ%^DQ0ISUyWF7^cx<4UOfqRqF_i z9vwNV{7}_8N}~lsCYB$r8gbsid?yT_Rz62Pg|`Vr{qtv+&sEL5Y1{CuFJyV0WZW0W(Il4q;FI1@frWoZ=tM`Nn|SXE%q z#>Qnpbp}9L((Yk{PN?}QG%9+$L3uDbfV$?v381@rxqCWMD2#$d8*T(yuR0$ zAFu8+s0!!=^{GMs8FEYciRx>EYKQykyA6`L7+Yd6(_5}t~%e=KG#NkwTD5^_sOd8)#V1+ zLpS8kSK-~XY;9QQpFkSMT54rEUY+FeQwYf15U3v zTUG9%wTv8b9?&fYB?nvv^r1nO@vAG&QA76Bl4bGhD$Y~W4f<~Enu-h5?+yBT?41?M z)!z)-R`<7x73vv-0`*T+TqdtK=}Uq77b`ATgZI)puj=z!#T9CTp!cn}YhATc-6Lq3 zY8dri#Y&aUS5+8)R}c8QVwF11pt}bIDu1t9r)pjo-l1Hlj-IB`;jKB9*QtjMnl-ej z@&+}3U(K5fbfdZt2h-F!uCJ?BtL*(WT3=aFxmsN$h~uGO<)74Ajbz`mR^4R~*Q2%S z0fRW#tyPZ-Ix|eKTdQ6-sAxz-vCqeVf=>N zn^m@;v%}RGN4Ka#!{a!*MO7JIC&tmOs?MOxFph3jgADp&#E8n?{RCl{5>jfS4#|frsBnlJG3Aqiv|=` z-r0=~?ORlNS2x-+U_JpQWJ$;XQM$nn+j}%c!}Pe^rYO%4<2b z@_x0_pxa}3^QZ36NYzRw4H_EYM~Zr**BPpQp@cNTVCnedJQ{>XVhoil6gStVAk{O@U3;8 z{j3TLdR(1{UDvZJPtf~T>#!Fqo>ly`m{w{Xwk`aenr6`Q$~@`dU}*T`l`pI2Zpn>6?-@z%KR2sS4Wi{YtFH~BJY>-|Eb6$%?9ft1!M;V_mr8{6ys$#69LGs?;FvDnC&*25}$xiQ<=T%*UPMC#u;X z?iD{#qYUEi@Dnw`Anpf0QF{nlslFXHpz0HKV>cQCbdNzbHRG$cs^bo42`kmc0c&&d z?&1h35AB;$^_d#0QFvIzepO$p$p+CUzEpb~R5fZk-ptG}=qN#lY6LBR4}Yod&&cex>!#!V-*XzNC+iQa`bNEGkehdHZwd?uM0`&J#PdEvua z^7DRB#~bv+@VQk#s5XOE!MZ=FPL0$X-tpk=Ggsk{TE^x5R~;_s?C>M-r61LA44N|Z zgTRmKWP{G~7FBhrc8%18u|<_#>Npuo@ zY{sqc4C2^~M*DU^JkrPwn4k%T1cIB zu|ZdOc}~4`r9pqf_1AjqI)mJ?yHyXc{%lam*nNTSG>A6ytose(Q?h40Y7pB#(0a-s zKD7?CUNVT5Xt3Tih)=Bz*1HDLx(REmL41NvSYI1NTQ^!i8pJ2)M$0|1$MQ{9u0ec) zZn8=Y8i_f1kQFy*Qq%0}K^8Bc(I@&;%`F>jH5=5oYIb$A)hcME8q|1H^$@G^BucJO zUh`?yBdj9~`ftn9>XFtJg0#<%wtla9G9E@-YkKkS6tqlvf%B_JTlX8(Kj)I_G1hv6 zmbvFwkF}mL=<{excB}QgL3>$ORFAV>H7M?0Q9a&z$Dj+M*HrIfeQeO*vTv-OU~MyK zbnfld6Rr6tvkiDkw(hN-WSwfzB=_&tldX>px-I&6^%Uz%gRGoqt9P}2Fld_nYSnI* z?Q1R7&g<2?TcZv7#@$lAhc(}zQCS~V?`b6snw9fW^$B=<)^dZ+%lWK&AL}ZEVrcum);$KjAN;y{y0y`utMs%3-^l;v`)_89b_#sy!Qj)_(9gi8NAunm4>%IkQ<+Et#u;lHJ-7)~AB>oP31!eYYg;_*vE|+7i(~QTzxiVo;Y= z5uanl40_A1jnB1e4El>(8$Z%&HE45oZTu+fK!a-RqWIC)5e6*=I>tKIpzEw~{5KZ= z3xV{yHTHn`u~xf5$GF4e$64nX^g?t(e4cfgLC-lw@#C%E3DRvi!TOUR-764 z-3{-jz`M~!)*%_Z-&#i*-esYp_;0NRg0@)K;~w9s)^!W0bBi@EJ_6_tgUDNK{bx}R zZ?UC*s}XspS&gUm@J_Q@4I;1I>RjBzYqu^jh`c4%Yp3<_mRRo#(zZ@nUkcJKN?AV$ zT83YD+drPNLha1AOg$Z(9q+LE7&I+NBjFf^_N2tT`Ey%dF#!=dBN z6wy-rtSNb;4B8hrA6>3HN0xQ_T7A;fz2d|1>Xypi^q@^yhJVDwL%dJ}sq9vAFXLd55w#0Jl zI)iA5<<>euTOu!wzBazxTCb5#vAm9U^I5AHOruyXf$@2HP@g`_-X9Rt>Xo0Emv4=hIe;h zRoNBR6$YIVT2;2vx>eqBTf@^fkGu~g?!YS!r# z+GVRBYDxcc9Mieb>8PjU>6WBR(PeFdeJrsR?*1a}NUML2azQ?|odf-r%1moLqhU$h zgOl)gWApMX^#DrOp{??UG5za4M*E;G5*{J-pEQ_yjv1*#a*wFZ!zUeSN}8@)#(p99 z#;Tr{_E6GZL5d@#^yEsHo2H~|Vxzt6>&!n(?FmaV?9H{*uFbTMZeu!a!=61F@K9FC zysTlmr8=!WHeI*8yny%#Zn}xh`2*CByixx-3iYRZpYmEJEqSW6_xD2A9>}ra82!K0 zBf9Sl%3knuOVx?Dd@_dV>3taLv7_62 zu}JQ$d64+9<}$6z>hVd|Vb^Acm)EezBT_fh7V*IGk}KVh>Hf3SRWW{F>z6LgRBKfh_IFEI1iY6RvYe7%HpKplZ{gX&vY65oV? z5>ol_qOckRpW#g(hI$<7RxB2Kvi{nC0_s$mb94_5Lwy`|8b108sOM#V(7Bev=C;}! z^9lY7OfurqzDoMOLwoFy=_j;TrGX~DcX{zKPl-q5$dsEtFO=&l!%#A z|E0C*7U|Yy&JXnGp5A0$S`}}!MKkOCzuE0@j3fNcGV($mtqZ6t(DtBuQ)bj(^6meX zo^FelXZ>w8vxa58UdOWd-=Ry(=+=>o-y=f5Sn8_^hI$^>;YgWjGwtx}Y3)lo+*y*g z(iTh4x;xAKFO-#NOWODJNbIR|x^=WbW;*Q~dX`R)U+T$BYpxEp&JvjcGDFRMQ~Y7) zP-}YyewAK3v`l6xnKD}2Vwsls6P?0$XItp&f4|T*G1#0?U!<8 zj&VIMbeOq1=(%xmya2zsUxa^^*p=+AzQ7mMU*Id?FYtxu7x?n-3w#%okALH=>9~ zaIS>&Bs>LSky?z?h$|goE)_2;bM8Vsocm zsrDL!Cr*0;o+D1N_rk8Zzp5HMS1q=y1|N_6F66cfWvP_4!FI-r5%}Om$7{9qU3<*7lnJfV*^L$X=k<*Tw9J zv!-9Uy+%EblhzIPT`i5a1)Jo-{%2OT*w={6YLoY>k@M_ZBz=$6WS!Jxy~sQx^bPha z-c6$CcKcDo$4tq4sDy0My1>z*=V3oi2l{0XN?*?8zZjw?C zML%wI-$mM0TM=$`w@G@tgaH|M*%B5?SSjIt4(0nJ{dYCn*(ZK{Xs+{O<)YARCs2QU zXsb14=tZGM;SQJZ1-q#A?og}bZMAvhxz*;)>{gp6MpHzl)#iE8R7uaYc_VzL&D-HK zZJvc4D)dvF?KM+C;Z5iG-jxV>j<;1> zu?-=MQevNuAHU+o!so@38es4s#**q=VE|LLfH{7QWIJ{dQaCp9#jsE4h?rL3< zl`Z9Nm%N1zHB^H8l^qaze}`{OH`xqdutPQ5vl<=RZMZ|bRoa}ZTb+CBrXZw;udvRm zZ^@qG&>B-5T5^iR_HMPT`j}m42kPIkvN7v^Wlt47Geyr<8HsDudqd97UZeINd_nek z7+IHRuW*_x|B!vCQ`U4#_R-Ee(7(aDDgTM=4N}U9(u!@?m9d|)w_2R>vTcSNY|eEH zgu7k1g%0UUq{K6�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 z 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 diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.pdb index d2e98791c1fcefae0934597e53057e2125f5483f..85c083612fe34046dcce9031d8a7cef564640fe1 100644 GIT binary patch delta 10660 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 GX9fT(3P*wf delta 235 zcmZoLX)u}4!E&(s+4_w=HoO8X0&*e8_fK%x(6!2l<;U8>%{O=_Flrc^n4I_5E}wTU_nezHhX}T@_!~2rGng?XGZ-*f zFeEY5F^RE|y99qIsA}W@o%A|!k0DZ9 z#J1n_Qty~}=m4%t96gv>GZKN%Hw6Fyt(4np8!-@u?*n;Pm4xoQrN$`vTwgFJ|fFRD9B!+Io7d2W<0mOmC%!&;`gFPth0s&j)yeB14 zP>tW%c|cpjGaCa1fpI~At1V4x+GukCPh0V|BwVL|srk^>93ORot%hYEgqo}UZSqK! zAtmhWRSf-tAy8A8{_@X&#u_;wqo7IEN6FE zk7Nh~{ST<^J?mO_AV0pt0|~;4Y*_b4IlH-ZJ`6{{r=UEyzg4*8rZohu>9oee#HMQ< zJ!LE8D^vuP^RVcQ+;cHp?UoI#$cKHkJjs&DB*}(zKG@3nX6-AQe*xd9`7E2|Sw1hz zGrGvflY)QF%jq;L$J0E!D9+|%HK*BmK3w;scV(w`+i-^sMH`a)jYGp(Pb`KGLRuZb z(Kt&b3hs?*>jI1O{U>imCorl-+Hjesnx*cFM7bt?DLUO9h4st7+x>;&AMvn!*Rd(# zvuB}&E9uswZpaEKgCQg_?Q0Ds%Z62~1B{BhT+XqOy99q)Cm`oSeE^-?2L$3S zC-)C-1#KS6t4!jSluMe{J!Cvk<#?^pzHW3P2mbVai^Lr zc@!$&ZVuymtT}&xawWkN2G|8a(F1}wXObAY3t!e~H3bj{5;H3{1P%6}unPoimGhpI zKtVNrW9I>F2~TVc6a>Zv0j_p5scEat0X*%*H)H_bUutnzo(!)x4%`m;-)nOt?9JJ!o;R) z9X(|$yo17KRKAa*Pa;ljj;qZe}rf!pQPW{py;@ zZwvzj`1k*wc5Ll;kBPn=XPAn&#Z2}wDpP<8p124V1gh3yW@TFP+U?_xvr2z9ZGL3b z!0MmOV9sF5U;xC1K++J%O94VNhExViAkT=wm>~(swg8Hm0HFbpHUiQhwU$5`GoX4S T29O!4Kocw&3^#AI@Mi`9XLwG2 delta 246 zcmZpuXsDRb!D8bsaB^c$gOabBTS<`c~`i%`(~xS@ev}&5{i)5)DmF z6H`r+%u-V=%q^45jgyU%Q%us#O-<5LQ;ZD^Q_L9{L zF@rgS8ACFI0fPlYB7-4=DG(+yq%xQ=Bmu=!fzSe|!V<_cXD|k;GXmlipllkDZwjVU SfqY}2enTK_zImgCKQjOzLr|Rn diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.pdb index 3c87786360716d6305f694dc78f608046e62105f..cf491f8a9ae27f35d5e59bda3ad304574dbbedbe 100644 GIT binary patch delta 829 zcmV-D1H$~cU$|e8d=wAA``b$IRS#cK5K8Nl?gtise2sIXkh&xU>eA-oK9oL;cE{4dYS-+J67)&^ zjec2KxivOzK?U!FK-x3s9Gw{^%T5n^`n@cJYplhc7G%kzkbc{KjOVH30Lp2CR}8QP zK;8g?IA_ub-NNT3+JXXz1BsO@HUt$mps)@EY?bq#lt4};zOeIvR>LbB137_zaY2Ar zTQ(_aqs;+4ZN*zjxX%9K`Owkydv#!2z+)4Hs;m9i^nq4}l(4f`5&9KFpei@b<)47` z=GWcaRco}(jfm&G7CK5Q5>y_ARdW2TGmBkuQO7E0ceozN5C-}mqIKiBC}oG_$9Gte zAS}s-wm-_*&8739JN0`C%JX`E-{Dd65rtm}7U6Tv3g)$u1%(nkp%JcP!>uJH&cn)i zc(yD}Yr;uM9xO=^v>LqzU)xxbz)8Os$0Z4Aa@^V8EgM>r5BmWQ(?L2Or-Sald2d(F zS8XHE{EP5J&8CCta4?){eMT3<(Kx4bJ(&#jXfhmJ1!8QoNu1JN!~zGimbzBmK7{zou|rG z*>Cq*e0<=%6>OKs-R>fbYi9BIu4bd*i)W#^({$^xsK^Q^gCV4`?k52OfQow}WN%}2 zZDnqBb0Ru>B1Sq~Tu^e73P>npH#IOdF)%SVWMnpFIWaObVr4jFG&C?|GBhzTIbt?9 zGGjMoH8?S|a0;jb7^__;iU7a?041COQcDOkMVX45voR8wT$3;jEf_NMV6^~%001p$ zLXIV1^-R0ZFg}89QDu`b4ILh2Y-|7k0YX()zyJUN08%}i8zu{UORkNiQzsk7uamG1 z7eosa=Yar#005*S2j1Y2^g@$?WyHc$OhHFsZDm7sY;-P7WpijQWNd5z00E|#RL%fk z3INM=?dn*tKTo7+KCOVkmd=w44jLFab5Dx^00;nP)d6Qrwi83KJQ|4fUP{!HunrWn HQ4VJzKn8Pn delta 829 zcmV-D1H$~cU$|e8d=zFdj{h@_rb>{0^9|S5#Y*~g@5Hf?J_jI7s{ZW>C`Rf8z2OQ5 zrr`!rn$4hy5(lKVo!1tXhJwqJ?gtis?AnggBotDYgg{-|T-=A!htcjx8d&X`-BE%* zslU-LD=W9grY)%8eGo`{=A5H5!(`d%LCc@)xbyN~faRvbV%P4I#N zwgAXmKoI9l8lhYGqC#6z0C6C(vS33{V+#tKK)_Zx?@0;dRN*r_4`?;KurZK-6Bri+ zxY)8uMH_7n;Atz~Ny1h37te=|W;kd9+Y%nyAXH!Ozoz$87*fK{UPkCw41wz0v=@H@ z((7M$3ssYy_I6jsUcx85wa;IfHT&hBvClOYWBKSb-+b6Lp_$&c@_ zBtck_4PAefvztrjLx1Y`6qM(G^}fTS#1#-VGaCkq`R;j?+;(nWUrszjn6y4okT@K*n(#H45%c`q~8+=i4W5l2?#aBI|IGWhG11B1Sq~Tu^e73P>n3H#TE1IAJk0HDP5mVm4)EI5#T3>!~nnn0LX|TpIhVRMZdJgBW~-&o0BjNEf|DszOVp*0038b zdCfGP(N2vuU|lxoiF}hV4ILh2Y-|7k0kOOFvj6}A0QlaG28axBNu{!W_x{u$pgf{RTt%&PWIuP|asHDF4jLHY6*-~+U<3Ia-wVdzh~x=VzUunrWn HQ4VJz-yeDE diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.dll index d31e5d59fe931ab366c7e8a65cbbb133436de353..a6e2493da36a6768464d1b714dcf7b866cf36d53 100644 GIT binary patch literal 653312 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
    @+zuIP-H=)uS9XQgCVz8`(KuV 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�R<<-^zUvzI1A>PlV6sDxiS|bP;VU^*UUAybrb! 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 z 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

    `a9~+dYO7gU!wl1zpI|tm#G)^_muW7 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 literal 599552 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ऀW$wc}}I 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�d*e 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%0D@IuC? z!3!Htg%`>20B^(boA-=>V~53z_kkBT&U^{u%%>ZF1YXiOSFn_EE?+wCI7AsJ6A$p! z;9Obbc=PDW8P5eTpQ(I&J5GUDFkT8?(fB>s?)3k#-5Vi?zZaG#B;cgayV?c_RKlK4 zM1T(-%ax7uwNk}6^Vb_^zA6TYmM;gdX8d+|b>ms!H9~KVHa^C6uBIs{1Fr?o6i%ou zyfy}moD-;HJb7WqM@y9CH0qlus~Q+jUO4N~68PJ5=Ng$Ps~Q_;zDcG^@v(U1HaFe` z-on&#`IaWnz1hlmZFuX9`aoN^O-4Z8);K57&UDZc-rnRnUoZgiN>3g3zL9e8#_K3llAxcp7V`HJiwImXAI z>^avX3ZOj%&z|t?VF!Ex^fHdGuDJo3u8-$=ZXSp&5Y=;w-0Jxt5wzN&3I?{?eLUvLe=0yjq_D>2Rt>*^Cdpacn|n+Od!g0f+J%2{Ak8r@^@yc9xqtE zu*hR|DrY#W?l$>}@Ox~B3nxC-z1T!k(Fzq0UQs#fqyQc7x1aJ z7XGm3k9a=K^XZ;H>iLWej~((eGXgr~A2ZG!G|McNbgmE4)i{LrJ9bO;47@jlqw(up!yTg}8&O?re^pjBlZ7#6P z_%ir%_;sek6`nt3ybbDC8ZQce+BlEMRoDXTPlr6$XmuDsQ(I(>aps>f&Mo$=aps>h z&iq>A%&#-f{Q8({eC_k+y@CzK*})6O*};p(nSaSR^Bc_?^Sr#tWU3YKpS$FL znQ;8s0S|f$95T)h4;yEPM@)y@LhqV9>)$iZ`uB}9|3M}kf6)Y3aMUaK&^YrS8D|H_ zj5GhSappfU&irxX%zw&v0d@kPnKf#Ug3nE!3w&Xm9e!z?`4h&OKWUu#Q^uJOzA^z8 zd~KWs-xz29v~lLYHO~AQR?Gk?K2^FNs_ zdLR6v$!F#H?`IR>0>2n%hrb$U{x{>yUoy`8@5Y(`!#MMQ8pl7E<=kZxV8LI;*}>n& zng7Q)^H+>B|F3c8|1-|~RpYw;gF&C!)YjK_EFJpbHT_KMFP=wCO@LhhJ3;BOx6YY?8ckIQ#?;Ko{oHu zxMTa5Kp zgTJwck@I%=Ty5L%Dm}XXbCXm28l1m{bNZ*!`{D~EaB zMAk6Qd%Bv&dHt_tyfnPF@qSoOdcY3Hvp6iM0)G+h1$fp$LDg_T9%OZma|_fn&fk8} ztE0Xi+AWZ;53dm}UlZQI^Bai13kah^#3le|AV}O!JZHC{5H>T_k5`5cbEaQ zIuk=kJ9g=d}S}LvSOIZxGgRK`e5pYHjip3m@nrst2D3FJYavyAg%Ham2VuZznZ zQ;>$(T;omQ^E{t#ydUz98|N{xAgNJ&i}3znq4D=JJaGLXe6pY!j#6HDc#u5-Zyp}C zh2e{nn#O%JdkUB=nLZsW|qX`J~z z#+iT1IP-gXVu{v>1#g=*=04nKoUhyc#@oW*F@7Wbfbl`_{~6~8lLw7+`QVTjIBc99 z9!Y8upCI@7yJo^%gZDgt-#G7@J}}Gkpgn55Jg@&Bng!V5N1h)u3-D8~kKygYV}y6j zpTOIP{#fW8;my#-0PZ;Qox(g1x=+!6|0{&I$f!ydL~&e8AXv_;=}J2O;-ACy)>YLQnKOQ|64L zm;)pkuL{rX)n_qz-jHN9&UZ%1p>urQ0cA4p> z3nE|3^V-I_h3a?%*7dxe=k+rO880i|a5OL-aueNPyfwU`ac-eT#<_(W8|Q~iO^kDk zH8svH)-3R5)ZFtHW&v)YmY%orytQ#|u{NH!HU0DQ9CSAYyu9`>&H;NGPl5OHytn6l zJnw6q{q?)n19$Va0oUL2Ta5G6JizmT#`%u;R^xnG4>HdDVBG z&ipjveBDns&itdsnV(?>mU;|<}DMfDh86POhRLZ9vV9M9)^KF5omYCb0wDV8yatPu)#QY*$eO>DkzP>iwF!07nmIS zNI3T&Zy;VmepHyR4&MmBD|DXQH+jCwgqr!OJMP+Z4QFoC9q0 ze7om6jB|iJ#<|5JkG9wzUjN5nz-W`bg$2fj6W}J>Yn+?xZR6Zx`{4J5^$SCP0Ddpp z++zEYpAhD`#omEW44o@6B7Wm8azdirQ^DCx5_W!T(TJZnk_1OMgDeLqUV)NJV^~MXJzA8M3HW>reOhG4jb@G0x@dX2JD8>X4hTo+;oatZ$sVpn-AbZ!pexIt`82 zfj2VFd&4cl12#9#ecHk}_i0Px+@-CIbC57_jy0#+{ZT?=T|uT8|Pj1EynZl`ai$~9z(%E_`~5*&x7t( zvB&KnIa?LK8iI(DO;2Pd5GGQWH3Cfv7`nfhorO!XNTFnCkh%ob#AubJhmV)@sNqtv|-bB(X}Av;aM6cp_8I^6B~o1X9S{4LM-dj7V?3-3Ys z-gBRsKnwVO_@ZzhbBnxV{4V$bbQtBikN@ZSLC+6)ewZHJgR+AoUctMbzvub;#(9JE zfpPYC)Hw4WW@#OtFt6SpAs^T^IOZ+zv2k|ziE(y#+&J@}8fX49h&Zx*W!t z&*@D#m&vm}w{g~AXPo&w#`R~{X(qseyvEriH_m(k0sn&H_RyEZ`S1Fa z34H~84}4DOPr*AU#{O=J9j=5gHvTmH6rAsEnO_ATo+bA zf;UCMGjKk5+uh9gNqBSkvtj-gcnjk#;Vq5VfVVQv8=BVeAnJf0P_!`x{D`KlaengJ z4*py?Aop{795a!l={gwaLDtbY^PP+{-kNu3T`yc4!Rm=2i=S_f0J?MyBlY| zhjHe6^89Nj(90|6owZ#&KMV`>Fa$oQS`!De|5IK=bYjB^6F2c`qwgbp>{7Ji5E zrto3LtHFmG=gVpYd~LXk_^P=xYsa{MjzeiA{Dm<8Har-O8Ep>(xRScNvv!F)Qtlq( z%-?IAYcR%m3Vf{bx8e7h{@LHSYdvuHUmI}aJ%7OS37${%{6Wtrc|Q3X$NuN9VWKU7 zrkmpVRO8$N51Tb){UgTtVx4B3TV%TN+VDqBf4ct9Fa)J%daqA1^$$APH1J^vH!~< z@N_(YyBYW@<9wa3_6A&I@?7I*jB|izjdP8kGmfs@+NeK_@3>FbMS;-Qd;YxV8$5r( z^A|mT$xL7b#@HA-$H%{lhVKuU1<-VxJ>TN_R?{Kh-@okTU-5jK=i6h;YkXZ^cX$P_ zdj6W{uY3N6nGlcqonHPelYbBSy~>C0|Iv1DdkgF{3zSEGKYUmCs%Q&;$M|sg0pr}I z|MUEyah{qF!FNaR|JmVT2EqZ@;SuBP@Ll7$r*Q8X=MBpH@Hfo_KQPV{&rz&kltc9p;Ivoptr?J;_>6H*@H^vtou4({0~dqujo*m; zIpb~NKLlRjN8?RVaNhF^#@|H#C-@$-&o6rZvvKzKi|4_wCa?wtzrpv09dgE(jC01n z8@~x&reGKG|mApd;XVk-1G+SZxa}b1^zM4Tk*(CBX@n6-;V*O8h;1=4ZJ3v zSFrqna6;Tg|6-R$j;8z1xZeL?H31gz{a3UA50V7q%qJRWK9h0glZ-Q;**NoAj3);O zWHkX6BpXN5Wi!rvcH_*a7-v4!IP*D-GoRDA-v8$^0T$#oj;6cLIP-aoGoNOh`Mk!N z&u5(Z{23m5|6d@vcYKrcWmeGmbMQj&gW*0s055F3J-moiGX9qQnGhfR%^Ri4f~HVg3zxJL5dnwl_Wq-obcVct_7W z8Gj7<&hQ`_fWIW_VhZ?6q8p9#RN57*5!G`IyBX&i-ejEl?#7w#VVwD%JpV==vY?k& z(AzlkeT=h%zQ&pFXPo()jWgfhtPt-v1}6s@o0xB>hnNDsmAcJzzz%Qse5k4CJE1#_ z^MW0FKF`N_e!u7Aul2w^aBaX%@O&aB6b+aS6L`=#x5y;pd{s;~ z&i8%+{Jn6(%ug|nzrn^A3`~G`JX4MT27efSH0Z7n%V(A^(JzU*!2>&zE?+%oxBOME_5F`Bibp z_U9U}jt64C#`9-9f7bKoJYVbiI?vZf&i&5`JRb!@-{AQRW{tSai(dXE&o_F$$@9&j zvoB3xi&wDK^Owy8_(9_By-k%<$eHIR{ssB(!aSFcJX-!&+7Ofynv6b8$Q`A^&~2KnwWq#(5O~k$g)$&*lF#&YPCY#<`3CGM>uo|KBFS z4*xOEeR{?CP4Iu==fVk%hW}@r175{J7UlV}bJ;TL*@zr#bUwDCFcGVt>mFB@0ZIM=A0alS7oZ=BbP3dZ@m zuNXSV*Pj7Lff8{3sa7QvTnGo`$7+?~KZSk|ybAnc=;h(p8|Q6#RpUI_RLeFbUVjl@ zJ?0u;zaFoFz%OBk|Dd2I{MXQX!D|`k8r3$=0qPh}gV)6-j+W;!RnItHp{~B%T>l$* z1veOH2Mvw0gGR=gZ)}|TCdQd>YMl9IbbI}8?iI8!&JJ1{X9ul}GvC@c^KFbX-_|(u z?cjmkMD4wT4#wF*N8{|EliB1v(R4P>bAK1(ZQ(Z>=Xs%Pwjn`$AJs>on^$m?=iQC- zT;IbukAa@qGR6Djf!quJTX+odzo+R9zZCj0TnzeV!}sr^06#eFhc%3xYkYIIjC=)n ze=mQF$#eMuUVfm-bNO4n{Gh-TaFY%83Wj)oo2gI18VohgE9MJ-;Vg>NQ*NUgJDbjmd`p8Z_Jm*?IjRXFA}C<^lNcVL>kV z1moN#4;p8OlZ^Avh9(>58cs3JKMQ`ycn@Cxr7MX9H6L{P>Uo{JjSAj1w-X6XL{%5#FE5er=$A6B8 zx8EkfEwIe<6~_6!pQnuTx8+a6FNXu9!&hUUN6us9nQXb@UJ(9Vh6k=W0&6n@_3|2#9^*U)_8R9t-)Efl`#pchI4{QsJU5s3fJVEv%@fo4krFov;^8%h1^t_01PN1l9u0S#4%m>B2K)P{W%}N>PnXYX1 zZ1D+m4JsICeZ}m><9S{yDw!?70V`kYfvaj3;7h5Rac;8e#yMaO&ubayL0rdpDR^Du zymr(xUV;AxX%yfug!uo+G(bUW_%b<;mrmpyd?vhc_L43~nCBWbFRxZFrR>@Vcn#kF?LeRpW|Tkdko&AJ z7Koe!^fS&0MIKG)X5>Ko zA{b4eDSVj8mxqrq&iXsUdXBH_|0q+y1x6d^%jj<7d>P$qoTuWk#+kp*cs?AIk@Fn! z9uDIBkuR7SUjO&uWE}<^Uxvj(FM>_lI|+Y4iWu`n;alL`CG=wO?KrLReZm9q;^8hB zfB_@t-A_^YMC8-M{QYsq^`8ZG5SWC5l3@Y=ci+glHf`Yn@}*2Z@+kih@}zwdw=x|Q<@~&K%N4cA8oHwEKjAMhk z`Pk=CJrDB7kq@E(U*`+V0=K~z8s{33H8?X0PNb zhV{H7f(Ht4jro7eEJH!1u%I_$%Z+mlS9t!E=PQkKjh{BoHC|<$`PJEji~)HjTw@A& zF?z;$efYD+`@o+wz8JpNIN$57GtL3md;Waj1vVHTjs;#a&g=I^<2;dU@_e&#uFw|a z+=5$;-wY34HUVDYwi)O3d%N*6@K=o&fWKy(x80F*>+HZTrB}u-&4pZl#NL2c33oBB zu7TTS0tZm=rtzcbAaWi={EtrFLcV6$L0uftk&i-t4sJl-M!t5Ke-rhQqg1!u`;o5` z=6CV@69sq>-iHMaWWV0k4GUTu=V_VmTn-{%FU;43zni^!+&Rd5#<|Il8s{$g(0C%x zzaNzb&l~3l7#EE5mh30v{EX;g z+_C-H!7uSZ%zrh`t5@XF)$0=S^}}PJJdT0Ld61sL^AF^22=fJzkDTX}MPa@n@@u&N z+u?Z`3p5HBXov+OXNP~``8V>7!~6`KNg_{2j{oEry#?}_a0A;IvH##L!+H*S)%YN| zONr$hk1jq@l^_B@;C*^RTml$dLL-2tVV0`8I=#(Ad8 zX`H(um+?R0*BQS6&zn*=z5*P@I`5k4t@!>w334x<`4DIwZnEO=0>*E^7AXX88|F(R zU&J^kT+Dc1)R%yF4C~tQ=hPaulwr}h@3C8s(8l`IR~s} z^1PbWG|qf2&+8bkhI~EaT@O^oZUmT?~CEsS%8T6*5f zIQwst5@f7#DFoV@0^ZlPH_m(qb@V@Y&q4W2K{fxg3zXcsd`KIszCSMBU zyMZRa1tRBBIuXx7$lnnT@T+m=U&eC?^25UXe&ftf$MbgNhlhE-yS~HtcwYa9n?Nos zFak4<7T`g0r{^P0{b_V~m+>_0qR6?4`A&yE0u$iw+Kkw}@H@i^)#m4qQJ@KuH-!Zw zQE(LPMtF|L0;9qOt{UeW?!ogxY-yKeX2kIQp=XpLq!vnqBc|0SaYrzx7d7@ctyd3;V_&wo(+(pZca|KqU zw2S9|HqI@!1<#ep->c=Z|5LC=QGf;S;<+ZJhZ_?Pz!S+c#yQ}##(6G}oLi(Sd_D4G z!{u>L>Yg|L3G$H-#`ySu263N{f^p#jT;q+#xj^KD!}`t0j}Pl>A-2VMUHDexHQ+BB z=N-^1p>ur48E!KL(~OruyKm?ZU_c(EmGIn-`U&9#*vSs~MB}f*9}JyaJNJPL-gqVKWBK@Ti}Sdz`LHm=heUOkdh|J3u(JpbG{SMUqtyvg}81%Lk+O@JMqFa;d&q;cj?dH$8>UmNFu-x%kB zr;W3}Z&QMdqm%=l@e024{H*8S8|Q%MjB~&rjq}8H-Z<|ue+o>11s9F;0`iM-p4omg z-VlBXJ}G>e@h0>SOBI{4IZfn&yb9aw>98uAZ^`F&U>@(IZC8c%-&`TcPAmk&P8^cT7Mx+hWT{lBWM0=Jc}SdGt6^Bkw+7vKZblXpJh(}XoagzY*u?aC$e)Mv6BPP3FHHGz<W>t*;W}LfV3!c?ebGhfjdhXU5sd?gl z3SKL89)IpDJnNVO-qS_S4qwN!9`ftL4)bG@kuO9pH&)^XoKH7|dA?6*i2BHRrfX!J zC#oi~dX29)7EQf^W}de&ULGB^G|s;hZf(3JysdGrP~_1HwMYJi==c9Tadb}Yhd^u- z^IYD=^RC7lAm1(ZmU#UEEEYKj7!L1_{7Yefy%FnyHQs3Y?@5nNg&eS#SI`?BL<=D0 z`WU|pyCCv!kxRk~^h17AI6xQUrI4SB2{FGJ`CVuaMr;5)*b**)dUq=Vk#ipnGMg<`5&XW?Tiwnu&zIeJiciILIRZ6}kSXr@xK-bktW2>-WRE zptciy3G(lR%b!3^RMQRpzD6HpA#7g5l zQ?4?;3BJZSFTu|m--Pkqy3{i94*9a%V4R!$1>-zwUoy_4e2a0`Z#B;PSB&!?FWX@} zXoZ4TO<*<(UN^o6`JKk!fbUK%AD?g{Hgn{B7xgT*ApJ15&~`XKa@hlaH{4=8Q$~)J z#ovD-urIZedoL{D7T9k*2l59}Tg3ApBYy~2$Ed!)alTCXUhpvT?}z>IpgUrm?|$En zJGOsk1l~j7gK&Y$@b``L8vX$;7EzvC;6vlw#~c2L=GW0Ky z$L~LJ-pBJa3cd^%cpv_)aeiBkekvTG1pGVrS7Cim)SorJG4#`6{oU|$$bTEwkB0vc zbFM$$iH3o*;R1`{=TY!|xWG901>;|Y{$p7G6#OFc=fnCH@SlzI;zPd}*7F$p75;N{ z{hx`zZwjCik4vHd7B0Xe`FG?mg#$E(|6%;$(EkkUTf;9Se>trG1pb%tJ1`9WA71~t z3o0V;4+2-h1)2~JY!2g50OlaWI70;{2p9wt^^6dY1JQH$ca!Fx5w`d|f zhytI7ffN+*LcuMPgo4y?0bZ>#d!EJftez)(p3OLKXtL+Xgn$3r43Od#quOC^4FR1uFDZz8_44oq3PEm zH3~gnI3a%QS1>?9elw#&o)IKafvOTc;m#@BHv)Tf67u*1@xm+`!;aZCum|GhTg${S~g6+EwKoUf8f z#;;(L(o2UE-W_@wI1lO<;Z=|?8=o-FKi8W8H&IpNoIo|tt9xF<_)Dm-X?!sTq*n+h z)Fm8h6BD5daZE4HSp%h*N%-B`}hA_WCZl@|F<;GqrR2# zEuq&72N)B2eK-%wJMe6S`UbH9^lrJW=k4N-{m(UQ9}nOICU^(q%y;y>lkt7XceajA zPHz-WkT<6E#&8~lW8pW#n{a}>{&B#rQ2^~acy=?+Q!%}H*kQ-eTfn)-P4VoGd`otS z2kUzn=RF|3Bl5M;UX5ojcqcf=*FV40I}FhIKA^90{`$S2apwCQXZ{xB%>TdM-UGg> zV*3}LJ!hZf)Ib6ufdq1rkOF}~fDk%?5PFBuOCW?AdX1FqeFCJNBsLtHfPjKmQ4}PC zAfOiz3l|G2qKMaPZzzi1doAy~W_AL2@9%xy=l^;Cmru^j+G}RktZ8f3teHJ~>TS;y zo_pIfg-=({0|6=q^8OSd-#c1zNa5l5&AjcIR5JQo519^q87nK8YD9IEmM-rz<*bVf zGb3Az`H_O?*8xm$Mz@{XSQ1dW47IZp#EcBpR?}K-$Q;BYVnNv8A&UVt%w1QAC{bJ2<_DM7L9|CGkJu|I9^g ze1)e}Hd!C4#D5B<_Wy6e*|KII)hYTM$>KD)Fj!DqGKKGpdgroou=1u_#%?sZR9!fY zAS;$`?1uo6nE%ADmiM2rzsSV*%Sg(t0IcDwZIoC#Q0)lPWR?^M>MjK`x-u97LPk<9 zfg1KEsLiMjFi+LFXyZDX8ntc_N}$S0O|9JlQ@?`djKmx#j0mPLE@*gti7={b(2G4f z`xv2ib`WrogoC9^FFH~D!;(N*UBV&!lAdXFbCsCKK zUEXgWjO(x|PSG4B&{#4$8fWd`Vse%wG6Ac~*YK@#f(fJHQ!WHY)xjL!c&1czEik<% zO)fQAZK{*V9=nz@l<-*HN@~iL=Z~=zlL4ytelDv^I+7KQQTaIg4X#aojQ|#US>g2U zN9YsMZ6p~YR+NyjvsaNZmu+v8F3#M@YJYR*aXRJf@SMsK`gVROJkt+ z%lgZc*{eoWS<*{xoGq4dNTR6y8ypk5RhOM*i8<~_ASNm#(JPYBBCw*d-vHa#KV@RN zxLq-)v*RwYAX;lw^aZl!l6fp7DA+3PEj-4GY`|NcQgui4C`p@Yvo@7#cIvX&xsx4T zmua5`Up5wmymWRMuAR|WIMLJS_$CYm@_}6J%gaV{$+{y6X_LDyI@<_xcAUVXrXz91 z<;PT1#ZRc1^xA7=x_hAYGbFtqt1#!+s^KV8^lfm51h>HZjjd4PPkBKKv`q7 z_r%$gc(&uMTEZ)LHDHacEr3@$<&Oib%eSLzBi)`L`#;F_l(nzi)_^s9pz#(p`h=*? zB5sQ_RrG4EwJA~xiK;dFViLN#Yzc+=pWIwIK_ttPsiF6u?(K0@JE;z}P%_aTb*Ztb zw3~#6#e+>sXr292RyYZ}Abg#VqM@>_G$Z2l zNAny`g@FXeA$DT-HMl|6#6d%zvvZOHxhiID9jH0sR*^UxMNAYa&&oiP87SpSW%)Qo zVjk2A^l3T3KbD=ePZsrXEHZyi)=hHW3QDx(bU;TAZL>$Q>kiQl?`QJlUb?{NkWm7U6Qm} z&Pd1MjOGfvMKhE7zs_7JtDP-J;vlvOZZJ-d(U7CMu`!yZbbRoT64QxLE-~Ed2gH_* zk$$Vos^;=y*xC$KXc=l(x9}eV6@;6~DHqIkMYy`MfMriu#1Qdr(aw7zMI=BW2IXml+I~%(aB8YQ-ksA5}1y^GGmTDU0+a z;`2#(9f_i*AOp^5`my11BFcsYDqx8xSFv~}bJW`vqg)O`8>2fzaC8l&he=xdh7(`6!)TsiiuL1X~XF73#*t zE|I;+D@li1y^eI(KSlcg6o;<6v&l}X%g+?@Q#Sbj*ALZyViRZ(h;!rCJ% zmfBm5Z&f!?1Z1_7x~Dpb>dEN&h_6HnG*YmuSz}=z;$xJ{en54vV?&#|8x7PT8YxAX zsZ>8~k4m=744kryxnvhpi@q7{6E4M{RcJM6>Bj#*k^VoTJpRu9^M9pGDr50Xs@B4)UMl0lLzET$Y3xlHTxD;?;82(!&eEu) zKPkr$r`0)HO%&+E5~-mHPUv@Rg`Bt@0x4-!L`};qidV(rfa+H z7uN%}f4R2UH1}~^J-15_b-VRMceS4EuF?m&&*?+lXY^t2v-$}4d3}`o6+OrOvOdAR zz&_PI+dj>`!k*_g?D_5@`z-f5dx3kWeSv$ceTjRweU*EQ-Ed#Em$@4SZFkQK-r=4Z zytl}GCiqeJ%fU~${}$}^{1RNx^LcQn=jY%Co-cyKJzob$c)kp7?70yf<@q+asptFP z7|(aXv7Vd3@tz-p6Fgr9CwZ<1xAH_g(meeg?L7k=>7GH349`GEmd9{pdrU_^PmyDQ zXRTv|=iiQT9_F0j;m&CuhcnOPa^`!S&Z0RUk8_@8P0=G^2N z>J*+4&Mlsi&h4IK&K;iP&Rw1p&fT8#&b^+OosW4&x(;|oyPo!pcOCXjbUo|Ibsh7} zbRGB1b3O05$92lH$#urF*LBV_*?rN|#q)-zhv!{S8P0Ifgj;eC4l4q}ms1T$84&z4G4ab6I2X{bZ`aPFtIBrz7Bd(LMFwlgKUspIwM?1K-kU2{5wWMe*jt` zp*XICh!LLFVy;z5PTjH8UW4~TPuR!uNf@ricM{{H%p}(L&V@}_A@goQ;kCHpNP-q3aXjWEoy`Z7R|gf>K_5$K9>t5I zcm!qDLB(~@9`q%h&7rpYSb>0SnB0H_R9pweqpQK@1l)@f%BK`{kj+P-gp03(^5O`W z2b_U9!NH;jU=sw8lcfXlLA*QIM}st$3#iD!n!>=pOCtAJkdqw;bWP%Z2IRxL#11xQ zh=QD~5Kykf{b)f>7CRJFB(4I`H3_{9$cF<94(1q!6cXwTXqSXuBd7?Vlf4h{nnd=- zF(rbWEFX{$8_y1Q(Sn@p3qZLNmpMW~PBtFUE{UrFbgeI?2*ta{1UXqtK)!y2yVru8 z>@h&O{R!7E2lM|f37*bD5()Le(JF$RY%-u-D1(FDfcfB>gsLVg$jSBr@_}&&%bKJh zCmRVUSK?l=ASZhd&@PEfo2(!w8wltc;c#-@0u|DS62h(qT&{%L;#l`C35^AGO+v>k z$jROWL;R6S2FjGNJwh>US#P!8-B!ZkQ2hc8w+YjiPgi>cC1!~d3 zrUS|Z<7n79(0>dGcApEbCA1z8Lm3?GZ9th4+J}unf}HGSKt7bg!Fm*c^fZD#2INC& z9IW+xPyv$;)@h-FoNNRjmQT1XfO2uB+QD95q#)Qjt^wR7kp+ttoTMTlSm6FS3;)&?J7X|9V~dc z1W~${fUe2lg%;#wrGN~S%fWiBK$#@;8z4IW>|ncB0zwfS>@px97{_hstB?YjJ6LQX zQb?#6kbx{6>{|H*CQlXLgdoV$%^6blDI`16y#+00lFq}Yc?vV$jNpBG!WomzX9^$ht5?3G7>5T zv`a#V0bP^O_)>)8=U`Xh?vhYM8A2sA7LX4=2is>s=(Yrv6K)|~f}Cs}Tvk*;$Wpir zKgcGynG%;5P>_?Y0p!Ea!9IhVD$aWQe&GOp#7Wz`3qL$7c8tflc|+x&iT_8Et<1nR`0@^tlruXEjVx5g1r2Kf|~Ly?H5gy zWozld(+UcvPs^KE^IW#pP77YXWKLGWocx+E`)U_;-)p(^qI!&N@bybycX;sfzOOn5 zF8?s&$n=qa>-}5dj%Pxy7l`);X*s_5B`M!#t=ZoCNTal>qjNUiH)g?>8^v+=jt%ha ztkce*bz<0H?J3`|4^m$LpxbA$%cm?1`7LC?h2gDU`*m%}7e#~PcZi2aEomZrL$pL+ z=SeSSh>~YN|y;l-B{qtuIt~pZvWa-K#;@9EY0pDTIrHM-`8oxd= z&gls0{>M`@pSn6}TYAJ@L)JxfJAQ7APn;j2edc>FE%c>sV>*7IKb>4M^v#wbJualP zM;=TF+R$vufUZMFU9Pz}QX8ZdZCMlf?@tOJPZ~P*^&xG8&y0Iva?-jc?4c)}mkx;` zgW4}JZ_LG#;K1lBbKh@Uf9=$Fiz0u$|L(Km#EkofB=4OV=9-*5;Mm&awRb=K)PcA` zecLa%p7c}3zw)y$thoGe>t~n!lzVX5r`z}JnRf3#e%(K>+rY4ALt8(0BdqmZr}t0! zdE2z^IYnDDyKK1L%CUmI)V2Pp3tKv6uDqU;P*A3SZDi#?*}VvcG^SVKKjK2CvAVf^3CO!FI67=p!K153SU_jR&?p5-gljz(0AX| zphNHW7W4NnSyBC!=5@VL6g#)eldqKj+<)DglJuty?}RTu?APVrOFr-B-M6ly`H2M~ zO?UKp?CtAK9-ZKS=)O+dj8Oc8_T~NwfSV| zj`L@_JveL5k>OwRC!apw;oP9~Z4b|F_sScO{W?AE9{2XCGhbZZbJe~HNB>xNWm2b* zw0cQ*y-{%ek2xLtz0~gT)X&Z03k#y>ta$$4pAY%bwY&W2L;3gKzxA<>)ek>*-_)x6 zt`|OeW6HspMnC_%I3=*D@lPLb8xv*Ud3@%i&Kp)vxj%hE&>Ve4^q1?nNFAe<*?$bw z5A>=zK1SOXMDV@)YbH(B*6Rd|WX+tEu&8*3osqMEBerHO}KjvtiB!17Ln%D)} zgA%__t9fy;_JM@|@=49Z%eBiAe&SpW^Z~n!|MZ(Rm20(+B>u>=HA_t`AmL*}YxE6T zXBp@DvYOsy+E6_hd7Wat->bpwuE|&&7wy&x0Pi zrqC!Iny)Ww9e8qHMta-yw6k6cg$#)myw^|DXpge``R-+^0CQD<@mrVOW3ZB9OP)9y`_BHp|r5g zlf;A%wWi6v7ECKByeogn($pCR1+cEQyOH}0GjODMcJHc$+@A(N_qVn^{PRcTQ|$Pn z-Z^7VkqK^O_w7-M?lps+sN6d$DeCN#{ie;&&stuvEOqe0S+g*MSj5~7J~N5f-niha z*Y5tY_kCvmUtbtCxK~~Dq4~>JE?hG2R*KF`hgFc3cjhH+*5D%zvYzVJr1Zxr1K%33 zbm5|fvul3+Ps<% z&T(=s)(rbY`+MjxqH*>xVeTY!_B;iAN&zw@B|4M`!v-5r-`kiTZsjgBRlcp zUBm@32nrQZ+#dXA3dd`9#qm8sw=r@j&#De?@pZhWpap-NhyBHj#)Z$u{XvdcHju-P z-bb`-#h+Uqd#GBi32V*A=tW`OsCxCVUeXKCR9?39B0DRuhxDQbC~v6r zV#g|PlJt_sDQ~j$QZkgMNT+s?PpO?@#$e%L1KrFXi8n;Y;0l%>Lf;YcvuX_mc4Wu6NC$~J-A2^PB)J8z#*LBLj6JO5#ClOIL0=n%ODFNJVRv$BY38Za zGn>g|b2`AB#KtWKb6L8h5$*v)d(}o=)s^D3yQ^(nBlwdH`k=rav4Vltjk50Kw=*i@ zrWxyTPTklnCb#49!8o8*7{P{%we5KFB=8VQgkd6MVa9ncC{dZ|;SD_Ws(rZP4YEbn zK78&C(s3?}$d5A{d&#eFzR{liF!NIS00Z{C5PwVIY|s0p`P1<|;4ZA08`(^RQHw?T zmje?_JFtm-7%T)FTdiOLb~w!__ZJDXJ#X7YHl^%~w|cTQVqa;`n`-xnFWU1rw0p(z z4t!Q8imlq5#?XK3$p5_`h>7X^xVA+^cH|4R?V_Y3PuH@my5QDXAXwSZzC%7b(GqU5MUn)EsnV=gwkvlpE^s9g`y zs}pbEe1z(RqZIR_Q)Sc~^)x09W@&rxd17ZL-aMf&U54EiC%x4w${LkmZJRdO*z08Y z#b=#(o1zDrtKw|#r~EB#mA}>Uw{=p_+vAk~P?F`hQvU9amfuzRd(tf5!tb@>?`;)| zYKt}=N_XSBTXdsHJr7%AUUrx9n6o}B;5dUaRXp68rw=;b!)xruR-AFlTaSiJqOpfM z^2<2s-v+nUu`rG!X|m%sofKtD=(XD_7lH%=1oJEc(a-2 zD5PE+V%{ZMbm37&COU5)t2;}MO_5>w-ITvM)AF;GzeSbI+@eZmZnd7bTF=`$sCe5t zD}VbS%O9@%2U9G+Ef~Q8a#Lix8P{>*CtMG5vowx-^EmINBJHs<-7`=<@3j)|Rn1~P zT2*^RH%TGf2t zjjz+RC&i*3e6n^>T&07cfjfE-l2A!Y;DBGg%paXd-9HIGFhzVh$U)tE^RJpE{l=g@`NtNVO(``m&nWH zvF-blT=#HT_pKV&7cVuQK_z;b$Efs%vM}8d#4yt#D;*yP$NVOq%H)k4bx$v6@{aDA z#u226Lz*+f-HS&jHRXkN$TQ5r(|BP^PY^Zt)FyZ>2-hRjBT-%t*MhP}qDwCx<*Y&4 zhDiIln9_@<^lEB6i$*klwsN=OdKT2a>JYBQ4&xwm_A`Uzu0savzh}B(ra*N4R?P4#CrBf~=V%vU~HCOj)ERdP7V%bP~A%?}_e4O&ZU0 z2tu`LI-S0$?TEo3*VvrZ&IiA~IagHn=Dwl@a`Z%)3*{Wz-CRUp^XA5<<`OyEMViaI zMh(STd~=l-r-3*w6dO!+lEQJ+44pfA0?{mjq)6c*B-!aZPcp-iyfG+g#=GWvZy0h6 zF*oAV>V2g=VMY}(Guv?Vni0t4L_ei z3EG*jdJBx>fEt3{MR7KZcX6`r%^e=ySkHyC4{y%>38Ibk(?w1no-i!SM=5oGAL)nq zvy&Xg37pUH_l1JMv<3dbXe9_w{|FSgc7`TQh=1&Dm}uj9TvXwoEYA1gQH^InA45NI z*J(?M#!0-3=3gX!>%(K~ox=TN{=2-<#%b*1`qzop**q$xI62mM0q>ysOT1pn$c6!! ztl_Hm@j*n(LDkt3bJ-04-C}7rZ<)5+;(U)1SpL1lFiP^UnrHlvD1qnS*V6}lJ^vAL zA)EVBPFTsFxBQcdR)J4pw4p)v`(N@xyxKDT7e(W~JSy%zB_RD*QXR&NR5R~O!UOzQ z;}S4q_V9l!#`NV0Exu1y`Tvlp{2P}4qvik9dJ*_Y^#3aM_T>vZ6#End#j%Rt;y5*r z7RSfP^u^6(o9e|035H?(6+OGSh3MCh7rDlG^Nlm~JWX8e$8&?uqP>f&M92O-JLnwY z_Y1Q>kJgTe9sQxkydd7{&l96wK_~2a+jKRr_;0dhTNS@4!Uym*F?Bk#(lhQ9pocGt zg9G?`+RLJ1Am0{3aY^gY__Bq@E26_7{`8;Ilk8LLH`26`9)c{L>w`r4V7^#;RqPwg z)3n#bW%4cv_Yl5Q`+h@nb_(jw7P zhD6*j-aGnjbf}T&jF^bL#yhwSXuQ|WjmJ6bXS`cu4CBp$w98^=4v*8`6EEcO)vot( zpU?UXZ%g9?(QgdzrCk+eW3Thvq*hzx?xg>hAi5{sjqa~ut5AimM64a+f2nVRNvT8Z23x6*Ea-OB^uYz zSvG7HL&ouhHV36f;oNYjM^ob?H1UQLp_b%^VvdtjN`~o+Bc@Z}%i^JNJR;`eXv)O1 z;o^8=q|=7CyiI8kbtDQ6HoPa^8OPIt0Ecb(T!f70=`C7ga)vG>*EelRmTv5TE)t?U zprvyMCK6s4j87l1AklU#Z&a(u8!^?2f zkpu7FU~Ww(bxRT)=0FrILA~^$1e+aVx&`ikstwI?%xP4|&uxM_#rO*M7Hlk<>y2QI zb$p{d7@{1XZorx>jg}Btu?3SOMMf+|PT6=rWEIwQ!8FrBvJktCbR>}V@ePhmZQO-! z63SCayhCx$ci;}Ml?_>24q1vh+08NY`p~S5FU92RjU3-L*ua@D@5a+&-~^r$^c^OR zjTgo03A{4%^xu*mQkptAWRqUl%eVm{RaG)j+&htXE&35RZk5c! z*MI7xfi&ZJ9W8|NmZ<3|v82%JFc4>8i6Q5!w2~5q7*$dw5nW0)Nxyx`cIme**(3dg zlD|klrQ|8^eB&p)_)>Bex>2O=u;De~c5dEGAC|&;iouik_>RByrvj`g`J=V~4eAPT z6K{c+dQgBc$=^XLz|Sba*3w9EWfJe2_6yF$m3Bk{RD`pt0If@V$?Q{0`%Aw==`b$| z|Bj^#MZd`q{)Q6zrNv5UmTpu+w6shOq|!ht)q`GIEoJoZ(w$=WWS&rTPzHyV9+I*( zy!43lBTJ7;+1;S@xSB&sPg==e=uKooOV3FzB1&JABC|p1n^;M-#l6-z_B}qbGj38Z zeb4LGj8{3nAhsmP0mZ7Br!dyI3R^|#FX#d7aOX9S`ijkCcz9UpW+$iyMVEdNK@-ig zGN+h7g*QnoYv_|qmqn=D%bHN`JhH5roRF54wL}Ya5R0eqM*YjuV^!QvR@|;u+@6xd zZe@cIH&cg-fF7=5j-axFT8>3+8e(*j)Dp`IRJqF*TGWMW^Aj%jj!lT^wLE$FhPbZm(O( zZuAK^{)IO1vKD2(Kr`^r`$CI(Yq#-liS1SPhisdSay$7vvfSmxaVTaRQ{G6#=JMVH z%M%o-^5iT@x;$lw@>8>wpVn9T9jxb!e(Jf)0OfZdoDj=wx#fMufn1)@c#P_D<>M`~ zlR9EK%-WaF6kp}?HqN!}r06U+Mf^107Uqf3(|Afl`YhfkYn9Z>_zk1B{55gkG@jJx zcO-6TZ&?0$y?CaDET?H=S@{p*;xyhIJH0B83SCuRMKDz!>rvs6t=zDJt_?|}_ZeI8 zu@sV7p{y_&6){!}y7ofGNK!E}Dq6{qunM{!Lav6R_(Y_&MOSoEHCT};o2Gxow87xI zuLEnlzPB4LDst3Pv0_|1$}_ZLqO6g66;osdhgM9J;Tn~2WfcMO)^y%-;)7NxcUh&}W0i8hOy8*D39BrJYs+GlwrRz4GDc>_Y3avQ zsBxNI@f!787FO}57@vow`V|?RQSp&Q=(Acvs#5GtD!!F5dQ|+=s+>RmTsZ-&dj-6* za>fK2|JS++#HqRoBy^T_6G%qgbcgyGNKus&NL7^+XfJbY6zDAdu7RG?Zym^%{-D4h zS%myRj%YiBN5xK#BYJuuSJhP@k47Pn49t?FZg^n1D44;0X@1o?0~=%&>VZ;KrGW~$ zn$HT{BdKQxgruGvco3U}JSz7QtX`Tct6qHI0HiS<8kxutvtM}NuqDA<#uGe;*r*pc zBkO5#;AL+Ud|?H1R&y!1!O$Brhwg!Z5*-1WHo7a(5%|L5?rV#y?}$sJx#6X5KRob< zSd`D3r&NZhc$J~5u$2uhKf>~xq(+z;c&m&RC-Zr@tFpD69r{;x6<70l%dvx7%gU-8 zrc|=ZkxCX-=2-qX3qP^F*MwrxqcYbU7KHZ`BTO6Pag__bi5!!BthNr0y^)&uhgX(} zsWZ8+>-}=h&?|+~(<`^CmZ^L&m6k<~Djz}DX^&4B=*{>jS-i@FvUvR~pBKkw@`Qn} zsnSpb&L38EJE5G)}NQQKap*~eiw3x+XhE{nMM^*I| zCshqp233t(5JwHG=q?_T0eUhYD|xJb`PdHLM;iw#~sxcpOo;MORNJpGQ{DrD|q5)hoo`KsT*etplnz zs_LySlWU3j)k-<*S$&_CY_qom1ZHOSUXd`DcNlw2DGJpmRO?iqQeCn7#Vp0%S=CC_ z=Oww+>Q__3%^>9KWzDN!$0XX94Xn>*a57hdr+2*2VA$~LkHx{cymQ)hi}($T_)UxW zKP}?FTEzcQ>z=#0XflttkegF#jiz>1YDUfD(`=2AMVRq5+Cok>^~vyx?^UFm4)NLo zo=(BxCSBJhHKYbS2g(5KwPvu0TF4W%V9|Ra->f-nt}Ns>4pZHSi}?XJ7KXJ;KOvUz zm^N7+%uz#Vj>;rwHbye(Jyc|UjIv#iRhIg(WT_XQEaBaQ(A*xQRIJV5Ep2h8SL7_^ z@mh!|T*{9$L=IZYCCbJJ=j^9Om03?@E#rIDc7&ZmT9R|yDzrvh&h463Uj(nadd#>auMKFl5zA@N6XsJ6A88+5DthKd8Ba77{ zR(dHZ(reX)yu{YjB;0tUEf#XH*|sMmK5yAUn(bpVQpwJg)D803Fxco=teH$MQ+Jn^ z!@)fyk=UM;syAzqDU;cIDWiYijxuULwS&;Vy?h#=kOMo*r$I8kKDbMBhR`RI6OIod;Ix(~3~85@C<8U)O4L6y>?9l=I@~^zxWRV)!Z^ zQ?yoPzOEgWr>U{NUITRKOcGoFfZ822&`YpOR2`d@#8KKwh?nP*;vNVjLl}0HxYUCGL>r2ClUSZdC5 z2oqwC$qdGrXy!rvNU7Dt91l^~hGu(=5uc1xGzB9RR&RW6h382-AFbG6z^h$7_+4tW z`(0|1^1IcZh2O1qZTy}VviAHQnMbtWRl7^0@mUyY_J)2R+6fA-dPuE@whmc78o4j^ zH*$(ucky8Zqge1F|GVCinz6e+OQhY{`mm`Mb|fz1OmNz*c&s-zI2o&~+oKGkZA?UI zV#b499P3>C$OEf+qsZ?`qU$q?fAZ!t%~fbrn@OmT;@?H;YF^3LyTyss{N*GmOlU0M zX1Bl7_H`&P#Y`4Ytl=pTK<};LC$-1L*0p?_=(di})mn;u>oDGj)cm@R|3lN-h>r|j zu5}OvCQsGU#Ws`o)jEp5oBTinnbj@XG1IobQ_XHaU#0P_9cvn{=O;Angm_~EEY&ZH zu#No1)_CnB&76xptTft~_HdXc>XV)Y+dzof3Crkb&DEH1a2a@t*;()saM(qpmhi-w zuF$s41742<0+AXf)I3V!+!<>=H!;%eCYF})o=u>addz=#LpjVcv9(4d$6}w^L%dqT zeOgcPO$p!FBoop6ZT=%#E3=oVEak15^rG@D6bi~n4&9}9u60Af-@2YlCvgFpe-cM9k@Q1Wy(I&vxXd}eq0aznPimL%^<&F|J1AKxu zT8yaV4JZA%?dsS)-pI^>l0}#IktSfD&Bum&+j&@Xa|{)MHKZ%uq>j*#k9A0h8>M_~ z=MWtS4iIJd0#P-DH^KG*BtA7KI;mlbYrqv5SZ=6|N|H=lluR(T(8P`B9cm^vb|~3l z?6<=ATj5VwJE~7)s`yW-F>E}g#;|eN+F?Cx#j8;>zENYvJJ#09;Fy)c3G4ZU^?a&} zB7CYRX*D#nK3K&g>Uo3e(|HVei}E<*f_T1)M>pz7qtTs=jgvu4it-jW$W#cQ+sIo`JL3bQqSE%@E(-%~xoXMgBe9*JKKAgDbrfL3y?*y&?r*PU%k( zPIIc*c@K}(ri#<|@X0`uslbPr5{^@^<{nE=3}a{L1{F{aACJxaWS} zT7PGlSs-4xpHED?+#FSaT`N|08Rw(f0SQS0l$ie7gJ!Ki&73cWZsPM}u3&qM&iAvj zD=)&mDj^s~<>hc?SHydppy$92y@`+3Kj>;M6k{IX{qzsx%thj%2f+77vF2j&<^#O7 z{bQrpTq5j(SBHN>`>u6=l<#PBsd!ZI+!mj;Kn{Ht&z|j(dirWw!WYNF6gVJuG2b(KI;ubzG<{L7dG$u;l ztb|K-RQAmaAoCu6W#5Pgx9|sb-8hgWI&S6nXe-4_TX})DN~CXtY+EVDY~y#iGl;ir z{K_-Lm2EsqD-=I(;}hJSqd=`Ae&wCTr0u+`c9+<^oi7Nw_#iI` z$sU8}1%%6w3cGLD57@qq@Z=UE7N~T^xw%7+dc`IJrQe4={JJkCH3o5*1Jj^7b z#oa{cE*_hai(9eCdLI1WD08A5!?Ykpxp-VJMY%ZNqI@?|ZeOo>iXsgWX3H&pNL=2< zqvkv&g-LT`Z*!-)0prjxe(OOD#+j}dg$bC+Qb08~(_=_w8Dwq@ZHO-(W79wx%~`Tp zAr~Lf{@Ll2w!iUs>R7WB5T2j~2C)SHOwsEho>R2kjY?0XieLU0xThs#t}x3G85<=y zTLjIje`$^Gbk$( zgeKOAq5j*-=U``$&Ww##SVlBW%%e!Vu@m!YyjueV@p1Z)IV{al2%GbMYPl6Ub{Gnv z2Nki&x}%|HT;Psqia5o^lBnU(!$Yt_qJtxNJ3>c!d+6Aro~##!YsTl?(TzZ)d!Ev@ z(F;S+xj^y`3fTF9@=SXhKib=h8hVX*bvF*Xt^EZd4Ji8BI|LZbYIh{-p_0v)$%=~Vk`;9|ad=Mg8D?Jn z?@VePdFwP>>dK9`boydnV`^$tIw}btOu%m+e&uFdEh%iVnb*D0Dk%jHH2x{Y1T-C6 zMoEez%qsYxW3#9FH4(d)M|RjS%B)sM^Z-9*`P+ujWInz-n@%gL;k>XJNv0SNw)3Wl z`FnZdpj4E4098iGdAR?Okn9*BC;#T7f6^cM1?Js=WIKnMgYU=%165qz%QMn3riMZ( z##qJ%9Rz^S>TR;%%RnD*H?i`vJF4Cx20qL)F{4*J%zHGv4_Dh7?}RoZIYS$Ti(8ua ziw_>=Ewu-P;}M>rKagVzk@X0l=H84qei&XMW96G`o_vH4)o@Pm_kD=DRkYa8pK%{0 zIWNPHiZAwKuGl6L9>pB;To>SJGA@5kls}5OWxIIfQOxisR+|rscOK;>_LJsDb4N|y zU--RR{%M+pAO=|Z=>{-VrQ%n9`V8D_5}Jka@5itFG_Amg;a7h8OSpDO!1B}gz?P*(SHkSHpsM$p7zm3f((r@iWX47Pcxrgy_#(Rw@VO!%$ zl*8PMdp?X0n-L<~_(4u9(WY%YJ$Eo2@_C-=NkUa>#$MAad5boqlI2c(v^k*nSo2}T zMSL{@8Q+P~Px72jKh#Y?Kh#Y?KMXJ*L0s9V+neLO;W!;No6eUt4#(s@AsBbYCy95S zd~=YO75(dTB1awVUo+65il|flt1Z&8QfkrvL!auY zfq8Zboz@DDF<}!DIl$Hw9kdIeuOBi;> zhG8CpYBH3^HiKpenT*q4g-zIMQCZ z-R`$Hj{qb4Z%==a2!ED$=s4nzGK7FsCzHA^V!2q3KfxPEx?~H;SvpM#?npx9g;)L1ygWNk@>9n?OA*-NPwi@+5d0XHGSgDb=f#j?z~yx`Pm0oGymyQItDyK#{3`M%g6>kH zoqtCGJ_V}1c}mUcQ;X#io^Gr+Pa`_Y z4M~kOE;e=JU7_ia(qyt}hzms=;dJE0PSXtPx*o-9p_A4$jOYR7#imJLu!Dn%dRIK- zU#GJm4e9Jm2#X2j4$8VNb%ZXSdV@#A&p^IV<5@+40~yB=!v)4e<_n4)7f$d5iK6Ft ztWKw6#NOxlvKUfcs4^-R(3FLjPXP@y2^+`yZG2i}9Ou0~XA}V&&Ia8S8;Vj$ei0Fwe1|iKSmik(^!jPw6)- z`y+L&`I1VHvVsX4>s!8Cq@3WZMwC%jJ}hu1O+!!+Y1&bnG04skf*N%08bLOaQQX?4AH?;Sm99g0Ia zv^B1FnPF9b3>?Q81|51Sf2XrPK(GCI{ypXyL{875vg>z#7-|niBt~y;^F4sh`^>g0(vb0 zoaqY2!LBY?wUO~2lV>x!eg+bM2-XfE2pS?s44POH195reN>cQgdvJ(Noh~B@AuZ4U zNil+M$f+e5K?l&)khy~(<~vwK58(7xCXP7vL%kS&s>dwzYt&l7xQ_EzT z-zAcM5@P;+w7X7Fs?cKc13?m_Lg}r+K5szt%=c<9X7~+`+tvU}(iVPxE#y z*OMaLh#7~2Q3EjEYnEVGUtg+1`ufmzL~iE#Mq<$mIQ_Fe%ECu?A^gZEb%)P<1DgGsyKor3guvGGy;ID{sn{Of;FCXfENb=mnuTFr)_;-`e z2$Rg7mJahRN_|60j70yBGI3(D2Z=Aq#KVhyGI7u1HgZEJrZ`q6PAZOT={Db%aRwK! zmT?k06jxi3*2qW+#cO3i>*D=VU5PIKJbkSB4iX`Mr8yRVN~Vj^*#R6O155Y?ytS%h zz*}Ixi^y{7#V5uZ_=mwFEUgydwBnUpJz=zMibIO&nsHX#{3{>SI8YCIE3&}Ai#0E+ z%xr90@ij5w43A9;gibf#tE1W)ROi=H4WskcP}ZX~XLVsw@2KYDPxG5W{&*d0kL&V~9JSHVT_t(RM2U2O~ z2eq+tif4NvSF!E$GG`rGYaKIWH*xn_9+MPkJl&+pN)?|N{r0~w`hs}-EFV-q5EX0E z$^;c_V>63Kh_rJ&HYU(C)x1`l6&M>>9IO~CAjU>X#_9)R)|emF=F_kEu-J8uH%=bo zg0%-djs@9<1~~?>xwtNdtT8a}gxOHvEm%7T=Jyfe{c}8W+z5`?N;aX|u@sl~4{)x& zyn@RzSRmGT#r(U<2Ug!UPvJ+iOCTPSnYF?%5MK`WVF~#V!or~3-|iC}0C%r}8RKR1V?2UE zVui)~@AW#l$+;uMHrG)I&0>VExWd|x1xJK1og4ebl=J+-BI>?B5UGUUKrE8-OIQK- z9trsnBENQfyHD_{+MLgt|G;By&drM(AZO$7Z8#pWvky6SUT8xTaIO`H2|*3eSuQv?5GG zR*RPArvPLp3SR~NS`M*Q;>lNVs3eeQe2HLtpnZz@nFxKAcMJ-o8~2-^ ziy^P_os9w+pMxT&4v;Yo*{{JbkRkYMyo2_Y$asx+(z9BbUx}pzWw$lI7Eiv$yXpNh z&2Pkaukpd*18U7efdQ*Pg)HcS0b=+CY_5GP)?eU7O-I~ePC17N^hbVk^E=`D8_(9R zi)Jv%T#@Yk^<`avYV&U5V3 zjGg8UVZ6>CYmv7A$;v2c-bZl%DWN-*Ao?upVl0eCzrokK^XvG}7w^9TOUO^+mpAzA z$T?18kaC){4=$P50&_;2H^r(qd9Hh28$1sr+&uB|o8aST5&RbK6F&crjDAKrdz-(A z+_(5p_d;4xMpBZ6;^ z1kwu@nw6sb5|7HhUoQJ&%@{d{+D%^{niB^Z|Dcr~Swc0PPIa@s#+O(i(9VAI)~n5b z15y&J85WJv;>$}g?za)Xw|SS&BnC*h2kyJ06toC19yWhfDba0lwAgqbvTh(7Nyg|l zO~vN7c|uGWYfGzwzT5#xG=kKwe$d|Nn{)LbYYWA>w|Vx!I8c$_zs{wMHqk5)M=iAJ zeYkXadSH|6F7#DX`Xir)^CSdio4)}9_g)kR=eytGeOrp@pmP_|5_d5D0Z;?Y-&K4Z z5;ez)(Q<&iOasg_;-D!Ghk<^MS$(NANXYMU?f-xQ55 z<4EmeMkSfb2#XAnJ8q&Y4iTd+^U~x4btQlf&AK6wD7Gq|3`!&b6s6)xiqg}dMB#T( zS|&2zt@x=>cMwiB<%xg2$7AykB8-+BfoJ7p zNS4Y7KeSm&fV<9(-=woq zz9s4T$tXWb-N5sA$OmpUJo!WY9+CMzpOAE_cFQYps;*?9Cxr;rK|Aw!uN1#moPHlG z>oXDl5b^8#Jih2$D?jEBk9joQQs#TpOGXViZb@uPZ+4*PVJ%R*mLNhg<_mq*s^u)w z;5|d@z{zcTJ-~K;aN#j8B1$rAf?W?u!pZ5Dc3Q1W)1f|f4C+9&%vnAZZ$2bqCM9_r zNgA;x;7aAnr_y>T(R@18P3OZR{Gp=L2k2@SBm7}vDxkPGh^Oc6~_GrXRP%(XP0p4Qaq0jhRb|0QC7Vi0+ zmuaz*bWO)Ecn{4Uhrmp+=o=K^?k_P@*yDj{D-q)RulPBwxhVJsjJ)+V7QP7t|87r2 zlujzm#&0oq*pqIhx$qtT$)1d7EMY)Ye0ZHdXK#V$Wc7?pBE^O8c_|LhNWx2g;4j!y z5TOG_h!YcU@MHE?c=o9T2yZSP`vz5)`y(H3N5`+NgiAm2gYx!+F6PznAXbk$lk+w^ MO(*josc5qQ1=Cc8+yDRo delta 85140 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 zξ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%0AZoq1_ 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⋙_DVC^Bd)6?pnLZWr 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 z zv(HVYd^u50acw%~iR1lf!^E-T^`O0_xSLdeyLg{CH<6R#o>a}MJY2?-_{_np@=Ycq zmN)D%)jfoAs#`9u5!Z{G#ckqF@psU_rMlet!g5$s7&WP`l$asbBt6#vf5M~|rrcgh z-Av8EL^;h(Mmf!Srsf{iEJ)P&eWtl(s$V6(DsB?r1@WGLrlq-$C4PCgDeqV658??^ ze^xaYO-*usPAEI*-_qQ4Q-0QzFDJ_Bu1b#rVFSNe7WY1CvbawY^;z5jQ~pKK-%L%L zf?*F?+=hbMh4H4U6R6GZ&Wabrcp<#!-(?Y-iS5L0Vn1<+c#SwwyivSOyhnUkd|Z4+ zTp_+BZXnyaEs_t!PsJ}md&}W|Nz~+UzbWTWFqgX|rWW=WC6~)tn6(AO;$m6QzvXgO zOu4oxH%yfM%-pU;q9(WNV9GsE&g}-6n%6VSxm}SW;b6I4mZF+e*W9jo(ahTRrrh0> z`=gxOT`S&T>T?y#Y&)`;dK{nIy^Px2?sXH}s+!&6ep7!_@yzybCdzqSdWo<;kLzN} zb4~d~34gWbbv3TQ=RRCL(BAU8rmAl%b`|@ISBs;?>%?i|t>WF{L*irN)8ccWf6MD$ zOqBC^?lnk$w>eRj-_f2p}6JZ8gae2S==V> z6!(hWLH+qbJRzPHFN(>f*Csq}kiS5L0Vn1<+c#Sv_v^TuiQvGdy<9q%~ z_+f<~7oSN)3%EZ`xpx_D!a~K}jxu}}wHx$rCESU!{^l*=`j=yDC>X}ZsAi(6nW>t) zOwBw~UaaU!Q}dcBziY}LoAPdyOEhx(P1UyY;UxU2B)Rbw!kQHKgem8$=uf|#n^rOI z%DJaN|5jc#<=yc_O$FCDBkn4=R$@o7huB{nB90a(h*QKF;vHi4N@4#M)mugNRuLac ztQ>b0T^_NpSW>JYRuk)rjm1`CNAX+Gzh$V?40W2}j#j}Z%iM3`pW-F4Pt`ELlJYA# zkIPg^lc?k_AY94CtC3m6++rc|4$!|?K|$4im?S6GbjSWj9UbnWC!^ z_EW_*_Aq=E&AN*F8G$N}9aV8BRX!(P6o=Fdn^o1^tEyF1O}(niUMudZx~`yqtEQZ4 z%BkjdqQ08jBkmU~)b=xRQm(Gl>PoHdHXu;ly(L}>lANpIZmolloGGV@49o11sb<|NE zbyUZ>hWK=!YYFg#IPtLr{g`BU)=v3{el)s^lP%2#^s5B_ogh{=sv z&L-v+xdUG5il}@K=-=vT$a)&Gp0;j1*R4t1)pLEt!Qwj5ztvZMeb>8b+|_pj#o?m2 z41fGv10^+ZrJKcF10^+3rwv?&YHEn}#AaeUv76Xe94wv#{aZuz+0b2T9(N60N((Z( zm`@z);g5f7q|`=AZRAd&zLEPwtlu)sX{?;aTJFYf1L_+)uCvDOEtR*4JH*}M*Ww{@ zRI9L`ChDgN`tjnfi8^Ycj+(e3tywc#oFH=lXyT@*JVU%g%-tsJuBj{9Htw2gT1~Y% zn!3`e;U3UbyIWJo<6~2oq52wPy|&o@o4Pk3{;iqj)yyq!hYy^(72=EHdht#1U9oig zuvK%lYOXcc+i@ycX^d{z zE#2%yw3VW*w5+Y%1=NE$ZnkpqPGlBwDCpl>E5Eh!TjO(~_!y_lA$9}(7X_}3R$vKpVGLWT$N$&j@YY0o5E9kBY;)gu}GeFl{wVTOI$~x`tixiE7tEoDKT7cFJt0 z%y!Nz*9{*WcU8m*pnq%cj-%Y(oe{Z8+v_pi-uJ8GqM)UmIl+m4)$j^~Ar?lYBZ_6l2dQmamC z)k&>7sZ}TUGjck)lj1q?qL|bh`+p~QbMLT=&RXuyu5BND(A;$qc^d8PdaL|2=-;}y zDt+Uwi>oa*6eofHt*fTeRa5DzsdUv;y1H+X)7AYbp6HAHzpMLQ!gG9AcV6XKKbF(Q zTw+17gt!azZ{2iS>gI|Mz~`qOS8O*|R%LFcZW^YWtE`$@Vgs?c*bel%x!w5V-@0qo z-8Jj(Zr4@#h_c%!78w}k^iWO@<@C^w)Zw*e)vBl4 zG$`(R>e$-T(-FI;dq-8<#ma-j!FsvFDED$l#ot6eQ|jgZRQZyadNpgtg8r?yD>x+X zdb<*0IkAe!<3Vrj2fcMT>W%ZC0u99$;x^E~_0g>R=#0=ur>H*esiAS##~lRyTVLh$ z)xoE)4%>Zo*zW5F4GVMnx&0{jbCrjOHT~Uol>58v-iWYjfO{0>0d8la<|@~8WZYfl z?g0JUK$m4y+zoW?LH{<$y@&E3=SGJ$gWWAC4|YovHCMaSC|~W0T@&UEaW|tp#65Ej z_J992)SW@qP*-|PSToGskMc0LHBmF%)f^jl!`)!ezm0GkQ6Ayat_^EOs_T*NxkSw< z_czL;T<&q?lVBOwd_381e7pqyjEDHQvThs7W!(<(kMZk{wO^jk!&d^h2C?F9Gp>>H z))@DO#&Ho}{ubhoAyy`cZ-GCJa?!xwhX05%zMnw(Tj3{B{si|%=x-aGxAwR<&UDYM zKt&T&d|(oqM!cEvhR6>+7s?s9H%I)#pnYBAjF-i|1>)O-_!M|c_zpRqqTYmxR;c(i zNO%g~+W1Cz8~A5I9AEwLFRvc>F2p(bP~6)h|H~l154;`xtH8Mi+K0~TR=48bA*?{T zHtrpb^P5yU86S)_*%`h+=rAwhT~HS~zWKv-HJ%RdW}NZvfpdI(fDzvV6G`Z4obg`9 z*+FmPjQ26lcwgg;_cP9Tf8RB}CNLmYGO+|Xk#Lpqs_=o44hBV>YsIdCt0O)n;zQNH zhg#hD1vSIWfH~m9jaP$@Fy0(K(s&X0DB~sIqu~dFO@!~man~5x{GgMB|K4f_rv=>mvy_7-t8QjkAL(#u=Y#obhSK z8NbmuAb?&irM@pTPd`Ec~ZnjnqJVx$$fG65%;h zF%=0b;J*Y7@U1-w=XrE!;KvZ>{=ikp{NwPIDD!c?5`H3Re`Dak!nysg!2Nl|PX_UH zjPG7B6nJx`;2qIuZ=Ul z-ycuo>p9#3lfVWCjkCcw#u@+CIOE?LXZ(4U2k>SDlp9y#y(7zJ!p4)^o zjyJm|oCDxZrU_>pZz4@N<9L5&!WqZ=9}~_v-r49*h39`J;7yMIN;qMh@n0jG=%k6W z!&AnY|C@2fPa9|a4BWG;1n<~OOn?bzjkAMu#u@*^IOBgBXB_WZOZ3M$-h!5J#?Qwx zyhKF?D)4TqgtNg#<7~heBX+`g!%)H*zigcC9gf*yKI1XtjK|~H|7=21JoCWAvsrSa zL5gv9m};CIrWt2E-8kb}j5D58DFd>_9CS*6xcn;%?=QI;;2G3>U%+GC{`FV^p z?&UQVOvq=P3HgmPUcd~P0WWCc%r9h|`Gt)$Uc@-!o-1l9m{80(J18C*u!M;-{|e*G zFKL|dQpOoCZ5;1Bz$;o)!GyAAKt7KzXX5Ozym97NFwS^IaGuFwS_#(7FAY&?&4ynF*bZGtO(#c8Ph# zIdsNxMKa-R&&$I$j;ogmXB<~|gW|fXZ16-~AR|8y)OgKB_6-nD6FD!=6_)z1V@G#?y50?k$ewPcY67 zt}|X`zqdph%rwsYTaB~B+l(_FJ-gl>iQi$*|LkB^B;iiujNfIP1Ke#UoB_Yb z#F>AuapvD=obmhZ44LpiB;i5hjL$aC4jwYj_`}8-pJSZyxyBjy9x)Y6m}i!VCztsq z&IXSfXZ~Zx8Gqb3<4+i8{7K`8dv1ZLV8TMO0W;v6 zG81$*eA77dHydY%Zy9HNi*d%^HqQ9gga_yUcM=u;+3;QC?BG4)>|mR5#@{#2_y@)r z|Ij$&+rtIs`Hx4sk4yp^d~BQzb{J=Tr*XzVG0ym>#u@+2IOCrOo;d&SiX`kd&JOk% zX9s(YGya8f#=kVq_*cdm-{*Vg`Ty%k!hYlI;DB*}zZ+)K@Zk!z?8D~7%IOF)xL83p#Q;jp8 zW}NYKe9v*B0TZ$qXF^uvjAu*w_XUdVCeHjE#+jefIODmDGw$KT5s3*f0UxGFI1}<3 zXFQ*A#`7Czynu1W3z`Y@QBcUlk?*;}rh*NM7-xq?jWb@%IOD~QGhV_Bm;t}S#F<~x zIDfaol`<7fC~ce_mNCwFS>ueCGtPK<p>-B$4Q^AB<#yLQ3Z;)A` z^L<0(?4Xg^rXRu^8|SgUiOJ^xO^vgCGvkamPdK(e6IvuH{FmP?jWgcLI6G)bk zk%XSc*+DPk?4Y-C#`_p&ysvS_`x$4vzwa7f6BrOlxXL&?7-*aw3^LC6V6#TJPh4%{ z%pYQ$`9tOA{68#`Fx)sh7-5_pj5N;pDC3NeHqQ7p#u*>O35Vx@zJ4ET64>Bc<7_a_ zIOF4uGd{sM|mC0c5tV0#_uxD z_}#`CzsF3NPy6q+=YKZ1FVf(Ch2=7-#;A#u8Gp?<;~O&FKmTvctkBu; zb>r;d4dd)!lX1r1G|u>D^IK%0ppAxG|u=p#u@)s z9-RM~@LeR~ka5PpH_i?Y8)y88amIfz&iIdJjquq26XW6epACMFH2B3h<429N!(+x7 zKW?1y6UG_;)i~oP;feD<6HY}Eels)Xv)a=p&ipgR+2QZT89!^B@pHx*|HGdDnee9> zFa!Qq#Q%=?dE*oDR;df{-yGfqfE(Z6cQL6-!rL1!i!$F~`A?Ep#hnfsJb{W!Xz+XB zoWN!H*}x~lU2+w7E^zMEG2>O>apT$GNyh79UdixFL3{p_E7?PZi}CAY@VXE86nG5I z+fT;vCUjRC_f*8=L3~2sDe%fDUx9lX;;BLWyA&KtlF=q`uJSC#xyC*Ix}iUlEWs#5`tfC{Rq-TMTMVZ^Y96W0fZv!uH{B+>if({>rS3o>Rkk5Uj zB0Oi{e4l8BbsqmJnF=be=v5ASZAdwmb%*T8$i3j`C0<8VSR2=9&9GTeK?3&T0S zCeRzJq)5lfIO8`MXM8di*t4s2idh3(rBjV_C!J=TtMo?W zli|~i4~O3bFB&Xhd-%-}pOIV(@Ba!CxXN$E3`6IPZ!^vrd&U{R-8kd3j5B_xamMd5 z&iLKQ*#E)-nQ%`e;a=m6-)Ed1+;5!m2a@Y1`YQ&1&^XuVY~$_W4|$P_hmB7~!W?)p zvkK=L=O%c>IM?7j;~ZeVaei{@QA{}Oj|<>EW-7P@j~i#g6UG_muO8bD78qxIp>ei< z$~fbTj3bWs|Ci|KD3?3HU5{i*Y_|-Zst;A#F9z z4;#D#FJm^ryT;3){d>lH!nY+HkN*y+ct25rXFu={jB|~AXq=x7+aB?cjPp4ly&NXQ z&wubepC7}^2NUFRVMpjZ|5e0&XIO#qRk(j*oag&b@i-1U=m-DII4AhIaW2paaL!+(O;2nL)4|JitR_%FuW!;fMw5A(T+ju}sfAE(>%|A|P# zug2NIN#pF`lySy?GtT(wmadzPF3fH!e8D~6hob8j0GoGB{Wv(K=^h!y| zbe=9#jSqvTp@Uk%KEMvsjkCin#u?9QobhbN8PAUI?MrmXgdE11kkdHhxr{TO+c@KS zG2w86JdouxapvcbxL3ebu!Dle*`Sbd#tR!~yohnei<$}Wfm1`ZI+k|+$P~T z|CYcLh_;Ce|D*EljPtXB?M;Uqpo4J^(9t;Kos2Wy**N1}Lg)FP30=bql$p@YIOE-o zGv32E<2{Wt-pe@Sy^S;8Cvc9h3G|I5^fS&5`Wt5l1B^3%m2t)g8fScvamEMxuJJX2 zt0M_RjI)EG#@WFzdmc^FI?Nm;t#2*F_pkG|v1<#@XTZ#u>lC zIOCIzGd>0G*(I79NtkAw9o%S~9ZWaQ_)W$czu7EM27HEzGyj$p9RI@!u))ko!mY*` zzs)#1;Mvo*zuh?FcNk~;S!P0fl6z+g_P?+LHn=O&;BMoL-(#E|-fNuk`;0Swzj4MN zFwXdFy97*lD3b87amMEuX9shQGyaHi#^)Jle7$7=IeR5#Gy><9Dl3@p@(jzW)jT?>By(aZaWw?wb(r z9Sm?K{7vI+0`H4Bzi^^D?wb+s7vy)sdw}VK;Lq{(XQLotFe+AI^^}9Zg@mhv23Met zJ_OFC>l(y|!WW?23->LE4-4`~1wI1K&DRO{w-Fx|#G3~`8eWXspGjMha7~cVCGatD zzH;RR-$8tA5HAmZ*ErX}d&W1yw;6vD3lMs3#IAwAkDd5h^vCh_gyRD=UG+>;2^+(3}F#Fi#SAg#@-V?slIIncxV2^RGvAxEb|Ajnw{m%wpMiRa<&iFp#Tti>OCj=AXX4-F@4@3Gy#0Q|v z2^@e=3iA2<;vhXd|MS1q-=O09Ab}5?Z;kWC=ywr6WSlRpzBkTGI)~vm1pV=|1N58V zBM@sG#J!tQ!N(*Yc1)N7ABg16@FVbBf)4nw`oVaEh}Vbzi1^GPpVy3jGS2>ghTj&% z`JdHaQkr^+3O;O(ngl*}k6|YZ8*ryPZk#*a3FD0aYMk+t#u-0loblgy{e zmzudvxD&;Umx9Mr|2@H^h$lxp#kA+6B-J?2u4(_y$Ll{+!5L*S&KYMl&UiNCjAu8_ zcn&ilU+d*G&PRLbRT1mW<9{x65IzjqVQw@Cosa8$#(5;nZ=4UM0>-)17BtRBK_TO% z;f0OkcZ+ce1r@gk4~sELzTXcIAE%5z0O!M$@AsoW2yca@SsM6kI6oCP1YQ*Jhv2;N z^d5S7lzA>GhWNul+~ZX*Tfx(7aU{$M61W515`7fA70%!*I*6f8St7|ps+m`sFsOyg0(~E_UAUKgNjFk0Uv_b zHO}pJWyI?l=M#|n#yh|pM7*K#f`~T?oa5u$fN?^=jKc|V#!XBE&bX;@{(HTd@#gU6 z#@oYNMEYxKoDb7hzH5AKjQJF7aHPT2#+g6FI6E9_obh4C86R$(@e!#w|AZ4@!pKO%sK|sy zn>h2YG0qOh7-xK}amKGT&iFX|ZcSnWOc)x{DlzUeSr0LCX7XZ(8OjNf1u zC<8v(GYM=k#W)*GHO}}nEobl<#8NbOm<2M^;+?!!4m~e}6Cd`b?_*N5V{%yw9 zp>f7lQIOF&KYk{!+A211Q@St%v zcqp}XVjJ@b#lyz=D4AnC13uR{^B;-$JnKCE&9@csM~(A^!ehoc;Nz+75)9s7=@&6xGJeye|Uv8WYo-=+wd?*#{An}5^Tw+p{sR1&AWmNeUo6M^=K!k{ z75>}f*1(?)8Z1NnMfl3VbHQIS&Lv)Jd^r4N_^KeE&yZd*&i1c{&h5|B>$q+m zMqiB%_%iDV?(5-egAPlY+_ zB=Ax2mT^7{-hxL(*a72j8|R~BtI011f5$kl8NF-#JNSFPYkaMNZ6<+hw_iY1hyMz{3G~=AYKaoF??g-jPHQI!R!CLmBM`|DmIx8KZ*FK5&taWpBrzF z{&vAP2mSH7;O>a;p@--H$w=6XiY-Bdrh&f==Mzv~`T7F!t!9E>8sCCA{XN9Fhx7G4 zeH;9Cl-b``@b`oE>~kO73oFi|;%iiV5G3$9-hSgP;0KIzlN>b8{BMk}fqx7CDCqA; z_;>J60`Cexl-k`(RB+bcn*<(M4jboQd&Kz7#`zE%68NVWpbN^J;19_EEEteG<&VZ& z!hcHjy5p-d{e9poRQ!yDy@A(;|6-g+!lMyCX8bk8kHfzT+VfFz!Z;`Nt8w;!(lZr& z9G^1I3x~hK_XQnZ0Y8n0-PeJ08=o=GL-+5<599Q+Ce8_+GjSd#ygwodf0~5sNchV* zkCcB${DN_=p^K6J{)zad)EtQk-oW$!<$qV;3PBEh*QdWpc;JZ{=Muyto@AU8PBzXZ zOo4wJ^v6d*YFbjlOJaPNhKlckgwA;Roen<~_y$}q$)1)q;ha{ki03iR3Fb9k9iHDf z;{}XY=kc#lTJFRET*XBqUd%X8*H;+N3NIb;G7&FpoR5NXm_@jNv9$SX-z<+=gcY1& zWz&FOCE`^hUM=F)BVHroHI4JiYAw%HaEa;~=jrlFSc2XQ~w@1Pc!J{AxcKe~m`K@N5Gd~GF z9Pyun{K0q>h0Zv?hGit;M}s)u#uYl_Yx%xzRvbe@6D0HaO+OAl4M7$Tu*W*4B`KN>YEa>xk;~u|{d1_j|L<0B9X~wyeO*hVM zdUM2YG0sgk(>Nb?w;8Vlza4(YpOB|76Tc&~LjQ;geHoHV<9;XNzXwaeujUQ?S;Si5 zemCN0gE)UX;NFPepH?st=aKON?6iJ9wm%;>4<;&npB?czrUR~#xe#0D z_>$t_zhHb^F2#VX;0;B$EaJ}^$BE4?4?18zkM++PFAHB`yc>Ka{9@359rz3IOX0g< z`9fliUx5;?eB=IN#9xZ|+K9hwoICNW#(8>PZ=5^nYx3Y(F!$1pCV_kD8)?PywaWe) z;Sz0vJAR@Fw=%eIHa-phmT|_n8t2LForu3n_ks?&%HJ~y^liquMm{jkCE6bGkBv`6 ze1~zKJ$D-Ck?>Qv7cLPiK8qymiui8h?_x!S&Yg~LPTz}oa)(d!kXmjce#z}i$ih`(c;PuFJQemt!_zIfW7ARi?sFw4+6 z;a`pOrQ1m_EhCY@ZF(xLO2S9Le=`l(!Rd&fiTLjkKO6CL5%>OxRQwt7zs!X2tkwM; ziJv#lCAwf7MR(CS8zk_fccIrrELY(9 z5nq9}yjMVefgnFSys~kw!K%hN!RndrIUcKPW>)CXTFW?}aMU)=uh0ygC$7%$x`-DF zCXf>osArtNjublkDhO|ccwyyZ{qxY;I8otyQ{!b2Z)TjGG&jBl69}CX>IrX&cu_N< z*2X!Z&?H2(5if4yp@;E~h?fZB70^C(9+>vy-Wl&rR5J_XYwsGxH%?QOgdypM5i)4mb!7xDfP9}w}YeAoComJf_142t+*<2=@1ZJZMt z67iuC9~SWu^5Fc>B_3r~5f8)Y=irNi4r;>r<opE}UOtQ;O&R#b|IPDtLPee?sS>l|Q{luZQ>+_)EAy3$GvK>y=Q%R~Y9KuQXmA z{(^CR3TBn5V8R;XJYBwIoE@$;&iq%5Gk=}&obcC->xGVSj}@<*3Vbtd!g*@uS7tNb z2ur*a&I1j-F`U1SMc)K(608wkAqkypumSw7^xXJi3MAvU4)?dy3x@9L3P)Jc0>Rxu zLJKs=k2ZWp^bQ)d3_9TVzK6~UwuQf+p5)pD@ye+C!1&m}+at~x@7odYpnPn9R(zDG zz;Qe9&ZfZ*#JdCo@LaJo;-5tPQ{y~ze`cKRKM$SfKUVAtD+1pg@jVgW8}ToUXJD;; zX`J69PwyTq(A9zWfP1wtAfH0*LqbopgkMK|zi}?n0pnbNgT@*E#yI2OM*KV9x%~bb zI21|v-Z(ov9PuN@n`4Q8FwXCNr}qh#_=dpy!nwdh;XfhXFK*8NKdZvuOF83TB7QXD z$0B~*_zJW?Vf;pPOTQ|ZP=mk+^8C*k@j2T`Bn*P{#tEE?_;1F!Mot@N{+WpXZk+jN zBYqCat zAT8qQ#@RlLapq?=z5|}kGZoKb0@>hWgBgwv{MulGz2P|!A7>_*Gvc|7bHLojZ-D19 z{x{rX#dX1eye31R7!1f$Za(-VGhqIR7l?Slh!-+G2mKW`jw>wq7Hm{Z4ko~H=u?6T z{DuZa;Zw~7ibcG*aV~KQ<6Pn^jB|kaRU_#vH8SvYJ32_N48Rt$`IpS3!UNz#?jC<^$x~ZVo zhc>Rbsh2J8{>p1x~*ZS!7{gxxjp|qcI{wyo~ zv0#GJ1Ajc2ARlD|5P!m+|F2R7BDisYfe{}R@xc+lI^si&a{-1L=T13{9=`rBjBUh< zg~5#XV;=OUf*EgzkAN?N^Tr8|jQFUCk2cN;Tw|Q=$H2X?!xvF8)+F#JwCRh33Gt#7 zeMvAOes+8ue5skxc;g&!f^iObopJ6{6SLs_A9lcFGb->SL;mx0o{Z?v1q1TXd_8=H z8SsXPPmcH$Ic^S|xzMw7r9PmlOb5x+U&Ga`PA@j+N)GmY~{OlI=@|3a|D z{PiLxtO}NR5&SmzYO}=551mVNd&KWB&IOodoTuMAjdPQFtavGy!08}iZ7_lF;CCbb zvYEg=#yNp|BYvN8ZsYrnp9y?jFy4BMuY~o%fXk5ZAR4@82Am!7ha&!P#OFkOZp0rk zo}K6ad8UG^Y<|QaHO?oMj~VB0gwbCQmZ)#wZv+d}8vX?0o6G_|X`RQv1-1gdFyc=c z=PF-hoD+UJ;?Edo{$k_IUt(P6|D~p)4VG}3@%OO=^tXZ~n;;SRR#yFSwMdLhMzGQqDCQN@<3xxGwCa8EXSfbqU zmyxi|EYT|we>LLkBECN2uSI-A=-mDraNihKaA`4P`iGh!4x@o@4<^WqQg0ysk(uBo z<6Hx8MtrkzuFsC(P^)fkYzGnf!pDgBdRLOI~?z&|w;de=B7^q%qF z@NK?pd|iNM#jaog*3x&wd4+2V?jOMSm;pXC&H=U?=KvoW=LK&1m!^OES3LiR1MEP> zJ~P11h<_6CPb2=BaZc!ScEoes2=^LgTRUDtK7Ze+-u3*C75=umA_(KOp|IS%4oS{!_$%=K0??_{Ajfba~Wx z9}GZ07EFNuNTeSRCXft24nJWga3bQr8s{21>6r>{vs1>o&FH6s0lCfSzXbzwlbwd2 z4hCe0XN+@||8AV|v&I?s&P6Kzi1?oo|108uNBq2T4tT+MJ*=UN#uxKf&{%OcSi<4h z#`JT+67t36CHNn~5^~0uBhDWRv+7lt@B8i%~Y^KcH`UNIgD?`1n8H73C;@qaxlT`;kgiZe2vDo zxaW>|9^?8J#Jr}04e}Z1gz_6_ynu1W3mRvi0J;VHoqaDZaQIY9A_oa1W(H6jT$BVH@wwIg09;&qKbhy}gU_+8jP>3NgzDRiFw_`f+;IiUd&zsfi#I4~>D|KWh!FoA(cs1VHXp1>;x6PyYkjCh8b;MEZy z67iuC9~SZ9UZi4#an5k0@zt0By-F}aUZSB_4JOD745Q)I%mlBA_!#3{W8T>=ZxQ6*55L3s*}z)|`Fw48C*o~_{E_gxjC-4diuOT+ z+u-*gp@SLVUgI2q-q{RrKfFtje``1#oWsCX!|!tD*bchKN* z_#DLh1OxDJI@dV=T~F^HFGHnJ}6Vq=T#N9l+=Z4St z@k+q8N%x!mzqXox`{n%e=bfus>r-{lpNopQPU`GVe9#X6ItODe8H2>}(OC}IN&{}1 zf9hPJB8@PeY_1t{vg4hg%wLEcY?%2a|0wIdtv;8lAD{fvRrVJWZ(c$T7Ex_WVRXD- z5;ZY>=Rn-?>n)Pq04!(<-U@}6IQrVwH20$N`42I_H>^EmhCOqXn48L{P;tj^Q^18c zG>EBj-0^&w6x91uiB1bAXbc(Cka4w2QV+>$n}Uzo2S{%q{|YmRFr?piPrS-kmcmu0^n zzdr1f>k=13(F$8bZkih~ zzw2Lxf@%4kmQf#eLRHaql0Fy~PS+pCr@wahVOnwbix!^s$y%2wj?+pt_2IPqEje6M zf3c$)GZp`=LKR+3q7NK5{)c7a)N$;^V9Blt+NNp;NORrX{BD00)U$1W{|Hy3zZ2!s zE*WJE-x(mL=Frm><)+^v6n!$fHfneV}cexikLP z8a$Oncjy93nT(&u(WU`YU0&3u;n&spu>^k9;otiQ`;2Q~ev*^X{fPx&e>&Rvvpb>{ zNXGDqK{oSuTYi~O48Ov~8o%+Eh{oJq>o~a~JFR#`u_yWN|ka{iNui$vS58F*1Mbg;HrvHNU3w=Uk}Ky#nT)?6#;m4}ttj z57J+T`N;IYNs=E8W|_aW7-3r+@LvVPpq9|D_kevXTUJpWxp^DdWdI+;7u3yJa(l10O>kH;m+#Igs z)Zj$1M+290aUa2j_>(}`2C+cI4 zzXXgACh4fbPlSd?I!19A#w#lPDUa@KgRsUwKJ!c$*OK8iI5Ly zf6>K1Gvd-AdW`8T>F=xIafkJI`o#g+szs25|4V6hS+%;JRhj2ETmVbdBx@(e^E*~+ z0BnN!-~UsnHP=>(tERQm7);lWo<+h8rd3uGIqjBXUAPKc3&ubI4595BQ|1 z&vblFnjiFNhK(4WSNUT&xq~w>%XrxQm;U{u9#;)knwG`iY57&bcomEKI4*2)b#Uf* z+Q=_C{O+;fy@{_%gFkp8nKcV&u`23x5wN+{4yv!V}K;#t1!@$ zzWx;2`RE;>kA! z&phy;NexaO{O?+d&gDMQT+75`dy?CaC|(L^iu~ELn0{+4?mj?AN$xW(-wf4%tumi& z@OdVq>;Y#J^?wDTscwgQ!?f@*OuWCCN&L}e^=;wdL^-@3%tN$#`cUm-|U9H~wt^Cc6VF&r;jWnn_9ef$umzE6!EzlVSXe zN;O=Ll;C9J9}@W(@oU0O!)c{z&-WjvarXcw7uRo-#j&Q?8y_#&Z=M()j}`LxJ1{x% z_H|sc)=#wN(a#&_)5;HbBED9LyN}eEKYpC7A9?ndK3(e|uFn}H>6e9*gI$#`slv%E z(MrCA8vn$G{xFG{8-{B?=(>`Yaw5u!!2e}^vOdD|KehTlM|q|Q=Mow6|J?Zhhqn9$ z-eLcVfrD{9yYl~6miXTb>^W}r|G>b(xE?{FBpvZV%8imCT3V|N4gTa6I}? z?g4l<@gLm-aMJM)g#V#qfcL+*>;1QnG9Lf`+ra-y{V+aLkLmP-6Rw8j`uIQ9{P&ye z|9vqq*42^0YGH2(FX8ylU!xPkXAk}_4q04?zE3_eGi$7j_ZXf8stKNk@D_9D7RU5~ zWB+YOta*Hi|9b^|8sO*LgttKDQ8{l=bN!3>G?>c#j2~NVd^x7ihWW2MS@Y$(n0~+y z|1S=5-tji#>8#|6pz5>NW3H6SrGuIRZ~9j`@#-b08L%bhDyUpBs5!d_+eKwwPUK(@ zf9ZeSod4Nh)?B+UreD*+$Jv9Nq6cxoqqc<4j+u1jH@K_J>(Z>Lb;$p&L;OcGsJZKK zOy6SX|6Cw*4xNwbtBUbK^B`x>#h7cUa;u=G!#^?CM&-6a&A5N?@74B_4nfrhBz01` zb5QdQo&t4MnJ@JDZAe@24M=a{TaI49b&1vZ@}Wief}z*&lyC*UIB2E2Bkdb}{mwyr z<<2pD&CXGL@ys9ia+%-oT_BBOd()c4zD#Qx+n3fZwm)q|3}3G?H}+%NoY>E4564QS zcS$aj-Z{BkddK7n>0Og+rw>i8n?5|bUiygS=IK+DTc+QX+&cZ{AxgDn%+G1@$_b?_>gJp)9I&E7pI>|eLel_)J^FJQ{PH& zm-cr06KVfnTUP>BL-)q#%-rg>(XO=b3(>x*l%z#UqJ=0WiHZ4a z7RjL7Kang-M^QM3MFJgkrN*KP6lnWc^vDQ3?}iXs-ntGE-e84ZX6QPA6*96 zj!!J~yN?J_OQJhl&k!MtDqkT&7D+xJLKd}uL4+*2jV>AXv52|Xb%RAo=ye&NSTsxx zpyyr~zIR%HaADD7JwQaV=mMImor4fM#H>KeF;}ue3f+j=$D*B%h>%4wZitXYVoyY< z$PkY3L4+)N;D-oVR1$y)S>!n!@v*2g6!Edh9^G-d!6GTTGJc2IPyho_v z13JX>i6k`!GDT)17p)WD(+jO2;e2oc|y5_+1b1dFy~Bu^Yh zDE>RM*BLGHsbSGljO2+*E%bW3d#vydvj&LA9E!`Cl_m(u6Ppn7VPy*FT}wh1ZNNyL zc#BX2E3@m1^2st~?_eZPd_qXb%KUUWBu|V&sDYJ1gzll|H<71@>2Xk=h(pMT&j|m) zh$|A$%HAMZ4U4?=Q3)1_5HdnD;e6r(M)JfhgyLD55t>3_5XVx3-aEr5)C>^|Lh^($ zgOt(u&nMm@cn>|I%qPS~$X3*E`9v#v9|nWui6;m(urd!54sj7cs5ALCBUufLT1*iO zivrD%2m3I43(PqrPt+ph!^(zRa7dmQi;!gvE6hjm9*f>!Bv1TA$Vi)^iM1qYV-4_( zq8hLg?4D?g~gBZj~O4l)9!U@(j`0zM`ZqqmC(9e*_?`1+K{#z-^xT~i@aIw#Na zp0&gC`{#abT0RCIHv&dxxu=ZeG{fJ%6{;^-aMdf-&vDD!?Jv|v8LxDnH>oSX-sk+6 z3^O?16_~(nWKP;(*z77B?q91DF_1q&NKzXKsY>L3Oq?^ zIqWtC{-pE<^fm*|Kp)OF1HK>v?lS{kZxMc1IMIS8hd@-*OlbKnSK;0|-( zK;{*}2j;++%sURvEx=59o~BMdKVK!^5Y||LR|34b*x0DMpKnzD29M#Zh(#v$)Pg;q z58UW_3eTO|8(R>wa?J84q7LSRmD@`%Pt~{@Cl}+taZVrCt;T;^YzhT&d zV*;}PQ1+f4Z?_|_KxWBh`5RVssy;W!-1*a2SlwxQs(G-4cTIfyLawcEk*#*BL|FOG zczJl!<`V&*z?H{!lcyP*)=kjZ-*#osI?L%={5|$>`rkMC5pXdt{o=cD)0e@~d)AGv zeq*pA+or!x(wj@Q9~BEmR<_UiL>nFWp6S}%r63rey``_)w9*M5r;c(0Wh34^ZareX zJhB zT6sJ-MEx1hX27dnzEpz26ZcT=e0avwH#-j3eZ8_!Vc%TxNN}e4 zZYSHAZ5G3q>}=`C+?4UHAtt%4Nc`eevxeN6R}aRYbjiCcD(n5kd($>y(umOG(HcPs zcf;UnYasd^6orw6GYe~t4!)n?lpicKH8fG*v##Zoxs6AaTYmky9TC?~%ijGq?q+_4 ze-OHv9D8Tx12?Usi?$vXZ+s%VH9Gfre4yo)bIYq<@96xve#pkB2~!71+=UyZjlnZ_ zrAAey4*XR7Nps(%hw-V335gd+@PB@}WclS;%R6_$rq3OMpV*7n?0^6^S0JZ*^^p*!`A$4N?Cih=;7>u z`^h_Z|F{+vnyyE;C=Ql;y?J3|@AZoguPDrZDe#M$;`>FTrLb_&a!hwPT-u5!N6L0=h`EaCtLh1f*z-&{PQF^J`q`p>DHec-f`Ec?6$#TnQ zCGM8aw|(UF>zb4H1W|0F;m8NUAIDdFw6<7^uPYQ@?7Db2t6n-}>S9d=v%ozS58V6o z`$vPn<(L2J%ApeDy=H2sYSZJY&Rj|Ea@Hz{FUTp_Ff?y}?W5Em0zKV=%T?EpRbQX> z?XZqXh|Pr@pB#gXw&cq?cZ`6IN{GdQ^Uj|qh315GP8Q6bt}`l4Kg9Z7@#tt(L-~f? zSFV6h&muxTD%j8ScI#a<`PtCDdyT@Pj~7q7{M^~geqgh$YJHT+PR~i-A|AYMJqee! zKBG22>W*q0>oomY*CXw3!v*_u4yPY8$f6w&KR#Gl@@!)A>m|i!=h&7fzqM^#;pFsO zE45>)+nT1SujCb-0;1$Bo!oT|MLT@=tjK%N^||d@?=6wriruGPXzm@AFH^c`-@emR zcXrqGyJqE3_rx=IVY48vS6D{<+Qtvnx$`T3Mqjqj-4cJ@U{>()D2b!a;$H6rw`em@ z;i)GMnOzSjE87k&KRC?$vD)OX4at{|$-LO!62=WhPaU&1K6UYn;1 zK-Yy+t|zq8e*Eb5=)J+7aryK1{rtSUeTe?Yt2RqNYDy&ImLD~mcFJGvinY>bnQOM) zVokfuKF^X*w3j=Y*Xlfv$h#Us?xM#{blkGE)z-TY3?QPyeb`_Li5BW}JmtIIzAR5Fax(;W7-(n@yJ zUB3U5wy681{=IHl7iwmAdQDU3z$SsPbwUOf3&O+`M?+%!{i+mh2dp9&zP7DDOLv z`ef_3>&0l{D&w&^)0*1loJa0-y7Eo%WvzHpz)L}-aFtHRvF{7LPAfzlZBo-`@;$F4 z&P7f8r>S)0Iv4q-iPHMu-O_`#qt+@!&MPnMPo2g@W%z zXZ4y!HILQ{zC+5C4Sg|2=T(YNw?@M^pEC>O=WlQ+?H*!wXML1S`B#4FdtTrcx95&= zDl5^Gz$;}}@s9Q$WlrI|{aP3`O(E-e{;k3C1HY&YKQLco!m2raTDK975A`-g4)F-N z;j>|-ulC8+vbW!?>9xvWddHU6nGq*5x6QwGE&fPE!>$&=(<)iZmWZgI7r%lVrJv{N z@pU|g3q~3g$Q9I`3OMm`K1Ti3PiZ?AYM#I8ZCsJd zR;9FnjFIV5yTdDo?{F}1oDnK6^qf3!hW6}jfi+WVCis6*FM1qV?A?rPX^c{tR2AJV zKEB1hyqa_=!cmI{6e$a2KA8c+`*vbRIf^}ewE`^^IDD>O@270IQpvF zsoNf!{OnUX?wW_^pE~S1cxqQcR=Ufl_XX~+?q50G@5#P^guc_G{V#=4njh|bJZNy* z``fPV{WrWA$KRdV_qnN4b6*1f13dSG{FTivSa zy@3_4Bh$V%+{(H+=W_0=3opjq+&u00l=}n<~_3DR@yG>6+fPjs2bboI8#6Rp@;S8pN?uD`>TXJeZJ&$UgVN(iIW57 z7!(|cPD!}>>bri(Co5jo;?hXWe@A@nv(6O#3heEy<^O?yXIyOJoIx z);!(L=#uu6=95fybyv?n{5f@fqF>Uovh78a`cIwyb6f4=pvxtn46Mp@w?tpPJMf9g zq2dDb`(Dvit|j$mhc=!#TAXM8%4_*-yHWLhzCUqM*UoBFOkL3)RhuLs&ZZb|W2JbB#}+H%8_mHMVS z*;D7&w4Z4@T~+g>)nv)gms_SzNI4OBa&PFvqV$CDi61IfFA3>yle$s=T;PdyjT`%J zS)$SZ`SW)It^TI{3g548O;37YU$?nl?&i@Yv-@xDe}0;_qguUH-RVe2#BEZs<78j! zHubhOyZ$MbdS#A?N-5HKdG`5)7e&oS&HXQ?opvm#TfZesI?YsWxWd=$jZ4xJ?!{ca z6!M~`SZKcYf|Gt<`RGw+Q)4=s8giYEnqPksbLAv$cED3HQX$&t(Bqhq$6TKb@KikE zYW;Kd>zL(79o{^xlKE2cXf9oDrDXf8quy(V>@2;JdmZ&ge(hCRT`QDt_&Ms=(eT+@ zUPl!zbTj)NGQn`)?qSEw)v6Y{Z~J8k-#LKw%J_trIkzcYN3U}PJl=n0sLsRLnL{KI3w=`Ir{yqhq;r%TQeM4VO1N%1IS6|;SN zG{UF&Kl`+H?Aqh*+S`^^EP_%}B?@L6@Y%jrb;`&&+cFFzA=NW3q+d z$D3+FYwN^9Ezj&e6APBi)NA-U=g^N^`OQ-T?-%TH3N_VkboUyr68m7eAD;D777XdV&TLTa+0&^fFIvC14a4SnJExM|et zh7ebe#%});Z>G$Ye78v)Ec2>s?4dFAxnc`9D_wcrfTm@g*VDDM{6fCiFVfM?xzM(J z=29gWt*p(hT?dYKSnVvNw}xtN_CDS`U3Yf&_B(2uw|8YWomAAj`a?8Nzy5Q{Ov#!E zgFNRjfnd!nz2|2F<>IbRx^37z`$g)74Bb!53+a}HDeGILcU{)clUesuPDJ1PCEsd8 z@-v+Hq;kG-?g^s@)jr~emWJJpg}}AKTx&&*oZCV*IJ28Lqu4;oSj-DNW!lN#QmCZt zxhcWr?3$=0(=2 zEGsNM-D+(+B2}9kTwf&ADyUm;4&PfoF6LZuB|qY*nrraz!ZmfJ z>NmVXn~b!w1;+|r+*~p4%Cg@%7ESThy|1EM?5%IfAVe4#5pNBzb+*dOLsi-6Q5bHxqp3- z=;i{`>(MXI=bwpL?YFUN{C(kt;oCp!d0g$==)T^+r0L+UT^o!9nTvBYEGu`6K6*W& zNpa;?sJkKHMTvvk&Rt2BZ?mtL&mXgXzO$|2)n?1})TGLqL2=n3J3T&h?o5rY8tdZn z+;hD0hx-GUrVI$U>o*}vu>|tXwB7Fdrv`W)_|g;dS8{!l^9%mba76l_4)1*9jOnpk0XYx8ARyQ z!|=&K-<7pdtKMvAmO15jV9bzMop;Ly!^z%j!@d2o9m_Hd%k1Xb$5{jvnoz3jRU{x1zgohqSx$sd{t04r82(n zJH=;Za~@@-l$7XB4nu!BPac%qT_LyeOo-IUYD87Cl1Iil<3$GA6)Gnq&+d|ccZ-g= znty*xp#Hsi@1|>fUHBzi_|seWp25ayJDtTZ4!_+r@LPdOb<{s)ai=^F3q!qxKVuTC zauwD(H_RGqmQ$PaWB=}72fp?yoAX0Z{cf|j`Cj5g|Hm0)QR?uI!B-yCRHF<2H-DRio6>VmGz012& z6WVUL-mjfvcYVH^d{+j4{@aj2w_jhlxjix|aalQ)`po;y#_3sA_p=+jyjtxRzw&Mr zTzudE{nR`EoKIi9R?Eq6#7p1llLrLkxm{@65AL3cli6sz@bj1}lXjWy@gLmv?1x#e zdcT8r2E@8147YPSoz@gRcVW2x^y^_$hplNn=&gU!E~I7d;^geAPL*3OlkVNvzI9o7 zrzLf=!k`=&uS`-qGjqYM8G65NJsq^^;8&-OIZvzv-#sjjesv<_?}ttt6dA80>KwN* zP3P#FH5;KmA@LZ9(CKFIqUmv$Hk_xKYDr3+B@z~b)%PyJcC@j5u%<5)+R z(#viE?;g^_?ey(?U~-S6+VRnJ_+yaTLwf2IeW4R9>A`S5j!u394)(}<#fi522%LHx z{BEStv%Z4CJs55sq>ujs=X)^RTSZs!$WJ{Op4QMcisY~!3@<;>T`FW-59xbUH!X5l z4~8#}w7ow0v4^&wZnTpL8UMEwkSpj~3sRB)mw$o6Vfx4b^6KBbKy@Wu|F#V1xzb)fJ?#Z1RBX6(e-G*C$Ml_fq-zgp^g!A)hm7qZ9k-NTDj+xakj4$A{l(;h z9@2#Cbn_yzxrcP}F}l8hwCN#D`AI)7BJawmuPcVu&1pm$o{1E;`K6(=#zXzQ@(NaxQ9>tkL@{Sn*O4(0@hcO`fzb2siG}O zJz7Ty(W2aWSr?run?sA7sThntb8NX!UBOld-skNZv~Cqi>&uq= zHh}UVy6q6@K^m=g0u5mGAm%5A`I*D~9FM8`eUx^pU%d(z_D3u8l(IZ*NYgilDceju?IdY(s)hi?51<7H{FNKsZcOIS|; z?JQ(A(O>iuUcE`C>avcacl^KF!kAm+c__F;T5-A9FkrpI`fvYXrcgROafiH3dI{j# zyW|8QTG>JN1-Vd{NyN~lgERvYIIe?SDDak-rFeY4K4Hv94<`XK%NCXYf9>>#y}A=+ z!L5s)jUZHmP0&qvLN82NnIT}Xex$O}Z>%@|4^~T5R%GN}C{JjHydnXk?~#MlmY6WL z?;~9193#v}PfQC-;f8x;G&ll(-a~#p4g20FEoB!odzxXueKJhG0OcnMUExPqeV?2s zTZmriA<~5U4@jTB_R0)dn#h|?O+-U{2ML#;cSedr;M@n~K{>W^s4KZWBoE05T$s$f z+$3hX1WHrbRW&Ge=eE;^;52|sGaPX0%B7ipI1S{|tid=P%B2f1&jN35TQm@-PRtWr zO1XlGLlg-mK9BiXphzh5^%Mzp{zNWQ5iV4Ol@w!Ri?Oj~*w`|xWEI}O3h%FUKob%lHEm{Rm_# zXr0^nyMmT{D>jE%o>M87=W>dbIhA5%PNi6ttA|+CpUbbw)mN;E$}vxkh;?vA9Ur*- z1&J1UarulxxYXPkryg8tJqD*^nYOeP%m21WiLaqZ@U)p>5V1OAvz)P6?$|7Mtj!CX z<>k*-OzixdMu2!YiXco8gegW~iV>J198-kjnvLOnC?4a*m5;$SiNQ4)&-qq7p7X7E zBCgp)53VLbtO@Y?OHx&k#&tJw8ZMK8b!A{(nf*B(nf6?o#q|hr7WVD}Y|8>{iwN_G zux=?A*kUOc*y6=_doj0dA}$K$h>Ie)v=}QYb}>T!RT8JcyjP@=pc4D268mT^_R(7G zqYc=e4LIKxEZ^e8M6b2Dl5;z!V=vCM7n2>pWCw7eBSBogBcV*2*@*XspogH??$)1g z!R^A`O^myn7r&&xvuL6XQN7euq`Q!>YP)t-5fnzTjGY!5;sCy@0!(1aO|00Ir-whVza@CQu9M zCoIJO_DN)uB4ML4fHhsB%ITG;a(X42TnCb9awD}whYJyj4i_R4eXhz9eJ&Iv#$5PH zj6;~FQj%x}GPPd7k=t@c3M97J8hdP=Jy$D<^GGhE^BBf){Uo-(`>pk$KdVpczZnFo`@?xkvr5$ zlDJrvBw@o+ey7;LH0;1M?7$2sIXhH0o+JYo%)}ne^ioB~c`eC8Wr}bl1}OICkr75H zr-Q^7Horx^rUElpVCHIUSv9t-7FW5Ji$=*NuGdR81+%?IQt_W&BiW6~c4IOclhK&$ z5I5#a4u!G3MzZ_gUSo^LaLF0$>N8mHd0f-;xTcr6(MNI_+tCukHEzoUE^WmsTDilD z6K( zH}2#^@@)jC=NI1oHG)0Kkh~eiglv)`p~<&me$a`ACZAyQN)YP)g>YP)geYh}__Th|@>T;Em>T*U)4Y{F0YRC>1)>6ga5zh@31W(!ztL%qW z4#Z3Yu||O-*9E1H!`P;h_WMm?!Pnxf_QDiim|`%d7>p@=@wPAC_QTtLc-tSB^GAaR z8h@o;j0PS$VNv3tFBUMroSrbOCk*Eg$2{SfCjwVC0y_owJt^*c(kSk{LK?+&326*= zW(;=bIBt-Vj&o#M%0?Q-*a7uFqT@gAe$phYdNNi$8LLj_x~nvq8=s_8>^PIBaEDWA z3fF0*DcG4)ak;5n5KE`w{nPONRBT!*XPSvL4L4{S7lqPvTp-=o2-#{bO@h}yqF~L$ zF2ZNR(mB}9IauFZ?4r5YMf0%T^RV4n*zPQB_k65oKDH|x+m(%7mcxyk(j0EIagZ*+ z1s31}3vq#kxPSorSm0=m?6#0*!i`;|xu6j1EyQ}4;bO~hu@$(m_%{&)(aD(Eckq9jt_FzmmQJNPx++<+X$r zJdqkVsEBG!*gA@8ExB})0ZvW1belDo?li+G-rmh!YKV5*a&j7%r@06b9WvtNhs@cQ z6xG_H3rhB6NRzL{wB%g)Z6bN^F1n(WwJ8H0e=y;% zl+{PL9om!B0z9KNl4-(p6%<&JA@Z`sU>^D&7qUoCxCCAzsf%c0XAMQ!_MHCu)6~D` z%{oyo0QSN@GSnil4_3)g`vDE3WYNNg{V-3K^0w(QHS%XxvHiux695n__XdIHGwrU(hb_$m(n-I1nUmF>k5h!ecS$wM6iKTy#&Q!;l`C%%? z`tOgT|4zT4y{q$Jh&;6loP_AzzlTj4Q6CmwKvN%m&}&-IH%?K^AxH3qNFE`)p=>8S zMK>x?QvjM&u~nk_=%95b)}ke-?*tR0RR|~2R>6WtqN$kEaJ&-L1C`RaF@eyE4!Fqxnt1%g`2{L$5RyA3|z{Wh7dnhMr;Pqt6Tz_QG?}R+aJq z=iwApsuEm)vT9T*xCkrMsL|jOe5*zc1(%_-Iu#GDz?JIMNYD(Qsv~z_g?%)r63_y- zYEUs~DvqZ~IfLuaLzC(cZop(sYCLF#r!=W=pbZ|^q8w4Ec4<+$pdHTZLz#h_u(A(T zsnSjmCV69&<jFZ93FMfK+xD9O#C_```1{+Xq-~lu>q#$?*4;fO~;1TU= zM0o*j0+yXxMe|KUV^kQ=$>yPkLtS8&DHYcn4PNd_$}+4(PFMu*n^OAZ>b#X^Xslzy zft~flu?oi_F?a?yno)yM^2Cf1q9oazaz#nCITZjp;Zt+eWu8MF3u+s90Z&;_p5P@U zEve~#J%abo1S1n&B>GMa(~FoNDf(e%l}X|RgE(^;R08){Qs$rt-n69VfLAcwiZb>_ z%S+G*peZa>R+L4JZccz+St`OejFcxUtW{PcfI^n05Un3!v(^2T?H#PMLP78zc3Dy0 z-~)8BMq3|YmNnH5x?zM36-Wv{!%7=!7AgD!)%sChr0^>Y??)Mt!f$X^KT1przr)Y{ zsCkCMALu2kBB81-ftE7x(WEWfs1ID_MokA*P~IIGq75gxQx-r67P?cD zb1^d&T%G>BFb6oiM?*wv&o(Q!*Qv`h=PgDr|4x;pXUmGMc z;DoY-ho}q=8$@}U-}tL&23yqdchRZ2UT6p>VxZw5N?WE)C=?mN#z9n}R^ClMqYkYv zVvqQIVI2w`V_4xunV|J0N4=;pnY@QVB2%d5O^r6ld(6C6>fb-KG>-jaQVWq8lz3D2 z@_A1gFK7tQ(nq~1MF6i1rec9PwDqBeYa0D!BU(>Kgo`X-kq9YQ$)YdCBOHP_NX7LlUvN8~%OMfW4f{QWm|6xqN>L#V-;PJh|YeB9bm z)DOD(QG*p-m@xz`vm)|cV6GqPFa6<8KWeVx;D4(y7}^h|bb&1#F_aq2^K}#rfXfl; z<@aw%KPS;ZcxNc(!}E6%*+FA}gaQVM>|v5W6`&dPmvReMxdS}zk4D$w5DcT10Y_Lo z3>_6qz((uE+&m51^JRPDks)2xG?7>2!J^#RI?<&I+Q2 zYL@<`0p0r{hKStYg&-=l*UEROdT6~Rk-u`Z$Q@b*Q}IUSXt^YT7CRF80D4tkLM~-qHk4mEPBaJ}A5JCPS2Ho9D>i3O@Rh_Cu1qn$fEl(3 z!bg~^sfxY?h$C_(l6u0J5EPMKFed~ZKfPgH2z5|tKY=o%)on!nes;isOGhAmgW>8C zRI%p4zv{w#C`C`?1ARg%E8dYPkuOXQr4lud{gr77sz8Wn2z(SuMJpXYjkcHqs# zhdxUvBR)Dbkb*FgA2b|Eg@K{;^pR-j0seGxIMobfhM}eJfpBd+H4u(lKq=AdA}ALC z0^qw0N*CJArnI5b80rfMgm!UAV30{^)9#VXP#lB``aoj=WdiFKQ_A%ID9Q$aVAzrU zyP#q=r37!sQ!4Q5SgIHFiJ_LG7H^KB+GRpe;r@))KAeubW2ss&g4q`b?~kLFfKbkW zdlQkqwXu{w0AWyN4q~pGh9vLDqeDL!Nh6z50SKon<0(r3Mlt1eAu4kVE%9RQSd)u# zzezyh3q~_FaD?8IP;JI=?95(>_UbVPYQf4RDj!60B)_JhT_fh9T?$iC1*DUyk1|oe zUDXFNyXo!8$W=1Yf2x9{hd>NRurwbLyiTD;z^7BuA#p53HtN#I`sDzOqkYpTRiGZH z5zfR9#=L~l0`E`lJ5(uB(rC>i)>5hV*>rc>TL;UiHjO9o?S zQHpR|6s62mN(o*GM_Fb~r?h#ovKgpe(^1RFrc)}~GUzks8JYxo)08G5Pog#L@jUc$ z1K|p|BaYJ1j^v>mw!$SmLY<)G(W@X8nAf277E0jo8B`${&-qblCaR4>2K59?U|iRZ z4z<3sxYkgF=gKGr_-!WT58@eV3p(=tj-IO^fos%+Ov;#wR11TGOyq$?8nvYjkeT$y zcT7ve^ttGKDv5I-6MHmj0aXAdLlmpJ^!zMzMhcQS@(=T=7hnpFS~(Dals~b-MDbgh zseg!*7gBq{G|t?bDCDuqsgw>KD?rD6kh)1Iq)3oPi*k|m=yU)DkRxM7UpO+8QiB!} zbheWMU{k-0Fv7~!)^ zQ9WvwprLafv$GLo!5vGHTxBV`0GQ9<8juacmQh(C2cBJqDzN~DEJw*gczHQh1q2LD zg^UnsGUhaymr%=PM1M3lm!PxtTo|!}nuhLXA6r4?p}W}urD(*ELY*?IKxPqJmhHjE L$|zrS93%b*lo$)K From 21163d83fa2670dbcc9cdd57c6c1776b33a91d62 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 10:42:33 +0200 Subject: [PATCH 093/283] Make CultMesh identity and route recovery explicit --- package-lock.json | 2 +- packages/cultmesh-browser/README.md | 11 +-- packages/cultmesh-browser/package.json | 2 +- packages/cultmesh-browser/src/index.ts | 22 ++--- .../test/cultmesh-browser.test.ts | 28 +++---- samples/eve-browser-network/Program.cs | 12 +-- samples/eve-browser-network/browser/main.ts | 2 +- scripts/verify-eve-getting-started.ps1 | 4 +- src/GameCult.Mesh/CultMeshClient.cs | 79 ++++++++++++++---- .../03-publish-an-eve-surface.md | 60 ++++++------- .../CultMeshClientTests.cs | 47 ++++++++++- .../Plugins/GameCult.Caching.MessagePack.dll | Bin 43520 -> 43520 bytes .../Plugins/GameCult.Caching.MessagePack.pdb | Bin 19940 -> 19940 bytes .../Runtime/Plugins/GameCult.Caching.dll | Bin 86016 -> 86016 bytes .../Runtime/Plugins/GameCult.Caching.pdb | Bin 30144 -> 30140 bytes .../Runtime/Plugins/GameCult.Logging.dll | Bin 6656 -> 6656 bytes .../Runtime/Plugins/GameCult.Logging.pdb | Bin 9480 -> 9480 bytes .../Plugins/GameCult.Mesh.Quic.Native.dll | Bin 15360 -> 15360 bytes .../Plugins/GameCult.Mesh.Quic.Native.pdb | Bin 12216 -> 12216 bytes .../Runtime/Plugins/GameCult.Mesh.dll | Bin 653312 -> 656384 bytes .../Runtime/Plugins/GameCult.Mesh.pdb | Bin 197240 -> 197728 bytes .../Runtime/Plugins/GameCult.Networking.dll | Bin 496128 -> 496128 bytes .../Runtime/Plugins/GameCult.Networking.pdb | Bin 235008 -> 235008 bytes unity/org.gamecult.cultlib/package.json | 2 +- 24 files changed, 178 insertions(+), 93 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0b8aae8b..74a753a5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -846,7 +846,7 @@ } }, "packages/cultmesh-browser": { - "version": "0.1.0", + "version": "0.2.0", "license": "MIT", "dependencies": { "@msgpack/msgpack": "^3.1.3", diff --git a/packages/cultmesh-browser/README.md b/packages/cultmesh-browser/README.md index 62f70585..4f5c7e8b 100644 --- a/packages/cultmesh-browser/README.md +++ b/packages/cultmesh-browser/README.md @@ -1,7 +1,7 @@ # CultMesh Browser `cultmesh-browser` is the browser-safe CultMesh client boundary. It owns one -WebSocket session for a stable Verse/provider identity, retains explicit raw +WebSocket session for a stable Verse/authority-runtime target, retains explicit raw document leases across route replacement, and correlates typed CultNet operations with provider receipts. @@ -17,7 +17,7 @@ const odin = new CultMeshBrowserOdinRendezvous({ const mesh = await CultMeshBrowserClient.connect({ verseId: "sample.counter", - providerId: "sample.counter-provider", + authorityRuntimeId: "sample.counter-daemon", runtimeId: "counter-browser", rendezvous: odin, }); @@ -38,9 +38,10 @@ responses because the domain still owns their receipt schema. `CultMeshBrowserOdinRendezvous` speaks the canonical CultNet Verse-catalog messages to one or more configured Odin WebSocket endpoints. Application code -supplies stable identity; it does not own endpoint selection, reconnect, or -resubscription. The physical provider socket is a replaceable route, not the -provider identity. +supplies the Verse and authority-runtime identity; it does not own endpoint +selection, reconnect, or resubscription. This is deliberately distinct from an +Eve surface's `providerId`, which identifies the UI provider inside the Verse. +The physical socket is a replaceable route, not either stable identity. The browser handshake carries authentication through the host application's ordinary secure cookie or equivalent upgrade credential. The C# host adapter diff --git a/packages/cultmesh-browser/package.json b/packages/cultmesh-browser/package.json index 7f110506..41833562 100644 --- a/packages/cultmesh-browser/package.json +++ b/packages/cultmesh-browser/package.json @@ -1,6 +1,6 @@ { "name": "cultmesh-browser", - "version": "0.1.0", + "version": "0.2.0", "description": "Browser-safe CultMesh document leases and typed operations over CultNet WebSocket transport.", "type": "module", "main": "dist/index.js", diff --git a/packages/cultmesh-browser/src/index.ts b/packages/cultmesh-browser/src/index.ts index b14e05ec..efeb4515 100644 --- a/packages/cultmesh-browser/src/index.ts +++ b/packages/cultmesh-browser/src/index.ts @@ -16,7 +16,7 @@ import { export interface CultMeshBrowserIdentity { verseId: string; - providerId: string; + authorityRuntimeId: string; } export interface CultMeshBrowserRoute extends CultMeshBrowserIdentity { @@ -49,7 +49,7 @@ export interface CultMeshBrowserSocket { close(code?: number, reason?: string): void; } -/** Resolves stable Verse/provider identity through Odin's canonical CultNet Verse catalog. */ +/** Resolves a stable Verse/authority-runtime target through Odin's canonical CultNet Verse catalog. */ export class CultMeshBrowserOdinRendezvous implements CultMeshBrowserRendezvous { #options: Required> & { transportVersion?: string; @@ -75,7 +75,7 @@ export class CultMeshBrowserOdinRendezvous implements CultMeshBrowserRendezvous async resolve(identity: CultMeshBrowserIdentity): Promise { requireText(identity.verseId, "verseId"); - requireText(identity.providerId, "providerId"); + requireText(identity.authorityRuntimeId, "authorityRuntimeId"); const failures: Error[] = []; for (const endpoint of this.#options.endpoints) { try { @@ -86,7 +86,7 @@ export class CultMeshBrowserOdinRendezvous implements CultMeshBrowserRendezvous } throw new AggregateError( failures, - `Odin could not resolve Verse '${identity.verseId}' provider '${identity.providerId}'.`, + `Odin could not resolve Verse '${identity.verseId}' authority runtime '${identity.authorityRuntimeId}'.`, ); } @@ -281,9 +281,9 @@ export class CultMeshBrowserClient implements AsyncDisposable { private constructor(options: CultMeshBrowserClientOptions) { requireText(options.verseId, "verseId"); - requireText(options.providerId, "providerId"); + requireText(options.authorityRuntimeId, "authorityRuntimeId"); requireText(options.runtimeId, "runtimeId"); - this.identity = { verseId: options.verseId, providerId: options.providerId }; + this.identity = { verseId: options.verseId, authorityRuntimeId: options.authorityRuntimeId }; this.runtimeId = options.runtimeId; this.#options = { ...options, @@ -477,7 +477,8 @@ export class CultMeshBrowserClient implements AsyncDisposable { private async openSocket(generation: number): Promise { const route = await this.#options.rendezvous.resolve(this.identity); - if (route.verseId !== this.identity.verseId || route.providerId !== this.identity.providerId) { + if (route.verseId !== this.identity.verseId || + route.authorityRuntimeId !== this.identity.authorityRuntimeId) { throw new Error("CultMesh rendezvous returned a route for the wrong stable identity."); } const endpoint = new URL(route.endpoint); @@ -733,10 +734,11 @@ function selectOdinRoute( identity: CultMeshBrowserIdentity, ): CultMeshBrowserRoute { const matchingVerses = response.verses.filter(verse => - verse.verseId === identity.verseId && verse.authorityRuntimeIds.includes(identity.providerId)); + verse.verseId === identity.verseId && + verse.authorityRuntimeIds.includes(identity.authorityRuntimeId)); if (matchingVerses.length !== 1) { throw new Error( - `Odin returned ${matchingVerses.length} routes for Verse '${identity.verseId}' provider '${identity.providerId}'.`, + `Odin returned ${matchingVerses.length} routes for Verse '${identity.verseId}' authority runtime '${identity.authorityRuntimeId}'.`, ); } const verse = matchingVerses[0]; @@ -749,7 +751,7 @@ function selectOdinRoute( } }); if (endpoints.length === 0) { - throw new Error(`Odin advertised no browser-compatible route for '${identity.providerId}'.`); + throw new Error(`Odin advertised no browser-compatible route for authority runtime '${identity.authorityRuntimeId}'.`); } return { ...identity, diff --git a/packages/cultmesh-browser/test/cultmesh-browser.test.ts b/packages/cultmesh-browser/test/cultmesh-browser.test.ts index 23f6f5a6..624bdf17 100644 --- a/packages/cultmesh-browser/test/cultmesh-browser.test.ts +++ b/packages/cultmesh-browser/test/cultmesh-browser.test.ts @@ -21,7 +21,7 @@ import { type CultMeshBrowserSocket, } from "../src/index.js"; -test("Odin rendezvous resolves stable provider identity and observes route rotation", async () => { +test("Odin rendezvous resolves stable authority-runtime identity and observes route rotation", async () => { const odin = new FakeOdin("ws://127.0.0.1:4050/mesh"); let id = 0; const rendezvous = new CultMeshBrowserOdinRendezvous({ @@ -33,17 +33,17 @@ test("Odin rendezvous resolves stable provider identity and observes route rotat assert.equal((await rendezvous.resolve({ verseId: "sample.counter", - providerId: "sample.counter-provider", + authorityRuntimeId: "sample.counter-daemon", })).endpoint, "ws://127.0.0.1:4050/mesh"); odin.providerEndpoint = "ws://127.0.0.1:4060/mesh"; assert.equal((await rendezvous.resolve({ verseId: "sample.counter", - providerId: "sample.counter-provider", + authorityRuntimeId: "sample.counter-daemon", })).endpoint, "ws://127.0.0.1:4060/mesh"); await assert.rejects( - rendezvous.resolve({ verseId: "sample.counter", providerId: "other-provider" }), + rendezvous.resolve({ verseId: "sample.counter", authorityRuntimeId: "other-runtime" }), /could not resolve/, ); }); @@ -55,7 +55,7 @@ test("browser client leases provider state, invokes an operation, and follows ro let id = 0; const client = await CultMeshBrowserClient.connect({ verseId: route.verseId, - providerId: route.providerId, + authorityRuntimeId: route.authorityRuntimeId, runtimeId: "browser-test", rendezvous: { resolve: async () => route }, createId: () => `id-${++id}`, @@ -101,12 +101,12 @@ test("browser client rejects wrong rendezvous identity and has no document write await assert.rejects( CultMeshBrowserClient.connect({ verseId: "sample.counter", - providerId: "sample.counter-provider", + authorityRuntimeId: "sample.counter-daemon", runtimeId: "browser-test", rendezvous: { resolve: async () => ({ ...provider.route, - providerId: "intruder-provider", + authorityRuntimeId: "intruder-runtime", }), }, socketFactory: () => provider.open(), @@ -120,7 +120,7 @@ test("browser client rejects wrong rendezvous identity and has no document write test("browser client bounds unanswered provider operations", async () => { const route = { verseId: "sample.counter", - providerId: "sample.counter-provider", + authorityRuntimeId: "sample.counter-daemon", endpoint: "ws://127.0.0.1:4301/mesh", }; const client = await CultMeshBrowserClient.connect({ @@ -175,7 +175,7 @@ test("browser client rejects a correlated framework failure without waiting for test("browser client rejects oversized outbound schema messages", async () => { const route = { verseId: "sample.counter", - providerId: "sample.counter-provider", + authorityRuntimeId: "sample.counter-daemon", endpoint: "ws://127.0.0.1:4401/mesh", }; await assert.rejects( @@ -224,7 +224,7 @@ class FakeProvider { constructor(endpoint: string, count: number, rejectOperations = false) { this.route = { verseId: "sample.counter", - providerId: "sample.counter-provider", + authorityRuntimeId: "sample.counter-daemon", endpoint, generation: endpoint, }; @@ -288,7 +288,7 @@ class FakeProvider { message: "Expected payload schema 'sample.increment.v1'.", })), diagnostics: ["Request schema did not match."], - sourceRuntimeId: "sample.counter-provider", + sourceRuntimeId: "sample.counter-daemon", }); return; } @@ -314,7 +314,7 @@ class FakeProvider { payloadSchema: "sample.increment_receipt.v1", payloadEncoding: "messagepack-base64", payload: bytesToBase64(encode({ count: this.#count })), - sourceRuntimeId: "sample.counter-provider", + sourceRuntimeId: "sample.counter-daemon", }); } @@ -328,7 +328,7 @@ class FakeProvider { storedAt: "2026-08-17T00:00:00Z", payloadEncoding: "messagepack", payload: encode({ count: this.#count }), - sourceRuntimeId: "sample.counter-provider", + sourceRuntimeId: "sample.counter-daemon", }; } } @@ -359,7 +359,7 @@ class FakeOdin { optionalPluginIds: [], }, discoveryEndpoints: [this.providerEndpoint], - authorityRuntimeIds: ["sample.counter-provider"], + authorityRuntimeIds: ["sample.counter-daemon"], }], }); }, () => undefined); diff --git a/samples/eve-browser-network/Program.cs b/samples/eve-browser-network/Program.cs index e06c235a..4b60a18e 100644 --- a/samples/eve-browser-network/Program.cs +++ b/samples/eve-browser-network/Program.cs @@ -86,7 +86,7 @@ static async Task RunProviderAsync(Args arguments) }, DatabaseOptions = new CultNetDatabaseOptions { - RuntimeId = "sample.counter-provider", + RuntimeId = arguments.AuthorityRuntimeId, DocumentRegistry = documents } }); @@ -99,7 +99,7 @@ static async Task RunProviderAsync(Args arguments) await using var schemaServer = new CultNetWebSocketSchemaServer(); using var subscriptions = new CultNetDatabaseSubscriptionServer(schemaServer, node.Database); using var operationGate = new SemaphoreSlim(1, 1); - using var operations = new CultNetOperationServer(schemaServer, "sample.counter-provider") + using var operations = new CultNetOperationServer(schemaServer, arguments.AuthorityRuntimeId) .Register( "sample.counter", "sample.counter.ping", @@ -329,7 +329,7 @@ static EveSurfaceDocument CreateCounterSurface() "sample.increment.v1", networkRoute); return EveSurface.Create(surfaceKey) - .Provider("sample.counter-provider", "sample.daemon") + .Provider("sample.counter-ui", "sample.daemon") .Title("CultMesh browser counter") .Version(1) .UpdatedAtUtc("2026-08-17T00:00:00Z") @@ -350,7 +350,7 @@ sealed class Args public string Token { get; private init; } = "sample-session"; public string VerseId { get; private init; } = "sample.counter"; public string VerseName { get; private init; } = "CultMesh browser counter"; - public string AuthorityRuntimeId { get; private init; } = "sample.counter-provider"; + public string AuthorityRuntimeId { get; private init; } = "sample.counter-daemon"; public string TransportVersion { get; private init; } = "cultmesh.v0"; public string RulesHash { get; private init; } = "sample-counter-v1"; public int ExpectedCount { get; private init; } = 2; @@ -372,7 +372,7 @@ sealed class Args Token = named.GetValueOrDefault("--token", "sample-session"), VerseId = named.GetValueOrDefault("--verse-id", "sample.counter"), VerseName = named.GetValueOrDefault("--verse-name", "CultMesh browser counter"), - AuthorityRuntimeId = named.GetValueOrDefault("--authority-runtime-id", "sample.counter-provider"), + AuthorityRuntimeId = named.GetValueOrDefault("--authority-runtime-id", "sample.counter-daemon"), TransportVersion = named.GetValueOrDefault("--transport-version", "cultmesh.v0"), RulesHash = named.GetValueOrDefault("--rules-hash", "sample-counter-v1"), ExpectedCount = named.TryGetValue("--expected-count", out var expectedCount) @@ -411,7 +411,7 @@ public sealed class IncrementReceipt [Key("state")] public string State { get; set; } = "accepted"; [Key("ownerRepo")] public string OwnerRepo { get; set; } = "CultLib"; [Key("authority")] public string Authority { get; set; } = "provider-daemon"; - [Key("providerId")] public string ProviderId { get; set; } = "sample.counter-provider"; + [Key("providerId")] public string ProviderId { get; set; } = "sample.counter-ui"; [Key("surfaceId")] public string SurfaceId { get; set; } = "sample.counter"; [Key("issuedAtUtc")] public string IssuedAtUtc { get; set; } = ""; [Key("sourceVersion")] public int SourceVersion { get; set; } diff --git a/samples/eve-browser-network/browser/main.ts b/samples/eve-browser-network/browser/main.ts index 9e30504d..3947516b 100644 --- a/samples/eve-browser-network/browser/main.ts +++ b/samples/eve-browser-network/browser/main.ts @@ -30,7 +30,7 @@ const receiptOutput = document.querySelector("#receipt")!; try { const mesh = await CultMeshBrowserClient.connect({ verseId: "sample.counter", - providerId: "sample.counter-provider", + authorityRuntimeId: "sample.counter-daemon", runtimeId: "sample.chromium", rendezvous: new CultMeshBrowserOdinRendezvous({ endpoints: [odinEndpoint], diff --git a/scripts/verify-eve-getting-started.ps1 b/scripts/verify-eve-getting-started.ps1 index 0a690712..eb653aa6 100644 --- a/scripts/verify-eve-getting-started.ps1 +++ b/scripts/verify-eve-getting-started.ps1 @@ -18,7 +18,7 @@ foreach ($requiredPrimitive in @("CultNetOperationServer", "EveSurface.Create")) } } if ($networkSampleSource -notmatch 'new\s+CultMeshSessionTarget\s*\(') { - throw "The getting-started client must address one explicit Verse/provider target." + throw "The getting-started client must address one explicit Verse/authority-runtime target." } $cultMeshClientSource = Get-Content -LiteralPath (Join-Path $cultLibRoot "src\GameCult.Mesh\CultMeshClient.cs") -Raw if ($cultMeshClientSource -match 'ConnectAsync\s*\(\s*string\s+(endpointId|verseId)' -or @@ -27,7 +27,7 @@ if ($cultMeshClientSource -match 'ConnectAsync\s*\(\s*string\s+(endpointId|verse } $discoverySource = Get-Content -LiteralPath (Join-Path $cultLibRoot "src\GameCult.Mesh\CultMeshDiscoveryService.cs") -Raw if ($discoverySource -notmatch 'AuthorityRuntimeIds\.Contains\(query\.AuthorityRuntimeId') { - throw "CultMesh discovery must prove that a selected Verse route advertises the requested provider runtime." + throw "CultMesh discovery must prove that a selected Verse route advertises the requested authority runtime." } $dotnetPackageRoot = Join-Path ([IO.Path]::GetTempPath()) ` diff --git a/src/GameCult.Mesh/CultMeshClient.cs b/src/GameCult.Mesh/CultMeshClient.cs index 99746a5c..b4667f9c 100644 --- a/src/GameCult.Mesh/CultMeshClient.cs +++ b/src/GameCult.Mesh/CultMeshClient.cs @@ -383,18 +383,7 @@ namespace GameCult.Mesh var expectedOperation = operation.Trim(); var expectedResponseSchema = responseSchema.Trim(); var messageId = idempotencyKey.Trim(); - var session = await ConnectAsync(target, CultMeshProtocols.Documents, cancellationToken).ConfigureAwait(false); - var completion = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - using var subscription = session.OnCultNet(response => - { - if (string.Equals(response.MessageId, messageId, StringComparison.Ordinal)) - completion.TrySetResult(response); - }); - using var timeout = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - timeout.CancelAfter(_operationResponseTimeout); - using var cancellation = timeout.Token.Register(() => completion.TrySetCanceled(timeout.Token)); - - session.SendCultNet(new CultNetOperationRequestMessage + var message = new CultNetOperationRequestMessage { MessageId = messageId, ServiceId = expectedService, @@ -403,14 +392,46 @@ namespace GameCult.Mesh PayloadEncoding = "messagepack-base64", Payload = Convert.ToBase64String(MessagePackSerializer.Serialize(request, CultNetSchemaMessageSerialization.Options)), SourceRuntimeId = sourceRuntimeId.Trim() - }); - + }; + using var timeout = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + timeout.CancelAfter(_operationResponseTimeout); CultNetOperationResponseMessage envelope; try { - envelope = await completion.Task.ConfigureAwait(false); + while (true) + { + var session = await ConnectOnlineAsync(target, timeout.Token).ConfigureAwait(false); + var completion = new TaskCompletionSource( + TaskCreationOptions.RunContinuationsAsynchronously); + var pathChanged = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var generation = session.PhysicalGeneration; + using var responseSubscription = session.OnCultNet(response => + { + if (string.Equals(response.MessageId, messageId, StringComparison.Ordinal)) + completion.TrySetResult(response); + }); + using var stateSubscription = session.WatchState().Subscribe(state => + { + if (state.Status != CultMeshSessionStatus.Online || session.PhysicalGeneration != generation) + pathChanged.TrySetResult(true); + }); + using var cancellation = timeout.Token.Register(() => completion.TrySetCanceled(timeout.Token)); + if (session.State.Status != CultMeshSessionStatus.Online || + session.PhysicalGeneration != generation) + continue; + + session.SendCultNet(message); + var finished = await Task.WhenAny(completion.Task, pathChanged.Task).ConfigureAwait(false); + if (finished == completion.Task) + { + envelope = await completion.Task.ConfigureAwait(false); + break; + } + // The operation has a durable idempotency key. A route loss before a + // correlated response replays the same request after replacement finality. + } } - catch (TaskCanceledException) when (!cancellationToken.IsCancellationRequested) + catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested) { throw new TimeoutException( $"CultMesh operation '{expectedService}/{expectedOperation}' did not answer idempotency key '{messageId}' " + @@ -462,6 +483,32 @@ namespace GameCult.Mesh return new CultMeshOperationResult(envelope, value); } + private async Task ConnectOnlineAsync( + CultMeshSessionTarget target, + CancellationToken cancellationToken) + { + while (true) + { + var session = await ConnectAsync(target, CultMeshProtocols.Documents, cancellationToken) + .ConfigureAwait(false); + if (session.State.Status == CultMeshSessionStatus.Online) + return session; + + var changed = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + using var subscription = session.WatchState().Subscribe(state => + { + if (state.Status == CultMeshSessionStatus.Online || state.Status == CultMeshSessionStatus.Offline) + changed.TrySetResult(true); + }); + using var cancellation = cancellationToken.Register(() => changed.TrySetCanceled(cancellationToken)); + if (session.State.Status != CultMeshSessionStatus.Reconnecting) + continue; + await changed.Task.ConfigureAwait(false); + if (session.State.Status == CultMeshSessionStatus.Online) + return session; + } + } + ///

    Gets the number of currently leased shared document subscriptions. public int ActiveDocumentResourceCount => _documents.Count; diff --git a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md index 265247b2..bbeff475 100644 --- a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md +++ b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md @@ -34,50 +34,42 @@ import provider internals. Install the renderer-neutral `GameCult.Eve.Surface` package in the provider. Do not install EveUnity or the browser lowerer there. A provider defines typed state, one typed operation transaction, and one Eve surface. CultNet envelope -encoding is framework work: +encoding is framework work. This complete method builds the surface document; +it has no hidden transport or state variables: ```csharp using GameCult.Eve.Surface; using GameCult.Mesh; -using GameCult.Networking; -using var operations = new CultNetOperationServer(schemaServer, "sample.counter-provider") - .Register( - "sample.counter", +static EveSurfaceDocument CreateCounterSurface() +{ + var route = new CultMeshRouteHint(CultMeshLocalityKind.Network, "cultmesh"); + var count = new CultMeshStateBindingDescriptor( + "value", + "sample.counter.count", + "sample.counter_state:counter:main", + "sample.counter_state.v1", + route); + var increment = CultMesh.OperationBinding( "sample.counter.increment", + "Increment", "sample.increment.v1", - "gamecult.eve.command_receipt.v1", - async command => await IncrementExactlyOnceAsync( - command.IdempotencyKey, - command.Value)); + route); -var route = new CultMeshRouteHint(CultMeshLocalityKind.Network, "cultmesh"); -var count = new CultMeshStateBindingDescriptor( - "value", - "sample.counter.count", - "sample.counter_state:counter:main", - "sample.counter_state.v1", - route); -var increment = CultMesh.OperationBinding( - "sample.counter.increment", - "Increment", - "sample.increment.v1", - route); - -var surface = EveSurface.Create("sample.counter") - .Provider("sample.counter-provider", "sample.daemon") - .Title("CultMesh browser counter") - .RootColumn("counter.root", root => root - .Metric("counter.value", "Canonical count", "0", count) - .Button("counter.increment", "Increment", increment)) - .Build(); + return EveSurface.Create("sample.counter") + .Provider("sample.counter-ui", "sample.daemon") + .Title("CultMesh browser counter") + .RootColumn("counter.root", root => root + .Metric("counter.value", "Canonical count", "0", count) + .Button("counter.increment", "Increment", increment)) + .Build(); +} ``` -`schemaServer` is a transport-neutral CultNet server port. WebSocket, RUDP, and -test transports attach the same dispatcher. The handler owns validation, -idempotency, state mutation, and its durable receipt. `CultNetOperationServer` -owns only route/schema checks and typed envelope serialization. The complete -provider transaction is in +The operation handler owns validation, idempotency, state mutation, and its +durable receipt. `CultNetOperationServer` owns only route/schema checks and +typed envelope serialization. The complete, compiling provider transaction—including +the schema server, typed request/receipt types, and exactly-once mutation—is in [`samples/eve-browser-network/Program.cs`](../../../../samples/eve-browser-network/Program.cs); it contains no hand-written operation base64 or MessagePack dispatch switch. diff --git a/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs b/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs index 94194abd..d88b5738 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs @@ -311,6 +311,35 @@ public sealed class CultMeshClientTests .Which.SourceRuntimeId.Should().Be("pilot-one"); } + [Test] + public async Task InvokeOperation_ReplaysSameIdempotencyKeyAfterRouteLossBeforeReceipt() + { + var connector = new DocumentConnector { FailFirstOperationBeforeResponse = true }; + using var mesh = new CultMeshClient(new CultMeshClientOptions + { + RendezvousEndpoints = new[] { "rudp://odin:3076" }, + Discovery = new CultMeshVerseDiscoveryClientOptions { CreateClient = () => new RendezvousClient() }, + Connectors = new[] { connector }, + OperationResponseTimeout = TimeSpan.FromSeconds(2) + }); + + var result = await mesh.InvokeAsync( + Target, + "tests.counter", + "tests.counter.increment", + "tests.counter.increment_request.v1", + "tests.counter.increment_receipt.v1", + new ClientOperationRequest { Amount = 2 }, + sourceRuntimeId: "pilot-one", + idempotencyKey: "pilot-command-route-loss"); + + result.Value.ReceiptId.Should().Be("receipt:pilot-command-route-loss"); + connector.Clients.Should().HaveCount(2); + connector.Clients.SelectMany(client => client.Operations) + .Select(operation => operation.MessageId) + .Should().Equal("pilot-command-route-loss", "pilot-command-route-loss"); + } + [Test] public async Task InvokeOperation_ThrowsCorrelatedFrameworkFailureWithoutTimingOut() { @@ -424,6 +453,7 @@ public sealed class CultMeshClientTests public bool SuppressFirstSnapshot { get; set; } public bool SuppressFirstSubscriptionSnapshot { get; set; } public bool RejectOperations { get; set; } + public bool FailFirstOperationBeforeResponse { get; set; } public string ConnectorId => "document-test"; public int Priority => 0; public int SubscribeCount => Clients.Sum(client => client.SubscribeCount); @@ -438,7 +468,8 @@ public sealed class CultMeshClientTests snapshotsToSuppress: SuppressFirstSnapshot && Clients.Count == 0 ? int.MaxValue : SuppressFirstSubscriptionSnapshot && Clients.Count == 0 ? 1 : 0, - rejectOperations: RejectOperations); + rejectOperations: RejectOperations, + failOperationBeforeResponse: FailFirstOperationBeforeResponse && Clients.Count == 0); Clients.Add(client); return Task.FromResult(client); } @@ -452,12 +483,18 @@ public sealed class CultMeshClientTests private readonly string _text; private readonly TaskCompletionSource _failure = new(TaskCreationOptions.RunContinuationsAsynchronously); private readonly bool _rejectOperations; + private bool _failOperationBeforeResponse; private int _snapshotsToSuppress; - public DocumentClient(string text, int snapshotsToSuppress = 0, bool rejectOperations = false) + public DocumentClient( + string text, + int snapshotsToSuppress = 0, + bool rejectOperations = false, + bool failOperationBeforeResponse = false) { _text = text; _snapshotsToSuppress = snapshotsToSuppress; _rejectOperations = rejectOperations; + _failOperationBeforeResponse = failOperationBeforeResponse; var cache = CultMesh.CreateCultCacheDocumentRegistry(typeof(ClientTestDocument)); _documents = CultMesh.CreateCultNetDocumentRegistry(new[] { typeof(ClientTestDocument) }, cache); } @@ -478,6 +515,12 @@ public sealed class CultMeshClientTests if (message is CultNetOperationRequestMessage operation) { Operations.Add(operation); + if (_failOperationBeforeResponse) + { + _failOperationBeforeResponse = false; + Fail(new InvalidOperationException("path lost before operation receipt")); + return; + } if (_rejectOperations) { var failure = new CultNetOperationFailure diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.dll index d99d9ea668925dd8f9ce26829a8572d19106604f..0e9e063f0e1eb4e6b422e481c73891e311b7c0c2 100644 GIT binary patch delta 248 zcmZp;!qjkuX+j6f;+mYL8+$Z51-AYFAIz5+G`2hmlQHqXl3~4|ziNOp=nlPjQp*e#kP&AdnkRg%500>inbSh9)3Q&zDSQezq U5-e`UV8M_K)|a+<;<9{Z0C^`>I{*Lx delta 248 zcmZp;!qjkuX+j5!Q)t+MjXfHj0ztNOq}8}WOGvkQ$qto z^OO{`R7*o61_nh&2ARnl7RYSQp4ZFBa?)h= z+R1$}3p1P4ydDq>^F$-!Gpn@haL7-~g_DRoE(?gy;&N~;rVDpa! zUabDf4CV}`3o`2fb2!IN z!nh_+5rxdVVKR;Tf5tNCUI$vLs#0%LaW-3=%+6Wn~>fi#=%Un811+ zVk9k~sKIYGL_lxg(K-i;zy%ht)tV*^J$YM(NNe-K63+8~?0MhO93FIReGPX#3$h+_5V<=34lzOr?f zs)FBO-I60@dJbsSM_V_t0r~MA79> zV@)@xA3&jgNXfE9z*p)` zF|7(UD+*&yf96vDGBTAY$LPX zx%XBa?VY;ZL(=J;85G=l!mGemLhL_9H+l`DMr6gOd0ty-I+f|r=D!b+r_V>L2E(B% zTy1u!)ISz??>p-Ze2!MA42CWv)-8Df?T|T3bw2?cvkV(U11MrOG%{v1Vm351WMnrv zGG#GgFfe3cWoBeHIX5{pGC5>nHaKH6WM;E>9;gBsu<94v0KfqN6CTwc5>PZrxMl&G zL?6@^aEbv)R94`B}2ev#TLFEOEL-4FCWD delta 702 zcmV;v0zv)cn*rpT0g!wYOiOVzGxcIbgtuj}0VBHI$uz62v5F%X9D19^wRS1pbA;6t1fh14Y> zP(w&k_oDP-R+`-v(Mm=$+pv$+*XWZKZBk?R01j9e3oHHe{n9TnX*%5NI6O#GxWHEY zup&nRh4lM=GLDDZe=sPo37(K)Er6l}1o7S`QM#7TYjhPchzE(4rLhDJcA&6j0^^hq zfs{Z&HGVff06Gm%##$%{tY-mJu4z)!v$tUgv^MW8;UfLVp7$Ni;X%vBRdC<2P;lGemml|D3mwrKwce5Yp9 zY?^2JOzUGhf6YhZf=={glIhVT&rXZu*+|W3dXn$%dmFrN)#g=PV?!~BBqm{8m270T zJNLnerM**^dq_IIGmU~e|rI5D$#9;gBst6e9G0KfqNC7c0LO9(SXnTngU zF%p6wZwE%zs04-=jjwN9AOuNr8K7wsgWk+FcWkYprbS_M9XJ=_{XD(!H kYybcO3lryo0Du4hq#_62;E?n}lYwQ#!c$B^v#TLFEU3>%Hvj+t diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.dll index bc68f797f05241d0aace96d8e9a0f153016af563..98c1020682e96095f4623614526d97f0d3d4130b 100644 GIT binary patch delta 247 zcmZozz}m2YbwUTrhF9XZ8+*3)Fowtp2+LiS7YZ=(+>ypO>#3lr#P$zzjP6PrNv0-7 zX(mZ#CMGE<=9WgOhKU9SDT%3RDQ1@DmL^7)DT!tl$tEdj+v6P>zcRC=cO_k&9^uLu zAn-&`SaHjlPRE9dn+Dn4?dj8ZxH6_FKt&r5Kt+M-L+dWr7aiR8Lh91JNl&)hxG~;h z^-p3jWiVkdVn_p$NepH{(u5%e2+bKRfugAlh75@e20)ksq*H;aQh;hK!LlG-mSAx+ R1`CE{u)ehIsXmOenE_AROep{W delta 247 zcmZozz}m2YbwUTr>R9!z#-6P`j3IIYs&g2Fyg7_rXLilrY$!A%X8Q*@Mt3ERWOGvk zQ$qto^OO{`R7*o6uX_33Y7R_e6>n6p)NgT3^28#l&V ztp3Ri<_x9`20&~GBn^SQ6d*KXNM*1D@{Aaa8Ipi(3!s<@5E=k!BOnb@YYCJw1FAP- T0GW{rG{J(waC@o`<7{RC_=-%{ diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.pdb index 85c083612fe34046dcce9031d8a7cef564640fe1..6213e7e82bce39a425eb1da20b69ab21dd060864 100644 GIT binary patch delta 3013 zcmYk-3tWu(8o=@YJH1ilvuS17!;uP=Xv)+yB{j8<%d)b^vTf^9qErVb?bdM{79rZ$ zd|VT1TnbT>>!MghvK%GKy{vYHEKaU%=QmTkdOx4<^M9WIJny{!cizhs)k(+dq*XKR z9D{^#2#lQ(E`+$>@xz`4rOUMo5-XK4E0#t^CWl{Ly{bXC$w3mC$i{vg!U>!~DaufV zd-xUgXh0(zdP%|s?(l{`{(+GggHVKH8fGE^^RWagk=9Gni7g~MuongR5vOn-mvIe` z@jo=eytgDez!u%%1~vRK1f%dZA`pvs%*A4?#2TbSk3GG09F*i3PNNj%xCuocNpwX| zI3oc%EJZ5TVGDL*9}b}q#khoPxPw}}z&prJlCVN2bc3Ug;0hH6;uDO(7<`Qg#3CLG zk%=7S<0wv{1P{>GSrWboLLO>S56MLmmgtB?j(p+^a>pbFJ^h-Y{Mg`Xta!3H109xm{J z4+1e9pW`cpBN}m-jqi|*AE4Vv$V3kEQHmNrO-yS!d7{)Dd(NvYVKOg z+#U9-MSV;CvSn;yu5AE|9M2hQjR|9Q%jl+Uu9HloF*k1fF=_c@!hJl#i_C1;;ZpE$_UiIb$1Bp5bM|Xlcrmz1uTdneusQH~RGpy(IUcFVwt` zXe;vCR2qM0m<^YTx`VmV--h42ViKr9O=BHC$%pM^-! z1`y9^i-IhKtzmNi=WTQoUR5ik`B|kSi>j_{s5mt~+_|&I%+$Oh2Ss(pz|pqt7uJ5k zTKA5*F}*CndfvWrU6)@hHov({14V1oAn?)%aAp!ENxLnO_plOr;iqoa*4Y?dT3#n{xu<2b-fpakKBJ! zgo;jnb{2+__VMj6#l+j1Ten%hd3&DRp<(O(_VQWhhKw}DS4gSDK2P> z)`WUx|E9emKP|BB;dsxZaYb#=kXduf&1+l^*Dng5mDjZC=ICj|mWL&D+_pt2N4LA- z)+9TQ^N-P}`yKsb_~}iVAI?@y(+v&&Pp7Qjss5=`|Gho?==C$xm)3pn8n(5mXY`yI zIbVG{^n`9vsLf)}Bg$i`;V*+DdYt`dVdmCj({!`eCyb37|KFY}jOdQqnh({|#FB@Y7O1i#hFr^OxSgRd+Sf?b_KZ8|Pks8Mkpnn!ym^lTn+} zw^FALdKlF-_?13!?ZuKk>mxT*)UN2dxjH^)^>Dw5>2CRzfi>@rl*DT$ygVLxEBn@v zqbHNX*ABBPI~+amTFJ8QizLdzexg5jJINgqKFGQF&-0!o0jEt0JZvo~m~#y1bAIs>A{z zUVY!U@mbuJKtp9=*z1t|Qp0|qx^DLNlHOU;50UiYl0H__CrbKcNuML>izR)Tq<<*s v-x`jO%eI#6(;}nFJJ3yQb6>Gx=(IbMb?YhicxzC{)F|4$pEWp6-`Mv5%?ZgU delta 3018 zcmYk-30PFu6~OWP;IS)OMRBVb7D4tM0a<2H8>?d7u!V{Zi&0dJ#3i6%AdTWe5sGzd zFc2q*5fud&qDG=bMFoWj)-@ssAuMV{v{58~1`>JS_dEBTJLk>2Z{9Meo28OwDgA>n zHbFvID3>me5JEJ4lTk6Y{^GRtImPNR8_Ip3hwN?4NbgW(Sx7>S12~Fel;9#NP>s8& z!%ujMm*|3(l_c!p1|KN!E@mJE^AUw5h(kP*kb*S)$4XL(9Fja7#&MiMDXyRjx9}J* z&;`A*k{AF}n85|!P+$sXA{+}5i`7WP2Bcv-_8=FB#;Q0d$v3!w3e?~}WNS%`gazyn zk7R5@26iC_`*8%t_!ecT#4XgK2_1L?T^mUlV<<*rtcu_WPxxapf)RpnEJQ3;EZKTJX)n(!3bwvsTyU?iXbT6WAqWkRq*7}g;l!|Wvy0ZRu-Tt*el z93?RU6EPE?BOgULjZ$324cv9)hSO}4sHbj0J6=O};_|^1=1yFHTc@|p2}~ZqN&JZC zn$K9Rb9av<44ox03YM^kHxvj%BodHmDLAXjb- z?8RB!K^>a$46mT=#!rU97zqp5!419$!c@#g7$V(z4)y_giYD)_yEjQ}Wv&1xRfNm9 zi6$7jbB69cZEquI%>2)gJ-B(`hV?k;p(T#t8j3A`+e1s#P&c9tvZt0X!XS)>73|># zl`kO(f5Bhz4=lqfqg_u^!++*e1eL8_+io|8nDuOz<2 zL6qSUTJap67(PJ~?_eBUun@6WjYJh;1JbY^dytE(xPiNSD z0wiG#Z%y6PqoAIGnfM#t!(yyJJdy)cyw6E8u&d9GIn?|6)JLd``_$j|$;&i3@BBV< zw|eJl*{=ytd+Y!Aj#416>p&JcpEC^VP8jQZM;Ap;y-_oE=iM8BObY&((112{^!B~^ zy-!={Dto%SA6H{#W{!cyIBwfnN?C*=;`dKw5kno(RaPS6+bfl0*bz!IXlLip*6 zcts%bqM{^7Uzip~IzH1?1?F!n%^Gy?(InCGW@W|n@QUceHR9p&rPp5tJPx>?v^KeE zE^9qF=T6L>z=0nRs5jFMI962o-I2OdgY|QkDRahIt+x^51{9 z(#h^X(S-)XOJ02{u^MCi;+}EbpQqme;<~_R|^5pv3oQAkAudnx2r4K6aa19K|d2ypY zcflKjjfYeobfY79 z-m#YSbzQn^EcKThP5j90yN)B5Dz@%RoD}YT?@fbqb81vxOsMig$f}BrA&YLc_dj*K z#&AyFxye)e_czT_=y`wT^v)WmmPM^5Y4Nty#`wso zt5xOcKD$+a@SnXU-gQRi%9$qbugnOZ@u82?!b0`VimH0^fUs%RpENW!eRS_d+Lqu} z|0)MhlcTB1owq~kibF#C{qfVqA16&buO4D^(yP>AtwYN%11hHNIjD=UUs+3`f?t)kg1|E}3Nwy=;6kdt}Po!MVZ1+x-nc4#*7m zT4WRH<>Bn%;_TuT73CT2?c(Yd5j{T2-Q79L)!oI}JHpe;HPS2EW4udYn^&IJFr&eZ z$s$PzwYlE?2kGs~%;f0ObF-%@3J>`-k21HE)OM13ilmN`)UlE}K~kqm>U>FECaJ3> zb&I6#EIc)D|3JwyGkVdD{&dsY(^pnFdGQa@z`j%L(OKxRq)yB5?QEfW>~1}ttX~0$ CjLo_L diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Logging.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Logging.dll index 9c9d4626efd9aba54b36af76fd802476c50e6c55..d1fe789ed5f0f8226967157f6bb7f31035834e15 100644 GIT binary patch delta 235 zcmZoLX)u}4!SaQ1%dL$)HoO8q`n3OkD!Syf`R4w_pOKr+Y`(!efl(vL)Wj&wB+1Og zBqhb%(kRt1(ZC=jF*Pm4%+lP_#KPhZ7lvt45kbw3`PuT zKr)HJ3`m+VqyV8ggC$TjmBEl9k--26Q-E|TP*n<0jU`wXq{|X4ZpL82kPOzBwpml` GIx_$Q(M-bt delta 235 zcmZoLX)u}4!NM*4ym4cX4X?lwCH8v{CVX+4+?aagP_U2V<{P{d7&Vg3O$|&94Ghgw zQp{2<4ULSGQY}(UObk+tObiVylg!MGlFd_1Eet15;J?GN?73m*Jfi$M)zvi#H z?&tvihffNO(p#DRsAV@XWuKd-Xr-hamwKo0V93t4p;-Ac5&S1)50K|qs z(h$f?0YWo|R0c~R&xpa8AqmK~0E(Fap#hLK0@5J0mOvRZpn4+)kQu2!6D$}EH*1Pr GX9fT(3P*wf diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Logging.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Logging.pdb index 626a27fac21d932f0b4b3f59a2755113ffba3636..27bf8a8a769d17e2da1fd42a5bc3357d6989e80a 100644 GIT binary patch delta 762 zcmeD1>hPLSBXYA^)9QZailWG=J@s^I6h{0>|Dr?m7G**n4*D z@tanqLR>4oofI2|mcLv0#X$RP7W)ap0&V5W=FU@Bk-XfP>-?w0oTE!ub-3%Jl4g&9Ur#Y2BJS{bMA;%-f zptPgY795llDVx|Z_mkoTA&r&C*1ut1aQVZLYfhdCwIUC)+$Yc4c1uR_f?tg?XZX+f zEW0hH$K7L7(i5(_FML*1Kif7S)swTje5R9qa?h11+xGu3R@nWoa{CwG?sfacIAhA3 z&a2h)a;|DPl=bP)>5Q(`H%c^5?`C}6sFS$lKjYTggy7Q*pZ-eUnXItpbSK>U z?6R9TBh6&bSH9PhpVhlQ<3DRn;6AOi(77?Wy-Gw7Tjsb)Nn?@uN8l3;#ul z?vh&nTe0Hq%0%hBjSEwp%eI$h*u0*2^pc~;Yi5gCX`YK8+?%n@Zqtto^*m*tgw(cr zNb7&Pv*AkYOwIdG_II6YU%a96=k~+#8h-`9uih>j%{!loTX*lW*$vAS)fea-o3V6{ zJR@^MSG7_~esXDU>STBJP>m#06QeYfBr_9}loWGIqg2C01A~;r)U*^cOLI#TBg>RT hGmB)Cl(fx9*cZq!>P}8oiDuDdT-Y}Gh>8m%0{{<+HnRW# delta 760 zcmeD1>hPLSBa+7S{MYUk`CZrC|-!ZJ^FMMefoAod61R7D0LU}7j! zWMY^B#7ls9H4twC;+f#P$4Bs;@rwrN21-i+ITq#YA8BMSrn=Jiaond<#CR%AV4 znES=5uwOAK`pCBXpM&1dsCdD!&P&F2Mx?P&<9TzS`D>@#&XP71XnW6G*?urw*Z124 z=Q+ZyS5y~HaOe#FzUWI*nDuJe3trtOw>R`(x&C6Z=*`}Z)eX84<&)C()&EFeVq$Ci z!phDoc*ilnJ1f<^nzyez)@1u>oV36f14Bof@l2ubiU!qv+H*cnd;v9=XRv{BIjNy z(|VN^He9POzFyy~xh?7LQJwVii2f7~=D++a-rBy7DpRoEcbJ*;P*+aGcX!L(J4@_% z-1jeEV6%OH=#D4LOj*{x+;Z&Dk!9JkwyD}rv_n{?e%|n+=T5O<%-d7>fZwqm;*r+%ir)t*()cz?xDo!L(#?etF@?>cdOa(&ae(=Sc5k6*Ugt#R&Ivgz`h zm3A@T7ni3lFS}jP&g&{Y>36U5;Yfd-Ha@2)*#j3Xyj8j0^=7_i>i+y!J>N~;V3q5w zf|<)^Eq&MJvQw>A)9S8l>(|r!Z~tw5B>!zYTY}I~wZE@ZSE{$eI6~p)H zjLZ#P)k-P($)&lIUD?AllFdyGObrbT%~Mj$QY{UQjFVC=QcO$?QjAOt4J?z)%#D)G dQ%x-lHy>tSAj7CPIYlL!MUQb|`{ctaE&yCoG6Mhr diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.dll index 9c0e55e74ac0c41b729736e5085a8f9dcbb6524e..c7ef8430abb7c0f8d10b1b9edda8610b71817e0a 100644 GIT binary patch delta 246 zcmZpuXsDRb!6NZK>*U6s1}%Y|lZ{SRPw8~uWZ76@%XDkcW*O~;EP6?%CPrx{NoFP{ zDJkZbMyZC01_mjKsc9)@mgbfwMwTgwW){gNDQOH0a*Pa;ljj;qZe}rf!pIWGaD49M zH--TMfoJ~ybTm8RJ$FaBPqU8W#K}HJWeQNiXj!NrP_?Yw>B+y$nF4t7qW?YL{K%+* z)jx^Bl);3-h#?I~CNY=+NfU+?AT(#N1d66I7&0U>7yw}kkWK}vN&%{|1j~YSS%SsQ R7%Ui)!TQoRZ?y1d1^^gCOdyo17KRKAa*Pa;ljj;qZe}rf!pQPW{py;@ zZwvzj`1k*wc5Ll;kBPn=XPAn&#Z2}wDpP<8p124V1gh3yW@TFP+U?_xvr2z9ZGL3b z!0MmOV9sF5U;xC1K++J%O94VNhExViAkT=wm>~(swg8Hm0HFbpHUiQhwU$5`GoX4S T29O!4Kocw&3^#AI@Mi`9XLwG2 diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.pdb index cf491f8a9ae27f35d5e59bda3ad304574dbbedbe..f2a26092cdb624cf42373336a744e30c45257fad 100644 GIT binary patch delta 829 zcmV-D1H$~cU$|e8d=yd4{rN#Q$V;8LcT9sUL6Ken$DOf|J_jHbw{IB4cltE4fEvE< z@?G4S(EnKs!Z+QcA7%D7rxZ1l?gtis97lEPBotDYgg{-|T-=A!htcjx8d&X`-BE%* zslU-LE334|rY)%8eGo`{=A5H5!(`dng>CXQI zq*uT07Oq*N?XE;T7p>4i(vYC?D6EphZ-ZHE$yFPxoZaHOBSRSIe~8wd=c<-1k{{n; zNrJE<8~XkzXJ0Oz55uY7Q&66N*Sii6l8-3-M6e8>TUM}WjVvkD;0cXz6B}+VDRCZ3 z=i$+^biD~DHF>ZkLC|XS8hmSGMFL0TQ5=^fq{-o6d)I7eMLz5Xc#=-i)6;Y^{5NlH z>3q{S0?oe&kBZm%w9JcHo@;$JpVA3VCK{>Kv-#OPpUyST-l$xc!*xG@d8b>o-M1TT zDCU{QK+_m+`V#hV(gzkp`=wm%A>%lX8U=SIeeD8^^WCF2$ty@|k##uFvWlf{i&VKL z`|Uo9j}Kh*g8lNi*B1Sq~Tu^e73P>noH8e72G-5V1G-PBqIWlE2VK6XcVP$4yHaRyrG%`74 zVKz8pG-PJ8a0;jb7_jOW+W^1;023b79}-YBNw{VKn&lBS7?Us!Ef`SC_4ojQ005Lj z1Yquq=1!EpANhegiRP0q4ILh2Y-|7k0i%3ur2qf{0Ji`CQx0KLL%La~w4C;|V3V*7 z7ew>{wAuiG008)oEB*3v(n7P@zhU`Vvdl+eZDm7sY;-P7WpijQWNd5z00C&LY`g$q z3IJbYc!aQBQACspUl;TCnhBE&4jLFMl6Q*$00;n|rE~_lK3z|=I>RtGMgO6bunrWn HQ4VJz2E=#R delta 829 zcmV-D1H$~cU$|e8d=wAA``b$IRS#cK5K8Nl?gtise2sIXkh&xU>eA-oK9oL;cE{4dYS-+J67)&^ zjec2KxivOzK?U!FK-x3s9Gw{^%T5n^`n@cJYplhc7G%kzkbc{KjOVH30Lp2CR}8QP zK;8g?IA_ub-NNT3+JXXz1BsO@HUt$mps)@EY?bq#lt4};zOeIvR>LbB137_zaY2Ar zTQ(_aqs;+4ZN*zjxX%9K`Owkydv#!2z+)4Hs;m9i^nq4}l(4f`5&9KFpei@b<)47` z=GWcaRco}(jfm&G7CK5Q5>y_ARdW2TGmBkuQO7E0ceozN5C-}mqIKiBC}oG_$9Gte zAS}s-wm-_*&8739JN0`C%JX`E-{Dd65rtm}7U6Tv3g)$u1%(nkp%JcP!>uJH&cn)i zc(yD}Yr;uM9xO=^v>LqzU)xxbz)8Os$0Z4Aa@^V8EgM>r5BmWQ(?L2Or-Sald2d(F zS8XHE{EP5J&8CCta4?){eMT3<(Kx4bJ(&#jXfhmJ1!8QoNu1JN!~zGimbzBmK7{zou|rG z*>Cq*e0<=%6>OKs-R>fbYi9BIu4bd*i)W#^({$^xsK^Q^gCV4`?k52OfQow}WN%}2 zZDnqBb0Ru>B1Sq~Tu^e73P>npH#IOdF)%SVWMnpFIWaObVr4jFG&C?|GBhzTIbt?9 zGGjMoH8?S|a0;jb7^__;iU7a?041COQcDOkMVX45voR8wT$3;jEf_NMV6^~%001p$ zLXIV1^-R0ZFg}89QDu`b4ILh2Y-|7k0YX()zyJUN08%}i8zu{UORkNiQzsk7uamG1 z7eosa=Yar#005*S2j1Y2^g@$?WyHc$OhHFsZDm7sY;-P7WpijQWNd5z00E|#RL%fk z3INM=?dn*tKTo7+KCOVkmd=w44jLFab5Dx^00;nP)d6Qrwi83KJQ|4fUP{!HunrWn HQ4VJzKn8Pn diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.dll index a6e2493da36a6768464d1b714dcf7b866cf36d53..57024e4f560a03e6bde48659e8fb80839e19af7b 100644 GIT binary patch literal 656384 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 WU!@sBHh9`WUhUqHO7_(jA=6~BbIRs1sI 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
    @+zuIP-H=)uS9XQgCVz8`(KuV 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�R<<-^zUvzI1A>PlV6sDxiS|bP;VU^*UUAybrb! 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
    {3l}Bq)E#s;g z*ezN*_dCWgEk(8|RZUCBKgG8zT57(Ot%|EP8+fdXE6Z{nL0jl_ufTsiTCBu^sJUi+ z;oYaSv>&%IJ3)%5Gl)MLpX2KL8Tea>MM!E7zjW2plWm8$iv*@8de!cE1L`e|+SMz-{y%PoV^f=2$hGIKyYh^DxD6S}zOOAtdW9mROc(vX+&6_mEm*2tEY zKWMj^zu~Jxo$hg|M_m1SSgE(QrN;W?lwIro9!5Ry$r7~XQO#}@|0Soq1na3EC8r!+&MlanGAd%&JoIyZ+IEzY=Ko~Iq2-uO zc|G)BCkxfcj+4Z0(UEf&cS$S5=5Snf z!G<;4oHvl}x`^+Bb-FQUSh8`7*`$vU8 zImR)e8E#vAptfZ%D>9L@+i|A4BXjVC}`Tbz@v12Ut z9$q`1#0a+xIpF)QrvG;M5#RS}EfkY$wUi6@12<~vspCq0t)+|b)el-~3HCE2yB4*5 zCK7luqKx$sMK*K%knq4u{ZTB0Aesw2fj#tskm`z?`q(vVYDfJVUBI;SJW23K; z&A(&(W9e0lNGwecW|!T)%$)LMFb9~oiHK?(w4fai?8tBDqw52|TtOLRUqsy=FgvH* zgZa(ZR`m`_yAt^R5+dvx{q*niM?^g!BYH&HS#m2Phf8Z0)Tlga&dl0u=cu<(MlM~( zaMZlORZ7DchBzpKrsKnhGLNeTu%M{6&#v^pU(Gd-tA$I94+`&ReGwHK zVdn0(N4Xvmm2%ujIkHA{eIx2Q%mF2|U+g$(S99hqE3V927Diz74IansT5mE&bY?XX z+5Em>?fd5%&B0p?<&CI4!;Q_x7Sv-0eqmMD+`Ok?ZGrch+qBIiF|zU+eZl}^fmwIr z&pAxMtzw;S>KFJO60K#Ml!m>QAcviWrenOK6;E6Z2qcOFt{e4$d$bm^>On0v-pFq( zVSUDexN1YQpSHl}Sc@LoQ0JwmO|)d=@6k*m@wE=dDif2*Dci0wGrNtP9;0}L7guF5 z|I&<&HT4;#TIn(doW`$qK#HhpVsk|Of>j3legMAYV=3hOOk!xzKSWdbjp~1moQOJr zby!Dj-z7-TYUwL@qlcDuVc(*cmdd=0-wD)G?>^l65p^#-NpXOc5=JDBh{~8XQjspM zUOBAP5S_!+Ev|AP-9$uPJSaD=Ou2Do%8e^iE+PW0KU(Ws0b3?Os-IF+S|K^*I97c$ zMkJ^Ff_)H{s#WKHnVeEFknV)X>1kZq9WT2JR^U~$D$Q&c>!&>zvY+E>#OK%pO_wgB>~5&tQ?>i7c865;#Xe>hDudSY z^d4o`qH#qt`(|hkuZNr(N_`5JoO087BhelYv$=H)qrD(z9o}atu4r~47FVyy$X{N~ zM$6DXFh6AvnWu4Oy-PnS$xqGBG1?bv+Z|fp(-;rl&@E$T#CWhv9Nx3ET5MjcZ<5TR zarHu5Qq_`R~+h{g9IGX5bM16(W z;PVB$wjJ9KIT9!@tx$M|Na$+bC6A$Q{8rfoE&YC3O4k;BmDcU$)k*Y<9k&qs7Bk6S zZNY2!7N0ETKJ%!~ky$N=VExw*dBgQhz;CSb_*dp}wko0u%r}x5_3%ct#*FuU5m!5O z8T20d!)sLTk5iO7rKQXF;ip!$MDM2F>-2Odp61ZfaXh^aQrM@f&{`vJBcH}FC$mI* zb1Xd;u(Qn#yD?z&enjcm<1F2T2;)5?JCjh$uutia3b0h7BS&mFa%SV*Z>-jL>_?^M zYH3N(8*Mz>=(G`=*;CsqGJ9%!?b>#x_hgoC%s*HV_GEj^Bqib9RbJE z&F6TtDNoGwkGR^6IgcY^4r*RJEA@}+hyyycjHo*xasR0Nw_Xufy^bhV8TI9HgM0Fs zcktHhQyDZmF4odNx33)?-#|SUX!|nLLZjJF`sx3ouXqKr#k`TmgYyqN55^UhcDHV~ zeL*DJ7&kG=qwPZ((wV2>F}ptM!Sjc;G&2iq-v64TOM9dFEt$o`vtKVn1ea_3zAeM{ zx6IQ0v*yh7Wj15mbeZWhIm)YV51TiFpG0Es*3sVWiHOZOH`-C)?=2Ho=6yP@zUX9p zu&?@91J)prZovFO?VFskrMi)_2JD?cIvhNm9!P70rx zNJrk~92g^He8z6dbB39nz=%53+Ay<67713C5!Jt^nODuqJQD1S{##yi8Xi&KV5LBQ ziKs7I8Oc7iWmwiEu$kt@=4gHFc(pNk?Nbvk5q%cJWxNp7sG{`7%x$J~13r^G_mt86 zU-QyFE0@+YsL{eyqwjWjjh|YZKkJA0)eQ9*8|1a=Y~8Fa#=i3EHOw08@}ys(bZenh zJ7`W$nTadvh8rn?*Q~G1K1d`u)rthCS~#a0Wb%@S_&wgvM+c|jZC2NVcA|S| z$*jXN+lfw2sXdXsk(_d9B){(`r(Bn2q+F}8A3Kn&Zy8AOpE&B0QxZg~pYrYfe7mE5 zO2HHSw7j~E_I(i+gjX5#zWNGSa!USnN~AK_vt%}TyJ7UZ#>B#TuiuCjsLop+D>s(D z!FvEp_hN;|((4}@X<8ti9b?$2Pgn|{6w*E`?`$_gAEa`5{X+V}GsHs@iCD8rgvHgK z4(z}1EI9|gf+8%g%q@_(dJ-#NV(gc}TC;7pVHdH7qM6y}DzBP}7W=**S9EH`n(h1L zCr=u-1NM#AT1>j~idIHbz{;!c(8tnjte{vbhG=5x-i}7%B!y?!hH zM77TQGh&FPB8YaDM!^=A4&cm-rEwn_MzO}M^%7=r^)uE2#Nx`V>cjP*(>byVCniCZ zQL(^Bv2r@sd)BjXKzx=BCny4>7)*%h4AQQoURrBjL> zI&WFjcORsPdU`$g+VFemuPJ=?gxy-KZm2EoDU{tW!Q1Tf=ENjdFz?$F#Si{a>N{Q9 zTu47^sXe3IEAPgLhNfu*Fnns>?BVxwvP(t1-co>=fCwj8Oij# zh?A1) zv5uD&BhEVDD?Z0DcRFy-4f^O@H}e~QcK_<30p^X~-VW>m-(|f2XLq;eN$*B$VblT%J%%wg%LeMZ`Jf~9Z{+D~k%bM%;wZ$h-xI*?Y*Gi>Zo zBlX{IB!85VD*nV$SaV8KoTO`g17;hEZoCl-r;EeuZ8#m;O{7UI#Z^JX5c}D_Q7yn2 z#&4gk5ZQbVVR}kjB}sq7X;6^v1FZQu$K;?NC8C!xYmd>9rRD)!6{I@=ebfiB(}uR> zbeG#0tL&^cqn%;2_e#FU8#CI7t*8C4_L|*=x5a0)R18u#E%nBj{eqUNBXY3egafJ0oG_hp$S?iw+Z0;LKbWe-oAg)SfV#{v$h1w{t ztQI=Q;ZwoP&V{VLR|7xW_pO&@B#f(x!AfC4M^oR2!B}%Yo+AZ(mPM~Jn(7S1GGp_cc$DglFBbOQ1 z!fSy)KF0{Gb8N?qy;Do}c8t}s>jHjzTtEFW(AVj4GnX07^;627VE@%mxml!ePkwl( zQpcbrIi*S<9sSI(+pzkgr#KnyW_<9m%!qL{_62jIvnr6j2_)Og%6Bq(N1$)9zPktG zwu9E(7=3|ewYW+S^1dDPReRQP;Fwas>Kt_P^CzUR|L9JUJ^7)tHa_|BhlbPrUrv7P zuDD&lm~kx<_$8vESk?1BdK_ceGSrWEyZJ7dxnEo{^8Jn6MinD7@5J9ljfW(%Lg1!dCROdbDc~N>_DE2AleXzK4I^*qFOSJOk{zkKNtt|A^&bnsRVwtaQ zoy{?hU+_ol4stMCsmLfk1;t-1z^>^Vnk_tuH%%?g8_8cD_^SLbIOEgopp1rMlO1%%deW_ZcjT{f4jN@zjT3=U)}5})m=+B zy7+r;Ecr&7ih7OKY%t2CyKni`;RGYC&yAI|e%dF7b51RN4lR_9%P3Cmq^{2k>mM+z zwq{9XaBmo1&#w;LhMS(%$s60p@;x43Rr!ujp?tNpq*8ApNBC)?jCC2)kv?DDjqxjE zjsl0cwS4u#J4Q-hM#j9KOy~P`zOs@n*RsqsZ=S&Wj=q|HhIh|>wdZ%3rM@zPh=A(R^qV zuUUPyPS(Zn?r*#*_0=!%%M!GpuinZL(L3*m(?z`V{@-)^?vtFZCr9S8@n}a+~r|`a7g7;OHYz~{w=1o5y ze4u@A#{-+!v{6J+?@p;@W%G#b&Q%aE+FzzVx>t z>`Eb{1sp>^%03*TeVS5*kt5t!Uz6RGh)RHFT4iv{l>A4{+~#Hk32S~}1>T8u8Ft<> zBOz;^S=ZRiWl#^LQ6;YEU5&r7Gb7ef zTAB?;68^63LH2>K)?cI4SUQM4DWXCf!A^QJGOOgeqxG9H_W+X-6pSZJoV3Ez(NcP=x@%@vPz5ljybOl(GOQi@YKiJLR7*5N zOx8Iv(_+W*|C<(W1*>HUqKUpRil`A7*J#ZeQQhHj`ig`-^iE*a5=i0OBJX4F`9MEy z)ZDZYebY*NDA0$KLfOY$XZC2<%epwO3MX@Eab@oPL?F)LL=1 z3OfX|_0z@6%noj8j5NHzap5D5N&HnwtamwH%+5qy(QXgl3Y!zy^1oY92&+x5(f_M0 z{Ed^{*`}SHE!w+u`atjT`4!C_b}ab}PxI?K5aY-mj@b`ymGCuvj}ubL7jI)(V#sh?7B%&6}=sV~2s{8xRkx}-V%cu-a|nuVw>eRUb} zLT$u5V_wyraHZ zNq661q$&3q>8t8SDu?wc&HKK3p@Cr&13w%4FgC;E`QT^#(l^F&?omt18fhrTac0@E zI^;NASlL*geuR5Xw^sU5V6$%N%<5rVE4?k}v@N9h-berLmz1mOGpn@lN{i~Y2wHe# z$V?yoz1Ga5)7qD?gX1rvN?dd*)W!v2e9jC$vtGfQh`z7n(R}Q+@c3f=auL1fZuB(Uf;=bF_bvGqt=woN44(zk z*h$}H#?>wF;=~T=!uz&nUoT@^okTj0*x$8OY8Ib{XY}qR{WN`VU6*3ZHIPEabKz>&#UZ> z>+v+dqSb3LEzxS^RxRzrSaqkC{>+8*MlI0_uZ5OqUDr-aNytkpMz*voSlIfPF;e%` z?AIlxjc9M~WzEd$foGQ~nq}r8iinJwtv<7Eim0;~4`xFP)*z+%`&HaOz16HJ;utX( z>ZfBcVlLCt*Hv({UrW>jG8;G6;Hj^yrGK{tXUQm+N97S1sp&k0+lY4;sEue9lreHP zYt2@lEo1z*W|f;(kKd^9=8D-xpU4KW!DZ0j4b7-|Uk1%qpVeYZv$1AMW6hb_%-*mz z+q|0=oAx!Dc`o|_wnS7?;Gwc;eU9R6<&D=aSHS*@PDic4E5;c?8<`l7s1s-{ULB6R z3tvm<9Ooc4E<9v{Y<34S@aUs}eJ^qt<@3FnYdh%DSZOJdbvhVCvMjU1Q+xvNDBM50O zqwTXbx>}6eakpH$9KQOyW{!=@>8#?hq#9U$mHus(c9Z#O&EV<7TB5gEdK$ie(6SHC zw(&HsZtuyzzQTDQ*EzN&Vtm%py%^iOXsI(={zWZaxD9`AT1(g6h_A4<)B^Fs(zS?^ z>6%SO9K5Tg_81xH+t2*ULF8=KQXPfwogwjPM!z87t1h^ucSN(qV7*2s5+^jXYtggV zp`zW7a1P^pU)iVWN4Wog)~6RU*t|Zl)L6jn=BAN-=`F~v8SQBm)RL`l`n*Ll$(ym< ztL4qCT+aLV9M<!4kM{{0D zu#9b)v5blvu`d;9xeF3oS`SiwRSdDgtK9Uvp$+xZK|XdgwX_K1DM`Nia4&!1i~ZdR z#?P0MjO3x+*nhny8eSeHeXs z9YHNP5$U-1Oy?Zv`yAtRsy|ONvt#Wmdh=hdnJI(EwfD7_640F4DcRLE+Z~&~Yqo1| zE@Q1O{e2dHVL%p3JirKHnOEo$|MC4(G_P@b@2urH{3I=`@G6q)%tx_us_m zfAw_tl{Mwk7plDDMc<`fJqK&9I}5j{)8)l?`G_?>d!i_&r&i0=*O*q{A#DM*CE1cu zA3e=XU-*lvcF$m?--_yy-WxX7PH3BF;%(OMvS$`o>2vU2IKKx_-MFus^)9}tksgZQ zvcUJrJzJBd!!fRLx=mA*O2oup<-_0|VG5^hI~=T~$J z@FgT>-v;ck?g7R=z87=@<_3;V+UaF|v|qw`o8W1Fbs4LN8d|cEn5(`Si;us~-=Jo+ z)OxK5<{H+_XWMl5<1sM4@zF+0nXwZ?v44QsiETNht*3~fZy9|x6?^L>@zb-qmU%E= zp4aK@-I?_Dbw-=|X48^cU$K3;HA|m^>(LRr`-T58uU+fKkuJZY^E{qie#_14tBf8h z8R#pgrOftoXw0sRr)-}s<1SqWwKRRJaCOb}8(=tzLl0e~)7kpk*`N+0$)2U!GOGQ@ zGHU*#^*rPJy^Qer%=FVrJ*;c_EJkY1Vb4V7tTU%Fl&+CZXP?q9W>MYZ>f=<-8&{Um ztzG(EurRBOH@?TAB_nH-fl*%ik}G4n_DIK3_Y9=`>L6C6-L&*JTKZ)z(XQ2CEzxP@ z1TC$>s5Mhdwb7ecT7dUPmOA0Rae;n{rL9`4r2^2*TAqex)>0f=w(F;hZ!=OkXkqp< z_CLSYPqDqNe$rAl>_D=XC-WFBY0z?k)4>*&QlW*Vdtr+^hU(TGTJk~SF@k>WBYehU zW>a5HUddm%_=?VPit8M7j#KeJm2qiKm9nwBfsgt|JT!{Pczil`o&n! ztGQh|ohgk+A3F8OIMVFX>8^VRzbT<5tA%F7%yy!WU&R70m%bOYD>p8ec7QULdp;;P zI+mWk(S*Oi;~X)~()%xCxwaLI57>fS$je&tXQJib{b&1!cr6nxr8Tp0n%;s+`e}OK z-uM>z4;o~WBV)N&^Fa&bW$RmKqQ%ba+#78a--*$i@9flCV&d79admHS z3|ViO7_ukE+%lcCRd(my?z+&rsjGf^8KYT>mgv29gqCP0rYNM$W5|}9z7?kGyjLr2 zrhZDLE!7g0wq8qAT4s^Mt#!51zWB$|b_b;$2}=7dD2>{P=OcF2Swc{!2SFB!d7L~F^1nKhD_EYqVP8_ZikgIp{mN@V#MsqL>Z6 zg6?JT%9rmU+Z;9>-Gt8gG=lb_Uof+~_8D7-X9%msXl6?@I|aR3jSC=--!09UFSbxldb_-cml1wJQ%Z0^1pkds%Jd#T^3JM_)xn)b-enO8?FoSBp0A z-HN!H(T&e$@hksWe(_DBVbAd$(u}^cV{wwU@9(E5)|QCcT%6z9BI*-(h&1EZS22b? zrtLdZA$;OQk^OI_nSP01pDJOr(5OuJuk2esk1EYjMt((m$n;j^tHGrMR-pE?s)>_iTNMWl)Th zK40w@Eg3z|JJFe?qupux8qn@eN7PA-40Hy`@toNi+Dcun+4dRvt zzsEO6tJ0d#_BW2Tk9CgB`iHf-_cXJfwB=rHN4TUegVtf0MGjk^ndS#p;0AHJy0N8p zZ+{3IwJO9#mMLEbSwLyX6f7VN6pADoWqQ3_GF&>$2p|qcFQb= z?2SRb<7#gQ(rEV2w-@;q>%Zr)?Qucd{Ld?e2ha+9&!}iwBatnabv>@u%M!*@`&u86 zU$`{#Uv50bFEyrXU)#$_Gq-eMq|2{p?<=#n7+VjzP30>)9}S6^)8P{My=$6}tSwjX zW%hig!xNOleEq}w@^lts`&)R=atG@6ZZCTJJN6!UUNyUt8T*3mWi_4+>$`fot{KwN zw+eg@IlXt|+T;IAoN^AMg`=~iZW(G{icbC&?v;IL-dglH*Da|iHUibagqIg#Pc%Yl znh43d7$+Kqh_n(??I(;sg^9Emau7G-*J#p}Nx>Jt!I!=dQ<@2yY*s~n#`oSiu#!;) z;|l*atKYCLS(cUBWU!DG^YJ}2_W1E-$BmR`V8V*!Y)?$p6B5C1r;|M~mCQt!wGwl8 zOm)`8mX$@V5@O0qRA+>kvJ%zf#dKL(52~)NQBVDibP17G@a8pYV2Je0MPzJ{~$B3LPq=kJB)SD`1n$|9rz$Rg;; zu5t@`5q*U8TRT47tSEUA^tX!(9kas}d zL#|xv0U;4sI0R{OtGYt+fviEAJgSK%{nR68aZ3wn@~UN;q^hT2^BW-fR3(f{_;ycy zi_*L1!i@wNgk= zyaT1+ji``XC!`<9EZ9>>Z56TvYse4Fp>L=!glqlkAih>t z`Gll`%!AEE)%8LSCvn~5s-%$9AfzX*ZWA(ep;C9;snm_?4k434s@5PV(#6;aK zs<{vob+@RtLQJ&Ws(-6I94)u1o|2|SA;ee=zht3a7E%G^oF)UA1hpuqW@utZwsPtn zO~$F4rr}px;Q4ZDiI5r-@M~uv<<+Yceo_=C8)kgW$ybMYt_$ zs01O#^EFgXO^#$SrPojenM6$KHB?t2ru2u@0Zq8{im<1Sx}?d#g!yBY+KSTassyY? zsPvsvmHJ$hd_p$w#VOF8tvzIkmgBM z3;Xv}uWA_CsDHInNkS5`<82YWshw&fFv`U+_Q`xe8Vr`791o(AcIUiq{dEoAC&9wpil(9=on5%K`W z7E04ueJ7+D2&L()jtQx7fzv#r&Im~Yp)}8^3qrae!rw#PyQoMR7=e2A1(}L8T~s2I zpf5kG?v^yoF`s^jT+gZ+LY@IxuSp#te>TNR4=vbLH4>5oV4D7YA3|Z zU(cy7Ld=NNO+7Ef%wOH~*J-dhu&}%ON~am8ragdt64=vS-B6b5HBK!O(o@|jWa0w! z9i(|dRTpvxW}^L?JS5~Eq&cKXJt1F$9MR-4Au)U{ds34pgcN@S`+FcSsrDg~Wg`Bf ziF!`R;merqL0(ZW3CV$6B|uVCKOsjku2u%=tA+^4I|}P4kbY{kkhQ4SLm>Utln`kG zGEmJH(n0hLR`Z3tE95n`T*&L_ryY>%b+t*zh6iCU$Z)kw$hduoACOV%fRJ}UCWDMt zKMMJDJyxC|W7Me-`2b{`O1y>JqAu>ce+4o@*wEKvfBm8$hP2 zMncN@5mg0bnra&&Ngy*+-w^2rGFvSOk*OeWt4~5?1;{*gG(`4-EKuI9Z1V$O;BEx& zq%Kj}L*!bJWvaB0PDpbr$O=_4L~4MnRF4Xw-|lY$^1f;jB7;EIst!V)MVi$h8&$6m z`3>X~HAu)M%yD;2!98I$Mo7Y5rK*E`sdj}(Q;GtJrN^uiM{641#>4 za)!t-kZ)Dl5SapUP~9oy$`JSu3e9Ukepbyxa6v@Fk>Dc3xZyCbiL$YGHCA~Qpz#GANX z6WJCb&w(UGrd6qBHQNQ=lZA+zwmw&TCnk-~a$HBJ%v0spm&R26au#<`0i z9U>oxNcL%%Wg^FfY+Z-dJ;-yB?UlK7B6os3A2}uDBKmR?Nbksn5NQpP5-F~iZ5YFm zt1C$V$gB_<2=ZEFqmcV+Vaxy-9=Yodg@5A|k@rEyMp_AJ3$hnvN@RD4{0cHNaxp}* zPDh(XN>zaxjBulW!P^GN;>gMnDF?D5(&R2mGfq+KR0a7U(&KJRT7Y~MnINPBR$qNU zK920J%4vwa0rF|&T!^dz`8?9<9-C$d$d{3n5cwWtPb7A)P4g$nH<6o!kUjZlD0L|E zaEMd}IU4CCq})Z^t^@fw(mh0;1UVJyEoAT+tSmrINBV`xOCV<=Lxmi#jg|rVC2}xC z=7OAyRISDq(%&%I1#&)eUdU{W`lmtujQmiY)AXR799lI-^WJZBl>~`JmkFU<)j_U_ z4y|ExH3!KVeH$x#Y6~js1(5vFkA+aKksyVlM}<&X?||G8&4PK9a_vGt-2_r1T29D9 zj1s#*N=6$CNg0ok59Fq3HzCPiV22!}RCHp9IJ5Bf7hNZ01NQNAfs~GJ5%M5Li9#S{ zqNjztiLy$Al#Ld^>`V3#xeMf$Xyp)j1mxCe%MfV>a$9sjh;#%g7o8s>-9gGncZEnQ zNQLNMAuj#jZmNS+j@B1)4Scv9VGt$PZE_x>}Po z^%i2|1jt>{qUd}0l1knA8|L@fc-x9*eV9ol_^${^jc6&XgeXljL@)hq)(4}#gtP>q z@1SZ$$7nK6-G#3otAacn?TRwU<|peYbw9`>(c2&y(i)^*G)YKp{Quq{4WjP~sUv!l zqbuuDt~6B?wQjax{{~D_y=xG}LLC8hyLQDZ^5nc5try(*I zq*ZjAkRtHUQjoUMs!5z?#%D^c18E%-`uLN-EkZjeFICJk5*k+L8oqhAUcya&ArWKwj$kS=TCQIN^eAB4QS0HXxR z8&SLf;@>z`9rio{@@6za$mFr80m!syaUsP}_wFDwqGg550{J5wM%rj)Aw{4kAv;!R z(dwF{sc!WCgWvX#F393&S0OhcdRKxhi*6Hg3u>_yWM#B4G*T`i-+;UyogidF3yh8+A4KU_ zS}0BY0nCFSA4b~?sVHP^beWJE-(kd>gSjA@(3o@Ofaby=8={{H>31K-1CWoS2ScO+ z$d+g$)S1e1FjrOu`83);L~4L+i_R6Y9sT1GknK^YDdifcBG>WT#Lj4SAw%&N&Ed=wOVVR2JoW4dm-+T8NAV*&m&x zNt$}(7}^}jD9Ef_I7g1ER!p{Di@$a_7pv1~ z*49FXV1@xXA6+S=0otn&$c5++Lhi!f9ch^xw_u}LpQK#l)B=no#gOK&Xg(p?*I`5l zxe_fUqzy*4yFj8&B_aJWo;?KOIwM1*8AujqOdGc6n{!ytgXD19w&k*(L#|gqayqj@ zWEe? ze2X;KJLiRLs)d;ma<=C*H(tbi3sTzY+JQ)# zssOLv4pP=xCnRwVR^|CH>p6ova+<#;U{#6HxSVrL6W#}?hFle#W1T3?z=XjV320~O zUgwOEtmx%T&I?IH?_`3_6P@e$5#H;**GUj^;E*9Xg(A@7IZ>r@eP;;1RBx{xCunq0M*sPCcq8C_O;A^HBmi5N&V=POOp z)R6aadID0zDgF%AD^2ahE_xYwtS0`Wf1AB&S1=DC4gD?vlkYIcjRUC_kdM&Mrhq)` zRMmRe&oe-3I}4a3O#BSzg&;}J3L!($I^>@uXN?eZI*{aS7D9EW{qQ7byO5_Qn_Rm! z;eFAiTJu>+vmyshJwO^dmxO#d9lKAOI9;d~0~1D|m(vMULnphC)U6m(b(;J_Ol&lC z?iFI%w4u|8iQZY-rgMG8L>+qva{)*b=jG?9tkD={aApkB)S045s#-DAr)r9 zLXbXAqZg=j9$Ov+dBu57lYt2|k~9QKbzT&5C(a9~-BX=ZA#DOOTu8NP=>0m)I3aD9 z@%WQ!M$v3v9l&n9PD5qWDV2$+AdMHt^W*ucEJ@>id?QvdAbkTuyJBZS`UNC6M%wcr z{R1+49M&2j0|Ih*E5-w8A81HW`s;>x#}TVtkj9d}SjqGR8REPx_3C*E)`1Lj=&u_< zpZ5GvO{({@WID(QXA2WWdfo#`b503q1@Z~VSjT^na`jV0z6P1#+@Q%oO^$<1amt3$ zTm+fwB=n|SY3i=^xW9lgXu7jf$c15e;|H1P?A3%Vq;YDN)3y)g8mN9>jI{>HTh7Xt znS4DKGbhLb=bR>~D(_PC+FbZOC#Ul(lqOAWgMV&pf>( zDy8YC=ceW$A2z!_z9LZv0ezWtE5aW%_&LAcc6Z4y$sX|Q5f9xz5Vq$)avrUMJ`K``j zAtvTOaV`omG5@Jkyg${#o<)A{w9q6~MbPeTiqWa+I8C^wFQOJ-ILkt05XesF0P6|b z^h@U;lfZ{xI_HHLAAaS$Hh@ZJ&BLK*xAUeZ)<1ilIYNwo_B!t{3H-Cy`A~@Q&({w9 zy=tnL@y|Zzgb?GO{Z4csr!oHd#<^CA@y`M04k6~O_K;IklT<}xW=r_zkkeihuEluN z;;=K5NkW!np3#mt^Mug80(|Yq@Svd|FskUopB~;Vq@$Vr|1w$ld2v; zKm8hMesNk1CBi;D2=c4b3!@d)%lPnulOn|U@Pac~h_U&CGg8PscnhFAITxG>Ld-3l z3(ho6tXD5MD>Y%S{)W;oIn6LrT>4!> zLuibOxV4z5FF(MJBGN?M{v#=kZJnt5rzQhc0z6S1X`=1~tR1PnZbf?$aoky&q^W#} zjWQsvTXYnqNmJD?VNVpqck5`9st&e5Ie3=fw${XYHNov5#H`s8+-^e3O5e%i(l5=B z5AOz{IVFqRPl#F9CAvd|m~~yEOTU{!xy-um8h45iv#z_woh`(y%(J@lg_xCjR(FLE zv-Zp8t`TC^e%aiQg_xCjcK353W@Vn;-7Cbbx^uV(g_u=$4)?eav+B<2{vyPzx^uc0 znFQ;)TyC+^TvHRPx!f{Bj8}8Hm4q0t=60(JF<#B>J|M(+HIG|Yi1BJ3H(7}BYF?Lq zH-P+Xyqed2T8Mck%I7{S#Jm&bb9)Ifp3m>52r-_|@4hC)c)oy}Cd7EYfICTu@q9sd zh7jZVg6=#a#`D*@ONAKEU+bmLu&x9;GjT1#g_;v0sAsazz zX>w4LajG)L@FbAJ?y)iCpK)p`NK=p-+}xO1$zxFvxtcp_=){%V~;sEYjTKo)JPT*y$j*x$P%fJv4ikcX6>n z=c1M8e59%9<`hy2B1<0N5;3-7xIChU)>kT5Q zYA05wdy(cI_q>q4&`fQ5uiGCQDb0h}IiWGCnw#}aCK33CMw@DGbxqP#0`5?K2R+r@ zy+X3UKeWca-|ae$a;2%#u(gY=kNTgVBlJE-(zx1o@8Ak;d^ zZVMsXKjbux-L^vZfl!*p?lVGuN9&NDCT>q54x)zAG;v=MQtl-FXA!)$x&wvW2~q{Y z(bOFwq~`s2XGATUx#NY@2kD~8G$D7?<+7T)bizgTss%!2HFuXW2|VAz&GHtfp>GGs z!WM2WA%#FFR|~h0kd=s3+LLMN-Y8@P2*q`NMSH=kZQNBMLZfI~cNgahENthV6+J19*@x}iOF~9~P`%o@ z?i{wqMATDmRv{*$o^taEF%k8&TSSP7sHfeMLPkk@wRdk7GDF&{y?cic@&>h62e+CK z@&>h62e+0G6PX>|Bq1g;JGxDUn274+wiaR{s*~GM$Z^DKDm>QN?Iz?L$Y4!+3o#M? zjN4C$iSTFKp+ZcAcX7uEF%jOyeM1v&osrP|th+HpCW3TztIXAY4qB(XyC6hnAWe7o zdnO6>G4?J7>FNF?glh4gCcg@)jlFl8D|@=QoQ8kc;rt8l(>hHPO~$F+m-)6~PxoDn z$u#FKdIZ64g0u5p^eC25A$uqSKK{9cF3K;6gOc3 zr5UZxq6O*9CDl#QBu#CCp3jiJuiI)7r+FOp`U<3<+g_72RSx41k^XKuL<#BHj+oyM zGQh2>Nt#->oXH?}wWPU>-1PSMnwzkMbKQa&jmQvpo+bkm7GLD|onh`$AzMM{8-!sl zeNRFjn}fTBKccMR?nWWYK~88wUzkvuwWly!fsAl>3E2j6UK9EbgwhoL1E+H!Bi$oH z%77%o4{7dcA$>sdgN$$ROIgodAh&>waTA2p2dSb-E+MzdcN}BgYlYO4 z?>NS~HwxK@d6~ZB80VH2@&^cg$1%>W#3YEr@$M8&_-$)B(u{ZWVAiC1ovY8|#zdEH zR1>)_AjO2dvEHO9BV@pzhEx>Nw7Ma83wgAGAvJ_Nc!=9;qFY3M}^@jUQC|4VhH{G5Ya=qz}4$F04RH4mtT8w()w-6kQj24tbTOvnwj zaXt^S#4WpubA9&!Zg_#LbU$R0P#1rtm*&ck+)sp*3CLc_)u$%bBnv4`rT1A6kpdta z-3dY_)xo+LWQ%)FlT`HpYFZ2AQ@6~iy9l|w7feKWB83$n*8E2Q2PCi~o~n(#VvA<`Uhw`gMR zIq06$gx8ttkmjJ&)-n{zA+;^Luxg5VOua?2Z*;)|rRhsZ4@C_=CG8M7E)< zAKW|FQCUZ_RBz1je8jCTq#90UsdbLHwU|T(T){abavgDd385G}406={RFi=TW?ufu z{ZfdTmw$4<5waC`4`}^!!u>(WA&{Jk$j?H|+zDi!urPbJ`^>bPi%x-2w3w+C91mJ8y2IP_A4c zzq+F}Ig-WXI_FMd5;3{XxqpOmQR#oUWig_W&7H7|Mcz2?RuXdV60af8yH$nc!C2=Z z^?A3JCOk@9i_$N+<0VaLjQ6DHlKZ9*v)6seoy$bmG>%-C++`bd>FRd$o!ddKxWzXz zsfb>X1mb#QgwXp%N02PuF-`DhR}&{)AlG;`H&L!sHES071xR*pbsXznT2)@>O%d`VBH?|cDePt4Lb=k^9~d`20x9A(7E%vywH01IfJhk$r}L)S}-8lOw1P#a+#P9h-YHn5)<$#jC>v7aTb1Zt>=7(ocOq z6fp=r<-EL~P_BL|`()Nr!E2?79a}1TD>boWT}5w)Ci3PBJr%ujpOPLMy|;T+m;}*# zyEjG?&gEitbf| z3C;IjYm!o0&kaJR3}bt0 z2JLP&lU}-oQURX7Rp&BfAY#5I$b%-A*A(&G5aeO66l>PCcmkxh*GtNxK1j7l@=}DD zvXZ>PLQE}^ypcjoEt0$mLQE}^ylG5ySzWc}LEFhj+ZK(z5kktJ$4U@s8hhh~{C*7Q znVP&Qq-kCDVPkKOki&JbM$l;%3Q^LgjlK7T%*A^F^{>X>S|Mgvq_Ow05Hnjf_I3!N zHPQlTZsP3~k_@s;lS4x2i^2~;ntI2Dd;{{4Ccg^#bR~a5+|0WuWIqV4JezsW=h_?E zKM{z{y(%HH1$vr$`F7|uswjHE9*~w^Q6X1w!t%W)O@!P{Js0E&Z;Fst(C%kIT6t$Q zNmHxfjR?lyC%vRENV8ohwDG2BlB(7rekfNv?~J55`4{%)k?U!1!cNMCH2|WHVyuIA zQj;__>;b&*AWdhl`j?!hJ?{3D0(sUOrHSqDJ-vmJ#_as}^fqc@W22|HO-S1&JP-Et zb_p@j^1OFINHxSyC6x8NcSHz93$^6k$DW@irG=O{?Cn($vK(zeW%c&% zW)eg~AMYheL%s45=;`D26>=CPNs}Q$Oh0|u8!hCm`do{by(vPd=Tc2y@n#7r079j| z;>{OAeVNj{>Ma-2QqsKYtr22+cZ#=J$PkQLjbTrU_c@cG7O9@I3kArY@Z(66>J``I zNW_d$eZ3Y!%osJmTc}Bz`WXJ9Id_n^MF_ps(yhh8Ue(>CIZb89&Chnw{F;XkwKO?| zTd!R}Uiao|GB6>IdHw~EA>JY(w}SN1WR;N5u*#q`L%olL>;s`RL%mOgoF2<*hIu=M zTmYdo!@T`Wg1Qg)3hgC(1}1!fS&zIr+`Cc8MiBD+aIcJzI!Ac7aD-P;NOKU{Ega!h zWfEu}={1uypEqXBBfTeu><1yuBfU;S%uT{Hue*@36F5zp*GEWa+2tGM^%pWgcKJqm z!-SaC@@Q|Y5VKky?M)S8cBsa9ZwWCwRAan_Ld>qwSnoX{X4hz}w~k3r({UdC8U^`q zHR73kIL<2~;@rkjQ8#kvQzX-@Tv(pEP5t*wS<^`zlmOw z5VP+$(Q7K?M!dcCMY~V(S_>%$GFX$2LXJx7O!m47`9oS~ve#S4$ipxXW6Kn;pOD!g zG`39fh6-tT5m5lmZ+K&bJP9&RlQ)Ez{ko~%Y$0a9ZmPFHi1GZJ-U=bc^KW|Vm;|1m z=H0iCJ)e}sUY+JWETkm}d3BoCK#17|o$fUgVs=5Ndu@cwTFH85c%6hS1tC2%ydFZ{ zn#5^ldVPe@ccqkOrZ+%H*-e~gmN!hueIS%(mPcRMQnZ*@o$XB(Vq$f+H%ExsDSgXZ zD8%fPzU8eHl6nDe$MEwUZ=H~#AhR{uDrCx!*j)gb>wO{QEs$lJ>=R;I=WXwMA*OZS z_D%>ft@Dm|R)}excf3C};oVf)shj5&-%mAVLc6K&dJ{C^buXKYx@sWmc3W7$=fZ&oMmtFz7=9lt~Yr{ zgqSnvP2MRX=0tUq_q&iWOZi=Rlcx{?C`+A%=W~K?@_GrOv#B`97H=fRcX}rpjy2NF zAX~khSVIs=`VePiAfI_7H5sUWg~#p%+3uaxBvsw=9adkOOobO{mv}L5hZb?*Ywukl zbcd=w(tPEe{E5>v*oIXn$S!a02_kkqw#RFAk_g_8@kI~a|Jmbp)nv3Lt&nT4H%mxL zB%(Tk?DLigsenkKdHEY}t&o}UI*|k3ej(2zPP-!4x1Rqql{H$8kX+w+d4+61EnYyH zgI+65@TD7Oe7ZMy*jp)S2EeN+NORaLaEfgu1kBqtj?I5#*G&=occ^hiAOQnsD^a zLYgyP{$F*jgh%03+M)W*yIzPnfB(%ZDdaMC+7~0&Z(b!Kdp|&*(Bx4jI$Abp@~kHP zRCPpD1cjXUUJ*iX0Zix@pu!fO_ttBYs=6T_In586us60t^LelAS;~b45-JcH==$eA!h$4>Q@zV zDsNiH)U=JiJi=_w;*UVpq0GeYL|-xTtrM0j3*ju10u=Jgjb(Y2rx zhrIr4zjH0jeUd_cnh-N)7V;+wF=J*Sf4UGeW)||_7GlQCLjGbQX3Q+)uV$iXgnSI8 z7xI7jLzk{&z9qEWmmV~1+=T`Jz5V8TWN@*(juL{`@LTM`b zgN3AyWj&SskwV6UP@2mAL?*$i@^*h^i0p)gxBHcGCQ3fsnT9h>kShK?LX20d_zws% zKCI%`6=FPA#eYnQ@lO@MrI0xo6Ao(4?M#|I7!@^nhKaf#b7mg+r;48< z!F;dR!2eE2)<(RdZr~pkG8TP^_C*``r-hhr`WpCu2r=LEHSn(pX@a?c-q9NPF|28* zO;|CrjOGU5c20VLvCQAR!+eDo}cto(!_p?*U;}T#C(g_$e*IgIMrq}{+2&E~kbZvW5NQH3z~3UI0s4DqkimXsoDb<0 zHEbRNGR*HPWI-+Lb%PA|Hwx+gAZ8Gdk$yp}X((4?kVPP){O+1?yKe;<>%Yb%fp#js z02%M63E8%Vd((J-q9)@Ku3+@rqti^&#Qp;6cz*%s(sj>=QpfwdMNhB?;(sf|XrAaF z(`20b{%!t^poxA_eEUuQISFzAWli!sYm%nEc@41#GTG0IeuXr;tTP~Q_|G#*Fyqg3 z{}mw>8*nYA`vZlTUtgT=4;RuJZv&C{@a>X6j)_{h3M(&7b_&@Gd-8$I@GlDKfnO21 z9%QDU7kA>x=3yWuKxX+jX=1nh#3dnrl!&?p2oqm;T9LNGcj}ZC|uDKu!{Wud{clu&wkzb2R zg4t1A>L&>?-zG2hn+P#q2QT$oX=1&))bGVPJZ4G@`3-jkS@?ev9a3k ztBJMwLw_Qt(Ki2pG;94Ym?S**7{}@c|7#&TTk?u%gMUcKGL%KXSi8YLE+ktGlj|2v zY*`!p1l(RSJ>?Y2+T`ECBq-}+zZw%oH&xOQhadYbLd0E({RF?05c>U0`qj`+{T?Bb z3u(6bBQ>$5f9B8OG`gm@xwv8C?`IOk{1^UVA#~GeBQ$^EpAcfa@r8e$iMEjJ`NGeQ zK4a=t6y!_)ZYBw)-FNvlgqT*|<=57P+q4vN?eZIO8r_1of$a9XYGP}##~;LLbS-Fa z@N0jC%C9EGc=eS35EE7BA-pq{qBLzogxc$j-(3iuJbnv3 zzxqpsP((FEu5`jm zTcb%Teg`F@`XNo0*fCA4R}*7bIG3(PM|d@BtRnXN!d}fDyIaUwjQoqBCwr`h5L46a zu_Pg;rrBdHg_xRVk9B0CYf4_t9_uH>cr{0CiYDU{w%{(-c+?_iY^El5y^%8p^YCwT zwuMu$c21x)hQyk%=PmheLPlbK$HS&EyAYNbn=LW*vSj~I9-l3lvnd1dvK+z+Mb~0B z*HruYb@(}F>*le)XE8E@E#kxUvin6=84g2fXXs8%@b?FxfK2G+*<6f=81I{ zG8J=X4MMzJo zTALSZF_7zG4TMZAjyV~mNUWWZE6_^h`dBYbc)xDl6S(&k`&g5K3H$KQNB3#tu^mF_ z3t94WJXY{}Dyv`c%hK^!6-@@JnW#IpPCV8}6T5p5kL}eYRXJGOUW48gk5#&XZ8rPi zH^v^;gzfnjEqG(Bzb4k660xB|Xw6TzRZ7IhFj4oRbZWs8v6Vtff_#BAC1Y+;Dr=x3 z@&m|Cu_Pf~L0&A2F)=np$hLPd$|B9pvCT{py#J5AGmqP9>K^{S?x8d6eQ`G_BuNjI zN`?j%g-S?+21%3>NhpO-DtGfhCAU;)E;587G%6`2AxffoKq-XE^scqnTGzhLshj-X z=Xu^g-rw!h=Q!W9*4k?iXV3dw&?ex1?DF0kCPjeYu9))PdL}YzJICA1L`H4rczc+< z2;+S##RCJC(ieJFD?vf&MuV3k<8O*M!M$P(m@LRlPAxsx5&x5<;))O|Yb&e-)5ZAYRqHX_mMWRoz=g zTB`n3D7n}N@~WQ+<{$?jfSA^VQht#)hl!NB8r~r$_=WTJC&Cv9y_#i6>qZC*|F4GE z&=OZNYk0FQaU~PTzfiWHnsftc)%3E?B63DU7%PL%HN7TG2C_^oucsxW)F4P_{El%g zPo0fgup9Fy=z&1JQQOO5(hX#efXt;{ey54LiXF#v&Ajs77PAp5I%bRkA zSH==oCtTsxv4lpff$wf@Q*aM^iuQ25%V=8~VZ!wXUs%vDg(zezo&jGm)N5JMUH|l7sEMdzeTLw(}ll zA|AH$hBA>HZ0C(;B01R38)wNt+XLwV{uB(o{SqPN$MiG%>ID>g{#4#D&${8$>cTtU_S9kM}lf-Nb7p z{k)}2cJF{*9?10bRufUUI#AvcbD{N6Ef@-`IY4r~%b2VHQX5Er?5H0NXCX< z4`c>TR&3pL+d6m^Fd09`!D)hFbkpHq4@9zvVIS zeoN@>ZU`}b%o}Tovoq3LmnO3X#(E>Y;?-^FHeUD(;ZJyZM0|Nu#(B>$kuo;Uo6bba z*f{ScA`16oV}E{}w>XVF0xjowZ(ABUd>)KHy#q{S{PnDtagp`Mj=!D-t!KS5OmIG7 z5@=2IDyEU<5YtKCm6o{qgvnlaOI)d&;teG&8`C)u_i5fjBB@!L8QyXxr@}1pJCGVP zyfsWDHD-8UFp;>=@b)l~^qJxPL?o3OGrVLC7cU%X&h*L>vHn~FVa@dVrjf2dUh<08 zv|6dWnB$$sM8cZm{fmkCGsmk)Bo+D`uQn4ruZOua*SjK326N|i@AfnqB=fv`(qu5d z-tzjU$sn2U4Phc<;f3CWG?H~bgy(&nMs9}uTH4<-Azt z)n|ewp%_?R<~2?uox$?E-W`^>lCa!+!V*^!-t%4{Et~T1LrGZaZ6T5>39Gz4Ot2(W zgs@h52bf4nSmpiBL{fg07hX*HCAqW8D@G)h7puH;nMhu&_NpS~eLnIwkc_q555oGy zy95WE&`&svThH}geI^q3^Kx?D-CX=1d!%PK`P2QR`G8@QO-VP@9S3x-ivekRAHkF?{pv*4?vdtT8i7Ol1 zyjLx8ao_H(B$Db`?ezAN9h(~1m)PmmtP@R*J>KO^B<_2>tC>jp?D3je;=ea-eAJNlF6OW zE@M~;zbO;(C*fbuMA9eW-)u>qDzKD(l_uf$vBafM0e>uM+0cK6(0%`Rwj-e@{p`Br zkA$A|lT0M^q+gVYq(;&|jftd2(l2WXr3U^2PSWp1GB!2-gwRj$HxaS^1aHHyUixM0 zMN^}wUzv%7UevG7MB-l5ufs&v8H@T2ETPcxw{?p8U729|;BV^`^B=XurB4ZeCfP}) zPf0&nKkCn!eo-dk&zb&dOe8hV^#8>~QsYd&A`|iOOuxD%dFr>t^cy{A`pZa0oxTKS zjUYA3`Sq@_p<93O|0?;-)5z%{Q_0_B3Dr^fJ3i<7`z_fOTnK%?b3x`@|2HNdeJdnr zfcAC;*|1XpXVuR2Phye_H3Zgd=lW%cB#OW~2JZH$?4QqM2-joh`E@NBs205lGdWQE zUEp_N@_A{P5rWXG_+y#83H`%MfK>BWFc}4-ZO0;%1HN_^m9V zTH+*FU8>`+CgRHosGh%$iPV1e{7p=x)YbEM5K*(=9>IzmbhB|YX3t^T*++c?;$N)61qZ68~N26+OT{%Q`6M1!z2ev zH`W_X{RT{yenWGoP5ma8_6=eGW6CgO8je;gC>xvf8$$&WlfZR>&Cg?UIhW^d{YDuWy*hSJdwFi!hO|sNLtEMkM9o{eDxH zd9MlO>HYroOg;sId3wL!o=MpuB-7LH%%nOHl=*3hVv~C`O}G{V$sXr$TDwn9p1~|#$*K$^stxzEfa}p zZ~sRo64T!PZ%ibn5BpiyQaVdaANG?>B&L1*qD&;Fef*M4B&L1+vzSOs`}*fH!7pH7 z8`saT#st5Bfj;;1>oA#i4aq#>H(-Lle1$TP_)VFdoC&`g566Z_i`} zw3QfEf4?)6kAa|_{(cW4sZ<@{uVWc0y#xGBOr-P<@OLtqm4x4Bg12CxzmLfqKo(l^ zGm(_#L4J{Dl&WHRkY9p{SRUm6i%3dquwR{JwsL9=_UkbDkyB%^eS zTQiY2Zm8d$iM(+`{X3XQX&L5sXCkF#nBR+ul)B-5e_aOAd;a`hZAfO>Z_siAdBNYqBx4$p7yW8ClFYmka4re#yyV}` zB&QJl-p#9iUnV7hpyfIKQ%pXEzIt`gdfk74$$RfZ-xI>=wtBEK386dE;R@*G0a==|BVP?# zmLl@ipcF}cHOLYCYS5iv=UqRiEqY3O82SNO;SaLJeKlyc{}>bbYS3!`NlV;UgI4}=*;MZzrOM;SEeCQ9h#CiU*Trd>Zfq`bRKy4k>B5v zJaz6k*immumkubCr_Ka|zcKT1DmAu3dB)uup9sl52YO8}fXpX;&5l;fzZKqY{2iK4 z{mU%rm&&hC{i`h56^NZr{iZ|`V&_x8wIyzZxZdw%35^gJg5~vowOei6eJO|A{n||A zdpq0xE0|1p3r_Tc)^@)!6I}n=XvuX_D=^-|}qy4$Kzo;geP-&!*~bAUphLEODv2 z!=G-+u7qgq@Ml`$(r~9g#}Z0I?DOyRzb4|#sl#3VK_cohX!Z6%SiAgMw_!Rv%e(wJ zmgM=k7Yk1r@Al_gGRn@u5;><6YPryN`_(MjmB3S4hrse~{}v{AN~-{j8^7@z-fr_W zRa*A>%`KsrV*9?&??5vCrBI7vJ@%b{hb4Kc7qkWV)xPii5ti&qoVE|l|N$d7&{CbO<3tsniW zmgM>aq0e>(g#M#{2@~8ii$4G8x3q*jJlo3TTH-uB=#OF|9{%LdV~1I&LRIwCg%t6 zJCBw$VNw9rSczQ61b0Caxrs^FCq$+rlTkkj>B3|!wB4lD!xC4b4*B0$LUFHYLqDSn z<&L~@zxw5v6dwxnS|IbQe;yO5)qnLbB4SJ3RaT}G%Ur(_+6y3m_+6RE&X7O+o=haH zKm5LFcCNQt(^zJ}Z_v8{k`cVfMCz!FU@nv5ufm=JE3<&f1ry=Byq3I6#CrIUB?n?M zSpj4|{4Gy?_0AEAX^N!UFGsNb8UU8FgF|UyJq5%MKEBhIpVT)bO|X%PST?~9BB^gk znxObyRO-ZXGU#Fn<=0DKIVadkGAYZ2gFQ^da^c_r+mSEz6%MN39kpB}7;cHPTr5a* zjrx2_;4=}+rv!#b%I8ypT1>>}Q-jAWq1Jpk_*^nrW{GRfO9!i&bejj~DnO=mu#U9+ zgRowZc^Q&TEF&#`>0pN?uEj4M>|?Da@6aj!GlL_frMAIaun8=m8Dwo{8aWK4VqosEsbRGWFNFOfL6`27KA3~}b=<1K3MN-y4K)eK zTojb(finG+552+qKxzhEnfwa9!4^O+4(3}jN(DeV0J$Xa?m2>QmTd@f46Nf+F{m))=t-Jdi7cWlXk# zomYWe9hB-xGAqE&G9ZnD9!y3|gnkx~CczFS2SIBKkY+&x97w}>=SK+ZCm`1aW0=Ty zZm$nEThdSM1v>@6gByZ_Ot3Fe7|2aQrw7rFD;w>Dbq|q0vKO>{@UZz9k5-#EvV0=8xZvQwxBVS^Pw!GOsC*F zCUtY>c-K{qCYG|jzt4jy1K76`rtor6c1>`ElmRn_5l zCxf9(4gonG^5Tx*aVE=Irb{rM$!9FnC78;j`v_RO0XugFFEDuo2->+bn9F3;?-Z}Q zf(1+_0YRVd3YJ?!UrZ_kT6YI~ncM?uSP@9qV0LfJL6`@C-q(ddx&{3owt1R*m%9g_ zr;$rQrh9ORh#Cs-X+0o4g1UX27VbT`FL~6z zj>*I9;{==XC^(iQ2p~*@CTEjK(PLKEbt$(Wh3<# zj10P3LVbyLP@+Z#b#hULMmKi=c|7p@BgwO0ckc-#FX)m+MgtiiY_epa!r$F~8OWrd z@&Fr_dizS~0Rov4^tZ&-*wcav18rEU9K5I7KxSGnlF6oxu)i0`^k5GYsnur$zgyx? zPR$6i2idUvS~%172JB}GPGC~|l!VI4gk5LBNlcmp2`xFD3I3Au0SN24;A|%E0QuRH z%1mSg{d`cJ$@Hd_JI@D~GLbdkS;3V|a$yWI74m&na4i!&BaXW$UkF+=X$Az(%e)YD zAdlHk64qB*`DThmf zBTS^!EeSG)Qt6d4wj>CdNQqh!6k;OfXGw4h5w!_gkQ>3DB|#Y`@(wNyYB6aGZ{@8Z z^KLMaiM*97gAGh(!h6~mWL5>WhFO2q5oiaW1@d7qn8|z~vw*A(b}%`Z4c|@&@=35` zIBE6u;M^9F^}&)6L@*8C2l9EaGL2xWZVV1E*$er;4#*e5Z)s!;kS~KakD{G^3g_PU z0of94w`7#swHCf24`f^5KZY`+)E@_7d^!_azF@s2{nUwBu#0C2%rWY9?OX3AA-e9%Iu@Ceh5}Dx!@17^Fy$fNp(eiwjY8GM6BiW!SWA5gHaSO z{I(zN+xaDE!sP7)Y5fwkV$zf?{}Qxg@-y@^v4{3c(22>N{0{ySbR}ZLstIBJ64V<_ zVNK&S%nYw#BJ)w1VGAbT!cGHB=gja%Ay7xP0XvytM<%kPEHk{537#KpZ)NUf())er z;abw0$v5y8+-1oCCRhFnJvd87F!}fwI00bE6HM}UQ~G3vPcwO^v3NL>h>ht0t98NS z30qp^%S&NclZnJM3@>MLFNYq6S2Ou_JA8u_?1W)6CX;qi{S$^aFbSYvhc!|dc3>hN zhT$DVtUu3LJ2P2EQodj~o5>7L=YrupCM#29F%$eP(YL@(!EgnW_c(nDhHIHf=mov$#4_PG%if<*XiNcOeF57hrck9ZxWs!W<5bECf_7HJv`l#T>rtz zP=|r#)5Eig*mT}&$tA2MVU-T+Gr`~b`2}Q3hmDxXR|-pqotVg13QLE%mbm^{>2NH` z*sy-LcJ{EA>#!KN>3h{SRs)t!)iQrcX>jJqbY-Wi|)r-P*mh@Av zJ_+@zm03+%enY6|n*pg2)_scXWIqja8b&=qkvo%?q#wK-ixt7>V{pPCar@&CIPu3Ty4oHHFzWR zoq=2#mUsqb;B+3;8?OMlD(r6wwWs*3Vfe8nk1N>|*f89iCi4zxH45uKi?Z(5e;S8Z zGm%-)#$h8%2Kvu&8EYK2A(_;?XydRi6P#7U-veqAZnETY^?Q&|Yapy@CBL{%A4ObHJzXA`vrO>K{UodHQ6ZIw9hkGn><)?kvV+vaCr%H2J?Zd@P z@*wU>u+t$dGL>WsH-K**0O=UsZOJJ0$$FUY1kx#-U`d|3545TQ=^XB1QVQncE(g*j ztTheohO(tKRno!SKvV_T2=+olt%HVJ%lj`jA;P4|R zWw=K)IQ*Q6oJJWO?jWM@RN~9la+{fy@|_`l%4nD+5B=vTUc*3Uz;p0Ehpm{%`!y`Q z+meC)dwXE-2G|)9K2OA+EL&p9JSO->#MPGUO(UNGc{IH6d7Fa@Ya9H%gvY`jOiDt} zd@GPq;rEufk~um&c@}E*Oa1Ei=&+I{u1**oHn)Vn>$o56j1HT;KryZS6|C0*c|6?1 zr0^6t$FL0cWQPY{wEoyPHwh#!y!IvXFbiag0T~;%v&8xHRG4cCeG#z~$UGH3Nm{8d zB90HAWg;^|7;a}WF^guFCWU*M$aga)hX(i+E~X2+gR8yG**Bdd@j6&34V{UCXiX-B1_;4 z=a6FfJ;s;9Lrm~{jEz9%<*@lHXs4gT?=iLm@@hDniTsw$+|Yj&Wk#v&Q7~@`GH-_! zh@^Hp%@12y^0>P8Gnl~unfYPyIaVtrvmiY5y7f5~uLYrc!;xP-NVTve5r5Y+@MeRZ zh2dFgGMLT_!^SLwtFAaoS`=QFCi56*Eeh{t8T_uu6d;Sk-f1#uXK^^4Wu!%0626os z^EzlP3HPy#l*6UrPcf~fp_+%W*qYc^kbWss)?OT)`7q4)h9=tD0H zn_A-b(!3j9Pb9UM=H0NJC2rmPy|7D~9Sq~Wu!kkN@M~cZ4*2|DIEYEbESM_*vLehA zQh>qxnfJprOdijKcHktK-v~D``OYV@I{b#o2ZdmE0kl2{e_%2Qa&I?~ zHDT~J`jx9TW|7v1VG&DQEY^mlEOE8p+ORBZl`8`C!LYWsHoP^a^-*|FOzWfYLDp)0 z4zvZeVK-Dbl*#UMp@&}w_CAH9V_Kht<5;HHi7@gFVNNET!{jT7H-3lVlkk9$v!Rx_ z1WD$6jFUzpgTW4ZxGtQ)q*X<-{Au{ICC>6^;TtS7 z6bdSO_*uA#$*^MN;b&p31(eP$%97>J!j??lV$18p+bwaHH-z0-M&iC99Lz-Gz9F1@ zl-2^4k(h1>H!_i!ZU~bLqv^9DENV%vl2~jAt22>UfImlRJ-{;cAb0SL&xUY%Oy-Ml zHp}dXbp9Sv^@}ijQ8e^TVbYRZb>9haz6s`bHigxhOad(=Uxpo+yaBm`n=gOE`vQCV+>yA8AWCk4aI;o%%qwhF`?AwuReS<`gI`Si-l3S&O4SZx4+n zxoR%t`*^UkJv=2Qvm-3cG6TTQckssT2y4bZ!fqA|~fSs_q2xUHCyv>p=KvOzS|nJ*M?T_JHJ6L{~3N1lTrF} zmKg+PIqO}BqAs*7nmY-7iY2*9Qa+(8GLh8C)ODChys~u*CbQs8!I&1%oh@-5db$V8 zH0Koa^kOD0AWt!-zSi$j+^a&0VN63^(h_G!>#{6^cDg}}rF9o3Xa`H3(T~NnjD9kv zW%N8tTuYtQW#7Zlw=5#8X^s7w*viiyY+ z)m=Y}$`sXonTX6udgS`3%t?A86Ok#Vi)@U_6w_sxh)i+ab5m5NxE{hYHB zN^Cv}_I`suXXCI#(75B6CZX&53?AiLen4NO^NSYmtdpVu46R){y6!aKR0}spT&=MDm^7)$~tH`cx)TUH@*0vwV@x-bMMo z2YLk<(~I=!mN=Oj`fQe218v;pV7Z2_ZHe=_roK9+RZ}-(tya*&Tm@P+^{p|jTKb-t zRxRC&wI)MeGzP6&dQzIqqqATpS-(NVm)~!ytrsy_TqL0$hgP<>e$Nu;VQu|MnjMUD zZT*EMxo}p1Jglw1X40@QtW!hib@UHRZin$#XCRmA?A?@NYe5FdWxBW}F2yd_rC8=U zD3$kv%;ox$m`q(=pJna?fBS<>U41)~XQ6+HJ-vFmza_4%tgo~7V(6}|tgnkOk$UwC zUE#Z^%oVzZB`!4@==zp8pBv~#mgK^($wJ>4{Ar+DF*!4YnJ^$%>Zh1Y#}OistMnu$ zcSA21$<_KfOPu9~dJfC{dN!OY1DS?;izO~z*J%IysL$8v;!Gr7jda-`qcV+jbtWRy zSdaNBD$`g`wS@e^FA+D7Kv3&^t7SnSb4v zh?3CT=w+6;(A(%bzoAw?C84*`{Vj2!x6wyfMnZ3+Gk>>X*|@KS6uVKEvSe2vvwZFJ zg+vnad*bc%AWK|XZLc3svx64f>+zQ4s^6fM!CI@mo*t9wpl7qpMeq*#5YrBN2a~Vh z{hHPg_QC3N|8O4S|8>;WEXh@OLs=!#_9&T7Eb}tFxoEkgp1@=_TfSBAj%nSd_p?kL zwtSl|_GdKo+w|#{btF!JIL}fbb!AwNv4qetnW$w_`nTSjmec*(s zOc$+ABqB0*>PjdnI-+~UdLTv`5}FX ziR^XkrCXhbS~P3D4`h1l7c6lls*he)$O|uKGf}+LVG7F`acLYAsg}L%cNjG*W9O??5cj!_m5kCH+(f4*hXG#1dD2^7Ipy zxbl;ypSC1dVb8oUSkBW^n6!bm`xGEg>KB;c@Bq_jte(rH0Q7__0~x2^Ve(Qo^v-~c z*DIJbgg(-xKqlyO%U~>WRciFqCLtpf6keQ@sTH;FGWUb0#=&p}6S?4g3Qa44HEgzMcqN_6znW?(OIZ>IZ zx&jlCnWoEDjLJ;Y)tQLQbiJioRA#z9z(izbXun2OW`-`#L}X@aRVykpQ|B-dndkKE zi=#5n>BUS$=6Rh{J1XJBqLBAxzW(=y`(7t9ld@{JO>UFs^)6 zKV^xF*Q~ z=m(g*Q-#Po`gtY>N)y^ysux(|!dj-^Wtm@~r;IYo^ae{@4e+k6TsK<6-_>=P$Xl>n z_pcX~S+2)05t;Y&y82O>_w)`XBC|r*Y7muKp&K$0nU%Uo-1VC+d-xUkWck?k%2PS8pvmQFO#1@3(0!zUrRBSl;5CB zG>gW4gRa0tWIor`n@43n*Yz!Nsj*Qvu_RZ`gLVgd1snAjOjf}7gUFGiw6a>D1po+$pSUqHD0bPrjtFS^Gp% zbElj2iI%vqw(3(Yaba!MXIhdAzx)Tg(jcZ=^*KVI1wpb+Ul7yUu4}T)eCX442bt~q zj+o32-JNB=WSJd$5RQHN^o@$BnaF?DPv$IRjW34XW&x4?~OD~Se?A9w-rXG|- zw7gsIVbYbu+M~<0#T0|lG4#-I-2Jt#W{C^^8-2MYE`7eySF_egNFUVtMz>^Ap)iqe z_03Gma*FNMx5w=4)7@AGXUy=oarfylOk~FFJN;rzYrmcw)7q~$#Iz3RgO<3G`MvJn zK3eL&*JGGS$^1dj=@^yyK`&z>GC%4IZ;#6SsOvHjnS;7(=cvp<-Is~T{G>~CiOT$> zD=-n6pY`lJqcT71#g@>QJw}v+-59#g-6%6kU067wzPt%mOZB}>7Q@{F_;*APw#22z z5#6q9)bbI1mnANjf7LxL$yFagS$ze<`c*GwQXcYrA&}qo9=0Ps|EU*ui(39uuVo@K z%Iv)-Dx=JAOhhJOwseomB+LOOB9md%eNmYVlfy)0GR^G!qcWLhp(Pa4+i!*yT(gEq z>N}+c%x6q`LA|mK-i-og3)>OPo@w}C)Us#VFcBHwZ0Qx1@y&OZQ0Oq=Qi1V%lgv$1 zs16TJDJEzKN5`RQ_pp@-@b{B*;av_*CnAZ*q29-uUz@vGW)sLf07#o&EHn2D7-d3C zjakG*zCD{XE0~DSCzu0$qCTHs{; z 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

    `a9~+dYO7gU!wl1zpI|tm#G)^_muW7 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 diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.pdb index ed81f17fce8e771765de8f21b5ae12f4d68c25c3..acac39f4f397cadfdd90ad83932f3bc4dab6f204 100644 GIT binary patch delta 66817 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 delta 66602 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 diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.dll index 458795905d3f8bfe643a5be5107af08a147d7696..ee85d89f1ccaf04db6a19baac7a3fc12b1744e08 100644 GIT binary patch delta 261 zcmZozBG<4)ZbApM_N4O0?$&O`)^4WOZsyi*mey|8t=(+Bh63}Kmay%#i}l}Pb=bh% z_5Z@{8b)kBH5y5#CPrx{NoFP{DJkZbMyZC01_mjKsc9)@mgbfwMwTgwW){gNDQVm1 ztYhOi&tl+qe)aSfwd?@`IR!^NO}@Tx+HkbRMN|2G)pU+J_ACXcXc0^lq<(hqUWcl% zwI#0c+F!R%s$(zV_fKLlWiVkdVn_p$NepH{(u5%e2+bKRfugAlh75@e20)ksq*H;a dQh;hK!LlG-mSAx+1`CE{u)ehIp?&PDnE@#ZQ(OQ5 delta 261 zcmZozBG<4)ZbApMWwC!_cWXCeYd2GCH*;$@OKUgl)^4_5LxHrbjOjkxgq=6qNOgRP z^SZKK!-&nNMkCqW)WFoxz|cG;#Vpm*(8xF`)gr~j#304U#L&Pp$;{j+**w+M!f^YX zb!;5xSp>rqHcnqr%N`)$n{ZV1#bPs;HoXDL8MpB#gVg49o*z0o&q z-vahM9Bk*ePpV@t;rCBwFlR7jFaTmhAZZBXr2wHBLn?zMkY~hT%#Z|RTL8sOfY1O) g8v$vMT1%je8Bo0u1IUb2pa~WXhTB8?*jFSLz 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 delta 22149 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 a0-sA>zi=$aT$aI^O={)ZP}JVI-~R(pk9ZmY diff --git a/unity/org.gamecult.cultlib/package.json b/unity/org.gamecult.cultlib/package.json index 979cabc8..7c2cce1c 100644 --- a/unity/org.gamecult.cultlib/package.json +++ b/unity/org.gamecult.cultlib/package.json @@ -1,7 +1,7 @@ { "name": "org.gamecult.cultlib", "displayName": "CultLib", - "version": "1.0.46", + "version": "1.0.47", "unity": "2021.3", "description": "CultCache, CultNet, and CultMesh managed runtime assemblies for Unity.", "license": "MIT", From 6c848bd6c0d961251c6ed210fa64e80ae0466bea Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 17:21:58 +0200 Subject: [PATCH 094/283] Bind CultMesh authority identity to physical routes --- package-lock.json | 6 +- packages/cultmesh-browser/README.md | 11 +- packages/cultmesh-browser/package.json | 4 +- packages/cultmesh-browser/src/index.ts | 153 ++++++++++--- .../test/cultmesh-browser.test.ts | 160 ++++++++++++- .../cultmesh.session-accepted.schema.json | 18 ++ .../cultmesh.session-open.schema.json | 17 ++ ...ultmesh.verse-catalog-response.schema.json | 13 ++ packages/cultnet-ts/package.json | 2 +- packages/cultnet-ts/src/contracts.ts | 45 +++- packages/cultnet-ts/test/cultnet.test.ts | 19 ++ samples/eve-browser-network/Program.cs | 35 ++- samples/eve-browser-network/README.md | 3 + samples/eve-browser-network/browser/main.ts | 6 +- scripts/verify-eve-browser-network.mjs | 33 ++- .../CultMeshNativeQuicRealtimeTransport.cs | 31 ++- .../CultMeshQuicRealtimeTransport.cs | 32 ++- src/GameCult.Mesh/CultMeshClient.cs | 12 +- src/GameCult.Mesh/CultMeshContentSessions.cs | 43 +++- .../CultMeshContentTransports.cs | 2 +- src/GameCult.Mesh/CultMeshDiscoveryService.cs | 3 +- .../CultMeshRealtimeTransports.cs | 2 +- src/GameCult.Mesh/CultMeshSessionIdentity.cs | 213 ++++++++++++++++++ src/GameCult.Mesh/CultMeshSessions.cs | 187 ++++++++++----- src/GameCult.Mesh/CultMeshSnapshots.cs | 2 +- .../CultMeshTcpContentTransport.cs | 113 +++++++++- src/GameCult.Mesh/CultMeshVerse.cs | 98 +++++++- src/GameCult.Mesh/CultMeshVerseDiscovery.cs | 21 +- src/GameCult.Mesh/docs/public-api.md | 8 +- src/GameCult.Mesh/docs/transport-planes.md | 14 +- src/GameCult.Mesh/docs/verses.md | 13 +- .../CultNetOperationServer.cs | 10 + .../CultNetSchemaMessageSerialization.cs | 2 + .../CultNetSchemaMessages.cs | 47 ++++ ...ultMeshNativeQuicRealtimeTransportTests.cs | 10 +- .../CultMeshQuicRealtimeTransportTests.cs | 18 +- .../CultMeshBodySessionTests.cs | 12 +- .../CultMeshClientTests.cs | 49 +++- .../CultMeshContentSessionTests.cs | 57 ++++- .../CultMeshDiscoveryServiceTests.cs | 2 +- .../CultMeshSessionManagerTests.cs | 154 ++++++++++++- .../CultMeshTransportModularityTests.cs | 101 ++++++++- .../CultNetOperationServerTests.cs | 38 +++- .../NetworkingTests.cs | 15 +- tools/GameCult.TransportParity/Program.cs | 29 ++- 45 files changed, 1670 insertions(+), 193 deletions(-) create mode 100644 packages/cultnet-ts/contracts/cultmesh.session-accepted.schema.json create mode 100644 packages/cultnet-ts/contracts/cultmesh.session-open.schema.json create mode 100644 src/GameCult.Mesh/CultMeshSessionIdentity.cs diff --git a/package-lock.json b/package-lock.json index 74a753a5..1e955e9e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -846,11 +846,11 @@ } }, "packages/cultmesh-browser": { - "version": "0.2.0", + "version": "0.3.0", "license": "MIT", "dependencies": { "@msgpack/msgpack": "^3.1.3", - "cultnet-ts": "^0.1.1" + "cultnet-ts": "^0.2.0" }, "devDependencies": { "@types/node": "^24.0.0", @@ -878,7 +878,7 @@ } }, "packages/cultnet-ts": { - "version": "0.1.1", + "version": "0.2.0", "license": "MIT", "dependencies": { "@msgpack/msgpack": "^3.1.3", diff --git a/packages/cultmesh-browser/README.md b/packages/cultmesh-browser/README.md index 4f5c7e8b..59a44016 100644 --- a/packages/cultmesh-browser/README.md +++ b/packages/cultmesh-browser/README.md @@ -43,10 +43,19 @@ selection, reconnect, or resubscription. This is deliberately distinct from an Eve surface's `providerId`, which identifies the UI provider inside the Verse. The physical socket is a replaceable route, not either stable identity. +Odin returns exact authority-route bindings. The browser selects only routes +bound to the requested authority and `cultmesh.documents.v1`, then performs a +session-open handshake. It does not report `connected` until the peer proves +the exact Verse, authority runtime, protocol, and route generation. Operation +responses must also name that authority. Legacy catalogs are accepted only +when one authority runtime makes the endpoint binding unambiguous. + The browser handshake carries authentication through the host application's ordinary secure cookie or equivalent upgrade credential. The C# host adapter rejects endpoints without an authorization predicate unless anonymous local development is explicitly enabled. Run `scripts/verify-eve-browser-network.mjs --eve-root ` for the -real Chromium + C# headless chronology. +real Chromium + C# headless chronology. The witness publishes a lower-priority +decoy endpoint owned by another runtime and proves that neither client connects +to it before and after route rotation. diff --git a/packages/cultmesh-browser/package.json b/packages/cultmesh-browser/package.json index 41833562..c49062b0 100644 --- a/packages/cultmesh-browser/package.json +++ b/packages/cultmesh-browser/package.json @@ -1,6 +1,6 @@ { "name": "cultmesh-browser", - "version": "0.2.0", + "version": "0.3.0", "description": "Browser-safe CultMesh document leases and typed operations over CultNet WebSocket transport.", "type": "module", "main": "dist/index.js", @@ -41,7 +41,7 @@ }, "dependencies": { "@msgpack/msgpack": "^3.1.3", - "cultnet-ts": "^0.1.1" + "cultnet-ts": "^0.2.0" }, "devDependencies": { "@types/node": "^24.0.0", diff --git a/packages/cultmesh-browser/src/index.ts b/packages/cultmesh-browser/src/index.ts index efeb4515..bbc253f4 100644 --- a/packages/cultmesh-browser/src/index.ts +++ b/packages/cultmesh-browser/src/index.ts @@ -12,6 +12,8 @@ import { type CultNetSnapshotResponseRawMessage, type CultMeshVerseCatalogRequestMessage, type CultMeshVerseCatalogResponseMessage, + type CultMeshSessionAcceptedMessage, + type CultMeshSessionOpenMessage, } from "cultnet-ts/contracts"; export interface CultMeshBrowserIdentity { @@ -21,7 +23,8 @@ export interface CultMeshBrowserIdentity { export interface CultMeshBrowserRoute extends CultMeshBrowserIdentity { endpoint: string; - generation?: string; + protocolId?: string; + generation: string; } export interface CultMeshBrowserRendezvous { @@ -173,6 +176,7 @@ export interface CultMeshOperationOptions { payloadSchema: string; payload: unknown; idempotencyKey?: string; + /** @deprecated The connected authority is the operation target. A different value is rejected. */ targetRuntimeId?: string; } @@ -338,6 +342,11 @@ export class CultMeshBrowserClient implements AsyncDisposable { requireText(options.serviceId, "serviceId"); requireText(options.operation, "operation"); requireText(options.payloadSchema, "payloadSchema"); + if (options.targetRuntimeId && options.targetRuntimeId !== this.identity.authorityRuntimeId) { + throw new Error( + `CultMesh operation target '${options.targetRuntimeId}' does not match connected authority '${this.identity.authorityRuntimeId}'.`, + ); + } await this.ensureConnected(); const messageId = options.idempotencyKey ?? this.#options.createId(); requireText(messageId, "operation idempotencyKey"); @@ -353,7 +362,7 @@ export class CultMeshBrowserClient implements AsyncDisposable { payloadEncoding: "messagepack-base64", payload: bytesToBase64(encode(options.payload)), sourceRuntimeId: this.runtimeId, - ...(options.targetRuntimeId ? { targetRuntimeId: options.targetRuntimeId } : {}), + targetRuntimeId: this.identity.authorityRuntimeId, }; const response = new Promise((resolve, reject) => { const timer = setTimeout(() => { @@ -489,13 +498,67 @@ export class CultMeshBrowserClient implements AsyncDisposable { socket.binaryType = "arraybuffer"; try { await new Promise((resolve, reject) => { + let opened = false; + let settled = false; + const handshakeId = this.#options.createId(); + const finish = (error?: Error) => { + if (settled) return; + settled = true; + clearTimeout(timer); + if (error) reject(error); + else resolve(); + }; const timer = setTimeout( - () => reject(new Error(`CultMesh WebSocket open timed out for '${route.endpoint}'.`)), + () => finish(new Error( + opened + ? `CultMesh authority handshake timed out for '${route.endpoint}'.` + : `CultMesh WebSocket open timed out for '${route.endpoint}'.`, + )), this.#options.connectTimeoutMs, ); - socket.onopen = () => { clearTimeout(timer); resolve(); }; - socket.onerror = () => { clearTimeout(timer); reject(new Error(`CultMesh WebSocket could not open '${route.endpoint}'.`)); }; - socket.onclose = () => { clearTimeout(timer); reject(new Error(`CultMesh WebSocket closed while opening '${route.endpoint}'.`)); }; + socket.onopen = () => { + opened = true; + try { + sendSocketMessage(socket, { + schemaVersion: "cultnet.hello.v0", + runtimeId: this.runtimeId, + runtimeKind: "browser", + supportedMessageVersions: [ + "cultmesh.session_open.v1", + "cultmesh.session_accepted.v1", + "cultnet.database_subscribe.v0", + "cultnet.database_unsubscribe.v0", + "cultnet.database_change_raw.v0", + "cultnet.operation_request.v0", + "cultnet.operation_response.v0", + ], + }, this.#options.maxFrameBytes); + const request: CultMeshSessionOpenMessage = { + schemaVersion: "cultmesh.session_open.v1", + messageId: handshakeId, + sourceRuntimeId: this.runtimeId, + verseId: this.identity.verseId, + authorityRuntimeId: this.identity.authorityRuntimeId, + protocolId: route.protocolId ?? "cultmesh.documents.v1", + routeGeneration: route.generation, + }; + sendSocketMessage(socket, request, this.#options.maxFrameBytes); + } catch (error) { + finish(error instanceof Error ? error : new Error(String(error))); + } + }; + socket.onmessage = event => { + void decodeSocketMessage(event, this.#options.maxFrameBytes).then(message => { + if (message.schemaVersion === "cultnet.error.v0") { + finish(new Error(message.error)); + return; + } + if (message.schemaVersion !== "cultmesh.session_accepted.v1" || message.messageId !== handshakeId) return; + finish(validateSessionAcceptance(message, this.identity, route)); + }).catch(error => finish(error instanceof Error ? error : new Error(String(error)))); + }; + socket.onerror = () => finish(new Error(`CultMesh WebSocket could not open '${route.endpoint}'.`)); + socket.onclose = () => finish(new Error(`CultMesh WebSocket closed before proving authority at '${route.endpoint}'.`)); }); } catch (error) { socket.close(1000, "CultMesh route open failed"); @@ -511,18 +574,6 @@ export class CultMeshBrowserClient implements AsyncDisposable { socket.onclose = () => this.handleClosed(generation); this.setState("connected"); try { - this.send({ - schemaVersion: "cultnet.hello.v0", - runtimeId: this.runtimeId, - runtimeKind: "browser", - supportedMessageVersions: [ - "cultnet.database_subscribe.v0", - "cultnet.database_unsubscribe.v0", - "cultnet.database_change_raw.v0", - "cultnet.operation_request.v0", - "cultnet.operation_response.v0", - ], - }); await Promise.all([...this.#leases.values()].map(lease => this.subscribe(lease))); } catch (error) { if (this.#socket === socket) this.#socket = undefined; @@ -576,6 +627,15 @@ export class CultMeshBrowserClient implements AsyncDisposable { case "cultnet.operation_response.v0": { const pending = this.#pendingOperations.get(message.messageId); if (!pending) return; + if (message.sourceRuntimeId !== this.identity.authorityRuntimeId) { + this.#pendingOperations.delete(message.messageId); + clearTimeout(pending.timer); + pending.reject(new Error( + `CultMesh operation response came from '${message.sourceRuntimeId ?? "unknown"}', expected '${this.identity.authorityRuntimeId}'.`, + )); + this.#socket?.close(1008, "CultMesh authority identity changed"); + return; + } this.#pendingOperations.delete(message.messageId); clearTimeout(pending.timer); if (message.payloadSchema === cultNetOperationFailureSchema) { @@ -733,33 +793,72 @@ function selectOdinRoute( response: CultMeshVerseCatalogResponseMessage, identity: CultMeshBrowserIdentity, ): CultMeshBrowserRoute { - const matchingVerses = response.verses.filter(verse => - verse.verseId === identity.verseId && - verse.authorityRuntimeIds.includes(identity.authorityRuntimeId)); + const matchingVerses = response.verses.filter(verse => verse.verseId === identity.verseId); if (matchingVerses.length !== 1) { throw new Error( `Odin returned ${matchingVerses.length} routes for Verse '${identity.verseId}' authority runtime '${identity.authorityRuntimeId}'.`, ); } const verse = matchingVerses[0]; - const endpoints = verse.discoveryEndpoints.filter(endpoint => { + if (verse.authorityRoutes == null && verse.authorityRuntimeIds.length !== 1) { + throw new Error( + `Odin returned ambiguous legacy routes for Verse '${identity.verseId}'. Explicit authority route bindings are required.`, + ); + } + if (verse.authorityRoutes == null && verse.authorityRuntimeIds[0] !== identity.authorityRuntimeId) { + throw new Error( + `Odin advertised no route for authority runtime '${identity.authorityRuntimeId}'.`, + ); + } + const boundRoutes = verse.authorityRoutes ?? verse.discoveryEndpoints.map(endpoint => ({ + authorityRuntimeId: verse.authorityRuntimeIds[0], + endpoint, + protocolIds: ["cultmesh.documents.v1"], + priority: 0, + generation: [verse.compatibility.transportVersion, verse.compatibility.rulesHash, endpoint].join(":"), + })); + const routes = boundRoutes.filter(route => + route.authorityRuntimeId === identity.authorityRuntimeId && + route.protocolIds.includes("cultmesh.documents.v1") && + (() => { try { - requireWebSocketEndpoint(endpoint, "Odin provider route"); + requireWebSocketEndpoint(route.endpoint, "Odin provider route"); return true; } catch { return false; } - }); - if (endpoints.length === 0) { + })()).sort((left, right) => left.priority - right.priority || left.endpoint.localeCompare(right.endpoint)); + if (routes.length === 0) { throw new Error(`Odin advertised no browser-compatible route for authority runtime '${identity.authorityRuntimeId}'.`); } + const route = routes[0]; return { ...identity, - endpoint: endpoints[0], - generation: [verse.compatibility.transportVersion, verse.compatibility.rulesHash, endpoints[0]].join(":"), + endpoint: route.endpoint, + protocolId: "cultmesh.documents.v1", + generation: route.generation, }; } +function validateSessionAcceptance( + message: CultMeshSessionAcceptedMessage, + identity: CultMeshBrowserIdentity, + route: CultMeshBrowserRoute, +): Error | undefined { + if (!message.accepted) return new Error(message.error ?? "CultMesh authority rejected the session."); + const protocolId = route.protocolId ?? "cultmesh.documents.v1"; + if (message.verseId !== identity.verseId || + message.authorityRuntimeId !== identity.authorityRuntimeId || + message.protocolId !== protocolId || + message.routeGeneration !== route.generation) { + return new Error( + `CultMesh route proved '${message.verseId}/${message.authorityRuntimeId}/${message.protocolId}/${message.routeGeneration}', ` + + `expected '${identity.verseId}/${identity.authorityRuntimeId}/${protocolId}/${route.generation}'.`, + ); + } + return undefined; +} + function requireText(value: string, field: string): void { if (!value || value.trim().length === 0) throw new Error(`CultMesh browser ${field} is required.`); } diff --git a/packages/cultmesh-browser/test/cultmesh-browser.test.ts b/packages/cultmesh-browser/test/cultmesh-browser.test.ts index 624bdf17..a785d47c 100644 --- a/packages/cultmesh-browser/test/cultmesh-browser.test.ts +++ b/packages/cultmesh-browser/test/cultmesh-browser.test.ts @@ -9,6 +9,7 @@ import { type CultNetMessage, type CultNetOperationRequestMessage, type CultNetRawDocumentRecord, + type CultMeshSessionOpenMessage, } from "cultnet-ts/contracts"; import { @@ -48,6 +49,46 @@ test("Odin rendezvous resolves stable authority-runtime identity and observes ro ); }); +test("Odin rendezvous never selects another authority's faster endpoint", async () => { + const odin = new FakeOdin("ws://127.0.0.1:4050/mesh"); + odin.decoyEndpoint = "ws://127.0.0.1:4049/decoy"; + const rendezvous = new CultMeshBrowserOdinRendezvous({ + endpoints: ["ws://127.0.0.1:4040/odin"], + runtimeId: "browser-route-binding-test", + socketFactory: () => odin.open(), + }); + + const route = await rendezvous.resolve({ + verseId: "sample.counter", + authorityRuntimeId: "sample.counter-daemon", + }); + assert.equal(route.endpoint, "ws://127.0.0.1:4050/mesh"); +}); + +test("Odin rendezvous accepts one-authority legacy routes and rejects ambiguous legacy catalogs", async () => { + const odin = new FakeOdin("ws://127.0.0.1:4070/mesh"); + odin.omitAuthorityRoutes = true; + const rendezvous = new CultMeshBrowserOdinRendezvous({ + endpoints: ["ws://127.0.0.1:4040/odin"], + runtimeId: "browser-legacy-route-test", + socketFactory: () => odin.open(), + }); + + const route = await rendezvous.resolve({ + verseId: "sample.counter", + authorityRuntimeId: "sample.counter-daemon", + }); + assert.equal(route.endpoint, "ws://127.0.0.1:4070/mesh"); + + odin.decoyEndpoint = "ws://127.0.0.1:4069/decoy"; + await assert.rejects( + rendezvous.resolve({ verseId: "sample.counter", authorityRuntimeId: "sample.counter-daemon" }), + (error: unknown) => + error instanceof AggregateError && + error.errors.some(inner => inner instanceof Error && /ambiguous legacy routes/.test(inner.message)), + ); +}); + test("browser client leases provider state, invokes an operation, and follows route replacement", async () => { const first = new FakeProvider("ws://127.0.0.1:4101/mesh", 4); const second = new FakeProvider("ws://127.0.0.1:4102/mesh", 9); @@ -117,18 +158,33 @@ test("browser client rejects wrong rendezvous identity and has no document write assert.equal("setDocument" in CultMeshBrowserClient.prototype, false); }); +test("browser client rejects a route whose peer proves the wrong authority", async () => { + const provider = new FakeProvider("ws://127.0.0.1:4251/mesh", 1, false, "intruder-runtime"); + await assert.rejects( + CultMeshBrowserClient.connect({ + verseId: "sample.counter", + authorityRuntimeId: "sample.counter-daemon", + runtimeId: "browser-peer-proof-test", + rendezvous: { resolve: async () => ({ ...provider.route, authorityRuntimeId: "sample.counter-daemon" }) }, + socketFactory: () => provider.open(), + }), + /proved .*intruder-runtime.*expected .*sample.counter-daemon/, + ); +}); + test("browser client bounds unanswered provider operations", async () => { const route = { verseId: "sample.counter", authorityRuntimeId: "sample.counter-daemon", endpoint: "ws://127.0.0.1:4301/mesh", + generation: "route-4301", }; const client = await CultMeshBrowserClient.connect({ ...route, runtimeId: "browser-timeout-test", rendezvous: { resolve: async () => route }, requestTimeoutMs: 5, - socketFactory: () => new FakeSocket(() => undefined, () => undefined), + socketFactory: () => handshakeOnlySocket(route), }); await assert.rejects( client.invoke({ @@ -172,11 +228,39 @@ test("browser client rejects a correlated framework failure without waiting for await client.dispose(); }); +test("browser client rejects an operation response from another runtime", async () => { + const provider = new FakeProvider( + "ws://127.0.0.1:4371/mesh", + 1, + false, + "sample.counter-daemon", + "intruder-runtime", + ); + const client = await CultMeshBrowserClient.connect({ + ...provider.route, + runtimeId: "browser-response-authority-test", + rendezvous: { resolve: async () => provider.route }, + socketFactory: () => provider.open(), + }); + + await assert.rejects( + client.invoke({ + serviceId: "sample.counter", + operation: "increment", + payloadSchema: "sample.increment.v1", + payload: { amount: 1 }, + }), + /response came from 'intruder-runtime'/, + ); + await client.dispose(); +}); + test("browser client rejects oversized outbound schema messages", async () => { const route = { verseId: "sample.counter", authorityRuntimeId: "sample.counter-daemon", endpoint: "ws://127.0.0.1:4401/mesh", + generation: "route-4401", }; await assert.rejects( CultMeshBrowserClient.connect({ @@ -220,8 +304,16 @@ class FakeProvider { #count: number; #subscriptions = new Map>(); #rejectOperations: boolean; + #runtimeId: string; + #responseRuntimeId: string; - constructor(endpoint: string, count: number, rejectOperations = false) { + constructor( + endpoint: string, + count: number, + rejectOperations = false, + runtimeId = "sample.counter-daemon", + responseRuntimeId = runtimeId, + ) { this.route = { verseId: "sample.counter", authorityRuntimeId: "sample.counter-daemon", @@ -230,6 +322,8 @@ class FakeProvider { }; this.#count = count; this.#rejectOperations = rejectOperations; + this.#runtimeId = runtimeId; + this.#responseRuntimeId = responseRuntimeId; } get activeSubscriptionCount(): number { @@ -250,6 +344,9 @@ class FakeProvider { private receive(socket: FakeSocket, wire: Uint8Array): void { const message = parseCultNetMessage(decode(wire)); switch (message.schemaVersion) { + case "cultmesh.session_open.v1": + this.acceptSession(socket, message); + return; case "cultnet.database_subscribe.v0": this.subscribe(socket, message); return; @@ -264,6 +361,18 @@ class FakeProvider { } } + private acceptSession(socket: FakeSocket, message: CultMeshSessionOpenMessage): void { + socket.deliver({ + schemaVersion: "cultmesh.session_accepted.v1", + messageId: message.messageId, + accepted: true, + verseId: message.verseId, + authorityRuntimeId: this.#runtimeId, + protocolId: message.protocolId, + routeGeneration: message.routeGeneration, + }); + } + private subscribe(socket: FakeSocket, message: CultNetDatabaseSubscribeMessage): void { this.#subscriptions.get(socket)!.set(message.subscriptionId, message); socket.deliver({ @@ -274,6 +383,7 @@ class FakeProvider { } private invoke(socket: FakeSocket, message: CultNetOperationRequestMessage): void { + assert.equal(message.targetRuntimeId, this.#runtimeId); if (this.#rejectOperations) { socket.deliver({ schemaVersion: "cultnet.operation_response.v0", @@ -288,7 +398,7 @@ class FakeProvider { message: "Expected payload schema 'sample.increment.v1'.", })), diagnostics: ["Request schema did not match."], - sourceRuntimeId: "sample.counter-daemon", + sourceRuntimeId: this.#responseRuntimeId, }); return; } @@ -314,7 +424,7 @@ class FakeProvider { payloadSchema: "sample.increment_receipt.v1", payloadEncoding: "messagepack-base64", payload: bytesToBase64(encode({ count: this.#count })), - sourceRuntimeId: "sample.counter-daemon", + sourceRuntimeId: this.#responseRuntimeId, }); } @@ -328,13 +438,15 @@ class FakeProvider { storedAt: "2026-08-17T00:00:00Z", payloadEncoding: "messagepack", payload: encode({ count: this.#count }), - sourceRuntimeId: "sample.counter-daemon", + sourceRuntimeId: this.#runtimeId, }; } } class FakeOdin { providerEndpoint: string; + decoyEndpoint: string | undefined; + omitAuthorityRoutes = false; constructor(providerEndpoint: string) { this.providerEndpoint = providerEndpoint; @@ -359,7 +471,25 @@ class FakeOdin { optionalPluginIds: [], }, discoveryEndpoints: [this.providerEndpoint], - authorityRuntimeIds: ["sample.counter-daemon"], + authorityRuntimeIds: this.decoyEndpoint + ? ["sample.counter-daemon", "sample.decoy-daemon"] + : ["sample.counter-daemon"], + ...(!this.omitAuthorityRoutes ? { authorityRoutes: [ + ...(this.decoyEndpoint ? [{ + authorityRuntimeId: "sample.decoy-daemon", + endpoint: this.decoyEndpoint, + protocolIds: ["cultmesh.documents.v1"], + priority: 0, + generation: "decoy-generation", + }] : []), + { + authorityRuntimeId: "sample.counter-daemon", + endpoint: this.providerEndpoint, + protocolIds: ["cultmesh.documents.v1"], + priority: 10, + generation: this.providerEndpoint, + }, + ] } : {}), }], }); }, () => undefined); @@ -367,6 +497,24 @@ class FakeOdin { } } +function handshakeOnlySocket(route: CultMeshBrowserRoute): FakeSocket { + let socket: FakeSocket; + socket = new FakeSocket(wire => { + const message = parseCultNetMessage(decode(wire)); + if (message.schemaVersion !== "cultmesh.session_open.v1") return; + socket.deliver({ + schemaVersion: "cultmesh.session_accepted.v1", + messageId: message.messageId, + accepted: true, + verseId: route.verseId, + authorityRuntimeId: route.authorityRuntimeId, + protocolId: message.protocolId, + routeGeneration: message.routeGeneration, + }); + }, () => undefined); + return socket; +} + class FakeSocket implements CultMeshBrowserSocket { binaryType: BinaryType = "arraybuffer"; readyState = 0; diff --git a/packages/cultnet-ts/contracts/cultmesh.session-accepted.schema.json b/packages/cultnet-ts/contracts/cultmesh.session-accepted.schema.json new file mode 100644 index 00000000..55a2f742 --- /dev/null +++ b/packages/cultnet-ts/contracts/cultmesh.session-accepted.schema.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/GameCult/cultnet-ts/contracts/cultmesh.session-accepted.schema.json", + "title": "CultMesh Session Accepted", + "type": "object", + "required": ["schemaVersion", "messageId", "accepted", "verseId", "authorityRuntimeId", "protocolId", "routeGeneration"], + "additionalProperties": false, + "properties": { + "schemaVersion": { "const": "cultmesh.session_accepted.v1" }, + "messageId": { "type": "string", "minLength": 1 }, + "accepted": { "type": "boolean" }, + "verseId": { "type": "string", "minLength": 1 }, + "authorityRuntimeId": { "type": "string", "minLength": 1 }, + "protocolId": { "type": "string", "minLength": 1 }, + "routeGeneration": { "type": "string" }, + "error": { "type": "string", "minLength": 1 } + } +} diff --git a/packages/cultnet-ts/contracts/cultmesh.session-open.schema.json b/packages/cultnet-ts/contracts/cultmesh.session-open.schema.json new file mode 100644 index 00000000..14d945ed --- /dev/null +++ b/packages/cultnet-ts/contracts/cultmesh.session-open.schema.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/GameCult/cultnet-ts/contracts/cultmesh.session-open.schema.json", + "title": "CultMesh Session Open", + "type": "object", + "required": ["schemaVersion", "messageId", "sourceRuntimeId", "verseId", "authorityRuntimeId", "protocolId", "routeGeneration"], + "additionalProperties": false, + "properties": { + "schemaVersion": { "const": "cultmesh.session_open.v1" }, + "messageId": { "type": "string", "minLength": 1 }, + "sourceRuntimeId": { "type": "string", "minLength": 1 }, + "verseId": { "type": "string", "minLength": 1 }, + "authorityRuntimeId": { "type": "string", "minLength": 1 }, + "protocolId": { "type": "string", "minLength": 1 }, + "routeGeneration": { "type": "string" } + } +} diff --git a/packages/cultnet-ts/contracts/cultmesh.verse-catalog-response.schema.json b/packages/cultnet-ts/contracts/cultmesh.verse-catalog-response.schema.json index 21367d09..6e7551d5 100644 --- a/packages/cultnet-ts/contracts/cultmesh.verse-catalog-response.schema.json +++ b/packages/cultnet-ts/contracts/cultmesh.verse-catalog-response.schema.json @@ -18,6 +18,18 @@ "optionalPluginIds": { "type": "array", "items": { "type": "string", "minLength": 1 }, "uniqueItems": true } } }, + "authorityRoute": { + "type": "object", + "required": ["authorityRuntimeId", "endpoint", "protocolIds", "priority", "generation"], + "additionalProperties": false, + "properties": { + "authorityRuntimeId": { "type": "string", "minLength": 1 }, + "endpoint": { "type": "string", "minLength": 1 }, + "protocolIds": { "type": "array", "items": { "type": "string", "minLength": 1 }, "uniqueItems": true }, + "priority": { "type": "integer", "minimum": 0 }, + "generation": { "type": "string", "minLength": 1 } + } + }, "verse": { "type": "object", "required": ["verseId", "displayName", "authorityModel", "compatibility", "discoveryEndpoints", "authorityRuntimeIds"], @@ -29,6 +41,7 @@ "compatibility": { "$ref": "#/$defs/compatibility" }, "discoveryEndpoints": { "type": "array", "items": { "type": "string", "minLength": 1 }, "uniqueItems": true }, "authorityRuntimeIds": { "type": "array", "items": { "type": "string", "minLength": 1 }, "uniqueItems": true }, + "authorityRoutes": { "type": "array", "items": { "$ref": "#/$defs/authorityRoute" } }, "parentVerseId": { "type": "string", "minLength": 1 }, "description": { "type": "string" } } diff --git a/packages/cultnet-ts/package.json b/packages/cultnet-ts/package.json index 6ff29340..df129a42 100644 --- a/packages/cultnet-ts/package.json +++ b/packages/cultnet-ts/package.json @@ -1,6 +1,6 @@ { "name": "cultnet-ts", - "version": "0.1.1", + "version": "0.2.0", "description": "CultNet-style typed direct-pipe messaging and state replication for TypeScript runtimes.", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/cultnet-ts/src/contracts.ts b/packages/cultnet-ts/src/contracts.ts index 1c3998ae..2d86ad27 100644 --- a/packages/cultnet-ts/src/contracts.ts +++ b/packages/cultnet-ts/src/contracts.ts @@ -30,6 +30,8 @@ import operationRequestSchema from "../contracts/cultnet.operation-request.schem import operationResponseSchema from "../contracts/cultnet.operation-response.schema.json"; import verseCatalogRequestSchema from "../contracts/cultmesh.verse-catalog-request.schema.json"; import verseCatalogResponseSchema from "../contracts/cultmesh.verse-catalog-response.schema.json"; +import sessionOpenSchema from "../contracts/cultmesh.session-open.schema.json"; +import sessionAcceptedSchema from "../contracts/cultmesh.session-accepted.schema.json"; import ghostlightAgentStateSchema from "../contracts/ghostlight.agent-state.schema.json"; export type CultNetWireContract = "cultnet.schema.v0" | "gamecult.networking.v0"; @@ -59,7 +61,9 @@ export type CultNetSchemaVersion = | "cultnet.operation_request.v0" | "cultnet.operation_response.v0" | "cultmesh.verse_catalog_request.v0" - | "cultmesh.verse_catalog_response.v0"; + | "cultmesh.verse_catalog_response.v0" + | "cultmesh.session_open.v1" + | "cultmesh.session_accepted.v1"; export type CultNetSchemaKind = "wire_message" | "document_payload" | "shared_contract"; export type CultNetRawPayloadEncoding = "messagepack"; @@ -350,10 +354,40 @@ export interface CultMeshVerseDescriptorMessage { compatibility: CultMeshVerseCompatibilityMessage; discoveryEndpoints: string[]; authorityRuntimeIds: string[]; + authorityRoutes?: CultMeshAuthorityRouteMessage[]; parentVerseId?: string; description?: string; } +export interface CultMeshAuthorityRouteMessage { + authorityRuntimeId: string; + endpoint: string; + protocolIds: string[]; + priority: number; + generation: string; +} + +export interface CultMeshSessionOpenMessage { + schemaVersion: "cultmesh.session_open.v1"; + messageId: string; + sourceRuntimeId: string; + verseId: string; + authorityRuntimeId: string; + protocolId: string; + routeGeneration: string; +} + +export interface CultMeshSessionAcceptedMessage { + schemaVersion: "cultmesh.session_accepted.v1"; + messageId: string; + accepted: boolean; + verseId: string; + authorityRuntimeId: string; + protocolId: string; + routeGeneration: string; + error?: string; +} + export interface CultMeshVerseCatalogRequestMessage { schemaVersion: "cultmesh.verse_catalog_request.v0"; messageId: string; @@ -618,7 +652,9 @@ export type CultNetMessage = | CultNetOperationRequestMessage | CultNetOperationResponseMessage | CultMeshVerseCatalogRequestMessage - | CultMeshVerseCatalogResponseMessage; + | CultMeshVerseCatalogResponseMessage + | CultMeshSessionOpenMessage + | CultMeshSessionAcceptedMessage; const ajv = new Ajv2020({ allErrors: true, @@ -651,6 +687,8 @@ const CULTNET_MESSAGE_SCHEMAS = [ operationResponseSchema, verseCatalogRequestSchema, verseCatalogResponseSchema, + sessionOpenSchema, + sessionAcceptedSchema, ] as const; const cultNetValidators = new Map(); @@ -1198,6 +1236,9 @@ function normalizeCultNetOptionalNulls( } } return; + case "cultmesh.session_accepted.v1": + stripNullProperties(candidate, ["error"]); + return; case "cultnet.schema_catalog_request.v0": stripNullProperties(candidate, ["schemaIds", "kinds"]); return; diff --git a/packages/cultnet-ts/test/cultnet.test.ts b/packages/cultnet-ts/test/cultnet.test.ts index 945e0a3b..f0f01b29 100644 --- a/packages/cultnet-ts/test/cultnet.test.ts +++ b/packages/cultnet-ts/test/cultnet.test.ts @@ -83,10 +83,29 @@ test("CultNet validates the canonical CultMesh Verse catalog messages", () => { }, discoveryEndpoints: ["wss://provider.example/cultmesh"], authorityRuntimeIds: ["sample.counter-provider"], + authorityRoutes: [{ + authorityRuntimeId: "sample.counter-provider", + endpoint: "wss://provider.example/cultmesh", + protocolIds: ["cultmesh.documents.v1"], + priority: 0, + generation: "provider-route-1", + }], }], }); assert.equal(response.schemaVersion, "cultmesh.verse_catalog_response.v0"); assert.equal(response.verses[0].authorityRuntimeIds[0], "sample.counter-provider"); + assert.equal(response.verses[0].authorityRoutes![0].generation, "provider-route-1"); + + const session = parseCultNetMessage({ + schemaVersion: "cultmesh.session_accepted.v1", + messageId: "session-1", + accepted: true, + verseId: "sample.counter", + authorityRuntimeId: "sample.counter-provider", + protocolId: "cultmesh.documents.v1", + routeGeneration: "provider-route-1", + }); + assert.equal(session.schemaVersion, "cultmesh.session_accepted.v1"); assert.throws(() => parseCultNetMessage({ ...response, diff --git a/samples/eve-browser-network/Program.cs b/samples/eve-browser-network/Program.cs index 4b60a18e..db92d3c1 100644 --- a/samples/eve-browser-network/Program.cs +++ b/samples/eve-browser-network/Program.cs @@ -37,13 +37,30 @@ static async Task RunOdinAsync(Args arguments) if (string.IsNullOrWhiteSpace(arguments.ProviderEndpoint)) throw new ArgumentException("The Odin fixture requires --provider-endpoint."); using var catalog = new CultMeshVerseCatalog(); + var routes = new List + { + new( + arguments.AuthorityRuntimeId, + arguments.ProviderEndpoint, + [CultMeshProtocols.Documents.Value], + priority: 10, + generation: arguments.RouteGeneration) + }; + if (!string.IsNullOrWhiteSpace(arguments.DecoyEndpoint)) + { + routes.Add(new CultMeshAuthorityRoute( + arguments.DecoyAuthorityRuntimeId, + arguments.DecoyEndpoint, + [CultMeshProtocols.Documents.Value], + priority: 0, + generation: arguments.DecoyRouteGeneration)); + } catalog.Upsert(new CultMeshVerseDescriptor( arguments.VerseId, arguments.VerseName, CultMeshVerseAuthorityModel.OperatorCluster, new CultMeshVerseCompatibility(arguments.TransportVersion, arguments.RulesHash), - discoveryEndpoints: [arguments.ProviderEndpoint], - authorityRuntimeIds: [arguments.AuthorityRuntimeId], + authorityRoutes: routes, description: "Local executable Odin fixture for the browser/network onboarding witness.")); await using var schemaServer = new CultNetWebSocketSchemaServer(); @@ -97,6 +114,12 @@ static async Task RunProviderAsync(Args arguments) await node.FlushAsync(); await using var schemaServer = new CultNetWebSocketSchemaServer(); + using var identity = new CultMeshSessionIdentityServer( + schemaServer, + arguments.AuthorityRuntimeId, + [arguments.VerseId], + [CultMeshProtocols.Documents.Value], + [arguments.RouteGeneration]); using var subscriptions = new CultNetDatabaseSubscriptionServer(schemaServer, node.Database); using var operationGate = new SemaphoreSlim(1, 1); using var operations = new CultNetOperationServer(schemaServer, arguments.AuthorityRuntimeId) @@ -347,12 +370,16 @@ sealed class Args public string StatePath { get; private init; } = "sample-counter.cc"; public string OdinEndpoint { get; private init; } = ""; public string ProviderEndpoint { get; private init; } = ""; + public string DecoyEndpoint { get; private init; } = ""; public string Token { get; private init; } = "sample-session"; public string VerseId { get; private init; } = "sample.counter"; public string VerseName { get; private init; } = "CultMesh browser counter"; public string AuthorityRuntimeId { get; private init; } = "sample.counter-daemon"; + public string DecoyAuthorityRuntimeId { get; private init; } = "sample.decoy-daemon"; public string TransportVersion { get; private init; } = "cultmesh.v0"; public string RulesHash { get; private init; } = "sample-counter-v1"; + public string RouteGeneration { get; private init; } = "sample-counter-route-1"; + public string DecoyRouteGeneration { get; private init; } = "sample-decoy-route-1"; public int ExpectedCount { get; private init; } = 2; public int BenchmarkOperations { get; private init; } = 10_000; @@ -369,12 +396,16 @@ sealed class Args StatePath = named.GetValueOrDefault("--state", "sample-counter.cc"), OdinEndpoint = named.GetValueOrDefault("--odin", ""), ProviderEndpoint = named.GetValueOrDefault("--provider-endpoint", ""), + DecoyEndpoint = named.GetValueOrDefault("--decoy-endpoint", ""), Token = named.GetValueOrDefault("--token", "sample-session"), VerseId = named.GetValueOrDefault("--verse-id", "sample.counter"), VerseName = named.GetValueOrDefault("--verse-name", "CultMesh browser counter"), AuthorityRuntimeId = named.GetValueOrDefault("--authority-runtime-id", "sample.counter-daemon"), + DecoyAuthorityRuntimeId = named.GetValueOrDefault("--decoy-authority-runtime-id", "sample.decoy-daemon"), TransportVersion = named.GetValueOrDefault("--transport-version", "cultmesh.v0"), RulesHash = named.GetValueOrDefault("--rules-hash", "sample-counter-v1"), + RouteGeneration = named.GetValueOrDefault("--route-generation", "sample-counter-route-1"), + DecoyRouteGeneration = named.GetValueOrDefault("--decoy-route-generation", "sample-decoy-route-1"), ExpectedCount = named.TryGetValue("--expected-count", out var expectedCount) ? int.Parse(expectedCount) : 2, diff --git a/samples/eve-browser-network/README.md b/samples/eve-browser-network/README.md index 7ad20a00..445bfb9d 100644 --- a/samples/eve-browser-network/README.md +++ b/samples/eve-browser-network/README.md @@ -12,6 +12,9 @@ This is the real-process continuation of `samples/eve-two-runtime`: without application transport or reconnect code; - one separate local Odin fixture answers the canonical CultMesh Verse catalog over binary CultNet WebSocket messages; +- one wrong-authority provider is deliberately advertised on a better-priority + route, and both clients must ignore it because the route is bound to another + runtime; - the browser and C# clients speak the same binary CultNet schema-v0 WebSocket messages through the authenticated host adapter. diff --git a/samples/eve-browser-network/browser/main.ts b/samples/eve-browser-network/browser/main.ts index 3947516b..3b0e28f9 100644 --- a/samples/eve-browser-network/browser/main.ts +++ b/samples/eve-browser-network/browser/main.ts @@ -86,7 +86,11 @@ try { window.__sampleCount = decodeCultNetPayload<{ count: number }>(counter.current!).count; window.__sampleReady = true; } catch (error) { - window.__sampleError = error instanceof Error ? error.stack || error.message : String(error); + const details = error instanceof AggregateError + ? error.errors.map(inner => inner instanceof Error ? inner.stack || inner.message : String(inner)).join("\n---\n") + : ""; + window.__sampleError = (error instanceof Error ? error.stack || error.message : String(error)) + + (details ? `\n${details}` : ""); host.textContent = window.__sampleError; throw error; } diff --git a/scripts/verify-eve-browser-network.mjs b/scripts/verify-eve-browser-network.mjs index 3f633dc9..20d819a0 100644 --- a/scripts/verify-eve-browser-network.mjs +++ b/scripts/verify-eve-browser-network.mjs @@ -17,9 +17,11 @@ const eveRoot = resolve(eveFlag >= 0 ? process.argv[eveFlag + 1] : join(repoRoot const sampleRoot = join(repoRoot, "samples", "eve-browser-network"); const workRoot = await mkdtemp(join(tmpdir(), "cultmesh-browser-network-")); const statePath = join(workRoot, "counter.cc"); +const decoyStatePath = join(workRoot, "decoy-counter.cc"); const bundlePath = join(workRoot, "bundle.js"); const token = "sample-session"; let provider; +let decoyProvider; let replacementProvider; let odin; let headless; @@ -41,6 +43,8 @@ try { alias: { "@gamecult/eve-contracts": join(eveRoot, "packages", "eve-contracts", "src", "index.ts"), "@gamecult/eve-browser-lowering": join(eveRoot, "packages", "eve-browser-lowering", "src", "index.ts"), + "cultmesh-browser": join(repoRoot, "packages", "cultmesh-browser", "src", "index.ts"), + "cultnet-ts/contracts": join(repoRoot, "packages", "cultnet-ts", "src", "contracts.ts"), }, logLevel: "warning", }); @@ -54,14 +58,22 @@ try { "--verbosity", "quiet", "-p:NoWarn=1591%3BCS8632", `-p:EveRoot=${eveRoot}`, + `-p:CultLibRoot=${repoRoot}`, ]); const providerPort = await freePort(); + const decoyProviderPort = await freePort(); const replacementProviderPort = await freePort(); const odinPort = await freePort(); const httpPort = await freePort(); provider = await startProvider(providerPort); const endpoint = await provider.waitFor("PROVIDER_READY "); - odin = await startOdin(odinPort, endpoint); + decoyProvider = await startProvider(decoyProviderPort, { + authorityRuntimeId: "sample.decoy-daemon", + routeGeneration: "sample-decoy-route-1", + statePath: decoyStatePath, + }); + const decoyEndpoint = await decoyProvider.waitFor("PROVIDER_READY "); + odin = await startOdin(odinPort, endpoint, decoyEndpoint); const odinEndpoint = await odin.waitFor("ODIN_READY "); headless = startDotnet([ "headless", "--odin", odinEndpoint, "--verse-id", "sample.counter", @@ -91,7 +103,7 @@ try { const restartedEndpoint = await replacementProvider.waitFor("PROVIDER_READY "); assert.notEqual(restartedEndpoint, endpoint); await stop(odin.process); - odin = await startOdin(odinPort, restartedEndpoint); + odin = await startOdin(odinPort, restartedEndpoint, decoyEndpoint); assert.equal(await odin.waitFor("ODIN_READY "), odinEndpoint); await stop(provider.process); provider = replacementProvider; @@ -122,6 +134,7 @@ try { console.log(JSON.stringify({ providerEndpoint: endpoint, replacementProviderEndpoint: restartedEndpoint, + rejectedWrongAuthorityEndpoint: decoyEndpoint, odinEndpoint, browserRuntime: "chromium", headlessRuntime: "csharp", @@ -136,21 +149,31 @@ try { if (browser) await browser.close().catch(() => undefined); if (headless) await stop(headless.process); if (provider) await stop(provider.process); + if (decoyProvider) await stop(decoyProvider.process); if (replacementProvider) await stop(replacementProvider.process); if (odin) await stop(odin.process); if (httpServer) await new Promise(resolve => httpServer.close(resolve)); await rm(workRoot, { recursive: true, force: true }); } -async function startProvider(port) { - return startDotnet(["provider", "--port", String(port), "--state", statePath, "--token", token]); +async function startProvider(port, options = {}) { + return startDotnet([ + "provider", "--port", String(port), + "--state", options.statePath ?? statePath, + "--authority-runtime-id", options.authorityRuntimeId ?? "sample.counter-daemon", + "--route-generation", options.routeGeneration ?? "sample-counter-route-1", + "--token", token, + ]); } -async function startOdin(port, providerEndpoint) { +async function startOdin(port, providerEndpoint, decoyEndpoint) { return startDotnet([ "odin", "--port", String(port), "--provider-endpoint", providerEndpoint, + "--decoy-endpoint", decoyEndpoint, + "--decoy-authority-runtime-id", "sample.decoy-daemon", + "--decoy-route-generation", "sample-decoy-route-1", "--token", token, ]); } diff --git a/src/GameCult.Mesh.Quic.Native/CultMeshNativeQuicRealtimeTransport.cs b/src/GameCult.Mesh.Quic.Native/CultMeshNativeQuicRealtimeTransport.cs index d687d5b6..cb356044 100644 --- a/src/GameCult.Mesh.Quic.Native/CultMeshNativeQuicRealtimeTransport.cs +++ b/src/GameCult.Mesh.Quic.Native/CultMeshNativeQuicRealtimeTransport.cs @@ -42,11 +42,11 @@ namespace GameCult.Mesh.Quic.Native public async Task ConnectAsync( CultMeshTransportCandidate candidate, - CultMeshEndpointId endpointId, + CultMeshSessionTarget target, CancellationToken cancellationToken = default) { if (candidate == null) throw new ArgumentNullException(nameof(candidate)); - if (endpointId == null) throw new ArgumentNullException(nameof(endpointId)); + if (target == null) throw new ArgumentNullException(nameof(target)); if (!TryParseEndpoint(candidate.Endpoint, out var host, out var port, out var pin)) throw new NotSupportedException($"Native QUIC connector does not support '{candidate.Endpoint}'."); @@ -72,7 +72,9 @@ namespace GameCult.Mesh.Quic.Native var transport = new CultMeshNativeQuicRealtimeTransport( candidate.Endpoint, handle, - _options.PollInterval); + _options.PollInterval, + target, + candidate.Generation); try { await transport.WaitUntilConnectedAsync(_options.HandshakeTimeout, cancellationToken).ConfigureAwait(false); @@ -122,23 +124,42 @@ namespace GameCult.Mesh.Quic.Native } } - internal sealed class CultMeshNativeQuicRealtimeTransport : ICultMeshRealtimeTransport + internal sealed class CultMeshNativeQuicRealtimeTransport : ICultMeshRealtimeTransport, ICultMeshVerifiedTransport { private readonly object _gate = new object(); private readonly TimeSpan _pollInterval; private IntPtr _handle; + private readonly CultMeshSessionTarget _target; + private readonly string _routeGeneration; private bool _disposed; - public CultMeshNativeQuicRealtimeTransport(string endpoint, IntPtr handle, TimeSpan pollInterval) + public CultMeshNativeQuicRealtimeTransport( + string endpoint, + IntPtr handle, + TimeSpan pollInterval, + CultMeshSessionTarget target, + string routeGeneration) { Endpoint = endpoint; _handle = handle; _pollInterval = pollInterval; + _target = target; + _routeGeneration = routeGeneration ?? string.Empty; } public string TransportId => "msquic-native-realtime"; public string Endpoint { get; } + public bool IsVerifiedFor( + string verseId, + string authorityRuntimeId, + string protocolId, + string routeGeneration) => + string.Equals(_target.VerseId, verseId, StringComparison.Ordinal) && + string.Equals(_target.AuthorityRuntimeId, authorityRuntimeId, StringComparison.Ordinal) && + string.Equals(CultMeshProtocols.RealtimeState.Value, protocolId, StringComparison.Ordinal) && + string.Equals(_routeGeneration, routeGeneration, StringComparison.Ordinal); + public Task SendAsync(CultMeshRealtimeFrame frame, CancellationToken cancellationToken = default) => Task.FromException(new NotSupportedException( "The Unity-compatible native QUIC connector currently owns provider-to-client state only.")); diff --git a/src/GameCult.Mesh.Quic/CultMeshQuicRealtimeTransport.cs b/src/GameCult.Mesh.Quic/CultMeshQuicRealtimeTransport.cs index a0198a32..91af6d7c 100644 --- a/src/GameCult.Mesh.Quic/CultMeshQuicRealtimeTransport.cs +++ b/src/GameCult.Mesh.Quic/CultMeshQuicRealtimeTransport.cs @@ -22,7 +22,7 @@ public sealed class CultMeshQuicRealtimeConnectorOptions ///

    /// Optional provider-aware certificate validator. Standard TLS validation is used when omitted. /// - public Func? + public Func? ValidateProviderCertificate { get; set; } } @@ -55,11 +55,11 @@ public sealed class CultMeshQuicRealtimeTransportConnector : ICultMeshRealtimeTr /// public async Task ConnectAsync( CultMeshTransportCandidate candidate, - CultMeshEndpointId endpointId, + CultMeshSessionTarget target, CancellationToken cancellationToken = default) { if (candidate == null) throw new ArgumentNullException(nameof(candidate)); - if (endpointId == null) throw new ArgumentNullException(nameof(endpointId)); + if (target == null) throw new ArgumentNullException(nameof(target)); if (!QuicConnection.IsSupported) throw new PlatformNotSupportedException("QUIC is unavailable. Install a supported MsQuic runtime."); if (!TryParseEndpoint(candidate.Endpoint, out var host, out var port)) @@ -84,14 +84,15 @@ public sealed class CultMeshQuicRealtimeTransportConnector : ICultMeshRealtimeTr { var providerCertificate = certificate as X509Certificate2 ?? (certificate == null ? null : new X509Certificate2(certificate)); - return validator?.Invoke(endpointId, providerCertificate, chain, errors) ?? + return validator?.Invoke(CultMeshRuntimeId.Parse(target.AuthorityRuntimeId), providerCertificate, chain, errors) ?? errors == SslPolicyErrors.None || MatchesAdvertisedCertificatePin(candidate.Endpoint, providerCertificate); } } }, cancellationToken).ConfigureAwait(false); - return new CultMeshQuicRealtimeTransport(candidate.Endpoint, connection); + return new CultMeshQuicRealtimeTransport( + candidate.Endpoint, connection, target: target, routeGeneration: candidate.Generation); } private static bool TryParseEndpoint(string? endpoint, out string host, out int port) @@ -308,7 +309,7 @@ public sealed class CultMeshQuicRealtimeServer : IAsyncDisposable } } -internal sealed class CultMeshQuicRealtimeTransport : ICultMeshRealtimeTransport +internal sealed class CultMeshQuicRealtimeTransport : ICultMeshRealtimeTransport, ICultMeshVerifiedTransport { private readonly QuicConnection _connection; private readonly CancellationTokenSource _shutdown = new(); @@ -318,6 +319,8 @@ internal sealed class CultMeshQuicRealtimeTransport : ICultMeshRealtimeTransport private readonly SemaphoreSlim _reliableSendGate = new(1, 1); private readonly CultMeshRealtimeInbox _outbound = new(); private readonly Action? _observer; + private readonly CultMeshSessionTarget? _target; + private readonly string _routeGeneration; private readonly Task _acceptLoop; private readonly Task _outboundLoop; private readonly Task _completion; @@ -328,11 +331,15 @@ internal sealed class CultMeshQuicRealtimeTransport : ICultMeshRealtimeTransport public CultMeshQuicRealtimeTransport( string endpoint, QuicConnection connection, - Action? observer = null) + Action? observer = null, + CultMeshSessionTarget? target = null, + string routeGeneration = "") { Endpoint = endpoint; _connection = connection; _observer = observer; + _target = target; + _routeGeneration = routeGeneration ?? string.Empty; _acceptLoop = AcceptStreamsAsync(_shutdown.Token); _outboundLoop = SendPublishedFramesAsync(_shutdown.Token); _completion = Task.WhenAll(_acceptLoop, _outboundLoop); @@ -342,6 +349,17 @@ internal sealed class CultMeshQuicRealtimeTransport : ICultMeshRealtimeTransport public string Endpoint { get; } public Task Completion => _completion; + public bool IsVerifiedFor( + string verseId, + string authorityRuntimeId, + string protocolId, + string routeGeneration) => + _target != null && + string.Equals(_target.VerseId, verseId, StringComparison.Ordinal) && + string.Equals(_target.AuthorityRuntimeId, authorityRuntimeId, StringComparison.Ordinal) && + string.Equals(CultMeshProtocols.RealtimeState.Value, protocolId, StringComparison.Ordinal) && + string.Equals(_routeGeneration, routeGeneration, StringComparison.Ordinal); + internal bool TryPublishLatest(CultMeshRealtimeFrame frame) { if (_disposed || frame.Delivery != CultMeshRealtimeDelivery.LatestOnly) return false; diff --git a/src/GameCult.Mesh/CultMeshClient.cs b/src/GameCult.Mesh/CultMeshClient.cs index b4667f9c..19a01c54 100644 --- a/src/GameCult.Mesh/CultMeshClient.cs +++ b/src/GameCult.Mesh/CultMeshClient.cs @@ -391,7 +391,8 @@ namespace GameCult.Mesh PayloadSchema = requestSchema.Trim(), PayloadEncoding = "messagepack-base64", Payload = Convert.ToBase64String(MessagePackSerializer.Serialize(request, CultNetSchemaMessageSerialization.Options)), - SourceRuntimeId = sourceRuntimeId.Trim() + SourceRuntimeId = sourceRuntimeId.Trim(), + TargetRuntimeId = target.AuthorityRuntimeId }; using var timeout = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); timeout.CancelAfter(_operationResponseTimeout); @@ -441,6 +442,11 @@ namespace GameCult.Mesh if (!string.Equals(envelope.ServiceId, expectedService, StringComparison.Ordinal) || !string.Equals(envelope.Operation, expectedOperation, StringComparison.Ordinal)) throw new InvalidOperationException("CultMesh operation response did not match the requested service and operation."); + if (!string.Equals(envelope.SourceRuntimeId, target.AuthorityRuntimeId, StringComparison.Ordinal)) + throw new CultMeshSessionException(new CultMeshSessionFailure( + CultMeshSessionFailureReason.Authority, + $"CultMesh operation response came from runtime '{envelope.SourceRuntimeId ?? "(missing)"}', " + + $"not selected authority '{target.AuthorityRuntimeId}'.")); if (string.Equals(envelope.PayloadSchema, CultNetOperationServer.FailureSchemaId, StringComparison.Ordinal)) { if (!string.Equals(envelope.PayloadEncoding, "messagepack-base64", StringComparison.Ordinal)) @@ -795,7 +801,7 @@ namespace GameCult.Mesh _cache, new CultRecordKey(recordKey), CultMesh.Verse(target.VerseId, "cultmesh-client").Context, - routeHint: new CultMeshRouteHint(CultMeshLocalityKind.Network, target.ProviderRuntimeId)); + routeHint: new CultMeshRouteHint(CultMeshLocalityKind.Network, target.AuthorityRuntimeId)); } public CultMeshDocumentHandle Handle { get; } @@ -897,7 +903,7 @@ namespace GameCult.Mesh _subscription = new CultNetDatabaseSubscriptionClient(session.OpenSchemaClient(), _cache, networkRegistry); Handle = CultMesh.Collection( _cache, - routeHint: new CultMeshRouteHint(CultMeshLocalityKind.Network, target.ProviderRuntimeId)); + routeHint: new CultMeshRouteHint(CultMeshLocalityKind.Network, target.AuthorityRuntimeId)); } public CultMeshCollectionHandle Handle { get; } diff --git a/src/GameCult.Mesh/CultMeshContentSessions.cs b/src/GameCult.Mesh/CultMeshContentSessions.cs index 51570c54..4c562450 100644 --- a/src/GameCult.Mesh/CultMeshContentSessions.cs +++ b/src/GameCult.Mesh/CultMeshContentSessions.cs @@ -122,31 +122,56 @@ namespace GameCult.Mesh public async Task ConnectAsync( CultMeshTransportCandidate candidate, - CultMeshEndpointId endpointId, + CultMeshSessionTarget target, CancellationToken cancellationToken = default) { if (!CanConnect(candidate)) throw new NotSupportedException($"Legacy RUDP content connector does not support '{candidate.Endpoint}'."); var client = await _schemaConnector.ConnectAsync(candidate, CultMeshProtocols.Content, cancellationToken) .ConfigureAwait(false); - return new LegacyRudpContentTransport(candidate.Endpoint, client, _options); + try + { + await CultMeshSessionIdentityClient.VerifyAsync( + client, + "cultmesh-content-client", + target, + CultMeshProtocols.Content, + candidate.Generation, + _options.ResponseTimeout, + cancellationToken).ConfigureAwait(false); + return new LegacyRudpContentTransport( + candidate.Endpoint, client, _options, target, candidate.Generation); + } + catch + { + client.Dispose(); + throw; + } } - private sealed class LegacyRudpContentTransport : ICultMeshContentTransport + private sealed class LegacyRudpContentTransport : ICultMeshContentTransport, ICultMeshVerifiedTransport { private readonly ICultNetSchemaClient _client; private readonly CultMeshLegacyRudpContentTransportOptions _options; + private readonly string _verseId; + private readonly string _authorityRuntimeId; + private readonly string _routeGeneration; private readonly System.Collections.Concurrent.ConcurrentDictionary> _pending = new(StringComparer.Ordinal); private bool _disposed; public LegacyRudpContentTransport( string endpoint, ICultNetSchemaClient client, - CultMeshLegacyRudpContentTransportOptions options) + CultMeshLegacyRudpContentTransportOptions options, + CultMeshSessionTarget target, + string routeGeneration) { Endpoint = endpoint; _client = client; _options = options; + _verseId = target.VerseId; + _authorityRuntimeId = target.AuthorityRuntimeId; + _routeGeneration = routeGeneration ?? string.Empty; _client.OnCultNet(OnResponse); _client.OnCultNet(OnError); } @@ -154,6 +179,16 @@ namespace GameCult.Mesh public string TransportId => "legacy-rudp-content"; public string Endpoint { get; } + public bool IsVerifiedFor( + string verseId, + string authorityRuntimeId, + string protocolId, + string routeGeneration) => + string.Equals(_verseId, verseId, StringComparison.Ordinal) && + string.Equals(_authorityRuntimeId, authorityRuntimeId, StringComparison.Ordinal) && + string.Equals(CultMeshProtocols.Content.Value, protocolId, StringComparison.Ordinal) && + string.Equals(_routeGeneration, routeGeneration, StringComparison.Ordinal); + public async Task CopyChunkToAsync( CultMeshCdnChunkRef chunk, Stream destination, diff --git a/src/GameCult.Mesh/CultMeshContentTransports.cs b/src/GameCult.Mesh/CultMeshContentTransports.cs index 3e2c54b1..891c221a 100644 --- a/src/GameCult.Mesh/CultMeshContentTransports.cs +++ b/src/GameCult.Mesh/CultMeshContentTransports.cs @@ -36,7 +36,7 @@ namespace GameCult.Mesh bool CanConnect(CultMeshTransportCandidate candidate); Task ConnectAsync( CultMeshTransportCandidate candidate, - CultMeshEndpointId endpointId, + CultMeshSessionTarget target, CancellationToken cancellationToken = default); } diff --git a/src/GameCult.Mesh/CultMeshDiscoveryService.cs b/src/GameCult.Mesh/CultMeshDiscoveryService.cs index 93ea6a84..3f108e03 100644 --- a/src/GameCult.Mesh/CultMeshDiscoveryService.cs +++ b/src/GameCult.Mesh/CultMeshDiscoveryService.cs @@ -267,7 +267,8 @@ namespace GameCult.Mesh var observations = results.SelectMany(result => result.Observations) .Where(observation => query.VerseIds.Count == 0 || query.VerseIds.Contains(observation.Candidate.VerseId, StringComparer.Ordinal)) .Where(observation => query.AuthorityRuntimeId == null || - observation.Candidate.AuthorityRuntimeIds.Contains(query.AuthorityRuntimeId, StringComparer.Ordinal)) + observation.Candidate.AuthorityRoutes.Any(route => + string.Equals(route.AuthorityRuntimeId, query.AuthorityRuntimeId, StringComparison.Ordinal))) .ToArray(); foreach (var rejected in observations.Where(observation => observation.Trust == CultMeshDiscoveryTrust.Rejected)) diff --git a/src/GameCult.Mesh/CultMeshRealtimeTransports.cs b/src/GameCult.Mesh/CultMeshRealtimeTransports.cs index 7b32ad6a..d37b7381 100644 --- a/src/GameCult.Mesh/CultMeshRealtimeTransports.cs +++ b/src/GameCult.Mesh/CultMeshRealtimeTransports.cs @@ -59,7 +59,7 @@ namespace GameCult.Mesh bool CanConnect(CultMeshTransportCandidate candidate); Task ConnectAsync( CultMeshTransportCandidate candidate, - CultMeshEndpointId endpointId, + CultMeshSessionTarget target, CancellationToken cancellationToken = default); } diff --git a/src/GameCult.Mesh/CultMeshSessionIdentity.cs b/src/GameCult.Mesh/CultMeshSessionIdentity.cs new file mode 100644 index 00000000..bb17a3d8 --- /dev/null +++ b/src/GameCult.Mesh/CultMeshSessionIdentity.cs @@ -0,0 +1,213 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using GameCult.Networking; + +namespace GameCult.Mesh +{ + /// + /// Optional transport proof surfaced by connectors that already authenticate + /// the peer during their native handshake. Other schema clients must complete + /// the portable CultMesh handshake before use. + /// + public interface ICultMeshVerifiedSchemaClient + { + bool IsVerifiedFor( + string verseId, + string authorityRuntimeId, + string protocolId, + string routeGeneration); + } + + /// + /// Proof exposed by content and realtime transports after their native or + /// portable handshake has bound the physical channel to an Odin route. + /// + public interface ICultMeshVerifiedTransport + { + bool IsVerifiedFor( + string verseId, + string authorityRuntimeId, + string protocolId, + string routeGeneration); + } + + internal static class CultMeshTransportIdentity + { + public static void RequireVerified( + object transport, + CultMeshSessionTarget target, + CultMeshProtocolId protocol, + CultMeshTransportCandidate candidate) + { + if (transport is ICultMeshVerifiedTransport verified && + verified.IsVerifiedFor( + target.VerseId, + target.AuthorityRuntimeId, + protocol.Value, + candidate.Generation)) + return; + throw new CultMeshSessionException(new CultMeshSessionFailure( + CultMeshSessionFailureReason.Authority, + $"Transport did not prove CultMesh authority '{target}' for protocol '{protocol}'.", + candidate.Endpoint)); + } + } + + /// + /// Owns the server side of the transport-neutral CultMesh session identity + /// handshake. Application messages are not authority proof; providers attach + /// this gate to every schema transport they advertise. + /// + public sealed class CultMeshSessionIdentityServer : IDisposable + { + private readonly ICultNetSchemaServer _server; + private readonly string _authorityRuntimeId; + private readonly HashSet _verseIds; + private readonly HashSet _protocolIds; + private readonly HashSet _routeGenerations; + private readonly Func _handler; + private bool _disposed; + + public CultMeshSessionIdentityServer( + ICultNetSchemaServer server, + string authorityRuntimeId, + IEnumerable verseIds, + IEnumerable protocolIds, + IEnumerable routeGenerations) + { + _server = server ?? throw new ArgumentNullException(nameof(server)); + _authorityRuntimeId = Require(authorityRuntimeId, nameof(authorityRuntimeId)); + _verseIds = Clean(verseIds, nameof(verseIds)); + _protocolIds = Clean(protocolIds, nameof(protocolIds)); + _routeGenerations = Clean(routeGenerations, nameof(routeGenerations)); + _handler = HandleAsync; + _server.OnCultNet(_handler); + } + + public void Dispose() + { + if (_disposed) return; + _disposed = true; + _server.RemoveCultNetMessageListener(_handler); + } + + private Task HandleAsync(CultMeshSessionOpenMessage request, ICultNetSchemaServerPeer peer) + { + var error = Validate(request); + peer.SendCultNet(new CultMeshSessionAcceptedMessage + { + MessageId = request.MessageId ?? string.Empty, + Accepted = error == null, + VerseId = request.VerseId ?? string.Empty, + AuthorityRuntimeId = _authorityRuntimeId, + ProtocolId = request.ProtocolId ?? string.Empty, + RouteGeneration = request.RouteGeneration ?? string.Empty, + Error = error + }); + return Task.CompletedTask; + } + + private string? Validate(CultMeshSessionOpenMessage request) + { + if (string.IsNullOrWhiteSpace(request.MessageId)) return "session-message-id-required"; + if (string.IsNullOrWhiteSpace(request.SourceRuntimeId)) return "source-runtime-id-required"; + if (!string.Equals(request.AuthorityRuntimeId, _authorityRuntimeId, StringComparison.Ordinal)) + return "target-runtime-mismatch"; + if (!_verseIds.Contains(request.VerseId ?? string.Empty)) return "verse-not-served"; + if (!_protocolIds.Contains(request.ProtocolId ?? string.Empty)) return "protocol-not-served"; + if (!_routeGenerations.Contains(request.RouteGeneration ?? string.Empty)) return "route-generation-not-served"; + return null; + } + + private static HashSet Clean(IEnumerable values, string name) + { + if (values == null) throw new ArgumentNullException(name); + var result = new HashSet( + values.Where(value => !string.IsNullOrWhiteSpace(value)).Select(value => value.Trim()), + StringComparer.Ordinal); + if (result.Count == 0) throw new ArgumentException("At least one identity is required.", name); + return result; + } + + private static string Require(string value, string name) => + string.IsNullOrWhiteSpace(value) + ? throw new ArgumentException("Value must be non-empty.", name) + : value.Trim(); + } + + internal static class CultMeshSessionIdentityClient + { + public static async Task VerifyAsync( + ICultNetSchemaClient client, + string sourceRuntimeId, + CultMeshSessionTarget target, + CultMeshProtocolId protocol, + string routeGeneration, + TimeSpan timeout, + CancellationToken cancellationToken = default) + { + if (client == null) throw new ArgumentNullException(nameof(client)); + if (client is ICultMeshVerifiedSchemaClient verified) + { + if (!verified.IsVerifiedFor( + target.VerseId, + target.AuthorityRuntimeId, + protocol.Value, + routeGeneration ?? string.Empty)) + { + throw new CultMeshSessionException(new CultMeshSessionFailure( + CultMeshSessionFailureReason.Authority, + $"Native transport identity did not match CultMesh target '{target}' for '{protocol}'.")); + } + return; + } + var messageId = Guid.NewGuid().ToString("N"); + var completion = new TaskCompletionSource( + TaskCreationOptions.RunContinuationsAsynchronously); + client.OnCultNet(response => + { + if (string.Equals(response.MessageId, messageId, StringComparison.Ordinal)) + completion.TrySetResult(response); + }); + client.SendCultNet(new CultMeshSessionOpenMessage + { + MessageId = messageId, + SourceRuntimeId = sourceRuntimeId, + VerseId = target.VerseId, + AuthorityRuntimeId = target.AuthorityRuntimeId, + ProtocolId = protocol.Value, + RouteGeneration = routeGeneration ?? string.Empty + }); + + using var deadline = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + deadline.CancelAfter(timeout); + var cancelled = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + using (deadline.Token.Register(() => cancelled.TrySetResult(true))) + { + if (await Task.WhenAny(completion.Task, cancelled.Task).ConfigureAwait(false) != completion.Task) + { + cancellationToken.ThrowIfCancellationRequested(); + throw new CultMeshSessionException(new CultMeshSessionFailure( + CultMeshSessionFailureReason.Timeout, + $"Timed out verifying authority runtime '{target.AuthorityRuntimeId}'.")); + } + } + + var accepted = await completion.Task.ConfigureAwait(false); + if (!accepted.Accepted || + !string.Equals(accepted.VerseId, target.VerseId, StringComparison.Ordinal) || + !string.Equals(accepted.AuthorityRuntimeId, target.AuthorityRuntimeId, StringComparison.Ordinal) || + !string.Equals(accepted.ProtocolId, protocol.Value, StringComparison.Ordinal) || + !string.Equals(accepted.RouteGeneration, routeGeneration ?? string.Empty, StringComparison.Ordinal)) + { + throw new CultMeshSessionException(new CultMeshSessionFailure( + CultMeshSessionFailureReason.Authority, + $"Route did not prove CultMesh authority '{target}' for protocol '{protocol}': " + + (accepted.Error ?? "identity-mismatch"))); + } + } + } +} diff --git a/src/GameCult.Mesh/CultMeshSessions.cs b/src/GameCult.Mesh/CultMeshSessions.cs index c562de83..7db6f06b 100644 --- a/src/GameCult.Mesh/CultMeshSessions.cs +++ b/src/GameCult.Mesh/CultMeshSessions.cs @@ -9,14 +9,14 @@ using R3; namespace GameCult.Mesh { - public sealed class CultMeshEndpointId : IEquatable + public sealed class CultMeshRuntimeId : IEquatable { - private CultMeshEndpointId(string value) { Value = value; } + private CultMeshRuntimeId(string value) { Value = value; } public string Value { get; } - public static CultMeshEndpointId Parse(string value) => new CultMeshEndpointId( - string.IsNullOrWhiteSpace(value) ? throw new FormatException("CultMesh endpoint identity must be non-empty.") : value.Trim()); - public bool Equals(CultMeshEndpointId? other) => other != null && string.Equals(Value, other.Value, StringComparison.Ordinal); - public override bool Equals(object? obj) => Equals(obj as CultMeshEndpointId); + public static CultMeshRuntimeId Parse(string value) => new CultMeshRuntimeId( + string.IsNullOrWhiteSpace(value) ? throw new FormatException("CultMesh runtime identity must be non-empty.") : value.Trim()); + public bool Equals(CultMeshRuntimeId? other) => other != null && string.Equals(Value, other.Value, StringComparison.Ordinal); + public override bool Equals(object? obj) => Equals(obj as CultMeshRuntimeId); public override int GetHashCode() => StringComparer.Ordinal.GetHashCode(Value); public override string ToString() => Value; } @@ -28,31 +28,32 @@ namespace GameCult.Mesh public sealed class CultMeshSessionTarget : IEquatable { /// Creates one stable provider target inside one Verse. - public CultMeshSessionTarget(string verseId, string providerRuntimeId) + public CultMeshSessionTarget(string verseId, string authorityRuntimeId) { VerseId = string.IsNullOrWhiteSpace(verseId) ? throw new ArgumentException("Verse identity is required.", nameof(verseId)) : verseId.Trim(); - ProviderEndpointId = CultMeshEndpointId.Parse(providerRuntimeId); - ProviderRuntimeId = ProviderEndpointId.Value; + AuthorityRuntimeId = CultMeshRuntimeId.Parse(authorityRuntimeId).Value; } /// Gets the stable Verse identity. public string VerseId { get; } - /// Gets the stable provider runtime identity advertised by that Verse. - public string ProviderRuntimeId { get; } - internal CultMeshEndpointId ProviderEndpointId { get; } - internal string SessionKey => VerseId + "\u001f" + ProviderRuntimeId; + /// Gets the stable authority runtime identity advertised by that Verse. + public string AuthorityRuntimeId { get; } + /// Compatibility projection. Use . + [Obsolete("Use AuthorityRuntimeId. Provider identity is not a physical endpoint.")] + public string ProviderRuntimeId => AuthorityRuntimeId; + internal string SessionKey => VerseId + "\u001f" + AuthorityRuntimeId; public bool Equals(CultMeshSessionTarget? other) => other != null && string.Equals(VerseId, other.VerseId, StringComparison.Ordinal) && - string.Equals(ProviderRuntimeId, other.ProviderRuntimeId, StringComparison.Ordinal); + string.Equals(AuthorityRuntimeId, other.AuthorityRuntimeId, StringComparison.Ordinal); public override bool Equals(object? obj) => Equals(obj as CultMeshSessionTarget); public override int GetHashCode() => HashCode.Combine( StringComparer.Ordinal.GetHashCode(VerseId), - StringComparer.Ordinal.GetHashCode(ProviderRuntimeId)); - public override string ToString() => VerseId + "/" + ProviderRuntimeId; + StringComparer.Ordinal.GetHashCode(AuthorityRuntimeId)); + public override string ToString() => VerseId + "/" + AuthorityRuntimeId; } public sealed class CultMeshProtocolId : IEquatable @@ -80,15 +81,24 @@ namespace GameCult.Mesh public sealed class CultMeshTransportCandidate { - public CultMeshTransportCandidate(string endpoint, CultMeshTransportPathKind pathKind = CultMeshTransportPathKind.Direct, int priority = 0) + public CultMeshTransportCandidate( + string endpoint, + CultMeshTransportPathKind pathKind = CultMeshTransportPathKind.Direct, + int priority = 0, + string authorityRuntimeId = "", + string generation = "") { Endpoint = string.IsNullOrWhiteSpace(endpoint) ? throw new ArgumentException("Physical endpoint is required.", nameof(endpoint)) : endpoint; PathKind = pathKind; Priority = priority; + AuthorityRuntimeId = authorityRuntimeId?.Trim() ?? string.Empty; + Generation = generation?.Trim() ?? string.Empty; } public string Endpoint { get; } public CultMeshTransportPathKind PathKind { get; } public int Priority { get; } + public string AuthorityRuntimeId { get; } + public string Generation { get; } } public enum CultMeshSessionStatus { Connecting, Online, Degraded, Reconnecting, Offline } @@ -522,6 +532,8 @@ namespace GameCult.Mesh public ICultMeshClock Clock { get; set; } = CultMeshSystemClock.Instance; public ICultMeshDiagnosticSink Diagnostics { get; set; } = CultMeshNullDiagnosticSink.Instance; public int MaxRacedCandidates { get; set; } = 2; + public string RuntimeId { get; set; } = "cultmesh-client"; + public TimeSpan IdentityHandshakeTimeout { get; set; } = TimeSpan.FromSeconds(5); } public sealed class CultMeshSessionManager : IDisposable @@ -581,6 +593,8 @@ namespace GameCult.Mesh throw new ArgumentException("Realtime transport connectors cannot contain null entries.", nameof(realtimeConnectors)); _options = options ?? new CultMeshSessionManagerOptions(); if (_options.MaxRacedCandidates <= 0) throw new ArgumentOutOfRangeException(nameof(options)); + if (string.IsNullOrWhiteSpace(_options.RuntimeId)) throw new ArgumentException("Client runtime identity is required.", nameof(options)); + if (_options.IdentityHandshakeTimeout <= TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(options)); } public async Task ConnectAsync( @@ -661,14 +675,10 @@ namespace GameCult.Mesh "No streaming content connectors are configured. Register the TCP content connector or the explicit legacy RUDP connector."); var discovery = await _discovery.ResolveAsync(new CultMeshDiscoveryQuery( - target.ProviderRuntimeId, + target.AuthorityRuntimeId, new[] { target.VerseId }, - target.ProviderRuntimeId)).ConfigureAwait(false); - var candidates = discovery.Candidates - .SelectMany(candidate => candidate.Descriptor.DiscoveryEndpoints) - .Distinct(StringComparer.Ordinal) - .Select(endpoint => new CultMeshTransportCandidate(endpoint)) - .ToArray(); + target.AuthorityRuntimeId)).ConfigureAwait(false); + var candidates = BoundCandidates(discovery, target, CultMeshProtocols.Content); var routes = candidates .SelectMany(candidate => _contentConnectors .Where(connector => connector.CanConnect(candidate)) @@ -685,7 +695,7 @@ namespace GameCult.Mesh foreach (var tier in routes.GroupBy(route => route.Connector.Priority).OrderBy(group => group.Key)) { var attempts = tier.Take(_options.MaxRacedCandidates) - .Select(route => ConnectContentCandidateAsync(target.ProviderEndpointId, route)) + .Select(route => ConnectContentCandidateAsync(target, route)) .ToList(); while (attempts.Count > 0) { @@ -709,18 +719,33 @@ namespace GameCult.Mesh } var last = failures.LastOrDefault(); + var reason = last is CultMeshSessionException typed + ? typed.Failure.Reason + : last is TimeoutException + ? CultMeshSessionFailureReason.Timeout + : CultMeshSessionFailureReason.Transport; throw Failure( - last is TimeoutException ? CultMeshSessionFailureReason.Timeout : CultMeshSessionFailureReason.Transport, + reason, $"No streaming content path connected for '{target}'.", last); } private static async Task ConnectContentCandidateAsync( - CultMeshEndpointId endpointId, + CultMeshSessionTarget target, ContentRoute route) { - var transport = await route.Connector.ConnectAsync(route.Candidate, endpointId).ConfigureAwait(false); - return new ConnectedContentPath(route.Candidate, transport); + var transport = await route.Connector.ConnectAsync(route.Candidate, target).ConfigureAwait(false); + try + { + CultMeshTransportIdentity.RequireVerified( + transport, target, CultMeshProtocols.Content, route.Candidate); + return new ConnectedContentPath(route.Candidate, transport); + } + catch + { + transport.Dispose(); + throw; + } } private void InvalidateContentSession(string key, CultMeshContentSession session) @@ -790,13 +815,10 @@ namespace GameCult.Mesh "No realtime state connectors are configured. Register a QUIC connector explicitly."); var discovery = await _discovery.ResolveAsync(new CultMeshDiscoveryQuery( - target.ProviderRuntimeId, + target.AuthorityRuntimeId, new[] { target.VerseId }, - target.ProviderRuntimeId)).ConfigureAwait(false); - var routes = discovery.Candidates - .SelectMany(candidate => candidate.Descriptor.DiscoveryEndpoints) - .Distinct(StringComparer.Ordinal) - .Select(endpoint => new CultMeshTransportCandidate(endpoint)) + target.AuthorityRuntimeId)).ConfigureAwait(false); + var routes = BoundCandidates(discovery, target, CultMeshProtocols.RealtimeState) .SelectMany(candidate => _realtimeConnectors .Where(connector => connector.CanConnect(candidate)) .Select(connector => new RealtimeRoute(candidate, connector))) @@ -812,7 +834,7 @@ namespace GameCult.Mesh foreach (var tier in routes.GroupBy(route => route.Connector.Priority).OrderBy(group => group.Key)) { var attempts = tier.Take(_options.MaxRacedCandidates) - .Select(route => ConnectRealtimeCandidateAsync(target.ProviderEndpointId, route)) + .Select(route => ConnectRealtimeCandidateAsync(target, route)) .ToList(); while (attempts.Count > 0) { @@ -836,18 +858,33 @@ namespace GameCult.Mesh } var last = failures.LastOrDefault(); + var reason = last is CultMeshSessionException typed + ? typed.Failure.Reason + : last is TimeoutException + ? CultMeshSessionFailureReason.Timeout + : CultMeshSessionFailureReason.Transport; throw Failure( - last is TimeoutException ? CultMeshSessionFailureReason.Timeout : CultMeshSessionFailureReason.Transport, + reason, $"No realtime state path connected for '{target}'.", last); } private static async Task ConnectRealtimeCandidateAsync( - CultMeshEndpointId endpointId, + CultMeshSessionTarget target, RealtimeRoute route) { - var transport = await route.Connector.ConnectAsync(route.Candidate, endpointId).ConfigureAwait(false); - return new ConnectedRealtimePath(route.Candidate, transport); + var transport = await route.Connector.ConnectAsync(route.Candidate, target).ConfigureAwait(false); + try + { + CultMeshTransportIdentity.RequireVerified( + transport, target, CultMeshProtocols.RealtimeState, route.Candidate); + return new ConnectedRealtimePath(route.Candidate, transport); + } + catch + { + transport.Dispose(); + throw; + } } private void InvalidateRealtimeSession(string key, CultMeshRealtimeSession session) @@ -880,13 +917,10 @@ namespace GameCult.Mesh private async Task ResolveConnectedPathAsync(CultMeshSessionTarget target, CultMeshProtocolId protocol) { var discovery = await _discovery.ResolveAsync(new CultMeshDiscoveryQuery( - target.ProviderRuntimeId, + target.AuthorityRuntimeId, new[] { target.VerseId }, - target.ProviderRuntimeId)).ConfigureAwait(false); - var candidates = discovery.Candidates.SelectMany(candidate => candidate.Descriptor.DiscoveryEndpoints) - .Distinct(StringComparer.Ordinal) - .Select(endpoint => new CultMeshTransportCandidate(endpoint)) - .ToArray(); + target.AuthorityRuntimeId)).ConfigureAwait(false); + var candidates = BoundCandidates(discovery, target, protocol); var routes = candidates .SelectMany(candidate => _connectors .Where(connector => connector.CanConnect(candidate)) @@ -908,7 +942,7 @@ namespace GameCult.Mesh foreach (var tier in routes.GroupBy(route => route.Connector.Priority).OrderBy(group => group.Key)) { var attempts = tier.Take(_options.MaxRacedCandidates) - .Select(route => ConnectCandidateAsync(route, protocol)) + .Select(route => ConnectCandidateAsync(target, route, protocol)) .ToList(); while (attempts.Count > 0) { @@ -925,7 +959,12 @@ namespace GameCult.Mesh } } var last = failures.LastOrDefault(); - throw Failure(last is TimeoutException ? CultMeshSessionFailureReason.Timeout : CultMeshSessionFailureReason.Transport, + var reason = last is CultMeshSessionException typed + ? typed.Failure.Reason + : last is TimeoutException + ? CultMeshSessionFailureReason.Timeout + : CultMeshSessionFailureReason.Transport; + throw Failure(reason, $"No transport path connected for '{target}' and protocol '{protocol}'.", last); } @@ -960,9 +999,9 @@ namespace GameCult.Mesh try { _discovery.Invalidate(new CultMeshDiscoveryQuery( - session.Target.ProviderRuntimeId, + session.Target.AuthorityRuntimeId, new[] { session.Target.VerseId }, - session.Target.ProviderRuntimeId)); + session.Target.AuthorityRuntimeId)); var replacement = await ResolveConnectedPathAsync(session.Target, session.Protocol).ConfigureAwait(false); session.ReplacePhysicalChannel(replacement.Client); session.Transition(new CultMeshSessionState( @@ -987,10 +1026,28 @@ namespace GameCult.Mesh } } - private static async Task ConnectCandidateAsync(SchemaRoute route, CultMeshProtocolId protocol) + private async Task ConnectCandidateAsync( + CultMeshSessionTarget target, + SchemaRoute route, + CultMeshProtocolId protocol) { var client = await route.Connector.ConnectAsync(route.Candidate, protocol).ConfigureAwait(false); - return new ConnectedPath(route.Candidate, client); + try + { + await CultMeshSessionIdentityClient.VerifyAsync( + client, + _options.RuntimeId, + target, + protocol, + route.Candidate.Generation, + _options.IdentityHandshakeTimeout).ConfigureAwait(false); + return new ConnectedPath(route.Candidate, client); + } + catch + { + client.Dispose(); + throw; + } } private static async Task AwaitForCallerAsync(Task shared, CancellationToken cancellationToken) @@ -1008,12 +1065,36 @@ namespace GameCult.Mesh private CultMeshSessionException Failure(CultMeshSessionFailureReason reason, string message, Exception? inner = null) => new CultMeshSessionException(new CultMeshSessionFailure(reason, message), inner); + private static CultMeshTransportCandidate[] BoundCandidates( + CultMeshDiscoveryState discovery, + CultMeshSessionTarget target, + CultMeshProtocolId protocol) + { + return discovery.Candidates + .SelectMany(candidate => candidate.Descriptor.AuthorityRoutes) + .Where(route => string.Equals( + route.AuthorityRuntimeId, + target.AuthorityRuntimeId, + StringComparison.Ordinal)) + .Where(route => route.Supports(protocol)) + .GroupBy(route => route.Endpoint, StringComparer.Ordinal) + .Select(group => group.OrderBy(route => route.Priority).First()) + .Select(route => new CultMeshTransportCandidate( + route.Endpoint, + priority: route.Priority, + authorityRuntimeId: route.AuthorityRuntimeId, + generation: route.Generation)) + .OrderBy(candidate => candidate.Priority) + .ThenBy(candidate => candidate.Endpoint, StringComparer.Ordinal) + .ToArray(); + } + private void Emit(CultMeshSessionTarget target, CultMeshProtocolId protocol, string state, string path) { _options.Diagnostics.Emit(new CultMeshDiagnosticEvent( Interlocked.Increment(ref _diagnosticSequence), _options.Clock.UtcNow, CultMeshReliabilityOrgan.Session, CultMeshDiagnosticKind.PathChanged, - target.SessionKey + ":" + protocol.Value, target.ProviderRuntimeId, state, + target.SessionKey + ":" + protocol.Value, target.AuthorityRuntimeId, state, sourceId: "session-manager", endpoint: path)); } diff --git a/src/GameCult.Mesh/CultMeshSnapshots.cs b/src/GameCult.Mesh/CultMeshSnapshots.cs index cff94fa4..305fed4a 100644 --- a/src/GameCult.Mesh/CultMeshSnapshots.cs +++ b/src/GameCult.Mesh/CultMeshSnapshots.cs @@ -102,7 +102,7 @@ namespace GameCult.Mesh CultNetDocumentRegistry? registry) { _sharedSession = session ?? throw new ArgumentNullException(nameof(session)); - _endpoint = session.State.Path?.Endpoint ?? session.Target.ProviderRuntimeId; + _endpoint = session.State.Path?.Endpoint ?? session.Target.AuthorityRuntimeId; _defaults = CultMesh.CloneSnapshotRequestOptions(options); _registry = registry ?? new CultNetDocumentRegistry(); _client = session.Channel; diff --git a/src/GameCult.Mesh/CultMeshTcpContentTransport.cs b/src/GameCult.Mesh/CultMeshTcpContentTransport.cs index 0c3eb19e..f47f08bd 100644 --- a/src/GameCult.Mesh/CultMeshTcpContentTransport.cs +++ b/src/GameCult.Mesh/CultMeshTcpContentTransport.cs @@ -11,6 +11,21 @@ using GameCult.Networking; namespace GameCult.Mesh { + /// Identity served by one dedicated content listener. + public sealed class CultMeshTcpContentServerOptions + { + public string VerseId { get; set; } = string.Empty; + public string AuthorityRuntimeId { get; set; } = string.Empty; + public string RouteGeneration { get; set; } = string.Empty; + + internal void Validate() + { + if (string.IsNullOrWhiteSpace(VerseId)) throw new InvalidOperationException("Content Verse identity is required."); + if (string.IsNullOrWhiteSpace(AuthorityRuntimeId)) throw new InvalidOperationException("Content authority runtime identity is required."); + if (string.IsNullOrWhiteSpace(RouteGeneration)) throw new InvalidOperationException("Content route generation is required."); + } + } + /// Creates dedicated TCP streams for immutable CultMesh content. public sealed class CultMeshTcpContentTransportConnector : ICultMeshContentTransportConnector { @@ -33,11 +48,11 @@ namespace GameCult.Mesh public async Task ConnectAsync( CultMeshTransportCandidate candidate, - CultMeshEndpointId endpointId, + CultMeshSessionTarget target, CancellationToken cancellationToken = default) { if (candidate == null) throw new ArgumentNullException(nameof(candidate)); - if (endpointId == null) throw new ArgumentNullException(nameof(endpointId)); + if (target == null) throw new ArgumentNullException(nameof(target)); if (!TryParseEndpoint(candidate.Endpoint, out var host, out var port)) throw new NotSupportedException($"TCP content connector does not support '{candidate.Endpoint}'."); @@ -48,8 +63,10 @@ namespace GameCult.Mesh { await CultMeshTcpContentWire.AwaitAsync(client.ConnectAsync(host, port), timeout.Token) .ConfigureAwait(false); + await CultMeshTcpContentWire.VerifyAuthorityAsync( + client.GetStream(), target, candidate, timeout.Token).ConfigureAwait(false); Interlocked.Increment(ref _connectCount); - return new CultMeshTcpContentTransport(candidate.Endpoint, client); + return new CultMeshTcpContentTransport(candidate.Endpoint, client, target, candidate.Generation); } catch { @@ -72,7 +89,7 @@ namespace GameCult.Mesh } } - internal sealed class CultMeshTcpContentTransport : ICultMeshContentTransport + internal sealed class CultMeshTcpContentTransport : ICultMeshContentTransport, ICultMeshVerifiedTransport { private readonly TcpClient _client; private readonly NetworkStream _stream; @@ -80,12 +97,22 @@ namespace GameCult.Mesh private readonly ConcurrentDictionary _pending = new(StringComparer.Ordinal); private readonly CancellationTokenSource _shutdown = new(); private readonly Task _receiveLoop; + private readonly string _verseId; + private readonly string _authorityRuntimeId; + private readonly string _routeGeneration; private bool _disposed; - public CultMeshTcpContentTransport(string endpoint, TcpClient client) + public CultMeshTcpContentTransport( + string endpoint, + TcpClient client, + CultMeshSessionTarget target, + string routeGeneration) { Endpoint = endpoint; _client = client ?? throw new ArgumentNullException(nameof(client)); + _verseId = target?.VerseId ?? throw new ArgumentNullException(nameof(target)); + _authorityRuntimeId = target.AuthorityRuntimeId; + _routeGeneration = routeGeneration ?? string.Empty; _stream = client.GetStream(); _receiveLoop = ReceiveLoopAsync(_shutdown.Token); } @@ -93,6 +120,16 @@ namespace GameCult.Mesh public string TransportId => "tcp-content"; public string Endpoint { get; } + public bool IsVerifiedFor( + string verseId, + string authorityRuntimeId, + string protocolId, + string routeGeneration) => + string.Equals(_verseId, verseId, StringComparison.Ordinal) && + string.Equals(_authorityRuntimeId, authorityRuntimeId, StringComparison.Ordinal) && + string.Equals(CultMeshProtocols.Content.Value, protocolId, StringComparison.Ordinal) && + string.Equals(_routeGeneration, routeGeneration, StringComparison.Ordinal); + public async Task CopyChunkToAsync( CultMeshCdnChunkRef chunk, Stream destination, @@ -212,6 +249,7 @@ namespace GameCult.Mesh private readonly TcpListener _listener; private readonly Func _resolveChunk; private readonly Func _canServeHash; + private readonly CultMeshTcpContentServerOptions _options; private readonly CancellationTokenSource _shutdown = new(); private readonly ConcurrentDictionary _clients = new(); private readonly Task _acceptLoop; @@ -221,8 +259,9 @@ namespace GameCult.Mesh public CultMeshTcpContentServer( TcpListener listener, CultCache content, + CultMeshTcpContentServerOptions options, Func? canServeHash = null) - : this(listener, CreateCacheResolver(content), canServeHash) + : this(listener, CreateCacheResolver(content), options, canServeHash) { } @@ -234,10 +273,13 @@ namespace GameCult.Mesh public CultMeshTcpContentServer( TcpListener listener, Func resolveChunk, + CultMeshTcpContentServerOptions options, Func? canServeHash = null) { _listener = listener ?? throw new ArgumentNullException(nameof(listener)); _resolveChunk = resolveChunk ?? throw new ArgumentNullException(nameof(resolveChunk)); + _options = options ?? throw new ArgumentNullException(nameof(options)); + _options.Validate(); _canServeHash = canServeHash ?? (_ => true); _listener.Start(); _acceptLoop = AcceptLoopAsync(_shutdown.Token); @@ -278,6 +320,7 @@ namespace GameCult.Mesh try { using var stream = client.GetStream(); + if (!await AcceptAuthorityAsync(stream, cancellationToken).ConfigureAwait(false)) return; while (!cancellationToken.IsCancellationRequested) { var requestBytes = await CultMeshTcpContentWire.ReadFrameAsync(stream, cancellationToken).ConfigureAwait(false); @@ -296,6 +339,32 @@ namespace GameCult.Mesh } } + private async Task AcceptAuthorityAsync(Stream stream, CancellationToken cancellationToken) + { + var requestBytes = await CultMeshTcpContentWire.ReadFrameAsync(stream, cancellationToken).ConfigureAwait(false); + var request = CultNetSchemaMessageSerialization.Deserialize(requestBytes) as CultMeshSessionOpenMessage + ?? throw new InvalidDataException("TCP content session did not begin with an authority handshake."); + var accepted = string.Equals(request.VerseId, _options.VerseId, StringComparison.Ordinal) && + string.Equals(request.AuthorityRuntimeId, _options.AuthorityRuntimeId, StringComparison.Ordinal) && + string.Equals(request.ProtocolId, CultMeshProtocols.Content.Value, StringComparison.Ordinal) && + string.Equals(request.RouteGeneration, _options.RouteGeneration, StringComparison.Ordinal); + var response = new CultMeshSessionAcceptedMessage + { + MessageId = request.MessageId, + Accepted = accepted, + VerseId = _options.VerseId, + AuthorityRuntimeId = _options.AuthorityRuntimeId, + ProtocolId = CultMeshProtocols.Content.Value, + RouteGeneration = _options.RouteGeneration, + Error = accepted ? null : "Content session target does not match this authority route." + }; + await CultMeshTcpContentWire.WriteFrameAsync( + stream, + CultNetSchemaMessageSerialization.Serialize(response), + cancellationToken).ConfigureAwait(false); + return accepted; + } + private async Task SendChunkAsync( Stream stream, CultMeshContentChunkRequestMessage request, @@ -391,6 +460,38 @@ namespace GameCult.Mesh await stream.FlushAsync(cancellationToken).ConfigureAwait(false); } + public static async Task VerifyAuthorityAsync( + Stream stream, + CultMeshSessionTarget target, + CultMeshTransportCandidate candidate, + CancellationToken cancellationToken) + { + var request = new CultMeshSessionOpenMessage + { + MessageId = Guid.NewGuid().ToString("N"), + SourceRuntimeId = "cultmesh-content-client", + VerseId = target.VerseId, + AuthorityRuntimeId = target.AuthorityRuntimeId, + ProtocolId = CultMeshProtocols.Content.Value, + RouteGeneration = candidate.Generation + }; + await WriteFrameAsync(stream, CultNetSchemaMessageSerialization.Serialize(request), cancellationToken) + .ConfigureAwait(false); + var responseBytes = await ReadFrameAsync(stream, cancellationToken).ConfigureAwait(false); + var response = CultNetSchemaMessageSerialization.Deserialize(responseBytes) as CultMeshSessionAcceptedMessage + ?? throw new InvalidDataException("TCP content authority handshake returned an unexpected schema."); + if (!string.Equals(response.MessageId, request.MessageId, StringComparison.Ordinal) || + !response.Accepted || + !string.Equals(response.VerseId, target.VerseId, StringComparison.Ordinal) || + !string.Equals(response.AuthorityRuntimeId, target.AuthorityRuntimeId, StringComparison.Ordinal) || + !string.Equals(response.ProtocolId, CultMeshProtocols.Content.Value, StringComparison.Ordinal) || + !string.Equals(response.RouteGeneration, candidate.Generation, StringComparison.Ordinal)) + throw new CultMeshSessionException(new CultMeshSessionFailure( + CultMeshSessionFailureReason.Authority, + response.Error ?? "TCP content endpoint did not prove the selected authority route.", + candidate.Endpoint)); + } + public static async Task ReadFrameAsync(Stream stream, CancellationToken cancellationToken) { var header = new byte[HeaderBytes]; diff --git a/src/GameCult.Mesh/CultMeshVerse.cs b/src/GameCult.Mesh/CultMeshVerse.cs index 547a46ec..55d6deeb 100644 --- a/src/GameCult.Mesh/CultMeshVerse.cs +++ b/src/GameCult.Mesh/CultMeshVerse.cs @@ -91,6 +91,53 @@ namespace GameCult.Mesh } } + /// + /// Binds one authoritative runtime to one physical route. This relationship is + /// the routing authority; the legacy endpoint/runtime lists are projections only. + /// + public sealed class CultMeshAuthorityRoute + { + public CultMeshAuthorityRoute( + string authorityRuntimeId, + string endpoint, + IEnumerable? protocolIds = null, + int priority = 0, + string? generation = null) + { + AuthorityRuntimeId = RequireNonEmpty(authorityRuntimeId, nameof(authorityRuntimeId)); + Endpoint = RequireNonEmpty(endpoint, nameof(endpoint)); + ProtocolIds = Clean(protocolIds); + if (priority < 0) throw new ArgumentOutOfRangeException(nameof(priority)); + Priority = priority; + Generation = string.IsNullOrWhiteSpace(generation) + ? AuthorityRuntimeId + "@" + Endpoint + : generation!.Trim(); + } + + public string AuthorityRuntimeId { get; } + public string Endpoint { get; } + public IReadOnlyList ProtocolIds { get; } + public int Priority { get; } + public string Generation { get; } + + public bool Supports(CultMeshProtocolId protocol) => + protocol != null && + (ProtocolIds.Count == 0 || ProtocolIds.Contains(protocol.Value, StringComparer.Ordinal)); + + private static string[] Clean(IEnumerable? values) => + values?.Where(value => !string.IsNullOrWhiteSpace(value)) + .Select(value => value.Trim()) + .Distinct(StringComparer.Ordinal) + .OrderBy(value => value, StringComparer.Ordinal) + .ToArray() + ?? Array.Empty(); + + private static string RequireNonEmpty(string value, string paramName) => + string.IsNullOrWhiteSpace(value) + ? throw new ArgumentException("Value must be non-empty.", paramName) + : value.Trim(); + } + /// /// Describes one CultMesh Verse: a rule-bearing consensus graph. /// @@ -107,14 +154,36 @@ namespace GameCult.Mesh IEnumerable? discoveryEndpoints = null, IEnumerable? authorityRuntimeIds = null, string? parentVerseId = null, - string? description = null) + string? description = null, + IEnumerable? authorityRoutes = null) { VerseId = RequireNonEmpty(verseId, nameof(verseId)); DisplayName = RequireNonEmpty(displayName, nameof(displayName)); AuthorityModel = authorityModel; Compatibility = compatibility ?? throw new ArgumentNullException(nameof(compatibility)); - DiscoveryEndpoints = Clean(discoveryEndpoints); - AuthorityRuntimeIds = Clean(authorityRuntimeIds); + var legacyEndpoints = Clean(discoveryEndpoints); + var legacyRuntimeIds = Clean(authorityRuntimeIds); + var suppliedRoutes = authorityRoutes?.ToArray(); + if (suppliedRoutes?.Any(route => route == null) == true) + throw new ArgumentException("Authority routes cannot contain null.", nameof(authorityRoutes)); + if (suppliedRoutes != null && (legacyEndpoints.Length > 0 || legacyRuntimeIds.Length > 0)) + throw new ArgumentException( + "Supply bound authority routes or legacy endpoint/runtime lists, never both.", + nameof(authorityRoutes)); + if (suppliedRoutes == null && legacyEndpoints.Length > 0 && legacyRuntimeIds.Length > 1) + throw new InvalidOperationException( + "Legacy Verse routing with multiple authority runtimes is ambiguous. " + + "Publish explicit CultMeshAuthorityRoute bindings."); + + AuthorityRoutes = NormalizeRoutes(suppliedRoutes ?? + (legacyRuntimeIds.Length == 1 + ? legacyEndpoints.Select(endpoint => new CultMeshAuthorityRoute(legacyRuntimeIds[0], endpoint)) + : Array.Empty())); + DiscoveryEndpoints = AuthorityRoutes.Count > 0 + ? AuthorityRoutes.Select(route => route.Endpoint).Distinct(StringComparer.Ordinal).ToArray() + : legacyEndpoints; + AuthorityRuntimeIds = AuthorityRoutes.Select(route => route.AuthorityRuntimeId) + .Distinct(StringComparer.Ordinal).OrderBy(value => value, StringComparer.Ordinal).ToArray(); ParentVerseId = parentVerseId; Description = description; } @@ -143,6 +212,8 @@ namespace GameCult.Mesh /// Gets known authoritative runtime ids, when authority is cluster-shaped. ///
    public IReadOnlyList AuthorityRuntimeIds { get; } + /// Gets exact authority-to-route bindings used for identity-sensitive resolution. + public IReadOnlyList AuthorityRoutes { get; } /// /// Gets the parent Verse id for subscribed overlays or branches. /// @@ -177,10 +248,29 @@ namespace GameCult.Mesh private static string[] Clean(IEnumerable? values) { - return values?.Where(value => !string.IsNullOrWhiteSpace(value)).Distinct(StringComparer.Ordinal).ToArray() + return values?.Where(value => !string.IsNullOrWhiteSpace(value)) + .Select(value => value.Trim()) + .Distinct(StringComparer.Ordinal) + .ToArray() ?? Array.Empty(); } + private static CultMeshAuthorityRoute[] NormalizeRoutes(IEnumerable routes) + { + return routes + .GroupBy(route => new + { + route.AuthorityRuntimeId, + route.Endpoint, + Protocols = string.Join("\u001f", route.ProtocolIds) + }) + .Select(group => group.OrderBy(route => route.Priority).First()) + .OrderBy(route => route.Priority) + .ThenBy(route => route.AuthorityRuntimeId, StringComparer.Ordinal) + .ThenBy(route => route.Endpoint, StringComparer.Ordinal) + .ToArray(); + } + private static string RequireNonEmpty(string value, string paramName) { if (string.IsNullOrWhiteSpace(value)) diff --git a/src/GameCult.Mesh/CultMeshVerseDiscovery.cs b/src/GameCult.Mesh/CultMeshVerseDiscovery.cs index 801e4716..774a05f9 100644 --- a/src/GameCult.Mesh/CultMeshVerseDiscovery.cs +++ b/src/GameCult.Mesh/CultMeshVerseDiscovery.cs @@ -33,6 +33,14 @@ namespace GameCult.Mesh }, DiscoveryEndpoints = verse.DiscoveryEndpoints.ToArray(), AuthorityRuntimeIds = verse.AuthorityRuntimeIds.ToArray(), + AuthorityRoutes = verse.AuthorityRoutes.Select(route => new CultMeshAuthorityRouteMessage + { + AuthorityRuntimeId = route.AuthorityRuntimeId, + Endpoint = route.Endpoint, + ProtocolIds = route.ProtocolIds.ToArray(), + Priority = route.Priority, + Generation = route.Generation + }).ToArray(), ParentVerseId = verse.ParentVerseId, Description = verse.Description }; @@ -50,6 +58,12 @@ namespace GameCult.Mesh out var parsed) ? parsed : CultMeshVerseAuthorityModel.SubscribedOverlay; + var routes = message.AuthorityRoutes?.Select(route => new CultMeshAuthorityRoute( + route.AuthorityRuntimeId, + route.Endpoint, + route.ProtocolIds, + route.Priority, + route.Generation)).ToArray(); return new CultMeshVerseDescriptor( message.VerseId, message.DisplayName, @@ -60,10 +74,11 @@ namespace GameCult.Mesh message.Compatibility.CompatibleVerseIds, message.Compatibility.RequiredPluginIds, message.Compatibility.OptionalPluginIds), - message.DiscoveryEndpoints, - message.AuthorityRuntimeIds, + routes is { Length: > 0 } ? null : message.DiscoveryEndpoints, + routes is { Length: > 0 } ? null : message.AuthorityRuntimeIds, message.ParentVerseId, - message.Description); + message.Description, + routes is { Length: > 0 } ? routes : null); } /// Creates the canonical filtered Verse catalog response for any CultNet transport adapter. diff --git a/src/GameCult.Mesh/docs/public-api.md b/src/GameCult.Mesh/docs/public-api.md index 88074704..df1735b6 100644 --- a/src/GameCult.Mesh/docs/public-api.md +++ b/src/GameCult.Mesh/docs/public-api.md @@ -50,8 +50,12 @@ not the brand surface. ### Verses `CultMeshVerseDescriptor` describes a rule-bearing consensus graph. It includes -transport compatibility, rules hash, authority model, discovery endpoints, -known authority runtimes, optional parent Verse id, and plugin requirements. +transport compatibility, rules hash, authority model, exact authority-route +bindings, optional parent Verse id, and plugin requirements. Each route binds +an authority runtime to one endpoint, protocol set, priority, and generation. +The old endpoint/runtime arrays are derived projections; a legacy descriptor +with several authority runtimes is rejected because it cannot identify which +runtime owns which route. `CultMeshVerseCatalog` is the local reactive catalog for discovered Verses. It can publish discovery updates and find compatible transfer targets. diff --git a/src/GameCult.Mesh/docs/transport-planes.md b/src/GameCult.Mesh/docs/transport-planes.md index 39be9c59..bd42a071 100644 --- a/src/GameCult.Mesh/docs/transport-planes.md +++ b/src/GameCult.Mesh/docs/transport-planes.md @@ -9,7 +9,8 @@ be equally good at files, realtime state, and same-machine memory access. registered connector for each traffic class. A connector owns only its physical connection and byte movement. -**Inputs:** stable Verse/provider identity, advertised physical candidates, +**Inputs:** stable Verse/authority-runtime identity, exact Odin-bound physical +routes with protocol and generation, connector support and priority, caller cancellation, and locality evidence for body negotiation. @@ -63,13 +64,22 @@ operation. transport diagnostics. None of these grant provider authority or become content identity. +Before a schema, content, or realtime session becomes online, the transport +must prove that the connected peer matches the selected Verse, authority +runtime, protocol, and route generation. TCP schema and content lanes use the +portable CultNet session-open handshake. QUIC uses the exact Odin-bound route +plus its TLS endpoint/certificate proof. A connector that returns bytes without +authority proof is rejected; racing every endpoint in a Verse descriptor is +not route selection. + **Forbidden writers:** applications and renderers do not choose unadvertised endpoints, implement reconnect loops, or bypass verification. Schema messages must not carry bulk bodies. RUDP/LiteNetLib cannot become an implicit default for any traffic class. QUIC does not own schemas or immutable files merely because it can transport bytes. -**Shared paths:** discovery and identity resolution remain common. Each traffic +**Shared paths:** exact route resolution and peer verification remain common. +Each traffic class has its own connector set, connection cache, priority tiers, and failure state. All content connectors feed the same transfer and promotion owner. diff --git a/src/GameCult.Mesh/docs/verses.md b/src/GameCult.Mesh/docs/verses.md index 656dcfaf..fbd9a522 100644 --- a/src/GameCult.Mesh/docs/verses.md +++ b/src/GameCult.Mesh/docs/verses.md @@ -21,8 +21,10 @@ The same transport can carry many Verses: subscribed overlay - `Compatibility`: transport version, rules hash, compatible Verse ids, and plugin requirements -- `DiscoveryEndpoints`: endpoints where nodes for the Verse can be found -- `AuthorityRuntimeIds`: known authoritative runtimes when cluster-shaped +- `AuthorityRoutes`: exact authority-runtime, endpoint, protocol, priority, and + generation bindings. This is the routing authority. +- `DiscoveryEndpoints`: read-only endpoint projection for legacy inspection +- `AuthorityRuntimeIds`: read-only authority projection for legacy inspection - `ParentVerseId`: source Verse for overlays or branches ## Compatibility @@ -57,6 +59,13 @@ static config, cloud discovery, peer gossip, or mod portals. It does not care where the descriptor came from. That keeps discovery pluggable while the Verse model stays stable. +An endpoint and an authority id are not two independent facts. A descriptor +with explicit routes binds them. The legacy parallel arrays are accepted only +when exactly one authority runtime exists; a multi-authority legacy descriptor +is ambiguous and fails closed. Session establishment then requires the selected +physical route to prove the exact Verse, authority runtime, protocol, and route +generation before the session becomes online. + Peer exchange is the torrent-shaped layer under Verse discovery. A Verse catalog says which graph exists; a peer catalog says which nodes can currently serve or observe parts of that graph. Peer cards can advertise discovery, diff --git a/src/GameCult.Networking/CultNetOperationServer.cs b/src/GameCult.Networking/CultNetOperationServer.cs index 6261328e..27b52c55 100644 --- a/src/GameCult.Networking/CultNetOperationServer.cs +++ b/src/GameCult.Networking/CultNetOperationServer.cs @@ -164,6 +164,16 @@ namespace GameCult.Networking if (_disposed) return; if (request == null) throw new ArgumentNullException(nameof(request)); if (peer == null) throw new ArgumentNullException(nameof(peer)); + if (_sourceRuntimeId != null && + !string.Equals(request.TargetRuntimeId, _sourceRuntimeId, StringComparison.Ordinal)) + { + peer.SendCultNet(Failure( + request, + "denied", + "target-runtime-mismatch", + $"Operation targeted runtime '{request.TargetRuntimeId ?? "(missing)"}', not '{_sourceRuntimeId}'.")); + return; + } Route route; try diff --git a/src/GameCult.Networking/CultNetSchemaMessageSerialization.cs b/src/GameCult.Networking/CultNetSchemaMessageSerialization.cs index 386bc99b..e712beef 100644 --- a/src/GameCult.Networking/CultNetSchemaMessageSerialization.cs +++ b/src/GameCult.Networking/CultNetSchemaMessageSerialization.cs @@ -72,6 +72,8 @@ namespace GameCult.Networking CultNetSchemaVersions.SimulationConsensusCandidate => Deserialize(payload), CultNetSchemaVersions.VerseCatalogRequest => Deserialize(payload), CultNetSchemaVersions.VerseCatalogResponse => Deserialize(payload), + CultNetSchemaVersions.SessionOpen => Deserialize(payload), + CultNetSchemaVersions.SessionAccepted => Deserialize(payload), CultNetSchemaVersions.PeerExchangeRequest => Deserialize(payload), CultNetSchemaVersions.PeerExchangeResponse => Deserialize(payload), CultNetSchemaVersions.ContentChunkRequest => Deserialize(payload), diff --git a/src/GameCult.Networking/CultNetSchemaMessages.cs b/src/GameCult.Networking/CultNetSchemaMessages.cs index 764238ff..2117693d 100644 --- a/src/GameCult.Networking/CultNetSchemaMessages.cs +++ b/src/GameCult.Networking/CultNetSchemaMessages.cs @@ -135,6 +135,10 @@ namespace GameCult.Networking /// CultMesh Verse catalog response contract identifier. /// public const string VerseCatalogResponse = "cultmesh.verse_catalog_response.v0"; + /// CultMesh session identity request contract identifier. + public const string SessionOpen = "cultmesh.session_open.v1"; + /// CultMesh verified session identity response contract identifier. + public const string SessionAccepted = "cultmesh.session_accepted.v1"; /// /// CultMesh peer exchange request contract identifier. /// @@ -1179,6 +1183,33 @@ namespace GameCult.Networking } } + /// Requests an identity-bound CultMesh session before application traffic begins. + [MessagePackObject] + public class CultMeshSessionOpenMessage : ICultNetSchemaMessage + { + [Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.SessionOpen; + [Key("messageId")] public string MessageId { get; set; } = string.Empty; + [Key("sourceRuntimeId")] public string SourceRuntimeId { get; set; } = string.Empty; + [Key("verseId")] public string VerseId { get; set; } = string.Empty; + [Key("authorityRuntimeId")] public string AuthorityRuntimeId { get; set; } = string.Empty; + [Key("protocolId")] public string ProtocolId { get; set; } = string.Empty; + [Key("routeGeneration")] public string RouteGeneration { get; set; } = string.Empty; + } + + /// Accepts or rejects a CultMesh session with the server's actual identity. + [MessagePackObject] + public class CultMeshSessionAcceptedMessage : ICultNetSchemaMessage + { + [Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.SessionAccepted; + [Key("messageId")] public string MessageId { get; set; } = string.Empty; + [Key("accepted")] public bool Accepted { get; set; } + [Key("verseId")] public string VerseId { get; set; } = string.Empty; + [Key("authorityRuntimeId")] public string AuthorityRuntimeId { get; set; } = string.Empty; + [Key("protocolId")] public string ProtocolId { get; set; } = string.Empty; + [Key("routeGeneration")] public string RouteGeneration { get; set; } = string.Empty; + [Key("error")] public string? Error { get; set; } + } + /// /// Requests known CultMesh Verses from a peer. /// @@ -1254,6 +1285,11 @@ namespace GameCult.Networking /// [Key("authorityRuntimeIds")] public string[] AuthorityRuntimeIds { get; set; } = Array.Empty(); /// + /// Gets or sets exact authoritative-runtime route bindings. This is the + /// routing authority; the parallel legacy arrays are projections only. + /// + [Key("authorityRoutes")] public CultMeshAuthorityRouteMessage[] AuthorityRoutes { get; set; } = Array.Empty(); + /// /// Gets or sets the parent Verse id for overlays or branches. /// [Key("parentVerseId")] public string? ParentVerseId { get; set; } @@ -1263,6 +1299,17 @@ namespace GameCult.Networking [Key("description")] public string? Description { get; set; } } + /// Wire representation of one authority-bound CultMesh route. + [MessagePackObject] + public class CultMeshAuthorityRouteMessage + { + [Key("authorityRuntimeId")] public string AuthorityRuntimeId { get; set; } = string.Empty; + [Key("endpoint")] public string Endpoint { get; set; } = string.Empty; + [Key("protocolIds")] public string[] ProtocolIds { get; set; } = Array.Empty(); + [Key("priority")] public int Priority { get; set; } + [Key("generation")] public string Generation { get; set; } = string.Empty; + } + /// /// Wire representation of CultMesh Verse compatibility. /// diff --git a/tests/GameCult.Mesh.Quic.Native.Tests/CultMeshNativeQuicRealtimeTransportTests.cs b/tests/GameCult.Mesh.Quic.Native.Tests/CultMeshNativeQuicRealtimeTransportTests.cs index afa74426..7eb99edc 100644 --- a/tests/GameCult.Mesh.Quic.Native.Tests/CultMeshNativeQuicRealtimeTransportTests.cs +++ b/tests/GameCult.Mesh.Quic.Native.Tests/CultMeshNativeQuicRealtimeTransportTests.cs @@ -22,7 +22,7 @@ public sealed class CultMeshNativeQuicRealtimeTransportTests var connector = new CultMeshNativeQuicRealtimeTransportConnector(); using var client = await connector.ConnectAsync( new CultMeshTransportCandidate(endpoint!), - CultMeshEndpointId.Parse("aetheria.local")); + new CultMeshSessionTarget("aetheria", "aetheria.local")); using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10)); var frame = await client.ReceiveAsync(timeout.Token); @@ -49,7 +49,7 @@ public sealed class CultMeshNativeQuicRealtimeTransportTests using var client = await connector.ConnectAsync( new CultMeshTransportCandidate(endpoint), - CultMeshEndpointId.Parse("aetheria.local")); + new CultMeshSessionTarget("aetheria", "aetheria.local")); var expected = new CultMeshRealtimeFrame { ChannelId = "aetheria.entities", @@ -92,7 +92,7 @@ public sealed class CultMeshNativeQuicRealtimeTransportTests var connect = () => connector.ConnectAsync( new CultMeshTransportCandidate(endpoint), - CultMeshEndpointId.Parse("aetheria.local")); + new CultMeshSessionTarget("aetheria", "aetheria.local")); await connect.Should().ThrowAsync() .WithMessage("*certificate*pin*"); @@ -114,10 +114,10 @@ public sealed class CultMeshNativeQuicRealtimeTransportTests var connector = new CultMeshNativeQuicRealtimeTransportConnector(); var departedClient = await connector.ConnectAsync( new CultMeshTransportCandidate(endpoint), - CultMeshEndpointId.Parse("aetheria.local")); + new CultMeshSessionTarget("aetheria", "aetheria.local")); using var healthyClient = await connector.ConnectAsync( new CultMeshTransportCandidate(endpoint), - CultMeshEndpointId.Parse("aetheria.local")); + new CultMeshSessionTarget("aetheria", "aetheria.local")); await WaitUntilAsync(() => server.ConnectionCount == 2); await server.BroadcastAsync(Frame(sequence: 1)); using var receiveTimeout = new CancellationTokenSource(TimeSpan.FromSeconds(5)); diff --git a/tests/GameCult.Mesh.Quic.Tests/CultMeshQuicRealtimeTransportTests.cs b/tests/GameCult.Mesh.Quic.Tests/CultMeshQuicRealtimeTransportTests.cs index 8d90f147..68afda10 100644 --- a/tests/GameCult.Mesh.Quic.Tests/CultMeshQuicRealtimeTransportTests.cs +++ b/tests/GameCult.Mesh.Quic.Tests/CultMeshQuicRealtimeTransportTests.cs @@ -40,7 +40,7 @@ public sealed class CultMeshQuicRealtimeTransportTests }); using var client = await connector.ConnectAsync( new CultMeshTransportCandidate($"cultmesh-state+quic://127.0.0.1:{listener.LocalEndPoint.Port}"), - CultMeshEndpointId.Parse("service:aetheria.daemon")); + new CultMeshSessionTarget("aetheria", "service:aetheria.daemon")); await using var serverConnection = await accept; client.TransportId.Should().Be("msquic-realtime"); @@ -62,7 +62,7 @@ public sealed class CultMeshQuicRealtimeTransportTests using var client = await connector.ConnectAsync( new CultMeshTransportCandidate(endpoint), - CultMeshEndpointId.Parse("service:aetheria.daemon")); + new CultMeshSessionTarget("aetheria", "service:aetheria.daemon")); client.TransportId.Should().Be("msquic-realtime"); await WaitUntilAsync(() => server.ConnectionCount == 1); @@ -78,8 +78,8 @@ public sealed class CultMeshQuicRealtimeTransportTests ListenEndPoint = new IPEndPoint(IPAddress.Loopback, 0), ServerCertificate = certificate }); - var endpointId = CultMeshEndpointId.Parse("service:aetheria.daemon"); - var target = new CultMeshSessionTarget("aetheria", endpointId.Value); + var runtimeId = CultMeshRuntimeId.Parse("service:aetheria.daemon"); + var target = new CultMeshSessionTarget("aetheria", runtimeId.Value); using var sessions = CreateSessions(server, out var validatedIdentity); CultMeshRealtimeSession session; try @@ -105,7 +105,7 @@ public sealed class CultMeshQuicRealtimeTransportTests new[] { firstAtServer.Sequence, secondAtServer.Sequence }.Should().Equal(1, 2); new[] { firstAtClient.Sequence, secondAtClient.Sequence }.Should().Equal(3, 4); firstAtClient.Payload.ToArray().Should().Equal(3, 4, 5); - validatedIdentity.Value.Should().Be(endpointId.Value); + validatedIdentity.Value.Should().Be(runtimeId.Value); } [Test] @@ -118,8 +118,8 @@ public sealed class CultMeshQuicRealtimeTransportTests ListenEndPoint = new IPEndPoint(IPAddress.Loopback, 0), ServerCertificate = certificate }); - var endpointId = CultMeshEndpointId.Parse("service:aetheria.daemon"); - var target = new CultMeshSessionTarget("aetheria", endpointId.Value); + var runtimeId = CultMeshRuntimeId.Parse("service:aetheria.daemon"); + var target = new CultMeshSessionTarget("aetheria", runtimeId.Value); using var sessions = CreateSessions(server, out _); var session = await sessions.ConnectRealtimeAsync(target); await WaitUntilAsync(() => server.ConnectionCount == 1); @@ -148,8 +148,8 @@ public sealed class CultMeshQuicRealtimeTransportTests ListenEndPoint = new IPEndPoint(IPAddress.Loopback, 0), ServerCertificate = certificate }); - var endpointId = CultMeshEndpointId.Parse("service:aetheria.daemon"); - var target = new CultMeshSessionTarget("aetheria", endpointId.Value); + var runtimeId = CultMeshRuntimeId.Parse("service:aetheria.daemon"); + var target = new CultMeshSessionTarget("aetheria", runtimeId.Value); using var sessions = CreateSessions(server, out _); var session = await sessions.ConnectRealtimeAsync(target); diff --git a/tests/GameCult.Mesh.Tests/CultMeshBodySessionTests.cs b/tests/GameCult.Mesh.Tests/CultMeshBodySessionTests.cs index bdf9928f..81ee15cc 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshBodySessionTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshBodySessionTests.cs @@ -53,6 +53,13 @@ public sealed class CultMeshBodySessionTests RuntimeId = "cultmesh-body-rudp-test", Socket = socket, MaxFragmentBytes = 1024, MaxPendingReliablePackets = 8192 }); + var endpoint = $"rudp://127.0.0.1:{server.LocalEndPoint.Port}"; + using var identityServer = new CultMeshSessionIdentityServer( + server, + "aetheria.daemon", + new[] { "aetheria" }, + new[] { CultMeshProtocols.Bodies.Value }, + new[] { "aetheria.daemon@" + endpoint }); using var bodyServer = new CultMeshBodyServer(server, store); using var pumpCancellation = new CancellationTokenSource(); var pump = Task.Run(async () => @@ -64,7 +71,6 @@ public sealed class CultMeshBodySessionTests if (progress.TransportItemsConsumed == 0) await Task.Delay(1, pumpCancellation.Token); } }); - var endpoint = $"rudp://127.0.0.1:{server.LocalEndPoint.Port}"; using var discovery = new CultMeshDiscoveryService(new[] { new RouteSource(endpoint) }); using var sessions = new CultMeshSessionManager(discovery, new ICultMeshTransportConnector[] { new CultMeshSchemaTransportConnector() }); @@ -179,7 +185,7 @@ public sealed class CultMeshBodySessionTests ((Func)_handlers[typeof(T)])(message, peer); } - private sealed class LoopbackClient : ICultNetSchemaClient + private sealed class LoopbackClient : ICultNetSchemaClient, ICultMeshVerifiedSchemaClient { private readonly LoopbackServer _server; private readonly Dictionary> _handlers = new(); @@ -208,6 +214,8 @@ public sealed class CultMeshBodySessionTests foreach (var value in values.ToArray()) ((Action)value)(message); } public void Dispose() { } + public bool IsVerifiedFor(string verseId, string authorityRuntimeId, string protocolId, string routeGeneration) => + verseId == "aetheria" && authorityRuntimeId == "aetheria.daemon"; } private sealed class LoopbackPeer : ICultNetSchemaServerPeer diff --git a/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs b/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs index d88b5738..e603415e 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs @@ -303,7 +303,7 @@ public sealed class CultMeshClientTests result.MessageId.Should().Be("pilot-command-1"); result.Status.Should().Be("accepted"); - result.SourceRuntimeId.Should().Be("provider-daemon"); + result.SourceRuntimeId.Should().Be("aetheria-daemon"); result.Value.ReceiptId.Should().Be("receipt:pilot-command-1"); result.Value.Count.Should().Be(2); connector.Clients.Should().ContainSingle(); @@ -370,6 +370,31 @@ public sealed class CultMeshClientTests connector.Clients[0].Operations.Should().ContainSingle(); } + [Test] + public async Task InvokeOperation_RejectsReceiptFromAnotherRuntime() + { + var connector = new DocumentConnector { ResponseSourceRuntimeId = "intruder-daemon" }; + using var mesh = new CultMeshClient(new CultMeshClientOptions + { + RendezvousEndpoints = new[] { "rudp://odin:3076" }, + Discovery = new CultMeshVerseDiscoveryClientOptions { CreateClient = () => new RendezvousClient() }, + Connectors = new[] { connector } + }); + + Func invoke = async () => await mesh.InvokeAsync( + Target, + "tests.counter", + "tests.counter.increment", + "tests.counter.increment_request.v1", + "tests.counter.increment_receipt.v1", + new ClientOperationRequest { Amount = 2 }, + sourceRuntimeId: "pilot-one", + idempotencyKey: "pilot-command-wrong-source"); + + var failure = await invoke.Should().ThrowAsync(); + failure.Which.Failure.Reason.Should().Be(CultMeshSessionFailureReason.Authority); + } + [Test] public async Task Dispose_TerminatesDocumentWaitingForInitialSnapshot() { @@ -438,13 +463,15 @@ public sealed class CultMeshClientTests } } - private sealed class ConnectedClient : ICultNetSchemaClient + private sealed class ConnectedClient : ICultNetSchemaClient, ICultMeshVerifiedSchemaClient { public bool Connected => true; public void Connect(string host, int port) { } public void SendCultNet(T message) where T : ICultNetSchemaMessage { } public void OnCultNet(Action callback) where T : ICultNetSchemaMessage { } public void Dispose() { } + public bool IsVerifiedFor(string verseId, string authorityRuntimeId, string protocolId, string routeGeneration) => + verseId == "aetheria" && authorityRuntimeId == "aetheria-daemon"; } private sealed class DocumentConnector : ICultMeshTransportConnector @@ -454,6 +481,7 @@ public sealed class CultMeshClientTests public bool SuppressFirstSubscriptionSnapshot { get; set; } public bool RejectOperations { get; set; } public bool FailFirstOperationBeforeResponse { get; set; } + public string ResponseSourceRuntimeId { get; set; } = "aetheria-daemon"; public string ConnectorId => "document-test"; public int Priority => 0; public int SubscribeCount => Clients.Sum(client => client.SubscribeCount); @@ -469,13 +497,14 @@ public sealed class CultMeshClientTests ? int.MaxValue : SuppressFirstSubscriptionSnapshot && Clients.Count == 0 ? 1 : 0, rejectOperations: RejectOperations, - failOperationBeforeResponse: FailFirstOperationBeforeResponse && Clients.Count == 0); + failOperationBeforeResponse: FailFirstOperationBeforeResponse && Clients.Count == 0, + responseSourceRuntimeId: ResponseSourceRuntimeId); Clients.Add(client); return Task.FromResult(client); } } - private sealed class DocumentClient : ICultNetSchemaClient, ICultNetSchemaClientHealth + private sealed class DocumentClient : ICultNetSchemaClient, ICultNetSchemaClientHealth, ICultMeshVerifiedSchemaClient { private readonly List> _snapshots = new(); private readonly List> _operationResponses = new(); @@ -484,17 +513,20 @@ public sealed class CultMeshClientTests private readonly TaskCompletionSource _failure = new(TaskCreationOptions.RunContinuationsAsynchronously); private readonly bool _rejectOperations; private bool _failOperationBeforeResponse; + private readonly string _responseSourceRuntimeId; private int _snapshotsToSuppress; public DocumentClient( string text, int snapshotsToSuppress = 0, bool rejectOperations = false, - bool failOperationBeforeResponse = false) + bool failOperationBeforeResponse = false, + string responseSourceRuntimeId = "aetheria-daemon") { _text = text; _snapshotsToSuppress = snapshotsToSuppress; _rejectOperations = rejectOperations; _failOperationBeforeResponse = failOperationBeforeResponse; + _responseSourceRuntimeId = responseSourceRuntimeId; var cache = CultMesh.CreateCultCacheDocumentRegistry(typeof(ClientTestDocument)); _documents = CultMesh.CreateCultNetDocumentRegistry(new[] { typeof(ClientTestDocument) }, cache); } @@ -514,6 +546,7 @@ public sealed class CultMeshClientTests } if (message is CultNetOperationRequestMessage operation) { + operation.TargetRuntimeId.Should().Be("aetheria-daemon"); Operations.Add(operation); if (_failOperationBeforeResponse) { @@ -539,7 +572,7 @@ public sealed class CultMeshClientTests failure, CultNetSchemaMessageSerialization.Options)), Diagnostics = new[] { failure.Message }, - SourceRuntimeId = "provider-daemon" + SourceRuntimeId = _responseSourceRuntimeId }; foreach (var handler in _operationResponses.ToArray()) handler(rejected); return; @@ -562,7 +595,7 @@ public sealed class CultMeshClientTests Payload = Convert.ToBase64String(MessagePackSerializer.Serialize( receipt, CultNetSchemaMessageSerialization.Options)), - SourceRuntimeId = "provider-daemon" + SourceRuntimeId = _responseSourceRuntimeId }; foreach (var handler in _operationResponses.ToArray()) handler(operationResponse); return; @@ -596,6 +629,8 @@ public sealed class CultMeshClientTests } public void Dispose() { } public void Fail(Exception error) => _failure.TrySetResult(error); + public bool IsVerifiedFor(string verseId, string authorityRuntimeId, string protocolId, string routeGeneration) => + verseId == "aetheria" && authorityRuntimeId == "aetheria-daemon"; } private static async Task WaitUntilAsync(Func condition) diff --git a/tests/GameCult.Mesh.Tests/CultMeshContentSessionTests.cs b/tests/GameCult.Mesh.Tests/CultMeshContentSessionTests.cs index d63254d1..fa11072c 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshContentSessionTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshContentSessionTests.cs @@ -17,6 +17,7 @@ namespace GameCult.Mesh.Tests; [TestFixture] public sealed class CultMeshContentSessionTests { + private const string RouteGeneration = "content-test-route-1"; private string _directory = null!; [SetUp] @@ -41,7 +42,13 @@ public sealed class CultMeshContentSessionTests StringComparer.Ordinal); using var contentServer = new CultMeshTcpContentServer( new TcpListener(IPAddress.Loopback, 0), - hash => providerChunks.TryGetValue(hash, out var chunk) ? chunk : null); + hash => providerChunks.TryGetValue(hash, out var chunk) ? chunk : null, + new CultMeshTcpContentServerOptions + { + VerseId = "aetheria", + AuthorityRuntimeId = "aetheria.daemon", + RouteGeneration = RouteGeneration + }); var endpoint = $"{CultMeshTcpContentTransportConnector.Scheme}://127.0.0.1:{contentServer.LocalEndPoint.Port}"; var connector = new CultMeshTcpContentTransportConnector(); using var discovery = new CultMeshDiscoveryService(new[] { new RouteSource(endpoint) }); @@ -73,6 +80,34 @@ public sealed class CultMeshContentSessionTests "all chunk requests borrow one identity-first content session"); } + [Test] + public async Task TcpContentSessionRejectsEndpointServingAnotherAuthority() + { + using var content = new CultCache(CultMesh.CreateCultCacheDocumentRegistry( + typeof(CultMeshCdnArtifactManifest), typeof(CultMeshCdnArtifactChunk))); + using var contentServer = new CultMeshTcpContentServer( + new TcpListener(IPAddress.Loopback, 0), + content, + new CultMeshTcpContentServerOptions + { + VerseId = "aetheria", + AuthorityRuntimeId = "intruder.daemon", + RouteGeneration = RouteGeneration + }); + var endpoint = $"{CultMeshTcpContentTransportConnector.Scheme}://127.0.0.1:{contentServer.LocalEndPoint.Port}"; + using var discovery = new CultMeshDiscoveryService(new[] { new RouteSource(endpoint) }); + using var sessions = new CultMeshSessionManager( + discovery, + Array.Empty(), + new ICultMeshContentTransportConnector[] { new CultMeshTcpContentTransportConnector() }); + + Func connect = async () => await sessions.ConnectContentAsync( + new CultMeshSessionTarget("aetheria", "aetheria.daemon")); + + var error = await connect.Should().ThrowAsync(); + error.Which.Failure.Reason.Should().Be(CultMeshSessionFailureReason.Authority); + } + [Test] public async Task RudpContentSessionCarriesConcurrentChunkWindowWithoutPerFragmentSchedulerDelay() { @@ -91,6 +126,12 @@ public sealed class CultMeshContentSessionTests MaxPendingReliablePackets = 8192 }); using var contentServer = new CultMeshLegacyRudpContentServer(wireServer, providerCache); + using var identityServer = new CultMeshSessionIdentityServer( + wireServer, + "aetheria.daemon", + new[] { "aetheria" }, + new[] { CultMeshProtocols.Content.Value }, + new[] { RouteGeneration }); using var pumpCancellation = new CancellationTokenSource(); var pump = Task.Run(async () => { @@ -196,8 +237,14 @@ public sealed class CultMeshContentSessionTests "Aetheria", CultMeshVerseAuthorityModel.OperatorCluster, new CultMeshVerseCompatibility("cultmesh.v1", "rules"), - new[] { _endpoint }, - new[] { "aetheria.daemon" }), + authorityRoutes: new[] + { + new CultMeshAuthorityRoute( + "aetheria.daemon", + _endpoint, + new[] { CultMeshProtocols.Content.Value }, + generation: RouteGeneration) + }), SourceId, now, now.AddMinutes(1), @@ -241,7 +288,7 @@ public sealed class CultMeshContentSessionTests ((Func)_handlers[typeof(TMessage)])(message, peer); } - private sealed class LoopbackSchemaClient : ICultNetSchemaClient + private sealed class LoopbackSchemaClient : ICultNetSchemaClient, ICultMeshVerifiedSchemaClient { private readonly LoopbackSchemaServer _server; private readonly Dictionary> _handlers = new(); @@ -270,6 +317,8 @@ public sealed class CultMeshContentSessionTests handlers.Add(callback); } public void Dispose() { } + public bool IsVerifiedFor(string verseId, string authorityRuntimeId, string protocolId, string routeGeneration) => + verseId == "aetheria" && authorityRuntimeId == "aetheria.daemon"; public void Emit(T message) where T : ICultNetSchemaMessage { if (!_handlers.TryGetValue(typeof(T), out var handlers)) return; diff --git a/tests/GameCult.Mesh.Tests/CultMeshDiscoveryServiceTests.cs b/tests/GameCult.Mesh.Tests/CultMeshDiscoveryServiceTests.cs index 7d2938e4..2313a5bd 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshDiscoveryServiceTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshDiscoveryServiceTests.cs @@ -295,7 +295,7 @@ public sealed class CultMeshDiscoveryServiceTests CultMeshVerseAuthorityModel.OperatorCluster, new CultMeshVerseCompatibility("cultmesh.v0", "rules"), new[] { endpoint }, - new[] { "odin:aetheria", "odin:games", "aetheria" }), + new[] { "aetheria" }), sourceId, clock.UtcNow, clock.UtcNow + ttl, diff --git a/tests/GameCult.Mesh.Tests/CultMeshSessionManagerTests.cs b/tests/GameCult.Mesh.Tests/CultMeshSessionManagerTests.cs index fe9ec370..46e0672f 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshSessionManagerTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshSessionManagerTests.cs @@ -79,6 +79,81 @@ public sealed class CultMeshSessionManagerTests fastClient.DisposeCount.Should().Be(0); } + [Test] + public async Task Connect_NeverAttemptsRouteBoundToAnotherAuthority() + { + var clock = new ManualSessionClock(); + var descriptor = new CultMeshVerseDescriptor( + "aetheria", + "Aetheria", + CultMeshVerseAuthorityModel.OperatorCluster, + new CultMeshVerseCompatibility("cultmesh.v0", "rules"), + authorityRoutes: new[] + { + new CultMeshAuthorityRoute("decoy-daemon", "rudp://decoy:3076"), + new CultMeshAuthorityRoute("aetheria-daemon", "rudp://authority:3076") + }); + using var discovery = new CultMeshDiscoveryService( + new[] { new StaticRouteSource(clock, descriptor) }, + new CultMeshDiscoveryServiceOptions { Clock = clock }); + var attempts = new List(); + var connector = new FakeConnector((candidate, _) => + { + attempts.Add(candidate.Endpoint); + return Task.FromResult(new FakeSchemaClient()); + }); + using var manager = new CultMeshSessionManager(discovery, new[] { connector }); + + var session = await manager.ConnectAsync(Target, CultMeshProtocols.Documents); + + session.State.Path!.Endpoint.Should().Be("rudp://authority:3076"); + attempts.Should().Equal("rudp://authority:3076"); + } + + [Test] + public void Connect_RejectsRouteWhoseNativeIdentityDoesNotMatchTarget() + { + var clock = new ManualSessionClock(); + using var discovery = Discovery(clock, () => new[] { "rudp://decoy:3076" }); + var connector = new FakeConnector((_, _) => + Task.FromResult(new NativeMismatchClient())); + using var manager = new CultMeshSessionManager(discovery, new[] { connector }); + + var error = Assert.ThrowsAsync(() => + manager.ConnectAsync(Target, CultMeshProtocols.Documents)); + + error!.Failure.Reason.Should().Be(CultMeshSessionFailureReason.Authority); + } + + [Test] + public void Connect_RejectsPortableHandshakeFromWrongRuntime() + { + var clock = new ManualSessionClock(); + using var discovery = Discovery(clock, () => new[] { "rudp://decoy:3076" }); + var connector = new FakeConnector((_, _) => + Task.FromResult(new HandshakeSchemaClient("decoy-daemon"))); + using var manager = new CultMeshSessionManager(discovery, new[] { connector }); + + var error = Assert.ThrowsAsync(() => + manager.ConnectAsync(Target, CultMeshProtocols.Documents)); + + error!.Failure.Reason.Should().Be(CultMeshSessionFailureReason.Authority); + } + + [Test] + public void Descriptor_RejectsAmbiguousLegacyMultiAuthorityRoutes() + { + var action = () => new CultMeshVerseDescriptor( + "aetheria", + "Aetheria", + CultMeshVerseAuthorityModel.OperatorCluster, + new CultMeshVerseCompatibility("cultmesh.v0", "rules"), + discoveryEndpoints: new[] { "rudp://shared:3076" }, + authorityRuntimeIds: new[] { "authority-a", "authority-b" }); + + action.Should().Throw().WithMessage("*ambiguous*"); + } + [Test] public async Task Connect_CallerCancellationDoesNotCancelSharedAttempt() { @@ -308,6 +383,30 @@ public sealed class CultMeshSessionManagerTests CultMeshDiscoveryTrust.Signed); } + private sealed class StaticRouteSource : ICultMeshLookupSource + { + private readonly ManualSessionClock _clock; + private readonly CultMeshVerseDescriptor _descriptor; + public StaticRouteSource(ManualSessionClock clock, CultMeshVerseDescriptor descriptor) + { + _clock = clock; + _descriptor = descriptor; + } + public string SourceId => "odin"; + public Task> LookupAsync( + CultMeshDiscoveryQuery query, + CancellationToken cancellationToken = default) => + Task.FromResult>(new[] + { + new CultMeshDiscoveryObservation( + _descriptor, + SourceId, + _clock.UtcNow, + _clock.UtcNow.AddMinutes(1), + CultMeshDiscoveryTrust.Signed) + }); + } + private sealed class FakeConnector : ICultMeshTransportConnector { private readonly Func> _connect; @@ -324,7 +423,7 @@ public sealed class CultMeshSessionManagerTests } } - private sealed class FakeSchemaClient : ICultNetSchemaClient, ICultNetSchemaClientHealth + private sealed class FakeSchemaClient : ICultNetSchemaClient, ICultNetSchemaClientHealth, ICultMeshVerifiedSchemaClient { private readonly TaskCompletionSource _failure = new(TaskCreationOptions.RunContinuationsAsynchronously); private readonly List> _handlers = new(); @@ -340,6 +439,8 @@ public sealed class CultMeshSessionManagerTests _handlers.Add(message => callback((T)(object)message)); } public void Dispose() => Interlocked.Increment(ref _disposeCount); + public bool IsVerifiedFor(string verseId, string authorityRuntimeId, string protocolId, string routeGeneration) => + verseId == "aetheria" && authorityRuntimeId == "aetheria-daemon"; public void Fail(Exception error) => _failure.TrySetResult(error); public void Emit(CultNetErrorMessage message) { foreach (var handler in _handlers.ToArray()) handler(message); } } @@ -360,7 +461,46 @@ public sealed class CultMeshSessionManagerTests public void Dispose() { } } - private sealed class RespondingSchemaClient : ICultNetSchemaClient + private sealed class NativeMismatchClient : ICultNetSchemaClient, ICultMeshVerifiedSchemaClient + { + public bool Connected => true; + public void Connect(string host, int port) { } + public void SendCultNet(T message) where T : ICultNetSchemaMessage { } + public void OnCultNet(Action callback) where T : ICultNetSchemaMessage { } + public bool IsVerifiedFor(string verseId, string authorityRuntimeId, string protocolId, string routeGeneration) => false; + public void Dispose() { } + } + + private sealed class HandshakeSchemaClient : ICultNetSchemaClient + { + private readonly string _actualRuntimeId; + private readonly List> _handlers = new(); + public HandshakeSchemaClient(string actualRuntimeId) => _actualRuntimeId = actualRuntimeId; + public bool Connected => true; + public void Connect(string host, int port) { } + public void SendCultNet(T message) where T : ICultNetSchemaMessage + { + if (message is not CultMeshSessionOpenMessage request) return; + var response = new CultMeshSessionAcceptedMessage + { + MessageId = request.MessageId, + Accepted = true, + VerseId = request.VerseId, + AuthorityRuntimeId = _actualRuntimeId, + ProtocolId = request.ProtocolId, + RouteGeneration = request.RouteGeneration + }; + foreach (var handler in _handlers.ToArray()) handler(response); + } + public void OnCultNet(Action callback) where T : ICultNetSchemaMessage + { + if (typeof(T) == typeof(CultMeshSessionAcceptedMessage)) + _handlers.Add(message => callback((T)(object)message)); + } + public void Dispose() { } + } + + private sealed class RespondingSchemaClient : ICultNetSchemaClient, ICultMeshVerifiedSchemaClient { private readonly List> _handlers = new(); private int _disposeCount; @@ -385,9 +525,11 @@ public sealed class CultMeshSessionManagerTests _handlers.Add(message => callback((T)(object)message)); } public void Dispose() => Interlocked.Increment(ref _disposeCount); + public bool IsVerifiedFor(string verseId, string authorityRuntimeId, string protocolId, string routeGeneration) => + verseId == "aetheria" && authorityRuntimeId == "aetheria-daemon"; } - private sealed class PeerExchangeSchemaClient : ICultNetSchemaClient + private sealed class PeerExchangeSchemaClient : ICultNetSchemaClient, ICultMeshVerifiedSchemaClient { private readonly List> _handlers = new(); public bool Connected => true; @@ -413,9 +555,11 @@ public sealed class CultMeshSessionManagerTests _handlers.Add(message => callback((T)(object)message)); } public void Dispose() { } + public bool IsVerifiedFor(string verseId, string authorityRuntimeId, string protocolId, string routeGeneration) => + verseId == "aetheria" && authorityRuntimeId == "aetheria-daemon"; } - private sealed class LeaseSchemaClient : ICultNetSchemaClient + private sealed class LeaseSchemaClient : ICultNetSchemaClient, ICultMeshVerifiedSchemaClient { private readonly List> _handlers = new(); private int _disposeCount; @@ -430,6 +574,8 @@ public sealed class CultMeshSessionManagerTests } public void Emit(CultNetErrorMessage message) { foreach (var handler in _handlers.ToArray()) handler(message); } public void Dispose() => Interlocked.Increment(ref _disposeCount); + public bool IsVerifiedFor(string verseId, string authorityRuntimeId, string protocolId, string routeGeneration) => + verseId == "aetheria" && authorityRuntimeId == "aetheria-daemon"; } private sealed class ManualSessionClock : ICultMeshClock diff --git a/tests/GameCult.Mesh.Tests/CultMeshTransportModularityTests.cs b/tests/GameCult.Mesh.Tests/CultMeshTransportModularityTests.cs index 5fe32fed..35b4a71c 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshTransportModularityTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshTransportModularityTests.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Net; using System.Net.Sockets; using System.Threading; @@ -15,10 +16,17 @@ namespace GameCult.Mesh.Tests; [TestFixture] public sealed class CultMeshTransportModularityTests { + private const string RouteGeneration = "transport-modularity-route-1"; [Test] public async Task SchemaSessionPrefersTcpTierWithoutTouchingLegacyDatagrams() { using var server = new TcpFramedCultNetSchemaServer(new TcpListener(IPAddress.Loopback, 0)); + using var identity = new CultMeshSessionIdentityServer( + server, + "aetheria.daemon", + new[] { "aetheria" }, + new[] { CultMeshProtocols.Documents.Value }, + new[] { RouteGeneration }); server.OnCultNet((message, peer) => { peer.SendCultNet(new CultNetErrorMessage { Error = "tcp:" + message.RuntimeId }); @@ -61,7 +69,15 @@ public sealed class CultMeshTransportModularityTests using var content = new CultCache(CultMesh.CreateCultCacheDocumentRegistry( typeof(CultMeshCdnArtifactManifest), typeof(CultMeshCdnArtifactChunk))); await CultMeshCdn.PublishAsync(content, artifact); - using var server = new CultMeshTcpContentServer(new TcpListener(IPAddress.Loopback, 0), content); + using var server = new CultMeshTcpContentServer( + new TcpListener(IPAddress.Loopback, 0), + content, + new CultMeshTcpContentServerOptions + { + VerseId = "aetheria", + AuthorityRuntimeId = "aetheria.daemon", + RouteGeneration = RouteGeneration + }); var tcpEndpoint = $"{CultMeshTcpContentTransportConnector.Scheme}://127.0.0.1:{server.LocalEndPoint.Port}"; var legacy = new RejectingLegacyContentConnector(); using var discovery = new CultMeshDiscoveryService(new[] @@ -156,6 +172,26 @@ public sealed class CultMeshTransportModularityTests .WithMessage("*No realtime state connectors are configured*"); } + [Test] + public async Task RealtimeSessionRejectsConnectedTransportWithoutAuthorityProof() + { + using var discovery = new CultMeshDiscoveryService(new[] + { + new RouteSource("cultmesh-state+quic://127.0.0.1:3076") + }); + using var sessions = new CultMeshSessionManager( + discovery, + Array.Empty(), + Array.Empty(), + new ICultMeshRealtimeTransportConnector[] { new UnverifiedRealtimeConnector() }); + + Func connect = async () => await sessions.ConnectRealtimeAsync( + new CultMeshSessionTarget("aetheria", "aetheria.daemon")); + + var error = await connect.Should().ThrowAsync(); + error.Which.Failure.Reason.Should().Be(CultMeshSessionFailureReason.Authority); + } + private sealed class RouteSource : ICultMeshLookupSource { private readonly string[] _endpoints; @@ -176,8 +212,11 @@ public sealed class CultMeshTransportModularityTests "Aetheria", CultMeshVerseAuthorityModel.OperatorCluster, new CultMeshVerseCompatibility("cultmesh.v1", "rules"), - _endpoints, - new[] { "aetheria.daemon" }), + authorityRoutes: _endpoints.Select(endpoint => new CultMeshAuthorityRoute( + "aetheria.daemon", + endpoint, + protocolIds: null, + generation: RouteGeneration))), SourceId, now, now.AddMinutes(1), @@ -214,7 +253,7 @@ public sealed class CultMeshTransportModularityTests candidate.Endpoint.StartsWith("rudp://", StringComparison.OrdinalIgnoreCase); public Task ConnectAsync( CultMeshTransportCandidate candidate, - CultMeshEndpointId endpointId, + CultMeshSessionTarget target, CancellationToken cancellationToken = default) { Interlocked.Increment(ref _connectCount); @@ -232,24 +271,70 @@ public sealed class CultMeshTransportModularityTests candidate.Endpoint.StartsWith("cultmesh-state+quic://", StringComparison.OrdinalIgnoreCase); public Task ConnectAsync( CultMeshTransportCandidate candidate, - CultMeshEndpointId endpointId, + CultMeshSessionTarget target, CancellationToken cancellationToken = default) { Interlocked.Increment(ref _connectCount); - return Task.FromResult(new LoopbackRealtimeTransport(candidate.Endpoint)); + return Task.FromResult( + new LoopbackRealtimeTransport(candidate.Endpoint, target, candidate.Generation)); } } - private sealed class LoopbackRealtimeTransport : ICultMeshRealtimeTransport + private sealed class UnverifiedRealtimeConnector : ICultMeshRealtimeTransportConnector + { + public string ConnectorId => "unverified-realtime"; + public int Priority => 0; + public bool CanConnect(CultMeshTransportCandidate candidate) => true; + public Task ConnectAsync( + CultMeshTransportCandidate candidate, + CultMeshSessionTarget target, + CancellationToken cancellationToken = default) => + Task.FromResult(new UnverifiedRealtimeTransport(candidate.Endpoint)); + } + + private sealed class UnverifiedRealtimeTransport : ICultMeshRealtimeTransport + { + public UnverifiedRealtimeTransport(string endpoint) => Endpoint = endpoint; + public string TransportId => "unverified-realtime"; + public string Endpoint { get; } + public Task SendAsync(CultMeshRealtimeFrame frame, CancellationToken cancellationToken = default) => + Task.CompletedTask; + public Task ReceiveAsync(CancellationToken cancellationToken = default) => + Task.FromException(new InvalidOperationException()); + public void Dispose() { } + } + + private sealed class LoopbackRealtimeTransport : ICultMeshRealtimeTransport, ICultMeshVerifiedTransport { private readonly Queue _frames = new(); private readonly SemaphoreSlim _available = new(0); private bool _disposed; - public LoopbackRealtimeTransport(string endpoint) => Endpoint = endpoint; + private readonly CultMeshSessionTarget _target; + private readonly string _routeGeneration; + + public LoopbackRealtimeTransport( + string endpoint, + CultMeshSessionTarget target, + string routeGeneration) + { + Endpoint = endpoint; + _target = target; + _routeGeneration = routeGeneration; + } public string TransportId => "test-quic-state"; public string Endpoint { get; } + public bool IsVerifiedFor( + string verseId, + string authorityRuntimeId, + string protocolId, + string routeGeneration) => + string.Equals(_target.VerseId, verseId, StringComparison.Ordinal) && + string.Equals(_target.AuthorityRuntimeId, authorityRuntimeId, StringComparison.Ordinal) && + string.Equals(CultMeshProtocols.RealtimeState.Value, protocolId, StringComparison.Ordinal) && + string.Equals(_routeGeneration, routeGeneration, StringComparison.Ordinal); + public Task SendAsync(CultMeshRealtimeFrame frame, CancellationToken cancellationToken = default) { if (_disposed) throw new ObjectDisposedException(nameof(LoopbackRealtimeTransport)); diff --git a/tests/GameCult.Networking.Tests/CultNetOperationServerTests.cs b/tests/GameCult.Networking.Tests/CultNetOperationServerTests.cs index f82456fb..ca36a2f4 100644 --- a/tests/GameCult.Networking.Tests/CultNetOperationServerTests.cs +++ b/tests/GameCult.Networking.Tests/CultNetOperationServerTests.cs @@ -77,6 +77,41 @@ namespace GameCult.Networking.Tests Is.EqualTo(4)); } + [Test] + public async Task RejectsRequestAddressedToAnotherRuntimeBeforeApplicationHandler() + { + var transport = new FakeServer(); + var peer = new FakePeer(); + var calls = 0; + using var operations = new CultNetOperationServer(transport, "sample.provider") + .Register( + "sample.counter", + "sample.counter.add", + "sample.add.v1", + "sample.add_receipt.v1", + context => + { + calls++; + return Task.FromResult(new AddReceipt { Count = context.Value.Amount }); + }); + var request = Request(new AddRequest { Amount = 3 }); + request.TargetRuntimeId = "other.provider"; + + await transport.DispatchAsync(request, peer); + + Assert.That(calls, Is.Zero); + var response = peer.Messages.OfType().Single(); + var failure = MessagePackSerializer.Deserialize( + Convert.FromBase64String(response.Payload), + CultNetSchemaMessageSerialization.Options); + Assert.Multiple(() => + { + Assert.That(response.Status, Is.EqualTo("denied")); + Assert.That(failure.Code, Is.EqualTo("target-runtime-mismatch")); + Assert.That(response.SourceRuntimeId, Is.EqualTo("sample.provider")); + }); + } + [Test] public async Task RejectsWrongSchemaBeforeApplicationHandler() { @@ -157,7 +192,8 @@ namespace GameCult.Networking.Tests Payload = Convert.ToBase64String(MessagePackSerializer.Serialize( value, CultNetSchemaMessageSerialization.Options)), - SourceRuntimeId = "sample.browser" + SourceRuntimeId = "sample.browser", + TargetRuntimeId = "sample.provider" }; [MessagePackObject] diff --git a/tests/GameCult.Networking.Tests/NetworkingTests.cs b/tests/GameCult.Networking.Tests/NetworkingTests.cs index dd4a63c9..03b4f76c 100644 --- a/tests/GameCult.Networking.Tests/NetworkingTests.cs +++ b/tests/GameCult.Networking.Tests/NetworkingTests.cs @@ -3627,8 +3627,19 @@ namespace GameCult.Networking.Tests "Aetheria", CultMeshVerseAuthorityModel.OperatorCluster, new CultMeshVerseCompatibility("cultmesh.v0", vanillaRules), - discoveryEndpoints: ["cultmesh://aetheria.example.test:3075"], - authorityRuntimeIds: ["gc-us-east", "gc-eu-west"]); + authorityRoutes: + [ + new CultMeshAuthorityRoute( + "gc-us-east", + "cultmesh://us-east.aetheria.example.test:3075", + [CultMeshProtocols.Documents.Value], + generation: "east-1"), + new CultMeshAuthorityRoute( + "gc-eu-west", + "cultmesh://eu-west.aetheria.example.test:3075", + [CultMeshProtocols.Documents.Value], + generation: "west-1") + ]); var modded = new CultMeshVerseDescriptor( "aetheria-skylands", "Aetheria: Skylands", diff --git a/tools/GameCult.TransportParity/Program.cs b/tools/GameCult.TransportParity/Program.cs index 04d7aafc..31c93e1e 100644 --- a/tools/GameCult.TransportParity/Program.cs +++ b/tools/GameCult.TransportParity/Program.cs @@ -339,6 +339,12 @@ static async Task MeasureCultMeshRudpAsync(byte[] payload) MaxPendingReliablePackets = 8192 }); using var contentServer = new CultMeshLegacyRudpContentServer(wireServer, providerCache); + using var identityServer = new CultMeshSessionIdentityServer( + wireServer, + "service:parity.provider", + ["parity"], + [CultMeshProtocols.Content.Value], + ["parity-route-1"]); using var pumpCancellation = new CancellationTokenSource(); var pump = Task.Run(async () => { @@ -359,7 +365,7 @@ static async Task MeasureCultMeshRudpAsync(byte[] payload) [new CultMeshLegacyRudpContentTransportConnector( new CultMeshLegacyRudpContentTransportOptions { ResponseTimeout = TimeSpan.FromMinutes(2) })]); var provider = new CultMeshSessionContentProvider( - "parity.provider", sessions, CultMeshEndpointId.Parse("service:parity.provider")); + "parity.provider", sessions, new CultMeshSessionTarget("parity", "service:parity.provider")); var directory = Path.Combine(Path.GetTempPath(), "cultmesh-transport-parity", Guid.NewGuid().ToString("N")); using var transferState = new CultCache(CultMesh.CreateCultCacheDocumentRegistry( typeof(CultMeshContentTransferStateDocument))); @@ -392,7 +398,14 @@ static async Task MeasureCultMeshTcpAsync(byte[] payload) await CultMeshCdn.PublishAsync(providerCache, artifact); using var contentServer = new CultMeshTcpContentServer( - new TcpListener(IPAddress.Loopback, 0), providerCache); + new TcpListener(IPAddress.Loopback, 0), + providerCache, + new CultMeshTcpContentServerOptions + { + VerseId = "parity", + AuthorityRuntimeId = "service:parity.provider", + RouteGeneration = "parity-route-1" + }); var endpoint = $"{CultMeshTcpContentTransportConnector.Scheme}://127.0.0.1:{contentServer.LocalEndPoint.Port}"; using var discovery = new CultMeshDiscoveryService([new RouteSource(endpoint)]); using var sessions = new CultMeshSessionManager( @@ -400,7 +413,7 @@ static async Task MeasureCultMeshTcpAsync(byte[] payload) Array.Empty(), [new CultMeshTcpContentTransportConnector()]); var provider = new CultMeshSessionContentProvider( - "parity.provider", sessions, CultMeshEndpointId.Parse("service:parity.provider")); + "parity.provider", sessions, new CultMeshSessionTarget("parity", "service:parity.provider")); var directory = Path.Combine(Path.GetTempPath(), "cultmesh-transport-parity", Guid.NewGuid().ToString("N")); using var transferState = new CultCache(CultMesh.CreateCultCacheDocumentRegistry( typeof(CultMeshContentTransferStateDocument))); @@ -479,8 +492,14 @@ internal sealed class RouteSource(string endpoint) : ICultMeshLookupSource new( new CultMeshVerseDescriptor( "parity", "Transport parity", CultMeshVerseAuthorityModel.OperatorCluster, - new CultMeshVerseCompatibility("cultmesh.v1", "parity"), [endpoint], - ["service:parity.provider"]), + new CultMeshVerseCompatibility("cultmesh.v1", "parity"), + authorityRoutes: + [ + new CultMeshAuthorityRoute( + "service:parity.provider", + endpoint, + generation: "parity-route-1") + ]), SourceId, now, now.AddMinutes(1), CultMeshDiscoveryTrust.Signed) ]; return Task.FromResult(observations); From 6835ea4c1063e504c79f03348ff85990af4cb4d5 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 17:39:59 +0200 Subject: [PATCH 095/283] Make Eve onboarding prove packaged authority routes --- .../EveBrowserNetworkSample.csproj | 11 ++- scripts/build-unity-package.ps1 | 13 +++- scripts/pack-nuget.ps1 | 13 +++- scripts/verify-eve-browser-network.mjs | 31 +++++++- scripts/verify-eve-getting-started.ps1 | 73 ++++++++++++------- .../getting-started/01-persist-typed-state.md | 2 +- .../getting-started/02-connect-by-identity.md | 15 +++- .../03-publish-an-eve-surface.md | 12 ++- .../04-run-the-multiruntime-game.md | 8 +- .../docs/getting-started/README.md | 20 ++++- .../GameCult.Networking.WebSockets.csproj | 2 + 11 files changed, 151 insertions(+), 49 deletions(-) diff --git a/samples/eve-browser-network/EveBrowserNetworkSample.csproj b/samples/eve-browser-network/EveBrowserNetworkSample.csproj index 7de0bdbd..c83a42df 100644 --- a/samples/eve-browser-network/EveBrowserNetworkSample.csproj +++ b/samples/eve-browser-network/EveBrowserNetworkSample.csproj @@ -4,11 +4,20 @@ enable enable $(MSBuildThisFileDirectory)..\..\..\Eve + false + 1.0.33 + 0.3.2 + $(PackageFeed) - + + + + + + diff --git a/scripts/build-unity-package.ps1 b/scripts/build-unity-package.ps1 index bb12e0c6..08366cc5 100644 --- a/scripts/build-unity-package.ps1 +++ b/scripts/build-unity-package.ps1 @@ -1,6 +1,7 @@ param( [string] $Configuration = "Release", [string] $OutputDirectory = "artifacts\unity\org.gamecult.cultlib", + [string] $NuGetConfig = "", [switch] $UpdateTemplate ) @@ -30,11 +31,19 @@ if (Test-Path -LiteralPath $outputRoot) { Remove-Item -LiteralPath $outputRoot -Recurse -Force } -dotnet publish $projectPath -c $Configuration -o $publishRoot +$publishArguments = @("publish", $projectPath, "-c", $Configuration, "-o", $publishRoot) +if (-not [string]::IsNullOrWhiteSpace($NuGetConfig)) { + $publishArguments += "-p:RestoreConfigFile=$([IO.Path]::GetFullPath($NuGetConfig))" +} +& dotnet @publishArguments if ($LASTEXITCODE -ne 0) { throw "CultLib publish failed with exit code $LASTEXITCODE" } -dotnet publish $quicProjectPath -c $Configuration -o $quicPublishRoot +$quicPublishArguments = @("publish", $quicProjectPath, "-c", $Configuration, "-o", $quicPublishRoot) +if (-not [string]::IsNullOrWhiteSpace($NuGetConfig)) { + $quicPublishArguments += "-p:RestoreConfigFile=$([IO.Path]::GetFullPath($NuGetConfig))" +} +& dotnet @quicPublishArguments if ($LASTEXITCODE -ne 0) { throw "CultLib native QUIC managed publish failed with exit code $LASTEXITCODE" } diff --git a/scripts/pack-nuget.ps1 b/scripts/pack-nuget.ps1 index 14fa7340..d6f4a224 100644 --- a/scripts/pack-nuget.ps1 +++ b/scripts/pack-nuget.ps1 @@ -1,6 +1,7 @@ param( [string] $Configuration = "Release", [string] $OutputDirectory = "artifacts\nuget", + [string] $PackageVersion = "", [switch] $SkipConsumerSmoke ) @@ -18,6 +19,7 @@ $projects = @( "src\GameCult.Caching.MessagePack.Analyzers\GameCult.Caching.MessagePack.Analyzers.csproj", "src\GameCult.Caching.MessagePack\GameCult.Caching.MessagePack.csproj", "src\GameCult.Networking\GameCult.Networking.csproj", + "src\GameCult.Networking.WebSockets\GameCult.Networking.WebSockets.csproj", "src\GameCult.Mesh\GameCult.Mesh.csproj" ) @@ -27,8 +29,14 @@ if (Test-Path -LiteralPath $outputRoot) { New-Item -ItemType Directory -Force -Path $outputRoot | Out-Null foreach ($project in $projects) { - dotnet pack (Join-Path $repoRoot $project) -c $Configuration -o $outputRoot ` - --nologo --verbosity quiet -p:NoWarn=1591%3BCS8632 + $packArguments = @( + "pack", (Join-Path $repoRoot $project), "-c", $Configuration, "-o", $outputRoot, + "--nologo", "--verbosity", "quiet", "-p:NoWarn=1591%3BCS8632" + ) + if (-not [string]::IsNullOrWhiteSpace($PackageVersion)) { + $packArguments += "-p:Version=$PackageVersion" + } + & dotnet @packArguments if ($LASTEXITCODE -ne 0) { throw "NuGet pack failed for $project with exit code $LASTEXITCODE" } @@ -48,6 +56,7 @@ $expectedPackages = @( "GameCult.Caching.MessagePack.Analyzers.$version.nupkg", "GameCult.Caching.MessagePack.$version.nupkg", "GameCult.Networking.$version.nupkg", + "GameCult.Networking.WebSockets.$version.nupkg", "GameCult.Mesh.$version.nupkg" ) foreach ($package in $expectedPackages) { diff --git a/scripts/verify-eve-browser-network.mjs b/scripts/verify-eve-browser-network.mjs index 20d819a0..8c865b1d 100644 --- a/scripts/verify-eve-browser-network.mjs +++ b/scripts/verify-eve-browser-network.mjs @@ -14,6 +14,14 @@ import { chromium } from "playwright-core"; const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), ".."); const eveFlag = process.argv.indexOf("--eve-root"); const eveRoot = resolve(eveFlag >= 0 ? process.argv[eveFlag + 1] : join(repoRoot, "..", "Eve")); +const packageFeedFlag = process.argv.indexOf("--package-feed"); +const packageFeed = packageFeedFlag >= 0 ? resolve(process.argv[packageFeedFlag + 1]) : undefined; +const cultLibVersionFlag = process.argv.indexOf("--cultlib-package-version"); +const cultLibPackageVersion = cultLibVersionFlag >= 0 ? process.argv[cultLibVersionFlag + 1] : undefined; +const eveSurfaceVersionFlag = process.argv.indexOf("--eve-surface-package-version"); +const eveSurfacePackageVersion = eveSurfaceVersionFlag >= 0 ? process.argv[eveSurfaceVersionFlag + 1] : undefined; +const nugetConfigFlag = process.argv.indexOf("--nuget-config"); +const nugetConfig = nugetConfigFlag >= 0 ? resolve(process.argv[nugetConfigFlag + 1]) : undefined; const sampleRoot = join(repoRoot, "samples", "eve-browser-network"); const workRoot = await mkdtemp(join(tmpdir(), "cultmesh-browser-network-")); const statePath = join(workRoot, "counter.cc"); @@ -51,15 +59,30 @@ try { const bundle = await readFile(bundlePath, "utf8"); assert.doesNotMatch(bundle, /(?:from\s*["']node:|require\(["']node:)/u, "browser bundle contains a Node builtin import"); - await run("dotnet", [ + const dotnetBuildArguments = [ "build", join(sampleRoot, "EveBrowserNetworkSample.csproj"), "-m:1", "--verbosity", "quiet", "-p:NoWarn=1591%3BCS8632", - `-p:EveRoot=${eveRoot}`, - `-p:CultLibRoot=${repoRoot}`, - ]); + "-p:NuGetAudit=false", + "-p:RestoreIgnoreFailedSources=true", + ]; + if (nugetConfig) dotnetBuildArguments.push(`-p:RestoreConfigFile=${nugetConfig}`); + if (packageFeed) { + if (!cultLibPackageVersion || !eveSurfacePackageVersion) { + throw new Error("Package artifact builds require both CultLib and Eve surface package versions."); + } + dotnetBuildArguments.push( + "-p:UsePackageArtifacts=true", + `-p:PackageFeed=${packageFeed}`, + `-p:CultLibPackageVersion=${cultLibPackageVersion}`, + `-p:EveSurfacePackageVersion=${eveSurfacePackageVersion}`, + ); + } else { + dotnetBuildArguments.push(`-p:EveRoot=${eveRoot}`, `-p:CultLibRoot=${repoRoot}`); + } + await run("dotnet", dotnetBuildArguments); const providerPort = await freePort(); const decoyProviderPort = await freePort(); const replacementProviderPort = await freePort(); diff --git a/scripts/verify-eve-getting-started.ps1 b/scripts/verify-eve-getting-started.ps1 index eb653aa6..e4143645 100644 --- a/scripts/verify-eve-getting-started.ps1 +++ b/scripts/verify-eve-getting-started.ps1 @@ -25,43 +25,62 @@ if ($cultMeshClientSource -match 'ConnectAsync\s*\(\s*string\s+(endpointId|verse $cultMeshClientSource -match 'Lease(Document|Collection)Async[^\(]*\(\s*string\s+(endpointId|verseId)') { throw "CultMeshClient must not expose an ambiguous one-string session identity." } -$discoverySource = Get-Content -LiteralPath (Join-Path $cultLibRoot "src\GameCult.Mesh\CultMeshDiscoveryService.cs") -Raw -if ($discoverySource -notmatch 'AuthorityRuntimeIds\.Contains\(query\.AuthorityRuntimeId') { - throw "CultMesh discovery must prove that a selected Verse route advertises the requested authority runtime." -} - $dotnetPackageRoot = Join-Path ([IO.Path]::GetTempPath()) ` ("eve-getting-started-nuget-" + [guid]::NewGuid().ToString("N")) +$sourceRevision = (& git -C $cultLibRoot rev-parse --short=12 HEAD).Trim() +if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($sourceRevision)) { + throw "Could not determine the CultLib source revision for local package identity." +} +$verificationNonce = [guid]::NewGuid().ToString("N").Substring(0, 8) +$cultLibLocalVersion = "1.0.33-local.$sourceRevision.$verificationNonce" +$surfaceLocalVersion = "0.3.2-local.$sourceRevision.$verificationNonce" try { & (Join-Path $EveRoot "scripts\pack-dotnet-surface.ps1") ` -CultLibRoot $cultLibRoot ` - -OutputDirectory $dotnetPackageRoot + -OutputDirectory $dotnetPackageRoot ` + -CultLibPackageVersion $cultLibLocalVersion ` + -SurfacePackageVersion $surfaceLocalVersion if ($LASTEXITCODE -ne 0) { throw "The clean .NET package-consumer checkpoint failed." } + + $cultLibPackage = Get-ChildItem -LiteralPath $dotnetPackageRoot -Filter "GameCult.Mesh.*.nupkg" | + Where-Object { $_.Name -notlike "*.snupkg" } | + Select-Object -First 1 + $surfacePackage = Get-ChildItem -LiteralPath $dotnetPackageRoot -Filter "GameCult.Eve.Surface.*.nupkg" | + Where-Object { $_.Name -notlike "*.snupkg" } | + Select-Object -First 1 + if (-not $cultLibPackage -or -not $surfacePackage) { + throw "The local package feed is missing CultMesh or Eve surface artifacts." + } + $cultLibVersion = [regex]::Match($cultLibPackage.Name, '^GameCult\.Mesh\.(.+)\.nupkg$').Groups[1].Value + $surfaceVersion = [regex]::Match($surfacePackage.Name, '^GameCult\.Eve\.Surface\.(.+)\.nupkg$').Groups[1].Value + + & (Join-Path $PSScriptRoot "verify-eve-two-runtime-sample.ps1") ` + -EveRoot $EveRoot ` + -SkipDependencyInstall:$SkipDependencyInstall + if ($LASTEXITCODE -ne 0) { + throw "The clean package-consumer checkpoint failed." + } + + $nodeCommand = Get-Command node -ErrorAction Stop + $playwrightCli = Join-Path $cultLibRoot "node_modules\playwright-core\cli.js" + if (-not (Test-Path -LiteralPath $playwrightCli -PathType Leaf)) { + throw "playwright-core is missing after dependency setup: $playwrightCli" + } + + & $nodeCommand.Source (Join-Path $PSScriptRoot "verify-eve-browser-network.mjs") ` + --eve-root $EveRoot ` + --package-feed $dotnetPackageRoot ` + --cultlib-package-version $cultLibVersion ` + --eve-surface-package-version $surfaceVersion + if ($LASTEXITCODE -ne 0) { + throw "The real browser/C# network checkpoint failed." + } + + Write-Host "Eve getting-started verification passed: clean .NET and TypeScript artifacts, DOM and headless convergence, real Chromium and C# clients, Odin discovery, authority-bound routes, receipts, persistence, and route replacement." } finally { if (Test-Path -LiteralPath $dotnetPackageRoot) { Remove-Item -LiteralPath $dotnetPackageRoot -Recurse -Force } } - -& (Join-Path $PSScriptRoot "verify-eve-two-runtime-sample.ps1") ` - -EveRoot $EveRoot ` - -SkipDependencyInstall:$SkipDependencyInstall -if ($LASTEXITCODE -ne 0) { - throw "The clean package-consumer checkpoint failed." -} - -$nodeCommand = Get-Command node -ErrorAction Stop -$playwrightCli = Join-Path $cultLibRoot "node_modules\playwright-core\cli.js" -if (-not (Test-Path -LiteralPath $playwrightCli -PathType Leaf)) { - throw "playwright-core is missing after dependency setup: $playwrightCli" -} - -& $nodeCommand.Source (Join-Path $PSScriptRoot "verify-eve-browser-network.mjs") ` - --eve-root $EveRoot -if ($LASTEXITCODE -ne 0) { - throw "The real browser/C# network checkpoint failed." -} - -Write-Host "Eve getting-started verification passed: clean .NET and TypeScript artifacts, DOM and headless convergence, real Chromium and C# clients, Odin discovery, receipts, persistence, and route replacement." diff --git a/src/GameCult.Mesh/docs/getting-started/01-persist-typed-state.md b/src/GameCult.Mesh/docs/getting-started/01-persist-typed-state.md index c2667e9b..7520d67f 100644 --- a/src/GameCult.Mesh/docs/getting-started/01-persist-typed-state.md +++ b/src/GameCult.Mesh/docs/getting-started/01-persist-typed-state.md @@ -34,7 +34,7 @@ using var node = await CultMesh.CreateNodeAsync("counter.cc", new CultMeshNodeOp CacheOptions = new CultCacheOpenOptions { Registry = registry }, DatabaseOptions = new CultNetDatabaseOptions { - RuntimeId = "sample.counter-provider", + RuntimeId = "sample.counter-daemon", DocumentRegistry = documents } }); diff --git a/src/GameCult.Mesh/docs/getting-started/02-connect-by-identity.md b/src/GameCult.Mesh/docs/getting-started/02-connect-by-identity.md index 5cf90a0e..ee505acb 100644 --- a/src/GameCult.Mesh/docs/getting-started/02-connect-by-identity.md +++ b/src/GameCult.Mesh/docs/getting-started/02-connect-by-identity.md @@ -1,13 +1,17 @@ # 2. Connect A Client By Stable Identity Clients address a live session by stable Verse/provider identity. In this tutorial, -`sample.counter` is the Verse id and `sample.counter-provider` is the authority +`sample.counter` is the Verse id and `sample.counter-daemon` is the authority runtime Odin currently advertises for it. Application clients pass that typed pair, never a socket address and never one ambiguous string that might mean either identity. A product may expose only a Verse choice to its user; its selection owner then resolves the provider runtime from Odin's descriptor before opening the session. Discovery owns the current physical routes, and the session manager owns connection reuse, path rotation, and transport failure state. +Each Odin route binds that authority runtime to one endpoint, protocol set, and +generation. The client verifies the same tuple with the connected peer before +the session becomes online; runtime membership and endpoint reachability are +not independent routing evidence. ```csharp using GameCult.Mesh; @@ -15,7 +19,9 @@ using GameCult.Mesh; var odinEndpoint = Environment.GetEnvironmentVariable("ODIN_ENDPOINT") ?? throw new InvalidOperationException("Set ODIN_ENDPOINT to the configured rendezvous route."); const string verseId = "sample.counter"; -var target = new CultMeshSessionTarget(verseId, "sample.counter-provider"); +var target = new CultMeshSessionTarget(verseId, "sample.counter-daemon"); +using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(30)); +var cancellationToken = timeout.Token; using var mesh = new CultMeshClient(new CultMeshClientOptions { RendezvousEndpoints = new[] { odinEndpoint } @@ -65,6 +71,11 @@ network proof): dotnet test tests/GameCult.Mesh.Tests/GameCult.Mesh.Tests.csproj --filter FullyQualifiedName~CultMeshSessionManagerTests ``` +The real checkpoint in chapter 4 additionally advertises a better-priority +endpoint for the wrong authority runtime. Both the C# and browser clients must +ignore it, verify the intended peer, survive route replacement, and reject +wrong-source operation responses. + Advanced hosts may inject lookup sources, connectors, clocks, persistence, and diagnostics through the lower-level discovery and session APIs. Application features should not need them. diff --git a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md index bbeff475..5cb5b742 100644 --- a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md +++ b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md @@ -97,6 +97,10 @@ GameCult dependency is `PackageReference Include="GameCult.Eve.Surface"`. This proves the renderer-neutral provider contract does not require a sibling Eve or CultLib source tree after packaging. +The real-process C# sample is then rebuilt from that same temporary NuGet feed. +The source project references in its `.csproj` are contributor convenience only +and are disabled by the checkpoint; they are not the consumer contract. + The first layer builds and packs `cultcache-ts`, `cultnet-ts`, `cultmesh-ts`, `@gamecult/eve-contracts`, and `@gamecult/eve-browser-lowering`, installs the tarballs into an empty temporary consumer, and runs @@ -108,11 +112,11 @@ both consumers converge on the same state and canonical receipt identity, a duplicate idempotency key is not applied twice, and the state plus receipt survive reopening the `.cc` store. -The second layer runs a durable C# provider, a separate local Odin fixture, a -real Chromium Eve lowerer, and an independent C# headless observer over binary +The second layer runs a durable C# provider, a wrong-authority decoy, a separate +local Odin fixture, a real Chromium Eve lowerer, and an independent C# headless observer over binary CultNet WebSocket lanes. The open browser resolves the `sample.counter` Verse -through the canonical catalog, survives its provider restarting on a different route, -and resubscribes. The retained C# client then invokes a second typed operation +through the canonical catalog, rejects the decoy route, survives its provider +restarting on a different route, and resubscribes. The retained C# client then invokes a second typed operation through `CultMeshClient.InvokeAsync`; Chromium and C# observe the same provider-authored state and receipt chronology. The same retained C# session then completes 10,000 typed no-op operations under explicit p99 and post-GC diff --git a/src/GameCult.Mesh/docs/getting-started/04-run-the-multiruntime-game.md b/src/GameCult.Mesh/docs/getting-started/04-run-the-multiruntime-game.md index ba9888c3..ce18fdb3 100644 --- a/src/GameCult.Mesh/docs/getting-started/04-run-the-multiruntime-game.md +++ b/src/GameCult.Mesh/docs/getting-started/04-run-the-multiruntime-game.md @@ -10,6 +10,8 @@ The counter is now one small multiplayer game: typed operation boundary; - both clients remain attached when Odin moves the Verse to a replacement physical provider route. +- a better-priority route bound to another runtime remains unreachable to both + clients throughout the chronology. Run the whole chronology from the CultLib checkout: @@ -34,8 +36,10 @@ packages, installs those artifacts into an empty temporary consumer, and proves DOM/headless convergence plus `.cc` reopen. This rejects a sample that only works through repository-relative source imports. -The third checkpoint boots separate Odin, provider, Chromium, and C# headless -processes. Chromium performs the first increment. The provider then restarts on +The third checkpoint boots separate Odin, intended provider, wrong-authority +decoy provider, Chromium, and C# headless processes. Its C# application is built +from the temporary NuGet feed produced by the first checkpoint, not sibling +project references. Chromium performs the first increment. The provider then restarts on a different route, Odin advertises the replacement, and the retained clients resubscribe without application reconnect code. C# performs the second increment. Both clients must observe count 2 and both canonical receipt ids. diff --git a/src/GameCult.Mesh/docs/getting-started/README.md b/src/GameCult.Mesh/docs/getting-started/README.md index b32052a7..66ded7a4 100644 --- a/src/GameCult.Mesh/docs/getting-started/README.md +++ b/src/GameCult.Mesh/docs/getting-started/README.md @@ -4,14 +4,22 @@ This series builds one typed application state and presents it through multiple Eve runtimes. It is maintained as an API acceptance test: examples use public APIs, name the owner of each decision, and include a verification checkpoint. -Run the complete getting-started checkpoint: +Application consumers install released packages and do not need the source +repositories. This checkout also contains a maintainer checkpoint that creates +the same clean consumers from local package artifacts: ```powershell pwsh -File ./scripts/verify-eve-getting-started.ps1 ``` -With clean sibling CultLib and Eve checkouts, the command installs missing build -dependencies and runs three explicit evidence layers. First it packs the +The maintainer command takes an explicit `-EveRoot` when Eve is not a sibling: + +```powershell +pwsh -File ./scripts/verify-eve-getting-started.ps1 -EveRoot D:\src\Eve +``` + +It installs missing build dependencies and runs three explicit evidence layers. +First it packs the CultLib managed dependency closure plus `GameCult.Eve.Surface`, then restores and runs an empty .NET consumer using only `PackageReference`. Next it packs the five TypeScript packages into another empty temporary consumer, validates the Eve surface @@ -20,7 +28,8 @@ headless observer converge, and reopens the durable `.cc` store. Then it boots a durable C# provider, local Odin fixture, real Chromium lowerer, and independent C# client. Chromium invokes before provider replacement; C# invokes afterward. Both retained clients prove discovery by identity, canonical receipts, provider -restart on another route, resubscription, and durable convergence. The retained +restart on another route, rejection of a better-priority wrong-authority route, +resubscription, and durable convergence. The retained C# session also completes 10,000 non-persistent typed operations under p99 and post-GC managed-memory gates. Set `CHROME_PATH` only when no installed Chrome, Chromium, Edge, or Playwright @@ -58,3 +67,6 @@ native projection. CultMesh owns discovery and connection continuity. pull request. - A setup step that depends on repository internals is an API defect, not acceptable tutorial folklore. +- The maintainer command may read owner checkouts to create packages. Every + sample process it launches must consume those package artifacts rather than + compiling through sibling project references. diff --git a/src/GameCult.Networking.WebSockets/GameCult.Networking.WebSockets.csproj b/src/GameCult.Networking.WebSockets/GameCult.Networking.WebSockets.csproj index 40214247..6ced9b42 100644 --- a/src/GameCult.Networking.WebSockets/GameCult.Networking.WebSockets.csproj +++ b/src/GameCult.Networking.WebSockets/GameCult.Networking.WebSockets.csproj @@ -4,6 +4,8 @@ enable enable CultNet schema-v0 WebSocket host adapter for browser and web runtimes + GameCult.Networking.WebSockets + game;networking;websocket;cultnet;cultmesh From f622ee1b248a8001ebb8e0960ce99679d163ce18 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 19:02:46 +0200 Subject: [PATCH 096/283] Authenticate CultMesh authority routes and replay operations --- Directory.Build.props | 1 + packages/cultmesh-browser/src/index.ts | 244 ++++++++++-- .../test/cultmesh-browser.test.ts | 273 +++++++++++++- .../cultmesh.session-accepted.schema.json | 7 +- .../cultmesh.session-open.schema.json | 7 +- ...ultmesh.verse-catalog-response.schema.json | 17 +- packages/cultnet-ts/src/contracts.ts | 25 +- packages/cultnet-ts/test/cultnet.test.ts | 7 +- samples/eve-browser-network/Program.cs | 4 + samples/eve-browser-network/browser/main.ts | 1 + scripts/pack-nuget.ps1 | 2 +- src/GameCult.Mesh/CultMeshAuthorityProof.cs | 349 ++++++++++++++++++ src/GameCult.Mesh/CultMeshContentSessions.cs | 4 +- src/GameCult.Mesh/CultMeshSessionIdentity.cs | 55 ++- src/GameCult.Mesh/CultMeshSessions.cs | 33 +- .../CultMeshTcpContentTransport.cs | 32 +- src/GameCult.Mesh/CultMeshVerse.cs | 6 +- src/GameCult.Mesh/CultMeshVerseDiscovery.cs | 23 +- .../docs/browser-verse-transport.md | 11 +- .../getting-started/02-connect-by-identity.md | 39 +- src/GameCult.Mesh/docs/transport-planes.md | 24 +- .../CultNetSchemaMessages.cs | 21 +- .../CultMeshAuthorityProofTests.cs | 241 ++++++++++++ .../CultMeshBodySessionTests.cs | 6 +- .../CultMeshClientTests.cs | 20 +- .../CultMeshContentSessionTests.cs | 8 +- .../CultMeshSessionManagerTests.cs | 70 ++-- .../GameCult.Mesh.Tests/CultMeshTestTrust.cs | 18 + .../CultMeshTransportModularityTests.cs | 12 +- tools/GameCult.TransportParity/Program.cs | 14 +- 30 files changed, 1432 insertions(+), 142 deletions(-) create mode 100644 src/GameCult.Mesh/CultMeshAuthorityProof.cs create mode 100644 tests/GameCult.Mesh.Tests/CultMeshAuthorityProofTests.cs create mode 100644 tests/GameCult.Mesh.Tests/CultMeshTestTrust.cs diff --git a/Directory.Build.props b/Directory.Build.props index db26d4f3..434617ff 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -15,6 +15,7 @@ © Meta Vens and contributors true 1.0.33 + $(CultLibPackageVersion) true diff --git a/packages/cultmesh-browser/src/index.ts b/packages/cultmesh-browser/src/index.ts index bbc253f4..a0596ae2 100644 --- a/packages/cultmesh-browser/src/index.ts +++ b/packages/cultmesh-browser/src/index.ts @@ -24,7 +24,32 @@ export interface CultMeshBrowserIdentity { export interface CultMeshBrowserRoute extends CultMeshBrowserIdentity { endpoint: string; protocolId?: string; + protocolIds?: readonly string[]; + priority?: number; generation: string; + certificate?: CultMeshBrowserRouteCertificate; +} + +export interface CultMeshBrowserP256PublicKey { + keyId: string; + x: string; + y: string; +} + +export interface CultMeshBrowserRouteCertificate { + providerKey: CultMeshBrowserP256PublicKey; + odinKeyId: string; + issuedAtUnixMilliseconds: number; + expiresAtUnixMilliseconds: number; + signature: string; +} + +export type CultMeshBrowserAuthorityTrustMode = "authenticated-remote" | "local-development"; + +export interface CultMeshBrowserAuthorityTrustPolicy { + mode: CultMeshBrowserAuthorityTrustMode; + odinRoots?: readonly CultMeshBrowserP256PublicKey[]; + now?: () => number; } export interface CultMeshBrowserRendezvous { @@ -162,6 +187,8 @@ export interface CultMeshBrowserClientOptions extends CultMeshBrowserIdentity { requestTimeoutMs?: number; maxFrameBytes?: number; createId?: () => string; + /** Consumer-owned authority roots. Remote sessions fail closed when omitted. */ + trust?: CultMeshBrowserAuthorityTrustPolicy; } export interface CultMeshRawDocumentLeaseOptions { @@ -215,6 +242,7 @@ interface PendingSnapshot { } interface PendingOperation { + request: CultNetOperationRequestMessage; resolve: (response: CultNetOperationResponseMessage) => void; reject: (error: Error) => void; timer: ReturnType; @@ -297,6 +325,7 @@ export class CultMeshBrowserClient implements AsyncDisposable { maxFrameBytes: options.maxFrameBytes ?? 4 * 1024 * 1024, createId: options.createId ?? (() => crypto.randomUUID()), socketFactory: options.socketFactory ?? (endpoint => new WebSocket(endpoint)), + trust: options.trust ?? { mode: "authenticated-remote", odinRoots: [] }, }; } @@ -369,15 +398,12 @@ export class CultMeshBrowserClient implements AsyncDisposable { if (!this.#pendingOperations.delete(messageId)) return; reject(new Error(`CultMesh operation '${messageId}' timed out.`)); }, this.#options.requestTimeoutMs); - this.#pendingOperations.set(messageId, { resolve, reject, timer }); + this.#pendingOperations.set(messageId, { request, resolve, reject, timer }); }); try { this.send(request); } catch (error) { - const pending = this.#pendingOperations.get(messageId); - if (pending) clearTimeout(pending.timer); - this.#pendingOperations.delete(messageId); - throw error; + this.scheduleReconnect(); } return response; } @@ -490,6 +516,7 @@ export class CultMeshBrowserClient implements AsyncDisposable { route.authorityRuntimeId !== this.identity.authorityRuntimeId) { throw new Error("CultMesh rendezvous returned a route for the wrong stable identity."); } + await verifyAuthorityRoute(route, this.#options.trust); const endpoint = new URL(route.endpoint); if (endpoint.protocol !== "ws:" && endpoint.protocol !== "wss:") { throw new Error(`CultMesh browser route must use ws:// or wss://, got '${route.endpoint}'.`); @@ -501,6 +528,17 @@ export class CultMeshBrowserClient implements AsyncDisposable { let opened = false; let settled = false; const handshakeId = this.#options.createId(); + const clientNonce = randomNonce(); + const sessionRequest: CultMeshSessionOpenMessage = { + schemaVersion: "cultmesh.session_open.v2", + messageId: handshakeId, + sourceRuntimeId: this.runtimeId, + verseId: this.identity.verseId, + authorityRuntimeId: this.identity.authorityRuntimeId, + protocolId: route.protocolId ?? "cultmesh.documents.v1", + routeGeneration: route.generation, + clientNonce, + }; const finish = (error?: Error) => { if (settled) return; settled = true; @@ -524,8 +562,8 @@ export class CultMeshBrowserClient implements AsyncDisposable { runtimeId: this.runtimeId, runtimeKind: "browser", supportedMessageVersions: [ - "cultmesh.session_open.v1", - "cultmesh.session_accepted.v1", + "cultmesh.session_open.v2", + "cultmesh.session_accepted.v2", "cultnet.database_subscribe.v0", "cultnet.database_unsubscribe.v0", "cultnet.database_change_raw.v0", @@ -533,16 +571,7 @@ export class CultMeshBrowserClient implements AsyncDisposable { "cultnet.operation_response.v0", ], }, this.#options.maxFrameBytes); - const request: CultMeshSessionOpenMessage = { - schemaVersion: "cultmesh.session_open.v1", - messageId: handshakeId, - sourceRuntimeId: this.runtimeId, - verseId: this.identity.verseId, - authorityRuntimeId: this.identity.authorityRuntimeId, - protocolId: route.protocolId ?? "cultmesh.documents.v1", - routeGeneration: route.generation, - }; - sendSocketMessage(socket, request, this.#options.maxFrameBytes); + sendSocketMessage(socket, sessionRequest, this.#options.maxFrameBytes); } catch (error) { finish(error instanceof Error ? error : new Error(String(error))); } @@ -553,8 +582,13 @@ export class CultMeshBrowserClient implements AsyncDisposable { finish(new Error(message.error)); return; } - if (message.schemaVersion !== "cultmesh.session_accepted.v1" || message.messageId !== handshakeId) return; - finish(validateSessionAcceptance(message, this.identity, route)); + if (message.schemaVersion !== "cultmesh.session_accepted.v2" || message.messageId !== handshakeId) return; + void validateSessionAcceptance( + message, + sessionRequest, + route, + this.#options.trust, + ).then(finish).catch(error => finish(error instanceof Error ? error : new Error(String(error)))); }).catch(error => finish(error instanceof Error ? error : new Error(String(error)))); }; socket.onerror = () => finish(new Error(`CultMesh WebSocket could not open '${route.endpoint}'.`)); @@ -575,6 +609,7 @@ export class CultMeshBrowserClient implements AsyncDisposable { this.setState("connected"); try { await Promise.all([...this.#leases.values()].map(lease => this.subscribe(lease))); + for (const pending of this.#pendingOperations.values()) this.send(pending.request); } catch (error) { if (this.#socket === socket) this.#socket = undefined; socket.onclose = null; @@ -591,12 +626,7 @@ export class CultMeshBrowserClient implements AsyncDisposable { clearTimeout(pending.timer); pending.reject(error); } - for (const pending of this.#pendingOperations.values()) { - clearTimeout(pending.timer); - pending.reject(error); - } this.#pendingSnapshots.clear(); - this.#pendingOperations.clear(); this.setState("reconnecting"); this.#reconnectTimer = setTimeout(() => { this.#reconnectTimer = undefined; @@ -713,6 +743,15 @@ export class CultMeshBrowserClient implements AsyncDisposable { for (const watcher of this.#stateWatchers) watcher(state); } + private scheduleReconnect(): void { + if (this.#disposed || this.#reconnectTimer) return; + this.setState("reconnecting"); + this.#reconnectTimer = setTimeout(() => { + this.#reconnectTimer = undefined; + void this.connectSocket().catch(() => this.scheduleReconnect()); + }, this.#options.reconnectDelayMs); + } + private throwIfDisposed(): void { if (this.#disposed) throw new Error("CultMesh browser client is disposed."); } @@ -816,6 +855,7 @@ function selectOdinRoute( protocolIds: ["cultmesh.documents.v1"], priority: 0, generation: [verse.compatibility.transportVersion, verse.compatibility.rulesHash, endpoint].join(":"), + certificate: undefined, })); const routes = boundRoutes.filter(route => route.authorityRuntimeId === identity.authorityRuntimeId && @@ -836,29 +876,171 @@ function selectOdinRoute( ...identity, endpoint: route.endpoint, protocolId: "cultmesh.documents.v1", + protocolIds: route.protocolIds, + priority: route.priority, generation: route.generation, + ...(route.certificate ? { certificate: { + providerKey: { + keyId: route.certificate.providerKeyId, + x: route.certificate.providerPublicKeyX, + y: route.certificate.providerPublicKeyY, + }, + odinKeyId: route.certificate.odinKeyId, + issuedAtUnixMilliseconds: route.certificate.issuedAtUnixMilliseconds, + expiresAtUnixMilliseconds: route.certificate.expiresAtUnixMilliseconds, + signature: route.certificate.signature, + } } : {}), }; } -function validateSessionAcceptance( +async function validateSessionAcceptance( message: CultMeshSessionAcceptedMessage, - identity: CultMeshBrowserIdentity, + request: CultMeshSessionOpenMessage, route: CultMeshBrowserRoute, -): Error | undefined { + trust: CultMeshBrowserAuthorityTrustPolicy, +): Promise { if (!message.accepted) return new Error(message.error ?? "CultMesh authority rejected the session."); const protocolId = route.protocolId ?? "cultmesh.documents.v1"; - if (message.verseId !== identity.verseId || - message.authorityRuntimeId !== identity.authorityRuntimeId || + if (message.verseId !== request.verseId || + message.authorityRuntimeId !== request.authorityRuntimeId || message.protocolId !== protocolId || - message.routeGeneration !== route.generation) { + message.routeGeneration !== route.generation || + message.clientNonce !== request.clientNonce) { return new Error( `CultMesh route proved '${message.verseId}/${message.authorityRuntimeId}/${message.protocolId}/${message.routeGeneration}', ` + - `expected '${identity.verseId}/${identity.authorityRuntimeId}/${protocolId}/${route.generation}'.`, + `expected '${request.verseId}/${request.authorityRuntimeId}/${protocolId}/${route.generation}'.`, ); } + if (trust.mode === "local-development" && isLoopbackEndpoint(route.endpoint) && !route.certificate) return undefined; + const providerKey = route.certificate?.providerKey; + if (!providerKey || message.providerKeyId !== providerKey.keyId || !message.providerSignature) { + return new Error("CultMesh authority did not prove possession of the Odin-certified provider key."); + } + if (!await verifyP256(providerKey, canonicalSession(request, route.endpoint), message.providerSignature)) { + return new Error("CultMesh provider session proof is invalid."); + } return undefined; } +async function verifyAuthorityRoute( + route: CultMeshBrowserRoute, + trust: CultMeshBrowserAuthorityTrustPolicy, +): Promise { + const certificate = route.certificate; + if (!certificate) { + if (trust.mode === "local-development" && isLoopbackEndpoint(route.endpoint)) return; + throw new Error("Remote CultMesh routes require an Odin-signed authority certificate."); + } + const endpoint = new URL(route.endpoint); + if (endpoint.protocol !== "wss:" && !(trust.mode === "local-development" && isLoopbackEndpoint(route.endpoint))) { + throw new Error("Authenticated remote CultMesh browser routes require wss:// channel protection."); + } + const now = trust.now?.() ?? Date.now(); + if (now < certificate.issuedAtUnixMilliseconds || now >= certificate.expiresAtUnixMilliseconds) { + throw new Error("The Odin route certificate is not currently valid."); + } + const root = trust.odinRoots?.find(candidate => candidate.keyId === certificate.odinKeyId); + if (!root) throw new Error(`Odin key '${certificate.odinKeyId}' is not trusted by this consumer.`); + if (!await verifyP256(root, canonicalRoute(route), certificate.signature)) { + throw new Error("The Odin route certificate signature is invalid."); + } +} + +function canonicalRoute(route: CultMeshBrowserRoute): Uint8Array { + const certificate = route.certificate!; + return canonicalFields( + "gamecult.cultmesh.route-certificate.v1", + route.verseId, + route.authorityRuntimeId, + route.endpoint, + [...(route.protocolIds ?? [route.protocolId ?? "cultmesh.documents.v1"])].sort().join("\u001f"), + String(route.priority ?? 0), + route.generation, + certificate.providerKey.keyId, + certificate.providerKey.x, + certificate.providerKey.y, + certificate.odinKeyId, + String(certificate.issuedAtUnixMilliseconds), + String(certificate.expiresAtUnixMilliseconds), + ); +} + +function canonicalSession(request: CultMeshSessionOpenMessage, endpoint: string): Uint8Array { + return canonicalFields( + "gamecult.cultmesh.session-proof.v1", + request.clientNonce, + request.messageId, + request.sourceRuntimeId, + request.verseId, + request.authorityRuntimeId, + request.protocolId, + endpoint, + request.routeGeneration, + ); +} + +function canonicalFields(...values: string[]): Uint8Array { + const encoder = new TextEncoder(); + const encoded = values.map(value => encoder.encode(value)); + const total = encoded.reduce((sum, value) => sum + 4 + value.byteLength, 0); + const result = new Uint8Array(total); + const view = new DataView(result.buffer); + let offset = 0; + for (const value of encoded) { + view.setUint32(offset, value.byteLength, false); + offset += 4; + result.set(value, offset); + offset += value.byteLength; + } + return result; +} + +async function verifyP256( + key: CultMeshBrowserP256PublicKey, + payload: Uint8Array, + signatureBase64: string, +): Promise { + try { + const x = base64ToBytes(key.x); + const y = base64ToBytes(key.y); + const signature = base64ToBytes(signatureBase64); + if (x.byteLength !== 32 || y.byteLength !== 32 || signature.byteLength !== 64) return false; + const raw = new Uint8Array(65); + raw[0] = 4; + raw.set(x, 1); + raw.set(y, 33); + const publicKey = await crypto.subtle.importKey( + "raw", + raw.slice().buffer as ArrayBuffer, + { name: "ECDSA", namedCurve: "P-256" }, + false, + ["verify"], + ); + return await crypto.subtle.verify( + { name: "ECDSA", hash: "SHA-256" }, + publicKey, + signature.slice().buffer as ArrayBuffer, + payload.slice().buffer as ArrayBuffer, + ); + } catch { + return false; + } +} + +function randomNonce(): string { + const bytes = crypto.getRandomValues(new Uint8Array(32)); + return bytesToBase64(bytes); +} + +function isLoopbackEndpoint(value: string): boolean { + try { + const host = new URL(value).hostname.replace(/^\[|\]$/g, "").toLowerCase(); + return host === "localhost" || host === "127.0.0.1" || host === "::1"; + } catch { + return false; + } +} + function requireText(value: string, field: string): void { if (!value || value.trim().length === 0) throw new Error(`CultMesh browser ${field} is required.`); } diff --git a/packages/cultmesh-browser/test/cultmesh-browser.test.ts b/packages/cultmesh-browser/test/cultmesh-browser.test.ts index a785d47c..4f90acf1 100644 --- a/packages/cultmesh-browser/test/cultmesh-browser.test.ts +++ b/packages/cultmesh-browser/test/cultmesh-browser.test.ts @@ -19,9 +19,12 @@ import { decodeCultNetOperationPayload, decodeCultNetPayload, type CultMeshBrowserRoute, + type CultMeshBrowserP256PublicKey, type CultMeshBrowserSocket, } from "../src/index.js"; +const localTrust = { mode: "local-development" as const }; + test("Odin rendezvous resolves stable authority-runtime identity and observes route rotation", async () => { const odin = new FakeOdin("ws://127.0.0.1:4050/mesh"); let id = 0; @@ -98,6 +101,7 @@ test("browser client leases provider state, invokes an operation, and follows ro verseId: route.verseId, authorityRuntimeId: route.authorityRuntimeId, runtimeId: "browser-test", + trust: localTrust, rendezvous: { resolve: async () => route }, createId: () => `id-${++id}`, socketFactory: endpoint => endpoint === first.route.endpoint ? first.open() : second.open(), @@ -144,6 +148,7 @@ test("browser client rejects wrong rendezvous identity and has no document write verseId: "sample.counter", authorityRuntimeId: "sample.counter-daemon", runtimeId: "browser-test", + trust: localTrust, rendezvous: { resolve: async () => ({ ...provider.route, @@ -165,6 +170,7 @@ test("browser client rejects a route whose peer proves the wrong authority", asy verseId: "sample.counter", authorityRuntimeId: "sample.counter-daemon", runtimeId: "browser-peer-proof-test", + trust: localTrust, rendezvous: { resolve: async () => ({ ...provider.route, authorityRuntimeId: "sample.counter-daemon" }) }, socketFactory: () => provider.open(), }), @@ -172,6 +178,56 @@ test("browser client rejects a route whose peer proves the wrong authority", asy ); }); +test("browser client accepts an Odin-certified route only after provider nonce proof", async () => { + const fixture = await createSignedRoute("wss://provider.example/mesh"); + const client = await CultMeshBrowserClient.connect({ + ...fixture.route, + runtimeId: "browser-authenticated-test", + rendezvous: { resolve: async () => fixture.route }, + trust: { mode: "authenticated-remote", odinRoots: [fixture.odinPublic] }, + socketFactory: () => signedHandshakeSocket(fixture.route, fixture.providerPrivate), + }); + + assert.equal(client.state, "connected"); + await client.dispose(); +}); + +test("browser client rejects a credential-free authority impersonator", async () => { + const fixture = await createSignedRoute("wss://provider.example/mesh"); + const impersonator = new FakeProvider("wss://provider.example/mesh", 1); + + await assert.rejects( + CultMeshBrowserClient.connect({ + ...fixture.route, + runtimeId: "browser-impersonation-test", + rendezvous: { resolve: async () => fixture.route }, + trust: { mode: "authenticated-remote", odinRoots: [fixture.odinPublic] }, + socketFactory: () => impersonator.open(), + }), + /did not prove possession/, + ); +}); + +test("browser client rejects a mutated or expired signed route before opening a provider socket", async () => { + const fixture = await createSignedRoute("wss://provider.example/mesh"); + let opened = false; + const connect = (route: CultMeshBrowserRoute, now?: () => number) => CultMeshBrowserClient.connect({ + ...route, + runtimeId: "browser-route-certificate-test", + rendezvous: { resolve: async () => route }, + trust: { mode: "authenticated-remote", odinRoots: [fixture.odinPublic], now }, + socketFactory: () => { + opened = true; + return signedHandshakeSocket(route, fixture.providerPrivate); + }, + }); + + await assert.rejects(connect({ ...fixture.route, endpoint: "wss://evil.example/mesh" }), /signature is invalid/); + assert.equal(opened, false); + await assert.rejects(connect(fixture.route, () => fixture.expiresAt), /not currently valid/); + assert.equal(opened, false); +}); + test("browser client bounds unanswered provider operations", async () => { const route = { verseId: "sample.counter", @@ -182,6 +238,7 @@ test("browser client bounds unanswered provider operations", async () => { const client = await CultMeshBrowserClient.connect({ ...route, runtimeId: "browser-timeout-test", + trust: localTrust, rendezvous: { resolve: async () => route }, requestTimeoutMs: 5, socketFactory: () => handshakeOnlySocket(route), @@ -204,6 +261,7 @@ test("browser client rejects a correlated framework failure without waiting for const client = await CultMeshBrowserClient.connect({ ...provider.route, runtimeId: "browser-failure-test", + trust: localTrust, rendezvous: { resolve: async () => provider.route }, requestTimeoutMs: 60_000, socketFactory: () => provider.open(), @@ -228,6 +286,82 @@ test("browser client rejects a correlated framework failure without waiting for await client.dispose(); }); +test("browser client replays one idempotent operation after route loss without duplicating its effect", async () => { + const firstRoute = localRoute("ws://127.0.0.1:4311/mesh", "generation-1"); + const secondRoute = localRoute("ws://127.0.0.1:4312/mesh", "generation-2"); + let route = firstRoute; + let effectCount = 0; + let dropFirstResponse = true; + const results = new Map(); + const open = () => { + let socket: FakeSocket; + socket = new FakeSocket(wire => { + const message = parseCultNetMessage(decode(wire)); + if (message.schemaVersion === "cultmesh.session_open.v2") { + socket.deliver({ + schemaVersion: "cultmesh.session_accepted.v2", + messageId: message.messageId, + accepted: true, + verseId: message.verseId, + authorityRuntimeId: message.authorityRuntimeId, + protocolId: message.protocolId, + routeGeneration: message.routeGeneration, + clientNonce: message.clientNonce, + providerKeyId: "", + providerSignature: "", + }); + return; + } + if (message.schemaVersion !== "cultnet.operation_request.v0") return; + let response = results.get(message.messageId); + if (!response) { + effectCount++; + response = { + schemaVersion: "cultnet.operation_response.v0", + messageId: message.messageId, + serviceId: message.serviceId, + operation: message.operation, + status: "accepted", + payloadSchema: "sample.increment_receipt.v1", + payloadEncoding: "messagepack-base64", + payload: Buffer.from(encode({ count: effectCount })).toString("base64"), + sourceRuntimeId: "sample.counter-daemon", + }; + results.set(message.messageId, response!); + } + if (dropFirstResponse) { + dropFirstResponse = false; + route = secondRoute; + socket.close(1012, "route lost after commit"); + return; + } + socket.deliver(response!); + }, () => undefined); + return socket; + }; + const client = await CultMeshBrowserClient.connect({ + ...firstRoute, + runtimeId: "browser-operation-replay-test", + rendezvous: { resolve: async () => route }, + trust: localTrust, + reconnectDelayMs: 1, + requestTimeoutMs: 2_000, + socketFactory: () => open(), + }); + + const response = await client.invoke({ + serviceId: "sample.counter", + operation: "increment", + payloadSchema: "sample.increment.v1", + payload: { amount: 1 }, + idempotencyKey: "replay-once", + }); + + assert.deepEqual(decodeCultNetOperationPayload<{ count: number }>(response), { count: 1 }); + assert.equal(effectCount, 1); + await client.dispose(); +}); + test("browser client rejects an operation response from another runtime", async () => { const provider = new FakeProvider( "ws://127.0.0.1:4371/mesh", @@ -239,6 +373,7 @@ test("browser client rejects an operation response from another runtime", async const client = await CultMeshBrowserClient.connect({ ...provider.route, runtimeId: "browser-response-authority-test", + trust: localTrust, rendezvous: { resolve: async () => provider.route }, socketFactory: () => provider.open(), }); @@ -266,6 +401,7 @@ test("browser client rejects oversized outbound schema messages", async () => { CultMeshBrowserClient.connect({ ...route, runtimeId: "browser-size-test", + trust: localTrust, rendezvous: { resolve: async () => route }, maxFrameBytes: 8, socketFactory: () => new FakeSocket(() => undefined, () => undefined), @@ -279,6 +415,7 @@ test("browser client reserves subscription identity while the initial lease open const client = await CultMeshBrowserClient.connect({ ...provider.route, runtimeId: "browser-lease-race-test", + trust: localTrust, rendezvous: { resolve: async () => provider.route }, socketFactory: () => provider.open(), }); @@ -344,7 +481,7 @@ class FakeProvider { private receive(socket: FakeSocket, wire: Uint8Array): void { const message = parseCultNetMessage(decode(wire)); switch (message.schemaVersion) { - case "cultmesh.session_open.v1": + case "cultmesh.session_open.v2": this.acceptSession(socket, message); return; case "cultnet.database_subscribe.v0": @@ -363,13 +500,16 @@ class FakeProvider { private acceptSession(socket: FakeSocket, message: CultMeshSessionOpenMessage): void { socket.deliver({ - schemaVersion: "cultmesh.session_accepted.v1", + schemaVersion: "cultmesh.session_accepted.v2", messageId: message.messageId, accepted: true, verseId: message.verseId, authorityRuntimeId: this.#runtimeId, protocolId: message.protocolId, routeGeneration: message.routeGeneration, + clientNonce: message.clientNonce, + providerKeyId: "", + providerSignature: "", }); } @@ -501,20 +641,35 @@ function handshakeOnlySocket(route: CultMeshBrowserRoute): FakeSocket { let socket: FakeSocket; socket = new FakeSocket(wire => { const message = parseCultNetMessage(decode(wire)); - if (message.schemaVersion !== "cultmesh.session_open.v1") return; + if (message.schemaVersion !== "cultmesh.session_open.v2") return; socket.deliver({ - schemaVersion: "cultmesh.session_accepted.v1", + schemaVersion: "cultmesh.session_accepted.v2", messageId: message.messageId, accepted: true, verseId: route.verseId, authorityRuntimeId: route.authorityRuntimeId, protocolId: message.protocolId, routeGeneration: message.routeGeneration, + clientNonce: message.clientNonce, + providerKeyId: "", + providerSignature: "", }); }, () => undefined); return socket; } +function localRoute(endpoint: string, generation: string): CultMeshBrowserRoute { + return { + verseId: "sample.counter", + authorityRuntimeId: "sample.counter-daemon", + endpoint, + protocolId: "cultmesh.documents.v1", + protocolIds: ["cultmesh.documents.v1"], + priority: 0, + generation, + }; +} + class FakeSocket implements CultMeshBrowserSocket { binaryType: BinaryType = "arraybuffer"; readyState = 0; @@ -555,6 +710,116 @@ class FakeSocket implements CultMeshBrowserSocket { } } +async function createSignedRoute(endpoint: string): Promise<{ + route: CultMeshBrowserRoute; + odinPublic: CultMeshBrowserP256PublicKey; + providerPrivate: CryptoKey; + expiresAt: number; +}> { + const odin = await crypto.subtle.generateKey({ name: "ECDSA", namedCurve: "P-256" }, true, ["sign", "verify"]); + const provider = await crypto.subtle.generateKey({ name: "ECDSA", namedCurve: "P-256" }, true, ["sign", "verify"]); + const odinPublic = await exportPublic("odin-root-1", odin.publicKey); + const providerPublic = await exportPublic("provider-1", provider.publicKey); + const issuedAt = Date.now() - 1_000; + const expiresAt = Date.now() + 60_000; + const unsigned: CultMeshBrowserRoute = { + verseId: "sample.counter", + authorityRuntimeId: "sample.counter-daemon", + endpoint, + protocolId: "cultmesh.documents.v1", + protocolIds: ["cultmesh.documents.v1"], + priority: 0, + generation: "signed-generation-1", + certificate: { + providerKey: providerPublic, + odinKeyId: odinPublic.keyId, + issuedAtUnixMilliseconds: issuedAt, + expiresAtUnixMilliseconds: expiresAt, + signature: "", + }, + }; + const signature = await crypto.subtle.sign( + { name: "ECDSA", hash: "SHA-256" }, + odin.privateKey, + testCanonicalRoute(unsigned).slice().buffer as ArrayBuffer, + ); + return { + route: { ...unsigned, certificate: { ...unsigned.certificate!, signature: toBase64(new Uint8Array(signature)) } }, + odinPublic, + providerPrivate: provider.privateKey, + expiresAt, + }; +} + +function signedHandshakeSocket(route: CultMeshBrowserRoute, providerPrivate: CryptoKey): FakeSocket { + let socket: FakeSocket; + socket = new FakeSocket(wire => { + const message = parseCultNetMessage(decode(wire)); + if (message.schemaVersion !== "cultmesh.session_open.v2") return; + void crypto.subtle.sign( + { name: "ECDSA", hash: "SHA-256" }, + providerPrivate, + testCanonicalSession(message, route.endpoint).slice().buffer as ArrayBuffer, + ).then(signature => socket.deliver({ + schemaVersion: "cultmesh.session_accepted.v2", + messageId: message.messageId, + accepted: true, + verseId: message.verseId, + authorityRuntimeId: message.authorityRuntimeId, + protocolId: message.protocolId, + routeGeneration: message.routeGeneration, + clientNonce: message.clientNonce, + providerKeyId: route.certificate!.providerKey.keyId, + providerSignature: toBase64(new Uint8Array(signature)), + })); + }, () => undefined); + return socket; +} + +async function exportPublic(keyId: string, key: CryptoKey): Promise { + const jwk = await crypto.subtle.exportKey("jwk", key); + return { keyId, x: urlBase64ToBase64(jwk.x!), y: urlBase64ToBase64(jwk.y!) }; +} + +function testCanonicalRoute(route: CultMeshBrowserRoute): Uint8Array { + const certificate = route.certificate!; + return testCanonical( + "gamecult.cultmesh.route-certificate.v1", route.verseId, route.authorityRuntimeId, route.endpoint, + [...route.protocolIds!].sort().join("\u001f"), String(route.priority), route.generation, + certificate.providerKey.keyId, certificate.providerKey.x, certificate.providerKey.y, + certificate.odinKeyId, String(certificate.issuedAtUnixMilliseconds), String(certificate.expiresAtUnixMilliseconds), + ); +} + +function testCanonicalSession(message: CultMeshSessionOpenMessage, endpoint: string): Uint8Array { + return testCanonical( + "gamecult.cultmesh.session-proof.v1", message.clientNonce, message.messageId, message.sourceRuntimeId, + message.verseId, message.authorityRuntimeId, message.protocolId, endpoint, message.routeGeneration, + ); +} + +function testCanonical(...values: string[]): Uint8Array { + const chunks = values.map(value => new TextEncoder().encode(value)); + const bytes = new Uint8Array(chunks.reduce((sum, chunk) => sum + 4 + chunk.length, 0)); + const view = new DataView(bytes.buffer); + let offset = 0; + for (const chunk of chunks) { + view.setUint32(offset, chunk.length, false); + offset += 4; + bytes.set(chunk, offset); + offset += chunk.length; + } + return bytes; +} + +function toBase64(bytes: Uint8Array): string { + return Buffer.from(bytes).toString("base64"); +} + +function urlBase64ToBase64(value: string): string { + return Buffer.from(value, "base64url").toString("base64"); +} + function bytesToBase64(bytes: Uint8Array): string { let binary = ""; for (const byte of bytes) binary += String.fromCharCode(byte); diff --git a/packages/cultnet-ts/contracts/cultmesh.session-accepted.schema.json b/packages/cultnet-ts/contracts/cultmesh.session-accepted.schema.json index 55a2f742..aca1ff2b 100644 --- a/packages/cultnet-ts/contracts/cultmesh.session-accepted.schema.json +++ b/packages/cultnet-ts/contracts/cultmesh.session-accepted.schema.json @@ -3,16 +3,19 @@ "$id": "https://github.com/GameCult/cultnet-ts/contracts/cultmesh.session-accepted.schema.json", "title": "CultMesh Session Accepted", "type": "object", - "required": ["schemaVersion", "messageId", "accepted", "verseId", "authorityRuntimeId", "protocolId", "routeGeneration"], + "required": ["schemaVersion", "messageId", "accepted", "verseId", "authorityRuntimeId", "protocolId", "routeGeneration", "clientNonce", "providerKeyId", "providerSignature"], "additionalProperties": false, "properties": { - "schemaVersion": { "const": "cultmesh.session_accepted.v1" }, + "schemaVersion": { "const": "cultmesh.session_accepted.v2" }, "messageId": { "type": "string", "minLength": 1 }, "accepted": { "type": "boolean" }, "verseId": { "type": "string", "minLength": 1 }, "authorityRuntimeId": { "type": "string", "minLength": 1 }, "protocolId": { "type": "string", "minLength": 1 }, "routeGeneration": { "type": "string" }, + "clientNonce": { "type": "string" }, + "providerKeyId": { "type": "string" }, + "providerSignature": { "type": "string" }, "error": { "type": "string", "minLength": 1 } } } diff --git a/packages/cultnet-ts/contracts/cultmesh.session-open.schema.json b/packages/cultnet-ts/contracts/cultmesh.session-open.schema.json index 14d945ed..937f3e28 100644 --- a/packages/cultnet-ts/contracts/cultmesh.session-open.schema.json +++ b/packages/cultnet-ts/contracts/cultmesh.session-open.schema.json @@ -3,15 +3,16 @@ "$id": "https://github.com/GameCult/cultnet-ts/contracts/cultmesh.session-open.schema.json", "title": "CultMesh Session Open", "type": "object", - "required": ["schemaVersion", "messageId", "sourceRuntimeId", "verseId", "authorityRuntimeId", "protocolId", "routeGeneration"], + "required": ["schemaVersion", "messageId", "sourceRuntimeId", "verseId", "authorityRuntimeId", "protocolId", "routeGeneration", "clientNonce"], "additionalProperties": false, "properties": { - "schemaVersion": { "const": "cultmesh.session_open.v1" }, + "schemaVersion": { "const": "cultmesh.session_open.v2" }, "messageId": { "type": "string", "minLength": 1 }, "sourceRuntimeId": { "type": "string", "minLength": 1 }, "verseId": { "type": "string", "minLength": 1 }, "authorityRuntimeId": { "type": "string", "minLength": 1 }, "protocolId": { "type": "string", "minLength": 1 }, - "routeGeneration": { "type": "string" } + "routeGeneration": { "type": "string" }, + "clientNonce": { "type": "string", "minLength": 1 } } } diff --git a/packages/cultnet-ts/contracts/cultmesh.verse-catalog-response.schema.json b/packages/cultnet-ts/contracts/cultmesh.verse-catalog-response.schema.json index 6e7551d5..f23ef5f7 100644 --- a/packages/cultnet-ts/contracts/cultmesh.verse-catalog-response.schema.json +++ b/packages/cultnet-ts/contracts/cultmesh.verse-catalog-response.schema.json @@ -27,7 +27,22 @@ "endpoint": { "type": "string", "minLength": 1 }, "protocolIds": { "type": "array", "items": { "type": "string", "minLength": 1 }, "uniqueItems": true }, "priority": { "type": "integer", "minimum": 0 }, - "generation": { "type": "string", "minLength": 1 } + "generation": { "type": "string", "minLength": 1 }, + "certificate": { "$ref": "#/$defs/routeCertificate" } + } + }, + "routeCertificate": { + "type": "object", + "required": ["providerKeyId", "providerPublicKeyX", "providerPublicKeyY", "odinKeyId", "issuedAtUnixMilliseconds", "expiresAtUnixMilliseconds", "signature"], + "additionalProperties": false, + "properties": { + "providerKeyId": { "type": "string", "minLength": 1 }, + "providerPublicKeyX": { "type": "string", "minLength": 1 }, + "providerPublicKeyY": { "type": "string", "minLength": 1 }, + "odinKeyId": { "type": "string", "minLength": 1 }, + "issuedAtUnixMilliseconds": { "type": "integer", "minimum": 0 }, + "expiresAtUnixMilliseconds": { "type": "integer", "minimum": 1 }, + "signature": { "type": "string", "minLength": 1 } } }, "verse": { diff --git a/packages/cultnet-ts/src/contracts.ts b/packages/cultnet-ts/src/contracts.ts index 2d86ad27..c71cdcc1 100644 --- a/packages/cultnet-ts/src/contracts.ts +++ b/packages/cultnet-ts/src/contracts.ts @@ -62,8 +62,8 @@ export type CultNetSchemaVersion = | "cultnet.operation_response.v0" | "cultmesh.verse_catalog_request.v0" | "cultmesh.verse_catalog_response.v0" - | "cultmesh.session_open.v1" - | "cultmesh.session_accepted.v1"; + | "cultmesh.session_open.v2" + | "cultmesh.session_accepted.v2"; export type CultNetSchemaKind = "wire_message" | "document_payload" | "shared_contract"; export type CultNetRawPayloadEncoding = "messagepack"; @@ -365,26 +365,41 @@ export interface CultMeshAuthorityRouteMessage { protocolIds: string[]; priority: number; generation: string; + certificate?: CultMeshRouteCertificateMessage; +} + +export interface CultMeshRouteCertificateMessage { + providerKeyId: string; + providerPublicKeyX: string; + providerPublicKeyY: string; + odinKeyId: string; + issuedAtUnixMilliseconds: number; + expiresAtUnixMilliseconds: number; + signature: string; } export interface CultMeshSessionOpenMessage { - schemaVersion: "cultmesh.session_open.v1"; + schemaVersion: "cultmesh.session_open.v2"; messageId: string; sourceRuntimeId: string; verseId: string; authorityRuntimeId: string; protocolId: string; routeGeneration: string; + clientNonce: string; } export interface CultMeshSessionAcceptedMessage { - schemaVersion: "cultmesh.session_accepted.v1"; + schemaVersion: "cultmesh.session_accepted.v2"; messageId: string; accepted: boolean; verseId: string; authorityRuntimeId: string; protocolId: string; routeGeneration: string; + clientNonce: string; + providerKeyId: string; + providerSignature: string; error?: string; } @@ -1236,7 +1251,7 @@ function normalizeCultNetOptionalNulls( } } return; - case "cultmesh.session_accepted.v1": + case "cultmesh.session_accepted.v2": stripNullProperties(candidate, ["error"]); return; case "cultnet.schema_catalog_request.v0": diff --git a/packages/cultnet-ts/test/cultnet.test.ts b/packages/cultnet-ts/test/cultnet.test.ts index f0f01b29..8d96c69a 100644 --- a/packages/cultnet-ts/test/cultnet.test.ts +++ b/packages/cultnet-ts/test/cultnet.test.ts @@ -97,15 +97,18 @@ test("CultNet validates the canonical CultMesh Verse catalog messages", () => { assert.equal(response.verses[0].authorityRoutes![0].generation, "provider-route-1"); const session = parseCultNetMessage({ - schemaVersion: "cultmesh.session_accepted.v1", + schemaVersion: "cultmesh.session_accepted.v2", messageId: "session-1", accepted: true, verseId: "sample.counter", authorityRuntimeId: "sample.counter-provider", protocolId: "cultmesh.documents.v1", routeGeneration: "provider-route-1", + clientNonce: "bm9uY2U=", + providerKeyId: "provider-key-1", + providerSignature: "c2lnbmF0dXJl", }); - assert.equal(session.schemaVersion, "cultmesh.session_accepted.v1"); + assert.equal(session.schemaVersion, "cultmesh.session_accepted.v2"); assert.throws(() => parseCultNetMessage({ ...response, diff --git a/samples/eve-browser-network/Program.cs b/samples/eve-browser-network/Program.cs index db92d3c1..bfadd7db 100644 --- a/samples/eve-browser-network/Program.cs +++ b/samples/eve-browser-network/Program.cs @@ -198,6 +198,10 @@ static async Task RunHeadlessAsync(Args arguments) CreateClient = CreateClient, TransportVersion = arguments.TransportVersion }, + Sessions = new CultMeshSessionManagerOptions + { + Trust = new CultMeshAuthorityTrustPolicy(CultMeshAuthorityTrustMode.LocalDevelopment) + }, Connectors = [ new CultMeshUriSchemaTransportConnector( diff --git a/samples/eve-browser-network/browser/main.ts b/samples/eve-browser-network/browser/main.ts index 3b0e28f9..8251a0a3 100644 --- a/samples/eve-browser-network/browser/main.ts +++ b/samples/eve-browser-network/browser/main.ts @@ -32,6 +32,7 @@ try { verseId: "sample.counter", authorityRuntimeId: "sample.counter-daemon", runtimeId: "sample.chromium", + trust: { mode: "local-development" }, rendezvous: new CultMeshBrowserOdinRendezvous({ endpoints: [odinEndpoint], runtimeId: "sample.chromium.discovery", diff --git a/scripts/pack-nuget.ps1 b/scripts/pack-nuget.ps1 index d6f4a224..fa0d12bd 100644 --- a/scripts/pack-nuget.ps1 +++ b/scripts/pack-nuget.ps1 @@ -34,7 +34,7 @@ foreach ($project in $projects) { "--nologo", "--verbosity", "quiet", "-p:NoWarn=1591%3BCS8632" ) if (-not [string]::IsNullOrWhiteSpace($PackageVersion)) { - $packArguments += "-p:Version=$PackageVersion" + $packArguments += "-p:CultLibPackageVersion=$PackageVersion" } & dotnet @packArguments if ($LASTEXITCODE -ne 0) { diff --git a/src/GameCult.Mesh/CultMeshAuthorityProof.cs b/src/GameCult.Mesh/CultMeshAuthorityProof.cs new file mode 100644 index 00000000..d4b2d0c8 --- /dev/null +++ b/src/GameCult.Mesh/CultMeshAuthorityProof.cs @@ -0,0 +1,349 @@ +using System; +using System.Buffers.Binary; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using GameCult.Networking; + +namespace GameCult.Mesh +{ + public enum CultMeshAuthorityTrustMode + { + AuthenticatedRemote, + LocalDevelopment + } + + public sealed class CultMeshEcdsaP256PublicKey + { + public CultMeshEcdsaP256PublicKey(string keyId, string x, string y) + { + KeyId = Require(keyId, nameof(keyId)); + X = RequireCoordinate(x, nameof(x)); + Y = RequireCoordinate(y, nameof(y)); + } + + public string KeyId { get; } + public string X { get; } + public string Y { get; } + + internal ECDsa CreateVerifier() + { + var verifier = ECDsa.Create(); + verifier.ImportParameters(new ECParameters + { + Curve = ECCurve.NamedCurves.nistP256, + Q = new ECPoint { X = Convert.FromBase64String(X), Y = Convert.FromBase64String(Y) } + }); + return verifier; + } + + public static CultMeshEcdsaP256PublicKey From(string keyId, ECDsa key) + { + if (key == null) throw new ArgumentNullException(nameof(key)); + var parameters = key.ExportParameters(false); + return new CultMeshEcdsaP256PublicKey( + keyId, + Convert.ToBase64String(parameters.Q.X ?? throw new InvalidOperationException("P-256 key has no X coordinate.")), + Convert.ToBase64String(parameters.Q.Y ?? throw new InvalidOperationException("P-256 key has no Y coordinate."))); + } + + private static string RequireCoordinate(string value, string name) + { + var required = Require(value, name); + byte[] bytes; + try { bytes = Convert.FromBase64String(required); } + catch (FormatException error) { throw new ArgumentException("P-256 coordinates must be base64.", name, error); } + if (bytes.Length != 32) throw new ArgumentException("P-256 coordinates must contain 32 bytes.", name); + return required; + } + + private static string Require(string value, string name) => + string.IsNullOrWhiteSpace(value) ? throw new ArgumentException("Value must be non-empty.", name) : value.Trim(); + } + + public sealed class CultMeshRouteCertificate + { + public CultMeshRouteCertificate( + CultMeshEcdsaP256PublicKey providerKey, + string odinKeyId, + long issuedAtUnixMilliseconds, + long expiresAtUnixMilliseconds, + string signature) + { + ProviderKey = providerKey ?? throw new ArgumentNullException(nameof(providerKey)); + OdinKeyId = string.IsNullOrWhiteSpace(odinKeyId) + ? throw new ArgumentException("Odin key identity is required.", nameof(odinKeyId)) + : odinKeyId.Trim(); + if (issuedAtUnixMilliseconds < 0) throw new ArgumentOutOfRangeException(nameof(issuedAtUnixMilliseconds)); + if (expiresAtUnixMilliseconds <= issuedAtUnixMilliseconds) throw new ArgumentOutOfRangeException(nameof(expiresAtUnixMilliseconds)); + IssuedAtUnixMilliseconds = issuedAtUnixMilliseconds; + ExpiresAtUnixMilliseconds = expiresAtUnixMilliseconds; + Signature = signature?.Trim() ?? string.Empty; + } + + public CultMeshEcdsaP256PublicKey ProviderKey { get; } + public string OdinKeyId { get; } + public long IssuedAtUnixMilliseconds { get; } + public long ExpiresAtUnixMilliseconds { get; } + public string Signature { get; } + } + + public sealed class CultMeshAuthorityTrustPolicy + { + private readonly Dictionary _odinRoots; + + public CultMeshAuthorityTrustPolicy( + CultMeshAuthorityTrustMode mode, + IEnumerable? odinRoots = null) + { + Mode = mode; + _odinRoots = (odinRoots ?? Array.Empty()) + .ToDictionary(key => key.KeyId, StringComparer.Ordinal); + } + + public CultMeshAuthorityTrustMode Mode { get; } + public IReadOnlyCollection OdinRoots => _odinRoots.Values; + + /// Fails closed unless the route is valid under this consumer-owned policy. + public void Validate(string verseId, CultMeshAuthorityRoute route, DateTimeOffset now) => + Verify(verseId, route, now); + + internal CultMeshVerifiedAuthorityRoute Verify( + string verseId, + CultMeshAuthorityRoute route, + DateTimeOffset now) + { + if (route == null) throw new ArgumentNullException(nameof(route)); + var certificate = route.Certificate; + if (certificate == null || string.IsNullOrWhiteSpace(certificate.Signature)) + { + if (Mode == CultMeshAuthorityTrustMode.LocalDevelopment && IsLoopback(route.Endpoint)) + return CultMeshVerifiedAuthorityRoute.Local(route); + throw Failure(route, "Remote CultMesh routes require an Odin-signed authority certificate."); + } + if (!IsProtected(route.Endpoint) && + !(Mode == CultMeshAuthorityTrustMode.LocalDevelopment && IsLoopback(route.Endpoint))) + throw Failure(route, "Authenticated remote CultMesh routes require TLS or QUIC channel protection."); + if (!_odinRoots.TryGetValue(certificate.OdinKeyId, out var root)) + throw Failure(route, $"Odin key '{certificate.OdinKeyId}' is not trusted by this consumer."); + var nowMs = now.ToUnixTimeMilliseconds(); + if (nowMs < certificate.IssuedAtUnixMilliseconds || nowMs >= certificate.ExpiresAtUnixMilliseconds) + throw Failure(route, "The Odin route certificate is not currently valid."); + byte[] signature; + try { signature = Convert.FromBase64String(certificate.Signature); } + catch (FormatException error) { throw Failure(route, "The Odin route signature is not base64.", error); } + if (signature.Length != 64) throw Failure(route, "The Odin route signature is not IEEE P1363 P-256."); + using var verifier = root.CreateVerifier(); + if (!verifier.VerifyData( + CultMeshAuthorityProof.CanonicalRoute(verseId, route), + signature, + HashAlgorithmName.SHA256)) + throw Failure(route, "The Odin route certificate signature is invalid."); + return CultMeshVerifiedAuthorityRoute.Authenticated(route, certificate.ProviderKey); + } + + private static bool IsLoopback(string endpoint) + { + if (!Uri.TryCreate(endpoint, UriKind.Absolute, out var uri)) return false; + return uri.IsLoopback || + string.Equals(uri.Host, "localhost", StringComparison.OrdinalIgnoreCase) || + string.Equals(uri.Host, "127.0.0.1", StringComparison.Ordinal) || + string.Equals(uri.Host, "::1", StringComparison.Ordinal); + } + + private static bool IsProtected(string endpoint) + { + if (!Uri.TryCreate(endpoint, UriKind.Absolute, out var uri)) return false; + return string.Equals(uri.Scheme, "wss", StringComparison.OrdinalIgnoreCase) || + string.Equals(uri.Scheme, "https", StringComparison.OrdinalIgnoreCase) || + uri.Scheme.IndexOf("quic", StringComparison.OrdinalIgnoreCase) >= 0; + } + + private static CultMeshSessionException Failure(CultMeshAuthorityRoute route, string message, Exception? inner = null) => + new CultMeshSessionException(new CultMeshSessionFailure( + CultMeshSessionFailureReason.Authentication, + message, + route.Endpoint), inner); + } + + internal sealed class CultMeshVerifiedAuthorityRoute + { + private CultMeshVerifiedAuthorityRoute( + CultMeshAuthorityRoute route, + CultMeshEcdsaP256PublicKey? providerKey, + bool localDevelopment) + { + Route = route; + ProviderKey = providerKey; + IsLocalDevelopment = localDevelopment; + } + + public CultMeshAuthorityRoute Route { get; } + public CultMeshEcdsaP256PublicKey? ProviderKey { get; } + public bool IsLocalDevelopment { get; } + public static CultMeshVerifiedAuthorityRoute Authenticated(CultMeshAuthorityRoute route, CultMeshEcdsaP256PublicKey key) => new(route, key, false); + public static CultMeshVerifiedAuthorityRoute Local(CultMeshAuthorityRoute route) => new(route, null, true); + } + + public sealed class CultMeshSessionProofSigner + { + private readonly ECDsa _key; + + public CultMeshSessionProofSigner(CultMeshAuthorityRoute route, ECDsa providerPrivateKey) + { + Route = route ?? throw new ArgumentNullException(nameof(route)); + _key = providerPrivateKey ?? throw new ArgumentNullException(nameof(providerPrivateKey)); + var certificate = route.Certificate ?? throw new ArgumentException("A session proof signer requires a certified route.", nameof(route)); + ProviderKeyId = certificate.ProviderKey.KeyId; + var exported = CultMeshEcdsaP256PublicKey.From(ProviderKeyId, _key); + if (!string.Equals(exported.X, certificate.ProviderKey.X, StringComparison.Ordinal) || + !string.Equals(exported.Y, certificate.ProviderKey.Y, StringComparison.Ordinal)) + throw new ArgumentException("Provider private key does not match the certified route key.", nameof(providerPrivateKey)); + } + + public CultMeshAuthorityRoute Route { get; } + public string ProviderKeyId { get; } + + public string Sign(CultMeshSessionOpenMessage request) + { + var bytes = CultMeshAuthorityProof.CanonicalSession(request, Route.Endpoint); + return Convert.ToBase64String(CultMeshAuthorityProof.SignP256(_key, bytes)); + } + } + + public static class CultMeshAuthorityProof + { + private const string RouteDomain = "gamecult.cultmesh.route-certificate.v1"; + private const string SessionDomain = "gamecult.cultmesh.session-proof.v1"; + + public static CultMeshAuthorityRoute CreateSignedRoute( + string verseId, + string authorityRuntimeId, + string endpoint, + IEnumerable protocolIds, + int priority, + string generation, + CultMeshEcdsaP256PublicKey providerKey, + string odinKeyId, + DateTimeOffset issuedAt, + DateTimeOffset expiresAt, + ECDsa odinPrivateKey) + { + if (odinPrivateKey == null) throw new ArgumentNullException(nameof(odinPrivateKey)); + var unsignedCertificate = new CultMeshRouteCertificate( + providerKey, + odinKeyId, + issuedAt.ToUnixTimeMilliseconds(), + expiresAt.ToUnixTimeMilliseconds(), + string.Empty); + var unsignedRoute = new CultMeshAuthorityRoute( + authorityRuntimeId, endpoint, protocolIds, priority, generation, unsignedCertificate); + var signature = Convert.ToBase64String(SignP256( + odinPrivateKey, + CanonicalRoute(verseId, unsignedRoute))); + return new CultMeshAuthorityRoute( + authorityRuntimeId, + endpoint, + protocolIds, + priority, + generation, + new CultMeshRouteCertificate( + providerKey, + odinKeyId, + issuedAt.ToUnixTimeMilliseconds(), + expiresAt.ToUnixTimeMilliseconds(), + signature)); + } + + /// Verifies both the Odin route certificate and provider nonce proof. + public static bool VerifySessionProof( + CultMeshSessionOpenMessage request, + CultMeshSessionAcceptedMessage response, + string verseId, + CultMeshAuthorityRoute route, + CultMeshAuthorityTrustPolicy trust, + DateTimeOffset now) + { + if (request == null) throw new ArgumentNullException(nameof(request)); + if (response == null) throw new ArgumentNullException(nameof(response)); + if (trust == null) throw new ArgumentNullException(nameof(trust)); + return VerifySession(request, response, trust.Verify(verseId, route, now)); + } + + internal static byte[] CanonicalRoute(string verseId, CultMeshAuthorityRoute route) + { + var certificate = route.Certificate ?? throw new InvalidOperationException("Route certificate is required."); + return Canonical( + RouteDomain, + verseId, + route.AuthorityRuntimeId, + route.Endpoint, + string.Join("\u001f", route.ProtocolIds.OrderBy(value => value, StringComparer.Ordinal)), + route.Priority.ToString(System.Globalization.CultureInfo.InvariantCulture), + route.Generation, + certificate.ProviderKey.KeyId, + certificate.ProviderKey.X, + certificate.ProviderKey.Y, + certificate.OdinKeyId, + certificate.IssuedAtUnixMilliseconds.ToString(System.Globalization.CultureInfo.InvariantCulture), + certificate.ExpiresAtUnixMilliseconds.ToString(System.Globalization.CultureInfo.InvariantCulture)); + } + + internal static byte[] CanonicalSession(CultMeshSessionOpenMessage request, string endpoint) => Canonical( + SessionDomain, + request.ClientNonce ?? string.Empty, + request.MessageId ?? string.Empty, + request.SourceRuntimeId ?? string.Empty, + request.VerseId ?? string.Empty, + request.AuthorityRuntimeId ?? string.Empty, + request.ProtocolId ?? string.Empty, + endpoint ?? string.Empty, + request.RouteGeneration ?? string.Empty); + + internal static bool VerifySession( + CultMeshSessionOpenMessage request, + CultMeshSessionAcceptedMessage response, + CultMeshVerifiedAuthorityRoute route) + { + if (route.IsLocalDevelopment) return true; + if (route.ProviderKey == null || + !string.Equals(response.ProviderKeyId, route.ProviderKey.KeyId, StringComparison.Ordinal) || + !string.Equals(response.ClientNonce, request.ClientNonce, StringComparison.Ordinal) || + string.IsNullOrWhiteSpace(response.ProviderSignature)) + return false; + byte[] signature; + try { signature = Convert.FromBase64String(response.ProviderSignature); } + catch (FormatException) { return false; } + if (signature.Length != 64) return false; + using var verifier = route.ProviderKey.CreateVerifier(); + return verifier.VerifyData( + CanonicalSession(request, route.Route.Endpoint), + signature, + HashAlgorithmName.SHA256); + } + + internal static byte[] SignP256(ECDsa key, byte[] payload) + { + var signature = key.SignData(payload, HashAlgorithmName.SHA256); + if (signature.Length != 64) + throw new CryptographicException("ECDSA provider did not emit IEEE P1363 P-256 signature bytes."); + return signature; + } + + private static byte[] Canonical(params string[] values) + { + using var stream = new MemoryStream(); + var length = new byte[4]; + foreach (var value in values) + { + var bytes = Encoding.UTF8.GetBytes(value ?? string.Empty); + BinaryPrimitives.WriteInt32BigEndian(length, bytes.Length); + stream.Write(length, 0, length.Length); + stream.Write(bytes, 0, bytes.Length); + } + return stream.ToArray(); + } + } +} diff --git a/src/GameCult.Mesh/CultMeshContentSessions.cs b/src/GameCult.Mesh/CultMeshContentSessions.cs index 4c562450..890dbfa8 100644 --- a/src/GameCult.Mesh/CultMeshContentSessions.cs +++ b/src/GameCult.Mesh/CultMeshContentSessions.cs @@ -136,7 +136,9 @@ namespace GameCult.Mesh "cultmesh-content-client", target, CultMeshProtocols.Content, - candidate.Generation, + candidate, + null, + _options.Clock.UtcNow, _options.ResponseTimeout, cancellationToken).ConfigureAwait(false); return new LegacyRudpContentTransport( diff --git a/src/GameCult.Mesh/CultMeshSessionIdentity.cs b/src/GameCult.Mesh/CultMeshSessionIdentity.cs index bb17a3d8..43a49162 100644 --- a/src/GameCult.Mesh/CultMeshSessionIdentity.cs +++ b/src/GameCult.Mesh/CultMeshSessionIdentity.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; using GameCult.Networking; @@ -68,6 +69,7 @@ namespace GameCult.Mesh private readonly HashSet _verseIds; private readonly HashSet _protocolIds; private readonly HashSet _routeGenerations; + private readonly Dictionary _proofSigners; private readonly Func _handler; private bool _disposed; @@ -76,13 +78,16 @@ namespace GameCult.Mesh string authorityRuntimeId, IEnumerable verseIds, IEnumerable protocolIds, - IEnumerable routeGenerations) + IEnumerable routeGenerations, + IEnumerable? proofSigners = null) { _server = server ?? throw new ArgumentNullException(nameof(server)); _authorityRuntimeId = Require(authorityRuntimeId, nameof(authorityRuntimeId)); _verseIds = Clean(verseIds, nameof(verseIds)); _protocolIds = Clean(protocolIds, nameof(protocolIds)); _routeGenerations = Clean(routeGenerations, nameof(routeGenerations)); + _proofSigners = (proofSigners ?? Array.Empty()) + .ToDictionary(signer => signer.Route.Generation, StringComparer.Ordinal); _handler = HandleAsync; _server.OnCultNet(_handler); } @@ -97,6 +102,7 @@ namespace GameCult.Mesh private Task HandleAsync(CultMeshSessionOpenMessage request, ICultNetSchemaServerPeer peer) { var error = Validate(request); + _proofSigners.TryGetValue(request.RouteGeneration ?? string.Empty, out var signer); peer.SendCultNet(new CultMeshSessionAcceptedMessage { MessageId = request.MessageId ?? string.Empty, @@ -105,6 +111,9 @@ namespace GameCult.Mesh AuthorityRuntimeId = _authorityRuntimeId, ProtocolId = request.ProtocolId ?? string.Empty, RouteGeneration = request.RouteGeneration ?? string.Empty, + ClientNonce = request.ClientNonce ?? string.Empty, + ProviderKeyId = error == null ? signer?.ProviderKeyId ?? string.Empty : string.Empty, + ProviderSignature = error == null && signer != null ? signer.Sign(request) : string.Empty, Error = error }); return Task.CompletedTask; @@ -114,6 +123,7 @@ namespace GameCult.Mesh { if (string.IsNullOrWhiteSpace(request.MessageId)) return "session-message-id-required"; if (string.IsNullOrWhiteSpace(request.SourceRuntimeId)) return "source-runtime-id-required"; + if (!TryNonce(request.ClientNonce)) return "client-nonce-invalid"; if (!string.Equals(request.AuthorityRuntimeId, _authorityRuntimeId, StringComparison.Ordinal)) return "target-runtime-mismatch"; if (!_verseIds.Contains(request.VerseId ?? string.Empty)) return "verse-not-served"; @@ -122,6 +132,13 @@ namespace GameCult.Mesh return null; } + private static bool TryNonce(string? value) + { + if (string.IsNullOrWhiteSpace(value)) return false; + try { return Convert.FromBase64String(value).Length == 32; } + catch (FormatException) { return false; } + } + private static HashSet Clean(IEnumerable values, string name) { if (values == null) throw new ArgumentNullException(name); @@ -145,26 +162,45 @@ namespace GameCult.Mesh string sourceRuntimeId, CultMeshSessionTarget target, CultMeshProtocolId protocol, - string routeGeneration, + CultMeshTransportCandidate candidate, + CultMeshAuthorityTrustPolicy? trust, + DateTimeOffset now, TimeSpan timeout, CancellationToken cancellationToken = default) { if (client == null) throw new ArgumentNullException(nameof(client)); + if (candidate == null) throw new ArgumentNullException(nameof(candidate)); + var route = candidate.AuthorityRoute ?? new CultMeshAuthorityRoute( + target.AuthorityRuntimeId, + candidate.Endpoint, + new[] { protocol.Value }, + candidate.Priority, + candidate.Generation); + var verifiedRoute = candidate.VerifiedAuthority ?? + (trust ?? throw new CultMeshSessionException(new CultMeshSessionFailure( + CultMeshSessionFailureReason.Authentication, + "No consumer trust policy verified this CultMesh route.", + candidate.Endpoint))).Verify(target.VerseId, route, now); if (client is ICultMeshVerifiedSchemaClient verified) { if (!verified.IsVerifiedFor( target.VerseId, target.AuthorityRuntimeId, protocol.Value, - routeGeneration ?? string.Empty)) + candidate.Generation)) { throw new CultMeshSessionException(new CultMeshSessionFailure( CultMeshSessionFailureReason.Authority, $"Native transport identity did not match CultMesh target '{target}' for '{protocol}'.")); } - return; + // Native identity is sufficient only for an explicitly selected + // loopback development route. Remote schema sessions still prove + // possession of the provider key certified by Odin. + if (verifiedRoute.IsLocalDevelopment) return; } var messageId = Guid.NewGuid().ToString("N"); + var nonce = new byte[32]; + using (var random = RandomNumberGenerator.Create()) random.GetBytes(nonce); var completion = new TaskCompletionSource( TaskCreationOptions.RunContinuationsAsynchronously); client.OnCultNet(response => @@ -172,15 +208,17 @@ namespace GameCult.Mesh if (string.Equals(response.MessageId, messageId, StringComparison.Ordinal)) completion.TrySetResult(response); }); - client.SendCultNet(new CultMeshSessionOpenMessage + var request = new CultMeshSessionOpenMessage { MessageId = messageId, SourceRuntimeId = sourceRuntimeId, VerseId = target.VerseId, AuthorityRuntimeId = target.AuthorityRuntimeId, ProtocolId = protocol.Value, - RouteGeneration = routeGeneration ?? string.Empty - }); + RouteGeneration = candidate.Generation, + ClientNonce = Convert.ToBase64String(nonce) + }; + client.SendCultNet(request); using var deadline = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); deadline.CancelAfter(timeout); @@ -201,7 +239,8 @@ namespace GameCult.Mesh !string.Equals(accepted.VerseId, target.VerseId, StringComparison.Ordinal) || !string.Equals(accepted.AuthorityRuntimeId, target.AuthorityRuntimeId, StringComparison.Ordinal) || !string.Equals(accepted.ProtocolId, protocol.Value, StringComparison.Ordinal) || - !string.Equals(accepted.RouteGeneration, routeGeneration ?? string.Empty, StringComparison.Ordinal)) + !string.Equals(accepted.RouteGeneration, candidate.Generation, StringComparison.Ordinal) || + !CultMeshAuthorityProof.VerifySession(request, accepted, verifiedRoute)) { throw new CultMeshSessionException(new CultMeshSessionFailure( CultMeshSessionFailureReason.Authority, diff --git a/src/GameCult.Mesh/CultMeshSessions.cs b/src/GameCult.Mesh/CultMeshSessions.cs index 7db6f06b..b0dace01 100644 --- a/src/GameCult.Mesh/CultMeshSessions.cs +++ b/src/GameCult.Mesh/CultMeshSessions.cs @@ -86,19 +86,28 @@ namespace GameCult.Mesh CultMeshTransportPathKind pathKind = CultMeshTransportPathKind.Direct, int priority = 0, string authorityRuntimeId = "", - string generation = "") + string generation = "", + CultMeshAuthorityRoute? authorityRoute = null) { Endpoint = string.IsNullOrWhiteSpace(endpoint) ? throw new ArgumentException("Physical endpoint is required.", nameof(endpoint)) : endpoint; PathKind = pathKind; Priority = priority; AuthorityRuntimeId = authorityRuntimeId?.Trim() ?? string.Empty; Generation = generation?.Trim() ?? string.Empty; + AuthorityRoute = authorityRoute; } public string Endpoint { get; } public CultMeshTransportPathKind PathKind { get; } public int Priority { get; } public string AuthorityRuntimeId { get; } public string Generation { get; } + public CultMeshAuthorityRoute? AuthorityRoute { get; } + internal CultMeshVerifiedAuthorityRoute? VerifiedAuthority { get; private set; } + internal CultMeshTransportCandidate WithVerifiedAuthority(CultMeshVerifiedAuthorityRoute verified) + { + VerifiedAuthority = verified ?? throw new ArgumentNullException(nameof(verified)); + return this; + } } public enum CultMeshSessionStatus { Connecting, Online, Degraded, Reconnecting, Offline } @@ -534,6 +543,9 @@ namespace GameCult.Mesh public int MaxRacedCandidates { get; set; } = 2; public string RuntimeId { get; set; } = "cultmesh-client"; public TimeSpan IdentityHandshakeTimeout { get; set; } = TimeSpan.FromSeconds(5); + /// Gets or sets the consumer-owned trust roots and explicit local-development policy. + public CultMeshAuthorityTrustPolicy Trust { get; set; } = new( + CultMeshAuthorityTrustMode.AuthenticatedRemote); } public sealed class CultMeshSessionManager : IDisposable @@ -1039,7 +1051,9 @@ namespace GameCult.Mesh _options.RuntimeId, target, protocol, - route.Candidate.Generation, + route.Candidate, + _options.Trust, + _options.Clock.UtcNow, _options.IdentityHandshakeTimeout).ConfigureAwait(false); return new ConnectedPath(route.Candidate, client); } @@ -1065,7 +1079,7 @@ namespace GameCult.Mesh private CultMeshSessionException Failure(CultMeshSessionFailureReason reason, string message, Exception? inner = null) => new CultMeshSessionException(new CultMeshSessionFailure(reason, message), inner); - private static CultMeshTransportCandidate[] BoundCandidates( + private CultMeshTransportCandidate[] BoundCandidates( CultMeshDiscoveryState discovery, CultMeshSessionTarget target, CultMeshProtocolId protocol) @@ -1080,10 +1094,15 @@ namespace GameCult.Mesh .GroupBy(route => route.Endpoint, StringComparer.Ordinal) .Select(group => group.OrderBy(route => route.Priority).First()) .Select(route => new CultMeshTransportCandidate( - route.Endpoint, - priority: route.Priority, - authorityRuntimeId: route.AuthorityRuntimeId, - generation: route.Generation)) + route.Endpoint, + priority: route.Priority, + authorityRuntimeId: route.AuthorityRuntimeId, + generation: route.Generation, + authorityRoute: route) + .WithVerifiedAuthority(_options.Trust.Verify( + target.VerseId, + route, + _options.Clock.UtcNow))) .OrderBy(candidate => candidate.Priority) .ThenBy(candidate => candidate.Endpoint, StringComparer.Ordinal) .ToArray(); diff --git a/src/GameCult.Mesh/CultMeshTcpContentTransport.cs b/src/GameCult.Mesh/CultMeshTcpContentTransport.cs index f47f08bd..dcb07feb 100644 --- a/src/GameCult.Mesh/CultMeshTcpContentTransport.cs +++ b/src/GameCult.Mesh/CultMeshTcpContentTransport.cs @@ -17,6 +17,7 @@ namespace GameCult.Mesh public string VerseId { get; set; } = string.Empty; public string AuthorityRuntimeId { get; set; } = string.Empty; public string RouteGeneration { get; set; } = string.Empty; + public CultMeshSessionProofSigner? ProofSigner { get; set; } internal void Validate() { @@ -344,7 +345,10 @@ namespace GameCult.Mesh var requestBytes = await CultMeshTcpContentWire.ReadFrameAsync(stream, cancellationToken).ConfigureAwait(false); var request = CultNetSchemaMessageSerialization.Deserialize(requestBytes) as CultMeshSessionOpenMessage ?? throw new InvalidDataException("TCP content session did not begin with an authority handshake."); - var accepted = string.Equals(request.VerseId, _options.VerseId, StringComparison.Ordinal) && + var accepted = !string.IsNullOrWhiteSpace(request.MessageId) && + !string.IsNullOrWhiteSpace(request.SourceRuntimeId) && + IsNonce(request.ClientNonce) && + string.Equals(request.VerseId, _options.VerseId, StringComparison.Ordinal) && string.Equals(request.AuthorityRuntimeId, _options.AuthorityRuntimeId, StringComparison.Ordinal) && string.Equals(request.ProtocolId, CultMeshProtocols.Content.Value, StringComparison.Ordinal) && string.Equals(request.RouteGeneration, _options.RouteGeneration, StringComparison.Ordinal); @@ -356,6 +360,11 @@ namespace GameCult.Mesh AuthorityRuntimeId = _options.AuthorityRuntimeId, ProtocolId = CultMeshProtocols.Content.Value, RouteGeneration = _options.RouteGeneration, + ClientNonce = request.ClientNonce ?? string.Empty, + ProviderKeyId = accepted ? _options.ProofSigner?.ProviderKeyId ?? string.Empty : string.Empty, + ProviderSignature = accepted && _options.ProofSigner != null + ? _options.ProofSigner.Sign(request) + : string.Empty, Error = accepted ? null : "Content session target does not match this authority route." }; await CultMeshTcpContentWire.WriteFrameAsync( @@ -365,6 +374,13 @@ namespace GameCult.Mesh return accepted; } + private static bool IsNonce(string? value) + { + if (string.IsNullOrWhiteSpace(value)) return false; + try { return Convert.FromBase64String(value).Length == 32; } + catch (FormatException) { return false; } + } + private async Task SendChunkAsync( Stream stream, CultMeshContentChunkRequestMessage request, @@ -473,7 +489,8 @@ namespace GameCult.Mesh VerseId = target.VerseId, AuthorityRuntimeId = target.AuthorityRuntimeId, ProtocolId = CultMeshProtocols.Content.Value, - RouteGeneration = candidate.Generation + RouteGeneration = candidate.Generation, + ClientNonce = CreateNonce() }; await WriteFrameAsync(stream, CultNetSchemaMessageSerialization.Serialize(request), cancellationToken) .ConfigureAwait(false); @@ -485,13 +502,22 @@ namespace GameCult.Mesh !string.Equals(response.VerseId, target.VerseId, StringComparison.Ordinal) || !string.Equals(response.AuthorityRuntimeId, target.AuthorityRuntimeId, StringComparison.Ordinal) || !string.Equals(response.ProtocolId, CultMeshProtocols.Content.Value, StringComparison.Ordinal) || - !string.Equals(response.RouteGeneration, candidate.Generation, StringComparison.Ordinal)) + !string.Equals(response.RouteGeneration, candidate.Generation, StringComparison.Ordinal) || + candidate.VerifiedAuthority == null || + !CultMeshAuthorityProof.VerifySession(request, response, candidate.VerifiedAuthority)) throw new CultMeshSessionException(new CultMeshSessionFailure( CultMeshSessionFailureReason.Authority, response.Error ?? "TCP content endpoint did not prove the selected authority route.", candidate.Endpoint)); } + private static string CreateNonce() + { + var nonce = new byte[32]; + using (var random = System.Security.Cryptography.RandomNumberGenerator.Create()) random.GetBytes(nonce); + return Convert.ToBase64String(nonce); + } + public static async Task ReadFrameAsync(Stream stream, CancellationToken cancellationToken) { var header = new byte[HeaderBytes]; diff --git a/src/GameCult.Mesh/CultMeshVerse.cs b/src/GameCult.Mesh/CultMeshVerse.cs index 55d6deeb..003dc161 100644 --- a/src/GameCult.Mesh/CultMeshVerse.cs +++ b/src/GameCult.Mesh/CultMeshVerse.cs @@ -102,7 +102,8 @@ namespace GameCult.Mesh string endpoint, IEnumerable? protocolIds = null, int priority = 0, - string? generation = null) + string? generation = null, + CultMeshRouteCertificate? certificate = null) { AuthorityRuntimeId = RequireNonEmpty(authorityRuntimeId, nameof(authorityRuntimeId)); Endpoint = RequireNonEmpty(endpoint, nameof(endpoint)); @@ -112,6 +113,7 @@ namespace GameCult.Mesh Generation = string.IsNullOrWhiteSpace(generation) ? AuthorityRuntimeId + "@" + Endpoint : generation!.Trim(); + Certificate = certificate; } public string AuthorityRuntimeId { get; } @@ -119,6 +121,8 @@ namespace GameCult.Mesh public IReadOnlyList ProtocolIds { get; } public int Priority { get; } public string Generation { get; } + /// Gets the optional Odin-signed binding from this route to its provider key. + public CultMeshRouteCertificate? Certificate { get; } public bool Supports(CultMeshProtocolId protocol) => protocol != null && diff --git a/src/GameCult.Mesh/CultMeshVerseDiscovery.cs b/src/GameCult.Mesh/CultMeshVerseDiscovery.cs index 774a05f9..c4ee15c7 100644 --- a/src/GameCult.Mesh/CultMeshVerseDiscovery.cs +++ b/src/GameCult.Mesh/CultMeshVerseDiscovery.cs @@ -39,7 +39,17 @@ namespace GameCult.Mesh Endpoint = route.Endpoint, ProtocolIds = route.ProtocolIds.ToArray(), Priority = route.Priority, - Generation = route.Generation + Generation = route.Generation, + Certificate = route.Certificate == null ? null : new CultMeshRouteCertificateMessage + { + ProviderKeyId = route.Certificate.ProviderKey.KeyId, + ProviderPublicKeyX = route.Certificate.ProviderKey.X, + ProviderPublicKeyY = route.Certificate.ProviderKey.Y, + OdinKeyId = route.Certificate.OdinKeyId, + IssuedAtUnixMilliseconds = route.Certificate.IssuedAtUnixMilliseconds, + ExpiresAtUnixMilliseconds = route.Certificate.ExpiresAtUnixMilliseconds, + Signature = route.Certificate.Signature + } }).ToArray(), ParentVerseId = verse.ParentVerseId, Description = verse.Description @@ -63,7 +73,16 @@ namespace GameCult.Mesh route.Endpoint, route.ProtocolIds, route.Priority, - route.Generation)).ToArray(); + route.Generation, + route.Certificate == null ? null : new CultMeshRouteCertificate( + new CultMeshEcdsaP256PublicKey( + route.Certificate.ProviderKeyId, + route.Certificate.ProviderPublicKeyX, + route.Certificate.ProviderPublicKeyY), + route.Certificate.OdinKeyId, + route.Certificate.IssuedAtUnixMilliseconds, + route.Certificate.ExpiresAtUnixMilliseconds, + route.Certificate.Signature))).ToArray(); return new CultMeshVerseDescriptor( message.VerseId, message.DisplayName, diff --git a/src/GameCult.Mesh/docs/browser-verse-transport.md b/src/GameCult.Mesh/docs/browser-verse-transport.md index ecec20ef..fcfde998 100644 --- a/src/GameCult.Mesh/docs/browser-verse-transport.md +++ b/src/GameCult.Mesh/docs/browser-verse-transport.md @@ -8,7 +8,8 @@ This is the implementation map for the browser Verse boundary. `samples/eve-two-runtime` remains the clean package-consumer/jsdom checkpoint. `samples/eve-browser-network` runs a durable C# provider, a real Chromium Eve lowerer, an independent C# headless observer, and a separate local Odin fixture -over authenticated binary CultNet WebSocket routes. It proves one canonical +over binary loopback CultNet WebSocket routes under an explicit +`local-development` trust policy. It proves one canonical command effect, idempotent retry, shared observation, provider restart on a new physical route, browser rediscovery, retained lease resubscription, and a second canonical command after reconnection. @@ -29,6 +30,10 @@ not a complete public Verse proof: `cultmesh.verse_catalog_request.v0` and `cultmesh.verse_catalog_response.v0`; application callbacks no longer need to smuggle provider URLs into the browser client; +- `CultMeshBrowserClient` owns the final authority gate: remote use requires a + consumer-pinned Odin P-256 root, an Odin-signed route certificate, `wss://`, + and provider possession proof over a fresh nonce. A catalog source cannot + bypass that gate by returning a route-shaped object; - Kotlin has a channel-aware WebSocket transport adapter, TypeScript has the browser client, and `GameCult.Networking.WebSockets` provides the bounded C# schema server host adapter; @@ -58,9 +63,9 @@ Owner: Inputs: -- an Odin-discovered WebSocket transport candidate; +- an Odin-discovered route certificate and consumer-configured Odin root; - stable Verse and provider identities; -- authenticated session evidence; +- provider key possession over a fresh client nonce; - requested schema ids and record keys; - typed operation invocations and idempotency keys; - canonical CultNet schema-v0 MessagePack messages. diff --git a/src/GameCult.Mesh/docs/getting-started/02-connect-by-identity.md b/src/GameCult.Mesh/docs/getting-started/02-connect-by-identity.md index ee505acb..28cc06ad 100644 --- a/src/GameCult.Mesh/docs/getting-started/02-connect-by-identity.md +++ b/src/GameCult.Mesh/docs/getting-started/02-connect-by-identity.md @@ -9,9 +9,10 @@ selection owner then resolves the provider runtime from Odin's descriptor before opening the session. Discovery owns the current physical routes, and the session manager owns connection reuse, path rotation, and transport failure state. Each Odin route binds that authority runtime to one endpoint, protocol set, and -generation. The client verifies the same tuple with the connected peer before -the session becomes online; runtime membership and endpoint reachability are -not independent routing evidence. +generation. For a remote Verse, Odin signs that exact tuple and the provider's +P-256 public key. The client pins an Odin root from its own configuration, then +requires the connected provider to sign a fresh client nonce. A route cannot +become usable by merely repeating the expected Verse and runtime strings. ```csharp using GameCult.Mesh; @@ -22,9 +23,22 @@ const string verseId = "sample.counter"; var target = new CultMeshSessionTarget(verseId, "sample.counter-daemon"); using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(30)); var cancellationToken = timeout.Token; +var odinRoot = new CultMeshEcdsaP256PublicKey( + Environment.GetEnvironmentVariable("ODIN_ROOT_KEY_ID") + ?? throw new InvalidOperationException("Set ODIN_ROOT_KEY_ID."), + Environment.GetEnvironmentVariable("ODIN_ROOT_P256_X") + ?? throw new InvalidOperationException("Set ODIN_ROOT_P256_X."), + Environment.GetEnvironmentVariable("ODIN_ROOT_P256_Y") + ?? throw new InvalidOperationException("Set ODIN_ROOT_P256_Y.")); using var mesh = new CultMeshClient(new CultMeshClientOptions { - RendezvousEndpoints = new[] { odinEndpoint } + RendezvousEndpoints = new[] { odinEndpoint }, + Sessions = new CultMeshSessionManagerOptions + { + Trust = new CultMeshAuthorityTrustPolicy( + CultMeshAuthorityTrustMode.AuthenticatedRemote, + new[] { odinRoot }) + } }); using var counterLease = await mesh.LeaseDocumentAsync( @@ -64,6 +78,21 @@ using var stateWatch = session.WatchState().Subscribe(state => Application code does not reconnect, sleep, rank endpoints, or replace the session. Those decisions belong to CultMesh. +For a deliberately local, moddable Verse, select the exception explicitly and +use only in-process or loopback routes: + +```csharp +Sessions = new CultMeshSessionManagerOptions +{ + Trust = new CultMeshAuthorityTrustPolicy(CultMeshAuthorityTrustMode.LocalDevelopment) +} +``` + +`LocalDevelopment` never accepts an unsigned non-loopback route. Verse names, +provider names, and Odin wire fields cannot turn this exception on. Remote +routes require a trusted Odin signature, provider nonce proof, certificate +validity, and a protected channel. + Fast session-management check (this uses controlled transports; it is not the network proof): @@ -71,7 +100,7 @@ network proof): dotnet test tests/GameCult.Mesh.Tests/GameCult.Mesh.Tests.csproj --filter FullyQualifiedName~CultMeshSessionManagerTests ``` -The real checkpoint in chapter 4 additionally advertises a better-priority +The local checkpoint in chapter 4 additionally advertises a better-priority endpoint for the wrong authority runtime. Both the C# and browser clients must ignore it, verify the intended peer, survive route replacement, and reject wrong-source operation responses. diff --git a/src/GameCult.Mesh/docs/transport-planes.md b/src/GameCult.Mesh/docs/transport-planes.md index bd42a071..fea2b69b 100644 --- a/src/GameCult.Mesh/docs/transport-planes.md +++ b/src/GameCult.Mesh/docs/transport-planes.md @@ -64,13 +64,20 @@ operation. transport diagnostics. None of these grant provider authority or become content identity. -Before a schema, content, or realtime session becomes online, the transport -must prove that the connected peer matches the selected Verse, authority -runtime, protocol, and route generation. TCP schema and content lanes use the -portable CultNet session-open handshake. QUIC uses the exact Odin-bound route -plus its TLS endpoint/certificate proof. A connector that returns bytes without -authority proof is rejected; racing every endpoint in a Verse descriptor is -not route selection. +Before a schema, content, or realtime session becomes online, consumer-owned +trust verifies an Odin-signed route certificate binding Verse, authority +runtime, protocol set, endpoint, generation, validity interval, and provider +P-256 key. Schema and content lanes then require a fresh client nonce signed by +that provider key. QUIC uses the signed endpoint plus its TLS +endpoint/certificate proof. A connector that returns bytes without this chain +is rejected; racing every endpoint in a Verse descriptor is not route +selection. Unsigned traffic exists only under an explicitly selected +`LocalDevelopment` policy and only for in-process or loopback routes. + +Route and session signatures use ECDSA P-256 with SHA-256 and fixed-width IEEE +P1363 `r || s` encoding, matching browser WebCrypto. Their canonical +transcripts are ordered UTF-8 fields prefixed by four-byte big-endian lengths; +serializer bytes are never signature authority. **Forbidden writers:** applications and renderers do not choose unadvertised endpoints, implement reconnect loops, or bypass verification. Schema messages @@ -94,7 +101,8 @@ new seam does not pretend that migration has already occurred. ## Security and release gate The current TCP control and content connectors are plaintext and therefore -restricted to local or otherwise trusted deployment. Adding TLS must not move +restricted to explicit loopback development. They cannot carry an authenticated +remote session. Adding TLS must not move discovery, authorization, content verification, or application semantics into the TCP adapter. diff --git a/src/GameCult.Networking/CultNetSchemaMessages.cs b/src/GameCult.Networking/CultNetSchemaMessages.cs index 2117693d..56370207 100644 --- a/src/GameCult.Networking/CultNetSchemaMessages.cs +++ b/src/GameCult.Networking/CultNetSchemaMessages.cs @@ -136,9 +136,9 @@ namespace GameCult.Networking /// public const string VerseCatalogResponse = "cultmesh.verse_catalog_response.v0"; /// CultMesh session identity request contract identifier. - public const string SessionOpen = "cultmesh.session_open.v1"; + public const string SessionOpen = "cultmesh.session_open.v2"; /// CultMesh verified session identity response contract identifier. - public const string SessionAccepted = "cultmesh.session_accepted.v1"; + public const string SessionAccepted = "cultmesh.session_accepted.v2"; /// /// CultMesh peer exchange request contract identifier. /// @@ -1194,6 +1194,7 @@ namespace GameCult.Networking [Key("authorityRuntimeId")] public string AuthorityRuntimeId { get; set; } = string.Empty; [Key("protocolId")] public string ProtocolId { get; set; } = string.Empty; [Key("routeGeneration")] public string RouteGeneration { get; set; } = string.Empty; + [Key("clientNonce")] public string ClientNonce { get; set; } = string.Empty; } /// Accepts or rejects a CultMesh session with the server's actual identity. @@ -1207,6 +1208,9 @@ namespace GameCult.Networking [Key("authorityRuntimeId")] public string AuthorityRuntimeId { get; set; } = string.Empty; [Key("protocolId")] public string ProtocolId { get; set; } = string.Empty; [Key("routeGeneration")] public string RouteGeneration { get; set; } = string.Empty; + [Key("clientNonce")] public string ClientNonce { get; set; } = string.Empty; + [Key("providerKeyId")] public string ProviderKeyId { get; set; } = string.Empty; + [Key("providerSignature")] public string ProviderSignature { get; set; } = string.Empty; [Key("error")] public string? Error { get; set; } } @@ -1308,6 +1312,19 @@ namespace GameCult.Networking [Key("protocolIds")] public string[] ProtocolIds { get; set; } = Array.Empty(); [Key("priority")] public int Priority { get; set; } [Key("generation")] public string Generation { get; set; } = string.Empty; + [Key("certificate")] public CultMeshRouteCertificateMessage? Certificate { get; set; } + } + + [MessagePackObject] + public class CultMeshRouteCertificateMessage + { + [Key("providerKeyId")] public string ProviderKeyId { get; set; } = string.Empty; + [Key("providerPublicKeyX")] public string ProviderPublicKeyX { get; set; } = string.Empty; + [Key("providerPublicKeyY")] public string ProviderPublicKeyY { get; set; } = string.Empty; + [Key("odinKeyId")] public string OdinKeyId { get; set; } = string.Empty; + [Key("issuedAtUnixMilliseconds")] public long IssuedAtUnixMilliseconds { get; set; } + [Key("expiresAtUnixMilliseconds")] public long ExpiresAtUnixMilliseconds { get; set; } + [Key("signature")] public string Signature { get; set; } = string.Empty; } /// diff --git a/tests/GameCult.Mesh.Tests/CultMeshAuthorityProofTests.cs b/tests/GameCult.Mesh.Tests/CultMeshAuthorityProofTests.cs new file mode 100644 index 00000000..88c7e803 --- /dev/null +++ b/tests/GameCult.Mesh.Tests/CultMeshAuthorityProofTests.cs @@ -0,0 +1,241 @@ +using System; +using System.Collections.Generic; +using System.Security.Cryptography; +using System.Threading; +using System.Threading.Tasks; +using FluentAssertions; +using GameCult.Networking; +using NUnit.Framework; + +namespace GameCult.Mesh.Tests; + +public sealed class CultMeshAuthorityProofTests +{ + private static readonly DateTimeOffset Now = DateTimeOffset.FromUnixTimeMilliseconds(1_800_000_000_000); + + [Test] + public void SignedRouteBindsEveryAuthorityFieldToConsumerTrust() + { + using var odin = ECDsa.Create(ECCurve.NamedCurves.nistP256); + using var provider = ECDsa.Create(ECCurve.NamedCurves.nistP256); + var route = SignedRoute(odin, provider); + var trust = Trust(odin); + + trust.Validate("aetheria", route, Now); + var wireRoundTrip = new CultMeshVerseDescriptor( + "aetheria", + "Aetheria", + CultMeshVerseAuthorityModel.OperatorCluster, + new CultMeshVerseCompatibility("cultmesh.v0", "rules"), + authorityRoutes: new[] { route }) + .ToMessage() + .ToVerseDescriptor() + .AuthorityRoutes[0]; + trust.Validate("aetheria", wireRoundTrip, Now); + wireRoundTrip.Certificate!.ProviderKey.KeyId.Should().Be("provider-1"); + + Action mutatedEndpoint = () => trust.Validate("aetheria", new CultMeshAuthorityRoute( + route.AuthorityRuntimeId, + "wss://evil.example/mesh", + route.ProtocolIds, + route.Priority, + route.Generation, + route.Certificate), Now); + mutatedEndpoint.Should().Throw() + .Which.Failure.Reason.Should().Be(CultMeshSessionFailureReason.Authentication); + } + + [Test] + public void RemoteTrustRejectsUnknownExpiredAndUnsignedRoutes() + { + using var odin = ECDsa.Create(ECCurve.NamedCurves.nistP256); + using var provider = ECDsa.Create(ECCurve.NamedCurves.nistP256); + using var stranger = ECDsa.Create(ECCurve.NamedCurves.nistP256); + var route = SignedRoute(odin, provider); + + Action unknownRoot = () => Trust(stranger).Validate("aetheria", route, Now); + Action expired = () => Trust(odin).Validate("aetheria", route, Now.AddHours(2)); + Action unsigned = () => Trust(odin).Validate("aetheria", new CultMeshAuthorityRoute( + "aetheria-daemon", "wss://provider.example/mesh", + new[] { CultMeshProtocols.Documents.Value }, generation: "generation-1"), Now); + + unknownRoot.Should().Throw(); + expired.Should().Throw(); + unsigned.Should().Throw(); + } + + [Test] + public void UnsignedRouteRequiresExplicitLoopbackDevelopmentPolicy() + { + var local = new CultMeshAuthorityRoute( + "aetheria-daemon", "rudp://127.0.0.1:3076", + new[] { CultMeshProtocols.Documents.Value }, generation: "local"); + var remote = new CultMeshAuthorityRoute( + "aetheria-daemon", "rudp://192.0.2.10:3076", + new[] { CultMeshProtocols.Documents.Value }, generation: "remote"); + var policy = new CultMeshAuthorityTrustPolicy(CultMeshAuthorityTrustMode.LocalDevelopment); + + policy.Validate("aetheria", local, Now); + Action remoteAttempt = () => policy.Validate("aetheria", remote, Now); + remoteAttempt.Should().Throw(); + } + + [Test] + public void ProviderProofRejectsCredentialFreeEchoAndNonceReplay() + { + using var odin = ECDsa.Create(ECCurve.NamedCurves.nistP256); + using var provider = ECDsa.Create(ECCurve.NamedCurves.nistP256); + var route = SignedRoute(odin, provider); + var trust = Trust(odin); + var signer = new CultMeshSessionProofSigner(route, provider); + var request = Request("nonce-a"); + var signed = Accepted(request, signer.Sign(request)); + + CultMeshAuthorityProof.VerifySessionProof(request, signed, "aetheria", route, trust, Now).Should().BeTrue(); + + var echo = Accepted(request, string.Empty); + CultMeshAuthorityProof.VerifySessionProof(request, echo, "aetheria", route, trust, Now).Should().BeFalse(); + + var replayedRequest = Request("nonce-b"); + CultMeshAuthorityProof.VerifySessionProof(replayedRequest, signed, "aetheria", route, trust, Now).Should().BeFalse(); + } + + [Test] + public async Task SessionManagerRejectsPeerThatOnlyEchoesCertifiedIdentityStrings() + { + using var odin = ECDsa.Create(ECCurve.NamedCurves.nistP256); + using var provider = ECDsa.Create(ECCurve.NamedCurves.nistP256); + var now = DateTimeOffset.UtcNow; + var route = CultMeshAuthorityProof.CreateSignedRoute( + "aetheria", "aetheria-daemon", "wss://provider.example/mesh", + new[] { CultMeshProtocols.Documents.Value }, 0, "generation-live", + CultMeshEcdsaP256PublicKey.From("provider-live", provider), "odin-live", + now.AddMinutes(-1), now.AddMinutes(5), odin); + var descriptor = new CultMeshVerseDescriptor( + "aetheria", "Aetheria", CultMeshVerseAuthorityModel.OperatorCluster, + new CultMeshVerseCompatibility("cultmesh.v0", "rules"), + authorityRoutes: new[] { route }); + using var discovery = new CultMeshDiscoveryService(new[] { new SignedRouteSource(descriptor) }); + using var manager = new CultMeshSessionManager( + discovery, + new[] { new EchoConnector() }, + new CultMeshSessionManagerOptions + { + Trust = new CultMeshAuthorityTrustPolicy( + CultMeshAuthorityTrustMode.AuthenticatedRemote, + new[] { CultMeshEcdsaP256PublicKey.From("odin-live", odin) }) + }); + + Func connect = async () => await manager.ConnectAsync( + new CultMeshSessionTarget("aetheria", "aetheria-daemon"), + CultMeshProtocols.Documents); + + (await connect.Should().ThrowAsync()) + .Which.Failure.Reason.Should().Be(CultMeshSessionFailureReason.Authority); + } + + private static CultMeshAuthorityRoute SignedRoute(ECDsa odin, ECDsa provider) => + CultMeshAuthorityProof.CreateSignedRoute( + "aetheria", + "aetheria-daemon", + "wss://provider.example/mesh", + new[] { CultMeshProtocols.Documents.Value }, + 0, + "generation-1", + CultMeshEcdsaP256PublicKey.From("provider-1", provider), + "odin-root-1", + Now.AddMinutes(-1), + Now.AddHours(1), + odin); + + private static CultMeshAuthorityTrustPolicy Trust(ECDsa odin) => new( + CultMeshAuthorityTrustMode.AuthenticatedRemote, + new[] { CultMeshEcdsaP256PublicKey.From("odin-root-1", odin) }); + + private static GameCult.Networking.CultMeshSessionOpenMessage Request(string nonceLabel) + { + using var hash = SHA256.Create(); + return new GameCult.Networking.CultMeshSessionOpenMessage + { + MessageId = "message-1", + SourceRuntimeId = "browser-1", + VerseId = "aetheria", + AuthorityRuntimeId = "aetheria-daemon", + ProtocolId = CultMeshProtocols.Documents.Value, + RouteGeneration = "generation-1", + ClientNonce = Convert.ToBase64String(hash.ComputeHash(System.Text.Encoding.UTF8.GetBytes(nonceLabel))) + }; + } + + private static GameCult.Networking.CultMeshSessionAcceptedMessage Accepted( + GameCult.Networking.CultMeshSessionOpenMessage request, + string signature) => new() + { + MessageId = request.MessageId, + Accepted = true, + VerseId = request.VerseId, + AuthorityRuntimeId = request.AuthorityRuntimeId, + ProtocolId = request.ProtocolId, + RouteGeneration = request.RouteGeneration, + ClientNonce = request.ClientNonce, + ProviderKeyId = "provider-1", + ProviderSignature = signature + }; + + private sealed class SignedRouteSource : ICultMeshLookupSource + { + private readonly CultMeshVerseDescriptor _descriptor; + public SignedRouteSource(CultMeshVerseDescriptor descriptor) => _descriptor = descriptor; + public string SourceId => "signed-odin"; + public Task> LookupAsync( + CultMeshDiscoveryQuery query, + CancellationToken cancellationToken = default) => + Task.FromResult>(new[] + { + new CultMeshDiscoveryObservation( + _descriptor, SourceId, DateTimeOffset.UtcNow, + DateTimeOffset.UtcNow.AddMinutes(1), CultMeshDiscoveryTrust.Signed) + }); + } + + private sealed class EchoConnector : ICultMeshTransportConnector + { + public string ConnectorId => "credential-free-echo"; + public int Priority => 0; + public bool CanConnect(CultMeshTransportCandidate candidate) => true; + public Task ConnectAsync( + CultMeshTransportCandidate candidate, + CultMeshProtocolId protocol, + CancellationToken cancellationToken = default) => + Task.FromResult(new EchoClient()); + } + + private sealed class EchoClient : ICultNetSchemaClient + { + private Action? _accepted; + public bool Connected => true; + public void Connect(string host, int port) { } + public void SendCultNet(T message) where T : ICultNetSchemaMessage + { + if (message is not CultMeshSessionOpenMessage request) return; + _accepted?.Invoke(new CultMeshSessionAcceptedMessage + { + MessageId = request.MessageId, + Accepted = true, + VerseId = request.VerseId, + AuthorityRuntimeId = request.AuthorityRuntimeId, + ProtocolId = request.ProtocolId, + RouteGeneration = request.RouteGeneration, + ClientNonce = request.ClientNonce, + ProviderKeyId = "provider-live", + ProviderSignature = string.Empty + }); + } + public void OnCultNet(Action callback) where T : ICultNetSchemaMessage + { + if (typeof(T) == typeof(CultMeshSessionAcceptedMessage)) + _accepted = response => callback((T)(object)response); + } + public void Dispose() { } + } +} diff --git a/tests/GameCult.Mesh.Tests/CultMeshBodySessionTests.cs b/tests/GameCult.Mesh.Tests/CultMeshBodySessionTests.cs index 81ee15cc..803a055d 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshBodySessionTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshBodySessionTests.cs @@ -26,7 +26,7 @@ public sealed class CultMeshBodySessionTests var client = new LoopbackClient(server); var connector = new LoopbackConnector(client); using var discovery = new CultMeshDiscoveryService(new[] { new RouteSource() }); - using var sessions = new CultMeshSessionManager(discovery, new[] { connector }); + using var sessions = new CultMeshSessionManager(discovery, new[] { connector }, CultMeshTestTrust.LocalSessions); var provider = new CultMeshSessionBodyProvider( "aetheria.daemon", sessions, new CultMeshSessionTarget("aetheria", "aetheria.daemon")); @@ -73,7 +73,7 @@ public sealed class CultMeshBodySessionTests }); using var discovery = new CultMeshDiscoveryService(new[] { new RouteSource(endpoint) }); using var sessions = new CultMeshSessionManager(discovery, - new ICultMeshTransportConnector[] { new CultMeshSchemaTransportConnector() }); + new ICultMeshTransportConnector[] { new CultMeshSchemaTransportConnector() }, CultMeshTestTrust.LocalSessions); var provider = new CultMeshSessionBodyProvider("aetheria.daemon", sessions, new CultMeshSessionTarget("aetheria", "aetheria.daemon"), new CultMeshSessionBodyProviderOptions { ResponseTimeout = TimeSpan.FromSeconds(10) }); @@ -142,7 +142,7 @@ public sealed class CultMeshBodySessionTests private sealed class RouteSource : ICultMeshLookupSource { private readonly string _endpoint; - public RouteSource(string endpoint = "rudp://body.test:3076") => _endpoint = endpoint; + public RouteSource(string endpoint = "rudp://127.0.0.13:3076") => _endpoint = endpoint; public string SourceId => "test"; public Task> LookupAsync(CultMeshDiscoveryQuery query, CancellationToken cancellationToken = default) diff --git a/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs b/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs index e603415e..dcabf6e6 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshClientTests.cs @@ -40,6 +40,7 @@ public sealed class CultMeshClientTests return new RendezvousClient(); } }, + Sessions = CultMeshTestTrust.LocalSessions, Connectors = new[] { connector } }); @@ -48,7 +49,7 @@ public sealed class CultMeshClientTests first.Should().BeSameAs(second); first.Target.Should().Be(Target); - first.State.Path!.Endpoint.Should().Be("rudp://aetheria:3081"); + first.State.Path!.Endpoint.Should().Be("rudp://127.0.0.1:3081"); discoveryClients.Should().Be(1); connector.ConnectCount.Should().Be(1); } @@ -61,6 +62,7 @@ public sealed class CultMeshClientTests { RendezvousEndpoints = new[] { "rudp://odin:3076" }, Discovery = new CultMeshVerseDiscoveryClientOptions { CreateClient = () => new RendezvousClient() }, + Sessions = CultMeshTestTrust.LocalSessions, Connectors = new[] { connector } }); @@ -82,6 +84,7 @@ public sealed class CultMeshClientTests { RendezvousEndpoints = new[] { "rudp://odin:3076" }, Discovery = new CultMeshVerseDiscoveryClientOptions { CreateClient = () => new RendezvousClient() }, + Sessions = CultMeshTestTrust.LocalSessions, Connectors = new[] { connector } }); @@ -103,6 +106,7 @@ public sealed class CultMeshClientTests { RendezvousEndpoints = new[] { "rudp://odin:3076" }, Discovery = new CultMeshVerseDiscoveryClientOptions { CreateClient = () => new RendezvousClient() }, + Sessions = CultMeshTestTrust.LocalSessions, Connectors = new[] { connector } }); using var lease = await mesh.LeaseDocumentAsync(Target, "surface:pilot"); @@ -125,6 +129,7 @@ public sealed class CultMeshClientTests { RendezvousEndpoints = new[] { "rudp://odin:3076" }, Discovery = new CultMeshVerseDiscoveryClientOptions { CreateClient = () => new RendezvousClient() }, + Sessions = CultMeshTestTrust.LocalSessions, Connectors = new[] { connector } }); @@ -148,6 +153,7 @@ public sealed class CultMeshClientTests { RendezvousEndpoints = new[] { "rudp://odin:3076" }, Discovery = new CultMeshVerseDiscoveryClientOptions { CreateClient = () => new RendezvousClient() }, + Sessions = CultMeshTestTrust.LocalSessions, Connectors = new[] { connector }, SubscriptionResponseTimeout = TimeSpan.FromMilliseconds(20) }); @@ -168,6 +174,7 @@ public sealed class CultMeshClientTests { RendezvousEndpoints = new[] { "rudp://odin:3076" }, Discovery = new CultMeshVerseDiscoveryClientOptions { CreateClient = () => new RendezvousClient() }, + Sessions = CultMeshTestTrust.LocalSessions, Connectors = new[] { connector } }); @@ -187,6 +194,7 @@ public sealed class CultMeshClientTests { RendezvousEndpoints = new[] { "rudp://odin:3076" }, Discovery = new CultMeshVerseDiscoveryClientOptions { CreateClient = () => new RendezvousClient() }, + Sessions = CultMeshTestTrust.LocalSessions, Connectors = new[] { connector } }); @@ -211,6 +219,7 @@ public sealed class CultMeshClientTests { RendezvousEndpoints = new[] { "rudp://odin:3076" }, Discovery = new CultMeshVerseDiscoveryClientOptions { CreateClient = () => new RendezvousClient() }, + Sessions = CultMeshTestTrust.LocalSessions, Connectors = new[] { connector } }); @@ -237,6 +246,7 @@ public sealed class CultMeshClientTests { RendezvousEndpoints = new[] { "rudp://odin:3076" }, Discovery = new CultMeshVerseDiscoveryClientOptions { CreateClient = () => new RendezvousClient() }, + Sessions = CultMeshTestTrust.LocalSessions, Connectors = new[] { connector } }); @@ -262,6 +272,7 @@ public sealed class CultMeshClientTests { RendezvousEndpoints = new[] { "rudp://odin:3076" }, Discovery = new CultMeshVerseDiscoveryClientOptions { CreateClient = () => new RendezvousClient() }, + Sessions = CultMeshTestTrust.LocalSessions, Connectors = new[] { connector } }); var request = new ClientTestDocument { Id = "command:1", Text = "move" }; @@ -288,6 +299,7 @@ public sealed class CultMeshClientTests { RendezvousEndpoints = new[] { "rudp://odin:3076" }, Discovery = new CultMeshVerseDiscoveryClientOptions { CreateClient = () => new RendezvousClient() }, + Sessions = CultMeshTestTrust.LocalSessions, Connectors = new[] { connector } }); @@ -319,6 +331,7 @@ public sealed class CultMeshClientTests { RendezvousEndpoints = new[] { "rudp://odin:3076" }, Discovery = new CultMeshVerseDiscoveryClientOptions { CreateClient = () => new RendezvousClient() }, + Sessions = CultMeshTestTrust.LocalSessions, Connectors = new[] { connector }, OperationResponseTimeout = TimeSpan.FromSeconds(2) }); @@ -348,6 +361,7 @@ public sealed class CultMeshClientTests { RendezvousEndpoints = new[] { "rudp://odin:3076" }, Discovery = new CultMeshVerseDiscoveryClientOptions { CreateClient = () => new RendezvousClient() }, + Sessions = CultMeshTestTrust.LocalSessions, Connectors = new[] { connector }, OperationResponseTimeout = TimeSpan.FromSeconds(5) }); @@ -378,6 +392,7 @@ public sealed class CultMeshClientTests { RendezvousEndpoints = new[] { "rudp://odin:3076" }, Discovery = new CultMeshVerseDiscoveryClientOptions { CreateClient = () => new RendezvousClient() }, + Sessions = CultMeshTestTrust.LocalSessions, Connectors = new[] { connector } }); @@ -403,6 +418,7 @@ public sealed class CultMeshClientTests { RendezvousEndpoints = new[] { "rudp://odin:3076" }, Discovery = new CultMeshVerseDiscoveryClientOptions { CreateClient = () => new RendezvousClient() }, + Sessions = CultMeshTestTrust.LocalSessions, Connectors = new[] { connector } }); var opening = mesh.LeaseDocumentAsync(Target, "surface:pilot"); @@ -432,7 +448,7 @@ public sealed class CultMeshClientTests "Aetheria", CultMeshVerseAuthorityModel.OperatorCluster, new CultMeshVerseCompatibility("cultmesh.v0", "rules"), - new[] { "rudp://aetheria:3081" }, + new[] { "rudp://127.0.0.1:3081" }, new[] { "aetheria-daemon" }).ToMessage() } }; diff --git a/tests/GameCult.Mesh.Tests/CultMeshContentSessionTests.cs b/tests/GameCult.Mesh.Tests/CultMeshContentSessionTests.cs index fa11072c..6ec0548f 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshContentSessionTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshContentSessionTests.cs @@ -55,7 +55,7 @@ public sealed class CultMeshContentSessionTests using var sessions = new CultMeshSessionManager( discovery, Array.Empty(), - new ICultMeshContentTransportConnector[] { connector }); + new ICultMeshContentTransportConnector[] { connector }, CultMeshTestTrust.LocalSessions); var provider = new CultMeshSessionContentProvider( "aetheria.daemon", sessions, @@ -99,7 +99,7 @@ public sealed class CultMeshContentSessionTests using var sessions = new CultMeshSessionManager( discovery, Array.Empty(), - new ICultMeshContentTransportConnector[] { new CultMeshTcpContentTransportConnector() }); + new ICultMeshContentTransportConnector[] { new CultMeshTcpContentTransportConnector() }, CultMeshTestTrust.LocalSessions); Func connect = async () => await sessions.ConnectContentAsync( new CultMeshSessionTarget("aetheria", "aetheria.daemon")); @@ -151,7 +151,7 @@ public sealed class CultMeshContentSessionTests using var sessions = new CultMeshSessionManager( discovery, Array.Empty(), - new ICultMeshContentTransportConnector[] { connector }); + new ICultMeshContentTransportConnector[] { connector }, CultMeshTestTrust.LocalSessions); var provider = new CultMeshSessionContentProvider( "aetheria.daemon", sessions, @@ -220,7 +220,7 @@ public sealed class CultMeshContentSessionTests { private readonly string _endpoint; - public RouteSource(string endpoint = "rudp://content.test:3076") => _endpoint = endpoint; + public RouteSource(string endpoint = "rudp://127.0.0.14:3076") => _endpoint = endpoint; public string SourceId => "test-rendezvous"; diff --git a/tests/GameCult.Mesh.Tests/CultMeshSessionManagerTests.cs b/tests/GameCult.Mesh.Tests/CultMeshSessionManagerTests.cs index 46e0672f..40fdfe15 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshSessionManagerTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshSessionManagerTests.cs @@ -28,22 +28,22 @@ public sealed class CultMeshSessionManagerTests connected = candidate; return Task.FromResult(new FakeSchemaClient()); }); - using var manager = new CultMeshSessionManager(discovery, new[] { connector }, new CultMeshSessionManagerOptions { Clock = clock }); + using var manager = new CultMeshSessionManager(discovery, new[] { connector }, CultMeshTestTrust.LocalSessionsWithClock(clock)); await manager.ConnectAsync(Target, CultMeshProtocols.Documents); connected.Should().NotBeNull(); - connected!.Endpoint.Should().Be("rudp://aetheria:3076"); + connected!.Endpoint.Should().Be("rudp://127.0.0.1:3076"); } [Test] public async Task Connect_ReusesInflightAndEstablishedSession() { var clock = new ManualSessionClock(); - using var discovery = Discovery(clock, () => new[] { "rudp://direct:3076" }); + using var discovery = Discovery(clock, () => new[] { "rudp://127.0.0.2:3076" }); var release = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var connector = new FakeConnector(async (_, _) => { await release.Task; return new FakeSchemaClient(); }); - using var manager = new CultMeshSessionManager(discovery, new[] { connector }, new CultMeshSessionManagerOptions { Clock = clock }); + using var manager = new CultMeshSessionManager(discovery, new[] { connector }, CultMeshTestTrust.LocalSessionsWithClock(clock)); var target = Target; var first = manager.ConnectAsync(target, CultMeshProtocols.Documents); @@ -61,19 +61,19 @@ public sealed class CultMeshSessionManagerTests public async Task Connect_RacesPathsAndDisposesSuccessfulLoser() { var clock = new ManualSessionClock(); - using var discovery = Discovery(clock, () => new[] { "rudp://slow:3076", "rudp://fast:3076" }); + using var discovery = Discovery(clock, () => new[] { "rudp://127.0.0.3:3076", "rudp://127.0.0.4:3076" }); var slowRelease = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var slowClient = new FakeSchemaClient(); var fastClient = new FakeSchemaClient(); var connector = new FakeConnector(async (candidate, _) => { - if (candidate.Endpoint.Contains("slow")) { await slowRelease.Task; return slowClient; } + if (candidate.Endpoint.Contains("127.0.0.3")) { await slowRelease.Task; return slowClient; } return fastClient; }); - using var manager = new CultMeshSessionManager(discovery, new[] { connector }, new CultMeshSessionManagerOptions { Clock = clock }); + using var manager = new CultMeshSessionManager(discovery, new[] { connector }, CultMeshTestTrust.LocalSessionsWithClock(clock)); var session = await manager.ConnectAsync(Target, CultMeshProtocols.Documents); - session.State.Path!.Endpoint.Should().Be("rudp://fast:3076"); + session.State.Path!.Endpoint.Should().Be("rudp://127.0.0.4:3076"); slowRelease.TrySetResult(); await WaitUntilAsync(() => slowClient.DisposeCount == 1); fastClient.DisposeCount.Should().Be(0); @@ -90,8 +90,8 @@ public sealed class CultMeshSessionManagerTests new CultMeshVerseCompatibility("cultmesh.v0", "rules"), authorityRoutes: new[] { - new CultMeshAuthorityRoute("decoy-daemon", "rudp://decoy:3076"), - new CultMeshAuthorityRoute("aetheria-daemon", "rudp://authority:3076") + new CultMeshAuthorityRoute("decoy-daemon", "rudp://127.0.0.5:3076"), + new CultMeshAuthorityRoute("aetheria-daemon", "rudp://127.0.0.6:3076") }); using var discovery = new CultMeshDiscoveryService( new[] { new StaticRouteSource(clock, descriptor) }, @@ -102,22 +102,22 @@ public sealed class CultMeshSessionManagerTests attempts.Add(candidate.Endpoint); return Task.FromResult(new FakeSchemaClient()); }); - using var manager = new CultMeshSessionManager(discovery, new[] { connector }); + using var manager = new CultMeshSessionManager(discovery, new[] { connector }, CultMeshTestTrust.LocalSessions); var session = await manager.ConnectAsync(Target, CultMeshProtocols.Documents); - session.State.Path!.Endpoint.Should().Be("rudp://authority:3076"); - attempts.Should().Equal("rudp://authority:3076"); + session.State.Path!.Endpoint.Should().Be("rudp://127.0.0.6:3076"); + attempts.Should().Equal("rudp://127.0.0.6:3076"); } [Test] public void Connect_RejectsRouteWhoseNativeIdentityDoesNotMatchTarget() { var clock = new ManualSessionClock(); - using var discovery = Discovery(clock, () => new[] { "rudp://decoy:3076" }); + using var discovery = Discovery(clock, () => new[] { "rudp://127.0.0.5:3076" }); var connector = new FakeConnector((_, _) => Task.FromResult(new NativeMismatchClient())); - using var manager = new CultMeshSessionManager(discovery, new[] { connector }); + using var manager = new CultMeshSessionManager(discovery, new[] { connector }, CultMeshTestTrust.LocalSessions); var error = Assert.ThrowsAsync(() => manager.ConnectAsync(Target, CultMeshProtocols.Documents)); @@ -129,10 +129,10 @@ public sealed class CultMeshSessionManagerTests public void Connect_RejectsPortableHandshakeFromWrongRuntime() { var clock = new ManualSessionClock(); - using var discovery = Discovery(clock, () => new[] { "rudp://decoy:3076" }); + using var discovery = Discovery(clock, () => new[] { "rudp://127.0.0.5:3076" }); var connector = new FakeConnector((_, _) => Task.FromResult(new HandshakeSchemaClient("decoy-daemon"))); - using var manager = new CultMeshSessionManager(discovery, new[] { connector }); + using var manager = new CultMeshSessionManager(discovery, new[] { connector }, CultMeshTestTrust.LocalSessions); var error = Assert.ThrowsAsync(() => manager.ConnectAsync(Target, CultMeshProtocols.Documents)); @@ -148,7 +148,7 @@ public sealed class CultMeshSessionManagerTests "Aetheria", CultMeshVerseAuthorityModel.OperatorCluster, new CultMeshVerseCompatibility("cultmesh.v0", "rules"), - discoveryEndpoints: new[] { "rudp://shared:3076" }, + discoveryEndpoints: new[] { "rudp://127.0.0.7:3076" }, authorityRuntimeIds: new[] { "authority-a", "authority-b" }); action.Should().Throw().WithMessage("*ambiguous*"); @@ -158,7 +158,7 @@ public sealed class CultMeshSessionManagerTests public async Task Connect_CallerCancellationDoesNotCancelSharedAttempt() { var clock = new ManualSessionClock(); - using var discovery = Discovery(clock, () => new[] { "rudp://direct:3076" }); + using var discovery = Discovery(clock, () => new[] { "rudp://127.0.0.2:3076" }); var release = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var connector = new FakeConnector(async (_, token) => { @@ -166,7 +166,7 @@ public sealed class CultMeshSessionManagerTests await release.Task; return new FakeSchemaClient(); }); - using var manager = new CultMeshSessionManager(discovery, new[] { connector }, new CultMeshSessionManagerOptions { Clock = clock }); + using var manager = new CultMeshSessionManager(discovery, new[] { connector }, CultMeshTestTrust.LocalSessionsWithClock(clock)); using var cancellation = new CancellationTokenSource(); var target = Target; @@ -185,7 +185,7 @@ public sealed class CultMeshSessionManagerTests public async Task BackgroundFailureMigratesSameSessionAcrossEndpointRotation() { var clock = new ManualSessionClock(); - var route = "rudp://first:3076"; + var route = "rudp://127.0.0.8:3076"; using var discovery = Discovery(clock, () => new[] { route }, TimeSpan.FromSeconds(5)); var clients = new List(); var connector = new FakeConnector((_, _) => @@ -194,7 +194,7 @@ public sealed class CultMeshSessionManagerTests clients.Add(client); return Task.FromResult(client); }); - using var manager = new CultMeshSessionManager(discovery, new[] { connector }, new CultMeshSessionManagerOptions { Clock = clock }); + using var manager = new CultMeshSessionManager(discovery, new[] { connector }, CultMeshTestTrust.LocalSessionsWithClock(clock)); var target = Target; var first = await manager.ConnectAsync(target, CultMeshProtocols.Documents); var states = new List(); @@ -204,14 +204,14 @@ public sealed class CultMeshSessionManagerTests schemaLease.OnCultNet(_ => deliveries++); clients[0].Emit(new CultNetErrorMessage { Error = "before rotation" }); - route = "rudp://second:3076"; + route = "rudp://127.0.0.9:3076"; clients[0].Fail(new IOException("partition")); await WaitUntilAsync(() => first.State.Status == CultMeshSessionStatus.Online && connector.ConnectCount == 2); var second = await manager.ConnectAsync(target, CultMeshProtocols.Documents); clients[1].Emit(new CultNetErrorMessage { Error = "after rotation" }); second.Should().BeSameAs(first); - second.State.Path!.Endpoint.Should().Be("rudp://second:3076"); + second.State.Path!.Endpoint.Should().Be("rudp://127.0.0.9:3076"); states.Should().ContainInOrder(CultMeshSessionStatus.Reconnecting, CultMeshSessionStatus.Online); connector.ConnectCount.Should().Be(2); clients[0].DisposeCount.Should().Be(1); @@ -238,8 +238,8 @@ public sealed class CultMeshSessionManagerTests public void Connect_ReportsUnsupportedPathPrecisely() { var clock = new ManualSessionClock(); - using var discovery = Discovery(clock, () => new[] { "quic://unimplemented:443" }); - using var manager = new CultMeshSessionManager(discovery, Array.Empty(), new CultMeshSessionManagerOptions { Clock = clock }); + using var discovery = Discovery(clock, () => new[] { "quic://127.0.0.10:443" }); + using var manager = new CultMeshSessionManager(discovery, Array.Empty(), CultMeshTestTrust.LocalSessionsWithClock(clock)); var error = Assert.ThrowsAsync(() => manager.ConnectAsync(Target, CultMeshProtocols.Documents)); @@ -253,10 +253,10 @@ public sealed class CultMeshSessionManagerTests public async Task SnapshotSessionsBorrowOneManagedChannelAndDisposeRegistrationsIndependently() { var clock = new ManualSessionClock(); - using var discovery = Discovery(clock, () => new[] { "rudp://direct:3076" }); + using var discovery = Discovery(clock, () => new[] { "rudp://127.0.0.2:3076" }); var client = new RespondingSchemaClient(); var connector = new FakeConnector((_, _) => Task.FromResult(client)); - using var manager = new CultMeshSessionManager(discovery, new[] { connector }, new CultMeshSessionManagerOptions { Clock = clock }); + using var manager = new CultMeshSessionManager(discovery, new[] { connector }, CultMeshTestTrust.LocalSessionsWithClock(clock)); var target = Target; using var first = await CultMeshSnapshotSession.ConnectAsync(manager, target, new CultMeshSnapshotRequestOptions()); using var second = await CultMeshSnapshotSession.ConnectAsync(manager, target, new CultMeshSnapshotRequestOptions()); @@ -274,10 +274,10 @@ public sealed class CultMeshSessionManagerTests public async Task PeerExchangeBorrowsManagedProtocolSessionAcrossRequests() { var clock = new ManualSessionClock(); - using var discovery = Discovery(clock, () => new[] { "rudp://direct:3076" }); + using var discovery = Discovery(clock, () => new[] { "rudp://127.0.0.2:3076" }); var client = new PeerExchangeSchemaClient(); var connector = new FakeConnector((_, _) => Task.FromResult(client)); - using var manager = new CultMeshSessionManager(discovery, new[] { connector }, new CultMeshSessionManagerOptions { Clock = clock }); + using var manager = new CultMeshSessionManager(discovery, new[] { connector }, CultMeshTestTrust.LocalSessionsWithClock(clock)); var exchange = new CultMeshPeerExchangeClient(new CultMeshPeerExchangeClientOptions { Sessions = manager, Clock = clock }); var target = Target; @@ -294,10 +294,10 @@ public sealed class CultMeshSessionManagerTests public async Task SchemaClientLeasesDisposeHandlersWithoutClosingSession() { var clock = new ManualSessionClock(); - using var discovery = Discovery(clock, () => new[] { "rudp://direct:3076" }); + using var discovery = Discovery(clock, () => new[] { "rudp://127.0.0.2:3076" }); var client = new LeaseSchemaClient(); var connector = new FakeConnector((_, _) => Task.FromResult(client)); - using var manager = new CultMeshSessionManager(discovery, new[] { connector }, new CultMeshSessionManagerOptions { Clock = clock }); + using var manager = new CultMeshSessionManager(discovery, new[] { connector }, CultMeshTestTrust.LocalSessionsWithClock(clock)); var session = await manager.ConnectAsync(Target, CultMeshProtocols.Subscriptions); using var first = session.OpenSchemaClient(); using var second = session.OpenSchemaClient(); @@ -363,8 +363,8 @@ public sealed class CultMeshSessionManagerTests var expires = _clock.UtcNow.AddMinutes(1); return Task.FromResult>(new[] { - Observation("norn", "rudp://norn:3076", expires), - Observation("aetheria", "rudp://aetheria:3076", expires) + Observation("norn", "rudp://127.0.0.11:3076", expires), + Observation("aetheria", "rudp://127.0.0.1:3076", expires) }); } @@ -544,7 +544,7 @@ public sealed class CultMeshSessionManagerTests MessageId = request.MessageId, Peers = new[] { - new CultMeshPeerCard("peer-a", request.VerseId, new[] { "rudp://peer-a:3076" }).ToMessage() + new CultMeshPeerCard("peer-a", request.VerseId, new[] { "rudp://127.0.0.12:3076" }).ToMessage() } }; foreach (var handler in _handlers.ToArray()) handler(response); diff --git a/tests/GameCult.Mesh.Tests/CultMeshTestTrust.cs b/tests/GameCult.Mesh.Tests/CultMeshTestTrust.cs new file mode 100644 index 00000000..2356462d --- /dev/null +++ b/tests/GameCult.Mesh.Tests/CultMeshTestTrust.cs @@ -0,0 +1,18 @@ +namespace GameCult.Mesh.Tests; + +internal static class CultMeshTestTrust +{ + internal static CultMeshAuthorityTrustPolicy LocalPolicy { get; } = + new(CultMeshAuthorityTrustMode.LocalDevelopment); + + internal static CultMeshSessionManagerOptions LocalSessions => new() + { + Trust = LocalPolicy + }; + + internal static CultMeshSessionManagerOptions LocalSessionsWithClock(ICultMeshClock clock) => new() + { + Clock = clock, + Trust = LocalPolicy + }; +} diff --git a/tests/GameCult.Mesh.Tests/CultMeshTransportModularityTests.cs b/tests/GameCult.Mesh.Tests/CultMeshTransportModularityTests.cs index 35b4a71c..979c7230 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshTransportModularityTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshTransportModularityTests.cs @@ -44,7 +44,7 @@ public sealed class CultMeshTransportModularityTests { legacy, new CultMeshTcpSchemaTransportConnector() - }); + }, CultMeshTestTrust.LocalSessions); var session = await sessions.ConnectAsync( new CultMeshSessionTarget("aetheria", "aetheria.daemon"), @@ -91,7 +91,7 @@ public sealed class CultMeshTransportModularityTests { legacy, new CultMeshTcpContentTransportConnector() - }); + }, CultMeshTestTrust.LocalSessions); var session = await sessions.ConnectContentAsync(new CultMeshSessionTarget("aetheria", "aetheria.daemon")); using var destination = new MemoryStream(); @@ -111,7 +111,7 @@ public sealed class CultMeshTransportModularityTests }); using var sessions = new CultMeshSessionManager( discovery, - Array.Empty()); + Array.Empty(), CultMeshTestTrust.LocalSessions); Func connect = async () => await sessions.ConnectContentAsync( new CultMeshSessionTarget("aetheria", "aetheria.daemon")); @@ -132,7 +132,7 @@ public sealed class CultMeshTransportModularityTests discovery, Array.Empty(), Array.Empty(), - new ICultMeshRealtimeTransportConnector[] { connector }); + new ICultMeshRealtimeTransportConnector[] { connector }, CultMeshTestTrust.LocalSessions); var session = await sessions.ConnectRealtimeAsync( new CultMeshSessionTarget("aetheria", "aetheria.daemon")); var sent = new CultMeshRealtimeFrame @@ -163,7 +163,7 @@ public sealed class CultMeshTransportModularityTests }); using var sessions = new CultMeshSessionManager( discovery, - Array.Empty()); + Array.Empty(), CultMeshTestTrust.LocalSessions); Func connect = async () => await sessions.ConnectRealtimeAsync( new CultMeshSessionTarget("aetheria", "aetheria.daemon")); @@ -183,7 +183,7 @@ public sealed class CultMeshTransportModularityTests discovery, Array.Empty(), Array.Empty(), - new ICultMeshRealtimeTransportConnector[] { new UnverifiedRealtimeConnector() }); + new ICultMeshRealtimeTransportConnector[] { new UnverifiedRealtimeConnector() }, CultMeshTestTrust.LocalSessions); Func connect = async () => await sessions.ConnectRealtimeAsync( new CultMeshSessionTarget("aetheria", "aetheria.daemon")); diff --git a/tools/GameCult.TransportParity/Program.cs b/tools/GameCult.TransportParity/Program.cs index 31c93e1e..04c71dfe 100644 --- a/tools/GameCult.TransportParity/Program.cs +++ b/tools/GameCult.TransportParity/Program.cs @@ -201,7 +201,8 @@ static async Task MeasureCultMeshQuicStateAsync(int payloadBytes, i [new CultMeshQuicRealtimeTransportConnector(new CultMeshQuicRealtimeConnectorOptions { ValidateProviderCertificate = (_, _, _, _) => true - })]); + })], + LocalDevelopmentSessions()); var session = await sessions.ConnectRealtimeAsync( new CultMeshSessionTarget("parity", "service:parity.provider")); var deadline = DateTime.UtcNow.AddSeconds(5); @@ -363,7 +364,8 @@ static async Task MeasureCultMeshRudpAsync(byte[] payload) discovery, Array.Empty(), [new CultMeshLegacyRudpContentTransportConnector( - new CultMeshLegacyRudpContentTransportOptions { ResponseTimeout = TimeSpan.FromMinutes(2) })]); + new CultMeshLegacyRudpContentTransportOptions { ResponseTimeout = TimeSpan.FromMinutes(2) })], + LocalDevelopmentSessions()); var provider = new CultMeshSessionContentProvider( "parity.provider", sessions, new CultMeshSessionTarget("parity", "service:parity.provider")); var directory = Path.Combine(Path.GetTempPath(), "cultmesh-transport-parity", Guid.NewGuid().ToString("N")); @@ -411,7 +413,8 @@ static async Task MeasureCultMeshTcpAsync(byte[] payload) using var sessions = new CultMeshSessionManager( discovery, Array.Empty(), - [new CultMeshTcpContentTransportConnector()]); + [new CultMeshTcpContentTransportConnector()], + LocalDevelopmentSessions()); var provider = new CultMeshSessionContentProvider( "parity.provider", sessions, new CultMeshSessionTarget("parity", "service:parity.provider")); var directory = Path.Combine(Path.GetTempPath(), "cultmesh-transport-parity", Guid.NewGuid().ToString("N")); @@ -456,6 +459,11 @@ static X509Certificate2 CreateCertificate() static string TempPath(string plane) => Path.Combine(Path.GetTempPath(), $"cultmesh-parity-{plane}-{Guid.NewGuid():N}.body"); +static CultMeshSessionManagerOptions LocalDevelopmentSessions() => new() +{ + Trust = new CultMeshAuthorityTrustPolicy(CultMeshAuthorityTrustMode.LocalDevelopment) +}; + static Socket BindUdpSocket() { var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); From c194bd4cc845459908afb4896b4191df5e1c9a94 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 19:41:03 +0200 Subject: [PATCH 097/283] Harden CultMesh route fallback and secure onboarding --- Directory.Build.props | 2 +- packages/cultmesh-browser/src/index.ts | 86 +++++++++----- .../test/cultmesh-browser.test.ts | 111 ++++++++++++++++-- .../EveBrowserNetworkSample.csproj | 4 +- scripts/pack-nuget.ps1 | 3 + scripts/verify-eve-getting-started.ps1 | 4 +- src/GameCult.Mesh/CultMeshSessions.cs | 31 ++++- src/GameCult.Mesh/CultMeshVerseDiscovery.cs | 9 +- .../getting-started/02-connect-by-identity.md | 36 ++++++ .../CultMeshAuthorityProofTests.cs | 88 ++++++++++++++ unity/org.gamecult.cultlib/package.json | 2 +- 11 files changed, 329 insertions(+), 47 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 434617ff..595da325 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -14,7 +14,7 @@ MIT © Meta Vens and contributors true - 1.0.33 + 1.0.34 $(CultLibPackageVersion) diff --git a/packages/cultmesh-browser/src/index.ts b/packages/cultmesh-browser/src/index.ts index a0596ae2..4dddfa7d 100644 --- a/packages/cultmesh-browser/src/index.ts +++ b/packages/cultmesh-browser/src/index.ts @@ -53,7 +53,10 @@ export interface CultMeshBrowserAuthorityTrustPolicy { } export interface CultMeshBrowserRendezvous { - resolve(identity: CultMeshBrowserIdentity): Promise; + resolve( + identity: CultMeshBrowserIdentity, + trust?: CultMeshBrowserAuthorityTrustPolicy, + ): Promise; } export interface CultMeshBrowserOdinRendezvousOptions { @@ -101,13 +104,16 @@ export class CultMeshBrowserOdinRendezvous implements CultMeshBrowserRendezvous if (this.#options.maxFrameBytes <= 0) throw new Error("Odin rendezvous maxFrameBytes must be positive."); } - async resolve(identity: CultMeshBrowserIdentity): Promise { + async resolve( + identity: CultMeshBrowserIdentity, + trust: CultMeshBrowserAuthorityTrustPolicy = { mode: "authenticated-remote", odinRoots: [] }, + ): Promise { requireText(identity.verseId, "verseId"); requireText(identity.authorityRuntimeId, "authorityRuntimeId"); const failures: Error[] = []; for (const endpoint of this.#options.endpoints) { try { - return await this.resolveFrom(endpoint, identity); + return await this.resolveFrom(endpoint, identity, trust); } catch (error) { failures.push(error instanceof Error ? error : new Error(String(error))); } @@ -118,7 +124,11 @@ export class CultMeshBrowserOdinRendezvous implements CultMeshBrowserRendezvous ); } - private resolveFrom(endpoint: string, identity: CultMeshBrowserIdentity): Promise { + private resolveFrom( + endpoint: string, + identity: CultMeshBrowserIdentity, + trust: CultMeshBrowserAuthorityTrustPolicy, + ): Promise { const socket = this.#options.socketFactory(endpoint); socket.binaryType = "arraybuffer"; const messageId = this.#options.createId(); @@ -169,7 +179,9 @@ export class CultMeshBrowserOdinRendezvous implements CultMeshBrowserRendezvous return; } if (message.schemaVersion !== "cultmesh.verse_catalog_response.v0" || message.messageId !== messageId) return; - finish(undefined, selectOdinRoute(message, identity)); + void selectOdinRoute(message, identity, trust) + .then(route => finish(undefined, route)) + .catch(error => finish(error instanceof Error ? error : new Error(String(error)))); }).catch(error => finish(error instanceof Error ? error : new Error(String(error)))); }; socket.onerror = () => finish(new Error(`Odin WebSocket could not open '${endpoint}'.`)); @@ -501,6 +513,11 @@ export class CultMeshBrowserClient implements AsyncDisposable { private connectSocket(): Promise { this.throwIfDisposed(); + if (this.#state === "connected" && this.#socket?.readyState === 1) return Promise.resolve(); + if (this.#reconnectTimer) { + clearTimeout(this.#reconnectTimer); + this.#reconnectTimer = undefined; + } if (this.#connectPromise) return this.#connectPromise; const generation = ++this.#socketGeneration; this.setState(this.#socket ? "reconnecting" : "connecting"); @@ -511,7 +528,7 @@ export class CultMeshBrowserClient implements AsyncDisposable { } private async openSocket(generation: number): Promise { - const route = await this.#options.rendezvous.resolve(this.identity); + const route = await this.#options.rendezvous.resolve(this.identity, this.#options.trust); if (route.verseId !== this.identity.verseId || route.authorityRuntimeId !== this.identity.authorityRuntimeId) { throw new Error("CultMesh rendezvous returned a route for the wrong stable identity."); @@ -828,10 +845,11 @@ async function decodeSocketMessage(event: MessageEvent, maxFrameBytes: number): return parseCultNetMessage(decode(payload)); } -function selectOdinRoute( +async function selectOdinRoute( response: CultMeshVerseCatalogResponseMessage, identity: CultMeshBrowserIdentity, -): CultMeshBrowserRoute { + trust: CultMeshBrowserAuthorityTrustPolicy, +): Promise { const matchingVerses = response.verses.filter(verse => verse.verseId === identity.verseId); if (matchingVerses.length !== 1) { throw new Error( @@ -871,26 +889,38 @@ function selectOdinRoute( if (routes.length === 0) { throw new Error(`Odin advertised no browser-compatible route for authority runtime '${identity.authorityRuntimeId}'.`); } - const route = routes[0]; - return { - ...identity, - endpoint: route.endpoint, - protocolId: "cultmesh.documents.v1", - protocolIds: route.protocolIds, - priority: route.priority, - generation: route.generation, - ...(route.certificate ? { certificate: { - providerKey: { - keyId: route.certificate.providerKeyId, - x: route.certificate.providerPublicKeyX, - y: route.certificate.providerPublicKeyY, - }, - odinKeyId: route.certificate.odinKeyId, - issuedAtUnixMilliseconds: route.certificate.issuedAtUnixMilliseconds, - expiresAtUnixMilliseconds: route.certificate.expiresAtUnixMilliseconds, - signature: route.certificate.signature, - } } : {}), - }; + const failures: Error[] = []; + for (const route of routes) { + const candidate: CultMeshBrowserRoute = { + ...identity, + endpoint: route.endpoint, + protocolId: "cultmesh.documents.v1", + protocolIds: route.protocolIds, + priority: route.priority, + generation: route.generation, + ...(route.certificate ? { certificate: { + providerKey: { + keyId: route.certificate.providerKeyId, + x: route.certificate.providerPublicKeyX, + y: route.certificate.providerPublicKeyY, + }, + odinKeyId: route.certificate.odinKeyId, + issuedAtUnixMilliseconds: route.certificate.issuedAtUnixMilliseconds, + expiresAtUnixMilliseconds: route.certificate.expiresAtUnixMilliseconds, + signature: route.certificate.signature, + } } : {}), + }; + try { + await verifyAuthorityRoute(candidate, trust); + return candidate; + } catch (error) { + failures.push(error instanceof Error ? error : new Error(String(error))); + } + } + throw new AggregateError( + failures, + `Odin advertised no trusted browser route for authority runtime '${identity.authorityRuntimeId}'.`, + ); } async function validateSessionAcceptance( diff --git a/packages/cultmesh-browser/test/cultmesh-browser.test.ts b/packages/cultmesh-browser/test/cultmesh-browser.test.ts index 4f90acf1..6c169d93 100644 --- a/packages/cultmesh-browser/test/cultmesh-browser.test.ts +++ b/packages/cultmesh-browser/test/cultmesh-browser.test.ts @@ -9,6 +9,7 @@ import { type CultNetMessage, type CultNetOperationRequestMessage, type CultNetRawDocumentRecord, + type CultMeshVerseCatalogResponseMessage, type CultMeshSessionOpenMessage, } from "cultnet-ts/contracts"; @@ -38,16 +39,16 @@ test("Odin rendezvous resolves stable authority-runtime identity and observes ro assert.equal((await rendezvous.resolve({ verseId: "sample.counter", authorityRuntimeId: "sample.counter-daemon", - })).endpoint, "ws://127.0.0.1:4050/mesh"); + }, localTrust)).endpoint, "ws://127.0.0.1:4050/mesh"); odin.providerEndpoint = "ws://127.0.0.1:4060/mesh"; assert.equal((await rendezvous.resolve({ verseId: "sample.counter", authorityRuntimeId: "sample.counter-daemon", - })).endpoint, "ws://127.0.0.1:4060/mesh"); + }, localTrust)).endpoint, "ws://127.0.0.1:4060/mesh"); await assert.rejects( - rendezvous.resolve({ verseId: "sample.counter", authorityRuntimeId: "other-runtime" }), + rendezvous.resolve({ verseId: "sample.counter", authorityRuntimeId: "other-runtime" }, localTrust), /could not resolve/, ); }); @@ -64,7 +65,7 @@ test("Odin rendezvous never selects another authority's faster endpoint", async const route = await rendezvous.resolve({ verseId: "sample.counter", authorityRuntimeId: "sample.counter-daemon", - }); + }, localTrust); assert.equal(route.endpoint, "ws://127.0.0.1:4050/mesh"); }); @@ -80,18 +81,45 @@ test("Odin rendezvous accepts one-authority legacy routes and rejects ambiguous const route = await rendezvous.resolve({ verseId: "sample.counter", authorityRuntimeId: "sample.counter-daemon", - }); + }, localTrust); assert.equal(route.endpoint, "ws://127.0.0.1:4070/mesh"); odin.decoyEndpoint = "ws://127.0.0.1:4069/decoy"; await assert.rejects( - rendezvous.resolve({ verseId: "sample.counter", authorityRuntimeId: "sample.counter-daemon" }), + rendezvous.resolve({ verseId: "sample.counter", authorityRuntimeId: "sample.counter-daemon" }, localTrust), (error: unknown) => error instanceof AggregateError && error.errors.some(inner => inner instanceof Error && /ambiguous legacy routes/.test(inner.message)), ); }); +test("Odin rendezvous rejects a poisoned route without vetoing a certified fallback", async () => { + const signed = await createSignedRoute("wss://provider.example/mesh"); + const odin = new FakeOdin(signed.route.endpoint); + odin.authorityRoutesOverride = [ + { + authorityRuntimeId: signed.route.authorityRuntimeId, + endpoint: "wss://poison.example/mesh", + protocolIds: ["cultmesh.documents.v1"], + priority: 0, + generation: "poisoned", + }, + routeForCatalog(signed.route), + ]; + const rendezvous = new CultMeshBrowserOdinRendezvous({ + endpoints: ["ws://127.0.0.1:4040/odin"], + runtimeId: "browser-certified-fallback-test", + socketFactory: () => odin.open(), + }); + + const selected = await rendezvous.resolve( + { verseId: signed.route.verseId, authorityRuntimeId: signed.route.authorityRuntimeId }, + { mode: "authenticated-remote", odinRoots: [signed.odinPublic] }, + ); + + assert.equal(selected.endpoint, signed.route.endpoint); +}); + test("browser client leases provider state, invokes an operation, and follows route replacement", async () => { const first = new FakeProvider("ws://127.0.0.1:4101/mesh", 4); const second = new FakeProvider("ws://127.0.0.1:4102/mesh", 9); @@ -362,6 +390,37 @@ test("browser client replays one idempotent operation after route loss without d await client.dispose(); }); +test("an early caller reconnect cancels the scheduled reconnect and keeps one live socket", async () => { + const provider = new FakeProvider("ws://127.0.0.1:4361/mesh", 2); + const client = await CultMeshBrowserClient.connect({ + ...provider.route, + runtimeId: "browser-single-reconnect-test", + rendezvous: { resolve: async () => provider.route }, + trust: localTrust, + reconnectDelayMs: 40, + socketFactory: () => provider.open(), + }); + const lease = await client.leaseRawDocument({ + schemaId: "sample.counter_state.v1", + recordKey: "counter:main", + }); + + provider.dropConnections(); + await client.invoke({ + serviceId: "sample.counter", + operation: "increment", + payloadSchema: "sample.increment.v1", + payload: { amount: 1 }, + }); + await new Promise(resolve => setTimeout(resolve, 80)); + + assert.equal(provider.openCount, 2); + assert.equal(provider.liveSocketCount, 1); + assert.equal(provider.activeSubscriptionCount, 1); + lease.dispose(); + await client.dispose(); +}); + test("browser client rejects an operation response from another runtime", async () => { const provider = new FakeProvider( "ws://127.0.0.1:4371/mesh", @@ -443,6 +502,7 @@ class FakeProvider { #rejectOperations: boolean; #runtimeId: string; #responseRuntimeId: string; + #openCount = 0; constructor( endpoint: string, @@ -469,7 +529,20 @@ class FakeProvider { return count; } + get openCount(): number { + return this.#openCount; + } + + get liveSocketCount(): number { + return this.#subscriptions.size; + } + + dropConnections(): void { + for (const socket of [...this.#subscriptions.keys()]) socket.close(1012, "route dropped"); + } + open(): FakeSocket { + this.#openCount++; const socket = new FakeSocket( wire => this.receive(socket, wire), () => this.#subscriptions.delete(socket), @@ -587,6 +660,7 @@ class FakeOdin { providerEndpoint: string; decoyEndpoint: string | undefined; omitAuthorityRoutes = false; + authorityRoutesOverride: NonNullable | undefined; constructor(providerEndpoint: string) { this.providerEndpoint = providerEndpoint; @@ -614,7 +688,7 @@ class FakeOdin { authorityRuntimeIds: this.decoyEndpoint ? ["sample.counter-daemon", "sample.decoy-daemon"] : ["sample.counter-daemon"], - ...(!this.omitAuthorityRoutes ? { authorityRoutes: [ + ...(!this.omitAuthorityRoutes ? { authorityRoutes: this.authorityRoutesOverride ?? [ ...(this.decoyEndpoint ? [{ authorityRuntimeId: "sample.decoy-daemon", endpoint: this.decoyEndpoint, @@ -637,6 +711,29 @@ class FakeOdin { } } +function routeForCatalog(route: CultMeshBrowserRoute): NonNullable< + CultMeshVerseCatalogResponseMessage["verses"][number]["authorityRoutes"] +>[number] { + return { + authorityRuntimeId: route.authorityRuntimeId, + endpoint: route.endpoint, + protocolIds: [...(route.protocolIds ?? [route.protocolId ?? "cultmesh.documents.v1"])], + priority: route.priority ?? 0, + generation: route.generation, + ...(route.certificate ? { + certificate: { + providerKeyId: route.certificate.providerKey.keyId, + providerPublicKeyX: route.certificate.providerKey.x, + providerPublicKeyY: route.certificate.providerKey.y, + odinKeyId: route.certificate.odinKeyId, + issuedAtUnixMilliseconds: route.certificate.issuedAtUnixMilliseconds, + expiresAtUnixMilliseconds: route.certificate.expiresAtUnixMilliseconds, + signature: route.certificate.signature, + }, + } : {}), + }; +} + function handshakeOnlySocket(route: CultMeshBrowserRoute): FakeSocket { let socket: FakeSocket; socket = new FakeSocket(wire => { diff --git a/samples/eve-browser-network/EveBrowserNetworkSample.csproj b/samples/eve-browser-network/EveBrowserNetworkSample.csproj index c83a42df..5dde9995 100644 --- a/samples/eve-browser-network/EveBrowserNetworkSample.csproj +++ b/samples/eve-browser-network/EveBrowserNetworkSample.csproj @@ -5,8 +5,8 @@ enable $(MSBuildThisFileDirectory)..\..\..\Eve false - 1.0.33 - 0.3.2 + 1.0.34 + 0.3.3 $(PackageFeed) diff --git a/scripts/pack-nuget.ps1 b/scripts/pack-nuget.ps1 index fa0d12bd..2b853aab 100644 --- a/scripts/pack-nuget.ps1 +++ b/scripts/pack-nuget.ps1 @@ -71,6 +71,7 @@ if (-not $SkipConsumerSmoke) { Remove-Item -LiteralPath $smokeRoot -Recurse -Force } New-Item -ItemType Directory -Force -Path $smokeRoot | Out-Null + $consumerPackages = Join-Path $smokeRoot "packages" $projectDocument = @" @@ -78,6 +79,8 @@ if (-not $SkipConsumerSmoke) { Exe enable $outputRoot;https://api.nuget.org/v3/index.json + $consumerPackages + true diff --git a/scripts/verify-eve-getting-started.ps1 b/scripts/verify-eve-getting-started.ps1 index e4143645..26c69f14 100644 --- a/scripts/verify-eve-getting-started.ps1 +++ b/scripts/verify-eve-getting-started.ps1 @@ -32,8 +32,8 @@ if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($sourceRevision)) { throw "Could not determine the CultLib source revision for local package identity." } $verificationNonce = [guid]::NewGuid().ToString("N").Substring(0, 8) -$cultLibLocalVersion = "1.0.33-local.$sourceRevision.$verificationNonce" -$surfaceLocalVersion = "0.3.2-local.$sourceRevision.$verificationNonce" +$cultLibLocalVersion = "1.0.34-local.$sourceRevision.$verificationNonce" +$surfaceLocalVersion = "0.3.3-local.$sourceRevision.$verificationNonce" try { & (Join-Path $EveRoot "scripts\pack-dotnet-surface.ps1") ` -CultLibRoot $cultLibRoot ` diff --git a/src/GameCult.Mesh/CultMeshSessions.cs b/src/GameCult.Mesh/CultMeshSessions.cs index b0dace01..9768dfd5 100644 --- a/src/GameCult.Mesh/CultMeshSessions.cs +++ b/src/GameCult.Mesh/CultMeshSessions.cs @@ -1084,16 +1084,21 @@ namespace GameCult.Mesh CultMeshSessionTarget target, CultMeshProtocolId protocol) { - return discovery.Candidates + var routes = discovery.Candidates .SelectMany(candidate => candidate.Descriptor.AuthorityRoutes) .Where(route => string.Equals( route.AuthorityRuntimeId, target.AuthorityRuntimeId, StringComparison.Ordinal)) .Where(route => route.Supports(protocol)) - .GroupBy(route => route.Endpoint, StringComparer.Ordinal) - .Select(group => group.OrderBy(route => route.Priority).First()) - .Select(route => new CultMeshTransportCandidate( + .ToArray(); + var verified = new List(); + var rejected = new List(); + foreach (var route in routes) + { + try + { + verified.Add(new CultMeshTransportCandidate( route.Endpoint, priority: route.Priority, authorityRuntimeId: route.AuthorityRuntimeId, @@ -1102,7 +1107,23 @@ namespace GameCult.Mesh .WithVerifiedAuthority(_options.Trust.Verify( target.VerseId, route, - _options.Clock.UtcNow))) + _options.Clock.UtcNow))); + } + catch (CultMeshSessionException error) + { + rejected.Add(error); + } + } + if (verified.Count == 0 && rejected.Count > 0) + { + throw Failure( + CultMeshSessionFailureReason.Authentication, + $"No trusted route remained for CultMesh target '{target}' and protocol '{protocol}'.", + new AggregateException(rejected)); + } + return verified + .GroupBy(candidate => candidate.Endpoint, StringComparer.Ordinal) + .Select(group => group.OrderBy(candidate => candidate.Priority).First()) .OrderBy(candidate => candidate.Priority) .ThenBy(candidate => candidate.Endpoint, StringComparer.Ordinal) .ToArray(); diff --git a/src/GameCult.Mesh/CultMeshVerseDiscovery.cs b/src/GameCult.Mesh/CultMeshVerseDiscovery.cs index c4ee15c7..1e98fc16 100644 --- a/src/GameCult.Mesh/CultMeshVerseDiscovery.cs +++ b/src/GameCult.Mesh/CultMeshVerseDiscovery.cs @@ -207,6 +207,12 @@ namespace GameCult.Mesh /// public Func? CreateClient { get; set; } + /// + /// Gets or sets an endpoint-aware client factory for external transport packages. + /// When present, this owns discovery transport selection for each exact Odin route. + /// + public Func? CreateClientForEndpoint { get; set; } + /// Gets or sets the clock that owns discovery deadlines. public ICultMeshClock Clock { get; set; } = CultMeshSystemClock.Instance; @@ -341,7 +347,8 @@ namespace GameCult.Mesh private ICultNetSchemaClient CreateClient(string endpoint) { - return _options.CreateClient?.Invoke() + return _options.CreateClientForEndpoint?.Invoke(endpoint) + ?? _options.CreateClient?.Invoke() ?? CultNetSchemaClients.CreateForEndpoint(endpoint, _options.Security, _options.ConfigureClient); } diff --git a/src/GameCult.Mesh/docs/getting-started/02-connect-by-identity.md b/src/GameCult.Mesh/docs/getting-started/02-connect-by-identity.md index 28cc06ad..47905fec 100644 --- a/src/GameCult.Mesh/docs/getting-started/02-connect-by-identity.md +++ b/src/GameCult.Mesh/docs/getting-started/02-connect-by-identity.md @@ -16,6 +16,7 @@ become usable by merely repeating the expected Verse and runtime strings. ```csharp using GameCult.Mesh; +using GameCult.Networking.WebSockets; var odinEndpoint = Environment.GetEnvironmentVariable("ODIN_ENDPOINT") ?? throw new InvalidOperationException("Set ODIN_ENDPOINT to the configured rendezvous route."); @@ -33,11 +34,22 @@ var odinRoot = new CultMeshEcdsaP256PublicKey( using var mesh = new CultMeshClient(new CultMeshClientOptions { RendezvousEndpoints = new[] { odinEndpoint }, + Discovery = new CultMeshVerseDiscoveryClientOptions + { + CreateClientForEndpoint = _ => new CultNetWebSocketSchemaClient() + }, Sessions = new CultMeshSessionManagerOptions { Trust = new CultMeshAuthorityTrustPolicy( CultMeshAuthorityTrustMode.AuthenticatedRemote, new[] { odinRoot }) + }, + Connectors = new ICultMeshTransportConnector[] + { + new CultMeshUriSchemaTransportConnector( + "cultnet-websocket", + new[] { "wss" }, + _ => new CultNetWebSocketSchemaClient()) } }); @@ -93,6 +105,30 @@ provider names, and Odin wire fields cannot turn this exception on. Remote routes require a trusted Odin signature, provider nonce proof, certificate validity, and a protected channel. +The remote example requires both `GameCult.Mesh` and +`GameCult.Networking.WebSockets` at the same CultLib package version. Core +CultMesh does not silently install a network stack: the consumer chooses the +secure connector and its TLS policy. The default TCP connector exists for the +explicit loopback-development case and cannot satisfy authenticated-remote +trust. + +An authenticated provider receives an Odin-certified route and its matching +provider private key from deployment configuration. It attaches the proof gate +to the same WSS schema server before publishing the route: + +```csharp +using var identity = new CultMeshSessionIdentityServer( + schemaServer, + authorityRuntimeId: "sample.counter-daemon", + verseIds: new[] { "sample.counter" }, + protocolIds: new[] { CultMeshProtocols.Documents.Value }, + routeGenerations: new[] { certifiedRoute.Generation }, + proofSigners: new[] { new CultMeshSessionProofSigner(certifiedRoute, providerPrivateKey) }); +``` + +`certifiedRoute` is the exact signed route Odin publishes. The provider never +holds Odin's signing key, and an unsigned WSS route is still untrusted. + Fast session-management check (this uses controlled transports; it is not the network proof): diff --git a/tests/GameCult.Mesh.Tests/CultMeshAuthorityProofTests.cs b/tests/GameCult.Mesh.Tests/CultMeshAuthorityProofTests.cs index 88c7e803..246e510a 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshAuthorityProofTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshAuthorityProofTests.cs @@ -134,6 +134,45 @@ public sealed class CultMeshAuthorityProofTests .Which.Failure.Reason.Should().Be(CultMeshSessionFailureReason.Authority); } + [Test] + public async Task SessionManagerRejectsOnlyThePoisonedRouteAndUsesCertifiedFallback() + { + using var odin = ECDsa.Create(ECCurve.NamedCurves.nistP256); + using var provider = ECDsa.Create(ECCurve.NamedCurves.nistP256); + var now = DateTimeOffset.UtcNow; + var valid = CultMeshAuthorityProof.CreateSignedRoute( + "aetheria", "aetheria-daemon", "wss://provider.example/mesh", + new[] { CultMeshProtocols.Documents.Value }, 10, "generation-valid", + CultMeshEcdsaP256PublicKey.From("provider-valid", provider), "odin-valid", + now.AddMinutes(-1), now.AddMinutes(5), odin); + var poisoned = new CultMeshAuthorityRoute( + "aetheria-daemon", "wss://poison.example/mesh", + new[] { CultMeshProtocols.Documents.Value }, priority: 0, generation: "generation-poisoned"); + var descriptor = new CultMeshVerseDescriptor( + "aetheria", "Aetheria", CultMeshVerseAuthorityModel.OperatorCluster, + new CultMeshVerseCompatibility("cultmesh.v0", "rules"), + authorityRoutes: new[] { poisoned, valid }); + using var discovery = new CultMeshDiscoveryService(new[] { new SignedRouteSource(descriptor) }); + var signer = new CultMeshSessionProofSigner(valid, provider); + var connector = new SigningConnector(signer); + using var manager = new CultMeshSessionManager( + discovery, + new[] { connector }, + new CultMeshSessionManagerOptions + { + Trust = new CultMeshAuthorityTrustPolicy( + CultMeshAuthorityTrustMode.AuthenticatedRemote, + new[] { CultMeshEcdsaP256PublicKey.From("odin-valid", odin) }) + }); + + var session = await manager.ConnectAsync( + new CultMeshSessionTarget("aetheria", "aetheria-daemon"), + CultMeshProtocols.Documents); + + session.State.Path!.Endpoint.Should().Be(valid.Endpoint); + connector.Attempts.Should().Equal(valid.Endpoint); + } + private static CultMeshAuthorityRoute SignedRoute(ECDsa odin, ECDsa provider) => CultMeshAuthorityProof.CreateSignedRoute( "aetheria", @@ -238,4 +277,53 @@ public sealed class CultMeshAuthorityProofTests } public void Dispose() { } } + + private sealed class SigningConnector : ICultMeshTransportConnector + { + private readonly CultMeshSessionProofSigner _signer; + public SigningConnector(CultMeshSessionProofSigner signer) => _signer = signer; + public List Attempts { get; } = new(); + public string ConnectorId => "signed-provider"; + public int Priority => 0; + public bool CanConnect(CultMeshTransportCandidate candidate) => true; + public Task ConnectAsync( + CultMeshTransportCandidate candidate, + CultMeshProtocolId protocol, + CancellationToken cancellationToken = default) + { + Attempts.Add(candidate.Endpoint); + return Task.FromResult(new SigningClient(_signer)); + } + } + + private sealed class SigningClient : ICultNetSchemaClient + { + private readonly CultMeshSessionProofSigner _signer; + private Action? _accepted; + public SigningClient(CultMeshSessionProofSigner signer) => _signer = signer; + public bool Connected => true; + public void Connect(string host, int port) { } + public void SendCultNet(T message) where T : ICultNetSchemaMessage + { + if (message is not CultMeshSessionOpenMessage request) return; + _accepted?.Invoke(new CultMeshSessionAcceptedMessage + { + MessageId = request.MessageId, + Accepted = true, + VerseId = request.VerseId, + AuthorityRuntimeId = request.AuthorityRuntimeId, + ProtocolId = request.ProtocolId, + RouteGeneration = request.RouteGeneration, + ClientNonce = request.ClientNonce, + ProviderKeyId = _signer.ProviderKeyId, + ProviderSignature = _signer.Sign(request) + }); + } + public void OnCultNet(Action callback) where T : ICultNetSchemaMessage + { + if (typeof(T) == typeof(CultMeshSessionAcceptedMessage)) + _accepted = response => callback((T)(object)response); + } + public void Dispose() { } + } } diff --git a/unity/org.gamecult.cultlib/package.json b/unity/org.gamecult.cultlib/package.json index 7c2cce1c..b0a00486 100644 --- a/unity/org.gamecult.cultlib/package.json +++ b/unity/org.gamecult.cultlib/package.json @@ -1,7 +1,7 @@ { "name": "org.gamecult.cultlib", "displayName": "CultLib", - "version": "1.0.47", + "version": "1.0.48", "unity": "2021.3", "description": "CultCache, CultNet, and CultMesh managed runtime assemblies for Unity.", "license": "MIT", From 99458dbb57bcb677bb72edba1362bce9fc9cab9d Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 20:09:44 +0200 Subject: [PATCH 098/283] Ship authenticated remote transports in Unity package --- Directory.Build.props | 2 +- .../EveBrowserNetworkSample.csproj | 2 +- scripts/build-unity-package.ps1 | 42 +++++- scripts/verify-eve-getting-started.ps1 | 2 +- src/GameCult.Mesh/CultMeshClient.cs | 5 +- .../CultMeshHttpsContentTransport.cs | 124 ++++++++++++++++++ .../CultNetWebSocketMessageIO.cs | 46 +++++++ .../CultNetWebSocketSchemaClient.cs | 10 +- .../CultNetWebSocketSchemaServer.cs | 38 ------ .../GameCult.Networking.WebSockets.csproj | 8 +- .../CultMeshAuthorityProofTests.cs | 78 +++++++++++ .../Runtime/GameCult.CultLib.asmdef | 1 + .../Plugins/GameCult.Caching.MessagePack.dll | Bin 43520 -> 45568 bytes .../Plugins/GameCult.Caching.MessagePack.pdb | Bin 19940 -> 23092 bytes .../Runtime/Plugins/GameCult.Caching.dll | Bin 86016 -> 90624 bytes .../Runtime/Plugins/GameCult.Caching.pdb | Bin 30140 -> 35804 bytes .../Runtime/Plugins/GameCult.Logging.dll | Bin 6656 -> 7168 bytes .../Runtime/Plugins/GameCult.Logging.pdb | Bin 9480 -> 9620 bytes .../Plugins/GameCult.Mesh.Quic.Native.dll | Bin 15360 -> 16896 bytes .../Plugins/GameCult.Mesh.Quic.Native.pdb | Bin 12216 -> 12832 bytes .../Runtime/Plugins/GameCult.Mesh.dll | Bin 656384 -> 758784 bytes .../Runtime/Plugins/GameCult.Mesh.pdb | Bin 197728 -> 251464 bytes .../GameCult.Networking.WebSockets.dll | Bin 0 -> 15360 bytes .../GameCult.Networking.WebSockets.dll.meta | 2 + .../Runtime/Plugins/GameCult.Networking.dll | Bin 496128 -> 549376 bytes .../Runtime/Plugins/GameCult.Networking.pdb | Bin 235008 -> 284016 bytes .../x86_64/gamecult_mesh_quic_native.dll | Bin 40448 -> 171008 bytes unity/org.gamecult.cultlib/package.json | 2 +- 28 files changed, 309 insertions(+), 53 deletions(-) create mode 100644 src/GameCult.Mesh/CultMeshHttpsContentTransport.cs create mode 100644 src/GameCult.Networking.WebSockets/CultNetWebSocketMessageIO.cs create mode 100644 unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.WebSockets.dll create mode 100644 unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.WebSockets.dll.meta diff --git a/Directory.Build.props b/Directory.Build.props index 595da325..10c8d749 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -14,7 +14,7 @@ MIT © Meta Vens and contributors true - 1.0.34 + 1.0.35 $(CultLibPackageVersion) diff --git a/samples/eve-browser-network/EveBrowserNetworkSample.csproj b/samples/eve-browser-network/EveBrowserNetworkSample.csproj index 5dde9995..50b41781 100644 --- a/samples/eve-browser-network/EveBrowserNetworkSample.csproj +++ b/samples/eve-browser-network/EveBrowserNetworkSample.csproj @@ -5,7 +5,7 @@ enable $(MSBuildThisFileDirectory)..\..\..\Eve false - 1.0.34 + 1.0.35 0.3.3 $(PackageFeed) diff --git a/scripts/build-unity-package.ps1 b/scripts/build-unity-package.ps1 index 08366cc5..c0e0518f 100644 --- a/scripts/build-unity-package.ps1 +++ b/scripts/build-unity-package.ps1 @@ -9,9 +9,11 @@ $ErrorActionPreference = "Stop" $repoRoot = Split-Path -Parent $PSScriptRoot $projectPath = Join-Path $repoRoot "src\GameCult.Mesh\GameCult.Mesh.csproj" +$webSocketProjectPath = Join-Path $repoRoot "src\GameCult.Networking.WebSockets\GameCult.Networking.WebSockets.csproj" $quicProjectPath = Join-Path $repoRoot "src\GameCult.Mesh.Quic.Native\GameCult.Mesh.Quic.Native.csproj" $templateRoot = Join-Path $repoRoot "unity\org.gamecult.cultlib" $publishRoot = Join-Path $repoRoot "artifacts\unity-publish" +$webSocketPublishRoot = Join-Path $repoRoot "artifacts\unity-websocket-publish" $quicPublishRoot = Join-Path $repoRoot "artifacts\unity-quic-publish" $quicNativeRoot = Join-Path $repoRoot "artifacts\unity-quic-native" $outputRoot = if ([System.IO.Path]::IsPathRooted($OutputDirectory)) { @@ -27,11 +29,15 @@ if (Test-Path -LiteralPath $publishRoot) { if (Test-Path -LiteralPath $quicPublishRoot) { Remove-Item -LiteralPath $quicPublishRoot -Recurse -Force } +if (Test-Path -LiteralPath $webSocketPublishRoot) { + Remove-Item -LiteralPath $webSocketPublishRoot -Recurse -Force +} if (Test-Path -LiteralPath $outputRoot) { Remove-Item -LiteralPath $outputRoot -Recurse -Force } -$publishArguments = @("publish", $projectPath, "-c", $Configuration, "-o", $publishRoot) +$unityPackageVersion = (Get-Content -LiteralPath (Join-Path $templateRoot "package.json") -Raw | ConvertFrom-Json).version +$publishArguments = @("publish", $projectPath, "-c", $Configuration, "-o", $publishRoot, "-p:CultLibPackageVersion=$unityPackageVersion") if (-not [string]::IsNullOrWhiteSpace($NuGetConfig)) { $publishArguments += "-p:RestoreConfigFile=$([IO.Path]::GetFullPath($NuGetConfig))" } @@ -39,7 +45,15 @@ if (-not [string]::IsNullOrWhiteSpace($NuGetConfig)) { if ($LASTEXITCODE -ne 0) { throw "CultLib publish failed with exit code $LASTEXITCODE" } -$quicPublishArguments = @("publish", $quicProjectPath, "-c", $Configuration, "-o", $quicPublishRoot) +$webSocketPublishArguments = @("publish", $webSocketProjectPath, "-c", $Configuration, "-f", "netstandard2.1", "-o", $webSocketPublishRoot, "-p:CultLibPackageVersion=$unityPackageVersion") +if (-not [string]::IsNullOrWhiteSpace($NuGetConfig)) { + $webSocketPublishArguments += "-p:RestoreConfigFile=$([IO.Path]::GetFullPath($NuGetConfig))" +} +& dotnet @webSocketPublishArguments +if ($LASTEXITCODE -ne 0) { + throw "CultLib WebSocket publish failed with exit code $LASTEXITCODE" +} +$quicPublishArguments = @("publish", $quicProjectPath, "-c", $Configuration, "-o", $quicPublishRoot, "-p:CultLibPackageVersion=$unityPackageVersion") if (-not [string]::IsNullOrWhiteSpace($NuGetConfig)) { $quicPublishArguments += "-p:RestoreConfigFile=$([IO.Path]::GetFullPath($NuGetConfig))" } @@ -63,6 +77,7 @@ $expectedAssemblies = @( "GameCult.Mesh.dll", "GameCult.Mesh.Quic.Native.dll", "GameCult.Networking.dll", + "GameCult.Networking.WebSockets.dll", "Isopoh.Cryptography.Argon2.dll", "Isopoh.Cryptography.Blake2b.dll", "Isopoh.Cryptography.SecureArray.dll", @@ -88,6 +103,9 @@ foreach ($assembly in Get-ChildItem -LiteralPath $publishRoot -Filter "*.dll") { foreach ($assembly in Get-ChildItem -LiteralPath $quicPublishRoot -Filter "*.dll") { $publishedByName[$assembly.Name] = $assembly } +foreach ($assembly in Get-ChildItem -LiteralPath $webSocketPublishRoot -Filter "*.dll") { + $publishedByName[$assembly.Name] = $assembly +} foreach ($assemblyName in $expectedAssemblies) { if (-not $publishedByName.ContainsKey($assemblyName)) { throw "CultLib Unity package is missing expected assembly: $assemblyName" @@ -112,6 +130,26 @@ New-Item -ItemType Directory -Force -Path (Join-Path $outputRoot "Third Party No Copy-Item -LiteralPath (Join-Path $quicNativeRoot "MSQUIC-LICENSE.txt") ` -Destination (Join-Path $outputRoot "Third Party Notices\MSQUIC-LICENSE.txt") +$meshPackagePath = Join-Path $pluginRoot "GameCult.Mesh.dll" +$meshPackageVersion = [Reflection.AssemblyName]::GetAssemblyName($meshPackagePath).Version.ToString() +if ($meshPackageVersion -ne "$unityPackageVersion.0") { + throw "Packaged GameCult.Mesh.dll version '$meshPackageVersion' does not match package '$unityPackageVersion'." +} +$meshPackageMetadata = [Text.Encoding]::UTF8.GetString([IO.File]::ReadAllBytes($meshPackagePath)) +foreach ($requiredType in @( + "GameCult.Mesh.CultMeshAuthorityTrustPolicy", + "GameCult.Mesh.CultMeshRouteCertificate", + "GameCult.Mesh.CultMeshHttpsContentTransportConnector")) { + if (-not $meshPackageMetadata.Contains($requiredType.Split('.')[-1])) { + throw "Packaged GameCult.Mesh.dll is missing required API '$requiredType'." + } +} +$webSocketPackageMetadata = [Text.Encoding]::UTF8.GetString( + [IO.File]::ReadAllBytes((Join-Path $pluginRoot "GameCult.Networking.WebSockets.dll"))) +if (-not $webSocketPackageMetadata.Contains("CultNetWebSocketSchemaClient")) { + throw "Packaged WebSocket assembly is missing the Unity-compatible CultNet client." +} + if ($UpdateTemplate) { $templatePluginRoot = Join-Path $templateRoot "Runtime\Plugins" foreach ($assemblyName in $expectedAssemblies) { diff --git a/scripts/verify-eve-getting-started.ps1 b/scripts/verify-eve-getting-started.ps1 index 26c69f14..4a87b19d 100644 --- a/scripts/verify-eve-getting-started.ps1 +++ b/scripts/verify-eve-getting-started.ps1 @@ -32,7 +32,7 @@ if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($sourceRevision)) { throw "Could not determine the CultLib source revision for local package identity." } $verificationNonce = [guid]::NewGuid().ToString("N").Substring(0, 8) -$cultLibLocalVersion = "1.0.34-local.$sourceRevision.$verificationNonce" +$cultLibLocalVersion = "1.0.35-local.$sourceRevision.$verificationNonce" $surfaceLocalVersion = "0.3.3-local.$sourceRevision.$verificationNonce" try { & (Join-Path $EveRoot "scripts\pack-dotnet-surface.ps1") ` diff --git a/src/GameCult.Mesh/CultMeshClient.cs b/src/GameCult.Mesh/CultMeshClient.cs index 19a01c54..230ce55b 100644 --- a/src/GameCult.Mesh/CultMeshClient.cs +++ b/src/GameCult.Mesh/CultMeshClient.cs @@ -27,8 +27,8 @@ namespace GameCult.Mesh public IReadOnlyList? Connectors { get; set; } /// - /// Gets or sets streaming content connectors. TCP content delivery is used by default; - /// applications may replace it or explicitly add legacy RUDP. + /// Gets or sets streaming content connectors. HTTPS and loopback TCP content + /// delivery are used by default; applications may replace them or explicitly add legacy RUDP. /// public IReadOnlyList? ContentConnectors { get; set; } @@ -184,6 +184,7 @@ namespace GameCult.Mesh }, options.ContentConnectors ?? new ICultMeshContentTransportConnector[] { + new CultMeshHttpsContentTransportConnector(), new CultMeshTcpContentTransportConnector() }, options.RealtimeConnectors, diff --git a/src/GameCult.Mesh/CultMeshHttpsContentTransport.cs b/src/GameCult.Mesh/CultMeshHttpsContentTransport.cs new file mode 100644 index 00000000..d6427470 --- /dev/null +++ b/src/GameCult.Mesh/CultMeshHttpsContentTransport.cs @@ -0,0 +1,124 @@ +using System; +using System.IO; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; + +namespace GameCult.Mesh +{ + /// + /// Opens immutable content over an Odin-certified HTTPS route. Provider + /// identity comes from the verified route and TLS endpoint; the transfer + /// service remains responsible for checking the advertised chunk hash. + /// + public sealed class CultMeshHttpsContentTransportConnector : ICultMeshContentTransportConnector + { + private readonly Func _createHandler; + + public CultMeshHttpsContentTransportConnector(Func? createHandler = null) + { + _createHandler = createHandler ?? (() => new HttpClientHandler()); + } + + public string ConnectorId => "https-content"; + public int Priority => 0; + + public bool CanConnect(CultMeshTransportCandidate candidate) => + candidate != null && + Uri.TryCreate(candidate.Endpoint, UriKind.Absolute, out var endpoint) && + string.Equals(endpoint.Scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase); + + public Task ConnectAsync( + CultMeshTransportCandidate candidate, + CultMeshSessionTarget target, + CancellationToken cancellationToken = default) + { + if (candidate == null) throw new ArgumentNullException(nameof(candidate)); + if (target == null) throw new ArgumentNullException(nameof(target)); + if (!CanConnect(candidate)) + throw new NotSupportedException($"HTTPS content connector does not support '{candidate.Endpoint}'."); + cancellationToken.ThrowIfCancellationRequested(); + return Task.FromResult(new CultMeshHttpsContentTransport( + candidate.Endpoint, + new HttpClient(_createHandler(), disposeHandler: true), + target, + candidate.Generation)); + } + } + + internal sealed class CultMeshHttpsContentTransport : ICultMeshContentTransport, ICultMeshVerifiedTransport + { + private readonly HttpClient _client; + private readonly CultMeshSessionTarget _target; + private readonly string _routeGeneration; + private bool _disposed; + + public CultMeshHttpsContentTransport( + string endpoint, + HttpClient client, + CultMeshSessionTarget target, + string routeGeneration) + { + Endpoint = endpoint ?? throw new ArgumentNullException(nameof(endpoint)); + _client = client ?? throw new ArgumentNullException(nameof(client)); + _target = target ?? throw new ArgumentNullException(nameof(target)); + _routeGeneration = routeGeneration ?? string.Empty; + } + + public string TransportId => "https-content"; + public string Endpoint { get; } + + public bool IsVerifiedFor( + string verseId, + string authorityRuntimeId, + string protocolId, + string routeGeneration) => + string.Equals(_target.VerseId, verseId, StringComparison.Ordinal) && + string.Equals(_target.AuthorityRuntimeId, authorityRuntimeId, StringComparison.Ordinal) && + string.Equals(CultMeshProtocols.Content.Value, protocolId, StringComparison.Ordinal) && + string.Equals(_routeGeneration, routeGeneration, StringComparison.Ordinal); + + public async Task CopyChunkToAsync( + CultMeshCdnChunkRef chunk, + Stream destination, + CancellationToken cancellationToken = default) + { + if (_disposed) throw new ObjectDisposedException(nameof(CultMeshHttpsContentTransport)); + if (chunk == null) throw new ArgumentNullException(nameof(chunk)); + if (destination == null) throw new ArgumentNullException(nameof(destination)); + if (!destination.CanWrite) throw new ArgumentException("Content destination must be writable.", nameof(destination)); + + var requestUri = BuildChunkUri(Endpoint, chunk); + using var response = await _client.GetAsync( + requestUri, + HttpCompletionOption.ResponseHeadersRead, + cancellationToken).ConfigureAwait(false); + response.EnsureSuccessStatusCode(); + if (response.Content.Headers.ContentLength is long contentLength && + contentLength != chunk.SizeBytes) + { + throw new InvalidDataException( + $"HTTPS content length {contentLength} did not match advertised chunk size {chunk.SizeBytes}."); + } + using var source = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await source.CopyToAsync(destination, 81920, cancellationToken).ConfigureAwait(false); + } + + public void Dispose() + { + if (_disposed) return; + _disposed = true; + _client.Dispose(); + } + + private static Uri BuildChunkUri(string endpoint, CultMeshCdnChunkRef chunk) + { + var builder = new UriBuilder(endpoint); + var separator = string.IsNullOrWhiteSpace(builder.Query) ? string.Empty : builder.Query.TrimStart('?') + "&"; + builder.Query = separator + + "chunkHash=" + Uri.EscapeDataString(CultMeshCdn.NormalizeHash(chunk.ChunkHash, nameof(chunk.ChunkHash))) + + "&recordKey=" + Uri.EscapeDataString(chunk.RecordKey ?? string.Empty); + return builder.Uri; + } + } +} diff --git a/src/GameCult.Networking.WebSockets/CultNetWebSocketMessageIO.cs b/src/GameCult.Networking.WebSockets/CultNetWebSocketMessageIO.cs new file mode 100644 index 00000000..de10a66e --- /dev/null +++ b/src/GameCult.Networking.WebSockets/CultNetWebSocketMessageIO.cs @@ -0,0 +1,46 @@ +using System; +using System.IO; +using System.Net.WebSockets; +using System.Threading; +using System.Threading.Tasks; + +namespace GameCult.Networking.WebSockets; + +internal static class CultNetWebSocketMessageIO +{ + public static Task SendAsync(WebSocket socket, byte[] payload, CancellationToken cancellationToken) => + socket.SendAsync(new ArraySegment(payload), WebSocketMessageType.Binary, true, cancellationToken); + + public static async Task ReceiveAsync( + WebSocket socket, + int maxMessageBytes, + CancellationToken cancellationToken) + { + var segment = new byte[Math.Min(16 * 1024, maxMessageBytes)]; + using var message = new MemoryStream(); + while (true) + { + var result = await socket.ReceiveAsync(new ArraySegment(segment), cancellationToken) + .ConfigureAwait(false); + if (result.MessageType == WebSocketMessageType.Close) return null; + if (result.MessageType != WebSocketMessageType.Binary) + { + await socket.CloseAsync( + WebSocketCloseStatus.InvalidMessageType, + "CultNet requires binary MessagePack WebSocket messages.", + cancellationToken).ConfigureAwait(false); + return null; + } + if (message.Length + result.Count > maxMessageBytes) + { + await socket.CloseAsync( + WebSocketCloseStatus.MessageTooBig, + "CultNet message exceeds the configured maximum.", + cancellationToken).ConfigureAwait(false); + return null; + } + message.Write(segment, 0, result.Count); + if (result.EndOfMessage) return message.ToArray(); + } + } +} diff --git a/src/GameCult.Networking.WebSockets/CultNetWebSocketSchemaClient.cs b/src/GameCult.Networking.WebSockets/CultNetWebSocketSchemaClient.cs index 0a233ab7..394fe207 100644 --- a/src/GameCult.Networking.WebSockets/CultNetWebSocketSchemaClient.cs +++ b/src/GameCult.Networking.WebSockets/CultNetWebSocketSchemaClient.cs @@ -37,7 +37,7 @@ public sealed class CultNetWebSocketSchemaClient : ICultNetUriSchemaClient, ICul /// public void Connect(string host, int port) { - ArgumentException.ThrowIfNullOrWhiteSpace(host); + if (string.IsNullOrWhiteSpace(host)) throw new ArgumentException("Host is required.", nameof(host)); if (port <= 0 || port > 65535) throw new ArgumentOutOfRangeException(nameof(port)); ConnectAsync(new Uri($"ws://{host}:{port}/cultmesh"), CancellationToken.None) .GetAwaiter().GetResult(); @@ -46,7 +46,7 @@ public sealed class CultNetWebSocketSchemaClient : ICultNetUriSchemaClient, ICul /// Connects to an exact WebSocket route. public async Task ConnectAsync(Uri endpoint, CancellationToken cancellationToken = default) { - ArgumentNullException.ThrowIfNull(endpoint); + if (endpoint == null) throw new ArgumentNullException(nameof(endpoint)); if (endpoint.Scheme is not ("ws" or "wss")) throw new ArgumentException("CultNet WebSocket endpoint must use ws:// or wss://.", nameof(endpoint)); ThrowIfDisposed(); @@ -69,7 +69,7 @@ public sealed class CultNetWebSocketSchemaClient : ICultNetUriSchemaClient, ICul /// public void SendCultNet(T message) where T : ICultNetSchemaMessage { - ArgumentNullException.ThrowIfNull(message); + if (message == null) throw new ArgumentNullException(nameof(message)); ThrowIfDisposed(); var socket = _socket; if (socket?.State != WebSocketState.Open) @@ -92,7 +92,7 @@ public sealed class CultNetWebSocketSchemaClient : ICultNetUriSchemaClient, ICul /// public void OnCultNet(Action callback) where T : ICultNetSchemaMessage { - ArgumentNullException.ThrowIfNull(callback); + if (callback == null) throw new ArgumentNullException(nameof(callback)); ThrowIfDisposed(); lock (_handlerGate) { @@ -161,6 +161,6 @@ public sealed class CultNetWebSocketSchemaClient : ICultNetUriSchemaClient, ICul private void ThrowIfDisposed() { - ObjectDisposedException.ThrowIf(_disposed, this); + if (_disposed) throw new ObjectDisposedException(nameof(CultNetWebSocketSchemaClient)); } } diff --git a/src/GameCult.Networking.WebSockets/CultNetWebSocketSchemaServer.cs b/src/GameCult.Networking.WebSockets/CultNetWebSocketSchemaServer.cs index 240311a1..fa2728d8 100644 --- a/src/GameCult.Networking.WebSockets/CultNetWebSocketSchemaServer.cs +++ b/src/GameCult.Networking.WebSockets/CultNetWebSocketSchemaServer.cs @@ -178,44 +178,6 @@ public sealed class CultNetWebSocketSchemaServer : } } -internal static class CultNetWebSocketMessageIO -{ - public static Task SendAsync(WebSocket socket, byte[] payload, CancellationToken cancellationToken) => - socket.SendAsync(payload, WebSocketMessageType.Binary, true, cancellationToken); - - public static async Task ReceiveAsync( - WebSocket socket, - int maxMessageBytes, - CancellationToken cancellationToken) - { - var segment = new byte[Math.Min(16 * 1024, maxMessageBytes)]; - using var message = new MemoryStream(); - while (true) - { - var result = await socket.ReceiveAsync(segment, cancellationToken).ConfigureAwait(false); - if (result.MessageType == WebSocketMessageType.Close) return null; - if (result.MessageType != WebSocketMessageType.Binary) - { - await socket.CloseAsync( - WebSocketCloseStatus.InvalidMessageType, - "CultNet requires binary MessagePack WebSocket messages.", - cancellationToken).ConfigureAwait(false); - return null; - } - if (message.Length + result.Count > maxMessageBytes) - { - await socket.CloseAsync( - WebSocketCloseStatus.MessageTooBig, - "CultNet message exceeds the configured maximum.", - cancellationToken).ConfigureAwait(false); - return null; - } - message.Write(segment, 0, result.Count); - if (result.EndOfMessage) return message.ToArray(); - } - } -} - /// ASP.NET Core endpoint mapping for the CultNet WebSocket schema server. public static class CultNetWebSocketEndpointRouteBuilderExtensions { diff --git a/src/GameCult.Networking.WebSockets/GameCult.Networking.WebSockets.csproj b/src/GameCult.Networking.WebSockets/GameCult.Networking.WebSockets.csproj index 6ced9b42..3144d7fe 100644 --- a/src/GameCult.Networking.WebSockets/GameCult.Networking.WebSockets.csproj +++ b/src/GameCult.Networking.WebSockets/GameCult.Networking.WebSockets.csproj @@ -1,14 +1,18 @@ - net10.0 + net10.0;netstandard2.1 enable enable CultNet schema-v0 WebSocket host adapter for browser and web runtimes GameCult.Networking.WebSockets game;networking;websocket;cultnet;cultmesh - + + + + + diff --git a/tests/GameCult.Mesh.Tests/CultMeshAuthorityProofTests.cs b/tests/GameCult.Mesh.Tests/CultMeshAuthorityProofTests.cs index 246e510a..42f02297 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshAuthorityProofTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshAuthorityProofTests.cs @@ -1,6 +1,10 @@ using System; using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Http; using System.Security.Cryptography; +using System.Text; using System.Threading; using System.Threading.Tasks; using FluentAssertions; @@ -173,6 +177,54 @@ public sealed class CultMeshAuthorityProofTests connector.Attempts.Should().Equal(valid.Endpoint); } + [Test] + public async Task AuthenticatedRemoteContentUsesCertifiedHttpsAndStreamsTheAdvertisedChunk() + { + using var odin = ECDsa.Create(ECCurve.NamedCurves.nistP256); + using var provider = ECDsa.Create(ECCurve.NamedCurves.nistP256); + var payload = Encoding.UTF8.GetBytes("certified-content"); + var route = CultMeshAuthorityProof.CreateSignedRoute( + "aetheria", "aetheria-daemon", "https://provider.example/cultmesh/content", + new[] { CultMeshProtocols.Content.Value }, 0, "content-generation", + CultMeshEcdsaP256PublicKey.From("provider-content", provider), "odin-content", + Now.AddMinutes(-1), Now.AddMinutes(5), odin); + var descriptor = new CultMeshVerseDescriptor( + "aetheria", "Aetheria", CultMeshVerseAuthorityModel.OperatorCluster, + new CultMeshVerseCompatibility("cultmesh.v0", "rules"), + authorityRoutes: new[] { route }); + using var discovery = new CultMeshDiscoveryService(new[] { new SignedRouteSource(descriptor) }); + var handler = new FixedContentHandler(payload); + using var manager = new CultMeshSessionManager( + discovery, + Array.Empty(), + new ICultMeshContentTransportConnector[] + { + new CultMeshHttpsContentTransportConnector(() => handler) + }, + new CultMeshSessionManagerOptions + { + Trust = new CultMeshAuthorityTrustPolicy( + CultMeshAuthorityTrustMode.AuthenticatedRemote, + new[] { CultMeshEcdsaP256PublicKey.From("odin-content", odin) }), + Clock = new FixedClock(Now) + }); + + var session = await manager.ConnectContentAsync( + new CultMeshSessionTarget("aetheria", "aetheria-daemon")); + using var destination = new MemoryStream(); + await session.CopyChunkToAsync(new CultMeshCdnChunkRef + { + ChunkHash = Convert.ToHexString(SHA256.HashData(payload)).ToLowerInvariant(), + RecordKey = "cdn:chunk:certified", + SizeBytes = payload.Length + }, destination); + + destination.ToArray().Should().Equal(payload); + handler.RequestUri.Should().NotBeNull(); + handler.RequestUri!.Scheme.Should().Be(Uri.UriSchemeHttps); + handler.RequestUri.Query.Should().Contain("chunkHash=").And.Contain("recordKey="); + } + private static CultMeshAuthorityRoute SignedRoute(ECDsa odin, ECDsa provider) => CultMeshAuthorityProof.CreateSignedRoute( "aetheria", @@ -326,4 +378,30 @@ public sealed class CultMeshAuthorityProofTests } public void Dispose() { } } + + private sealed class FixedContentHandler : HttpMessageHandler + { + private readonly byte[] _payload; + public FixedContentHandler(byte[] payload) => _payload = payload; + public Uri? RequestUri { get; private set; } + + protected override Task SendAsync( + HttpRequestMessage request, + CancellationToken cancellationToken) + { + RequestUri = request.RequestUri; + return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new ByteArrayContent(_payload) + }); + } + } + + private sealed class FixedClock : ICultMeshClock + { + public FixedClock(DateTimeOffset now) => UtcNow = now; + public DateTimeOffset UtcNow { get; } + public Task DelayAsync(TimeSpan delay, CancellationToken cancellationToken = default) => + Task.Delay(delay, cancellationToken); + } } diff --git a/unity/org.gamecult.cultlib/Runtime/GameCult.CultLib.asmdef b/unity/org.gamecult.cultlib/Runtime/GameCult.CultLib.asmdef index 100db084..bd13cb38 100644 --- a/unity/org.gamecult.cultlib/Runtime/GameCult.CultLib.asmdef +++ b/unity/org.gamecult.cultlib/Runtime/GameCult.CultLib.asmdef @@ -14,6 +14,7 @@ "GameCult.Mesh.dll", "GameCult.Mesh.Quic.Native.dll", "GameCult.Networking.dll", + "GameCult.Networking.WebSockets.dll", "Isopoh.Cryptography.Argon2.dll", "Isopoh.Cryptography.Blake2b.dll", "Isopoh.Cryptography.SecureArray.dll", diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.dll index 0e9e063f0e1eb4e6b422e481c73891e311b7c0c2..2fdc1ff90934f068ecad258a10f1b229a7f08b48 100644 GIT binary patch literal 45568 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 diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.pdb index 56d08c92eef104d2d1e3d7b401e9a07b48f057e6..1b4555df2c2c008dccf5ae33ec5ee0c027dca9d3 100644 GIT binary patch delta 12251 zcmaJ{30&1x_P_V?c2-fI3dk-X0)m193W5qmL2i&6$}XTNDwsaC-tYGSMMX28TH2;< zZk49iI7_KbjoP#?PFB+}+B8d>)wIv}|9{VYzb8Mbh7afd?)Tnvw{y=u=lt&PeRvN) zae{Bla4Lfsi@lw(Wg(2s7Rb+RU(vj@v5n#H++fBGc*a)DWG^9ql=8(DB~$QRH-xd1 z1;CS9T5Exil)rvz%gWtFyLa8;eD?gQMVXJS`X`FntjGs_tpSX23T|CfGB0p2bse&iuGw)A5{#=L>kgO;3TR z5bQ=HXA6wNUBhp3FXJYsnH@51J#0>LCZj^ zK(~XsKs_KgXb)%~=m6*l=xNY1pyxq<1Q|wn`i>nT*aM*Nok-G>1RDn`1Sw;&M3Q7j$jW)1p zpjn^=pz1LO)(FbYG%)8INInD^#~N5X=;kZ~YXWtFBC`!FDhGMc7SK-6p793u5a=yXr zDPZ_Buy*9{*Yb~Q&nF@ZLYNPfjT4X5c)Je!x(f`E&N$QzWu|LfDZpVMp|vt2Plw2h zEyxekVXBYNVXBYRVXBYPVXBYr!%jvFF?|J$7-Dsp>S>bt2@Ka^s*l%UYM-FPRG+BB zR8I%R)1Q;c2_#)BU~&Q@b(lIx)?w;^q~x6t)u-w()sJGfYxRM^X*vu`#?rkQ{u5c>?67rXf$1iF&if?+ZLu!!$k% z1&z}&L;`2&Fqy<`9j?(~(hU-C4(cu10K`9Dhsgj>0JduNV}NskeHoYI%L(M6z)xeC z3kJdgz@#h#Kofxiwfe~#4hAM=Bn8Yz{Xnh$HyREBo`gKLr+Pc^TI2_U3V;VQr$>bU z)e1tvP>eh^B8D*FD&$FF2!{i^b@ju559{h9fZqm=k~{%837-DRHcdu*FaDE;qn%(N zKSv^;0)`l^!ATu%Kprkl*2kiLH}bTiLX^g7{Hrkz;dtO@QCFhXCjirg(lwk2JOI4; z8g`CA0epwtL+T(2csejms0er@F#W9n73;7siV3Hn{zKFe{|&&Y8h<8mi4NOAbld=|JC*hvj;Lcuc3c%H^k3LK5Wk~LfgoCF*TJRAHs1JmDl&>Y~Y8lDY27kHY6 zzXKcL>A=sSj!qKc8Nla}2fq`8216{K4!?z%30DC3g5fC?6TSu52XzjV5uOF?3%p#z zbAWdO*JyYy@E+hPz?I;i2TXsbG+YVXj{J=nUoy-`!D@M_@E9Wq=xb_R)_iqt^Iqz^}tOU-m1f7_MJ^g8oH@g2iB1p)ru9YeAUe#U#chz-?N+ z8MqbR(2E1mOB>pIF}d4z9VY&j{qU{VFyv1RtF9F=I2n3n=ep+S#+MV=(2t?J zAKusxZ|a9P_rpCpOcUIq!(^(rdaxWHp%P><|7uI!qI|ryssghv`(^ufsvWdkK^Or$4gg59$~QKdi$E zz>n&1DVpsEc4+O%J08$sYJX6N9|1n3!*t3H13SGPP{CvU7@p8!GPOs5*Xjm*Qio|p z$90%2CH+mJy~TN8IKngu13N(lSUpA1+iCv=tB^wQq#4L_Rw7GMWZGAPcPQB%m2>tk zQo*jE2OkzM%lmVhaq{WU!@o!J_aZg2Ge}Knh4HQI5dfR)!cXgnSh;L$ktIUfHY1Bi zId)#w(o`($N#w0s+gFhHm-)c!`k_{y{;5|Y+!@g7InKS0jPXsZ8Z{O+4XIV$MFcUt zi6hQyK!XrXjQYmqDEE>6!9X3!ZmH`pkQZzy+WIgXQoP`z#K>L;hetD9jg(LRa*M6!IsPVeFqW{R3s;|EYrBX@p#{58iD^jI>IlTqQXa;vvVBK;@h(+UMkz#vbV6VO4G zB>{W&wC!m~;2VB{Qt=H^r}4BfvyT&^e9SB-k(p#3Y3PV3lZ6c%k&pb=5em}yq|-=m zNa~d-GfPgSPbKBcd^J+rNX3jRs+^H~0df*gBRw#(7wOfJ%wlFclcSLKq*Nnald2#M zAGH^0eOfQlKc?qfsncqiDl*+GQ)V->`D5~tzMGM6v$D|4YUCe5YGo%g734oo=tX*F zT(8aQWP`GpubDMuMQN#(IkWPS{{pF%nX{{re-o*deVeTyza&RNeoam<@{Qwrk>5T( z-_OjxA771h-h^sDD_c52LH^=|y-0HsdyyvQGJi8Wl^cchhunOm>+%$&$-m0miw9dT@h?j2}myYf#DGP8t&(;>(gxSt!?YHVIw->}-9Iw;C-Ve5(|HSO&U zE6N?q+@*uUZHpTmZRM@ARy4P}7Y@oWG}W{_=Y*z=nY)kV85 z4s;b5OCNai!PwXKez3FgS@loTaZn!L@#jVFrv-I=?&H`{b7bzGr&gVrccCQl;jm!a zd`ro1o=JRW$oaZ?Q+D+%e80E&UyJ{Je$%}Rm;d0C`dF%A*DLFab4I%#{i)-Ls|5}Oq;JvsTzx}do%M&rCFQT42ma%K^ znTU*AORMkwCVHEFTKVO1mwon*?0tQ<@21mh>}h|yKRz?p5w<>m?N?`lUwQM?z2Cp~ zdU)i@mP+HQT;I&bQ4`(sl2V$}Ke(^(pM&ckExLI1-&36hE52CVdifsvd}nlU&%Zhs zyc`<*7JuO%7e7AY9`Qs*#o)ug3wtuPWaZocSN(3@-G_D!xO8^aJKLi^IrqhtoOge_ zzbtZf&JWvXo8P>8>$4;4nxEKqP)SLzD;#$qGJoIg-M>EeUH-Hm*gdbjXj)nJ=CIhc z#cEYfs=ILe-_FU zCyna@ikdD5`2NN=JM%-siNcTKF8tTv_6=J*XyA2v()nuV$6evacZbaulMk$osc)@Y zxdfWu7L&6!rYNVfa@va4MK};`m6cv~uB`lD`fQKL9#xl~ol#q#QCF9hk(rU1ot>6d zv#>TJD|>8hMtXL7{ld(K^t$Yt?2J)KF}L03s&L;PallqjdYrPXWo4T?CGu|Ll)_0B z#m8TYoXLlz8IHZjPUBtv)RN8aL%wAP&IfGnnG?s3s6#V?eOeHKAEE8l6q^ujHH zlhxGmfltQIUQ=ANq+v3STWV=*VU_+)_h3pv%4!_9ddPc@g1igUA%9{ zgIA6pj*beSNwHG=09bN_0Wuaam$fxctEpS;Th`FlR@2x(d82v%>HX(|a7egaa26{B zuGfT9*trSKYXU_Oo;(m=9BPFn#%<1vh&;y+m|&*0CiOm7yJARmLt z5z68%xIJ!|xh<8r0a}rO)KqJJ%@*o~&aF5XE+4Q$7^a4G|V! zRw4SP!fq3mXm%ql-OuE}_`+f3L1H9V?(+yQH`o{iPt0@CdYrHfCJrBlf#I5YAqw+I zb~H6a#k>p!lZ4ZP%SYiTg4gC1o>8$iKDa%?M1nwR+c^uuig_bCEfStlG7%E+*6T)bVwhx6VWBPU>p2SzxN^zl zz@?JGVdJ&vSJ{CsCr+)GL{b$q=`EZm!X4_gk@m5bV;JZX8e-$|jb?4Ui3Qr`$>9c4 zaS#n>R!&)!Q(QTPai@gP0FQXb9Zqw@XC^cA7ZkZ-5V4A5!PKjhx;3vYG9Z4cgXSC1 z_Z+D|0qC}fujI-Jp&YhzWxbtxed@Zk9%p~?^+&7vBUgXKx|R2E&BK*fybH&t zIJs~W8%Srut2Tw2YH})u{IO=Qf>|jH4j?(<9#50gWT|ByF_oKe)}SoZ#4=rW(AOT@ zWMx@DX`iEOKLb-?v-;Y{8l1Y30!YKSVa#`qg5?HT_eRzV!y!M#%Nj zMo$rKLixK;tA%-*BQ}u($4A9ma9u4 zX^76kLa*(;)b(hB;grB}YB{MHr25~5QPZ_X?)0cW%wxY@iYAl&Q`P?kvHybV<5=}| z(kIN}eZ}~e-B+I4SFSJCvFnQwLuj3k_(e%~_enayhHnp8P^=X6I-&Fmb)ImlZwXg{ za2*sKp`ydZJH8PepGtRbTrt{6uh0SN$pSJt{97=G| zh}ij|KR#Ao3Bg5JnbZa+q1Bz(-FUSwD&gOmr<4#Oei1vC~h$f53;z z35H>UKFT4%lzn6<0vUeM5lst)i-wRf01Gu?4FzcLqnrcZeJsV|WieB|i6tQ{GGg>* z5*jSbO~NvgCTA5Eqfp*5IOfQyVkIbYS_F%v5HW-tIk+N(1>uEYQ3kjaE)WEXsyJ*8 z3|Rbpgj#IuSgH?!=-< z=KxlNpX-o=vwEhD83$v=wcNFacTC_NyC}e0KQx#o@gP_K#a*MhtBAW!2-laqb1EM& z3<|6qg#t@4qIpyll{}3SSc)*bN8qD2e$x}~2?dD((ndT6h9p@0a5xZDB325!#-Z+x z(H2CfCyp$)clu`Nfcx>HFsB(u4^gFVCx(huR&66F*k)!!6~~t7IK2K!?l4Rcf@G;5 zju>nnwJ}EcRVlk!iyzDJfvucujIc0e6H5!g&1M8HgPEC>4*PG$J(^Sis2s)VP$SqV zIA2Z5P*q`wH#x#tiw(D_ShYuo8e^bC5tvsIOOk5%vsx~Ma=&myGHyaM(H5u8j+uj@ zzy&N3-$9+4`pKbj>TJwTd*~fMSo&}pRSqrMyekw@!Bx2|%7WvC;J{1?OaSEuQVxem zCUi6$GoT2{XIve|T}yap2JiZcuRqVb^I%aroZ-A9+|<#=>Hlrfan#&>$=ZF1cVCL! z=*Kti5*x!zn}hl0V6l0Fspk;K|CV85%cN{O7ks0idX}qy=B^98^EB`B;aw%X>lj}@ zTC8{Q4Y_t9jw%aK3A0!gW0F>EH1&;WtM9GFGs4eCdJ zU=7UPR2jd)R3ss&5H+{oIg*T$(g_2E5^{YT|tXPP5ucfJvLQ#YMzP_L9D*f5={Q@^Vy zO~j76ID~>A3Uksf6xzuIxS1t(AAtY@u_&*E*yJ&%Nl-Cb3`oFF^#^k`Y zi?$+aAc9SfIA)|KniF-R7pxxlDs~vjJB4yqs3rE1G~_%CiJL2b5lmn4V8co4Cb?=; zqm!w+0oAc2dMG-6sv_tIWuCJs942n(xp|l{go)gbg$}vdzvNqi9Wg&?t~3 zL$jgV7H+`dOQQf8K?#ceS+F4r?|wL0Bko|zE;lIT8A4O zU%DZJ0J35#WZZ4zAwsz#)GmQ9Gx*h(S{9d(hW;acC~Ofy4CY2QkefR}2)dlamwF@y z?kncW`?6#(`xyjjg|jeyA^JgIxG0)|_#c;=1KAY8hCpfIK)tfZwH{ul@arS8RWSzC z;0_W_I+{wLg|HEx-+=GJvlRt+slYz@hw~6Fl)GY-SC1dLX)=!;HX4&Hz&HbFXV5#& z;|L7pka95yHG#P;Wl_$>W5B1j`g4{oEWvcMVWqpbV44+T2&e_l4vqsfaxQIGG0hmo z*u@**`Wzu_7L-i-zbqC=F@jem5G?t!T)H%nYe5puU6*-BD(_gpJKp7;gLzkNxaim> zI-N{x!21e``SwJ5MyZ=em^0j4%Oa*kXVL_p#stG@$Kh>p>jQHths0fo1y_WsgRA>V Xw&>s)*})L?GJbcBpZmFn;Y|NO($0JQ delta 9068 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 diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.dll index 98c1020682e96095f4623614526d97f0d3d4130b..4d90585e932b6b1706e3b6a74b7fc03263176086 100644 GIT binary patch literal 90624 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 literal 86016 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

    jOW%vHD+)J_&|bFz2*R>;_w8BIfr>>J6zN$}j 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 J|KGL1{{xQCHaP$Q diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.pdb index 6213e7e82bce39a425eb1da20b69ab21dd060864..345abea559693d74ce8f34c8d68bc32309d48dc7 100644 GIT binary patch literal 35804 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%0AL8`s?wQ>JZk0~h*=}juyODcZshb<8r@`=hR*^ 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 G=KlcXgGdel diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Logging.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Logging.dll index d1fe789ed5f0f8226967157f6bb7f31035834e15..d37534a3b4d14a0e8ebbe58082ec2fe1695c6a4f 100644 GIT binary patch delta 1593 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 delta 1429 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 Yud7&KkNd6t-`sMQy8kBqe{X^R3-rqFnE(I) delta 7166 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 diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.pdb index f2a26092cdb624cf42373336a744e30c45257fad..a73f4ef6cf4dec36f835d3c95792602d11f3df4f 100644 GIT binary patch delta 3487 zcmaJ@4Oo;_7C!gRH_SH-KLaR`{EehA{K-!P!77R%A|i?+3hD*}jDa8sf{JaEa4_+U;}da`INo&bz-rO|yfx2Wg#&82E`G7f=Ey3=~D=Ng6N~ zkP~PI$aOJ1(7RWzJEW%VH0 z06uR(R%2Y)o(}TFe9gf8RLEZUWh+>sA)tE`1n5KWPaxrt_aIph*=LYE4zlkcSw!-I zL9!Y0ut72s1M#}&kd)JI^|j@KwMVOmdzDv}T9#3XxvI3h)LduDvNVvrP+f26m{C~Yv*GphgI$KF zYc9<=TK2)Rmh+=@sn6)X&Ts14^Md^ob<{|Cyrr(pQd@5JTU=6Wt}7{vDygrmt1K^$ zs;#cC!#x1G&aQPzH_7vuzqk@6Oxn8rrvzK@9opAyK26C!Q~%&wPXBk z(J$?;4pmhbFHldg6xTm$U+FYX@9tQrY>P`!b}BC_N9?DaelY!BX*+7T@vK{LTgYcq zf>JO1SbDL`82@C&vasaaOKK1?jvH=t4^MMz z-m~MG&6$&KJ?m!YKV|5Aw{P3%ldT`@tiQYHir=-9SC?DA`YQ99 zwt1^|)7`8hbxWHi^L2GbNAqjvs!AsPxjtvEX4Sxy(^ZyTJF5yQ1#Mt)8Bt+t*t%we4W>guXn7A zY<)88@E=m&xtcV~*p*g0t)jP}vv=!Xrk+pv_=(Ot>6_vs7aDUduYG^$*T|}%!~W9h z(=~@izjJYY!Psv1&WOG%`DNyaBlYL%N~Mhxe>#(Y(~B{s!``b67FMsA z6kQUVWGXH-m6Rl!;!W{MNim7$`NgKhq=aHqY*K9L{CG=jNs>9q6dfM?_~VUv_NC4p z&ZQzpqZU=xFSdv1o>5OoPtD7CrAL>`d}E{oU(hi|*WOszV&9|7?s(7hrzch{h_%PK zM)~$kNq8Mah-N7^X!b5XB{f%X*6DxchO@l?Wk% zH#mesAuwK}<`!=A5%t4&M2P6vNP`n6R%>+iWy*I32vgIx&TPW5j}7^3J?uAnH~~5z=SBazRIQ$(M!taVAL>`vQc^7 z6%133DLY*Kn6gGvcBzzI%qBD27H0dLHJ)WFEvzY3fVnC~$A(DCQI&F(*#d>e+GtOA zEdLtEbm6imHi8>&0%<_25lDOR5)JtYC!h(SL>KbrnL6PS@O3=Nz-lGEO3#zIvgQFi zwwUrg>>0TX#8fnm%VK&B=X#TvuUx~RpHL=R#Q_~Dl*?rg{s>38XU+`{4=}(R;0=tk zAuO3GyF{FHI6Ztr!Hp{2Bl;Z= z=E4L=N$0TPL1A)(kTG$gLzMbsSj1&NwMlA77ACMSb3pA!6r3 z$Z0$fqH(4g;OYuz=^$2q0t!wMl6axq@A0Jhz2f)stC$H0>EnUk+n)_(+?~(o$|2-p z)41T~e_}{ED_%1Fs3;wPg^+U+ayC}DG*o1gi+IC0-1HQ>F!8OrbFvNqX7HxT+#HO+ zi-@Z5CJOYXAYS6*IJAHT@$#TVj*mx#ON!)jG(|eoaDg#m=Lj(JL5yKG5(w$c0SyF4 zj|RiO12}qeJZ~}C`Y?rfP$r*?Sj`j@WpWuOUT4FIO@PpkAWlGWpplc{4^0|C5bSS1 z@sdr)X8+yah5k8EFviS-dOrt{wlpiZ{fjqF%pzX~>`kw&wfLGF~v~?07*sKBc+H%p#n<;ojNt1wJ}(cK_ebJ_Vka lgNz3FMEBmWg1`4G1yca>^2hB}z;Tb+dV?D`;wX5I{|Dn6(jx!> delta 2932 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

    a&ndIJaaL0OdJCgrC025 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

    +_tMHkN*-8xGz&)Um>FXG4KbyWFN@swo8 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

    @s5RZ|pGPdGts%89tvPNBK3-A+VkE2) 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%0Aqa80O3o++)($sK^D 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 literal 656384 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 WU!@sBHh9`WUhUqHO7_(jA=6~BbIRs1sI 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%0D_lqH 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%0D5~@jW)1Z<`MVBLqj-`U{F9lk^hdWOZs(w*%BH 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 literal 197728 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 I9nuK?3x3}OHUIzs diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.WebSockets.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.WebSockets.dll new file mode 100644 index 0000000000000000000000000000000000000000..233edd88b4107ef0127227111d6d5e602a2e79e2 GIT binary patch literal 15360 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 PzR0Qf|6l*h}6;9i1~%~=D8N(qVx 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�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

    S$B9yIBAighj;p= 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 zξ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 TgizP?;g3dD;EQrTPZan+O+&cr diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.pdb index 090557587b154ac8f72ee73c912f5a8f5a99a443..bbacfe84115aaa0c47dd65eed630f1c7b07ac37b 100644 GIT binary patch literal 284016 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 I_GIzD0OazLU;qFB delta 126013 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 diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/x86_64/gamecult_mesh_quic_native.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/x86_64/gamecult_mesh_quic_native.dll index 91133b5a4a241023578fb9dce5cf395e49ce5be5..6805f1757c4eda510063731332cb7de58bcc9059 100644 GIT binary patch literal 171008 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�m9J*0 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≪jM65ZH9kHCdCE(ncK6ZGOX>}A=FVssA@ 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 Date: Tue, 18 Aug 2026 23:08:59 +0200 Subject: [PATCH 099/283] Bind CultMesh application ingress to session identity --- src/GameCult.Mesh/CultMeshClient.cs | 2 +- src/GameCult.Mesh/CultMeshSessionIdentity.cs | 31 +++++++++++++++++++ .../CultMeshTransportModularityTests.cs | 6 ++-- .../GameCult.Mesh.Tests.csproj | 2 +- unity/org.gamecult.cultlib/package.json | 2 +- 5 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/GameCult.Mesh/CultMeshClient.cs b/src/GameCult.Mesh/CultMeshClient.cs index 230ce55b..5db03ca5 100644 --- a/src/GameCult.Mesh/CultMeshClient.cs +++ b/src/GameCult.Mesh/CultMeshClient.cs @@ -587,7 +587,7 @@ namespace GameCult.Mesh using var snapshot = await CultMeshSnapshotSession.ConnectAsync( _sessions, target, - CultMeshProtocols.Content, + CultMeshProtocols.Documents, new CultMeshSnapshotRequestOptions { ConnectTimeout = TimeSpan.FromSeconds(5), diff --git a/src/GameCult.Mesh/CultMeshSessionIdentity.cs b/src/GameCult.Mesh/CultMeshSessionIdentity.cs index 43a49162..3fad99f9 100644 --- a/src/GameCult.Mesh/CultMeshSessionIdentity.cs +++ b/src/GameCult.Mesh/CultMeshSessionIdentity.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.Concurrent; using System.Linq; using System.Security.Cryptography; using System.Threading; @@ -70,7 +71,9 @@ namespace GameCult.Mesh private readonly HashSet _protocolIds; private readonly HashSet _routeGenerations; private readonly Dictionary _proofSigners; + private readonly ConcurrentDictionary _acceptedPeers = new(); private readonly Func _handler; + private readonly ICultNetSchemaServerPeerLifecycle? _peerLifecycle; private bool _disposed; public CultMeshSessionIdentityServer( @@ -90,18 +93,33 @@ namespace GameCult.Mesh .ToDictionary(signer => signer.Route.Generation, StringComparer.Ordinal); _handler = HandleAsync; _server.OnCultNet(_handler); + _peerLifecycle = server as ICultNetSchemaServerPeerLifecycle; + if (_peerLifecycle != null) + _peerLifecycle.PeerDisconnected += ForgetPeer; } + ///

    + /// Resolves the runtime identity established by this peer's accepted session-open handshake. + /// Application ingress must use this transport-bound value instead of trusting payload identity fields. + /// + public bool TryGetSourceRuntimeId(ICultNetSchemaServerPeer peer, out string sourceRuntimeId) => + _acceptedPeers.TryGetValue(peer, out sourceRuntimeId!); + public void Dispose() { if (_disposed) return; _disposed = true; _server.RemoveCultNetMessageListener(_handler); + if (_peerLifecycle != null) + _peerLifecycle.PeerDisconnected -= ForgetPeer; + _acceptedPeers.Clear(); } private Task HandleAsync(CultMeshSessionOpenMessage request, ICultNetSchemaServerPeer peer) { var error = Validate(request); + if (error == null) + error = BindPeer(peer, request.SourceRuntimeId); _proofSigners.TryGetValue(request.RouteGeneration ?? string.Empty, out var signer); peer.SendCultNet(new CultMeshSessionAcceptedMessage { @@ -119,6 +137,19 @@ namespace GameCult.Mesh return Task.CompletedTask; } + private void ForgetPeer(ICultNetSchemaServerPeer peer) => _acceptedPeers.TryRemove(peer, out _); + + private string? BindPeer(ICultNetSchemaServerPeer peer, string sourceRuntimeId) + { + if (_acceptedPeers.TryGetValue(peer, out var established)) + return string.Equals(established, sourceRuntimeId, StringComparison.Ordinal) + ? null + : "session-source-runtime-rebind-forbidden"; + return _acceptedPeers.TryAdd(peer, sourceRuntimeId) + ? null + : BindPeer(peer, sourceRuntimeId); + } + private string? Validate(CultMeshSessionOpenMessage request) { if (string.IsNullOrWhiteSpace(request.MessageId)) return "session-message-id-required"; diff --git a/tests/GameCult.Mesh.Tests/CultMeshTransportModularityTests.cs b/tests/GameCult.Mesh.Tests/CultMeshTransportModularityTests.cs index 979c7230..e5d3867e 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshTransportModularityTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshTransportModularityTests.cs @@ -29,7 +29,9 @@ public sealed class CultMeshTransportModularityTests new[] { RouteGeneration }); server.OnCultNet((message, peer) => { - peer.SendCultNet(new CultNetErrorMessage { Error = "tcp:" + message.RuntimeId }); + identity.TryGetSourceRuntimeId(peer, out var sourceRuntimeId).Should().BeTrue( + "application ingress must only trust a runtime identity bound by the session-open handshake"); + peer.SendCultNet(new CultNetErrorMessage { Error = $"tcp:{message.RuntimeId}:{sourceRuntimeId}" }); return Task.CompletedTask; }); var tcpEndpoint = $"cultnet+tcp://127.0.0.1:{server.LocalEndPoint.Port}"; @@ -55,7 +57,7 @@ public sealed class CultMeshTransportModularityTests var received = await response.Task.WaitAsync(TimeSpan.FromSeconds(5)); session.State.Path!.Endpoint.Should().Be(tcpEndpoint); - received.Error.Should().Be("tcp:eve-unity"); + received.Error.Should().Be("tcp:eve-unity:cultmesh-client"); legacy.ConnectCount.Should().Be(0, "a lower transport tier is fallback, not a race against the preferred TCP tier"); } diff --git a/tests/GameCult.Mesh.Tests/GameCult.Mesh.Tests.csproj b/tests/GameCult.Mesh.Tests/GameCult.Mesh.Tests.csproj index 14e99d63..292e42df 100644 --- a/tests/GameCult.Mesh.Tests/GameCult.Mesh.Tests.csproj +++ b/tests/GameCult.Mesh.Tests/GameCult.Mesh.Tests.csproj @@ -15,7 +15,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/unity/org.gamecult.cultlib/package.json b/unity/org.gamecult.cultlib/package.json index b957b18c..cae02b50 100644 --- a/unity/org.gamecult.cultlib/package.json +++ b/unity/org.gamecult.cultlib/package.json @@ -1,7 +1,7 @@ { "name": "org.gamecult.cultlib", "displayName": "CultLib", - "version": "1.0.49", + "version": "1.0.50", "unity": "2021.3", "description": "CultCache, CultNet, and CultMesh managed runtime assemblies for Unity.", "license": "MIT", From cc89aae4a0298f820c0cf99e58d3fda507ccec90 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 23:42:15 +0200 Subject: [PATCH 100/283] Make CultCache directory commits generation-atomic --- .../DirectoryMessagePackBackingStore.cs | 110 +++++++++++++----- .../BackingStoreTests.cs | 88 +++++++++++--- unity/org.gamecult.cultlib/package.json | 2 +- 3 files changed, 153 insertions(+), 47 deletions(-) diff --git a/src/GameCult.Caching.MessagePack/DirectoryMessagePackBackingStore.cs b/src/GameCult.Caching.MessagePack/DirectoryMessagePackBackingStore.cs index 191febef..9d9584a5 100644 --- a/src/GameCult.Caching.MessagePack/DirectoryMessagePackBackingStore.cs +++ b/src/GameCult.Caching.MessagePack/DirectoryMessagePackBackingStore.cs @@ -17,7 +17,12 @@ namespace GameCult.Caching.MessagePack; /// public sealed class DirectoryMessagePackBackingStore : CacheBackingStore { - private const string IndexedFormatVersion = "cultcache.store.v2.directory-indexed"; + /// Fault-probe stage emitted before each immutable record page write. + public const string BeforeRecordPageWriteStage = "before-record-page-write"; + /// Fault-probe stage emitted after all pages exist and before manifest finality. + public const string BeforeManifestCommitStage = "before-manifest-commit"; + private const string LegacyIndexedFormatVersion = "cultcache.store.v2.directory-indexed"; + private const string IndexedFormatVersion = "cultcache.store.v3.directory-immutable-pages"; private readonly FileInfo _manifestFile; private readonly DirectoryInfo _recordDirectory; private readonly ConcurrentDictionary _dirtyKeys = new(StringComparer.Ordinal); @@ -27,6 +32,7 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore private Dictionary _legacyInlineRecords = new(StringComparer.Ordinal); private CultSchemaCatalogEntry[] _durableCatalog = Array.Empty(); private bool _needsIndexUpgrade; + private bool _manifestUsesImmutablePages; /// /// Gets or sets the predicate that selects indexed record payloads for hydration. @@ -34,6 +40,9 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore /// public Func? HydrationFilter { get; set; } + /// Optional deterministic fault/progress hook for durability tests and host diagnostics. + public Action? FlushStageProbe { get; set; } + /// /// Creates a paged MessagePack backing store. /// @@ -81,10 +90,12 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore _durableCatalog = manifest.SchemaCatalog; var reports = new List(); var loaded = new Dictionary(StringComparer.Ordinal); - var indexed = string.Equals(manifest.FormatVersion, IndexedFormatVersion, StringComparison.Ordinal); + var indexed = string.Equals(manifest.FormatVersion, IndexedFormatVersion, StringComparison.Ordinal) || + string.Equals(manifest.FormatVersion, LegacyIndexedFormatVersion, StringComparison.Ordinal); if (indexed) { - _needsIndexUpgrade = false; + _manifestUsesImmutablePages = string.Equals(manifest.FormatVersion, IndexedFormatVersion, StringComparison.Ordinal); + _needsIndexUpgrade = !_manifestUsesImmutablePages; _durableIndex = manifest.Records .Where(record => !string.IsNullOrWhiteSpace(record.Key)) .GroupBy(record => record.Key, StringComparer.Ordinal) @@ -148,12 +159,15 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore { if (selector == null) throw new ArgumentNullException(nameof(selector)); var manifest = ReadManifest(); - if (!string.Equals(manifest.FormatVersion, IndexedFormatVersion, StringComparison.Ordinal)) + if (!string.Equals(manifest.FormatVersion, IndexedFormatVersion, StringComparison.Ordinal) && + !string.Equals(manifest.FormatVersion, LegacyIndexedFormatVersion, StringComparison.Ordinal)) { PullAll(); return; } + _manifestUsesImmutablePages = string.Equals(manifest.FormatVersion, IndexedFormatVersion, StringComparison.Ordinal); + _needsIndexUpgrade = !_manifestUsesImmutablePages; _durableCatalog = manifest.SchemaCatalog; _durableIndex = manifest.Records .Where(record => !string.IsNullOrWhiteSpace(record.Key)) @@ -207,13 +221,12 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore Directory.CreateDirectory(_recordDirectory.FullName); var currentManifest = ReadManifest(); - var currentIndex = string.Equals(currentManifest.FormatVersion, IndexedFormatVersion, StringComparison.Ordinal) + var currentManifestIsIndexed = string.Equals(currentManifest.FormatVersion, IndexedFormatVersion, StringComparison.Ordinal) || + string.Equals(currentManifest.FormatVersion, LegacyIndexedFormatVersion, StringComparison.Ordinal); + var currentManifestUsesImmutablePages = string.Equals(currentManifest.FormatVersion, IndexedFormatVersion, StringComparison.Ordinal); + var currentIndex = currentManifestIsIndexed ? currentManifest.Records.ToDictionary(record => record.Key, record => record, StringComparer.Ordinal) : new Dictionary(_durableIndex, StringComparer.Ordinal); - var precommitIndex = currentIndex.Values - .Select(ToIndexRecord) - .OrderBy(record => record.Key, StringComparer.Ordinal) - .ToArray(); foreach (var key in _deletedKeys.Keys) currentIndex.Remove(key); foreach (var key in _dirtyKeys.Keys) @@ -233,18 +246,10 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore .Where(entry => usedSchemaIds.Contains(entry.SchemaId)) .OrderBy(entry => entry.SchemaName, StringComparer.Ordinal) .ToArray(); - var precommitCatalog = currentManifest.SchemaCatalog - .Concat(targetCatalog) - .GroupBy(entry => entry.SchemaId, StringComparer.Ordinal) - .Select(group => group.Last()) - .OrderBy(entry => entry.SchemaName, StringComparer.Ordinal) - .ToArray(); - - WriteManifest(precommitCatalog, precommitIndex); - var keysToWrite = (_needsIndexUpgrade ? Entries.Keys : _dirtyKeys.Keys) .OrderBy(value => value, StringComparer.Ordinal) .ToArray(); + var pageWriteIndex = 0; foreach (var key in keysToWrite) { if (!Entries.TryGetValue(key, out var stored)) @@ -257,7 +262,23 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore document, stored.Descriptor.DocumentType, Registry)); - WriteFileAtomically(RecordPath(key), CultDocumentMessagePackSerialization.SerializePersistedRecord(record)); + FlushStageProbe?.Invoke(BeforeRecordPageWriteStage, pageWriteIndex++); + WriteFileAtomically( + ImmutableRecordPath(ToIndexRecord(record)), + CultDocumentMessagePackSerialization.SerializePersistedRecord(record)); + } + + if (!currentManifestUsesImmutablePages) + { + foreach (var metadata in currentManifest.Records + .Where(record => !_deletedKeys.ContainsKey(record.Key) && !_dirtyKeys.ContainsKey(record.Key)) + .OrderBy(record => record.Key, StringComparer.Ordinal)) + { + var sourcePath = LegacyRecordPath(metadata.Key); + var targetPath = ImmutableRecordPath(ToIndexRecord(metadata)); + if (File.Exists(sourcePath) && !File.Exists(targetPath)) + WriteFileAtomically(targetPath, ReadAllBytesShared(sourcePath)); + } } foreach (var pair in _legacyInlineRecords.OrderBy(pair => pair.Key, StringComparer.Ordinal)) @@ -265,23 +286,18 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore if (_deletedKeys.ContainsKey(pair.Key) || _dirtyKeys.ContainsKey(pair.Key)) continue; WriteFileAtomically( - RecordPath(pair.Key), + ImmutableRecordPath(ToIndexRecord(pair.Value)), CultDocumentMessagePackSerialization.SerializePersistedRecord(pair.Value)); } - foreach (var key in _deletedKeys.Keys.OrderBy(value => value, StringComparer.Ordinal)) - { - var path = RecordPath(key); - if (File.Exists(path)) - { - File.Delete(path); - } - } - + FlushStageProbe?.Invoke(BeforeManifestCommitStage, pageWriteIndex); WriteManifest(targetCatalog, currentIndex.Values .OrderBy(record => record.Key, StringComparer.Ordinal) .ToArray()); + _manifestUsesImmutablePages = true; + DeleteUnreferencedRecordPages(currentIndex.Values); + _durableCatalog = targetCatalog; _durableIndex = currentIndex; _legacyInlineRecords.Clear(); @@ -367,7 +383,9 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore { var started = tracePages ? Stopwatch.GetTimestamp() : 0L; var metadata = records[index]; - var path = RecordPath(metadata.Key); + var path = _manifestUsesImmutablePages + ? ImmutableRecordPath(metadata) + : LegacyRecordPath(metadata.Key); if (!File.Exists(path)) return; var pagePayload = ReadAllBytesShared(path); @@ -607,7 +625,35 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore : ""; } - private string RecordPath(string key) => Path.Combine(_recordDirectory.FullName, $"{HashKey(key)}.msgpack"); + private string LegacyRecordPath(string key) => Path.Combine(_recordDirectory.FullName, $"{HashKey(key)}.msgpack"); + + private string ImmutableRecordPath(CultPersistedRecord metadata) => Path.Combine( + _recordDirectory.FullName, + $"{HashKey(metadata.Key + "\0" + metadata.SchemaId + "\0" + metadata.StoredAt)}.msgpack"); + + private void DeleteUnreferencedRecordPages(IEnumerable durableRecords) + { + var referenced = durableRecords + .Select(ImmutableRecordPath) + .ToHashSet(StringComparer.OrdinalIgnoreCase); + foreach (var file in _recordDirectory.EnumerateFiles("*.msgpack")) + { + if (referenced.Contains(file.FullName)) + continue; + try + { + File.Delete(file.FullName); + } + catch (IOException) + { + // An orphan is harmless: no committed manifest references it. + } + catch (UnauthorizedAccessException) + { + // Cleanup is best effort and never changes the committed generation. + } + } + } private static string HashKey(string key) { @@ -681,6 +727,6 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore } } - File.Copy(sourcePath, destinationPath, overwrite: true); + File.Replace(sourcePath, destinationPath, null); } } diff --git a/tests/GameCult.Caching.Tests/BackingStoreTests.cs b/tests/GameCult.Caching.Tests/BackingStoreTests.cs index 3910946a..66078f26 100644 --- a/tests/GameCult.Caching.Tests/BackingStoreTests.cs +++ b/tests/GameCult.Caching.Tests/BackingStoreTests.cs @@ -434,7 +434,7 @@ namespace GameCult.Caching.Tests } var manifest = CultDocumentMessagePackSerialization.DeserializeSnapshot(File.ReadAllBytes(filePath)); - Assert.That(manifest.FormatVersion, Is.EqualTo("cultcache.store.v2.directory-indexed")); + Assert.That(manifest.FormatVersion, Is.EqualTo("cultcache.store.v3.directory-immutable-pages")); Assert.That(manifest.Records, Has.Length.EqualTo(2)); Assert.That(manifest.Records.All(record => record.Payload.Length == 0), Is.True); @@ -599,7 +599,7 @@ namespace GameCult.Caching.Tests } [Test] - public async Task DirectoryMessagePackBackingStore_Precommits_Catalog_And_Remains_Dirty_When_Record_Write_Fails() + public async Task DirectoryMessagePackBackingStore_Does_Not_Expose_New_Pages_Before_Manifest_Commit() { var filePath = Path.Combine(Path.GetTempPath(), $"cultlib-tests-{Guid.NewGuid():N}.cc"); var recordsPath = DirectoryMessagePackBackingStore.DefaultRecordDirectoryPath(filePath); @@ -624,18 +624,21 @@ namespace GameCult.Caching.Tests alternateDescriptor, new AlternateNamedTestEntry { Name = "new" })); - using (new FileStream(recordPath, FileMode.Open, FileAccess.Read, FileShare.Read)) + store.FlushStageProbe = (stage, _) => { - Assert.That(() => store.PushAll(), Throws.Exception); - } + if (string.Equals(stage, DirectoryMessagePackBackingStore.BeforeManifestCommitStage, StringComparison.Ordinal)) + throw new IOException("injected crash before manifest commit"); + }; + Assert.That(() => store.PushAll(), Throws.TypeOf()); var precommit = CultDocumentMessagePackSerialization.DeserializeSnapshot(File.ReadAllBytes(filePath)); var alternateSchema = alternateDescriptor.SchemaId; Assert.That(precommit.SchemaCatalog.Select(entry => entry.SchemaId), Does.Contain(durableSchema)); - Assert.That(precommit.SchemaCatalog.Select(entry => entry.SchemaId), Does.Contain(alternateSchema)); + Assert.That(precommit.SchemaCatalog.Select(entry => entry.SchemaId), Does.Not.Contain(alternateSchema)); Assert.That(store.IsDirty, Is.True); Assert.That(CultDocumentMessagePackSerialization.DeserializePersistedRecord(File.ReadAllBytes(recordPath)).SchemaId, Is.EqualTo(durableSchema)); + store.FlushStageProbe = null; store.PushAll(); var compacted = CultDocumentMessagePackSerialization.DeserializeSnapshot(File.ReadAllBytes(filePath)); @@ -649,6 +652,67 @@ namespace GameCult.Caching.Tests } } + [TestCase(0)] + [TestCase(1)] + [TestCase(2)] + [TestCase(3)] + public async Task DirectoryMessagePackBackingStore_Fault_Before_Manifest_Leaves_Entire_Previous_Generation(int writtenPageCount) + { + var filePath = Path.Combine(Path.GetTempPath(), $"cultlib-tests-{Guid.NewGuid():N}.cc"); + var recordsPath = DirectoryMessagePackBackingStore.DefaultRecordDirectoryPath(filePath); + try + { + var store = new DirectoryMessagePackBackingStore(filePath, recordsPath); + var cache = new CultCache(); + cache.AddBackingStore(store); + var handles = new[] + { + new CultRecordHandle(new CultRecordKey("record:atomic:a")), + new CultRecordHandle(new CultRecordKey("record:atomic:b")), + new CultRecordHandle(new CultRecordKey("record:atomic:c")) + }; + foreach (var handle in handles) + await cache.UpsertAsync(new NamedTestEntry { Name = handle.Key.Value, Value = "old" }, handle); + store.PushAll(); + + foreach (var handle in handles) + await cache.UpsertAsync(new NamedTestEntry { Name = handle.Key.Value, Value = "new" }, handle); + store.FlushStageProbe = (stage, index) => + { + if ((writtenPageCount < handles.Length && + string.Equals(stage, DirectoryMessagePackBackingStore.BeforeRecordPageWriteStage, StringComparison.Ordinal) && + index == writtenPageCount) || + (writtenPageCount == handles.Length && + string.Equals(stage, DirectoryMessagePackBackingStore.BeforeManifestCommitStage, StringComparison.Ordinal))) + throw new IOException($"injected crash after {writtenPageCount} pages"); + }; + Assert.That(() => store.PushAll(), Throws.TypeOf()); + + using (var reopened = await CultCacheMessagePack.OpenAsync( + filePath, + new CultCacheOpenOptions { UseDirectoryStore = true })) + { + foreach (var handle in handles) + Assert.That(reopened.Get(handle.Key)?.Value, Is.EqualTo("old")); + } + + store.FlushStageProbe = null; + store.PushAll(); + using (var reopened = await CultCacheMessagePack.OpenAsync( + filePath, + new CultCacheOpenOptions { UseDirectoryStore = true })) + { + foreach (var handle in handles) + Assert.That(reopened.Get(handle.Key)?.Value, Is.EqualTo("new")); + } + } + finally + { + if (File.Exists(filePath)) File.Delete(filePath); + if (Directory.Exists(recordsPath)) Directory.Delete(recordsPath, recursive: true); + } + } + [Test] public async Task DirectoryMessagePackBackingStore_PullsOnlyExternalRecordDeltas() { @@ -743,7 +807,7 @@ namespace GameCult.Caching.Tests } [Test] - public async Task DirectoryMessagePackBackingStore_Remains_Dirty_When_Deletion_Fails() + public async Task DirectoryMessagePackBackingStore_Deletion_Commits_While_Locked_Old_Page_Remains_An_Orphan() { var filePath = Path.Combine(Path.GetTempPath(), $"cultlib-tests-{Guid.NewGuid():N}.cc"); var recordsPath = DirectoryMessagePackBackingStore.DefaultRecordDirectoryPath(filePath); @@ -760,18 +824,14 @@ namespace GameCult.Caching.Tests using (new FileStream(recordPath, FileMode.Open, FileAccess.Read, FileShare.Read)) { - Assert.That(() => store.PushAll(), Throws.Exception); + Assert.That(() => store.PushAll(), Throws.Nothing); + Assert.That(File.Exists(recordPath), Is.True); } - Assert.That(File.Exists(recordPath), Is.True); - Assert.That(store.IsDirty, Is.True); - - store.PushAll(); - - Assert.That(File.Exists(recordPath), Is.False); Assert.That(store.IsDirty, Is.False); var compacted = CultDocumentMessagePackSerialization.DeserializeSnapshot(File.ReadAllBytes(filePath)); Assert.That(compacted.SchemaCatalog, Is.Empty); + Assert.That(compacted.Records, Is.Empty); } finally { diff --git a/unity/org.gamecult.cultlib/package.json b/unity/org.gamecult.cultlib/package.json index cae02b50..b695c7b6 100644 --- a/unity/org.gamecult.cultlib/package.json +++ b/unity/org.gamecult.cultlib/package.json @@ -1,7 +1,7 @@ { "name": "org.gamecult.cultlib", "displayName": "CultLib", - "version": "1.0.50", + "version": "1.0.51", "unity": "2021.3", "description": "CultCache, CultNet, and CultMesh managed runtime assemblies for Unity.", "license": "MIT", From 8a203c165fe8abea5a96af4a87b0882392cbef28 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 23:44:51 +0200 Subject: [PATCH 101/283] Publish atomic CultCache Unity package --- scripts/build-unity-package.ps1 | 4 ++++ .../Plugins/GameCult.Caching.MessagePack.dll | Bin 45568 -> 44544 bytes .../Plugins/GameCult.Caching.MessagePack.pdb | Bin 23092 -> 20236 bytes .../Runtime/Plugins/GameCult.Caching.dll | Bin 90624 -> 86016 bytes .../Runtime/Plugins/GameCult.Caching.pdb | Bin 35804 -> 30204 bytes .../Runtime/Plugins/GameCult.Logging.dll | Bin 7168 -> 6656 bytes .../Runtime/Plugins/GameCult.Logging.pdb | Bin 9620 -> 9544 bytes .../Plugins/GameCult.Mesh.Quic.Native.dll | Bin 16896 -> 15872 bytes .../Plugins/GameCult.Mesh.Quic.Native.pdb | Bin 12832 -> 12312 bytes .../Runtime/Plugins/GameCult.Mesh.dll | Bin 758784 -> 695296 bytes .../Runtime/Plugins/GameCult.Mesh.pdb | Bin 251464 -> 205548 bytes .../GameCult.Networking.WebSockets.dll | Bin 15360 -> 14848 bytes .../Runtime/Plugins/GameCult.Networking.dll | Bin 549376 -> 510976 bytes .../Runtime/Plugins/GameCult.Networking.pdb | Bin 284016 -> 246920 bytes .../x86_64/gamecult_mesh_quic_native.dll | Bin 171008 -> 40448 bytes 15 files changed, 4 insertions(+) diff --git a/scripts/build-unity-package.ps1 b/scripts/build-unity-package.ps1 index c0e0518f..804f78df 100644 --- a/scripts/build-unity-package.ps1 +++ b/scripts/build-unity-package.ps1 @@ -2,6 +2,7 @@ param( [string] $Configuration = "Release", [string] $OutputDirectory = "artifacts\unity\org.gamecult.cultlib", [string] $NuGetConfig = "", + [switch] $NoRestore, [switch] $UpdateTemplate ) @@ -38,6 +39,7 @@ if (Test-Path -LiteralPath $outputRoot) { $unityPackageVersion = (Get-Content -LiteralPath (Join-Path $templateRoot "package.json") -Raw | ConvertFrom-Json).version $publishArguments = @("publish", $projectPath, "-c", $Configuration, "-o", $publishRoot, "-p:CultLibPackageVersion=$unityPackageVersion") +if ($NoRestore) { $publishArguments += "--no-restore" } if (-not [string]::IsNullOrWhiteSpace($NuGetConfig)) { $publishArguments += "-p:RestoreConfigFile=$([IO.Path]::GetFullPath($NuGetConfig))" } @@ -46,6 +48,7 @@ if ($LASTEXITCODE -ne 0) { throw "CultLib publish failed with exit code $LASTEXITCODE" } $webSocketPublishArguments = @("publish", $webSocketProjectPath, "-c", $Configuration, "-f", "netstandard2.1", "-o", $webSocketPublishRoot, "-p:CultLibPackageVersion=$unityPackageVersion") +if ($NoRestore) { $webSocketPublishArguments += "--no-restore" } if (-not [string]::IsNullOrWhiteSpace($NuGetConfig)) { $webSocketPublishArguments += "-p:RestoreConfigFile=$([IO.Path]::GetFullPath($NuGetConfig))" } @@ -54,6 +57,7 @@ if ($LASTEXITCODE -ne 0) { throw "CultLib WebSocket publish failed with exit code $LASTEXITCODE" } $quicPublishArguments = @("publish", $quicProjectPath, "-c", $Configuration, "-o", $quicPublishRoot, "-p:CultLibPackageVersion=$unityPackageVersion") +if ($NoRestore) { $quicPublishArguments += "--no-restore" } if (-not [string]::IsNullOrWhiteSpace($NuGetConfig)) { $quicPublishArguments += "-p:RestoreConfigFile=$([IO.Path]::GetFullPath($NuGetConfig))" } diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.dll index 2fdc1ff90934f068ecad258a10f1b229a7f08b48..dd41e76d91054b0af3171d5e1cbd967af00caa14 100644 GIT binary patch literal 44544 zcmeIbd0#OfoZJLI?>HLc*90!Xk@+gs{beED4)Z!;lOxn&gI=2^wQC zacfny#igxQE8x;%ZL6);+Ez=dtzt{-_O;)NBDl1*wX5y7)mnW&&vWjbB?R?--`{_~ zH<0H(+d1bs&w0*%XR`8~&kIcmVZ-l-9}4k3Jn3g4!;c1o5c?*4-zOe)9V!2wvf@a2 z>yCIb+>giqf8azE^wTZ`{T#)4CD7WeuXGtT$OecgY4&@up$Kb^rML_SCT6I&pb_% zSorBezN-j1F2oDzOo(CqD8dVL#gBz(wOF6z8BUwd+D_2Rv(nY4Vi%=AKXoSnWL#I% zZczLa7Gg_%BAI9h#kL&>qT}}-{AT?uM03?AVx0yQ$yOmuAEZ6XOtDaiMH0)v{ir|v zkZr24iUm7Womy&2zND}Mf6;+M#kc)Y6HYpZ3D~|A~;nOjmR99`n6tE zyu_{Q^)vL^DUo7QelF~N^Pl1HY3tVAeNI+# zqZA4oO?D==QAX@)vcVy?a=nGWFab+?#$FeINtGd4ygMK&ciLgv9s+f?s=^x22O+|Z z3CQ9=Ws$6;C!kdBM7xyiAz+9^ z@TX0{9~dcw-)=NO9#Mp-(el;EbP#Z7WCosgV$ zW)+Ao0uR`#Ct|o@1Ps(vG8h5FXE7K7Bi~{$0tSYAnS>EA{1$@|Fwo1T1|whuEe0cC z6j}^Mz<>{A5=Q2#MFV7z>8Z1|I!6)>pcg2rRuq{A48a$is){q=D~tqw_+>7tI)K2m z1%x^P&*G^KAQ7Hp2I}~Ei4;dvxHKS`ip(PqaesOSd7+2<)yRDCY6}uCBb*Z=uYCDak zr0ryFJ>C4lsk%Ve(vXsrwn!QDH&kEMnI@gAi7kQFI+5 z0He2Vd z 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
    WaRTL zyG^&@KIi(VZ}kzRYc|iqAp!n$&E{GCjO4V?-dXdkAsM_=t88l0w1wWb(!Yv`NM zsn*pQl5N%vhUW(w!)?}M8N8(RoZ&4F6jdgz?FO9`Dyp1sH6(RCS7sGeF0ghHq-%DX zwTI#T6nH;+nssOf@3+>`hId7%DE?b(zMxIkjkw2mx^=^R>fB__jgJ7j%OLU=TK_q% zhqusDztxDmGpxqbdw6G9tp<_TZgno~;k8?r8ARS9>y0ydc#EtL1!-HStS<%W7Nx8o z1TDd@yB!cuS)q33TcVx~&Wd+feGHl!Ju-f#Rbo&odse*Dsxj!lIkoY{)>uJW=ULVy z!@DJLS@l`g3_-f|CD!Z=$tBkDM)C%AQhbS(?B-eOZ0j;Xo2+B;%zTce7U>q*N2MXF0Ic0P*evWmxMpo@e@{TdQ#FzttPBOf4gBHfmweB>i zYtRYmJnMczy4L4gPYBZOJKuU%&=UNJz>@g+)++{WbeF_0u--PPChNlZh1Ms6w3dsk zuLWr>7g;|V$qKbBevuXIV2hTh1A^DYFSc?7QPNVESe_tliKW(U2GJ5rt+P9sPg`QC zb%Q~)#8PXGpiPliMqeLaYOU2sEV0yj*6?VFrPiy4w{p-e@k_0e#R`9$EL!3+D=tX4 zVVRW>q}#B}8YXCoN}>OjS>p}*Logb<+?r`nO*9(2!kS~y2K+SkmDUM@w3e%^Hp9C& zu%hfL>nelJ3auzxZrvqFkE3g>i_g+E<2bs;!qqaozx{tZe19-+m|rlKtyo*b^u^T* zZ+U|Q`6b5pdAvby4d5MU{Jb)5vYvo+SoLef?;fe|n(!HdT7)o5J%BJV_89inR?GJz<>D;}+WxhM%G4mef{(Ewt!fEn~ls zdvjG!OM573uOP*dQhIWw%S}_#HL=lN_I2i;rS^g)8TRH{YPV+EN4GJZwqeg64R|Q4 zWM0-V-BO*_9-FRPUS2@_1UKEp=KKL_N8YIa9EJMRy-#^9la@SP+WUKJi;{6Sa3qk0hlxljG7h$E`h3Y}FBCiJw<6O<#ro2xV{hxuxpFTQ-kjdRiZbdhF=- zUMiA1YaS#%thr3u^^C^^C}zfLY=f<^6Z)lGlGW~>h(ALmCseL}}pDU&BK0{m5^rt2LHbOlXZ1ok|f)X)v z>c6x$-6Gw(%=v--+|!%PORM6IwrFOZ|2MlGfpLW2Sw>#Sqjdpw71|zDZ_AAOOTPWT z($j6x@~pqDX4J5(H|tmy|2uSP8QnT^@q0w*7fXFr!BEe`Ivgo8ZKfT5J*|C7hdWEs zR@!3eS$Aid|An#~ZAtr{9*I45PPdL0$V{hwL(kIb@k>3KY0cH4)>$GmKxU}9Z;LpZ^aj$Tk+-HR(uzekALH=X}FO! zO^rsp3g5X@*No$ZW2PhE@fLj1}sHBUzP zclDCpzjdveV$vI0wt&*unuT_MS=rB8XO~nqScfT|>Tg0F^1%If%OvX<(R`AW@(Jig zYQCC0be^?H^lY^+8F02m%@uf3UY;|4iJ?mmq*7lnJfV+5P$eyp(*2V0I zv#MXYy-Gcalh$?iJuQv41)Jo-{%2RU*w=~7N|X1Rk#p_aBz>RMWR28ht;jql^mX=Y z-Yuf%PWx4%%vXcFub_wF22gD0eF-hKjyDdsiT;(MXO$W~Czt zBJYU7&jxn2n)?3U9qnw+y&2)yp{v|oo!9E`boX*DsQ;_G&hAsW2H`g&wO>8%Zje$A zLqD!}-$&Y2TM%w>w@G@tgaH|M*%B5?SSjKD4(0nJ{dYCX**AVdXpZx81ND-MrbhdE@9T8UX@ntES)*0P)WUKFwHF=Lk@oH*e6 z$ouG>haMQewBJ5HW|0|so^Eees4v$**q=VE|LLfcig8BIJ{dQaCp9#jsE4h?rL3> zl`Z9Nm%N1zHB^H8l^qaze}`{OH`okcvO_i7vl<=RZMZ|bRoa}ZTb=vsCL^SWFS9PF zZ^@qQ&>E8+T5__(_HMDP`j}m42kPImvN7v^Wls@3Gepl88HuaZ2Sd)yUZwUKd{OoV z7+F_lFLRnJ|B!u{Q`U4__A$QCI6}HbyCVn(u!@?)v=$lw^*F-NdH7_FOzFUn|*fK5Hww$#&M_`b{xtJLq}D|1+r+j1)H z)nlIxT<5UWD;=&Kw;_Bh=Q?O`)j(J~PhIQqe&Dsv0WFgea-P2rTzrLwaErUf;p%W7 z!e;}wNx9cK)Vakvyrn94tx%qm@Flylb#m^jlHMTUK)XKf**7{h#FWW_c=3?Mz%DPMsngLl0CL0$4>lhIkpqo(L}Nx zC3fuCQbHP2X*?R+6YDE8qa=b*X0R!tgtnp0Eh(W$FNTK;TtW%l%e#pj6NKvkN5t%l|8?+&f05#uf6u#`+T{-kLQ$M4)EEb zm(}~Pihfn}D}i$>*VVidsMxT%=5@&jgKWLirVUrOPMeRwf}J*>SW5aGt7y#@t~g%v zocnv-Wa5=t_G*sX$$g+rnVrTXle`cIiir6r=AW4c`e-u{{G4XwF8nI2vUm%AX#n( zg<0W)z*oyp0_|M+Xzjy@JL>$gI1egr7ID8@JE(jgR62t}>OfXF802g?D4DG22ZJ0b zgTd3+IVLMSZQ?5z)O9JZu3*!;+PcSsw_M*+cMA30ZyrXhX6F=I;MVHL-1UuH>mGB% z+hdStnI8|*n;Hyq_WZj0hc~>w@RLZVr|v1F^X|GYBAr{SyOhFX8atK2pWN^v@EPlq z4qNgu_k8PSfd91lqC-n^($JzV)7;m9-g&kBdE`=Vo)2=q zXbAGIjTgmv5u6`}z9afOpkX0JzYIFI@Kv?OPlKF~ej4O_^m_2g)elBq2PY5YQz)+o zX_*_OGr=;-RF%=9zN%JjC{t(|Q)nooJ#Q$ZJ#Q>yIUCDp@!C;BcqxImN4iWy8J{(3 zDB~>9QZ^8IJ@PU_$3bVWSzO;z_Ue|e23yLwkJ{iqUiUBVY3GVH*Vp4~wTRmlp!^l? zKfu@R3Q)c)K>4l!=#=== z!V3z$pwJ7*rFjM4i-ukcs{FzLIIlHF#gB@!OxP@bbC4zP5GN+=6u(paesSW$g!l>Z zGr*^p=agnnp?Tp6$()eP9|bv@CL}YV&`IGFl6gWhXT_NkP75zc{(?eHnQ9>nlu7H# zSlXyK%Y@D1H;dmPPE6QY#41+9giEIC0T&(Fuj-MCXMk#F-F1DSSeB8vLi1pA~&h zI3=7GUJ$+_8B?M13-LuW)FmohCTtdV2xG!dVZ4Ir$3-WEIbmLSqT(8~z=Y^YNluD> zLU=}aR(MW0C7c#s5SoxmB@76o!ezo{VTZ6&*e^^7bHWqC3E>mMGs1JiDd7d7sbpRO zVN}>G>=4E(PvDukSmko_)0R$g`h^MM3E>mMGs1JiDd7cSV1ZgyxJ=kA>=4F;ox-jK zY}J0zanW(n31Lo{7oHGK2q%S42+s)53eO3rgwsmxf@rf)wq>D8CF~IP3**9^FfW`C zP72Qor-i0UeI$$umkC!@u@)VoW5Vt#j)i{FabXIa7h7_o^TPLvGa-6Xct&_uI3=7G znrh`Mj0%?tJE~c)4$(1Tzc~G(1U;iT}a@EOF~zT!EhIW3M;!(4(j%gu_` zWujX^Z(k7;-CaX(DlU3JGAUq9YaaZkm*>Tw6rL65tmu~|`3msL)~;Gg#%q~NUN|W{ zCH`5_&xoF`#gx?gvglYH<-6(_cR-jD=Ea{Bo)+gU@U`Z%;!M}EY}2BH5yov1c0|~B zT@lu?U-W?JQ^M&8^D^~BM;H|@t7rL_iEgQ9YO91D;>19IX>q^kxaa|e=IWVOPW-(1 z?-hSS{0Z?Vg=dA&DD*kyH7$+Kz#)NTUUN|W{)xh$c6+PAPK0G%)E!r%4pDAm0 z7BSRWq;!Naablw5!n|-&cm}b$o6m}#7Mjc6XYdN*%anq!<1*GOCOR(63nztVFH?C$ zPYa#P758%Tmx+!EV*c=lb7v_bN z!n49@p>u^|31h77#rpx}!;PMR$oGZ(43PwC07AO`NkP zLEqSVRx;B#FpIk=mJtaIN{=rZ%yh`A&#)MmQy$R;X!Kt(z$s z6}?P!hv=B-oalTrQ$7g}QWIxVp=X89h(9I%v^b_kDYqzP(aS`4h>nTw7aea=nOj)S zoH%)fPKcfqeMX^Y#5pU@w9vGE*8HqF-pX8Zt;{hmdP4MMD^orr`mE?F(bJN78JsIy zofV85TtPazf+;K$rvv*67=5DS!U4(TMNbM(0bvhCPbu!ppkHe?S2LZCtEqLdtC@a3 zXv}D$bE0#S$%``~dQ$XR;k3|M$+*jeF=1SoU%A}uYn>MDtdfi{w~F~r2+s(oR(;m& zY?-)*B{?IEUaPVRyRK#V`$eA=Jt6vxa7q|mEqP(TFejW4o>|RSIwN{YXx5Np)-YDf z8jjhPHOo!+iVku5g*oAb@QiRuXx1`TRM;Wx7v_W$!ZX4tp;<@y;5xQIRCJ5z4$)nr z``58N{o)LWlM^Q=&Pj15M4u5(3C((yWIf|XMR$nq5Zy1#2`7Z7*0T&}L_Z_?Wnpv! zQS+v>6(BMYZLUf0)Uzih42+s(gfh4>*(Poq4Zc<#)9m0NLPBw#l%@(#&{}ys`!U^FS;gry9RXV~B;Tg-> zrgVf8!ZX6?^-4{628fzo|333OEzuju?-%BT6T&HBv|XX?PoO*#!YN^NJ30NrGutUM zB{VxoM}-~2oN!8LZe*;ea6))SI3+Y43Kix$n9hXoj4&D_r$g8uqhwBKZc;2^hp=Cm z6HeX4Sf*2@5_SluIvMLTX0daf^Q2Sd?sh-tKI3i->3fE_mmH&oB7o!oOJf+`=C&{O=2wR^3pwud1)=>8cm1 z2C65jzgYcT^*>c#9eyG_6<%DEsQEz6-`6a!9jN_Q?aQ@4tWDNU)_tok5Lp^o6}cz! zc;r7umezOI57$3e|3B(qufMIKr=cGA#2CEWubgj>#T{=U+>yd}6*b^4+sko}?G+|$ zmf?Lt&ET%beJWeAhuLoG@rKt1vkP~@bmKj<2O-J(TJA7c;SH{h<}SQN_P21q%iVZ? z>>k5(#=Om}!5!7>O%8XvoWL&d@0v|`w`rUCBjoTA z+&MFWRR1@W?#H#C#yvy%CB&bvB>rp#@!4yLZ(ILaV5aRq1J~d1H1G$Kd`ft*@xOxe z<96a*;w)TBdfj@)eXyNq)Bls}NWZ7%R_sw2_?83ja*y`AcC? zX|5M$ulgIvoY?#w;FpC@ZJY-Et#$theAf-H0{M2;Tz#)WEL&4ss@&Ff;M7Gn0l(I^75Kf?G2q%A zEW?epyFq_-8R-QZ4}fmna5u1Ja{~C}_Ces>HnjYe8}3Eu+|>R=snuWiAVN>oy&JeK zLcCLW;MzX`UD`f3s;Azob_;H2N&cyoE%RVI>tZpX(7A0pwh44b-GZJ+}2NnJ}R_jLutWz`*lwNJ2rm__-EHsOS_h`7B_GFOK|>h zDytwQ-?iIptpRX2nSxs;Bbxg%?rbah1&+tAki16wag+}+#Oq2&LvwaKGH zxK@dK&hgG+-lJWCJ2q)~0-!5#cPQSu4|H)Qh!&{|=)w+Ff(`>+*rJ7?Yk@B8Q8nlY zkYACh0o?#}VUy}WUk-Hf7BAYkD}XL+)FRMV0bSUs%Rx5*UD&ECKraQlCW>$eR_iLz z%MtFtay5Z&K{)Q12D-3gctAckoT! zCI)ozZlrCXJAwRe@eQDN0{QKp?Vxu9UEHO3Bj|3RYi>b22iMMGpl?Gw+!7l~+9y}n;hop~#9yCLshw#re z!)65Z2>!VSZ`=W9@Xy74f@8oj%quS5Ha-q~8?L;$=26Trcv~UR#oMso3H+eRgYy{B zHGhhE$1xuQy5`T!yMZ6Uo44^4h?%t^HJb`GygmA z=eUCFn*V7&0el_reR0jdnok3NjjuMicn82|ffdf@fD4@e1PnW00MaUjsHdUk5IAz5$FnF9C5E9&owy zEnu_rZD5P@U0|#8J>Uvw8o1iI09@mIAGp@}N8mc=72pQvhro@_kAPd8*MM7{p8&Tx z{{n1xeg@p`{2aK$`2}!~^Go1f=U2enoL>X)!n@C*S9rfQ^vWp%zSXG!{x;r%?&7)B zg}}H|4Lt1B028>Q1$yP+LOnjavj}*^xg2=ZxdM31xe9oX(*!*3ECmkYUI*6b2XAFJSs=8_Sp)h$plj}T)`5Ni=;GPN4WQo!bn(36 zCeRN8UGolSGw9y|y5^nE7SK7MYx2%E(C-4e=7e(t=#xMfPwH(4{kuTd{AcGz;IEt* z@YhZ!u-4rPjJUg<-FVY$D@N*H2Cl}aeiro2=KliSZJr0+ZT<@ME#^GvTg+dBzSX=4 z`d0Hz(0KbsU>)$Mfepa_JFp3eyNZDS8rT9f!EHb{cmqcM;@~>^b-@k5XmC4ld2lnZ zC5SiHnH9ksfh!^T7SkSV1@6F0-g0^@;q1-=q^HSl^M9K1YuTd)`R=ZptG5d8Dt zx!|{h*OqN8+g3JEHdvM|`>V1alvR|kDsL~(mcPCH+466fUnu{1c}2x#71vg@RqUwP zS@9XH`H#f z-C282?O5$QYERZaT>EtGv$c(N>+AN^y}j;{x^s0KBiBc6irf-85IG#lM*cYRvB)+!n* zKdu3`zRw0^VA7tA4fRwiClk2Zxug7QXKzK^IZ?6Ce54{}K2>qt`BcTtPAGK3 zd28r>&Y$CGD&OZ^Q@IPgce$a^N1b%#r=7>}`$Xjn&YA^>!2gD`Z^0292l3lyKE2>I z$Ye~_!e2Qb#547wP!_+p;aBZeRyDcZRT&G&`!tWr5l*Rv-na zK%$N&vwdhg_D{+-`lf`F1IffldY~ljg8UXyv4Mf^;eq4>wwRVTy9G8} zSLjPoUiDP!f_~X9El7%3oA7$9z}~o}P@&F|q0x9Yb$Bp&Aek8%9HSzF8XL6rlHl5e zpTZ`c&nekfzhoOlDa~~9VB#2B>)^4tr}8#%cI37~?V`Ft^6p?W(lSvmsk!exC)r<aStSqK+$ANAmb^a7q%-sGGs@m$LL9qYw+z( z4ky#7@~ly)vK?ia(#7I?QPGt1Xa{2W*2t4XDQC)c4=A!ldudCsWL$e}jB8M;)+NWa zA7v|}TztfOVw<;7Y<`8ZVe_auV$4)$FuLb6`QVqTBu;0~jGVvGp=0)der;RdPsXes zZo@1%AAb|Z@_c+0U3?VY+I{4+d4n&xd8y>l3jK-xdsmmWxB%ACpEdG8op3mdg_WcWzx=on;r;+f;I z`{OA;WZ&UTGJT&fhN4)@b8~!nK$)_1mIZr*LNGoK2a@rDeZzy}2S?+>#gcZy^bheo zmf#Ekq8qHiWZ}$@HiN4+W4e2j*<&LEQoLl^M#i*~wlu3Vn97cOO2+U)T|5cfCYYuW zc5v+QJ;)c-&GF2!gGo}X%ij2K{AkgW0=L^Q)E?MBobQRhZ5)U89b5YP?oY=@Ne=b( zVXlr34vudyy|8PWHiAi;-Us4R7RZx@1p+nG0(n6&DWK-JK%NL}4XF8TjW5!6F%boL zwg$p;Y>k%yYzU|~Wox_`icn%fJT@!{s5fUp{3u%)<>D5^6T=V$<&PB3AC@zZ-PmXc z*hT~8ACPMtAG|XeKW>N9Msr7ea4gv~HVQT0Xu5Z&N5)3sj)C@+ccZyAIWD37@l={J zT`4JYJUxyxq?#B@r{RsyU>CG$2DhM0tVU6paMnAD@s}-{jZNmjCaYV}7f>_x#S4PI zfSO-lJQ3&%sQLB96M-KMYMz#}0n`^vUl&P50ThAKK;%s+jh8R9!%y^*^NSy4E2CUo zJ3KMy0;pNqvB~NI0xs^T!(g|yX=Gp5R%m@tGh5#aLhFN?zx6#4v_7c$TOR>$=-9I? zn`dVY1{)h$gPK3<%_{$f>&(HMV;eW)a4gQleA4rCw-`DNy*<0OGBeY@cVu8}Fu4OK z`^>>{_=ZDkyZ2!;=ROXczCO$WaP{YSvj#Jk>B|6UZVRriokL*Z;{%wLkY+-;!J8f* zjt`|0eh$T%A+uJ_DuVoZ6**#Eok(i5n6BhtGV9U12D!rJn#=4@Cpl;A8c82W4q|1z zFMaUXSax9K{$Vft4Hi}Aq8ftXJ~WiFfxn2LM6sI|lpuwDS-jEHL{Rs95{s&wNutdA($Ea$qumpnBnQmic>1`yKs}NqOAC>~k;HM(%)L8vFd4^! z>mnNLug4^dQG`~3WPAYb^iAX0WX5Bm0DhyH!mfqMaQRQ z+3N6skw?}$oWX9)zG0d2K(%$j5(n91xea8K<4)(? zu>I+g`%+j#%^zy3IDeS$Y|I~e)A;;+8K`~3n8-&*GV_$jn?tf(7TR5v%o|9n(sL_i z`^4K{o*N7YHVf~S%cHr0-5I-=Iyc0h!h1%JCx_<-+f47Ep&FSd7}N4lJbTgL&iL@i zaH=qO-IAF%4Q!Tm4<8wso4L2;HOJIZS1uN2N8Q}C3Oi+?9@EcF?kBu z{+_p-7Y{|M{>J&7n6bfBJTo^zZ3kZ@tY}PZpLGw+lYn*G<_Vyg<$m~_l1Lfn;olig z4`Y2bPl)ZAc>;E((<8XNFeeLJE3Xyj3HQh3JVD;Yg`E#%)A56YBiVUGa497Y&ow!) zHw@*|~*=p3PJf_qa(u{jOHA^vfu zfVrg)O=q`;tVdQj8%}03S!`6r(*vewq%fUXotmKES<1c%O#{ zQ;4OVMXqJIMB4d4!aIk$YX{OKIN`uwz7NK|xG~8+NKBjBIPp8A#8Xk0C|4<~WP_6X zCY;P@fa?S4JDbU-G?+tooCz!_Bgnpp{C$Ar9m}#IEc}T z1DgfibH~UabP429^Z;i75mwQ3%H>nZDa8spRKlNUl~qV>mUpCvLI(T~OG9ytTT87$v7ex~y9ew62y)?2#!s zU&eO9P2&YgTo}XpW+ZJnDBw)SF#7;qe>gRa{?Te&m*4h6>Bu_B3r!e0{y7Fv@nn`~ zpzDEH>mA3{Yh2MvC0JumyGl8|!$Wq%SK*1lIP_|uAgh&7;jG|0+8qw@Ir8m5-giWd z3_~eBS-bzO6SlW)Q=L+YN=|JP7X(Y)PcvHLi~5SMnibtpV>Lzb z(abvslm1-+67=T`g}3k6)Ymsqa^rxfRi&AaVhd89s>!k$saIO$nmdnSZ8O6VXoBO8 zOz9O#BkM7PW5*&>n!%Q1JAcJXft7!0a!F4SO zf{8DzREz8a)ypMm;SA+EJa+UbEq0OTFHDOZzra1IY^fmUdfJ3iLF~+xj_qPlH)f4E zY{vYdR^@l4k=p$u>Ep#{%)_owiad;j&M~OdP?2Tpkxbv5Lh}t5`F_c%pWb3*ZXnkf zT&=(#i4R^>3ND2%tx0ZfBEHj(M2dkbec?*HH#Yrl_l-eO9398|bh6_IupgT#@^$gT z8~kkWk|3)JDigLr;}3``3HKWSnGK93idWDJO4vCvI-X7)JysILQv0T*SO{M&w48ik zmbmrQ{mb*1l(~<_>xRYneo0tjIGn`*&kGPAdmbrX{40jW3yB`&rkv@K^_HENQE-O6l@natgIIGhHk?yS(dt=g zZ<#MMHf2icMRNrKg7_N>t#?2xsmyc5)PBCg(o81!TH#g%vwGSR*Nk10|DeVHhNjc=rg{ zi?YRQK+=SwgIB!EQRAdA&-n^qJ*-Pfm4puzZkwcLdxfB9#5+f@K1z<#`kUKEaD8W# zOK033ci1hCG+Ee!+v;C{(I7eip9iYI>LB8Tli z%OU1gnR;P9zP%Ff4<*|XiclC{B|J;Y!Ite!rV65Oe11C`o z72en(QmTW7(}~7~t}J?Dyq{F${y67+j8C1x8o}UUo*J>|g>{9MO^?Wd)yYv_$M+R$ zPipvHgGFyzI&QVY8z{^PZtINgMo)kySPm`Ly&kKuF7(b>3(mOS>2Q%O-l}AVw2r!% zrrHak)H4*Mn|aQo&Q{3x2r&5JN6ooY#_Jn(GSX__k?rd{%sXwFFsC3KSzwRkQp6*v zjvm=JXaz^IaQSESHcrw0vu_^)cQ@=L?<4|=-9X??sVpQh@Oi={EQQXp@%>C_Fov=#_40dYaWZwR<-i@~pY2rTN z?|nd9eMKxTe?Dl7i1F2Jf7? zkKVk|JwZSYS@b_GD+m<2WGKVC!fkwDLn-=vKN+X+x1`I3-Yp4JK*>4VX}0zEcgbPW zXW!DQ!RX7EBr{OhTDMBU-E_>$J0FNAvUg%vLtE$yvVE>_s&&b!=QEaYQgjz>RM>f> z=(&AesW|R&$2LMDqcnXN7prc~k=Tj1rkpOZF83ArXhPXl8`ExJT4|r2P_gZ=VtbbWycYBCkT-p}sKiSH zi~-9<)6BCz-EoNHfVbYU8+n-$kCziKhah;Y`OJI2l?^4Bxi{?XDf|vgXgj9#i3Szg zUnmsrZnwgIG3?pSp;5a7VyjlVLy@t5F0cNV-r;Zh4$nBHZqHnOss(h%fXc45M#e5M zGIU<0DX5P1R*Prag&6nGad(Ao=`Y;=$;C$owibI6!$<822atb#MVeDMx!=3$f?1)h zuP=Knl`(r$iS$TjkZ`|;% znON@~&+71|O?IcL$r0`m;o8m^HW!tbH(W|Aw2>ZhW-c0B^<~j;6dtzGf?%J#M5wm>fcPkt9g4bF zl)6tOdx_47RWa*2*rDsw{zD(<_{T|SDq>9HX0e@!ZO@mJHtRp zX5S#RZ;&^G%^wqYreO(TE4q{W$d=@lL<2Kvp9#@f-%&luWa;A!XQ6C+#V=PHZz*jF#dRVH0r{cneG_&v_UYJ-N~%CwT~3F4TAAy zZ*j4TVUpf8M(=d)2rBqCDB4;if)u-8BYLp;zVFBpo))LPu5{`MY6N@4a$7f3ZY7Nc z@3}*X0VtIW=srB4qE3e9rZcz&%s-_kVB1}#E_npW$Z06%I42xwgNOL+TaW4)*)wuK zmml}VajV)eN-=z2Dm^mHjds)Hj|w$d;lytK&eVGC+OUI)QY@(YtiWQk&%WS`>i{#a z0Gk1C;`B{*iOKSBl`L)e{})cBw@2_BWiZ>Fe1kN7N0M6d24bF}_zmmEHva!2liBsV zM7pJQEER3vv9Yf&VQ;FOue~{jy-=y|JdX@Y`8u)tkTnS*hd^PaDiu38j5+Ao2o>AA z;j+NNBru1U@x@tE-a%k34GD5e?=4Ws42EwNY&^!no_;#(-7TvGtO@naO0lTk&Je9* zi90yU^5W{a6@Y=YgCEly9^}&|?QO{ivS#0~4xT;gA&bSvow&D+-0xjdKLARXTS%aM z5Fo`Z3m((>?TtTBxVEYJ6xXHgbGO!Iy=esD$CAT0jT=2RfTJG3!Ler~mQKgVl`XdQ z3N#G48jMHwlJ(VjCS!D8QURWqM7j?J$=ozf@;H88l@2DM6W9h{+nFB61GKnVV)U5J z%-=s}-}f{G)2~3}Ub~m@e~Y9g;XEQNP1VjqgQbnrub3+92wGlsT{S zYkKjr4nv;3sPgVDmVw;E$nhvzVgx^yiyD!}85ROKV=l~*{c;~tur>61^lsFCH9}18 z{clB4qIgkBrJjt3BzF%pV3 zyNTH;=+4w_$Yo~XFWpG&Rt^a^JgZJszhsA2urXJn8CEf0yj;0dMP@Yn<&>P+gz65w zcE`a>t4re*RBO?Er8eFE5MZ}(z{XK)wh`&0Xcyb|Jfp&JSW}_*;Pok`!xZ^;vP^7Q zU$KhAlWAuZlj=vc8-!#^YDDS7$`NVgK1cnJ;=L@TRd{pVY?EeJ+vJNyK8DIrBadn< z&+YcPowEkTEiC~nkV28!mDGKXnF0KG#Hd+#AC7~_A&Czdoy$vBuZ8_dGv)q`gm*b5zGbQdoXmONya(Ih2aZoFR6=E0Gc70=XD z)>j@cg+(?6-^zO2WtPh>KY+B4C~pp&1Srawg-29R+80wvyQdo0+0xirN^TW7Y#Z!; zLKePKNo$tY+En_M+B7i^?G=0Q0leYIZ*ir#$cAR{7M^08nXHxM_^msa15KI}uz19%4=9##Q$1a&prI1s1>RQW*- z)8f#1!`v~K+Ih^Ht3K!}b?(^A^lyA~hLHx(p9lPOWF)q*d;==2?PF^75tNw5bf%%3 z5%21mt>x)Enz1(2VpUANCjLH(b8Oc?Ru7jWxM*dqDV; zgwKxR1$*n!)wGURgWdr8YP{mm@AjF=l~%@|`sNPt+1B2-T%7c+>%b|Ds^h0o+I2H4 zMO*9}0GNaBx#gxYVGbM)RvCN;r&yn2qrKg1R1M!uO4i)aO!z~UHKS=@ew_30q#l&= z(q&?+r==L|T7M=rcV9YY=}@2Du5Vbs>UNaT8cKXKd+()l@|A9l6lMf&))?m2`D*Ok zdFj-O=7uwuZ*Zu#zK+e)C#`gGSZcO7m6_&>#t;vNmMHT3=O3k3&o8CWzCSwKpDU{1 zV8M~0Iu(`H&Vn@vC-8q!dF1X8N(Fx?AdF!%h7`FPtju z@$j}PD)mOZz3n>A4uLh83F$7_rZIQjX3|IE_)`CF=VSgvIT$P{ovXq zj#)H&TxjNRrXOHOuRqRb+B4{D(?PUY400U(hc!w#eX|wef8q7x)&sFCbfsF)R9O=G z+e0WPQfZwpl~S2v%%TmV*W*-k#p##M1TcQr%q}xMFnTI9`o%KZg^=mIm|g9bytRa- z+Axo$y?t)$(PFZsoWiMDb4TeLmdY4&&58$p>)Cz%9rMMMsh#$#Gmq{o^s2><+XSh_7W3V;Dmzd2%v%dE-+?l-GVS5z6_t%{B=@(G+!?RM zBkeX1)v_0vlp8ckEqf&QQRIz|LvA*&UiY$E2W>UGsa#afX=Ky3hoUaTYwMj5shkXoRUqq^q1jUC%~rc|C*3lnojZ9&MMdOLBzN96j8&kfNC%qD6FhGP&-;B?COopLg8ooNa7GCp z4pHHA4~M)+4||bt^a}NmU#N#{>dNXNFRNH5Q6!E+K_St!I2pr9T}3dGdnS^59+iGShIeGWEmbsWUa>&3sEK0efI8!Z_-;3ZR7(h2v}X(dksbtT z0w|9NZ1HD9SIVj&GJ0&5{ZTtV8$tnT3ZKPMDWWD`UK&x2jTI&s4mZNavOF#3~S8gQ#82)>;Id4_te5eki6}+M`MSm$1eEC4NiNP?~Q5AD3JVRGC&SHxz&{U{! zED{Sf+SnGsMtj7(P*fVVmI6H*#`M$JD2179DwAQ%P0Boe7`+P)#G1;Q%F1X4%3%F5 zuGDB$f_w~?c>xD3Ntrx0Mh_e1GcZzJUf3fDs}V2K>j$yLKLguo&%+HmqO@NC&xUCL zOGZZOOKxK%_hah9S;w1>dQ|P6%PU~UHD%5`EHr5APuc&NY6444E#@fvt6YE*D*`?V zg0g=O(~WJ~u0|UDE-(GAu+GBK(uu;G^?VDVnWD0SO%Q@QvQ>Btlt=ai%IijLD}m49 z`Vs~Um6%5UC726|=l&;-)u`89=+WHcXeyUO73_M0_Vbxl1p(Oc#hO!cFCZo)?Lh|K z*6eZc?Of`mSZ@~61bAn%f1=qKSJ=^nMA#_Bw3avv7ud`xg?i*BkZfZ#2>-+DZx*SZ zbx}my|F1)cY6$JO^>`f_L&@Amj|sn`(N?!nWl$|Ws!_GH{3T|=0@o*P16MI^et*fwBV_n-^8V+ino0n$}g;nd|@pyzdYr(!+6JOIsr z(IXF|H}{glSBkT8VFf0q+_#|Dksj&`Y1Y;9m`3io5Y8TRKyc{fUSe_U@{P!QA&!+e z$%3vlh>SBuR%jK*xEBl`uDsrmfrKazJtz;cKW#$N)ZBN$R@qh~f5faCRT)>;a*F(M zA+GZE(pkcZmf6!<*NxKUP;(iUNPQCNva_@dn@5jk_+{w-qz(_DU5IQjP!RV&#hziW{5GpAX2zeC7Ts!v*hT2Oue~0 z3XNr_&Jw#~o~*3kRrC6zDzj4$ZJ${ds)-xMP{NGq+bNu)h-`r{TvCq$lL{cyg~omW zD}wGsYJ9$#DQZ7OSoBVVsd(GzTIt*DOV z+afCw_5C<)inN3xEfLtNy3r=JNtiPvQ)V!_1#5?JVLmb(rz^ct7-`ff^jBex;Z{vZ zXsSrQbsjGWZ2GI5yc%u$OE4U1j5Jo!s3Vq6{PbIF`Yq)K3h`1HdK-@9n}V40!*$Ve z2Tu5R>+;ie`R|A7@~>1x18@o8=E0u0@TVX|mjDMuaKZ~{n42Q`Wld$(m@JBMVOfy+ zkI-pNWr!QX3?(zC5d#gY2-KTKSUp%cI`$6VvJn69&Cumqcv#^(VN=~qqP7k zXA@9AokG29sgf91a&g#Ziz>>HXfM<__Z0u<_lEF;^M#E7@@%HP%Am3!2`vtVLSfGL z#kkt>pt8eDruUBh2WzxEz3b(o32N6Hq7w)c+gk-iUle)Q8l_&37Ac&lEulcr&-|gt zAT*JtVo-A~IurB&$Ne!<$Cw_CziLTukex_x3P(-VJaQhaQL7eBEcqeutrya-7ST!iLkS@?yx&GYx#++_Y4LLXkaoplYJ!B%oq(&Y_nQ$^D8mQX@z>JD$@a z?Y1*U(E~!o*SjuVt=c6{t)^R>nj*_QdZc4 zNByjX{)I=&{q#>7yvqBDNrOVqzrFs~FRc0Q?V<1OX+ z<&7k{Em&T@G=&{0ByzJ%F{aWUIfIJmMv@5rZag9<&pd%p2azx`NYEuDec*1$-dv46lj^1BPA;(^(1u_3A-NTyRCYaMDFPTJ5F1pSjt!7zugnB4|KRto(YfQe6?hIE`Uj3Jlp+ z^cB1^)}Q{LSGs~r!}#h{6d7(0Yk88q&5S_1!a~qqoFu_|Va!GHH~Z~~3ET29PcvYT zfBHzFfgioN0-A6r`)^YZWYt=Xqh<7Fji7jt^tUjvE{pK#eeL*xiCh ze6yX_B@7$gjqm@JKP(3qxl zl?jHD4STbT{($9TW8<)Zo)`5s_Z+r|Y%I{28Ih>$ncqG=6>PR4xIp#@#YRFmS7GM_ zlH3=n8?8Ze;N%5zxB*pX1B>UQ3#A&I!ysl&C9^$ssYfU{5%c7cz|Fh_4=1!=P}SR1iwqF9v|OBW7%MW$ba z+J)e+ih#b?jiOK09$j2n!Dyikw5VeLcr%&b5pB|Btwn7&sp+braadY<P^eb_sF*h)TB zBKeS7_Ss0(JHn>onvIQy%IRte8p(~sglKcnw57-xSN3q|0XAYZvJhRc4ZiYojp&`A zd+G`_YV`%qct`_w(Z*|}O~IUCCsw7-zJb*{DGkwF2{x+s6b`tgzyp19dw5i`PZeaJ z3am8Y;7U$%09+$qX+rq9WR;24C~N@((;B!Tov#Opwgt2idP6Ir&g`2?k7z3MC{9Y` z6(=R0VUTnnA};l>G>yR!jIC1O^n>(iydmWoZ-pR2PX%MrO4}o>G(>Nvq;Ez@Lb6SH z%ZxC!{34wrAooy#dKe)XS4aXw%Eqf3^#}|))YS6rbz2H(v?w!s<=tj%Ro-LkIx`y* z*BDui4>Li{RysW?d@96mgY$2RgY`s@d)b|M0_nDq;li6~@boyITXG=BB?rDXj*oq> zy=`X?o&?itT337T6WV^?#<@DJv{xIe`$5ithCmqy zxsB>2Wls_6MKX-E0$ku>av9uRve(3xrBLRbxMV;mV#L-I4gi z`|r%7V*cNUNJss%naB5+$l)W-og?Y4!NI+JpWP7N9+gfe^+rA~&aYdM%1Kfe{Iv)Vljqg0) zhVyRVF3|k@Qt-8ZfW;viK%rm+imr1G9}-lfm`W%<`4 zlhA`u-Z#p}A9#nZeP&hy=E>lnb8(I`*}MIDH~-v}epfQbRlr1)ZBk!hWSs2GY>&*UR?;Gei%ev1?kM(9*{kG#7 zTL}KLM_sI~O3Qqc+J8UNv>L#tzl*iMbXqLeNwlhCW~MQ_^-J6STGTROwwi4yXB;JN z1FlE!Z3FKJej9O?(C-L%+aR$S+yS!*p?n&2Gs3ng4L<9!4QB?=cChbbXes+p7VmNA htyu|8gzx{{RagN38$= literal 90624 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 diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.pdb index 345abea559693d74ce8f34c8d68bc32309d48dc7..978cd4cbe7f222da256c5032c96cc7734ade4931 100644 GIT binary patch delta 15933 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 M-Vy!+wB)P*14?DmWdHyG literal 35804 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 delta 1520 zcmZXUU2GIp6vzMf&h%rqb=_^tw%A14uBGd?ZoBEU?x2F9ZTP4{L)%c&CZs!U!9b8K z7zI+cSOOKR1uh9uXd*3=pfQ+i=!+UKCZ;|ZT76LC2PP0+w29Hg@IV^>Go5Z0oZWlw z`JInBXV2{15o08NdaUy1y~B6mUcaNNqChkNMKt6u85hr7-7Y>>Le%73jsjh(Qr4** zqQh8pgUci2Qp$*-eTDfab$iwKUutQIjb!oXA(T)s_l9Cx3BfXg++jllYf;8pOJ@JS1ldik; zHc8?Km)du0erR~$;v}6q>iOW7%jY1TAwLJP$)RH?!3qv|pF>L}@-gg^UBZKLm)cpu ziwkONZkzd0R=gjdWW@*YX;yp@(k|H@6=Np-ZEl`Ot-*V+XYvh%z7ALMlh%rP{G+`D zAKU3gHD9q|{;?u>OGZ(EcM)asdCGFkP=;`WvKDzFibj-DK8GsG7PL{e;}B&hPEz*b zb4tsRd+?oT!2x(uvW36IBio!ZmTi)jW3g}qJ~`;vM;-g9V;`lxNlrVKX~!~6OP~A- zRT!nT+r8uHcN|?4wmsxZ+uIC%#CcB;gPO}P)3%{Jy^#O2?(Z4vyH&Q>vti=Kl|7fv zP5q^Qe5_g5@`O}AUrOc)HR0>?cm;A=2NSRDQvdq;O~Z`x7%~LvW6_4FVb)qP(?|>$ zmK8Uej3(1;i1!aAjJVmHFk)tGV5n&@W|_=Wryu{N6ezgZ^*6-J9sCnxoa;W1uKVhk zzclAK&!*#Q(jW2nb&DX}v+ TCGt2w9xX`s2R{&MB-ryG05%cn diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Logging.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Logging.pdb index fa1b1cb445516cd68826f515bb6b522c4d3329cf..5aaeb6b14f96eadbd27ea9be13628aac9360ab68 100644 GIT binary patch delta 1278 zcmbQ@eZp&kN__wW1A}rvN)nJ_I0M8l7=ipc28Jz63=AwFx!{tb%)Insko*pqSZFZA z9w55_B<~*T=>nv6m>C#klz@Dvoctsp|AY4Avm7PQJoXDm-j6g46A@Hy+YJ(oOnTlk!|8nX9Mw zGBI2O;zvOI5{N$l@prHsNFD~58U86UGq5T#Gw=YhFwj8^3~WG;FoG>)U=RfI*^&6N zKt2Z=pA*Kf2TFnza09i#4B!Lud64)Z8+eiUyg)u58lNAHFM!4uW#EFF4+MIGq-+dz_?!H|6#P%f8o8<0$7VrFDv z&`7G3U&Lpk zyIx_F+81WO#(mM85wrH6eOqF3rSXh8D+9yYDYvuk7znhzXRd5dTpxAohTpBFuT?}Y z>2kKRc$wXen-bUabfe9J=84C6>z3?uo4@A7ZM}PP3CydlJ&o_%|1l1lH(#biR{p7F zOp^XTm&uD8oW9=vSZ}bleVVdHys%ADOD;nQvqHyrHSdMDKcsg11+#oq(A=EpoKVQn zTC0+E8@5vMN%N7bqFnaTRP{>gg?=+b58rZRd3;^>Z24ju%YJ3roCYI_8KGR#YpcyJ zz_Eh82%3~Gam-*3a`ka_40hd|&*>wbE(%PWdIG%c4C+h_0t})I0jvy+Oqw83ZE>Ke z21GOnB&sd|6t$M)t=AAhH^kO$Hl20vq9Bhs$6FhN4qsfX;na(Q*L~ag( z7{owGEdmZqNz(%7t8u;7_noar&6Cx~ZtwbfQTg`2pp2qi3F1J6#~^2fN@_eyy1ZAi zfufSfj+`5aE~Vp%tTVA8>UdF(AY?Fc^AUtGjEh!-`L#dR=RgA+-&q_ zOtWl)6115~Mo;Dz#(W{yn9Y1_m_KamMtyjs@5acOd3NU3({+2FSKhr{YC7K7y*|4= z?AS|*Q-9%2KX{|dr!2eg%6LUnjGRw2^|3<(?e`>qx;ymRa*CLt{+75?amPj**1ClS zJFoh?WX?Ii@vP;*-Z_T!(nEd4?5*_R9hGNXGAk-al{>XQ|MZ-wDG2;!*kbsh`Q7Em ztMWHKI>KK<)C{+yGyY+{A0M<-`8sS^yQ%KdpnY>dL8r?8YM+YPONyPJ|ENOOxRnF3 zYG!{3zGA0H-ZgcTPh5JkOzB^~Jbzyol9AgRa)9OkzQb;x%CshSog`T^B|Z7nw{z3w z#_wj&9G;xGKRDFta_zTJ_p1|zqPU(|`=4>q^yJv*-40Pr;}NARnKt0 zxpd8rK1=FAuPN~0!$FfNCxgu$UckTQk>iWcV_Ttuo@M2;6uvk$s-K8D(IQM{W|3TKpz;F4Zg{xg- z4mzn=Yw~QHg3o<=KPNT1EG}WFb+*3t$>Yd@7c;HDuktYSW=?0V8|JEP9AoE;Q%RYr zyr9KNXPP*KFr(l?o=BgjGwRt{Qn^y0)hl$m0EM5zPpOmzXcD!G0HwcHAy>-viGB%k zol>Jz_;`u(^AATFIn)KNo?b|j^pwmDV;l8_P0+@`$dINe&X(l{I4uyi<6t-lC<=)Q z;v)f4vk)epuPjHfR??QoYb%_##7?l(u?tvh2*pRRq&-kJ9}G+gPXHZdd=BheI5E&t zLeW_cCn6_ff5IN==B+GTor0@J=-rH$v7yIKLWzvr_uPCJ(Iv5j-tWv;xtHv1E|I>? JWv_D>{xAIXb;tk! diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.dll index a7c40f955087f0026f13a9fdb40fc33d16844230..2e4576da8dffebd0e8db19c1c84be958510744d0 100644 GIT binary patch delta 7178 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

    3=q8ocktdq+5#j3?=(jVY?N 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 E7fy)n}VQh0)niH2~})PcMb!B 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

    a&ndIJaaL0OdJCgrC025 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

    +_tMHkN*-8xGz&)Um>FXG4KbyWFN@swo8 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

    @s5RZ|pGPdGts%89tvPNBK3-A+VkE2) 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%0Aqa80O3o++)($sK^D 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 diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.pdb index e9bcee25a9d8998d79a4cc9485cb5246f16f03fa..5971d0e3dbcd70ee2dcf381803a9558c4a2f92ac 100644 GIT binary patch literal 205548 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Μ_WIy;Vr6}_F^l! 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 literal 251464 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%0D_lqH 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%0D5~@jW)1Z<`MVBLqj-`U{F9lk^hdWOZs(w*%BH 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 diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.WebSockets.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.WebSockets.dll index 233edd88b4107ef0127227111d6d5e602a2e79e2..e5c84a7fd44384e8ecdad34ebec833ab37d6723a 100644 GIT binary patch delta 6920 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 N8S_E@LF`Fd{|)IWHI@JX delta 7540 zcmaJ`4|G)3ng8y6Z{C}ElRxuj@{fd&$zLX!BqU_O1QFz)h(ZAa3Sz|&0tAJ@8R$_a z;~R?D71SflTBVDwG)q^k>sDC>w%SV7o@xu$+U;2sQlY2*?QV6qr|Nba_V?X411RV0 z9Nu@o|M$D!{qA?)3z^NCJ0AR-x+j;89HrdvU8)QFMF-JDFuX4F`Ng}RyuPS^G0{S1 z+ya4TcWtO3LsS6z%0)y=vbC}`yIhR7Ug!iXjAvqYr-+JJ_IWX0Ov#Rjx-k#K1OKkZ zBgsSFcB1Y&B9ZOvyv(VSky0XyT2|!{S$=;vgpFm|zO*3HTc+g&+9kC7id|}_@u#89rBEo1RQ;>32LCUeYNI4UcR#?Ki3Mqd9&XHWK<~|HnC8MIii(q$fux(J=DkDKm zM{a^FqfIN178v;qA;E<{s6WK&s6)%yszs2TsNZ~GP^LJ?qcWu1dTUkUW9YancilK0 zma^F@Q@o>blspU!Q>J)V<2X821Ohi3Ay3fbrh`U`5sk9wf=UyeY7wY3N#CNzryN4< z@yc}iCPrvsWmuFdgB!#pi^7_9e_4TvT*uV(GR0N*OU^}P5;#FEJ{bcRs+LjxReAC< zNE-{|IAa$1G$-D}2#xr?t)>~7!o(@0+KsS*uKNa|(A)rHC`+u=#%j0-Q6!%3dhld< zn(15`E@v0H?8}lgmnj)-1wmu96vkDy5%s&%mhpXlaAgyD7OaoHrt7!K|$yeDf zqn`4R9@WZtB_WUPX`N4~VE%nFJ%U=al2-zROe6dO_AoJsblIlbhxiN#R8@w&L9e?H zBZaov>V?8g$mkT-eASj()Sqxq(fE+h_HCI9y3G&dYDT^sfn_7D+Nj-x^~k7c#AmT1 z8p)Hhnau6<92ZxGaTVh&0wpi$L5dt9bQXB0PI_e2A^SBD`Qw74YbR0i=Z{Mm>BDis zviZ2+*z#$?+2+$y!^043;IyC$a9WtSa9TXH8NSg!c+0+8Ic{M%S{zHxS52E4fm$?b z_~P@xwZ2ppWQ6pxkSAJW>$c}RA;UJx??*G`PW|2ZHBfJ|J>|=IpKSes!HFkxRc=vx zw_8J@4nb(h$in#=vK(%Ad%4c9g@>&zxDJpfq>E3)SnMhiY|9k)V#}zQETb|yo@AJ= zgqsxi>&SfQs2d}VbC34B0CXC0q3Y(qo@WED(m>II=xyDXp=7(?XV5Fr|KW$*zf7^Y zx;SKtZ-DsM;HWH)E@%}7wa6ljT&s&Qw#}Ahjh4C~q&JQ3rlV&__o|RVotr?EPOrku zGR4vYImE+gDHc;DOY^4i){FVAG%i40$`lXj62?nhR*H%E5~!fLs{>$`_)mX;(B%bD z`KaK-j_v5#g=OZJ6aE-$PrQZ1=2kNUUdrN20o94Po)I%>I*}WIwOu94^HJGm8k=;{ zicG8sb&M75Q8TkNWXd5PM@z$~fb&ZVnvrF2M~HHk(&c@KF9$0Z@Qpy%FLQTpJvyz= zv3*|(`%?~kmi&Liwt`kZ>WcGGTVILVIv@3El@t}VbxG6?R~G!`!+t<1bJ%V{lwA~f zdkS((9pVHU>7ol*BHGdatlYzxBW13?p~l8WZ6%wQm5FP_#wEF zRnS4h)5{B^vaHaTzghx`mmzfx8=!(~5l2_gU%!m2mz0uGP1UYH(Wd2Y-K{d&4~uj) zbX=E&`7b-$oW;6 zNv2rnmqR>^mKNokqp}PNC$a(F(v9purg%uB%(yu!R*DI{DXG^S&*`%&R*q6CNn|68 zBWUDk#xPNq?jrbIrEQ$MF895#DfcusZYPv|3 zn{MunfJWwRL85Z+5;f?L=%Y<48kISoln;*A_U0^dDMbk)V%Cgr!tAIQ8mWYN&8VX; zcsFylnX8Nvt_+nRmC;;9%$V`T%Qv26xDuB={_#Xcv;+3scA z2ccuo6mx+v=uhxq(Ftp}VbObl1|5})OpAVNFn)$A{Ek6KurmhzT1|X|3Szb7P-d%% zzeViyIUk4kb$3cHPw+ojlSM<49j#D0?`y2{u#(PID?X_BOBH{=kC#!bLj19krWkkV z$4V)x1Tz3FdctIrg0h8faHT^m-PjgCf*87?NnZn;tPOrqev9~l^LBR!x zuZdcHt#1Z!m)eT#G9@8%0`wX7eFg|!sqRvgh6>KW@CNa|Zvnr}kpT4<%cZ=efkG>! z1$dnfDXId#7f=P2DXLXbHMldIXrZrFYoe6V0r+Q^;BV6&Xy!dU41BVGAE3j=*je9xC>0Y=cEu&C?qnBh3N_hV3Vu!pl+}~k zqA;iao{F<5TS3duQ%4|AoTpv{_02rxcv-k7PkMQezN@Hj(*xpV$o?fq4T}?+PTpF= zkEb}Ld1**d@A>{DhJ;0r<*2mwp=QxjE+wX0{|%}EEtcp#aZJ1<3+Rp>!(28hL zy({dsNH3;Oa@5nvOMvF1-xF=4ABX}yK#%9BpBkn3?&(11WZBy|KOyQ>l)L&6-K3~9 zVx^yDN19pljHuDZgZfuRDNTn;=#`w1RZHmI=mpghI;$wxX(|07Cu7Z0(%Ua+a)T47 z3fwnzLU5DY$^BLR^8D#&XUq?v8z;3uK%#yeHoFnMRnk&GfwEu$8wudCf5+Q^kG~CgW#I8FHr56-a3ap4B{c&E@C|y_!O)|K84Au* zaIu2R73@=RP{G>)OX*HPgLVT}(J{bUdQEXo66fV4agu8V>ugi}0>Bs@L_J-O{2teq z1J3jJ1Dd9@2?vK&_bS*2v-@dK88?8l4|~Ru9;DOSFg3tn6MZNa%V+3Q@JoSrTF=v7 zrSl9;)n3HP-}L?jciLezsiWe!b{vo=J1R``-|@A=-h2w$a=`dcN4fY5^@%Mo7!(^# zA^ODkG((J$r@UjtQTn3{?-K{<5s?)=f{XefEkvFU65~#vVht*|m)2{?#5_6V|0yO|=YLBq z7vGmBv0jdPx!h-Jatz$D@v!j8*|gQFmGiOUiE;^zkwc<{q?`%-FsA>M=4i|0e(2mR zzktqaDG>0G5Gpr)^4CT}e(KP4zajdh(7z!+r9BXj5$pVS$r4)O-46JQHB;;roBWT; zy+UaJC_e=LeR;16;$HEP?-_X$Ju7F5dj+5Dqk^YDD%kd@cm)|0nVZ`fY(y1r=5Cf3g8Ng1NJL;D`h=h%JVErI#gxM!Xc?L<|tOL zg8h^Pr(f~=DMcR{1B$<0@wY4fcJOWUZoE1Tm^+koSV@PKbQscZ^MK;NOm(!%&XNN35^NOb;U)dM~;=H!OTGs%>0wg-rO8(YBc@Ok)?L#--Mkx ziGT7u5zIViXI=|tcF62=&F$e}gk47}OtTv17aTF=#j~enoKtTWd8<98_7)Mmv(&yF zFc_B7&TO;O45frO4@s}r8wewkL8X@Yz3|w}4VUzV1sjG)8mg{p~Cce*$)SPJ76#Z6<)Rq3Dz!K&0p=wO$xQ_^ypBtW(4mvbD`-595XnrBlE{0 z8q3HICC|PSZ4iTdS}Vn1wyJe9;B~DNq$#r7TW|7Nf;_4uvLChH(G%-w?;ye-?~|J20Cua#hdJyGBGFq`5$s(p5>kP#FN{u zd1KZiJ^LQp1yA|k0mj3-Ys=)ri?g3~G-vBNmt~74W_+FCt4?s};fX$}#i-}daO}8P z3Iw-BKRQGYddezXPBBpZ)QxeHdU_z~0NqDxAddm-LEmAFZ8~AG2ATuF`a$>MiDh4% d+-0)ocIr4}cT3?zBJjmeM>;|NQS9z8{|}?gqL%;w diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.dll index eab06cce16caed0e27d9c033e7fd219a3aeb8c36..ac97186460e3b8907647c411d48de34a23d4150d 100644 GIT binary patch literal 510976 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 z%0AQ~fG<86EhmQEyG<~tdVIv0Ju+LHDXfLXlJ9w}7&!wgg{8?B!1J$CQwV^2KNK;h zrV4iMr65mD=d-Xsg}uc>!&Lq3g{>}5Y>jcM)GSSfg*W;2-2h48%sTA3QgLEaUw*0q z&)keC4zaLCSOQt!5rNbe^b8o^-2oK+X!E_1=b)y8@WZMgp0ms|S0TNgXW-m}NH`9J z7kGO-L({wy@pE*8wSe#RsJOX?;||d6C%SPXP>|c}aYNg@SI*pBK!s6fW

    E~#Dd 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

    H#}pzvE<5{d}X_z1tWL`Y`0m{6vlT? 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 literal 549376 zcmb@P2Y_8g+4s+$+jj5nCb_$t-Bc3FhC}Xd=nx3KcaWlhN>h}6;9i1~%~=D8N(qVx zD5yXXPyrFd0*ZiQLq#lL0iv(n&)#0ktIPNMKQnXh*<=Iwz28FaJoBHKXP)WL)N|F3m%*n-QV@~jX%|K$k#VM`n1!V3(sw&uWy`u z_QKbke9k%P`3p}ubzx)qISWreXW>4FAGPr8^tGoh>Fup<=2;)HZxkKUQHZ|vnR^}$ zvHd98WMOy5R#9|pXB6?j{#Kj?u@GXF0W*w_o!oMl{Py<L?>MuMKkRGw&|_T zOEe7M!$rgQ-7O~GQO3=kQ4hwfGdrWBbMT9j3tOU_*G}vQ5h0m*2C>M(xo}L9Ywm6 zVDYU)m&2DLtPM0s#ksRr&m=j+gHH5nUo?E)aU|{ zzK-GZj+a0E1b?Evzge**s;4g=K93BWd!>GYKhe%#vJ9?^H;I#7Fr&q%cp@HJeV0j9 zcyC5+FD~9KI26{im)3Eo<`ow&a^)CBi&bVFQ8#I(|ENXdyAn~g9+ej_Y4%c0S5@S_ z<%h`dLtQJHAMj$-Pc{)rEsD=yL(WylcY{TDb9a7w`U;)N9uR$njgmbvqe@EMttJGi z_Z7{reN%xt;<=zdtd~7`zO3S!?++662TJex3bNQsX?3Z&PCFb&gx$K{FAuZ*}PwYZUW=JJra94ME*LUNGI&Xnp{?JxEflS4$5>QSwvd@DvPNGu`AH)Tw`S99HXcCFf4mJ2PfkGVy!qbFX}4iGODAT9)Yj)qj;h}8p2npR@#uS`<$;? z_$t@R8}fC(^EDe^m0Bg|%QBM~U#1v8;e5@(S7)s==gTq{Uq{N4<$PHt zmt(HD4R`_ta-Zktd7UgeCjy0In-0Dd&Ab`O4it1jaGXoMqj`$ zwOoGh-*BCtJE=~?TeV~CqC!-xq_2=jlWY6f#pW_aZ6CX2gD!7g&jqs58{U4R}(zqs~wX zH{eNG5Osz+*!E-@L3DJh)l9h&&F$}+R3W;k5Y$Lj2&$YaL^lJUgMMN;PV@`LUiu@#^(Iy{5MZ_(mtuYcR4bKkH&5C z)_96va$zu+BLle{Vfc1AGRtygc(Cyc7hos^XrAIT;~&mp)?|mdArBR9uu&>H*^Esq z9~HEnj}2M9+pNZXLQIvH5`1>Z<5ro>Y3zvqIgMj{Jibg^9!Pa$IHtZ7B5H~Cdhr+o zb+KCRt`rhf$LjeEOmlnUl|nl!2~ECUEmyYvA;C5n?$nnU4n3h3k4>8#AI(7V2_?Sj zRPn7F&f?opIF!zf;I(+axS;mZd>z7NhTyV5E}Ni$8Ue5{07h&Rk5R70^x_gKjM7_* zXhG7aYmJl~ZQhE*aN`Qd^ajXiI3Am;0Ppn{T6%GCtM0yNV&>_jt6cAn$AmRsj}+ixQOy2 zuczZwEsyk!4hgzwSQlaYnU-NO7O4O%@izQ%(w=h>ubI2!3 zb3^&$QaUiv(OntoZrn&OZwyJ_CDKoQXbCpmYrpp z?k&q?iR-1I{&KxAC`C~LO|3jU z`*kZn^5|>It(;qY231JaH*G2><1y7=M~Aw$JE^Ar*P7?!qgpOx%jL6Olr#@9sFWwl z7vR!-13%Dj6n!B-=?Z=pEnZBGPpGqXH~%R`;!Dxinq#<&?@G+cd?k$dX1D~t&XPs;SoE~bN%2emmlXeGk1qa86_?_F3&ceEt^E4<;O8Om7#7>GFx`=^VMhC8nQ_cS5PD6@7AQ#VONs zmZfI{j_1g+v;oJnm0D!|Pg0w8TWW#9t^Ujv-Ji=Rl)L4vLobX|ZB7IeL!cL(SYLGKZCLx2tybfcj63R?W% zQ9R^wXM<_a-b$Zw(wZE?M{~p{xrM~B@|dhq^6OD$aWt2DZ~^YL6P1(du61wi zh9rpgL~l%isNSPKQB^2dXH9Q~Srn};E#gO@nhbtu&YK2n`T^&MC3 zgVq^ETShZ>k4jXKjyO6hn(-Rs;ZOB+6qEWu-~^84!bFFws&h&1W&p&=5bWeeUARqg zE#BEFR0XF@Ek4Z2<^^+(|GkkL`4s64ja9j*ot{ ztp$kRn2(oQ=emj!$XyD>u%v;s*40HjM z5R|18*JW-kB6{u+I^WLZ4&>;K6KTL&@EX}Z1iOb|o#|^yLGvSU9O&!y+Hh}j5B8h_ z7u9KaE+J15sLP~YPZM@ScoI;pI)0jI$YlaJ-jw; z>|9173=P|Uj2mLi&Zx)5`h2{!N8;Yv^s)2s=Eh<?S-87=jFU)DmjZ|_etb0N#u_~x%T46*jVeC z4D^fQVzP-*bI~Esfayk-e&0`TaO|4pI_8K0*amQ$I1f7QAzI7IfS2s^NLF6AFnr{$ zOghNHh!u`mDGKyEcIy9HiT$^!We}y^%M_UG#8~Q}F(9%67|AwpIB`>0lg(shcA-#9{ zDa`J*-Q^KF5fWaFo~4V9l!llU=W5NiSLhQ9(N=^dXKT&3&?+>~IH$<6Wt=`hsF8t~ z>BU=dXg-KFp~lo1U#-IrVG*R(e47u;ddB3imu)cY4#Z1VP=^byS7X#J4)xYIjgwXo+R@#31iry(zc8)fb4%G>86Jpi zYC8ycJmu~y!^pOA@=C15mxAGVP(t(a|VW=R>m{j}2f`5}j!mcv)K zb674foWt80t8%uznH7zr<%~u}Je|(6qglF~WvN-J*-n@$2}vqb0?L$xG9{r*v6m_K zGR0Y@n93ACnZ~bwtE$Q{+Fa#Wh=@fDr%;PcDcN0J{ai zh{NK>AP82Vbg_@C|SoIRnoRm{F2qm(@OgFLWAkYOX0K2nXaBD33~<5zJ=u?2$9}x*&F{;JPB0V_(c7B%AJt!< ziQ|gwWw;hcE6o+u?HO@g)Ut9pJ4#`S=>^ckqrHm?=@0Nc(AXW(s3wVcdXKYz4iaXy%J{%9g~>7@0H z=7!+(mYP*bPUgZN!`6I`7}B-;M9Mh1$dp_%#Zab#n{Gv3MkB8MQKbSiOH#U!h?o!; zlCR*RLrP`W7^NGiPBHA%nm-~cRHE#^Fi~%QteE4(c$HoJZD!d|aCMP0>i-l=^Jn}d z8xv8kov()X67jx^23;)|v$xZl15-D?vW(z|SB(z7s~A(k7y3HVpTm@K-V}*yB+a(Y z`HY>ln0vSSh+imDG^=_KW8E*Y*tv-rQ76`4$qmh^-ovyD?MET)WQW>PF``do25kM6 zr7@?A+Gw8_M-{+Lu=^+^*$Tx{dL=4UPn`{|VkxCmhnoQ3nqaCxL!Bhg=%WmaXRuj2iue}j{$tvU*42X0vZ z>+6hbowZVe@>)*+jt>)Q9>mTkKmYvmYkN6W)QOOD<@9Xx5z;p7wj4(b#d?485AgnK zU$rrtOiTWWEoF0_?a|Kke`I;UEQRzW@&B~9oPwqKFF8MCNbKB`8(R3o!u_EOHy?Uq zbo)jfz2unHWrmDsTSRSs*V=aSZ2ND~;&Tvu$gY>r&ImYBvgYPB6blJ(-@nS74;c2sIS{A&G%WF*FhokIjU>p^_~b51|QtUtN31_3q|0WEd`_9T=`kBc?3%KC4{4 zeT7`z>c$}&uB5#(eREcx&m_<3?^=0Ix2Pr<)LN@EjC#=yc|SI+6;k@LdO}A~_Y)J% z;b-A@$MyWCR5|BM`p|6rEM3n}LFZ5dE2~#?ruJ7%Da_zeI?227w-fxD-Q<(T!X8X2 zaxX?G=JJ?qWc4(R=5$9>F{;fPKe2O8NM(Jz55P*1bCztq4an0>VXNelkh=Q#knGx? zbAD#Y&usG}mxR>Sn{3m&#bc#e?QUnuI1g0n1xB_JKZv_PMj=}$qnK?hV`jFAjFs|1 zyCZe9J6RGGFxT!JPsXNNlQTsvo{OO2xw(u&#<@@N+(O38Y_W`$@&Qkzfu}5Oo}JN0 zkdyY@t`An$Z55)Wk7)h&GxPxkjZ1H%;dUjDQ*V5C?J7r4ryVn33^rBZ(BRmt6Kjg- zEJ9XhaVk}e2E6Cw0b>*3N?&PWChFkaTB&oOIVy3HkB%r=0?lT6RCDJ}V%t+@PEc!p z)Aemz;vxGSt%m$~OhzH&z=b-sM`f&(6B$7eGD4PQYeMMkKs9=reAq3Q4+XjjOGN&p zKp(rT*V5r8=$?$#Qt}GvH2~@ED5Kpmqlr|vo=!K?&~Lm)zH|9hPTAb6_I8Q8PMD%C z`D7jEl(%xa9Ud0NowGQ$YuVJ*+>tgs+{oy!(rv6+7t$SM`kbqz+Y==C?;Pk#zN8!t zj3?*U?#i$4xcsuQ;2X-CIQyoILiVJLnb{LER?3O|B3sBWS^OZNe&m(p*B-h2ipM~T z<2xXUwUZqoCdy0sZSEv&m0S{HuaEC6yV{cTvrK+=F+Xxi;OZND*rVBVy?9&)Bsu8v zwJuw0a-NPhQOI_~q!S=aoz_pexW;VFIH&W{jYWGK-}NedV>LPL>ZmQ}Yo<}Pt|Axy z2*U59c=xb)<7`h%qTdUHB|90`Nw-JE_i4OAG0}k?FWuhwvaZIYGZj>6x&Yq$iuXRa zt8wp(3Ge-6Fp0z<3fb0);*M4n<*Bf_sStIK&K3UTg8+q90nZauC@L*+4dN6UTWzF|nKgE%* z!bm}@Y4wg-SN0HsLz!JyQuG~bhG%tJ6I(MpyH;E?JcoaC3u_W~fNX-IZcJygXZUoX zV;-uMS)B{}7W*r0Pf}VPCQ0LA@;EsRZ$YNwn)Gn26r&|E?6DNqq(=aES3*BCJ!&VH zDbPL@%b3RZ;g`M)pFN$@t1F!UI})2FP|KAFblCE3B6{oj{OaiP)2QPYOf-K$b03bg zKhlDS3)vqqw7*%fdpZYL*^JC#eyy(RG;(vax0sFx3mPzGUy261>y)VL^NJ~rtlU#z zUM+uCLh0F*W%t_hB7ClmDvPCyYJXwVL!vV6q+>Tf78G6owpe!c7zLN7%#FLElL>L4 zyEK>>UV_o$5UO?s!3{09Vha1{n%6PBM2EPrik+HBQPVE( z04MIF!O~ZdobLJd0Z-RhU3BxzOH{?wwL69QCaJl=s>d zmyZ6m=RAj!uI3YNoI9T2*=G=duJmCUh3p|2#q6^(W@ew3u~I%5?ifuN?qo?`ML=qO z(B}>l&#&fqenjEo>|Pm#>>e4#?4vSfW_Qb2DIf5pfx=UkHqUB=ny))`^o{BEjOQHM z;LtYJN_p#cdPb76sSy1fh*VwgFZY#_S0h!eJkbGp0_2IVidmIOqC(?mv=Yaon2y5s z%5SN2`XHsyIJt)*Xf=FR^l_>`r^&QB-?CF@PJ}NFNpPj5u@tP|o=!nI+!U42R-Jq< z#$vi9@%qlSGSFr1vY1%gi#wgRQgK~xA!sXPGx=PJ=;|WIR(~d}JZlMU{R$+ea#~lk zla&9+sYI?3rAwp>F)?~8-cq_XEO}+Ac_W!RY*QpIjpe3D?*v!4%M|Wi-f}q>?u^;O zL3*7B)$G%Ed&{L*+?@OdAx;(RU3$Yy5UY@)IJ1e_xR8RVml~I0c$KbsJItn%@+OOx z9#N9Hyl`s}w|IF>xLduYE!=HF((RNT?LE7)-Ib#FY8%c%HwG}bRDRaWt}uPRx&+Kx zGB{OANKj5kEvDNN_sF>}Va}GmAE8=fjNA?J6IdoGxzcgz_Tg?OT>4THOh50^JnY)k zP8X|KtOhtBy*e*~nw=q2ir^}U4`*t=t0f*$`*}%KL_(Ru-qIf{(dUqh`2)HGvu&rv zEEq^nqTP+ZnQkK2iQcSE^kf`{SII@kzUtMYQ=6Wo`*4a!P&d2^)YI8gG@PzuT1{^` z=S^CP8_(x>UCFIcmHJBUVvw?go`e!3ZAE>|`RF=vsshQ)#R}2!q~|E5XNW0VY&ARK z5=(V-UTn49S^8tEBF<8+_prse(NMKMXI8a7*tnL~5I3IVH+d}~n@`bYtq?oEq-y%) zZN$UCRBJwL{cxP!LY~n1u8~p9ZpEO3I);u5?f(&F-OpfSE8dLftmB=*+}}Kp$*-+_ zbXVrD{xBKI&6S@JyWKG*EvSRD8hbyl0w(?bb@)LepdQykJq~pY6<6ALwcOIhgZ^C#`u8;Q zc=ogs`8uskrcSFk?OR%Lf#T9wBPFrYR=g$Gp2YbI<>%)uKMUC%E+aqaGE#aAh5wi` zvWNgW+{s>k?;@wt45qIK^i7dE<@llB)tX=M{66IPeRvYTFTO;6CA-@=S9!wrhDPX- z0f^HeVjILKI^5zi%GP#d?Hy!oY-7H2w(;5raAWt!CXd~*+Zw8B;ous=K=yz#NAf>+13R>29c7GrUp04quDMd>t-mJ{qB))tX=Od32{` zPI*jbQ5B=y&4t-gdb%aJL;-wR8FmI%9a_>so1RMNiD4|#{Nq#bq~AdQ8JSgdCv;{M z($~VuEKaXs0$myES$Y+It+iH@{nY_Ff92tcidO5}=Xubyi$gv2Q&_1nMrRQ}%bz=- zp`I3zD?JPq{|en9#DO2&97LV#o1lTvqE|fQIa^HvRm-YrB=CFTTN4(NrqB=DQ@2B zVdO|3;io{F<)xiwQ~i|c;|k+ruWZ-5meALa`dk=J>1S zO4)La?3p%tg3yxP;$vc8&Q6q_Eza*FS+gOoCwb&qAx$B42j=HFA?FJr+YI@EkmW+i zJ42oka)A&s(2%u4-XMewG~|au-YA4zWO2wO9aFsNfz&y&!6Aw_Jt&VT-jwNU+mGT+ z56L5nH)T54_M>=HCSz?x@#+==_hQ&=SDv`BH`d*th}cyYf(ts188$mKuai3tZFdIi zwtFeMlX4HbZ6Y;!m%EJq_%4 zYGAFw$*l*YT#alTHPnqe{>G>ATkJW7$UEIj6wC(8Zh+Z%T~wn@*QC+LmYesCx*A(f z*I{Hzr|dk~7&BG)sRtj+#xC#wLm{D~y*VW8c2@c-ZB5d<-$=auo%LgVcDxg-C$Cn{ zxcvK%*$$*EGK+6i#jPUmZtUZ>lwa@5_~uLFFnVEXhqSS-GVB zOc<}dR{aGtBVXFT1#h2cvn9wa;SDCW+R!a^Xxz&dPeT zqwY4Q+T&%x_J>>ko|Zqf@pb%Zy>c1+NG%f$G5oGPqLPw=wHsAA*1sE_(Xc!9o-Tuq z^lpV*U5rlSck9v}QD1+w(XQxhVQr5*t2O_}`hvvP3m4PeS=$?xQON2tiWv*xTHD(~ z#!C5MZ4V8PwLMwdYkO|5mRzqj|DNNyk;28<#xl5HFQb?(lrb}#FJq;Az!Pl;p0c!g zmLeAZG~cQoqnHh0s0)=f{X)KHZXxw<@BDe3vq6O$)30@DOt`k7 zKM@<3myJzl(6Dn^X=aI(pF47s zpb^yFi5piXT@49y6Y1{Mz=))19rAndcZ*gmipiprUQc5(Z=m^BN9Vd!7hP^7$_SR> zSCLeU&%Y`^ zFM@wUvvDW+G#7t@`hi9&neQUHYPr38DYkQ`@RO+nMxcZ;`1Q^B1_TIXpf&Q+g|E&twxOYm~hDR%lhHPQswjTPj z{&KnT=_x(3dd+e&TaRuj*`7!`ENcFWf^_Sy{oQ@tZG9zOi$laR;*ZR9OPfD7njML+ zk-zEB&DNRzQYH`M9Qjh2p#n@^19p64giC&`jQgqQ7}ea}kV^C=vVd-Xs`bJdR1jM) zoDMNj{8L7lqx%C9vV`ntfyL1j7-Q>#_ z6m-i)D+$&inTLO<(v2y&^g$ig=!^z?mr_1a#o=zcu27?#bv3VcQ^pvLZXTe|s;-!? zff74|rBq9r2H37N4@6KOEXudEqHJH+sjRoeVcRez(ojFHGTw`Pe!l-RDok zGk50uu5$cFmBY>Vn&Yvz(7D(>z=CaM`Sr)x?h&48b;$L_g?Or^d^h&1kK7x+XUV@C;$pib z=f=3<=H65?RutY&My7i~Yk7f%r*iTQA$tf(ch#@cUV`qxtiIOl=(GXht;m_}Lh=}% zcb8Gfc9l`gc9StPTP9^xAz*)5zh&$!-?_SLE++TCmDroM;XOz zsf?M~_A*w=2Ru(Up0c!g79s`&`-_{GOTtt-lskKSh3x0b-rR~3%FZ*VB|;lU3Z<>M z)B4X*8h$~7Yzzw$xikD^hAl|2O!4csUy_5GYau4ee^Eufk_a>-kxJ_EzY1S194(Kj zyz0RgNR6<(({ny7a&IuPBA_>sgmNYV^=wT~Y_673$lfWVm|Y{Il)X#F%Xj%SGnCUxAGL5J=sCTvtW)9`@+@+%zY$Oxhlr4Pn644*O*d@hTg!=uy0oy-)}O5?luFtOv&KO#$Z}8 z{hA}n=@X8qNRQfnT4j9y$xM6NOyx2q(w8mP`2i4L0@Nj8<;6hL!6?oz`k)dRlsUndb|8j%yH!v zo&jv#{pR>zv=9GQP{-8=&$PK$N&0F;H=}hLRd43Tas8F9;xgA4zYA zyuec3YJe`)etP`OI@4og@?nDcTuoU_6m3n`CIpN99p**R7KgXz&Fb^$*J{lgIjoN5 zP)d)EZ z&W>>`j+QYqJ5t6FJ`P)!?OG3p_F}G#+dn@D1QP=^OO9fzwsF!#-=xt)_Ckw zIOWEs!`#>;l(7l%)*qYJ4QFH1O9*$N#rMGE_!#{<7z>3GAL(2_zIDS{d@m4AZAA5O z1@TdQ%G2s#H}hIoeDTt?HA<$5i#wKUocPcX_JO!o}^l zH=+MrseI&m3Il#@{{2C*A+DqtrYv-ro9~dK($Zfebs=THp=|S5=Z>JS@A8;*G+wDpnwZII+g#ofa#_{Gc15Mjmwh~@$~UYBz{=@EkWqa_A*~SM zas|3gKh?6m>CM)D&>-UaF|KO$R|c8x>jKs!3G~)+ymsrjJh_m1S-Qq|D{8efi<&D6 zpHCgYDiS8>bKAVlKmh?!m5-!NuH*%q(RWV`@i9 zzGTXqO!<>3e=^OV&0C%zu0gfYWTCpXhY=@x8@{~#5!o*@`&M*E$mP`P+&a|1Us#Cfkh2^-!*;~!Oekl`1 zUe<05nke^(=jY*>Ue1!D@-y^znbJ0P1z~di-Qljk6H5Pc&Q$%+y5X$g)c38=4_ei_5<0mZziQ>7?X+xJ^LVwoB@fE@mpO~eO zizaVfTR%HG^g-9wwKno@(n)QrHJA8tlt;6QElIyhNFM6|8Xg^7q$R;ERolJ>JlvZJ z?@AbP>j^__ong0rV5RehevQLQs67Gnb^MzC&85bC5^*fM)MLLxWE8XWF|;}?>*V$57NYfNv)FocQ{l$+Yjb&K zGmBY)5u5ebqtVm+4nco$>2?U>Ji6dbUXIdQv~n4ZBYi??wd*!MRWrbF%w^r7D zLpeH8-bVD3(CIh%LH#urUdV3&p?{ggl_6Ky-pSUoH7RO%L3r(2Mf^?#^W@c#xzvWW z?pE?!Yu$!STI)8Xz1Hn^J5yA|I{$02+w$lUX~DS|{Qc7WVz&$8ZU(t4zN%}CnGrqN zOIhot=cXm?LpfO)6rQ9HNJW3T{7kwMdVHGtWwg=dJJAW*p*y!> zF|Cr`L3SnIA#`uOIOrDyH3sYh55|*Pb6aB4++;bj(B?0YQOw>Tqm=RZpgJ3C0(Yz4 zPn5Tl_!q%2zh_a5o~L~A_LBB28e8_G#%}|U+@3|z%H9?vHm#MfI(=~Kc@FZc^zGGR z(}xD#O6~yL=a&-oOWalH+0dp!Z|AHfW!>gOqtu4QPE<2--5N<#>ht7%6yB_>b-m~& zizPGZr}+ArsaVCVb=9iL0EjdveYK%e33!aC@>>o)eLd^#UzA>S|Dsm)8yJ=P1u+WU zOht?aVi9+70?sZ5g~<8r!$^t9>j%Bmn3=v!I`8iGI^gRzIeZ78`bjO+oP)YRhEh9= zMJ^rXI#Rc-WgA9eWo{H<^|ls1BinCR9o61lVtlyCO^uj{sn+D2Sn}G}ZiQ02QlJD2 zTU;F3w2aj4@5bn|RO^`mjx%?*k8t;Poxd+_KfRf*CcLzvzL!4B{&dYq{g?f) zA)|X$iMkSd1JCVi%VSQ3zLF6D6?(OdQg)RLROq*xS<2pFW;tW{v$t)K*50W#qR+5i{1WV(>N?{2>$?N-9{x|zQYOi%iK{Mpwipno9xMEYu7u?}~;6d%KKgz8&sF7^HN znCqEW%0TiA6U9NO+m)pua7ytg^{@;MEFQOHa=xq?psp!Id-^Z1E8ZzuJD%7GsvF3pPY)D&x*WBWbVCupC#G*z_kZQ^X0_zR%lhv;k~=gdmd{c zxRchIY)k4Fg<~qen6wTT){ORx=D#NB*9Ch!72QsA3yDy$O}Rq)Ll^={ltMZJ(?a?q zgYxH9=8z61Ag!=m8T>CiX(6|xeOIBNw`GGrV~D>WukWuI?TJ6;PV7n9MU_J1Y)TJdMkHcElXH7 ztar2hdH^mx?#fPH40jo)d6o2&irc?@12iWy+=l0c-tt+>KOOUypODrxGYdPnKgGuC ztlK$%lcAmIMP@ecAT8-7Mpx1$h)}Y31k#_0!=;8#v&H)gBC-lnPT#r?xS7Dq)&Um@ zykZ?N5x82QyHM168>49J(sVo!w zY~`0-ZiqdnlU)W)JC`RW`RML6OJ_}gPVV;9w`4{37b=^m(B*FO(w1x+9RH>)F$ZLE zC`t|@=eUj;C%?qQ=$E;R8BYv;hpE5Q_n(cHQZ)P(a&PyPm;MQao6~o)f7GckJDS6Sax>#23STh;og6-cetn@E%#TRq5Yey8DfBoR$M6VpFEu2pK& zTe(Dv8AYo*$L?t$_V+=kBdlRZ{%xRKD|e@o%3~_5+-pGnH6};3#nGPIG2W6`MiYB` z=X;pb`KLeO|KcBuf4YF+E+1eId(#Y~wdUbA1|(Y|c6KdsptiqTMj^XSMlriy#?0(p zGFHk53Aunu?kxV93>(Mpg*QVoZxe{8X=;od-HoqO0Dj;|_E$yW#-b^X%+1TZWjNZ! zk-goZ`J#vQIu+|)ZB)rt6Jup`|MHj!yC3Sw&yZu|7Xz9;wF+XQyjvJ(hF8gj;bz}S z!%cT3C82cOZ>F83zaq`;^9)XZL6xXA{|^rA-~L*8@*950li$iHWWSS9%ziIpX7&de zE9HYcVP}IpktO*PKQ?c5JW)$(&0}0X{~4$3gOV-I?vzo;J|v@<$?#y_P!hWjEYmEgndTtPNJ%7>&y3{pr!r})`xgz+fteAsZ4g4rUoYp6E%jy z>RQ{g*4k1B|IOGT(r2vfJgW3;&)bTkV3%O3YZv8s_rW`1^1T7Jwq|8~S$+^->D`Qp z5n5QSxu4}jA-jr1(c8!fD>}>_iuF_DWG`4J7m{?|mEprTD#8C&wypr`=?q;@sT1Ej zvTR~3_9aaAc9@mN^y?M`1{D6lN#X6V8BIr*03;V}AVL|eH4lGy?& zJ9rZFDTFf?CfqxXrG9h59Wp6=PB_W-VPr!u4Z1}7H!@*#hSNaOzhiN;R&<|fel-6F zV0ZluPH##7iOu`|AIM~k{9~E;U=rB;w}6!Z<9szK--LFTL=(7jFJH2QiPerE;K}K!RJ}5c9eN2mu-GlF)$(smXEnhV}u_fr_T0-gn6BLg&;O9; z&fvMzdA6~!_56LAA+NZ0dbGB(h$EE6wbt(Zn||)zT1T`S-xb(Z-2*4_F8pj%5v{U4 z4Y3zlo&0}#*ZEEDQel=Hj(iE-z>%*oRxyjJH4Eeb{c;f_EAd0sD$6Kj6&b~>Q^w4! zOU6q1pbx!BC25wV8^pK!%Si`gE^RBln6bdr%%lf*TGPC!F*Klym*(()6$sqSsq#JbX2l8 zsd0T9&4v3Aod{VnJ$0n!%%Yu z)J;E1V^Wl-n1giM9K@&jXLM+O4pK55J1jlr<{^_Ea&wW%4!QZrWQW|GMc4Kc%Vf{ROaek}x zcHza0m0>M`d{74SnGcy+%IL6c$wR&*th~vTKbi6;)BNpBZ}=)IK)OFC99!$teH1Qr zi1w-@C}?og)mHVX}|8X>~uT z;g~(7DjH{>l~KqZmN7H?jEt3XqC>gZIuu!wenPlAWeecNgqih8-Y7nnsAhB&hBWJt zwws)S>E?dw&xY~)eoKq3qr43H2AW&)TP^TaxK7@{8<3b`xxn<4Ss@HB)xK8T_-;)~ zr_ARne7i5|yFt-S;%i?WTv+Ilf~bcFT5-Gk>^Ga7V-J!7db=$ee1hrRxG?rE5HGT)@WFBZX zpC1@+B%?IaTWT(VN*3}{FWIVQwlTDr$frzsm1+16jeo%^9%ybNbce>YL1mn?UEm%~ z=M+i0DX#UN{LAU?8-%A)KKhHBo8cq-L_0GmCwCU9eR=nOxq4NR$Fz(mPlbM5FiPAw zrP>@8n@>Ws7W_o9*N?OYzBlQlv#2!}<5JZ@)w;Zt z$7C>1C(7>m|MIfh%(n0wv~-Mpidd<)aebH$NtQ{ezf`Gr zVy8Y7Sl7#Y+OYyr)N3(2cpk0 zx_K65IBX9ou)xNN(KA)1PWR+HTC4?hR1%hUc@~zWr{`LrA^!*j4{D?hLtM$F=bOb9 zn(n5n|CpS|-3`ESHT{Ka_+HfE>;aWVF+-2G{#;fyo?!p9?CLO#z=1iu1B?K8C;&zP zFi<-mMgTk<03!e%34jp*j|RX9fX@ZM2mlJsF*SnzHMaMLNj`6GEFr}vV7&0?Lyp-y zlO*wi*JctRUNHNNOcBS8Q{+ui#tTuHqUP%voHNB3`nMC>Jy7Y4wr?3cx?xitlxeWe|r4LsMwkbx(CE2cfC zNHg0gnl)=dt+@^UtL5=+F$SC4sdg}9sgmGw_C;fuA_p&CT`HN5ht>k_tIXsXEP*F@ z%N4Sm@mlXe){qiV0j?En;-zxdg z$9?6Jj$`Aa#A6aR-4XZmccQkpoG+Gh@cSlN-28qE^6qx!-Pl(Nm^+trB>F$+B874; z=`!+rz3()y8}3w!`1}_PSJGQP(H-h%mLj5NCOavY%VRP^x3@xV>P(n%L|=v3UVWzn z+!>GI3#VMKob-iLcxw)}GbXB2t+@;Ciepzy;*c>#95CHYj97B6CYSq)B|eA42i1#r zN^udNJu%@U13tEP*OnDFd*NVgI6tGR=e$3A|C~7Sc(IHCFIk*eD9^6BTxN}@U0-~^{tq>mQ=yxq^Oqs|Twr6bZ%v#$}fh-%wQY@(fhtLAF9C3vz@ zl8sW@Re|gkPy=-5iq254f;u~E%-EGw3%-YWC;wC?G%I(;vU!k7<6Cg_N58)O9;>tUXNhk9`*>T0(c@Nkw(GqMCFchu5{vZEVJm6Qek| zb+x$g`RAiZrxk{5UDSYf*F6qDM0ixl-lwZuwbi(ZAq8pWBL+v9w#k6P^8*9_5 zcTnEjXq!&+h)N;tl%=^XznMzIm5F_O&OX#rv=7jwJIj~!=SMZnyd3G8ui%H8daNWJ zZmcDJ>2ad7r;Uw%)8hqDj;`OhN9E`~Lb~DAR%>;3 zwMiZQsPP~;^{%_o?q%((LF?Rx&fKnOSz;c^3&VJ zGoP5OF-~)U6?Z$zGZ^L3M+pY@ct0=sOivJE*{FPE)uQ*js3;w)<$r;$XL zvxh2YqqVwi6_z#Qp^5%Xb-hg6=ji;=mic4KQS_4DN^&w1h8NGQ+aHQ5n-Xgj?UC+b z-x6ib@O`9a@k5CxPx$8lt5ai9rzDjbr8Lxn}|S z$n`=6-LhKdRN~7JN9(70TW80pGIVTr*GNC_-cTKLUm%qa9bN2;yX@1R$;oV6B%h=D zAi_t>>5)oQMdOxEF>>_tHJ0tMZ{~7fsdncx+3btf9=}}jx}IXjqTomSnSN^~TD#+N zC2u`1tl+l14D{<9g8CQEXEDhjgVt)o*OBm#|K9&lRJw`e8vUcFgxYJi_x~&!pl>C= zN;*>zeay;SpQ)Ov!nqSwol9zM?C6CrQ`!h1~5Mh65%xoTRPK=k3|oi!8IZ z8+K`V@9%CJ!lDRAraINpAFxGSni%{GTA1JabY+ZNwC%30Zt82xi^tk;_x2(){W3ZQ zA0(py+=`0&eLnoscGFC<`CxFL(>#a*rR|n%U*h8y-WF7;gDjO?M-6T~p_U43y8IzV z)zguJ6w?fbqQ;MKiyP%RVHKDe8doIKGcg*wfX+?OBc#~yKGS~KZPw6OAxaYiW(>(= z2*YO8@jld=Rw%1kyz~DB=V2%B;lZ{CRjMA%**S499)n(<$MND;rA;38vzS*DI{duG z2!LV$i~uMFzzBeH0E_^r1i%OY7GK?D$q0b102pz5Y!5$ViZXUMAUO$%!lDLKm z5kadVs1X3&0WbofCjdqO^aj8PfN23R0$_Roi~vBrbP^i@Pz!(&0DS>40)S-?7sLnv z&NMo}h}(InRLPOpKD`pylM*$T$eAIi5%3xefDr(knRCpIfccGLF7KYBJjTg2G_y=z za?EFiphm!Jb^we3m=gda0Okh32!MG3FaltH0E__GC;&zPEC_%R01E?PM5qK3$|phM z#L2sq1bN9NVdD_g2zaqt?y|!OfK3Bn1i)qiFalsW07d|?e(rb}5#&(}ULNuGq`2nf z**pX_0$wb+J6=WrY!Lt>02T+ph;PM>r&NFn@1syiPb!Qj;G*yXPp6o|Kmy^KC;=BjCje5Eq*f0NV$^2$=6J=JM`2%A+UcCC7Y+5Yz~G?HB+f z0G0;82-c^Ui@Cgej`En}xKr?N1Ppc#fDwoJP_pDgEeoEEAk;1aFoI~WSG02V420(x z>>B(V0fXHFU<3@lEe3M+420(xa2&+tsu3{QBLGGK>=^(f0QL%i5deD!zzBeS0$>Ed zz5y@-V7~wu0kD4njIjCHF^tptiyIyDNrMFRX^?21lu(|OIG&UsaYL)2nMClYBF`oL z0Ib%gj6jA117HNeK>;uV;NSol0dPnFi~u+^07d{D762mv4iA7407nGC2!NLbz=+md z)#b%9<%J~niIS|Il$4&7e4dnKo|H^JTO^G~C5Io5B|$ESj>Kv?WCW5O6#ydujt+nk z0LKKt2!NLdzzBd>1i%P@V*_9Wz;OXE0^s-n7yw705$~K3Y4C3Z z49*RJ5dh}}zzBdw0E_@=2EYh_^8;W6nKFMPgis7#2=Qj?Sk*;bbMh35ub}2Cn^aN$|phMcv6C})FcuN3`0C;NvjG&o4BLNkqmr9X&Qqg!)5#(fj8&=B*BVc=30E_^*JOD-jToC{x z0Im#x5df1i%P@cLl%*fNKL_1kHH%0&-sAy*LV)i{iTA-v}679{?i& z-W>oVsBEtkM|t-gEdZ2>R>;PwC* zL2LNFB$fEdCj(#vz^4LW1i%9UFaqGg02l%A=>Ql3 z@R;6#F2X0Y#^vuxb~lbAv)pcD^Hsb*JnYY@v>wBo{Nba$^h7b+z`R3SPWSPa zO=Q{6TQ-&D0B_k$mV>-ySe8S)Wsxk0dCTUq9N{gAEJu3F7P1`eEsJG&xwq71Io4aW zYnUD{OY4kDe$W1FRR|TauMjF+PpViwsp9ga3d)lzqFjx62&**#Bgo~?2EYh_hXY^) zz#{=L0^rdA7y2!O8# zzzBdR0$>EdHv(Y9I`gPME1#4EpGpbuNlEER$>&K)=1IxqNlD{L$>B*!kjt_sv09cH zfn?tdfDr)S3V;y+-wuEg44k7IBd@~yC=@am#dm^#BVh1U0E_^5Isit{HJ&Gq^6ojx zW2~>l*LABj&-}X~s1fk`UI2^$_KgVjK83Eg01i%P@Uk1Pk zfL{f`2!Q_+03!f?9RMQ$eiHyA!aQ10dZ`qdCl!q+6@e!eFemnJv6|RM5X0{RUm{_N2Jx%>O3@H3DA$3V;y+{|FUn*G@rI$*Pc~V^c`j3KpQ~`5h zbA!Z*Z3HoN2EYgaZk0G6MgUX;U<5#S0E__W34jp*T-tCvi~!&QhXafN;9R={i~yJs z03*~tw&sD2uPV_J*r!RNdQw7qQsQ}1f_YNxa_Q&ryNlNd;_VB75da)^cRq{&7zlt7 z03057K8yh16uAS80N@Fh?UDc( z0kCBNi~ykhxFALVY#jh2P|EgI1rkFarU+$Q)p0tOtZbsUWV*e(D@(2ZXvj`Hp~ z%43||pl)1V0&|_4+=lx6Njsxp&m4pULb>xr>zwxH@QyzwPdjkoITOzri4gP~MD9RxIym3k^^V!b=F7Y6 zF}Une0va2^%eEAo&pCguxbU0>%RU-nkwnW-F{7ooI_I7KcK*R8*2w(7Z(;mCaL@A1 zmYp2p6};?1@oTsM3okf)uVqwm7oCDHyAs>dqnz`s2R1&|*ff6k`lFX!XQ!HwR`9ZS z$Y0(0`_=BBJ#pEs!TEu2o^|RnW_XUNvT)h;5|V>-O6&9A+~Uo9ab8^XJeH9)6#@%hwu@qV)CK93cll~_Wa)&-G^azJ)f7_v77rL`UwK46` z$AoU?Q0*H#^wUD8IaHg$4!uw4-^mGN(DtfBKP2?W4%J4ZLvI%PHHT`0%AsmOOF!XI zZ5BE7Dxo(!R9iL7{& zzvWPkbq>8-=w}?N@yemM2)&)3IC(!UgZDJ=Hw(uLWx2yFH#^G>X1T>#R-0vwv#c`9 ztta4kyI z-f=?wqIQat&pK+$IC%ObZR9QTIG^6se0g#AkEno)?_$4DXD_ zGwXV2;$ftxkjnJ;?(N7W=RUiK*I~9?%+BP87Y5G8;EszD?u00mE6q#MU{X3V4&Syu zZ*Dr*wxofQa%nJ~Nl$Wx8$QN_>o4aMQg`|*JWP5Otirv!f}IDad~4130qY)4UzwAm zWqVPo+kM#BJ?At7ylk&Nb-QN@9b5x;!luiKgo`@whf(ta=;Tpq2Ea`M-XP#}0Lkb1 zaSwLrZi42M)T-Q`!P(tG{^kit!hXQv80jnd;k!2+orWl+N7?T&{3Z-><@DA3M7eiB zwt_Epv=)soB_qds5z~K;=nQ-|--tNFtAr+xAy4x)fOe#J$@q@=PcOusI$4O+`X3RW z#_1Fq-{2uJNlF!{KKVMeuvbB*EAU;``(k!9zHtXW%egl2lxj?O#ZIj^8Kd;Mh76;Z z4`WWuyp&VXJP9=ppsJ)t065Cb$L{|Pn`D)2)xK(S5rhujH+Z)L?pyGidl`aHu9g~y zg7H*2!+|SoXoc#pG&7Pn%u7$_Dwp_p(AA_OZFtMIvb@n-u9sznS$Ovfox=QIqg2l& zqtf#Y=}Iq<+26f(Qx33qA~lY@A;qEW@UC?3gN(Iq&R26jJm$-F_sw>1oyXB((f1a0 zbW=>=dquzB+R^F<&I6EnwnZ&R)nn{Ni_MPg-IS8|qw z;%qn{srHZkK5Lm?(L)K<^ez1Km(~vEMB~(ac>k(aT1>o7&Lpbs6wZMUMSC6_=vs87 zf2&V*qe$JLO7lJSD0wTqyDQc5(2{993@~fiYIrSuh9B-z;-rVMlFJ~j{1tJGPq*sG zEefuY@O0FB$=>GWxDKz9i+ct13(9U3cHTncqRMIro)yC3peKcSGmQ-tKW20}F~d6$S{eSjDCuNA3N^MM=Kbzq}E;jnyhVvsZY z9lnqYDViEAyQfEm1dRleC+z2`98Ze2zB=U9!_me+a_8rD@8klqf|g&4G!j*-RxGjI z-ry0glrf1$an>m1ocb$kyYmIB2UuPIUx`jWE%g7L+!~A`T7PX|qI?=Pr}K_ZI(q}GG{<>qtmX$+_ilidCPpuf)kcBU z&o;nHv#FQHYC%`vwe1#!nWFw_4)zjxRRgc)26$=a=6P+PQZDEYJRaTv56$ylghx-{ z(Ytu+G-+1&B0PEnk7IH?a;;-S@=pulZp($sS3b=>UnK77fyeJRz(X_D7vV7@@Ytz7 zbslJ5`yxDQfye3%@X##yMR@cD9?xumhvv*L!lOU%7#*29Et+A!2#|fDr)80$>CHYj-Y)5df@m zIKT*i-2z|)!0rJsA}qZtO20g<$o$f~qVcFA2rJdx+C%qRjP8Yo#9R?gAGM}+|K-n5g)T9KFDCyH8d9{n0Yxg2YD?q!aCoEMV5 zL`>56>e(JjVh|%-M3rFvW6bTn zp+h)Ft(d@Cb)mb?R}EDYdO9c71N(T8|MuV7NpFtF1DOh@RTnmn7VYoSe59)Y_Q(RC z96k`P{vD@DZ}Uh5yET5nRy4D-Dex8U4T(LGc~JGpeXMm~{I!~q&_|i?zznQP&;$vVwvMoPKW1q3p?H0P_@qFTb3jA zao3UWd?)S0s$>!U6rZrJ75!(^T6Och=#sy-CpmC?38zJ zeYBk11thpPq(mo9X{}_acN_CGd))ysLr8~+<;h(g`!>vuZQ(IvNvxdKVD4s?|9k0=SX!*vJb?j zTKnBB1lFr$mLe>>0w9R>cSm8;cZBs3_r!%;AhFev?#lR_$pwF>3Z88u`X#v}Ps2R9 z2RmQC%&mU#^~;t ze^Bsm1i--oFaqF^02l#qXaI}=I4l500I=uggfQa1cvG^Czd!7re3X=DiYi_h(T3fd zXo@L_ zm|R8G$9;3Vr+e0r&TQEe0uwHonLt>>p2)t4>?Ujh1eEncHxZ@h#-P5g0YO|NxCFsn zQ9%JkToJcda7QJIzV7=j`Z|8U|Ea3mw`2&6GwZK#CP50WIW05P6%$I@7yUmPNo2R7zbu6|3kU0za_+ z!~FXEvA|qu+|74-4?j^*s@~VGq>wQuLsvzoelFP0+&x?L>9xj(p{=!p#g?LDK&7cK z>#S`=o-$q+3d#t4cPLwOIHl5!@fx$v>#pY!7n5Jyv_kDP?=g8O)Z;nUEJZZm{siJy!Zi{z;6b)Mp%_XGFAb z^*^V;K(rT@oz|d)>C1C9y%(Ob1jQ9d9|7uxdu9fYKztO$_>ZxjPMaL+ot9rT;;JLP zPt4}@tLpk=g1sKNI9jmM*-S%ukgHnbqpm!s>z*(~Mdev0r<9G$8O+$KL3!jwdA?=k z(TBe@MdR4i?bziO4*25O695jYP?@%9) z2nPKqVe^g@#?L{gaXqX8x>pH+;HQ^1i8@^K3i-y>l1eJdx&vSCj039;al{74P9 z%;~NkrnY0Vp_+*%#zbMx{@Cfjth5P@TgO!kEcsiWcn}w#Oi=B z0K}SrFaX5q0bu}$GXlbZPlkbMV5J+FL})5bw8G$YVN0fMc=;l=ot-I~lv!;~Wk=X* zjW3(bB%h*y*$LDQZH~LG)aJNTN^R~WIUU)_at5=f$(c|18^X`T2MXIIPN=}b9;*;R5TW&@09}Z_#8#@ z?`gcC62R*b+Anq2%ZMO3_v1=lg~He24sKt4L=dKXiIzu_GGj z8|8w0%a($zzp_1B-)Ut_KHJKcx~vix!$FDJL>O!7Eo+S*xO%eo#3h-krx(g8WzUyW z&R!sAFxwz!LLsOwOcGR=KBl%O`oCJ^M}@k7iQ>iC%jJ|ZuJ9Dim&qB-UMy!qA)xtl zqp1%s0ygLQKeVR{B$aAU1|a$u280KkiB~=KGlP!-Af6Qv27tIIAPfL;aX=VQpW0>= zZ+mU#aVjypMDbmlQQyY!QEU97P#2rTn>f2gPAPkX9Nu4)Gnl0nJ|;O?|Xzx;8{lN*l5<8QFY-yXMB` zxQpMCh-0qWO8o`ewZ&sAHIkm+LO12sHy5yyev#ngofW-)%=Mmj@qgpLf&JrFL5Ast z8N0wU(KZ==2$(WHET@!xMNT>Us+_^>YjP$Of-?Tf%BYWG84G=mYAF2+b+wH#%lv+a zA9sc**q;EWj9H~JghEihUt9U~Q7qq~tI+mxnCd5Je-n zR6?vKW&nuG0>S_gmj{FaAku&^0K^pmVE~9L1Hu3h^?)z{L?a*!0C8177yx2jKo~%o zWrKSiE&~nn>*j$y_1EOuaD6jiy#D>L%X<7f046JchVlNDCHdGZOUc&}nQq%|;`d%v z+-;$EGm!LluKz$giNA=%dxW3Xc@gf~r-&`-R&MolbvDwDM(PE*wW|$g}>u zEku0wpg8P7an6I{nFqzK&@KJ;kW8%cK4MDfoM6_o`LtRz0L0Y+VE~Bd1cU(}V!EoJ z1>y=AKEHoRreGlf*Th?_J4gCV6yTz$=JVE)m1ph2z_qPX})(R+}R>0&hgwA!ap6EX608zVMi{+y57`=bfob-}$D$Ca*qOkNJ(mD6cMLx{R!0 zgX@y?{}$hbrPERCGJ2w_EMTMay4aUN1;b=y`U2*}L`XJQHR45cKE|#CSXHY}4mkY}Pw2BNg{zw6{ zjaGOI-4vXbs2h8)OJOO#jjbo)G7Q!l-Cj;UD>wMGwNQ%nuQRV-M z6cZLiMw1SH^6?^$)b3p$)4YzTu5M;iH~QjIHT$*fRV;hbIZq)D!)^@+v+^M%(>>HP zITkv zk$xiDb!oJKdCN4mBfOeCj1O?(8Lqo;y(9TE<)QBMe#4ER-TMv7n`|Oz1GGDfCv!-B zXH|n$p(Db3oYt_;7M?|e?rR!}U^kNQUCuSxz;JwpC0AI1EMw8_r* z^USeny%Uyl&gBL?+w9iv0{m(rD=E{aO8UR#!FH|xLz!te7>6~^gQDe^hdmW8UuZgo zc3s@J^9mAf-z?C)9#rc=oGI7O&*v(=Hvh&X85!wI|Ec^u*_#I^rLDPwY;RsZB?ri7 zJh~k5)Q2y2R8oz3@!;K)N@7*ueW%H{^>z!ITCLG*ZOP58KSx7i?)e2drR?)^2D1m{ zOvsB#XBW(OAAZuQbqU$J{_N^;Dsx=fOZFb8=gW9C>4wT^r7MlePj}n)3N6fO1OGy8 z;NPU>fvLCgw{6^i#Lua^qh%{vd|E|*^cTDLRK$J13Z(3LQ1X*Mt)g}lH%eqDlOVUI zHrDSjdA2|Qmep%5a9M$0*NXRgf#Io^O)Vl}IXKxX@BdyS-===k4%GpgbDKJgyAR=f*n+F_5~6U9S?)`RBl>7C5{ns=v!CA}VMZ>x8w zrpB}Mwik~lv8?nQf^9vCC0?dgFzU#}K-ZDM1C2FfxF-AghRtG|RF$+EAdiSsTD^VZ z-i}1WS0B?Jh|_J)Bh*+ICs#U2l^&E1a@JPCV)t5;#vrZlPT(>P5WP2$sI|e%X@mOk z)#%%xm9R_oOIRyhHy>#aKRu(6|IpypJat5>S$(c|HNcI^?eK?Y6if@EDW`HmN#G3-b01$5u2m?U8B_IrN zGN3XtBjWACb7>?TAzh7=uHlEXY02sOIKzLOsgJY#$JzQ=s}Iv}7Ki3dGMhs(27tIV zAPnGUjU76<2SdL8x)tFI1l}6L8vudZ0>S_gw+Dm)Al?=b27q{bKo|hx9RXng7X|H4 z=aDIexc*obP_*MkKP^R3CaUqG-PZw%Uc3k?h%!+MxwQ6kC|D+v@U8(P3KuGN7{&Br z<5elW)Lh;@H@73b!dzZ$tP2SGVI{g8dQ3EF2f@}>&pWu`QZgN(?T*vSh{QDO<2)qu zy;X5~37?mSY1hii@S01L9SC@OGK1fXk{Z7~%$ZVxmF>&u^j15yb6VRq;LSTJnaPp? zAl?-a27q{XKo|hxJpo|=i1!AB2mC^T&Xw*%xq2y=XP))mJ1sFD8NZFw#^agMS{&Roh#P`%mNRQ1U|Pa+Z;FUSjFI$i9b? zm&mm_fqUBt6_I*KUJQDC*EsnvTp7U6X4}WuP^pD@7Kq8RP0WYY-Hk?7>m#Yhh*`gA zynwiDl8%$-1Eg2-)5kUjjH=yZv#^G>VKH-c+teAwZA}ypyL`p|l;vDDH&})n8=!)~ ziFA53KYB;&x!!G>+lrEAh8RwtCl^KF!nor3V2L|2W~Y~_ zUq@ZfnAYIJ308FDlzZzKFo&<(m&hEl>}2}X+gVCC63W?n{KsgAaXRJFyGqnqe>coX zxr+|ClwMEZluP35;|6_jHyj^R&VH3NH6!?I2r)9goo;{~BI*XZtQ$x>EXwe8D_rgd z`5dt^B<+^ZNd1$_N3VmwCV0BR9J5t6X84a+>0_ooHm6lNotsmxpP}HsClvo^&;JVl zZiUv9^Y8V9%K4`c_$L7h{4+T4k6Ct$f4Atv@ozilqXHk_LdbuMkF)**KE6rWF+S=5 zt*e0lQ9+)p0tykg&vR~>{8xDX0W$IAJbx>pa-Qo0o~xw7-;^eCa%ElIhGh z;`DBC$$$l4*c*`d7LYRn@}mXhKtO)1fSfhU(|l0KK}T~=Kz_b}oEMN^EFgWBD9qg< zLyIXNnO(Tk(9M;ug*zu478y-u@Do+LItyQ2#XDLm(J3*n9Ok^o7J~imi#hM(>n~ck zGY8VNZ4&l=BWLdrXZ?6izSeo8u@TqatJJYS1$@drp&p`ICr1r=$kD>t@xty}_xPvd zIXCidV}DPrXKZ#=GfO~ z?JM3Y6X`w9BS={*d+A5Kj~BIq&wbv<%Ui+ce(&Rj&iQaHP=LJ~4sQw$o4IrT0>&u~PNv0M9xnP9F## zbNG;$5ACjC3(on9%>~b%WBeX@=wYrkNfwaY1~pwN(~rv4-Vp;pYzYVhKzuJC3<$lE zg8SY`0Yh&@`0t1C27q`hAPfNUgMcsq#18|)01*EZ5C(wwQ9u}Qdz{p0mzh%VnNUm* zDo7zeKMqk1fYwg}!T=CI4G053{45|0kl{!{-K72EOrZ+&e;xuGKRfz3;^+X zKo|hxZvkNdh`$Gf0U-W2APo3{-{hila4uE3hmFcWV58FZQx2sXIBN6j?<4c9-qeUP zDZj=-WH!U{8|=bm0~ZO4ahAvrGBs)JsBg@b;d`;ZF;<4}o%D?vF(lSHSAP16Fj$t- z-_U+~XU1+mJ=FTvOqwmKZpqwjyHm9K#fs|=UY63I5jn%2$YJmF7lQwx{Fl;S3C6T2 zSP5kR1g{3DuyW+$I=o>4pgE;DhCwY2*mxoBO*0siLdHv`XZgB1? z*ScywL$z)q!61FLyI_K3pq5oQxPO2YoXTzx8l1*eZF%c`9r7Ba~izit5Dkll~9ml*NIUMct z$X!8Vfpfw;%g(dygn(^JSQ|ejB6l`^T{^lofw}%xi9_0BSiq5Zp2>EpUHcvya!oD$ z9>gN3y*Q^fXIYOUJ5PIghV9Jyr9LH4CM zsi{r6K#c>A)#*~|0SjY+?^Q`KCzN~??!PQ0qZG8a6BD>;%PqgdT_B{kGes&YHXb~Rc^ zKA3HhkGW2g@?J6sQCJ_S+FlA5HdIqQ|A`{W_I(2M6SIB$K5}eEJfZetrfg@o#z@!^ zVY=S6J6*<4 z-{_&(zIOxa=OjNjg3PCq*2KvWyfibq&1@I2E>TJs;6<0keTD$Z9^$s^jda-_$#;+6 z$(hd5c8H&RlIZTv8;eeuaA!Z`XhyXD z`Y_IR+a4ZQ2lR2%%hNliS5#5zPpzW#_SXC03o}vbv?+a}o3&`U!{2o3MM2dL?!9EY?Had}n%R>ZUi-yHYosX^q82 zfz-Z(r;&HGb>)3Kx{GVRjfJpsq~xk)o@#2O>}o9K%4UX)Hk~Ex3F(gZJJj(qoa;r& zVNZyJQYw~>%ehc;%JrErkzGsF!l%p3= zUUaM{EU&B^>0TtaWT?(_gZBGVTt~XM@=+M<#%9oJZRk@!HCfVmh|1V> z`t`;>AToK`{*>P|K_U%V)aYx?*`&XYC5aUOrdab9$zh;j`R_ zyMloE#!{{K-NkrK%c5T0?3SKfhL#JW#$FPd#&_TsW0)*l={NY%fYv_1e9L1sil^V! zN4lHISjlG6>2m)e|KZi?p8D*st~iKT>jyNEw zX7xJ(UDh0-jV#(vOWv-f6rO^Cm#FgTew0`#XzV&DYK*H?zC25c*-ZS0=J@GSeXz;O zh*Z=4p}{mE-4(RU(w_a*bQk-QwZH~cX$UeIQH)RLd90?R7RnXIF|NF1fP=Kd^kn(? zkshEFswoF@Nx%g*ezJ#Bco9ht0uBr@3sYA#03+F{6+#?Li1mMO??(3{YU2<*MmESN z;l6FI=yGO8Hhm8D_l++1@oRnQDgsJr9AYbIZF;aCIhaN0sMa^U`eBXTc}8}q?J$17 z%X#_~V%sbT`;+5cdMKzRMOmt*BPxuOrLNRT57(#6CSPsh;~4D4hX8X3(2^gFIJ%w` zowFl)2C5PRgZc$cQA_F9sT20M96{PtJ=2WEQAa6#1Z;97IHaQ$&fZ0&cAbA^A2#2p z@gf6+9NRf=YL@Fs#_7>Q_Hu0N7)P5*ckOPjTQ}YY;nCYX>B$bWANNIOV(IT#fkiPS zi@8zF?m~)CNUv(?h4wK&Y8*?d{cQ1Th2gT{<3KVHaQl=>*w`8NBH=sYsGr|SZu(S( z@#&84TP%NB??QG*K|L#NM&}d%60S(#?qZmpaPFQn`f!|^ezm9QTJnwfqDvf4RJdu` zp{CgPC-N1l65L|p zERX1$yOAm8g||c9u8pz$97}!>>yRJMLp@i?42#g}H5XMoH}yqvm!nVtQ2El6m6q%4 zF<9^M?ZUknrRY59B9^&awTTo1-cfC$vM})B38ZAGC?!GiM(;+D#n(Ma4=GoAvdu^r zkxPqnwi^3#0^P-w-H@o?qnyUK_y-f;?Gdx(0H^g@-^3`hOH|+eK=qeeDcH!Sfoaa) zKf^ zj4f?!mea3ZPVHV4MJuDpGU^Ch4}~>E`gF-A6#l8)%}|t5It`)CSdtOkCzw4$#cF@Of_0bpr%-F0Hva>Ji8|(H%IJj;pRnZz+$%R^% z;@oBgFoq0__EeI$Q9`>nI(?hR_i7`{MKHKlR)F^t!0r=D-(dmRfG;ZV@*m27`X2vb zd3vA!sLAL3`bh5LHyb8{vgDa7yImaV90Bt}wH4K2(Qd~BZD7)2h)lJ{QLq`zLe<~x z==3(adsTdT4(TWfR&bov-T=u=Z1y_(5v3(@&;z$JSJJ3vM%?dUxHaHTWV+Q;vbp1l zZg-LL+7X>WUg<*>U)9LU3sF%MHcKMhil7yuI31(ys}#vwt zK8|i7{Ct%)c?+py>@8^n6|VqykI(Qs-~6Rhqg6c4z#}=6pYHNj;kX0jP0+~0G3ljH zCy?HfI5|n>h?Bi>Y*ej8!wgY7Rg<$I#xz=~R}x;Yu{&1AAMio_D5iR;nC*9gtCy{0 z$g#h~1!_+xiMXkDmYQYrWTo6TV{#%ilCDOEdOL?NUhVc|=CDFakbdB8Qzyzg|o(Cr^U+!cLV-}qoBPR3R^YKc~<=9H^XvZ){p8Gmki<>4n zjMy_o8%d5Np>^yzpL?5ra#@Tc_JT)?+GNX#PREmrPI-LC_5TQp@&5u$Rt`k3Xsks* zMmET2Mm)NgFO3OQH`BiK9K5BfaOvq-6+;K62X^wA>}^ZZbUE!u26Fp^+7Eqcw8+X; zT0hyIfrDBZkWV=|nu7bY_=(um8n;Rj{ZF)`$!e*b97905kWR-)uDx)UcGb-+!Z|(? z?%1t4sdFcsr3rR}?a6(s$Jr4Yp~oq#Y|w?|ed#XCoqYe>v={w5v`f)mr1^w>zUwX1 z#gLua^M`(a{w^-B>em?xqQ%Bjc8i`!q$O^ZMSb?OOHs6w`8A~tq~{_D^!aA<9a67v z*z>@iIE?)t{gfrI6Kxs6=2qS7PhglCYV5^t4;{aT^`W8k8AfKB?M3L~!rjhC>E*q* zW~=Ap-y1!;iJYxl4~N|ur$n>Y^aA`A?YT=7Et?U(j^oSOrkQy%u1wZ+i*M(n_b|CG z#NWr34=nx>iobxx0{c4LQS)ENpEOx13YHi|3JSE5dwW0o*wc5;?Zu!oSpe)*G3>`@4^6Le;uQrpLQ)_;a zPC0oAY9S5R6Y3x8AE@=u9LU!JH57Y7=>q7eLrAxfPmYiE57q|9rpF%PQt+9awJc;8 zo4f1-L$#r?*=}edh-Ua^_(>OvCZkGUZGepR=NF-+-xn{2Yr|uM6jF)?$@~CZ`YiE^ z8Cm*23NfoTiwj4ThadClYD>jJ1G7NiRg{Z}(m#9j#Mkj!pa0 zXYj!ekvZu%73TtdrI#qNQ0u3I>YrPit8wlOc}EbO$8bA-JNchY{%3~=Pkbw}wzIpG z#$vOn8T01V=8bj5TzY0o4S8mo$#f=~wvzwo@M!NlP@^e?!IRO@y})sF$FwEi2=C!M zKJD3Q+y@%`!|~a>l?;~6Tk}G%cNLl+9cMhckE`kJXhowtPRA@I4^vyr z*2N1XUBS{TAVIB21s+My#Gf7I?%YWIWyCCDYfw1X2G!@wW_UHO%`@vOW^vQkNpx}b zvw`x#-sSeR@IQ$13<8K!yya+u_z!60I_307yx2%Ko|gGr+_fv$9`{#vd!KSWj0=Tex@vi z%_Yi>-&~@6gv}){^T!HDS~yxlwnU%hY-b$Ju7ayj`j)r5H?%dMOX{?}w)tFgC76G4 zKBu{%>?pgKY;2F#Y!SQ?*`KN=8Te1N zKG2iUgXni_>w~b1WRA$K4`)Fk8&{N4x>oQq2cIi=HwQmcFdeSKTqJn8gD(TlHOXub zAziv{W(JiZm>He{{C_tyTp%jJ%%IHWW(MUh4Q7T*^ieP~u*PCiX)b3pRT1e`)I-9I zcC>XSH9@xGCQB*BGpVOgr<@TL7M+D@<<@6Jr^d50qT7pyVM2o83=`01-_NDU^%vCV zO7nuF@$>bBN<~^IfeC)3tJG zUQ0KxM1MkM<{cA_b!s5#I;u#zxmJiwH#aOAyma&K6`y@F-CROn(9N}oBi+3F(d$e% zmv=!ozn;<*bnB$0TYKHyYtt>=yroTxC=ybPzmN1~r;U5v+<$r9+<&!nbJXWt)9-$i zt&y-nk}{IE>El!N>RhpowxD&umq$6N$CTEYikoWTZeNI0YN_YlE3PL%HMtJvqwnTw zcYm!`+fTbm@Vg#AXMBu}f;T?$raR=k@sao3_2G<5F>R~t=YrkU#Q%DUMm z0G+(`Xz30Op>+?<9QHE+(1iru6oAQoJ_V5eJ%|?Ta_8`g<;C+2{l9-U%JH0>(p2rg zQ`sIydmakff7R*sb82(O_SXh4ZZkq7Nv~EBLs`=2Qj#UEGqN{GRDx^7L6!PTswLvJ z)c?7o7uM!F^?#mkK8*XFOmitvb^4a{qs4a_Uf2AT?&HkC+_Jew2Dugx#a3Ff*v z!Htw^E~T2=niI6zte+FKnrn@%M5X=(wFPW42;A&+jHEnF4eajSX~%7IZqTi{K@^Qo z>)mf!_hAHyqn}LMb558Wtc~jr2Y9bi<85J{P&R#b)b%HYuE6FA=Xp-Ih5;=m9bt<} zT~1VVUqkCLkhrVMM8zc2O(R@q+x}WdYsu-(FsIl*+WBnvZin>wr&5wIr`Vq^)+CEn z$xC6oV@P3UQQrQ{B6u;gxX0=5?u@PJ?>sa9Gz!9pjkU`r9T;-~1l`roZcKXDP8D%m(!1&RRI<-DAfFh*J`$`^J>*)6GCpD!1I zv*i{ceHq~~4ZB@1wsWn=<#UPKw>-cPo^|g&Q^;h#yL0?9ty*0g zzkaebSmJTFlBrG4CJn1AZ0@#fbmDOLmaZi-whwi0u`3IGdz}{bO^>?jjQh&lO5*9y zH)fl}GCuN=~?+xmJ~R zEgO`>tMGElS-+f)Y(UOnHbc&Y0y4K@QHL97^bxKxHrj_kdtcFBF4|4S>MvfG_~Wnt(6>#OVQH0EjaJ!T=Cw2802( z`;?V}2SwY1qFTt$Ss|(c&^kLH3;?kK24GGpokQbXGzc1 zvH{Ry$<84R0C9dm7y#mefG_~Wg#lpzh-U_b0UzH0eS3zyP^$e`h0e! z;anz;_r<6eaN)h$XA9?|Fw2KD%SNMFvxP-t1G_s~6NV)plAaG7_T16zc?P<4X!Gjl zvB5|C*%-8*4v+rIy;oC7-k^=5^?J@gl>uv+uDF%7iGAnoSwv~)&_iJH|q5l*#dk|0t*X; z?yZ#KYUe=u5*50WbM)6=wA$^0?i}hG0+GNJ_F4~hIZyZ5rMIaHuL2g{rrIw$d84z5 z{vYyv1?B$#E#G;i&l2}toofzt(39{VJ+90?pJ9%DCUc0|Z4yyQUu3g%?MD62XwBUg ztvr+R)ml*{(yF$XktI}jtD^UKGLd=C_C%&dV~vv@t`iI5lhC@llb7oU3;t;DR$kWy zuf9sDtFtX`sD5m7gE%uzfyZo-kuOlhrTE~^*o$c97 zUJtT&%Z^K)gn)XPRj3d8!yFuORw_D&{~dv`4cZ)V1lZXh6GqVPg$JdZAii*P;duH6 z0lO_+Ye37cSBg$1&Qq-Z7mhC+b>Y@7+|7lnq%T4G=A6~r*;AdhjIAow*~?~(&a2eF zh3wh;y4`GXtZ!+3F{0i~Qtq^Z=Ccc+PagC4YPq>b0^K&qNM~{T)vDBZ=qF-3e|o6p zt#J!Pxha0zkzL$Qy#mxjayFmTJo+%jT`yf>WV~m|dPc%>`bH7bt>>> zN_-R8#+&)spg_r61W9LTt%2T78Mrdm*gK41>?D^3f#J0O?3OQ^vz7BloM~r|G;jAp0BbO9l}E+owTcE?N5H`VXk3 z#;ur#M(UG*=_Ww#r(3)V_-2FMqfE~v(e#Z%m>G_`k$wILkUc_aH7-`B=m3~C8b~`2 zAWao;ISFSpSU|Gcozdt3-zt#C26&r58biR+1OgU;1}6d zA1zvUcv|llt(d4EQ1B1(ld$gGmi93Uf2R+Bm%_J|No-Ks9})pyrVk4)lqpa9Skb!M z)4E5rl=i&}{t)~HC^Sm3f@AS*KgTL{3KiqB`s&IunU+8_0_?-T7xQx3BUOszfj z)@{-x`7t~!Noqxc>w;F(Ly=@QcKVDgqb|zH(@+P^J?@|rTGlAIhC@N z^e&_+C#2c3cyk}NB_rSFi#XAKF}XNjJ<3tZbT?{y=Cc-(^Y$0e zKAv(yTbwFE@-Vo>c6WLV4wk!CQAl!{UAt{t%#VwzE>UeKg(-F-PRp{A*g}-5yMj9! zowJo6J3j5MZ*+{NWUUY@b_wa`h~v1#(@Li;5=uyiVU^I7C~XO~`_;NaLQAzA!mtsR zL$LlM6a$%1uI{HX4nNKDgps2Rdsz=T;3;&swjL5EM_A94e1dAt)KxcL4h`LJrp!LTo`!6^wNN071I;)%bN?*kf>pYW{Gllw;MCQ}{80svcUaL^A z3!%;y>h(fx3aGV0VKV4WF$K7Y=Lq#`px5l<^Z-iick9gfPe0VyX7Nt9C`g>rW2P4Va?$y7&ER;iBWMV1$hc8R91yoqQ- z-^^(=PmVyQJQwL3W zDJwR-0~MO(+!m4B+KG%F($&NYQSNlxXLKE5A@Jv>1fCg}tI5e^26|n|sRC@?!F^8A z$*z1CLu~8vbu?wm+X~MyJEl}zqf<3kYWtKj|E4_$D>kdl+|fbOYzmm}iqD-16n7NW z$(Zpt%%~JNpz|*yIR`q&tM%bSqbs+12a6J#VB8#J)aze-dqMvmMurq zhm0#TE6KwEY@(75QgZ6Y%sBmueASwhsMAq4hICe}?4XonhEmB~CqwHjN68Mz0vAFx zBHWR#OkLDSm8ayamy%_*wHfvb{JidD@~}T;eY13wazUoQN)~#!j*f{@w=4R`>nrWx zsm{`&eOZf0PJy!1hYNOMzem&sOc+Wk<@A{@V4FR8Tj8)uNWqc4<3aMZI0DC*)_4~C4J6XZLX~E=^ehaX#%U-`} z?WT&j_@Xm?1g|By-^LwU&J8)=0jS#HP6S?ZJ^lz+GJF@T4^^`Jkov1^KI>rfSvlWQ z=g(wb8Xb4H+iS&R7$+H5uJ@z)?|5ILWP6Xw8>tj`pGf<7egHgi<727$D2ZBV+v1d* z04>H#+l8uHH*0*lg+NPGmQwmXWzuxyN^}f#?9V6t0{TXmbU}$|6U)ZM&>tyfYQZBV zwS!DHkz!;~wXV3C|sHcw7Dn=hv$!%|qT z@J{MNxq}(@Wpo2YKsR7PoNd^YF}AaSXNvAq3v`z&aGdQar<5_mi2@x76yya3mcd7t zexo&wwl)9OJS1aQ9(Dpe0@wU`{oBB5CxCpH*5l+E)PhyI2j5R$YA5{^$O7*XCl@Ht zn^`nks#CK1Dy6Jc(Xd+IZt>_~v}b15`MQt}5U7Uz0+{-iuw(>%rlFRZJLOt^Gp{rq zFchm~ssLg*qyDol?nfN$rX+Wg$7{;wLp9B)|BB+(4>>IOU{MfZ9;y{xe|Fr~c#;NL z&zK5(EE|C}-Wry9vDf)uN*>OVT+}aurkx4uuD?EjUQ5ALD`lmxvumwsDNI2$^%?6* zQqthu?2+|Hl%uaJubo}zSoh1t6|0XRuixRPlUD`^nfwqbGJ~&~dR_QRb*OQfBg1Z4 z#Kd?*J9T!i`jK#<{uo4tEtog@Y5x{$deI^`KU6XO{`)_l)imGi|Ts?=_fj&u9xF))Opp z>!0qvgtgF($97%xnOo*vD^+74W{WYLtem^(rfJc%)4NRINQp3@P@9*e#4!ZMP>wD`w(_Eh)d z$RO+0=1{OLgY5(@A&@*|6S~d$BG#3$p1M1`|*D`|0nW)7XKIVzmETF`M-|;*YkfH|L^Dj zKK?()|JV6{jQ?Np|2Y30CCbnLeExUke{cR*@&8o**YJM<|5x&V4gYA?(MJ9;G(^m{ zBl?W!4*u`qpBZz61{g6YM~q1k+>TcKoSz008!qr$@l(P42xg>=8b5O|N>J1wpzutZ zqsA{Bj2$X!{L;ZFdr{+84#xZ%HGb{jR|)=&gI^-}w+@~V{5uC9sHo+2ORuS!C!Xp9fH5^;I|6?o`YW}_*V|zDEO}q-XQp&4!%lo z2j&Fw`7FVG4n9-xYzLnpcqa#AIf@#)Ie3NOy&XIz_+SSw5`2_{2Lzws;7-A(Irx7O z*2eh`{;l9k9Q;3muXOOY1V7usUlja&2Y+1fD;#{M;5Rz>?SkLt;F|@%&%rkczSF@k z6nu|^pCkAa4!%_IXB|wZ5H-HyU?xCO;}HjA#D%vGK2Y#49Zdg>oH&?mTT$a54xS~r z)5$}x;2j(s2_A6pAL$GlBM$zl;5{7tUBN3H{E*;P4*s;@V;sz~Ow>5p!S5El*1>NU ze1U_pJHcBA(`iPH%MBiVUgJs!JiBp~11@V^?SS(e*EryeM&^K%8XFvNbmIjMSlM`y z1NLpa)B(#H8yzsxc!dMzHD2j}{>G~v&^>_BvqL|6DNK4`vtoT+ZQ;`!f2MJDR~|~~ zrLF%SO8){TsyuW>z;GniVXh3ASpicInAri-2$(qmb5+314VZNSGcRDC9We6)=IVf1 z5HN_1%i+SVfTElBsP2HeCP(!IR5M5Q2Gm53>IS1v8SW z)KNKV=YTpoM~wuOY?`jpmITzEIck@HIy^@u0d-K0+BKl|&QVJPYQG#c8c+x3sIh=r zoTJ7AYE_O}7En*gQM(1yp*d>zfTH{G1zH|Z%sxG8kAONPN9`Fx>2l1Hrys1tM4QvymRZYL&(1{4N!k2)-%R^+I|0}5N44|PO9 z?USR93@8i%KGabGwK+!}9ZXd-GBS)PYP>hg1;%OeWL3%&y^M0@6 zvc_K-UN$_=PYcOpVOisE!vB3LK99(Z_kZQd@T$28tvotU^9l^B!Y2rO_d0}aZa3Do z;U)E5kCYJwx$3qJ8E$T96QLr>e~9E%dP4pu^!DL8pvx(3LO)n(l}_kXXgaA%!F(4tdx$ID8_DG7fH@EKUpneI} zkvxMCV_ft<34>*RFXVYyRBCcUT6c9G z?ka(;Twg;KlnLEr97A9_0J)Qt-;|-WP$wj)QpL?zQ0U3HMc{ZIS_j3;^8A((#&;&g zlAHO+A;n_BcLEFQr^L?8IPf=@UlE!|6Doo^fi=N6G95%1D9!*fOqEYUN`PFm4Vh zHwSGiH!F*|+5KOL`UH8BT)qV+d%4_f0&uIij@DNY0EK&NE8J}s?skQ1m*3+F_crr< zyF4##BO=dtnCCm?d0Ct1y*wZ+EOwTP?eZR0lY%M0( z!MY=v5H7Gb@*YBB&5B1mR=k$^nO=OqLy`AH#y#6 zN(w@x^HgSC0K(14^DJqKqd;wSXTqe)FI1xkcO%~}xAT^DIsi%7Di6GPY(!NjjThvU zl6wL36fNH@G17({6Ri4+#Zg9zq>|4n{+6TryW@qEuCfMP!?f z<8u0WKIo$WGkIw{VOuxCiwX=``Lc^t&g397-f1SgiVCsCD$$m!e15R9+U;{%d|*L( z>m1#0)p2n-GXev(fIr5WzR-R4wD?i_Oji^gby>Rk* z%ezm-^uXvMHBFDr+8kU`=veDQVd1mj6WvNO8-lLNN@11h(XQupwb@F{byaawm>znpPRY0NY(iPgyDF27 z0Vfgznbqn*V4*R^Dy7z$>}*Z*u>TX8YBC}!tuq1YvoxjnPrgmzLnFL_W)>P@?wKxu^EAUX(cJ5p zoKG7Ws`pQ~^*o+J4irq|=1Ro+W=L=uV$qA$58FIa?>rN;D_r{zKOF!%Yxty)f8q^_AP!XmmHhk z@+>u=+gzfJZIx&RhT*M4up_Cp8}N{*&M_x=(q7Y!79l-b@z4b7pt4%DTYc*ia&0TJVJ2!l0?h zkh4J(mgHG;ytf9>#KOB(1-UY%F){~N28@5i7c+-f8<*XOEO%m5Tu(mpna`UJDK}(je;D0yZ zt;gWbXhwxKUF#pdP0oD(a3K-m#(UL2d=D(I_}cFlezO}2i0=w_4>*jAs@ zd#vws^4RKb_AxBoO`bI)q+aGxhLE;i#-+>pD7!TnO*Lm48}+%#vGl17CoO7uN1@$X z>MPd5lia(073mkgy`q)-TR-F5h~>L2omOKhb|1b{Eco4I){&pAyidKtuE;{d8L!dx z8(?Cg&$wB>OYt4qAfJS@R-^X(ZE~bKj#q+1m{pmD?CR8AB{__s+4u2L4-IRLB)fz zJ|!O}BU^`j zygT|XF@#l~r*OUbD)3wL;Qgd#RWZ`vnJEaGfGQ;&gD=_th?X-L%%Ou_@qp`_g-*v6 z;71BTVsZ=W>yP;at2*-Ps|7I4^(O^Cr%o!gQ#yYtzhX3_piqt5kslN&E7ga9(>L)W zmC7iiU)V>^O%vbr)~(QL1oi@I%9arB&nsxL-E_*cD3tZ(vjO~^UA<0R>&kv1mtJw= zI{-7gX7(hUJY(9!DlGLa-~O(6LT*8ewaAPOrp5kT6ym0w>}P@pGDCS`7H7N?C`LG~ zHf|a-o95|M!Mu<>vAT$oaL)0ry`@?;m7JSjm+6 z<}#(PAW|QLZ`SL`Xp=o=w5Bvh-*?C_d82C%f_t`bOQ*&OW6FT*xCgAgI;Pfo{b;h& z6NL)H$g1PuJMFW<4~I&k9)^V3xcU?RIehL`n4BSy676AGYj~UWe_Cx+G5zW1LR94lgT@R!4hR{DVkC z-H#qC*&8%606eb_Ju~R0f1p1||EMm@GPCd>7HGw9iAOl$(m%;pc@#!&`fgz?yG2sp z2Fo+-3h-wIu!6V%E}rvDn9x=-mCu#Z%$IJYWK{c&@J)-_R2VaWG7>RmK1k_Xs^;%! zt47GO)wl`9X1@}FVJii9Pn{b35>cE1m*oMMu_A|k6}aMB{~6JLx|$00#QjyBaq=CK zh`!6Jg40dPxcXyl!TvklXH@shb{tegF-}@T(aMc7xpYorH)Q9U@Tql*Ly6D!8|FBw z@r9FnG9E~_Ov?7`LH9MG>mKbNYJ8il=p2peGSd(6Zv~5mEcL|6V}xi~*5~ft89f_; zXD=P}cPDADBWd#;J=1b9LG9TC*std}W5pNxbG65Xbkd_LPdO+$n(avpsz*e)X4HQ7 z;@24(_O@^LD?eX#3cxF~gRG{{?aIvzBHym zbST{)&o0 zD?w+g_@TsdvZn~15I8x==1dNgI7YZ4EAz(9&{Zqjj!T{sIlsB%GXx$8Q-4P)$8VR2 zOUyAwp$8g=@|$qxRYy#e#hxuIF(%WWSV0C{r43{jaY9ih2epV7Pbjc2i7^O`=P*#w zmIMBi*r-d2Ort64^M8QTf8&28(zh*r{y=2)a+B2~i0x%n{TYQh5=@ZQqky+Bs|q<) zR*wcp&B=?a&g}OXex0lyYu{V>ea6No7s*Sf;yCF%E|25AlqW7t<9FNADWQ~f%7ALZ z=?teTXxx=ORgMh%#{v9UBX;GnOqWLrt;KnnY>;%CR0)uE8 zOPqB}h4&(89FWPL>)^l|N7EC5JiC!;1#t}XaU8E)Va0=XiBrmwI5V|c{suDR_CRJ4 zCln<}oB{`lQ?W6~79{T9jU6PeC~x<`J#Ck4$=kBV&*>pI?9fqMI{#Of!t+(ud>wWs zbW*PA-fA5-57Dm>{n$UIF2P{}9>9<1JM4GJeuw!@zE6#~bGjOH*b&HH3V)pQiK5sB z_dJWNKbP%YJoXRjEXXVj8?ORU4MxvO|S_~~-&_0aLok3tR zNOT2dXv=aM94l@+14CpHPUB$el9_{0DZ6O8(*tZSfGGv8Y$22)>Oj-*vW^u@#iXBz zEE*$7ZxJbm~={@e#K{6=4LU`|JUkv|1<#6!H7HT6P|i-u$=P-Kft!?6 zQ=T#g$(K7A(ozIx<3l}$)CA|t>NnL@Y=m=+;sfw{>4lH4? zFp9=&uC@YHS}S`;sk9;3Qi% ze{-@Ws>s%!a^U$=T$3%%#>4Z6Nq`|6B(f!^FnLoj~ z$R~8v6Q_pnDiCYQvKC3@b_}8&uw<- zjD~t1)rNW=5+F=pSNdA|rSUl&U9~vZt4*K7&q#kc<=}(NOgrT8--K~_Xx;qfS>W;e}T;0h_btkt_cZ#`n-5EV2 z(q4Bh{J&Or+@!j@`b$pXWvfVuos>_J(~%vDqxrV5a)p*__+^c*PSn4{gv(W>!e+-O z1@lPgSEYz7M4Y0Keswe?o2jk190SO4y4z@Pm}Yp)q)M7xpA0%(qXA>-KJmnHd?lxw zlon~aJNY?>QEObu5v8za@L4({8)p}}1GAhG=fJFRY!*D3dT<|8HVcwB*%#P59dU}I z*0`!b?+QonN=J{gozN2wdZ!pYeN3Up1=}a82xpM#7V{XVtI>nBE6#<`c1|LMZ#yeM z!kAMO=SK*#v-j|jjA4EfFm!NmspC;rDm03nO7Q08#>YHd$|jOZb{anMLr+6}Na&Zl zhp(Gq>$KdbtQ53DzBy&mga_LnS->qMZCkuHVriMSIYGhg&Yo_x4iB{Ir!f#M97xWj zXxpTVLclc0^2YAGaw`cD+MF^tc3*V@)Uwqg+|=)Ow#%$CrB-ZWyUZFnGCG_LVB2L* zwN|yBE1kixS4K{uQ7K-&S7tY-s~N2U$DRRKvH_P5BbyJ0yQ+_TlE7h%#2}_W>1eDK zX%4cTHMs8Rc*a8x08#g6!98F1FIH?Wh6ZERjwx?O{c@OGze!dlbV0Vja8ES;R@tp{ ztExyA(%n<>%zlCAF7YA7`t;kxHT#oINV9Vw;VE&ev_34=#(99*Gx+hU;RM-HaxPFf zmg@pTiU*b8^uaCpe7E&D#cGQ&e5po&^`tu0nFJHikv)K+(+_h$8m6gobXF zktj_;P#EERwyap|rd{^xy z8RCpC|7+mk@A;?2>&+SXzArO%I* z#+H`Hb}6L`=%UN^o9qP0y~gQ6L+RH|-LXh7z21dPb_ToXI#NH~mLFZb~8IuU3Ji9zZSlO1zgS-cG%g8qsRj@Wb)t>B`TD70k^6gYQ=6iJt)m*oc`E#L!gG1Cee;SKSUVN-GCTc2h*ENf z5AhuQO6fKHn$2!X8s+F((wJ}eA2gfFYuY3z^Dw0Dh}LFKAf)Dp^O#}tK`f+CT?zopwV!twrJybo%}>(s-N0! zIYN(%GU|xeZplO3yq@5$6Bu7pGD}z+?(kB|#JD}&@>0qcRc=N!j~gH`GCs6Kchnt4 zX&d)~#_A({B^k!Lgc`JTf4JF7YU%MIsaNF5w+ex$OY_E-XCC2|EnLnK8S-udzfD6P z<<)tBQ|U|BQ*Q1ZB%~k9S=^x8X}(r*-;CDgw#967zv}AjAUBl1P3kW)|*6%}G;_2hyxzIw2InnB*E4!8;#$c*;`j-LaL zTLYODimM`t=2FEdzccxZwj83t{Xe0Q@BD0E3;H}_^)Ua3Q5H9L=c0-%mZHytf1b(W z^GM%hF&;e?LEOM++`QI)pU-d7+NdEe%FHKopPBibwk-l^+b@tKZTp1)rfoClU=Dj> z+>{sEww!{I&*DK!R=(^-{KQTDTE8u8gqcb$kdZ{welgzB7PCgQ@YUocLZcXjJ>@rT z+SZ=(4!h%IgO&MhRDf@PUxX2w8NCx!s=ZRzU(|Rh1haR8X!FS4qiP$<-ix#1k1m#> zn!;?#-sdAIVs-~VoFKB_ckmmw(O5EV+h`OmwQV#{#A+wF$~Ub3fE=;GCKzeYseON^GcsOgMciZ}3LtWB;NY_YpT$aP}`g?)EP_ zHmKk|TXu96XXySj?oCW-;jeqswq&^yb+O0h`Bv_a z!gVjp45t!+kAVsELI#ri==JN5^W!Im&HM2m?};1mwvy?CLnHjw`;KRLnDUx^c5m+Q z?yLO>-#!h_jqss0txEDbvOSc(o?q*9Hvx#vZ@~2vIpvd1_j7X8>D~umoi6*1>2z5M zf~f1R$feV7QS%}lh=&ROf7o)Xxt$5 zXGGyUTT>9_xG7(sItHOi<6%X4KvC9CErsJTlU>p*Es+u^66u>LRVZTIv_hFjpe+mf+3pu>~vTyd`i<|yJP)%Tcs-Bo-I#zn;VS(CL@!B)42!)mV3@y!UM)H zkj9GvD?4Ax0*<9`wauP~H!Is)PErr>{}Rz^@)pt5ys&7GUX3`d<)2k~-)~6wEJaUI z6XCBgk=;!ExLkidJV@wDD%q_p(b9o`O%Mdx8>DO$>P;M;$RZ+B2= z`1XDr9rzR9J}9T8vwq^+U2-Pm1>Y_(zUd?RFh4Dt(yw(#7?-D`Uw;)|_&)Jt3?4}P zH^DUT#=>RR&@n=C0s>svg??F2z8$Oi4TrZ~=&idEJq@-ym&bN=k<+u$7YcaC(!$>J zb)+I{E{uy*|0jH@_dPATB0mdr5Fe({Dn~|C7p2y(HuS9e%gtrZXoXM)+V`d>C~}pQ z(}#4Ubl)nk&mUjp�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

    S@%mRB z&yxS*ZqI)_rdQ()_F;p$OTM;)gor0bJV_j{>obUBz>LYA;}gOQoJ^tP`d8fU$zg*n z2e{PXbd|6+v#u?Aa;eI8KI{0qMVuJ47+PsoG{ zi@#`j5%W_%hZi+J?H%tGuM@`x7o+>@|0ruHZVli26|l=oh@*p&;&_o+N*sR^9R7o? z-`TRf=B3Sl@%@#xwldc*pg>f;c*?oZKg#<5^He z922Z+jp6#ptBK=TQr+rrbh81{tl+Zm z5C=(%h_@7!`@Bf+O6)yHbYs;_71lx%JWOdD~7L{kAvH=ySZr>mc6FyrVcybe+UeA9R+6kFBALd8+R))duKlp3OVn z$#fI1YTjKOXSN>VIB0u{&lAsW%j0nUM?rQQppP|FwtFx09DYC?<-Nr_nfEcz>GQA5 z`W~ zd)gKDj`|zL>)7~in5_^N;5ZmA1-9sJk{k!th)6zCay%_>7RQNeRK!P%2Pn8j8t@q2 z8W~_r#BWQ^7N0QQtd13*V?NHjnBQW2%r;&e6P%Fl0sq|o#PkOKtoH5VI5SQ%FD|?A z&g7)Hm$!Vfc?qB6=R2mDm-LPg8}3fd9QQ=458`h79}P3&4YBVB+$Ub!^83w8`3`Mo zxCg|M&q~heO8XoavpEreNIbjc^Fznuk5l2Iu)+Hy5nn8h6U!2tMK~ZPv^3(&BECH0 zkNN&EK3{S@E(4&$l@Wg;;;SOQI^s`?HhkUf|sQLXRfW{_~!C9*@ex`cSw#87+w>{OSoO)6U_IB z-(&tdJn#n%w%|=EfbSE>1P?^~ka#uA4~wJzh&cY5!h7Ns?9~3Dc@Q2%)ve$YDZnq9 z9~Z~>>`sW|+x4f#@3g1U_u@^=e@f01KS*&5oD;`G`b)C?|G#ho*oD7J0sJ>{?2+Ha zE1CZ(j_+vvWnRYbQS5=g#qo#guZVZH30_UM|Nj@RFxv_eQ?B(4Df#0$CXmrC5MezI z!b}lQj(BESA6uLy;#q@8L$-+L5U*h!HS!_wkYaQ!c14Hf+swYP$D=9RtU zC0Ipq?7~VBuN?6z5w9wagRr`IZe0IsN&_C_TH-j!>WJeZsFzaI{v5mQJG^0bJz5XT;AC61R>Z6e-Ie4OR&#RFW8I!FVa zHk~5gIpSR--d((p9Yeju4_kkI#h5wLiRXrtQgLr-`A~73 zdT$iR77w$7FnkEG$A(LeH#Rp#@)2>j{f`w!$_iD?Zx+WZqEY76{9|0fe6%>8CAV6K zVU7vjCizs`pz$eX<2lBg5IP=zJa2EehU$I*Tzu{j$3rw({DAGksp3n_?-9rQf*C0l z;{D-id7n)%>>m@D=^f+q$M5b>sT?oBG4Mc2wYcA8{$QkoSrMNd@i`Hn8}Wx?&hhyW z%!?E}9P#-wq3JfE1(AHAxGlOx;@ILx#E~zi`|CdnmP87ciX&epZi{ZYIPw+Z$RCvn z<2Tv4i`7zq7m-h;*zW=RW5Qn4x~F9T47gSt9d1ae6R$`9Y{WN4{5kU= z8~_78F9m!FC61%~MRDY>q|}cOh-b+*@x10c#Bof$Cce=Q(%mWc`+wmCT3EyDQh*=B zeoMTZQ>vfOo|4-tS%U^5#dy@%rNZlpuWz3fS}XBPqZ?6+I@7r`_k`IQ4!J z@h`xy1tLb0j zc*ui)q@lMpTo%VJz7p|&BmQ5+uSVRZrcVI^H>B~&hPOelBiwWroRlJ~GYuXzpsG{yw- zi?7D{r;s$@FI*R~4#O2NKv8i#�lUQ8T$@zhrF_3^AIAvx+xiu3dTQqq8e(&Ff_ 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 literal 171008 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�m9J*0 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 fI#zIo5EKk Date: Wed, 19 Aug 2026 00:11:20 +0200 Subject: [PATCH 102/283] Make CultCache page commits content-addressed --- .../DirectoryMessagePackBackingStore.cs | 147 +++++++++++++++--- .../BackingStoreTests.cs | 132 +++++++++++++++- .../Plugins/GameCult.Caching.MessagePack.dll | Bin 44544 -> 47104 bytes .../Plugins/GameCult.Caching.MessagePack.pdb | Bin 20236 -> 20852 bytes .../Runtime/Plugins/GameCult.Caching.dll | Bin 86016 -> 86016 bytes .../Runtime/Plugins/GameCult.Caching.pdb | Bin 30204 -> 30208 bytes .../Runtime/Plugins/GameCult.Logging.dll | Bin 6656 -> 6656 bytes .../Runtime/Plugins/GameCult.Logging.pdb | Bin 9544 -> 9544 bytes .../Plugins/GameCult.Mesh.Quic.Native.dll | Bin 15872 -> 15872 bytes .../Plugins/GameCult.Mesh.Quic.Native.pdb | Bin 12312 -> 12316 bytes .../Runtime/Plugins/GameCult.Mesh.dll | Bin 695296 -> 695296 bytes .../Runtime/Plugins/GameCult.Mesh.pdb | Bin 205548 -> 205548 bytes .../GameCult.Networking.WebSockets.dll | Bin 14848 -> 14848 bytes .../Runtime/Plugins/GameCult.Networking.dll | Bin 510976 -> 510976 bytes .../Runtime/Plugins/GameCult.Networking.pdb | Bin 246920 -> 246920 bytes unity/org.gamecult.cultlib/package.json | 2 +- 16 files changed, 254 insertions(+), 27 deletions(-) diff --git a/src/GameCult.Caching.MessagePack/DirectoryMessagePackBackingStore.cs b/src/GameCult.Caching.MessagePack/DirectoryMessagePackBackingStore.cs index 9d9584a5..0c980c61 100644 --- a/src/GameCult.Caching.MessagePack/DirectoryMessagePackBackingStore.cs +++ b/src/GameCult.Caching.MessagePack/DirectoryMessagePackBackingStore.cs @@ -22,9 +22,11 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore ///

    Fault-probe stage emitted after all pages exist and before manifest finality. public const string BeforeManifestCommitStage = "before-manifest-commit"; private const string LegacyIndexedFormatVersion = "cultcache.store.v2.directory-indexed"; - private const string IndexedFormatVersion = "cultcache.store.v3.directory-immutable-pages"; + private const string LegacyMetadataPageFormatVersion = "cultcache.store.v3.directory-immutable-pages"; + private const string IndexedFormatVersion = "cultcache.store.v4.directory-content-addressed-pages"; private readonly FileInfo _manifestFile; private readonly DirectoryInfo _recordDirectory; + private readonly object _mutationGate = new(); private readonly ConcurrentDictionary _dirtyKeys = new(StringComparer.Ordinal); private readonly ConcurrentDictionary _deletedKeys = new(StringComparer.Ordinal); private readonly HashSet _hydratedKeys = new(StringComparer.Ordinal); @@ -33,6 +35,7 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore private CultSchemaCatalogEntry[] _durableCatalog = Array.Empty(); private bool _needsIndexUpgrade; private bool _manifestUsesImmutablePages; + private bool _manifestUsesMetadataPages; /// /// Gets or sets the predicate that selects indexed record payloads for hydration. @@ -64,6 +67,12 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore /// public override void PullAll() + { + lock (_mutationGate) + PullAllCore(); + } + + private void PullAllCore() { var traceStartup = string.Equals( Environment.GetEnvironmentVariable("CULTCACHE_TRACE_STARTUP_PHASES"), @@ -91,10 +100,12 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore var reports = new List(); var loaded = new Dictionary(StringComparer.Ordinal); var indexed = string.Equals(manifest.FormatVersion, IndexedFormatVersion, StringComparison.Ordinal) || + string.Equals(manifest.FormatVersion, LegacyMetadataPageFormatVersion, StringComparison.Ordinal) || string.Equals(manifest.FormatVersion, LegacyIndexedFormatVersion, StringComparison.Ordinal); if (indexed) { _manifestUsesImmutablePages = string.Equals(manifest.FormatVersion, IndexedFormatVersion, StringComparison.Ordinal); + _manifestUsesMetadataPages = string.Equals(manifest.FormatVersion, LegacyMetadataPageFormatVersion, StringComparison.Ordinal); _needsIndexUpgrade = !_manifestUsesImmutablePages; _durableIndex = manifest.Records .Where(record => !string.IsNullOrWhiteSpace(record.Key)) @@ -156,17 +167,25 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore /// public override void PullSelected(Func selector) + { + lock (_mutationGate) + PullSelectedCore(selector); + } + + private void PullSelectedCore(Func selector) { if (selector == null) throw new ArgumentNullException(nameof(selector)); var manifest = ReadManifest(); if (!string.Equals(manifest.FormatVersion, IndexedFormatVersion, StringComparison.Ordinal) && + !string.Equals(manifest.FormatVersion, LegacyMetadataPageFormatVersion, StringComparison.Ordinal) && !string.Equals(manifest.FormatVersion, LegacyIndexedFormatVersion, StringComparison.Ordinal)) { - PullAll(); + PullAllCore(); return; } _manifestUsesImmutablePages = string.Equals(manifest.FormatVersion, IndexedFormatVersion, StringComparison.Ordinal); + _manifestUsesMetadataPages = string.Equals(manifest.FormatVersion, LegacyMetadataPageFormatVersion, StringComparison.Ordinal); _needsIndexUpgrade = !_manifestUsesImmutablePages; _durableCatalog = manifest.SchemaCatalog; _durableIndex = manifest.Records @@ -188,29 +207,42 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore /// public override bool ContainsDurableRecord(CultRecordKey key) { - return _durableIndex.ContainsKey(key.Value) || base.ContainsDurableRecord(key); + lock (_mutationGate) + return _durableIndex.ContainsKey(key.Value) || base.ContainsDurableRecord(key); } /// public override void Push(CultStoredDocument entry) { - Entries[entry.Key.Value] = entry; - _dirtyKeys[entry.Key.Value] = true; - _deletedKeys.TryRemove(entry.Key.Value, out _); - IsDirty = true; + lock (_mutationGate) + { + Entries[entry.Key.Value] = entry; + _dirtyKeys[entry.Key.Value] = true; + _deletedKeys.TryRemove(entry.Key.Value, out _); + IsDirty = true; + } } /// public override void Delete(CultStoredDocument entry) { - Entries.TryRemove(entry.Key.Value, out _); - _dirtyKeys.TryRemove(entry.Key.Value, out _); - _deletedKeys[entry.Key.Value] = true; - IsDirty = true; + lock (_mutationGate) + { + Entries.TryRemove(entry.Key.Value, out _); + _dirtyKeys.TryRemove(entry.Key.Value, out _); + _deletedKeys[entry.Key.Value] = true; + IsDirty = true; + } } /// public override void PushAll(bool soft = false) + { + lock (_mutationGate) + PushAllCore(soft); + } + + private void PushAllCore(bool soft) { if (!IsDirty && !_needsIndexUpgrade) { @@ -219,11 +251,14 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore Directory.CreateDirectory(_manifestFile.DirectoryName!); Directory.CreateDirectory(_recordDirectory.FullName); + using var commitLease = AcquireCommitLease(); var currentManifest = ReadManifest(); var currentManifestIsIndexed = string.Equals(currentManifest.FormatVersion, IndexedFormatVersion, StringComparison.Ordinal) || + string.Equals(currentManifest.FormatVersion, LegacyMetadataPageFormatVersion, StringComparison.Ordinal) || string.Equals(currentManifest.FormatVersion, LegacyIndexedFormatVersion, StringComparison.Ordinal); var currentManifestUsesImmutablePages = string.Equals(currentManifest.FormatVersion, IndexedFormatVersion, StringComparison.Ordinal); + var currentManifestUsesMetadataPages = string.Equals(currentManifest.FormatVersion, LegacyMetadataPageFormatVersion, StringComparison.Ordinal); var currentIndex = currentManifestIsIndexed ? currentManifest.Records.ToDictionary(record => record.Key, record => record, StringComparer.Ordinal) : new Dictionary(_durableIndex, StringComparer.Ordinal); @@ -262,10 +297,13 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore document, stored.Descriptor.DocumentType, Registry)); + var pagePayload = CultDocumentMessagePackSerialization.SerializePersistedRecord(record); + var indexRecord = ToContentAddressedIndexRecord(record, pagePayload); + currentIndex[key] = indexRecord; FlushStageProbe?.Invoke(BeforeRecordPageWriteStage, pageWriteIndex++); WriteFileAtomically( - ImmutableRecordPath(ToIndexRecord(record)), - CultDocumentMessagePackSerialization.SerializePersistedRecord(record)); + ContentAddressedRecordPath(indexRecord), + pagePayload); } if (!currentManifestUsesImmutablePages) @@ -274,10 +312,17 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore .Where(record => !_deletedKeys.ContainsKey(record.Key) && !_dirtyKeys.ContainsKey(record.Key)) .OrderBy(record => record.Key, StringComparer.Ordinal)) { - var sourcePath = LegacyRecordPath(metadata.Key); - var targetPath = ImmutableRecordPath(ToIndexRecord(metadata)); - if (File.Exists(sourcePath) && !File.Exists(targetPath)) - WriteFileAtomically(targetPath, ReadAllBytesShared(sourcePath)); + var sourcePath = currentManifestUsesMetadataPages + ? MetadataRecordPath(metadata) + : LegacyRecordPath(metadata.Key); + if (!File.Exists(sourcePath)) + continue; + var pagePayload = ReadAllBytesShared(sourcePath); + var indexRecord = ToContentAddressedIndexRecord(metadata, pagePayload); + currentIndex[metadata.Key] = indexRecord; + var targetPath = ContentAddressedRecordPath(indexRecord); + if (!File.Exists(targetPath)) + WriteFileAtomically(targetPath, pagePayload); } } @@ -285,9 +330,12 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore { if (_deletedKeys.ContainsKey(pair.Key) || _dirtyKeys.ContainsKey(pair.Key)) continue; + var pagePayload = CultDocumentMessagePackSerialization.SerializePersistedRecord(pair.Value); + var indexRecord = ToContentAddressedIndexRecord(pair.Value, pagePayload); + currentIndex[pair.Key] = indexRecord; WriteFileAtomically( - ImmutableRecordPath(ToIndexRecord(pair.Value)), - CultDocumentMessagePackSerialization.SerializePersistedRecord(pair.Value)); + ContentAddressedRecordPath(indexRecord), + pagePayload); } FlushStageProbe?.Invoke(BeforeManifestCommitStage, pageWriteIndex); @@ -296,6 +344,7 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore .ToArray()); _manifestUsesImmutablePages = true; + _manifestUsesMetadataPages = false; DeleteUnreferencedRecordPages(currentIndex.Values); _durableCatalog = targetCatalog; @@ -384,11 +433,16 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore var started = tracePages ? Stopwatch.GetTimestamp() : 0L; var metadata = records[index]; var path = _manifestUsesImmutablePages - ? ImmutableRecordPath(metadata) - : LegacyRecordPath(metadata.Key); + ? ContentAddressedRecordPath(metadata) + : _manifestUsesMetadataPages + ? MetadataRecordPath(metadata) + : LegacyRecordPath(metadata.Key); if (!File.Exists(path)) return; var pagePayload = ReadAllBytesShared(path); + if (_manifestUsesImmutablePages && + !HashPayload(pagePayload).SequenceEqual(metadata.Payload)) + throw new InvalidDataException($"Record page '{path}' does not match its committed content hash."); var record = CultDocumentMessagePackSerialization.DeserializePersistedRecord(pagePayload); if (!string.Equals(record.Key, metadata.Key, StringComparison.Ordinal)) throw new InvalidDataException($"Record page '{path}' contains key '{record.Key}', expected '{metadata.Key}'."); @@ -527,6 +581,16 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore Payload = Array.Empty() }; + private static CultPersistedRecord ToContentAddressedIndexRecord( + CultPersistedRecord record, + byte[] pagePayload) => new() + { + Key = record.Key, + SchemaId = record.SchemaId, + StoredAt = record.StoredAt, + Payload = HashPayload(pagePayload) + }; + private CultPersistedStoreSnapshot ReadManifest() { if (File.Exists(_manifestFile.FullName)) @@ -627,14 +691,28 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore private string LegacyRecordPath(string key) => Path.Combine(_recordDirectory.FullName, $"{HashKey(key)}.msgpack"); - private string ImmutableRecordPath(CultPersistedRecord metadata) => Path.Combine( + private string MetadataRecordPath(CultPersistedRecord metadata) => Path.Combine( _recordDirectory.FullName, $"{HashKey(metadata.Key + "\0" + metadata.SchemaId + "\0" + metadata.StoredAt)}.msgpack"); + private string ContentAddressedRecordPath(CultPersistedRecord metadata) + { + if (metadata.Payload == null || metadata.Payload.Length != 32) + throw new InvalidDataException($"Record '{metadata.Key}' has no committed SHA-256 page identity."); + var hash = BitConverter.ToString(metadata.Payload).Replace("-", string.Empty).ToLowerInvariant(); + return Path.Combine(_recordDirectory.FullName, $"{hash}.msgpack"); + } + + private static byte[] HashPayload(byte[] payload) + { + using var sha256 = SHA256.Create(); + return sha256.ComputeHash(payload); + } + private void DeleteUnreferencedRecordPages(IEnumerable durableRecords) { var referenced = durableRecords - .Select(ImmutableRecordPath) + .Select(ContentAddressedRecordPath) .ToHashSet(StringComparer.OrdinalIgnoreCase); foreach (var file in _recordDirectory.EnumerateFiles("*.msgpack")) { @@ -708,6 +786,29 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore return buffer.ToArray(); } + private FileStream AcquireCommitLease() + { + var lockPath = Path.Combine(_recordDirectory.FullName, ".commit.lock"); + var started = Stopwatch.StartNew(); + while (true) + { + try + { + return new FileStream( + lockPath, + FileMode.OpenOrCreate, + FileAccess.ReadWrite, + FileShare.None, + bufferSize: 1, + FileOptions.WriteThrough); + } + catch (IOException) when (started.Elapsed < TimeSpan.FromSeconds(30)) + { + Thread.Sleep(10); + } + } + } + private static void ReplaceExistingFile(string sourcePath, string destinationPath) { for (var attempt = 0; attempt < 3; attempt++) diff --git a/tests/GameCult.Caching.Tests/BackingStoreTests.cs b/tests/GameCult.Caching.Tests/BackingStoreTests.cs index 66078f26..e43fa7b6 100644 --- a/tests/GameCult.Caching.Tests/BackingStoreTests.cs +++ b/tests/GameCult.Caching.Tests/BackingStoreTests.cs @@ -3,6 +3,7 @@ using System; using System.IO; using System.Linq; using System.Reflection; +using System.Threading; using System.Threading.Tasks; using GameCult.Caching; using GameCult.Caching.MessagePack; @@ -434,9 +435,10 @@ namespace GameCult.Caching.Tests } var manifest = CultDocumentMessagePackSerialization.DeserializeSnapshot(File.ReadAllBytes(filePath)); - Assert.That(manifest.FormatVersion, Is.EqualTo("cultcache.store.v3.directory-immutable-pages")); + Assert.That(manifest.FormatVersion, Is.EqualTo("cultcache.store.v4.directory-content-addressed-pages")); Assert.That(manifest.Records, Has.Length.EqualTo(2)); - Assert.That(manifest.Records.All(record => record.Payload.Length == 0), Is.True); + Assert.That(manifest.Records.All(record => record.Payload.Length == 32), Is.True, + "the hot index carries only the SHA-256 page identity, never the document body"); var coldPath = Directory.GetFiles(recordsPath, "*.msgpack") .Single(path => string.Equals( @@ -469,7 +471,7 @@ namespace GameCult.Caching.Tests var finalManifest = CultDocumentMessagePackSerialization.DeserializeSnapshot(File.ReadAllBytes(filePath)); Assert.That(finalManifest.Records, Has.Length.EqualTo(3)); Assert.That(finalManifest.Records.Any(record => record.Key == cold.Key.Value), Is.True); - Assert.That(finalManifest.Records.All(record => record.Payload.Length == 0), Is.True); + Assert.That(finalManifest.Records.All(record => record.Payload.Length == 32), Is.True); } finally { @@ -713,6 +715,130 @@ namespace GameCult.Caching.Tests } } + [Test] + public async Task DirectoryMessagePackBackingStore_SameTimestampPayload_CannotOverwriteCommittedPageBeforeManifest() + { + var filePath = Path.Combine(Path.GetTempPath(), $"cultlib-tests-{Guid.NewGuid():N}.cc"); + var recordsPath = DirectoryMessagePackBackingStore.DefaultRecordDirectoryPath(filePath); + try + { + const string storedAt = "2026-08-19T00:00:00.0000000+00:00"; + var store = new DirectoryMessagePackBackingStore(filePath, recordsPath); + var cache = new CultCache(); + cache.AddBackingStore(store); + var key = new CultRecordKey("record:atomic:same-timestamp"); + var descriptor = CultDocumentRegistry.Shared.GetRequired(); + store.Push(new CultStoredDocument( + key, + storedAt, + descriptor, + new NamedTestEntry { Name = "same", Value = "old" })); + store.PushAll(); + + store.Push(new CultStoredDocument( + key, + storedAt, + descriptor, + new NamedTestEntry { Name = "same", Value = "new" })); + store.FlushStageProbe = (stage, _) => + { + if (string.Equals(stage, DirectoryMessagePackBackingStore.BeforeManifestCommitStage, StringComparison.Ordinal)) + throw new IOException("injected crash before same-timestamp manifest commit"); + }; + Assert.That(() => store.PushAll(), Throws.TypeOf()); + + using var reopened = await CultCacheMessagePack.OpenAsync( + filePath, + new CultCacheOpenOptions { UseDirectoryStore = true }); + Assert.That(reopened.Get(key)?.Value, Is.EqualTo("old")); + } + finally + { + if (File.Exists(filePath)) File.Delete(filePath); + if (Directory.Exists(recordsPath)) Directory.Delete(recordsPath, recursive: true); + } + } + + [Test] + public async Task DirectoryMessagePackBackingStore_MutationDuringFlush_RemainsDirtyAndCommitsNextGeneration() + { + var filePath = Path.Combine(Path.GetTempPath(), $"cultlib-tests-{Guid.NewGuid():N}.cc"); + var recordsPath = DirectoryMessagePackBackingStore.DefaultRecordDirectoryPath(filePath); + try + { + var store = new DirectoryMessagePackBackingStore(filePath, recordsPath); + var cache = new CultCache(); + cache.AddBackingStore(store); + var first = await cache.UpsertAsync(new NamedTestEntry { Name = "first", Value = "one" }); + using var flushEntered = new ManualResetEventSlim(); + using var writerAttempting = new ManualResetEventSlim(); + store.FlushStageProbe = (stage, _) => + { + if (!string.Equals(stage, DirectoryMessagePackBackingStore.BeforeManifestCommitStage, StringComparison.Ordinal)) + return; + flushEntered.Set(); + Assert.That(writerAttempting.Wait(TimeSpan.FromSeconds(5)), Is.True); + }; + + var flush = Task.Run(() => store.PushAll()); + var writer = Task.Run(async () => + { + Assert.That(flushEntered.Wait(TimeSpan.FromSeconds(5)), Is.True); + writerAttempting.Set(); + return await cache.UpsertAsync(new NamedTestEntry { Name = "second", Value = "two" }); + }); + await flush; + var second = await writer; + + Assert.That(store.IsDirty, Is.True, "the mutation blocked behind flush must remain pending"); + store.FlushStageProbe = null; + store.PushAll(); + using var reopened = await CultCacheMessagePack.OpenAsync( + filePath, + new CultCacheOpenOptions { UseDirectoryStore = true }); + Assert.That(reopened.Get(first.Key)?.Value, Is.EqualTo("one")); + Assert.That(reopened.Get(second.Key)?.Value, Is.EqualTo("two")); + } + finally + { + if (File.Exists(filePath)) File.Delete(filePath); + if (Directory.Exists(recordsPath)) Directory.Delete(recordsPath, recursive: true); + } + } + + [Test] + public async Task DirectoryMessagePackBackingStore_ConcurrentInstances_MergeUnderOneCommitLease() + { + var filePath = Path.Combine(Path.GetTempPath(), $"cultlib-tests-{Guid.NewGuid():N}.cc"); + var recordsPath = DirectoryMessagePackBackingStore.DefaultRecordDirectoryPath(filePath); + try + { + var firstStore = new DirectoryMessagePackBackingStore(filePath, recordsPath); + var firstCache = new CultCache(); + firstCache.AddBackingStore(firstStore); + var secondStore = new DirectoryMessagePackBackingStore(filePath, recordsPath); + var secondCache = new CultCache(); + secondCache.AddBackingStore(secondStore); + var first = await firstCache.UpsertAsync(new NamedTestEntry { Name = "first-process", Value = "one" }); + var second = await secondCache.UpsertAsync(new NamedTestEntry { Name = "second-process", Value = "two" }); + + await Task.WhenAll( + Task.Run(() => firstStore.PushAll()), + Task.Run(() => secondStore.PushAll())); + + using var reopened = await CultCacheMessagePack.OpenAsync( + filePath, + new CultCacheOpenOptions { UseDirectoryStore = true }); + Assert.That(reopened.Get(first.Key)?.Value, Is.EqualTo("one")); + Assert.That(reopened.Get(second.Key)?.Value, Is.EqualTo("two")); + } + finally + { + if (File.Exists(filePath)) File.Delete(filePath); + if (Directory.Exists(recordsPath)) Directory.Delete(recordsPath, recursive: true); + } + } + [Test] public async Task DirectoryMessagePackBackingStore_PullsOnlyExternalRecordDeltas() { diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.dll index dd41e76d91054b0af3171d5e1cbd967af00caa14..b279cd097384209b114e381122167efe477e350e 100644 GIT binary patch literal 47104 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 z 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 stage emitted after all pages exist and before manifest finality. public const string BeforeManifestCommitStage = "before-manifest-commit"; + /// Read-probe stage emitted while the selected manifest generation is leased. + public const string AfterManifestReadStage = "after-manifest-read"; private const string LegacyIndexedFormatVersion = "cultcache.store.v2.directory-indexed"; private const string LegacyMetadataPageFormatVersion = "cultcache.store.v3.directory-immutable-pages"; private const string IndexedFormatVersion = "cultcache.store.v4.directory-content-addressed-pages"; @@ -46,6 +48,9 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore /// Optional deterministic fault/progress hook for durability tests and host diagnostics. public Action? FlushStageProbe { get; set; } + /// Optional deterministic read hook for generation-consistency tests and host diagnostics. + public Action? ReadStageProbe { get; set; } + /// /// Creates a paged MessagePack backing store. /// @@ -86,46 +91,50 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore startupPhase.Restart(); } - _recordDirectory.Refresh(); - if (!File.Exists(_manifestFile.FullName) && !_recordDirectory.Exists) - { - SetLastSchemaMigrationReports(Array.Empty()); - IsDirty = false; - return; - } - - var manifest = ReadManifest(); - Trace($"manifest records={manifest.Records.Length}"); - _durableCatalog = manifest.SchemaCatalog; var reports = new List(); var loaded = new Dictionary(StringComparer.Ordinal); - var indexed = string.Equals(manifest.FormatVersion, IndexedFormatVersion, StringComparison.Ordinal) || - string.Equals(manifest.FormatVersion, LegacyMetadataPageFormatVersion, StringComparison.Ordinal) || - string.Equals(manifest.FormatVersion, LegacyIndexedFormatVersion, StringComparison.Ordinal); - if (indexed) + using (AcquireCommitLease()) { - _manifestUsesImmutablePages = string.Equals(manifest.FormatVersion, IndexedFormatVersion, StringComparison.Ordinal); - _manifestUsesMetadataPages = string.Equals(manifest.FormatVersion, LegacyMetadataPageFormatVersion, StringComparison.Ordinal); - _needsIndexUpgrade = !_manifestUsesImmutablePages; - _durableIndex = manifest.Records - .Where(record => !string.IsNullOrWhiteSpace(record.Key)) - .GroupBy(record => record.Key, StringComparer.Ordinal) - .ToDictionary(group => group.Key, group => group.Last(), StringComparer.Ordinal); + _recordDirectory.Refresh(); + if (!File.Exists(_manifestFile.FullName) && !_recordDirectory.Exists) + { + SetLastSchemaMigrationReports(Array.Empty()); + IsDirty = false; + return; + } - LoadIndexedRecords(manifest, loaded, reports); - Trace($"indexed-pages loaded={loaded.Count}"); - } - else - { - // V1 manifests have no page index. Hydrate once to discover the durable keys; - // the next flush replaces this compatibility path with the indexed manifest. - _needsIndexUpgrade = true; - var legacyRecords = LoadLegacyRecords(manifest, loaded, reports); - _durableIndex = legacyRecords - .Where(record => !string.IsNullOrWhiteSpace(record.Key)) - .GroupBy(record => record.Key, StringComparer.Ordinal) - .ToDictionary(group => group.Key, group => ToIndexRecord(group.Last()), StringComparer.Ordinal); - Trace($"legacy-pages loaded={loaded.Count}"); + var manifest = ReadManifest(); + ReadStageProbe?.Invoke(AfterManifestReadStage); + Trace($"manifest records={manifest.Records.Length}"); + _durableCatalog = manifest.SchemaCatalog; + var indexed = string.Equals(manifest.FormatVersion, IndexedFormatVersion, StringComparison.Ordinal) || + string.Equals(manifest.FormatVersion, LegacyMetadataPageFormatVersion, StringComparison.Ordinal) || + string.Equals(manifest.FormatVersion, LegacyIndexedFormatVersion, StringComparison.Ordinal); + if (indexed) + { + _manifestUsesImmutablePages = string.Equals(manifest.FormatVersion, IndexedFormatVersion, StringComparison.Ordinal); + _manifestUsesMetadataPages = string.Equals(manifest.FormatVersion, LegacyMetadataPageFormatVersion, StringComparison.Ordinal); + _needsIndexUpgrade = !_manifestUsesImmutablePages; + _durableIndex = manifest.Records + .Where(record => !string.IsNullOrWhiteSpace(record.Key)) + .GroupBy(record => record.Key, StringComparer.Ordinal) + .ToDictionary(group => group.Key, group => group.Last(), StringComparer.Ordinal); + + LoadIndexedRecords(manifest, loaded, reports); + Trace($"indexed-pages loaded={loaded.Count}"); + } + else + { + // V1 manifests have no page index. Hydrate once to discover the durable keys; + // the next flush replaces this compatibility path with the indexed manifest. + _needsIndexUpgrade = true; + var legacyRecords = LoadLegacyRecords(manifest, loaded, reports); + _durableIndex = legacyRecords + .Where(record => !string.IsNullOrWhiteSpace(record.Key)) + .GroupBy(record => record.Key, StringComparer.Ordinal) + .ToDictionary(group => group.Key, group => ToIndexRecord(group.Last()), StringComparer.Ordinal); + Trace($"legacy-pages loaded={loaded.Count}"); + } } foreach (var pair in loaded) @@ -175,30 +184,39 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore private void PullSelectedCore(Func selector) { if (selector == null) throw new ArgumentNullException(nameof(selector)); - var manifest = ReadManifest(); - if (!string.Equals(manifest.FormatVersion, IndexedFormatVersion, StringComparison.Ordinal) && - !string.Equals(manifest.FormatVersion, LegacyMetadataPageFormatVersion, StringComparison.Ordinal) && - !string.Equals(manifest.FormatVersion, LegacyIndexedFormatVersion, StringComparison.Ordinal)) + var fallbackToFullPull = false; + CultPersistedRecord[] selected = Array.Empty(); + var loaded = new Dictionary(StringComparer.Ordinal); + var reports = new List(); + using (AcquireCommitLease()) + { + var manifest = ReadManifest(); + ReadStageProbe?.Invoke(AfterManifestReadStage); + fallbackToFullPull = !string.Equals(manifest.FormatVersion, IndexedFormatVersion, StringComparison.Ordinal) && + !string.Equals(manifest.FormatVersion, LegacyMetadataPageFormatVersion, StringComparison.Ordinal) && + !string.Equals(manifest.FormatVersion, LegacyIndexedFormatVersion, StringComparison.Ordinal); + if (!fallbackToFullPull) + { + _manifestUsesImmutablePages = string.Equals(manifest.FormatVersion, IndexedFormatVersion, StringComparison.Ordinal); + _manifestUsesMetadataPages = string.Equals(manifest.FormatVersion, LegacyMetadataPageFormatVersion, StringComparison.Ordinal); + _needsIndexUpgrade = !_manifestUsesImmutablePages; + _durableCatalog = manifest.SchemaCatalog; + _durableIndex = manifest.Records + .Where(record => !string.IsNullOrWhiteSpace(record.Key)) + .GroupBy(record => record.Key, StringComparer.Ordinal) + .ToDictionary(group => group.Key, group => group.Last(), StringComparer.Ordinal); + selected = manifest.Records + .Where(record => selector(ToMetadata(record))) + .OrderBy(record => record.Key, StringComparer.Ordinal) + .ToArray(); + LoadRecordPages(selected, manifest.SchemaCatalog, loaded, reports); + } + } + if (fallbackToFullPull) { PullAllCore(); return; } - - _manifestUsesImmutablePages = string.Equals(manifest.FormatVersion, IndexedFormatVersion, StringComparison.Ordinal); - _manifestUsesMetadataPages = string.Equals(manifest.FormatVersion, LegacyMetadataPageFormatVersion, StringComparison.Ordinal); - _needsIndexUpgrade = !_manifestUsesImmutablePages; - _durableCatalog = manifest.SchemaCatalog; - _durableIndex = manifest.Records - .Where(record => !string.IsNullOrWhiteSpace(record.Key)) - .GroupBy(record => record.Key, StringComparer.Ordinal) - .ToDictionary(group => group.Key, group => group.Last(), StringComparer.Ordinal); - var selected = manifest.Records - .Where(record => selector(ToMetadata(record))) - .OrderBy(record => record.Key, StringComparer.Ordinal) - .ToArray(); - var loaded = new Dictionary(StringComparer.Ordinal); - var reports = new List(); - LoadRecordPages(selected, manifest.SchemaCatalog, loaded, reports); PublishSelected(loaded, selected.Select(record => record.Key).ToHashSet(StringComparer.Ordinal)); SetLastSchemaMigrationReports(reports); IsDirty = !_dirtyKeys.IsEmpty || !_deletedKeys.IsEmpty; @@ -438,7 +456,7 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore ? MetadataRecordPath(metadata) : LegacyRecordPath(metadata.Key); if (!File.Exists(path)) - return; + throw new InvalidDataException($"Committed record page '{path}' is missing from the selected manifest generation."); var pagePayload = ReadAllBytesShared(path); if (_manifestUsesImmutablePages && !HashPayload(pagePayload).SequenceEqual(metadata.Payload)) @@ -788,6 +806,7 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore private FileStream AcquireCommitLease() { + Directory.CreateDirectory(_recordDirectory.FullName); var lockPath = Path.Combine(_recordDirectory.FullName, ".commit.lock"); var started = Stopwatch.StartNew(); while (true) diff --git a/tests/GameCult.Caching.Tests/BackingStoreTests.cs b/tests/GameCult.Caching.Tests/BackingStoreTests.cs index e43fa7b6..ee833f17 100644 --- a/tests/GameCult.Caching.Tests/BackingStoreTests.cs +++ b/tests/GameCult.Caching.Tests/BackingStoreTests.cs @@ -839,6 +839,103 @@ namespace GameCult.Caching.Tests } } + [Test] + public async Task DirectoryMessagePackBackingStore_ReaderLeasesManifestUntilEveryReferencedPageIsHydrated() + { + var filePath = Path.Combine(Path.GetTempPath(), $"cultlib-tests-{Guid.NewGuid():N}.cc"); + var recordsPath = DirectoryMessagePackBackingStore.DefaultRecordDirectoryPath(filePath); + try + { + var key = new CultRecordKey("record:reader-generation"); + var writerStore = new DirectoryMessagePackBackingStore(filePath, recordsPath); + var writerCache = new CultCache(); + writerCache.AddBackingStore(writerStore); + await writerCache.UpsertAsync( + new NamedTestEntry { Name = "generation", Value = "old" }, + new CultRecordHandle(key)); + writerStore.PushAll(); + + var readerStore = new DirectoryMessagePackBackingStore(filePath, recordsPath); + var readerCache = new CultCache(); + readerCache.AddBackingStore(readerStore); + using var manifestRead = new ManualResetEventSlim(); + using var releaseReader = new ManualResetEventSlim(); + readerStore.ReadStageProbe = stage => + { + if (!string.Equals(stage, DirectoryMessagePackBackingStore.AfterManifestReadStage, StringComparison.Ordinal)) + return; + manifestRead.Set(); + Assert.That(releaseReader.Wait(TimeSpan.FromSeconds(5)), Is.True); + }; + + var read = Task.Run(() => readerStore.PullAll()); + Assert.That(manifestRead.Wait(TimeSpan.FromSeconds(5)), Is.True); + await writerCache.UpsertAsync( + new NamedTestEntry { Name = "generation", Value = "new" }, + new CultRecordHandle(key)); + var write = Task.Run(() => writerStore.PushAll()); + Assert.That(write.Wait(TimeSpan.FromMilliseconds(100)), Is.False, + "writer must wait while a reader hydrates its selected manifest generation"); + + releaseReader.Set(); + await Task.WhenAll(read, write); + Assert.That(readerCache.Get(key)?.Value, Is.EqualTo("old")); + + using var reopened = await CultCacheMessagePack.OpenAsync( + filePath, + new CultCacheOpenOptions { UseDirectoryStore = true }); + Assert.That(reopened.Get(key)?.Value, Is.EqualTo("new")); + } + finally + { + if (File.Exists(filePath)) File.Delete(filePath); + if (Directory.Exists(recordsPath)) Directory.Delete(recordsPath, recursive: true); + } + } + + [Test] + public async Task DirectoryMessagePackBackingStore_ReleasesGenerationLeaseBeforePublishingObservers() + { + var filePath = Path.Combine(Path.GetTempPath(), $"cultlib-tests-{Guid.NewGuid():N}.cc"); + var recordsPath = DirectoryMessagePackBackingStore.DefaultRecordDirectoryPath(filePath); + try + { + var writerStore = new DirectoryMessagePackBackingStore(filePath, recordsPath); + var writerCache = new CultCache(); + writerCache.AddBackingStore(writerStore); + await writerCache.UpsertAsync(new NamedTestEntry { Name = "source", Value = "one" }); + writerStore.PushAll(); + + var readerStore = new DirectoryMessagePackBackingStore(filePath, recordsPath); + var readerCache = new CultCache(); + readerCache.AddBackingStore(readerStore); + var observerRan = false; + using var subscription = readerStore.EntryAdded.Subscribe(_ => + { + if (observerRan) + return; + observerRan = true; + readerCache.UpsertAsync(new NamedTestEntry { Name = "observer", Value = "two" }) + .GetAwaiter() + .GetResult(); + readerStore.PushAll(); + }); + + Assert.That(() => readerStore.PullAll(), Throws.Nothing); + Assert.That(observerRan, Is.True); + using var reopened = await CultCacheMessagePack.OpenAsync( + filePath, + new CultCacheOpenOptions { UseDirectoryStore = true }); + Assert.That(reopened.GetAll().Select(value => value.Name), + Is.EquivalentTo(new[] { "source", "observer" })); + } + finally + { + if (File.Exists(filePath)) File.Delete(filePath); + if (Directory.Exists(recordsPath)) Directory.Delete(recordsPath, recursive: true); + } + } + [Test] public async Task DirectoryMessagePackBackingStore_PullsOnlyExternalRecordDeltas() { diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.dll index b279cd097384209b114e381122167efe477e350e..1deb800477b19261d5e7ac968d3cda450b042687 100644 GIT binary patch delta 22197 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 delta 637 zcmV-@0)qX3>;Zu60g!wYsFi+q{&)3Cpxke0Ex z5=E#D;Q{e5UXSe&>m6%%Oyp1EH~2ENE<_0z$w=7;OWrwi&e7S?r0LOK&*4Fu!X zPevi98o#o5Kv%$;t%aPxN>Jc(!=^PoXmbEh8}UIBF4Mnw-gh*I2VG!S!F?Z;nv31v z;9Mp@iNgnq&hsL5?V{}Yg0{j4pdY0>pps-E*s>CvPie?{X_*-RdP9?jxPuDaMI zZj0-VEMcJkA!>WiRjpej-@m~vDZ+|e7~aQ-dnk$zk#rBQ(wq^q+R$!be-S>(a5gZ4X&fP2E diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Logging.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Logging.dll index be0edb36bdd2b942c5c65bce2fe6491e7effc4e5..bc67fc77ad5d50d767e73d7960b8ba01bd556024 100644 GIT binary patch delta 290 zcmZoLX)u}4!SZ}ha_7b#Ck{r_&F49OvIw|eh+2L5SCHe%S5`$cS_Kq0-{5Uvv@q5) zU|=v|WY9O%Gte_N)=o`Lv@kNUurN2bOffODG&Hs}PfRs1w@6J*GfhcMO)*I}OG&aw zPMJJ`{|?I{iwA9!3j_iL4n8z9(J5i`=<{WKemG7`bn*p(Mg^!KhaXfBsG4oNy5W}z zfo6v+%O`x^Tqr2Z$Z5*Jz`zK^rkke=9cE-S-W)Ab%@}OVpv{m9goz9m3`PtlK+=N2 z90)BLQh+=&AZ^HC3?$8gDpDB?fV2fzeHw!)Pz6W~q%Ik#GKC=tD3{ETGFem16li?B H*g|Fi-6c{a delta 290 zcmZoLX)u}4!IF06$gGV$P8^ITo6mFnWD%IcyqqOM=C%8@9EFzary_T6zQNnTXknyh zz`$U_$e?eiXP{?lq-~LCWMG_ZXl9z0YLS?fnrND6X_lB~l4xO`WME-oWNc}aoRpeo zWHEUH{~Z=L*=3t27YGCh82TH(__6V?`|fwIcW!<8vvBeSfkp+WAiFhG5UAStH+PBR zuB7a}OH(eM*jy+m%gAZMz`(!=#3q}k3ms-;G};_3Qq34_#GuV!!H~#c#9+W+%#h4r z$Y91`%8MelK2&l^vNG1bCQi1YD3>K3$ N#Y}<5$BQjw1^@=dS!n?ZB}_ z4tpPYT|KtwyB5WJ7k?vL9ABV;&Nl@B0IihIY8x>S#_xf=!{Ad(lU=8AVmk?i)Fq*i zK!{WKP6W~4kn-s?I%$aA>DR{XIc zM*)TOyY*pOPZfVhP+k)}V}xx06dfRl_clwR+wet&&QJvLASttCOHgA63foA)PWcc> z2^3V}H}(P0X?SL9p&+n63UIllNktoNju2=ozLtcm{4X`{+nU3JHnKCY?4nS8xx39C zskEeoy}L}IUob|h3)@}%8IWE7yj%FXLDyZ21TI>kSEGNL1XVy`HG2JZFvXQ@+LYy8 zkM&5FFw*~knl7-ZqzC!_0{0{cD{^t&ALZTV(uX)4{ehwi-27JIlIzA2G`2Mc3!9p5 zO!AbSP$*Fmls>?swQ|SBaJ3t@w4xAq)lRZ;c6OSLhjTu<(uaEOE82en-w@&K?PNBa zPUm`ZK0kjsollX*(-~2DrjhhSo$F$z^l;sW;B~9|ZMemnk`3A2#-ZV?Cl*V4A+7e{ zXqqLBf;(f{_{icz_bJ%X5sWI4CSK&ZVX4|8Q@+lB6`l7-Vg2%N`@c~7Bkq^)TeccL z2Nqg*O*a8eO-?{rj4?}jKL7y(fT(*SWN%}2ZDo^b2XiQ8WnnlnG&ndnH#uZ9HaRgf fIX7WtFgG}5Wo9*GVP#}AV>V=BIAdh91PDYO{TUXg delta 593 zcmV-X0$$b*`Ef=arn9k--2{JOx?7TpiFA*=)GNN{ z6z%fKJE$<4AfsYjsh*g8uIYz?&Nl@B0IihIYTPgo#_xf=!?358Huh%IO`Sg!(k%&v z1WGp99!d`*c`Ogel99#@ex$xepR8!NUA%1rF05{nW`5uB%}9BEwAXcbkmqoTo%ka| zjsgmm@79NDJ=A|3LHm;62_tL+K=pti-rFpNZo?NfIzth}gQU!gEkT1lXzU^ZJMBXt zEug5zZ|no0E8&T)1w~+e6yR!0lbSZ#93jwFd@Tu=`9Esjw>5_cU1Voq*+-$~Vt1R} zQ)NjDdv}pSzhI2iDBGX^9gto9x?A|BMb}@61Xi8Ui%EY&f;ynEp1k}zn&K)pUCQ!q zz`7?(80mjNZ6DawGJyQ}4tFF7D{^t&AMM@d(uX)6{ehwm-2PGFlAG2Nw6-$_l}$}I zCV9$EC{(BkDj#6cS-E93UhSGKttiA@wc~7>&1czkJm;gUd}!9bqJ0kds=(RwL?55d zD=JVC&hdZj6stE_yj9bpn4O%>w4!QOjMx1XeA($?8*Z?nWJ7klacDg2fyL5ZNUJ?K znr5j)!JRQ}ePr>We++i=8YZ0W@R{GVr5}9 fVL3KoW;9_qH)1e2I5IOiGGk(8W->Ul1PDYOxuhN5 diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.dll index 477716731b9682725ad61241d001cf31b06c6be3..96f9481b7cfcfe45c8b580726362f6404eedbaa0 100644 GIT binary patch delta 316 zcmZpuX{edd!Lr6*?ZU<$14%~H$$KSL8BI4omi#Fsuv9qvA?Nke4(*8t{&{YFQ?U7s z&LS2&V?6@~1`|dGeM3D1JyT=t)YL=^BNGb?b92iS6EjOgV@vbIR0DI1)YLT7l*H5& zlVr1$B#Yz}1_n7s2Fc0uOe8lyHGIyB$$20|ch|i#_(4Y~$HD=VDUEeXW+s z1}2jgpn@|GLIpvpHH=pHp6Z-%eG%KVJDVSytY+jiWnf@n1Y*<8)6Jxr7>ze?wph&= zY|Nm|kP3u}3>FMV3?@L*g25aJEg4dPJTo9|$Y2a4&4DUX84Q551z3F=gDFr2NDQPd j8K^RaAqgm#%#bp9qm?PEF@qk1!Dc}lF~-e|Hvbs`H#1>B delta 316 zcmZpuX{edd!SXrO=Ih2D14%}c$$KSL8BI1nmi#Fs;CREjiu3my?~V3vmxv_v-rD>| zXAz5?k)8nqg9#&pzM-Cho~e!g?W;Jg@uu^ zrBQNHYMPM+1A`nRgXH9SCX$<<8a`)aIl?r5)#MAt0Rlgj9wg-4zUHuAH~EyCXT|Kv z1}2jgpn?-%fwACVr8VQBwVNNCtY+jiVPIfj1Y(oT)6Jxr7>zb>wph&= zY{a0=V8M{cV8md+V9b!rV8~#`V9JojkO~$}0@8^X7UN8lJV}9^(PC)dDum36*UPbxatD74DG0}L#`bT++vAzN zXJ8C-kk8vj=Qk0(jz9x;OR(yJ_Id>X0IgKpYTG~%eGm8_20bODSvidp+es*-E(wLY zw7Iwsr4OUskufs0n?Fl&EEPzMy&+0nP1SzO6go2tCq z;JPPE80mkAmR;bgmJO00-(gOIupk%v{%G%3mp;VZsozo5ftTA353`Rb{7f*9pIg>2 zYpu*F)({A-aFZJD9BJ_ZN+00Kv2?u&FEs^lBvH^A3DU`zX*?saPoRInT*F%GrE|bo=wL{!|{ZuJU2*Y zq%TY{(PnquPr;j3Z}#mD8%lYq6sSt^s#Vy#lRmOo+Arl|4;iO%G$^<==}RA3eCVEn z&0axPi!9@1o>we&TPW?D{I~l&Jw9;J3--(7ZgU)wr8P5uc-yiy@FlR&%p1B5ST*DX zw8a=zs{09(8VY|XWo2PFGBh|iH#a$CG&VUgGdVY5WiU55Wo2eHWMO4wG-EboVmM=D zv%w0e0vNS%*qH#p0RT}jq8)Rxqe_$m#*!jT(RGu74J{ZKYfOm%fB*m##Pf4!=D0zz zY`V=K*2SumfejrVWNd5z00BbBs;B@U0RYhY5Olu2Q$vAEm5eCs*Z`9O4i^~bykm&~ zfB*nT&|0h0`cgru>N;|mg%BZ=Fb)(L#ym3H000XB!ReIawq8?1v{UlqXBcbOlUxoO l7)vsk`~W}*00kPrmpQ^EtatD7v0OVB!B1VuI4Sk?$ zJV_>Je?4ZC|BbyjCH2PrtC3KF_Id>X0IgKpYTG~%eK+_Y20bODSvgLfDi;c=OG2P7 zZ7%LZ>BDF>k_J}0W_OgJPwH><%gV~Fv1tn`cpn7Po;l~}%rI$syw@`xr72utEAF@= zOCE)axBbU>9&3LNpj|=mf&n%F$U8s~=ZuQb4SZgsttfyvkXTu=A!x7zjcp)ctDX0x z1#+tKnVko;1-!5^kP{de1i0L=Nlj~Q4&Z4c-b=z&`WMgpj%GY+1KSE7x**hC?!Kyf zDh+92XD=i4D~3Q#Zn}#<0qXkK-P|=RwB5Cc=e!jV^ z8C>wW^08VY|XIAJm{Gh;C}HD+ZvVPa)rHDNh6VP-U8I5%Q2I5;vhIWl8nWo9xs zv%w0e0vN8@hM)kz0RV{C#vIKwOGTR(lW)#k;scX`4J{Zs^kts_fB*o{+n5nVm8?mJ zVqX@?YgFQsfejrVWNd5z00GN61=|210RWD}XKW?++(nqfZj;KkHe-_k4i^|^)Wn(q zfB*oL1E&O79P3AxY#@Z!%2~UUFb)(L+B06m000XBXXy7{J*{;?xrBxe1(J2vlUxoO l7ToB%)w0LW1F4t6gULX-21co3Izhm!#h6tkiZdLj4AYR~`x diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.dll index 6d06333d04a1f77851a053138468757cde03b199..65f566e9d3683aff583d28438c5dc911cf8f16f2 100644 GIT binary patch delta 384 zcmZqJq1CWMYeEOhF&m@XjXkYBjIBLPtv$@GJuIy~tgSt4TYK1l)G?Y)Z>?wdmo;TT z0Hgf~HY1Q}I{jlkyELO|J8uI!5OZwjZQ$I_EO7AUl*ilRf}OVne|nrQk$rvpm1fR; z_biO{3>X+p7#Z{p^$he(jkQx#6D^EPEG*2;EmKU)EDen<%@b1%%q>z=(@awmQ&UWm z%~Fyql2f*yO5)PfW6AonX5sWd6Sx8dUaK9Dxu2}%ut47beD(WXYo^CcMHie6BF ziUQRuzRZ2I>>@w=>)qnaI@`Zb?wdmo;HP z0Hgf~HY1Q}GW}ycyELOoJ8uI!5OZwjZQ$I_ERg=qfrW*Uv87RR zQfiu!#r9K4TzYyecWi_AP5(22D?osG|C2m5jYRKlvx;vW=`@%#J!T?TwE|Q$y9_D{ zRBzY$rK!5xe@Srb>s!*>zfa_v&cq4w57_P7r%&M$W@0qjzIqy0GGnk2gEoT&Ln4C_ zg8_pvLo$OQgBgPn6Y)-(xC3pdU}qd+)leYW%FBfsnP30qtvlhe|5W7)19u zjQfp{-G)i7yF- z)FmNMLrGHiq4Z(2JCe4ncFoSHL7&v$=$DmMTw~J~RO)>YX!p!HXU`6kWv2&S!$Fq8 zH8$c;OL7!YNWbYe<9e!p41@BT;29aV0LWWF5btdop7mXPURh}LZ|WhFZ#Kfc3~1Yt#vyZ2Gvy&U?${i)v(t6$g^~mUYw_+{@1;Cg%5S-6Ybv!Pl#~(dOV#@CNn+0oSmJ|CP<^n zl&HASNP4U;bv{+PzwU?Nb)$CQZy< zyn>_>S@S&0N+VU1r^?saFUMK@yf=9#*bR%j-N6;d%JT6RZDXv4Pr(Q+yr$cLWlc^% zS!7OQ-A}iVZUHogC}m|~I5IRiI5#&rWHdH8F*7+gVP!BkIAvvKHDqCBWHe(oWMVjD zWVh?|0kr}cwQ<;)0KfqNQ81z%bF!mKlmo_+B23YBm;Ltv9hcSj0T37$YfOm%fB*m# z#Pf4!=D0zzY`V=K*2Suq{r3SQe?rHqr~n`V0MPmnbiTe*LxD?`j412a07qeMWkYpr zbS_M9XJ=_{XD(!HYybcO=e%Qy0Du4hN6=cU)A~|Dsp>j%n1v7_M`3McLv?I)E>2~1 zcW-iQX>MmOWNd5z00B!fnEU`h2ml2d)Gj7&u1lBqiY)j{Ww}XnZ*XsDhoATXx1aa| FO)5Qbg0=tv delta 827 zcmV-B1H}C7#SHAl43K;j1Ha^MCMaP`wwiO=#ECGR+&xpifsnP30qtvl@aUaTq&t_P8BB< zQkR564JAq4hth}9Y9wvhi`f}9=#%;z{j#!(Yi!zrO1%#P?VdU3?Ac+m?DU{(Jjyb- z##a1kO^yNzm9P8FxE>pS&7gcq@PrIo02Cb{i1#Lq&@Ft?psR^NJV>mpv>~wAfx?yv zv{OC=QUV1v_)Yr&=t_9f#y~+}JPYV*%O(vyYiou;Tk&2JuCqUQK6EtWQOnxZ@X)c4 zz1sgx@2N7RM093A$*7juK0Mf-0bBl^lN=%;G9t zx3S8*9j<#agiQZJwC;kg8`&ZG@g0^V2rF{jzmM|n`OpU*PW_fx1-;&Pc$6$!BTM3D z4yESJb_s#dh_(clxPcM{3uNlmS=-k17mY@k9JdUW4{(Q;7OhF(WIT%Pk_fDW|4K?Y zIUa2DRvTJT;Qb(f&(cXco2HZD*L~+IA8hXv&EE)5a-2@i)!D_Yq8tmt8D3ss^%C<} z#U#(C=a*AeP&Lhm>wXBnY}M}jZE}$`#yp(pQH!Dfr&%2!%h-Og2lhI9?OBTt-N#^( z7mzd}Yo2FWt)*#;RC$~Ia-7A_dtLN`{jj*(9b9p&EFaz$wAz&LDQKaEFX=X5ZOI8J zgUo5H`w6#?ZUHogC^%sV@F|aWkYpr zbS_M9XJ=_{XD(!HYybcOX4J%*0Du4hlmn*(SRCs|mTVw|*UDMDM`3McLv?I)E>2~1 zcW-iQX>MmOWNd5z00B7-X`BE+2mr`X^$vC~6+)BqjCc^2a)(KCZ*XsDhoATXx1aa| FO)3U$g^d6J diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.WebSockets.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.WebSockets.dll index 3b4141647f2625001e3f7284147352ff46905243..7cfbbf1329f9fc6a106ab8aff8cb25109f1391ed 100644 GIT binary patch delta 306 zcmZoDX(*Y{!4l0nZNtW%90^9#$v-7j8BI6KODggUY;bMg`A5~tb3%+oQ0D)oYc~gI z2(wxk>lrXGm@qQv8|oS8nHp=SrY2e#nOInun_H%sm{}ScTbd`P8kk$8rly&uB&MdA zB%7rqStO@yo~qo2MIbGcg)(UTkunG1!XH5Lz;%0C{FW+K|B*NSXsxq%s%)X$!FWGzL?k3Xm8`T{2K*3PTc5E}0=^ Z@=-HWR$~S|27}Fl7EFwr87=-Z0s!UmT$}&^ delta 306 zcmXYoF-yZx6ou~#tsn(Wafy_of`U*?UT$8}n@u+nECnasUP3bIR#(kfp@TG_gE;9b zRNgKs6cH@>0d*D~`~kY?Q_AI>%l*!|Stsk9c1y1}GyU7%zQsiTWvwuw7Uq{`&Go6; z_1SZ_*&Du(5AOz_s=Yc_CbT(#VBokmw|#7oMDE3I;HL@6D3QJl1DOg*&4?4B7h)VG zDU!Nas~V-{m~606wIU{L@Hpsc#9P=2CN^ouCPk?vozW bU!nF`lSJnTln(>Hj9>#-RWg`j^uvAu5T;q3 diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.dll index a6163a0a9f8604ad0c972867f36d0aab151753bc..40d4ec74585ecf0077d40ae478ebdbeed3720d96 100644 GIT binary patch delta 361 zcmZpeA>S}VenJO}x6zD0jXkYBjIBLPtv$?JdsvpeU^Ja>{F22LNL9XM(Fam1!BqRr zmn_?FzGSVh6=0RRqNkR(&U^azE}b7fsXMo4q_dgU*%|8@Fff=fGUyxX8R(fBYp13r zS{RvFSeTnzrkI#n8X8-gC#D*hTcoC@nWiMBrkEs~r6gG-r!X)`Ffs^FH{8uCy#3u% zwyp~-AAapWJ-ucddw_s2?~XMAY^U5dEh|f&7%c8K{mwS_b_JNI5mXeY-n*#nPc&1; zzapR1=X16#GG~Ql)jJ=&P*qA|^Ar%M{87vr#7)*eq z1%o*dS~8>nd1gS`kii&8ngdm&G8h193$Xe$22-F4kQhi^GEij-LlRIfnIUC*=m~aH XR$~S|27~Q_r`U@aw=Z3}fQVQZyU0e$JcuCq92M5JbD2TJXghX9C_<^mhNQp=WK_ne? z6Tv|c(Z0b=L`o+oq2QzlX3@dAs?So6yC3(v|5fXmYCUtXCs~QrFgaDp&m(d0-KSf2%LA}wGAqYCgVDULQc84-IJWB%3NVTw6>7J!6#sY|*ngCMCNA&7 zQUe!~pC{63rPG-|y0{vAc~axya|8S1JzGxq?0>$fEKRyojrG#(*frnfcqkD!004gg3;bkOy1jsVE}8EHNEn aTyZBr!^I{xV+3SS`A7>F5l1cji~azLj&X+o diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.pdb index 5e79480f43ace503c5386c5c7996034e19403c3b..e1aa9f03792f573dfed8ec058fba2760cdd7a35a 100644 GIT binary patch delta 744 zcmVD%+i#5QXmpd56JQEsb}b#)*Ft z3aLv%p$R2U(~HuJS?$?fQLVH{voZTfeT_a@(WW(af4~9jLZH!^?+ha`X*%5NIy^{I zy5Lsau!MzYLH?!>#&utR=|IZmpcMyN3n=S|Nt`oDl&dbWWzXi$Vue*h-8@Ao0h}T&wcrmDdA*?)$R)d#ccc$1v zmu<{)c7t^X0}gl&sOh{eE7^ej_)a$vrU%&2zmIbE>C*YIJNg}h^1At>!bNN37BZ(L zRO@j>l`gAc17A2_vsIuPA#fSnTsTi9*9d8Vf5dalue8AfeAqTWPDaV;Niy1<^WOG# z#Tc9a0bc<;eLbFkPA8LDK0ccrpUftV(PRn~r#T}ZtFt_ts(g3fkKX02+I*F3t`VD; z+(K5)f77D2Qo~EUis?8GR>hyQr zY1}^OtT*h(!S&{7ii6{3`L@+2r_Wvs7B0t?=dy+sQiekWNMhbkhsHDkx5hLAor@@C zWnnlnG&ndnH#uZ9HaRgfIX7WtFgG}5Wo9*GVP#}AV>V=BIAdhDi@*Y^0vNS%*qH#p z0RT}jq8)Rxqe_$m#*!jT(RG*pxB?xQYQq8$7#C|yi2#5A02IXYb7$tbL9uMQ%^%jq zs+az_0v(sH!vY2vLdUA803ZPX(E1Q`zP?jKflHN)DC^h&m(9Zh7Z~TfV~GHO002kO aTC3CgQbDQeI&zqW5Fv;B!vdH5!vl<#>SSgB delta 744 zcmVQr$; zA$3UzG@-<)dni4ORwHTXYFF%xV)RITjXqgfr!{u}fCJvc!p?s4`-a(N(sa1jb$F1b zaDkorVMUGtDiv>6!MGlOY8EiQAXuWnS^#+u2^_8XwsQKv%$$t%aPxdQsqVP1Bm5yjdX7+I(dR7wJE0-gj#b4?1C2!Mqox z=6w5@+*4`ED0_DvrC(5ln%wr&zXi$Vue+IVT6F!TYT&$6dNF8!NYMmTHiMU6cc!?K zt1f1Fx52t6ODOalP}>KtYTbbR_zt(E2n%wudLQH6)1?oxJNi9|3Ecis;jFWIM>>T$ znJ&-~)LhlWmO|-6gU%2%B!X3JbLj(A*pQ?`;gOzWe#Mp+6lB}{I2k3AaWdMSbK_QZ z#TeTE0bgY}9-WwfUGn=n+jSa=- zC3mDtAHK1xcE>%iTG|(Ev4_6K4_2V!*57Ttu=>z{3U+V=gIcwfX_{87b(bf`H|g)X z)3|-$d}X*A2iKdUDGrX?`MZv70iOda&3r*u0jq|bg0UzBlEl29hsHDkx5hLAor@?q zVKOi?V=*>0W@R{GVr5}9VL3KoW;9_qH)1e2I5IOiGGk(8W->Upi@*Y^0vN8@hM)kz z0RV{C#vIKwOGTR(lW)#k;scldxB?xQYQq8$7&-K1p8$XW0MOf*5k!@&Nrz%z7RhT= z;+Ouo0v(sH!vY2v%Q*$x03ZPXj>BhcCHLG#n8R+9%CqnMsAcWV-S-Xe)!vdH5!vl;v`C#|} diff --git a/unity/org.gamecult.cultlib/package.json b/unity/org.gamecult.cultlib/package.json index ad99d1ba..b441d31b 100644 --- a/unity/org.gamecult.cultlib/package.json +++ b/unity/org.gamecult.cultlib/package.json @@ -1,7 +1,7 @@ { "name": "org.gamecult.cultlib", "displayName": "CultLib", - "version": "1.0.52", + "version": "1.0.53", "unity": "2021.3", "description": "CultCache, CultNet, and CultMesh managed runtime assemblies for Unity.", "license": "MIT", From e80383c33f54e83e44bf9e4d2c5a612f802e819a Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 19 Aug 2026 01:36:23 +0200 Subject: [PATCH 104/283] Make CultCache transactions atomic to observers --- .../DirectoryMessagePackBackingStore.cs | 46 ++ .../Contracts/cultcache-persistence-format.md | 15 + src/GameCult.Caching/CultCache.cs | 424 ++++++++++++++---- src/GameCult.Networking/CultNetDatabase.cs | 239 +++++++--- .../BackingStoreTests.cs | 140 ++++++ .../NetworkingTests.cs | 54 +++ .../Plugins/GameCult.Caching.MessagePack.dll | Bin 47616 -> 49152 bytes .../Plugins/GameCult.Caching.MessagePack.pdb | Bin 21032 -> 21564 bytes .../Runtime/Plugins/GameCult.Caching.dll | Bin 86016 -> 95232 bytes .../Runtime/Plugins/GameCult.Caching.pdb | Bin 30208 -> 32688 bytes .../Runtime/Plugins/GameCult.Logging.dll | Bin 6656 -> 6656 bytes .../Runtime/Plugins/GameCult.Logging.pdb | Bin 9544 -> 9548 bytes .../Plugins/GameCult.Mesh.Quic.Native.dll | Bin 15872 -> 15872 bytes .../Plugins/GameCult.Mesh.Quic.Native.pdb | Bin 12316 -> 12320 bytes .../Runtime/Plugins/GameCult.Mesh.dll | Bin 695296 -> 695296 bytes .../Runtime/Plugins/GameCult.Mesh.pdb | Bin 205548 -> 205552 bytes .../GameCult.Networking.WebSockets.dll | Bin 14848 -> 14848 bytes .../Runtime/Plugins/GameCult.Networking.dll | Bin 510976 -> 517120 bytes .../Runtime/Plugins/GameCult.Networking.pdb | Bin 246920 -> 247876 bytes unity/org.gamecult.cultlib/package.json | 2 +- 20 files changed, 774 insertions(+), 146 deletions(-) diff --git a/src/GameCult.Caching.MessagePack/DirectoryMessagePackBackingStore.cs b/src/GameCult.Caching.MessagePack/DirectoryMessagePackBackingStore.cs index 4f1a2521..454a8ed8 100644 --- a/src/GameCult.Caching.MessagePack/DirectoryMessagePackBackingStore.cs +++ b/src/GameCult.Caching.MessagePack/DirectoryMessagePackBackingStore.cs @@ -253,6 +253,52 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore } } + /// + public override void CommitBatch( + IReadOnlyCollection upserts, + IReadOnlyCollection deletes, + bool soft) + { + lock (_mutationGate) + { + var previousEntries = Entries.ToDictionary(pair => pair.Key, pair => pair.Value, StringComparer.Ordinal); + var previousDirtyKeys = _dirtyKeys.Keys.ToArray(); + var previousDeletedKeys = _deletedKeys.Keys.ToArray(); + var wasDirty = IsDirty; + try + { + foreach (var entry in deletes) + { + Entries.TryRemove(entry.Key.Value, out _); + _dirtyKeys.TryRemove(entry.Key.Value, out _); + _deletedKeys[entry.Key.Value] = true; + } + foreach (var entry in upserts) + { + Entries[entry.Key.Value] = entry; + _dirtyKeys[entry.Key.Value] = true; + _deletedKeys.TryRemove(entry.Key.Value, out _); + } + IsDirty = true; + PushAllCore(soft); + } + catch + { + Entries.Clear(); + foreach (var pair in previousEntries) + Entries[pair.Key] = pair.Value; + _dirtyKeys.Clear(); + foreach (var key in previousDirtyKeys) + _dirtyKeys[key] = true; + _deletedKeys.Clear(); + foreach (var key in previousDeletedKeys) + _deletedKeys[key] = true; + IsDirty = wasDirty; + throw; + } + } + } + /// public override void PushAll(bool soft = false) { diff --git a/src/GameCult.Caching/Contracts/cultcache-persistence-format.md b/src/GameCult.Caching/Contracts/cultcache-persistence-format.md index 66d0e135..e7ffd54f 100644 --- a/src/GameCult.Caching/Contracts/cultcache-persistence-format.md +++ b/src/GameCult.Caching/Contracts/cultcache-persistence-format.md @@ -39,6 +39,21 @@ These are **not** domain fields and should not be exposed on app-facing types: Those belong to the CultCache persistence layer. +## Transaction Visibility + +An authoritative multi-record change uses `CultCache.ExecuteTransactionAsync`. +The executing async flow sees its buffered overlay while staging; other readers +and all observers continue to see the prior committed generation. The backing +store commits the complete batch before the live cache swaps to it. Observer +notifications run only after the transaction context and commit lock have been +released, so an observer-triggered write begins a separate transaction. + +An exception before durable finality discards the overlay. It cannot become +visible through a later flush. A transaction currently permits at most one +durable backing store because independent stores cannot provide one atomic +commit boundary. Applications that require authoritative writes may configure +`CultNetDatabase` to reject record-at-a-time writes outside this primitive. + ## Canonical Store Shape A persisted CultCache file should contain: diff --git a/src/GameCult.Caching/CultCache.cs b/src/GameCult.Caching/CultCache.cs index 21b437af..1d1dab81 100644 --- a/src/GameCult.Caching/CultCache.cs +++ b/src/GameCult.Caching/CultCache.cs @@ -7,6 +7,7 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Security.Cryptography; using System.Text; +using System.Threading; using System.Threading.Tasks; using GameCult.Logging; using R3; @@ -1278,6 +1279,9 @@ namespace GameCult.Caching private readonly ConditionalWeakTable _documentHandles = new(); private readonly Subject _changes = new(); private readonly CultCacheSoaStore _soa = new(); + private readonly SemaphoreSlim _transactionGate = new(1, 1); + private readonly AsyncLocal _ambientTransaction = new(); + private readonly object _stateGate = new(); private ILogger _logger = new NullLogger(); private bool _hasUnflushedMutations; @@ -1348,14 +1352,29 @@ namespace GameCult.Caching /// /// Gets all document instances currently held by the cache. /// - public IEnumerable AllEntries => _entries.Values.Select(entry => entry.Document); + public IEnumerable AllEntries + { + get + { + lock (_stateGate) + return VisibleStoredDocuments().Select(entry => entry.Document).ToArray(); + } + } /// /// Gets all stored document records currently held by the cache. /// - public IEnumerable AllStoredDocuments => - _entries.Values.OrderBy(entry => entry.Descriptor.SchemaName, StringComparer.Ordinal) - .ThenBy(entry => entry.Key.Value, StringComparer.Ordinal); + public IEnumerable AllStoredDocuments + { + get + { + lock (_stateGate) + return VisibleStoredDocuments() + .OrderBy(entry => entry.Descriptor.SchemaName, StringComparer.Ordinal) + .ThenBy(entry => entry.Key.Value, StringComparer.Ordinal) + .ToArray(); + } + } /// /// Gets the document registry used by this cache. @@ -1457,15 +1476,22 @@ namespace GameCult.Caching /// public void FlushAllBackingStores(bool soft = false) { - foreach (var store in _backingStores) - { - FlushBackingStore(store, soft); - } + if (_ambientTransaction.Value != null) + throw new InvalidOperationException("A CultCache transaction owns durable commit; do not flush inside its stage callback."); - RecomputeDirtyState(); - if (!IsDirty) + _transactionGate.Wait(); + try { - LastSuccessfulFlushAtUtc = DateTimeOffset.UtcNow; + foreach (var store in _backingStores) + FlushBackingStoreCore(store, soft); + + RecomputeDirtyState(); + if (!IsDirty) + LastSuccessfulFlushAtUtc = DateTimeOffset.UtcNow; + } + finally + { + _transactionGate.Release(); } } @@ -1489,6 +1515,22 @@ namespace GameCult.Caching throw new InvalidOperationException("Backing store is not attached to this cache."); } + if (_ambientTransaction.Value != null) + throw new InvalidOperationException("A CultCache transaction owns durable commit; do not flush inside its stage callback."); + + _transactionGate.Wait(); + try + { + FlushBackingStoreCore(store, soft); + } + finally + { + _transactionGate.Release(); + } + } + + private void FlushBackingStoreCore(CacheBackingStore store, bool soft) + { store.PushAll(soft); RecomputeDirtyState(); if (!store.IsDirty) @@ -1514,17 +1556,77 @@ namespace GameCult.Caching return Task.CompletedTask; } + /// + /// Runs a buffered cache mutation. Staged records are visible only to the executing + /// async flow. The durable backing store is committed before the live cache and its + /// observers advance; an exception discards the entire staged batch. + /// + public async Task ExecuteTransactionAsync(Func stageAsync, bool soft = false) + { + if (stageAsync == null) throw new ArgumentNullException(nameof(stageAsync)); + if (_ambientTransaction.Value != null) + { + await stageAsync().ConfigureAwait(false); + return; + } + + await _transactionGate.WaitAsync().ConfigureAwait(false); + var transaction = new CultCacheTransaction(); + IReadOnlyList<(CultStoredDocument Stored, object? Previous, bool Removed)> changes; + _ambientTransaction.Value = transaction; + try + { + await stageAsync().ConfigureAwait(false); + changes = CommitTransaction(transaction, soft); + } + finally + { + _ambientTransaction.Value = null; + _transactionGate.Release(); + } + + foreach (var change in changes) + PublishChange(change.Stored, change.Previous, change.Removed); + } + + /// Runs a value-producing buffered cache mutation. + public async Task ExecuteTransactionAsync(Func> stageAsync, bool soft = false) + { + if (stageAsync == null) throw new ArgumentNullException(nameof(stageAsync)); + T result = default!; + await ExecuteTransactionAsync(async () => + { + result = await stageAsync().ConfigureAwait(false); + }, soft).ConfigureAwait(false); + return result; + } + /// /// Adds or replaces a typed document and returns its record handle. /// public async Task> AddAsync(T document, CultRecordHandle? handle = null) { if (document == null) throw new ArgumentNullException(nameof(document)); - var stored = await AddStoredDocumentInternal( - CreateStoredDocument(typeof(T), document, handle?.Key), - source: null, - raiseUpdate: false); - return new CultRecordHandle(stored.Key); + if (_ambientTransaction.Value is { } transaction) + { + var staged = CreateStoredDocument(typeof(T), document, handle?.Key); + transaction.Stage(staged); + return new CultRecordHandle(staged.Key); + } + + await _transactionGate.WaitAsync().ConfigureAwait(false); + try + { + var stored = await AddStoredDocumentInternal( + CreateStoredDocument(typeof(T), document, handle?.Key), + source: null, + raiseUpdate: false).ConfigureAwait(false); + return new CultRecordHandle(stored.Key); + } + finally + { + _transactionGate.Release(); + } } /// @@ -1549,11 +1651,26 @@ namespace GameCult.Caching nameof(document)); } - var stored = await AddStoredDocumentInternal( - CreateStoredDocument(documentType, document, key), - source: null, - raiseUpdate: false).ConfigureAwait(false); - return stored.Key; + if (_ambientTransaction.Value is { } transaction) + { + var staged = CreateStoredDocument(documentType, document, key); + transaction.Stage(staged); + return staged.Key; + } + + await _transactionGate.WaitAsync().ConfigureAwait(false); + try + { + var stored = await AddStoredDocumentInternal( + CreateStoredDocument(documentType, document, key), + source: null, + raiseUpdate: false).ConfigureAwait(false); + return stored.Key; + } + finally + { + _transactionGate.Release(); + } } /// @@ -1572,9 +1689,15 @@ namespace GameCult.Caching /// public object? Get(CultRecordKey key) { - return _entries.TryGetValue(key.Value, out var stored) - ? stored.Document - : null; + lock (_stateGate) + { + if (_ambientTransaction.Value is { } transaction && + transaction.TryGet(key, out var staged)) + return staged?.Document; + return _entries.TryGetValue(key.Value, out var stored) + ? stored.Document + : null; + } } /// @@ -1607,17 +1730,13 @@ namespace GameCult.Caching /// public IEnumerable GetStoredDocuments() where T : class { - var type = typeof(T); - if (type.IsSealed) + lock (_stateGate) { - return _typeMaps.TryGetValue(type, out var exact) - ? exact.Values - : Enumerable.Empty(); + var type = typeof(T); + return VisibleStoredDocuments() + .Where(entry => type.IsAssignableFrom(entry.Descriptor.DocumentType)) + .ToArray(); } - - return _typeMaps - .Where(pair => type.IsAssignableFrom(pair.Key)) - .SelectMany(pair => pair.Value.Values); } /// @@ -1690,9 +1809,21 @@ namespace GameCult.Caching /// public void Remove(CultRecordHandle handle) { - if (_entries.TryGetValue(handle.Key.Value, out var stored)) + if (_ambientTransaction.Value is { } transaction) { - RemoveStoredDocumentInternal(stored, source: null, raiseUpdate: false); + transaction.Delete(handle.Key); + return; + } + + _transactionGate.Wait(); + try + { + if (_entries.TryGetValue(handle.Key.Value, out var stored)) + RemoveStoredDocumentInternal(stored, source: null, raiseUpdate: false); + } + finally + { + _transactionGate.Release(); } } @@ -1701,12 +1832,27 @@ namespace GameCult.Caching /// public bool Remove(CultRecordKey key) { - if (!_entries.TryGetValue(key.Value, out var stored)) + if (Get(key) == null) { return false; } - RemoveStoredDocumentInternal(stored, source: null, raiseUpdate: false); + if (_ambientTransaction.Value is { } transaction) + { + transaction.Delete(key); + return true; + } + + _transactionGate.Wait(); + try + { + if (_entries.TryGetValue(key.Value, out var stored)) + RemoveStoredDocumentInternal(stored, source: null, raiseUpdate: false); + } + finally + { + _transactionGate.Release(); + } return true; } @@ -1734,9 +1880,116 @@ namespace GameCult.Caching store.Dispose(); } + _transactionGate.Dispose(); _changes.Dispose(); } + private IEnumerable VisibleStoredDocuments() + { + if (_ambientTransaction.Value == null) + return _entries.Values.ToArray(); + + var visible = _entries.ToDictionary(pair => pair.Key, pair => pair.Value, StringComparer.Ordinal); + foreach (var pair in _ambientTransaction.Value.Mutations) + { + if (pair.Value == null) + visible.Remove(pair.Key); + else + visible[pair.Key] = pair.Value; + } + return visible.Values.ToArray(); + } + + private IReadOnlyList<(CultStoredDocument Stored, object? Previous, bool Removed)> CommitTransaction( + CultCacheTransaction transaction, + bool soft) + { + var mutations = transaction.Mutations + .OrderBy(pair => pair.Key, StringComparer.Ordinal) + .ToArray(); + if (mutations.Length == 0) + return Array.Empty<(CultStoredDocument, object?, bool)>(); + + if (_backingStores.Count > 1) + { + throw new InvalidOperationException( + "A CultCache transaction requires zero or one durable backing store; multiple stores cannot share one atomic commit boundary."); + } + + CultStoredDocument[] previous; + lock (_stateGate) + { + previous = mutations + .Select(pair => _entries.TryGetValue(pair.Key, out var stored) ? stored : null) + .Where(stored => stored != null) + .Cast() + .ToArray(); + } + + var upserts = mutations.Where(pair => pair.Value != null).Select(pair => pair.Value!).ToArray(); + var deleted = mutations + .Where(pair => pair.Value == null) + .Select(pair => previous.FirstOrDefault(stored => string.Equals(stored.Key.Value, pair.Key, StringComparison.Ordinal))) + .Where(stored => stored != null) + .Cast() + .ToArray(); + + foreach (var store in _backingStores) + store.CommitBatch(upserts, deleted, soft); + + var changes = new List<(CultStoredDocument Stored, object? Previous, bool Removed)>(); + lock (_stateGate) + { + foreach (var pair in mutations) + { + _entries.TryGetValue(pair.Key, out var existing); + if (existing != null) + { + RemoveIndexes(existing); + _documentHandles.Remove(existing.Document); + _soa.Remove(existing); + } + + if (pair.Value == null) + { + if (existing != null) + { + _entries.TryRemove(pair.Key, out _); + changes.Add((existing, existing.Document, true)); + } + continue; + } + + var stored = pair.Value; + _entries[pair.Key] = stored; + _documentHandles.Remove(stored.Document); + _documentHandles.Add(stored.Document, new DocumentHandleBox(stored.Key)); + _soa.Upsert(stored); + AddIndexes(stored); + changes.Add((stored, existing?.Document, false)); + } + _hasUnflushedMutations = _backingStores.Any(store => store.IsDirty); + if (!IsDirty) + LastSuccessfulFlushAtUtc = DateTimeOffset.UtcNow; + } + + return changes; + } + + private sealed class CultCacheTransaction + { + private readonly Dictionary _mutations = new(StringComparer.Ordinal); + + public IReadOnlyDictionary Mutations => _mutations; + + public void Stage(CultStoredDocument stored) => _mutations[stored.Key.Value] = stored; + + public void Delete(CultRecordKey key) => _mutations[key.Value] = null; + + public bool TryGet(CultRecordKey key, out CultStoredDocument? stored) => + _mutations.TryGetValue(key.Value, out stored); + } + internal CultStoredDocument CreateStoredDocument(Type documentType, object document, CultRecordKey? key = null, string? storedAt = null) { var descriptor = _registry.GetRequired(documentType); @@ -1754,33 +2007,28 @@ namespace GameCult.Caching bool raiseUpdate) { CultStoredDocument? existing = null; - _entries.TryGetValue(stored.Key.Value, out existing); - if (existing != null) + lock (_stateGate) { - RemoveIndexes(existing); - } + _entries.TryGetValue(stored.Key.Value, out existing); + if (existing != null) + RemoveIndexes(existing); - _entries[stored.Key.Value] = stored; - _documentHandles.Remove(stored.Document); - _documentHandles.Add(stored.Document, new DocumentHandleBox(stored.Key)); - _soa.Upsert(stored); - AddIndexes(stored); + _entries[stored.Key.Value] = stored; + _documentHandles.Remove(stored.Document); + _documentHandles.Add(stored.Document, new DocumentHandleBox(stored.Key)); + _soa.Upsert(stored); + AddIndexes(stored); - foreach (var store in _backingStores) - { - if (store != source) + foreach (var store in _backingStores) { - store.Push(stored); + if (store != source) + store.Push(stored); } - } - if (source == null) - { - _hasUnflushedMutations = true; - } - else - { - RecomputeDirtyState(); + if (source == null) + _hasUnflushedMutations = true; + else + RecomputeDirtyState(); } PublishChange(stored, existing?.Document); @@ -1799,30 +2047,26 @@ namespace GameCult.Caching CacheBackingStore? source, bool raiseUpdate) { - if (!_entries.TryRemove(stored.Key.Value, out var existing)) + CultStoredDocument? existing; + lock (_stateGate) { - return; - } + if (!_entries.TryRemove(stored.Key.Value, out existing)) + return; - RemoveIndexes(existing); - _documentHandles.Remove(existing.Document); - _soa.Remove(existing); + RemoveIndexes(existing); + _documentHandles.Remove(existing.Document); + _soa.Remove(existing); - foreach (var store in _backingStores) - { - if (store != source) + foreach (var store in _backingStores) { - store.Delete(existing); + if (store != source) + store.Delete(existing); } - } - if (source == null) - { - _hasUnflushedMutations = true; - } - else - { - RecomputeDirtyState(); + if (source == null) + _hasUnflushedMutations = true; + else + RecomputeDirtyState(); } PublishChange(existing, existing.Document, removed: true); @@ -2104,6 +2348,34 @@ namespace GameCult.Caching /// public abstract void Delete(CultStoredDocument entry); /// + /// Atomically stages and durably commits a buffered record batch for this store. + /// Implementations must restore their prior staged view when finality fails. + /// + public virtual void CommitBatch( + IReadOnlyCollection upserts, + IReadOnlyCollection deletes, + bool soft) + { + var previousEntries = Entries.ToDictionary(pair => pair.Key, pair => pair.Value, StringComparer.Ordinal); + var wasDirty = IsDirty; + try + { + foreach (var entry in deletes) + Delete(entry); + foreach (var entry in upserts) + Push(entry); + PushAll(soft); + } + catch + { + Entries.Clear(); + foreach (var pair in previousEntries) + Entries[pair.Key] = pair.Value; + IsDirty = wasDirty; + throw; + } + } + /// /// Persists all current backing store entries. /// public abstract void PushAll(bool soft = false); diff --git a/src/GameCult.Networking/CultNetDatabase.cs b/src/GameCult.Networking/CultNetDatabase.cs index 8000e45b..9c1d1480 100644 --- a/src/GameCult.Networking/CultNetDatabase.cs +++ b/src/GameCult.Networking/CultNetDatabase.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Threading; using System.Threading.Tasks; using GameCult.Caching; using R3; @@ -297,6 +298,11 @@ namespace GameCult.Networking /// Gets or sets the durable store for accepted shard mutation logs. /// public ICultNetShardMutationLogStore? MutationLogStore { get; set; } + /// + /// Gets or sets whether authoritative writes must occur inside ExecuteTransactionAsync. + /// Use this for state owners that forbid record-at-a-time mutation bypasses. + /// + public bool RequireTransactionsForAuthoritativeWrites { get; set; } } /// @@ -464,6 +470,8 @@ namespace GameCult.Networking private readonly Dictionary _nextLogSequences = new(StringComparer.Ordinal); private readonly Dictionary _appliedShardSequences = new(StringComparer.Ordinal); private readonly Subject _changes = new(); + private readonly AsyncLocal _ambientTransaction = new(); + private readonly bool _requireTransactionsForAuthoritativeWrites; private bool _disposed; /// @@ -476,6 +484,7 @@ namespace GameCult.Networking _runtimeId = options.RuntimeId; _documents = options.DocumentRegistry ?? new CultNetDocumentRegistry(cache.Registry); _mutationLogStore = options.MutationLogStore; + _requireTransactionsForAuthoritativeWrites = options.RequireTransactionsForAuthoritativeWrites; _shards = (options.Shards == null || options.Shards.Count == 0 ? new[] { CultNetShardDescriptor.PrimaryAll(options.RuntimeId) } : options.Shards) @@ -503,6 +512,49 @@ namespace GameCult.Networking /// public IReadOnlyList ClientAuthorityScopes => _clientAuthorityScopes; + /// + /// Runs one buffered authoritative database mutation. Cache state, durable state, + /// mutation logs, and database observers advance only after the complete stage succeeds. + /// + public async Task ExecuteTransactionAsync(Func stageAsync, bool soft = false) + { + ThrowIfDisposed(); + if (stageAsync == null) throw new ArgumentNullException(nameof(stageAsync)); + if (_ambientTransaction.Value != null) + { + await stageAsync().ConfigureAwait(false); + return; + } + + var transaction = new CultNetDatabaseTransaction(); + IReadOnlyList afterCommit; + _ambientTransaction.Value = transaction; + try + { + await _cache.ExecuteTransactionAsync(stageAsync, soft).ConfigureAwait(false); + afterCommit = transaction.AfterCommit.ToArray(); + } + finally + { + _ambientTransaction.Value = null; + } + + foreach (var publish in afterCommit) + publish(); + } + + /// Runs one value-producing buffered authoritative database mutation. + public async Task ExecuteTransactionAsync(Func> stageAsync, bool soft = false) + { + if (stageAsync == null) throw new ArgumentNullException(nameof(stageAsync)); + T result = default!; + await ExecuteTransactionAsync(async () => + { + result = await stageAsync().ConfigureAwait(false); + }, soft).ConfigureAwait(false); + return result; + } + /// Gets whether this database instance can authoritatively replace the document at a key. public bool CanWriteAuthoritatively(CultRecordKey key) where T : class { @@ -817,6 +869,7 @@ namespace GameCult.Networking public async Task> PutAsync(CultRecordKey key, T document) where T : class { ThrowIfDisposed(); + EnsureAuthoritativeTransaction(); if (document == null) throw new ArgumentNullException(nameof(document)); var descriptor = _cache.Registry.GetRequired(); @@ -825,20 +878,27 @@ namespace GameCult.Networking var previous = _cache.Get(key); var handle = await _cache.UpsertAsync(document, new CultRecordHandle(key)).ConfigureAwait(false); - AppendMutationLogEntry( - shard, - previous == null ? CultNetDatabaseChangeKind.Added : CultNetDatabaseChangeKind.Updated, - key, - descriptor.SchemaId, - document, - previous); - Publish(new CultNetDatabaseChange( - previous == null ? CultNetDatabaseChangeKind.Added : CultNetDatabaseChangeKind.Updated, - key, - descriptor.SchemaId, - shard, - document, - previous)); + void PublishCommittedPut() + { + AppendMutationLogEntry( + shard, + previous == null ? CultNetDatabaseChangeKind.Added : CultNetDatabaseChangeKind.Updated, + key, + descriptor.SchemaId, + document, + previous); + Publish(new CultNetDatabaseChange( + previous == null ? CultNetDatabaseChangeKind.Added : CultNetDatabaseChangeKind.Updated, + key, + descriptor.SchemaId, + shard, + document, + previous)); + } + if (_ambientTransaction.Value is { } transaction) + transaction.AfterCommit.Add(PublishCommittedPut); + else + PublishCommittedPut(); return handle; } @@ -873,6 +933,7 @@ namespace GameCult.Networking public Task DeleteAsync(CultRecordKey key) where T : class { ThrowIfDisposed(); + EnsureAuthoritativeTransaction(); var descriptor = _cache.Registry.GetRequired(); var shard = ResolveShardInternal(descriptor, key); EnsurePrimary(shard, descriptor.SchemaId, key); @@ -881,20 +942,27 @@ namespace GameCult.Networking if (previous != null) { _cache.Remove(new CultRecordHandle(key)); - AppendMutationLogEntry( - shard, - CultNetDatabaseChangeKind.Removed, - key, - descriptor.SchemaId, - document: null, - previousDocument: previous); - Publish(new CultNetDatabaseChange( - CultNetDatabaseChangeKind.Removed, - key, - descriptor.SchemaId, - shard, - document: null, - previousDocument: previous)); + void PublishCommittedDelete() + { + AppendMutationLogEntry( + shard, + CultNetDatabaseChangeKind.Removed, + key, + descriptor.SchemaId, + document: null, + previousDocument: previous); + Publish(new CultNetDatabaseChange( + CultNetDatabaseChangeKind.Removed, + key, + descriptor.SchemaId, + shard, + document: null, + previousDocument: previous)); + } + if (_ambientTransaction.Value is { } transaction) + transaction.AfterCommit.Add(PublishCommittedDelete); + else + PublishCommittedDelete(); } return Task.CompletedTask; @@ -906,6 +974,7 @@ namespace GameCult.Networking public async Task ApplyPutAsync(CultNetDocumentPutRawMessage message) { ThrowIfDisposed(); + EnsureAuthoritativeTransaction(); if (message == null) throw new ArgumentNullException(nameof(message)); if (message.Document == null) { @@ -920,31 +989,41 @@ namespace GameCult.Networking var document = await _documents.ApplyRawDocumentPutMessageAsync(_cache, message).ConfigureAwait(false); var kind = previous == null ? CultNetDatabaseChangeKind.Added : CultNetDatabaseChangeKind.Updated; var predictionKey = PredictionKey(descriptor.SchemaId, key); - if (_predictedDocuments.Remove(predictionKey)) + var reconcilesPrediction = _predictedDocuments.ContainsKey(predictionKey); + if (reconcilesPrediction) { kind = CultNetDatabaseChangeKind.Reconciled; } - AppendMutationLogEntry( - shard, - kind == CultNetDatabaseChangeKind.Reconciled ? CultNetDatabaseChangeKind.Updated : kind, - key, - descriptor.SchemaId, - document, - previous, - new CultNetShardLogEntryMessage - { - ChangeKind = previous == null ? "added" : "updated", - Put = message - }); - PublishUntyped( - descriptor.DocumentType, - kind, - key, - descriptor.SchemaId, - shard, - document, - previous); + void PublishCommittedPut() + { + if (reconcilesPrediction) + _predictedDocuments.Remove(predictionKey); + AppendMutationLogEntry( + shard, + kind == CultNetDatabaseChangeKind.Reconciled ? CultNetDatabaseChangeKind.Updated : kind, + key, + descriptor.SchemaId, + document, + previous, + new CultNetShardLogEntryMessage + { + ChangeKind = previous == null ? "added" : "updated", + Put = message + }); + PublishUntyped( + descriptor.DocumentType, + kind, + key, + descriptor.SchemaId, + shard, + document, + previous); + } + if (_ambientTransaction.Value is { } transaction) + transaction.AfterCommit.Add(PublishCommittedPut); + else + PublishCommittedPut(); return document; } @@ -954,6 +1033,7 @@ namespace GameCult.Networking public Task ApplyDeleteAsync(CultNetDocumentDeleteMessage message) { ThrowIfDisposed(); + EnsureAuthoritativeTransaction(); if (message == null) throw new ArgumentNullException(nameof(message)); var key = new CultRecordKey(message.RecordKey); @@ -967,26 +1047,33 @@ namespace GameCult.Networking } _cache.Remove(key); - AppendMutationLogEntry( - shard, - CultNetDatabaseChangeKind.Removed, - key, - descriptor.SchemaId, - document: null, - previousDocument: previous, - wireEntry: new CultNetShardLogEntryMessage - { - ChangeKind = "removed", - Delete = message - }); - PublishUntyped( - descriptor.DocumentType, - CultNetDatabaseChangeKind.Removed, - key, - descriptor.SchemaId, - shard, - document: null, - previousDocument: previous); + void PublishCommittedDelete() + { + AppendMutationLogEntry( + shard, + CultNetDatabaseChangeKind.Removed, + key, + descriptor.SchemaId, + document: null, + previousDocument: previous, + wireEntry: new CultNetShardLogEntryMessage + { + ChangeKind = "removed", + Delete = message + }); + PublishUntyped( + descriptor.DocumentType, + CultNetDatabaseChangeKind.Removed, + key, + descriptor.SchemaId, + shard, + document: null, + previousDocument: previous); + } + if (_ambientTransaction.Value is { } transaction) + transaction.AfterCommit.Add(PublishCommittedDelete); + else + PublishCommittedDelete(); return Task.CompletedTask; } @@ -1699,6 +1786,20 @@ namespace GameCult.Networking }; } + private sealed class CultNetDatabaseTransaction + { + public List AfterCommit { get; } = new(); + } + + private void EnsureAuthoritativeTransaction() + { + if (_requireTransactionsForAuthoritativeWrites && _ambientTransaction.Value == null) + { + throw new InvalidOperationException( + "This CultNet database requires authoritative writes to use ExecuteTransactionAsync."); + } + } + private void ThrowIfDisposed() { if (_disposed) diff --git a/tests/GameCult.Caching.Tests/BackingStoreTests.cs b/tests/GameCult.Caching.Tests/BackingStoreTests.cs index ee833f17..39fe52ca 100644 --- a/tests/GameCult.Caching.Tests/BackingStoreTests.cs +++ b/tests/GameCult.Caching.Tests/BackingStoreTests.cs @@ -1335,6 +1335,146 @@ namespace GameCult.Caching.Tests Throws.TypeOf().With.Message.Contains("changed target schema")); } + [Test] + public async Task CultCache_Transaction_Hides_Staged_Records_Until_Whole_Batch_Is_Durable() + { + var root = Path.Combine(Path.GetTempPath(), $"cultcache-transaction-{Guid.NewGuid():N}"); + var manifest = Path.Combine(root, "state.cc"); + Directory.CreateDirectory(root); + try + { + using var cache = new CultCache(); + cache.AddBackingStore(new DirectoryMessagePackBackingStore(manifest)); + var firstKey = new CultRecordKey("transaction:first"); + var secondKey = new CultRecordKey("transaction:second"); + var staged = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var release = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var observed = 0; + using var subscription = cache.Watch().Subscribe(_ => observed++); + + var transaction = cache.ExecuteTransactionAsync(async () => + { + await cache.UpsertAsync( + new NamedTestEntry { Name = "first", Value = "one" }, + new CultRecordHandle(firstKey)); + staged.SetResult(true); + await release.Task; + await cache.UpsertAsync( + new NamedTestEntry { Name = "second", Value = "two" }, + new CultRecordHandle(secondKey)); + }); + + await staged.Task; + Assert.That(cache.Get(firstKey), Is.Null); + Assert.That(observed, Is.Zero); + + release.SetResult(true); + await transaction; + Assert.That(cache.Get(firstKey)?.Value, Is.EqualTo("one")); + Assert.That(cache.Get(secondKey)?.Value, Is.EqualTo("two")); + Assert.That(observed, Is.EqualTo(2)); + + using var reopened = new CultCache(); + reopened.AddBackingStore(new DirectoryMessagePackBackingStore(manifest)); + await reopened.PullAllBackingStoresAsync(); + Assert.That(reopened.Get(firstKey)?.Value, Is.EqualTo("one")); + Assert.That(reopened.Get(secondKey)?.Value, Is.EqualTo("two")); + } + finally + { + if (Directory.Exists(root)) Directory.Delete(root, recursive: true); + } + } + + [Test] + public async Task CultCache_Transaction_Abort_Cannot_Leak_Into_Later_Commit() + { + var root = Path.Combine(Path.GetTempPath(), $"cultcache-abort-{Guid.NewGuid():N}"); + var manifest = Path.Combine(root, "state.cc"); + Directory.CreateDirectory(root); + try + { + using var cache = new CultCache(); + cache.AddBackingStore(new DirectoryMessagePackBackingStore(manifest)); + var abortedKey = new CultRecordKey("transaction:aborted"); + var committedKey = new CultRecordKey("transaction:committed"); + var observed = 0; + using var subscription = cache.Watch().Subscribe(_ => observed++); + + Assert.ThrowsAsync(async () => + await cache.ExecuteTransactionAsync(async () => + { + await cache.UpsertAsync( + new NamedTestEntry { Name = "aborted", Value = "must-not-leak" }, + new CultRecordHandle(abortedKey)); + throw new InvalidOperationException("abort probe"); + })); + + Assert.That(cache.Get(abortedKey), Is.Null); + Assert.That(observed, Is.Zero); + await cache.ExecuteTransactionAsync(async () => + { + await cache.UpsertAsync( + new NamedTestEntry { Name = "committed", Value = "survives" }, + new CultRecordHandle(committedKey)); + }); + Assert.That(observed, Is.EqualTo(1)); + + using var reopened = new CultCache(); + reopened.AddBackingStore(new DirectoryMessagePackBackingStore(manifest)); + await reopened.PullAllBackingStoresAsync(); + Assert.That(reopened.Get(abortedKey), Is.Null); + Assert.That(reopened.Get(committedKey)?.Value, Is.EqualTo("survives")); + } + finally + { + if (Directory.Exists(root)) Directory.Delete(root, recursive: true); + } + } + + [Test] + public async Task CultCache_Transaction_Observer_Writes_In_A_New_Commit() + { + var root = Path.Combine(Path.GetTempPath(), $"cultcache-observer-transaction-{Guid.NewGuid():N}"); + var manifest = Path.Combine(root, "state.cc"); + Directory.CreateDirectory(root); + try + { + using var cache = new CultCache(); + cache.AddBackingStore(new DirectoryMessagePackBackingStore(manifest)); + var firstKey = new CultRecordKey("transaction:observer-source"); + var secondKey = new CultRecordKey("transaction:observer-write"); + using var subscription = cache.Watch().Subscribe(change => + { + if (!change.Key.Equals(firstKey)) return; + cache.ExecuteTransactionAsync(async () => + { + await cache.UpsertAsync( + new NamedTestEntry { Name = "observer", Value = "separate-commit" }, + new CultRecordHandle(secondKey)); + }).GetAwaiter().GetResult(); + }); + + await cache.ExecuteTransactionAsync(async () => + { + await cache.UpsertAsync( + new NamedTestEntry { Name = "source", Value = "committed-first" }, + new CultRecordHandle(firstKey)); + }); + + Assert.That(cache.Get(secondKey)?.Value, Is.EqualTo("separate-commit")); + using var reopened = new CultCache(); + reopened.AddBackingStore(new DirectoryMessagePackBackingStore(manifest)); + await reopened.PullAllBackingStoresAsync(); + Assert.That(reopened.Get(firstKey)?.Value, Is.EqualTo("committed-first")); + Assert.That(reopened.Get(secondKey)?.Value, Is.EqualTo("separate-commit")); + } + finally + { + if (Directory.Exists(root)) Directory.Delete(root, recursive: true); + } + } + private const string NamedFixtureCanonicalSchemaJson = "{\"schemaName\":\"tests.named_entry\",\"schemaVersion\":\"tests.named_entry.v1\",\"members\":[{\"slot\":0,\"name\":\"Name\",\"type\":\"System.String\",\"isReference\":false,\"many\":false,\"targetSchemaName\":null,\"indexAlias\":null,\"isName\":true},{\"slot\":1,\"name\":\"Value\",\"type\":\"System.String\",\"isReference\":false,\"many\":false,\"targetSchemaName\":null,\"indexAlias\":null,\"isName\":false}]}"; private const string NamedFixtureSchemaId = "sha256:e7b97801b94190f3159012ede45b0069bb09ebf7920f7432c971bc86a0e08de8"; diff --git a/tests/GameCult.Networking.Tests/NetworkingTests.cs b/tests/GameCult.Networking.Tests/NetworkingTests.cs index 03b4f76c..28245a3d 100644 --- a/tests/GameCult.Networking.Tests/NetworkingTests.cs +++ b/tests/GameCult.Networking.Tests/NetworkingTests.cs @@ -2701,6 +2701,60 @@ namespace GameCult.Networking.Tests Assert.That(changes[0].Document!.Username, Is.EqualTo("Raw")); } + [Test] + public async Task CultNetDatabase_RequiredTransaction_DefersRawPutPublicationUntilCommit() + { + var cache = new CultCache(); + var registry = new CultNetDocumentRegistry(cache.Registry) + .Register(CultNetDocumentBinding.ForDocument( + cache.Registry, + payloadSerializer: SerializePlayerDataPayload, + payloadDeserializer: DeserializePlayerDataPayload)); + var database = new CultNetDatabase(cache, new CultNetDatabaseOptions + { + DocumentRegistry = registry, + RequireTransactionsForAuthoritativeWrites = true + }); + var key = new CultRecordKey("player:transactional-raw"); + var message = registry.CreateRawDocumentPutMessage( + "put-transactional-raw", + new CultRecordHandle(key), + new PlayerData + { + PlayerId = Guid.NewGuid(), + Email = "transactional@example.test", + PasswordHash = "hash", + Username = "Transactional" + }); + var changes = new List>(); + using var subscription = database.WatchRecord(key) + .Subscribe(change => changes.Add(change)); + + Assert.That( + async () => await database.ApplyPutAsync(message), + Throws.TypeOf()); + + var staged = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var release = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var transaction = database.ExecuteTransactionAsync(async () => + { + await database.ApplyPutAsync(message); + staged.SetResult(true); + await release.Task; + }); + await staged.Task; + + Assert.That(cache.Get(key), Is.Null); + Assert.That(changes, Is.Empty); + + release.SetResult(true); + await transaction; + + Assert.That(cache.Get(key)?.Username, Is.EqualTo("Transactional")); + Assert.That(changes, Has.Count.EqualTo(1)); + Assert.That(changes[0].Kind, Is.EqualTo(CultNetDatabaseChangeKind.Added)); + } + [Test] public async Task CultNetDatabase_ApplyRawPut_ResolvesForeignSchemaIdFromPayload() { diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.dll index 1deb800477b19261d5e7ac968d3cda450b042687..7284604e40cbebb6969c979999eed559cf05ec16 100644 GIT binary patch delta 18501 zcmaic349b)w*INA?&>w2^p@`I9gkB^6XrA6Y#Vn47>mGsTFNZk$*wQNas2*6v7pR9F zYS7Vg26(4{H<))sN|YPT?GZz{$vhA#RBkqZj3gBa80LTnz3%S1JM}tpI)HH7&y8wI z?o^2qFVpoC`eryaeaIjoH_r^nvUqwCd(fwP z*r^(`&HDJuW>JoFbxx78+)U&c$_jH>PN8zEIU}cB*<#+AQ=qIgx8_tSQ_T-^YRsYn zpBc`LxUNJ1G{!87RcyaBccbER5C($sOeK_^{u5GZIk#&wZ|5BUN4k|QEg0g?y>JJc z|0!m+$e0;nqAI`IoP;9v1#CtJ6d7uBSr-L*)%X(Du+x$Himz$Csv)SSzGm5_8k|kg zmHInVPsn4`K?u212XHB~g8#zmO?_@zxu*ZL#!~-)5fyxcOZD9c{XxCE3slBOLkekB zq*qPuNWo{P;Om+~(3g520qhL^!)VoEwG@tBbGNhW$l#u?8K|+e@jDLeG$x@_|MCuI zW0{pg>RagDsW*UOe^s}T-*}V749gnIFx~>i1x37)96a_zu73YuAml%hU5){^nrRQp zzhLx)1KHuss=Qzzn0a3~3zjr@T9(~SnXz%<%wT3PaQn>Of3b&-iv=BB$_4GV27k3! z&?!wik?ZQN>ju^j?}5reOL&bSGVz&1ek# z6{|gJGvEHzN~PM|4MOTWlr{bhz?3Ut#q*~W2H%aCC9}=d`Sa7?!%#KSotlAb%P_ch zS}X44yJRm6$yTFip|Hw%ogh=ir}8Xt$ymJN&Ntiu)8W8bf^e*c9hdIRHKAOli=! zj5MngIq8vX46<NYTpRZFKqhlTQSuGj%rBNy713!&}QyLYqIs+%oV@jMR1wS;wh zOtAo+T#>5mn>*#?`Y+;m=~K^&dpMvj8MDa>h$&Mg3t4v974~O`Gy2|z2^RDRGwurq znw~%rzF+jEGf~1`IdEq!K_@#>Z=*ror>McqW~RZ+6Z(@}g^OF{=6Z|)6h(lnV3sk9 zBLy+EfnYH8lex1fKg$CbH5fGJ!vv2-=3k4tm0=}ECs+@XtsL$5s3aKxLV9xe@EXtfoU+imso6uY!*UBBVFtZf)uTE=xXuV?csXlAl?oS9de zm+qRm%uQd_1eeTAzv|Xfn9g2f4vJ-9-}5MlJB5kq^`yc)1tQ#sZV$R(F-OL;!)xGS z;0-$*L5KDHb%va>cL0yU;<6UX2M&7iP;!~il$NFAP`8ZlnrJ(R%Yh-;$`)&I(dShy zmvwdAz>c}%$QA>gStS#|tLncP88KLGaySia>~wUyj^^k_!knBe%}?-yX&dys@tci! zcs`-=4&AZzDziPAo1Vo)Z)Vf&GjAJ&XWi1dT~tF@g`1eY*tyze6eFdojFW|~We@b> z|KWkv#*y7os40(IXym7HDKrXzsX_qO=BK#*MUagIpvjN6Q32r^)yr z`&+9uTUsvfYTkIt%oeNP@hGnHNh)ba%N1PDRZomNMj}i`IStjCo1RZi5rin z=XHG1n_1a0F`K)nWMVFX3X{t6>X=lhsOy~iFYdcjb1K_c)r<3M&Om7w@NMMYOO3*sTtEDr|Qgs74iCd6s*MBnb*@n?_-8yUIm+W z+0AL;Y?~QVecSdEufjQP)byVujY)c`e*TAi) z`&`BuklExi=9)@%3~$gm)rCXFjaSvwazJvyo0v?g6)YO)uBsHWfLO)iN{9xYY1Zb- z>P%HO@}=g|>SCq8xxTst_)_&bSK#gmstf*zV7aLQ=mf8x-78Ozk5f};fc3~yA*arS zXq*M8)}`J`HCs;&1h2fQ)0SH^7NP+Q-a{;FA`ddB)m&71HW&U+3zy~Rq(-yRdu8VS zn(A?bp}bDBx?%|A1sCZwujMo}CUp*IYA66hf{wMe_+6@ktrBxarF_K0s0EF4*U@B&s=}2T4#AH@f#gPf`k-oD1gE6+?y_Jk zTB{nPxY%gG%A0uIkX2z2s8^50vlE0}O9BmSZ5jie&!uH+x6e$Ch3tx@E;bMK%+1AZ zs~?Q(s&NUl2QzhRXNXt33(QEb?uD2jK{Y2<&~zyWZ5qd6bXRIThe%y!PV9Ad5Hkm_ zj3>L<__w*OS9GK#AqPM{(sOgNW2f@)AFN-5yIDzAJIb=F3d&rm2?&P({CDO+<8my-UIqSw(tmoLA53 z{g61B>w5R?g?(D^Z6}rp<6NHUSi-Q@b@%BDv8T#wos3eI-UvFFmyqv~LXGLH9T98b z1X5Fg86nM>imN}Q8ja?R+9IXeyrs6(KOH)?xew2;E6p9XWy%cm>rg^-!zb z%9^IMSzOoMKbuLRX4K#&GkewL2Sw4_QW!Il5NpSDc7wZY-cMe;Wh!zgP|3nOXvj&6 zSF7x;rQYS~ca>F93X7Cf*u(s^u0+W+UG+T*|1_X7{4H$=vKT;-W%%}9Pk*&Yixr*(jr?g=f6xELGSyfJB5j>D378r+ipHFS(Jz6s+x1+ko zCYVT$>aayzonEa_9Xq?^^@@+lEH>Z#u}{HyvP`+U~}?mlhV96Hc3P)R1mKjcnmmXH_b;2{Jh6ta5b{C z#txYu0@y}`QS?EznRf`bL(maK2_zwpI~A+lb|fSlZhqXcA*jpN8|Ap8x~I`ngmY+~ z+h?s;n|V8_Nx$ji*H@0zkj%-7jsA$m!zoUwYf<~%*|Scl)--a{LzqUrFa%m^F-)2P zxe9q<;YT*vWt`2koJ}*VN$*nD>qfe_<%RdAlU~nt@?yPiu+toCIT?7zz{^^eBE*~t z2!3^^Vmmq&W4&(F{%WzNG)h;VZne8uvl_y@Q@c7*^NM~k&JrskR#r?T%qZDSsm;8b zl5xV^!WzV*z!n)MT}H{(F-W}cvCX0iovw>3ak?_2TAZ~8@C zyiL(kt!Ci#ICcc(r`Ml34r_S{)O&Fqfng{avv9%8xmPw}ASmk+obFLfX~S>?>oIF-3p353GKlL3o5l@!xg|4yEj6k$-y!{#rUZBjK>Ei(fe`D zzz5xozkBg|#eX`zm_4SOPD5gh7e~hyXHpaPa5}vj)#5r;#m>*yX+SpPzteJ=Ab2dw zs%()D3f?W6?;@;!AoOvrm#)peJXfb~Q4alj@?*%aM8+2D)QoC$IxILY#`+&h8PAAv zsa}cxz-f-(mj-B^_I1olPZ#~Z)JyqAX*SF$?VlT8pLNfxg_Cm%f7zi&NE$I(A zL;7P-1()5C#nyKcu%_u+jEznYJ6QF!RPef>AzkDw<&IipaG)ba`!Qz!5{y)Gsn4aF zh*bP_;$^gNS{cW=P%4`z{d6pgtNdKzU!TRzyA9Qc=vK!$I{NZvja6<5@rJZ@N5Vjr zN2Q}KM@Q*&Oj>zvDUWw;4p)%QWx2YHahtS83v!BcLY!8Gq(#zC>!s&@Tg0XQmdibQ zG}av$^t0x}bS7u_MJeNNLyY}Jeq9Pb=jApHm&#(8&wP8iyo?Ipgi01Yf_rw@Nj4Do z`!LeTCAO^S+>-J54iR@gJZECkG7Aa|;pQBV!}oMp=)<^U$CFp?^el>CNQRLQhn)%v zj&OV(8-~OGxUfr0qpr;v*7>de_$3KaxW zz-<`|f#)%%X@-zp{%fE*;BNyaMRQxmC`F-vW~_kbxPOg=_)XTR)_2Ng0K1hlelD^X zavy3deK6~i)*muQDVMZHvlu^xJgW8Yd5q3{#xEfk)0bHfXBAUr#THC&@C$h3>VOmv#*%WkU0I$^Jz(Q9A@KqP{~Jbc%$Ht>OjbT_Xywzp38s=9#tHf zvBon4$kDL=|8L=}5QV-Q;Ch|n1?Feo5xOXW8-i|fKj3`~_uDv|onsX03Qe|H{6L}t z>{?+j)Bci&LmK_TW`E2q&>VE!W=1-`23v_)#e_dAsFN1h?A5YD-AUKkthD47pOdb) zS)zCi*b19C(l~5Dh+ZbH-baUQX2jELu+F_AJIk9;5M4%p zI?1+#{PfvL)};CAyOWG<&QeJm<@lEv5n*k1lzd@-Q(iB65}qZ(R>eO_{1;eH+qORT zVj6U!O*hBh3T4ub!mMOMbeqN8FI7}KLbS$aZ&w@$h3GdnyCm-;B}@<7Y+7DB*b_FZ zj(ns<=sBAWjI@L8w%Hii(ouTVrn6y;(mtE@$oe#tP5W(jcGf>bG5W-2{|NmMiqqe1 zb|T~m=g>Dc`$PC6C6|7**+=1aFh^4Q$$e|i8ay}rHhVB9i}KRMX8=6*R}^K2^QpjQ z>7u-F0hQV8wy+T{q#B!T4)+ch(P`8WYxI1mK**ITYxCcFbk}VJSB0gH?D6N6J!gVw`ZPT@Zb>Vut!Df@)J48}3VQ+bmuFVz?hYz^`Dmie?914xdgR*zD54+u;GU67L3Vn^N&% z_zW7*-D1Nlj)c#m$<;U+W#iDoe})Irdw3gWR#W(W_-rz9v;ih_b}+prjHhK54W@U5 z?L{(bWC(p|vvj#Pat?iBvroLC$WZ#uX5V<@k#ot3V+J1VdJOh3%IJY#b1)r-(LSHD zZR4=aL}WM>+U$zV%E$;Rw^>PMedGe_VY5D&XGTU+UyC8ND1IRI4`FxHpL1SxjH2&_ zy-asvvo)If_T=i@=wmEqqp7_f`(IuZUi0OJN7E5dHa-{13y-0NeVM&X9|jz*vGlgh zjGXf#7gJ+D%XTz!UgQ$`-ew2m7e+3nZ}~6<(}j;NCRCv)M5{G+Zbu28N)30KgAm(GpPK0i|vf;jm)8e z!Z3v1HzHTjcf`G5^F~@>*5$47Uront);sv3;~E-#p;c~rP9l0O&9GVDoMdz{y=k-IVAs)* zi>xTRuY0tamI!N0)8pN0qf4lClx5s#yy#d;tv36@I4jyhb-a~BE3WnpjkeNV!rI6c z84+zGV~k}xkd>X$MmvPH(Gqt&vW#A}Y%+mwq;G_o^m@?`%8m5Bu)|6^AA9ke$bT`1 zIjrP`27=`Zvu6IyR3^+?kZ-0MVaupR-5a@?&a_#cGa0>whT3etK03ObM%v79O^U9d zOKkRzYj5OMnr^cz)9z$+CC#;Ij%RfAHoDqoOFfgKx6?A4{T>zGL8i?np~5@qew#gm z3Rlrao6SLmt7(hPHlPNRw%hC|C8KxI^ESIsNzaY0p}jW!o7x<`o8Ge78F0Oa-nZE> zbw%`E`oLz#9cFYb{ncip^>xwv=znbHaczv=Pye#nc2_dGj()P)5AJo*2gr$|38G~* z(UV9=e?xAYzT-$n*UPyD8++(aMcXOIw!P#@MmJEg&2B+z4^oBAw$k3nM(Ss?2h?PA z6AiN2>CVy7hiI71?$jqmAEr?@JJYA{7Z)6+Ag;`;qqJ(Wb=>9(X6xG@+ig~e}W_0p=n&#Oy4}~I6)4iQ+&rrK< z`xqPYXDB^uyj5X=7LPnj{QWw2ex>{8=nlHeX7wIV_D(wIGRyXrr#Sn+XspfhsW|(2 znrbscEzaIW3xru|zd%cD+g?=o0)1~Y74^MH{`3S6YPs&Fh_GdNef%c6o06Sud#KvB z-J^UT-Ged;ZT0ez)TMYzDzqZTarm!8KLU?kjrdDA2bE$k=%k*&uAVhTSpQWitl>?? z3cyZl@d~Pn#wzejw0ygU<0LwJ{_j55=VWC`{4@%jBqDcItkL7L+2kM{K|{U{S)~U< zU1g2F#-2bCy-JoR`&e>^H9wPmEbE`+c>Z({6W!Gz*A#Iv%awaVAxrauRM1&7NvxLU z`W*JO;#`cOQD_bJPr#E&{7QeMyNsOGfv-vDd?n#t6Fi#WKo&kH<87s4VG;IsNEf}O z(I?3)ykdR=O$Tx-Rk}h-VHXFv5WT3;81YH}QZ*be2P&NaYU1j!UH><|)lU|3XqA>q z=ruA}r>rXdS$c&vD!q)f(BEls+L6b^YS}1pvd|i*C{pRLI&-D0Ep!3jlRKw9My*0#^Kg#m_ z?_9XE+&Q5WSscQ`&K0nK$LM}2{b7|V$C-6UpII@jQkHB@Or8^%|D8Lna|lcBjMgOT z?B6jN-82n{X*xdh@g_J8zixd9GQSrFfjZ>?y;K3r!Z8`%rM!;MC7X_B z@TxUb*{s%7j)I;$Z3%F!vJ!83Gk{ym7XZ)AO~Yq#rm4K9azEvuC+<~plx29Gy^9*N zwkrG7Nl920e*0Y~nj9q<-lc4UoZhM|rq{FH1)dlB2zXuo$G{&ejsShh&w+hIUn_^z zm6<;%N7ePQ40RWMmn>6{s+(iAsz;ga8=@XV#aZN0mixx2i}qIk zPb^d4v^AS!_o$0$b&&gbSMrgxs%TvJJ?WOCz*p3xRGp(kQ%=4rrc<(0Y2beL+Lim4V*QB*ch&JUm{0y#5dDP4JL^2COYf4sYM`(WR zBjpI?l|7~fwI*YmmZQ~F?nSBBy-nI$3A$E^pnYqVYmwqwh49wDRw*iATvWUtKKGX% z1ahKl(^A1&r6iaI^9tm{J_z*^;~lzk=&;OaHCyRMwRjNQw&WRMw+{oyxU> z_h){jaO&;KPQ_L65%6r$zYt`(PceI1z4HGY1&H%dIY-!v8h0w`8*x#TFpf}mDqAu+ zM5u!CQZc_8WceH%Jby)J23(F}ZFQ#KQK3DBU*mp7u0)QbmzM8Muw0pR>_IhIxPz92 zKE`z8Bb$EOMY*+(&oQin9N!8a7ko_;+NT^yqriSC#?xV{W0gDPD{kit;&e5}y;tUnq@SBKSE? zPu}KAzoyh7&<&`j-L+Dx*{pGPBb1Utd~HOG`;>Rl$@|p)6?twRzi#fkB*Z!?wMj}H zm!ywNWs9|4$;;d$l;I^!?#IOQX~A8B$7y)UUiV&+N2Jlp+gxu7*^AHtbnMfC&)n}} z5EKMA9e%S*a zzYNEIC8K1ACnEZMH7#Z=K{}1n&MH64yH8t~H`x1{_AS26EfuHz+S7@P@N+cwo&HiG?xA7o!ZF2o4mSEZ8d8F1TB8kCXlPh>lIz%==amac!SP!qE+X) z(kAi-JWS2EjdohXoa%Ze)b>aUroP@H;CK@`HlDn zk@pB57F04MGGjW_kikxEqS_$x9>K%FKgX4TxC#ymtfs^929etYHwf+#JS?bWa zuJAN^{_ff0d&O7npW;vXSNS*ipY}ulq=E`T(e#G zxE^)&agT71aW8eRc5igQ?f%gHy_-B9{2T8co-;iccvgG%dfxX8^Um~c@IL4LqgU~b z^Ihq?+SlrP*7u{&>(BAO?tj;RRmQ@M9U1Ru^bL#(I9mBkhVX-+j=!j!X0gutyFV~I zK&M02;OMfIn*#me_Mb(+mIGhz!j8Yk1Lv4OP3=ErZvh8%Py}a_{Oc`?>*Op{g@0GT zWpw&;fkUpJ;XsW4Ju-g2g};P-t+uZ-?dw(cHHE8rU*q}drLI-V+3uf|D;#er%iXss z>)dZC&$yohzZsu5z~4|l!Ka(&4dsuXx0J)4pOhNsG3xJKr8IcYQP+5HRJ^S-l*D<*dHzL^-%vMa>{n}?`yqd!?$-XLZuK6+=OD)^^2(<4f~dGYk=i9Q{++I}nzPF;1?%!Ow+ESx%ni`Mp&=>5!H z)BlL-d;MDV?N@U3&t7S0b(4CT!Rc|t|KZB+F$9GFF9L2aobkRg2(fzqN-)-rp4QMf zZ0^EZ*d^y)lYY(9teeFZ_T~!B`({Qi?z7NlRs8Z?Jv)k&=1&Z$8+-!Uhi zsGoGISpBaR`-c>(xBIWhRV&N`SDkEBAI@X--2866CY|;xg;~kXudSVQnmKS*#2h`h z2F-7q8v))u*U;)G_2meqxU%QT20;2n1GfJ-*OTe%G;G_omRhf~aoU_|3%A$aazb$~ zn%6XK!SK zXsGp=8VI!o3jzfJu(qTEV*M|;RD}=?wq=M1gsAQ64g@k$a+P{g7YKIcD46NhPMN_y z2}1mR_*IM>*ZLS&Wa*N&PU<$_`b}Z)q!I{NS-AtD%L|;L);(5kd_}$B{0WF9z$UX` zeVMY~9J0QfU+3^jfG;P)Tk#Hq2L0?!E`70#7_x9+&K-l2Z+o%Ffuh9WGyOjG&ahsZc?P z-S@p>P|hkt03{T@Egnk`Ru%X;J6*$=+)(5EAQcfpO5PCMgXGM{{MZEst- zE^R9jd)}6T3qCJhn|ZBg(fHxhP`=|Y&2nN@ake`DJ=5IQygjj_yJ7~OYW46VjBD+) z{hp^jRg}8z%}>9ijH$zGW&_pZzg{#QkGXpMY_%VqMs<)I@m|>v+FJa0wHKt`(Dj4I z6#Um0SN_yNQ;P_-@a+rVI;t~QJzMXrqZ;bDJ-DNf;(6Qpzu~y64)hCURZrLd2Xpeh A&;S4c delta 17507 zcma*O349b));@f0b$9ieq_?EAr?YfYAqfN$ARsVoDkv(O3Mxw=D4R4SpkfG}2#O0X zP@=-<7z7t^88ztW$oRsDI_}Hpyefz=GCD3Z4sIjL;Qu+NDi|E!@An1!sq>t3?z!hK zb?escw!Pia{dJ-+mw2e+Q@}?pL)$4@2Rxluy65Zu>du^Iju5ixmfm-g2%h zj`|e^K*zjFG}$cHs?DjY!nfzQP{r|i*t}L%sYlJnRfT%O+^=K*%-LRs|o;3yb(R!V+<6A?M1W;5`DaGH;BQ zs?}y!)KFKN`=W*FD)WbELP@{~2i))TRO_DPi^ypo!gZaR=}@_dhbYT zamo>2Tcg>Obty{k%W6UE#>X~i+zYc$ceKqy5xsTR`s`{idQgwJG-JNmKl?eg#ypx` zs;)NUIfhx3<1)|4$yL{yb8{-xedbL$1?oEUp`0o;%X}}VxA|a>-;Cr&-4`MPT4NT) zD!b0j-J;BI3k%hBb9by_Vnip(BMP-_lZv&rCRD5$|3HE@Uagh;rAGDAT1y}#{|T+} z1)yAOEoH@1KPe1O)6ZGnP_(4vUocdi=}FGTb>*pW?a_(X!?9(L**8Dulp9z)44*_h zCXG`@--r-Zp}no;T*H?zCcgqiJXMj9C;2st-jFNgO@0Hh9I9{4_IPfnr(-X6H1CfW zq+NsxlK+OI_`MyEr=p0i8JMZQXBWLtI42gEO7@2T4xXjAaPISD99e)r< zwpgiWvE%6{I<8~Kqv8ll%4x(nWHvw#xsw0k9LAkkVm+7GBPG~kgt)-{;6@ly+id7C zk+!qfG1lflyYh?^W0*gs#}=!2F437*)e+qu+cd2;0lV~b6^2hb=0{HI%o79N%mGPp z$FRi;m}ibCDM&p4QzRplp|_#CF?l#fC_R+10`tz9d>yQMmKMrrWg5yjra#D`6havq z$1`x(>XBe5Xv||FguzV@g=Ew;V?0!e8b^6msQCgXEe^R8u_+OE(t(0nC}b>#*@==% z&4VQ+sX3^i`#wW|=`DXm-HAw~jSZoQ;pL7xOPr3c5gXXg>TI@H?aF{-(uq1E;i_aP zoOH1m4LNHvv`{peL{wuD%2jzl4NyIj8Ok*J?Bu2nhqR1US)phs%W6{$ZL-RRVphXK zF=Mg$NNL2g6t1Y@Tl3}8+#p)p^G>SGY zGr=0i6LdqteDJV3IL~IGJS(UCkjwTC<=Z*sOMk*alFCVb%aP6N%SuyLe;=Q)6Hd(Y zR_Xhei+`X<&WVvBp-zq-C|$@Wr0_Ml+j2dRs3`*=F#ywGx>0BXhV{u_oJ^ zqybi0>w<_znt5tsgUUDGPt>2nIU`J@)rQ7km!=n`mdt%5%(h<&o6$qCom~Nk2-qac}$|Es;6uuR7l?Gc=%i97)`QK4Sr* zr{R&Y9mJEwP2%$=(|N9Ba1VOC=#tAgfgq?60z{n7kTV(k6rK@R*k#m1fFcZ&8*}rX zioU4`H|&@xj%+c|rByOHe474W<0A&EB~F)t z?iM>4tgNkH8kB zZQ%*3(X6`IQn7Q5+lV8jsMXd5P%-ipC;uAB^&3 zJpaT3o4G(fs!p`C#lYjdN^e~vPFb=qd4xR**(0ru^`qqTQiDx^@G33jj_A#=^V5MBC__=ow-zI(Kq}$6mWR^l1*v(Y3r?HlpkLqsOsDWf4ai7r}6804kYp&?Iq07Q1WT@WC^Cslkgl&ko+DOMXjpr5=a(D60 zq)6@~U)X2eM_##)LLNN1JRuLto8znEDa^M}%j0N2PvT1u0h9PrzBt>EFi$&Hc2D2s zC#YolUJezep5@g&^^p0AGw*lY!#~ZuEPqvBPI-APO1rI;^;Qn$-V|_olAL*3*dd8~ ztouJU#qWlTSyUa<@gUWceas=%+5Kx#RWB^Gd9_Y@8xtARFT^`{Y0nByx0Ny37k>VR zm*DA6_A{@kezD)TsAF)iAAkIDzt3H*yRFSK+%Y2EGf4kEr~Mur6A`_w&AhVa(i(|Y zhiKM*&|4KlSAPwc2p$TUG0u=L`B%_#sJ}HUdmoBo9_vX&MV^sb2VI98^3CEt#cG*3 zs?SNlRG&d7<5mc@JZ0y-5@C3AwUetqhLQ%JNLAIEvzOk=wj>@{J_F;e``yM+$ZT>O z7n}d-6PqIryx1nM0wg@iHGFX=ujY$gUd-39qWNV^#^kju8kIcXksd^JX;pG9M579l z>=UhC)(CT&O3mf9#cF{0>)KM_|J0s54R>EiYkn2Ma+3qmJ3c+DZ=Rk#MN2k-^$BW_ zlY<}{g8?pk>W(A(nL`3^5z~jxQU^g@110vi!7l&;q2D zFyHQ5Gi4Z*mpiOJ`W58n@j5MDIS`FW4hKz+0AQ@Juvo7SCsYMnFH9zl@(~Z~K*$)$ z?z)y7WuDis*Bp#+$bn}CdeC}WTl?bCaFTto9k_WX7J?){tdb`K{8g3i*i^uUEL{W@KteQu0RbCp|YOD;CEmf5V0w=Ykni09nTz$3o>;!KZ@kf5Ov?RFKTP{+a1KO|yJe=aS}#8t0kA`j@Jy z=B)mu5%DBFHpQps^t;=#-qydNZ#4?M?!x+FoXU3tmME+&)qZ{Hc<9>CNBmyCC>qb} z&v!_p##95w4ZMJpNKOOtDmES0Kv*+o;94_8%S!m#`eE{Eo;FNMr?#RF7}hkS+FU)L zEYJuqt#ts;&ROP;0p)78xpzRmYBIkYP~e#ZW3S#VE6sv|)qx9{6gmv-Wvk4Zf%)m8 z=w~U6xn^o$(TJWt@RhfQ|GN4dz4|$lf982P*NU0MDk8Can}-LMDzBN@(5LX{vF5Sw zDGuxXdzm?_p(HimF22CN@-wbip~ee{z5ES9C-s(@Fda>-Hk#LB)E!zYw&zY6PhXgf zg(xPEMr)$-lhF3Km;;W~T4%!Dkz53pbxa+v;k47V)>&*ZtVaYpch?TnY$?P|ll!mN zn_6oVRI-=1y2g5q!K+P^dDfsr)`hTI{gRXvE@JN{^V&g$v-?OJWKZVInqTEI7Q+Ks z&f_{Z`L)*h?2GB+tm$nNe&?u(Sj64q{SDQzvs>Qbssi0?vFRUNFh*80kG#v_E%|uR z>N>B%4;Etys&!k79g7C?s;bFqzQIk4Jr4ldIbN}G5@Pkjn2A%e1wn7gntx2| zh3ONi_0Zk8)?x@8$)zwk49Hc;3lBzQlU2^yba6J9a5la+*6T*9ujPfO$Z@Y7J-k@2 z8|<{uT2+SMIQ+bomm$Q$^AUV$k7AGYD8_o-z%Bg?#ab>$>0X1ab{9LWhA{8Zt{&99 zcu0)1#6rnCD#s?wD6G8Lm9_GAOvVXwi}ztjh%GWqx{Q*$dyse|Wt(-k*4hf%-6>CS z-ZDgiHr9Kr0kV4Eif1~8M%^noM6%T^9Gb0GngfUSAGQl!Uy6ID8teGic+8YeTG~8s z(M9MpJUj6AIK~6r*^_AQG@Q3WS9hgjwsc&P z524ZI#3zamHgPz*B|=n!N%R3+)9^tz`#L5$qJr6p^2Zvg?fShFl*F&I;%1bSTQ97biAAz9#A` z)@dlJ(P@idZjAN!l`;Mp!LPI!$-%i1}!K(c&^6y;+!ILvGpOoOC+L zV8hTtmRD8oK&Go58*xV#{3JTuz>eOHGN!R#toz8W}eLB7CVlsD|&3)7R1GU9@NDYa9J3N1& zl6*WJ73)(v{Ypao+QA{#xE2-Y^ty!0_FQJ@bdu=D=5xiHq)nG2s7{^P+~GTPuJT|m zpJ)EP{Gg9_rgUenXWb4&&SX0zH&gQvJR?QcucEL}ji@Hj= zqw)+6w5ezf#_WE<-&b;}yQG@GNX7TXuSO5~%Q=p#fU#Wq>8T)B`H;jP9pvVnh3dm} zhSRO(}VOPZkMs-r%X~PnC{#W8;kFIvW2wlA}0C`98KaP@C9pKu?UN>9kcCPE^2V(Y?YZifuM+6ZR`a8A}(^1HwKK+gy5x zaDEx2K2q=!dR&ZnIe_a5dQ#X6;<}Qa!V36~e>|`zF!{J#AaYvZF=#&XKMDMg{||Ua zah86NQBJF39|HfJ_ff_Gnw;@ThN2JB{sC-B`x5A5Oi?c(D+Av^^_#$tz>foLJ}Yg4 zQuJ_|2P^T@fk==;7&w6Xl*NPRwC~KApw4OkU%|V96WTlT z7@rcn2Utvx2FrrQ^tw?AOkEi5jmywPUtq0ZW@0d^{H9_g@V#Qj%d*b^wqUf{KE))#qL|AvS4{k^Q;DE@<8tiMV8Pj$0?g?N5LtgjP{ zYrluQ!}&bWr@sZ&{roP1G8mayx*AI|ey=e84vqxXIfDyff}W zuM`vyPT>+Ry%?&0s&>fd`jjBs4ybn}DwJ z%di+S2WXN+3Vw#V3!Gdj@Fb?*g?>lP96aKDB zNl+IxThz0tyij-1MEASs3Y+~U9s#@7W`B)mgRQq1s{bm@MZ1Jq)%$1)HXTII z5m)c012*I8{q($SCa=m)t&ihzORw2@?I`i;#3d3#la?y*^3UMJXZZT3ZEuZq&|Y^Fs!!FJg!GrCu0(w}Tr6HRr3zG2hD z8AHQa^sddE!7x$2b&5oq@O$^ayH;u z5wO{moFG`H%_2qfQh34^*tCDqvTy;F+w82!72!haZLQkj%ch44CPqe*iDLj5 zWzLSG7liS&4ALliQ`jDgR9p}lP4C$(QPC7Rnf_|Ct-ghkQ|McpJ?3kUoJuad{_^Va zS>e3!SW2_mkA=&^r%_hQrv8k}Bd1fL&5ANsN5)Zw&Hk2tW8@6#W3%tlZ;PBs4HiRc znfPhSXTolwwK-2aC(w7oo}*K+<(fzhcn!ta)8;U<&i>4vqwD<3!V~Eb`d^I8!^^^x zXla9Gygl9No=mUXY=8D$k+Z33kY&3+dROEe`p#y96h9U@pW1EqMe!?<>9k@Las3@MspRjGMp}4^<+`Q#?~yrFb*jZ$qu%H| z8Z8VX>I+8a)68z0KPS3?W{zdgb@Y0Ab@XC-=s4>iT||d$_GtRBXp-_zvts_HVl0lp zcYvY(4w{gC7UPZ!c1x}`d(c@M}-|!f5e7+ z6$N=qNC(yXq2XYK!cx{;UroJ)T1)V1>L+X!&CtBj)ily(?>py5ucXs#R;S+@y^1E< z>{ESfbPb(nvzy)C=+!jeW|f}#(QByLW_vxiMz5vIEtaBRdACNdqcyg13o2Yox7uv9 zYku^4y3=NxP~i=9ugxa7w?=QI-`eadRB;pi&SpQ-{OCIRADayYTTjp1te4gmHR(m0 zrJi=~jNVNDYtyLyY;*&CV6&I>m!r4P$2ME$o*%uHzOdO&&$H3n=-)Prd*?(q()TvI z8U3`0v`O6EtLU(6Z}ivXx7n56`O(`cVzcHHa=U}_Z2Ay+qraglo2}I5NAILMn;muD z8ttT$Y&H?yy_rVY%1Yqnr^q?Qs$!PP&wPq9g;`N{Qh{x|OciJDR{ zVjmwa{RafT*U*eJMps%ohbJBZp!tVz^0-or32=9!Vly%^hgG=)t-l9a$ z8q5FZDC@uF+OuMod%8-rpH*r3G~@(>npBCmq7!6Jh%0u``LcujsTM_Vp}`VA1*fKP zcV(9Bpxf}ISEAQ!SN5^wZtMPZ_OSxpmi?1FNP5xITfJg=a!)9-G_xf>Yf{~+Ofg$d z4LR&;1;UXS*IBYIrqv zZQaOi(#XM1^d#D(;RT92^N5V)e`^%xhekVq4)Ju_p8uEL>Xnpr;m{hDO7-XZxk^jV zsL^fG2bO$wkFH*n$DYy-iinSeR_DKjmyvGkQ)qqnP_nG3Ml?yQTYef{Mf+s@{=vsI zJ(5s#egSJN{3*F^&HsOW&$6>CG5?i41U*AogJR8atH2x?xt@i4$~}|Y737!}b`NfM zW4Z_QCLCo+>M2}4i7>Ic(F$r6vt(=PS@WQ0KOGN&vX> zZ051a9=ro89EvAi2tNqyD&_+T0<8%0w;`IUjGb zS3<+Mj`%%xn>H_TI}MS8sUgINQA3CiqlU;~)DSt08Z8kXlw##oxRlWtFx zYoBNfVs)BV)%ZtiM^JH)yy|rSByG9Mh@Y?RLFA;C;sTdIH9EdZds$Rm>{e|#O%8D< z&q~~^P6QEjU&(sMA*ze*RflMI;sHmhdTog1A22|N@l}W0S?rjc5pY&I zmg1MWhv^SRInKV0{oXj_2P+fK-KZsqJ7`$=1I)I0m8lx%Acvk?=lmSwI>Pz2;8DRB zB%wE?z`KGx8)iGlI?gRx1bjHL%sIhPgLkBD+M3d5oY!dkD_(XwrBnbo!rAEf3uZ~9 zgJ;q_2T$-uhf3^4#e2&>bH1QHs>J+{DxUv*Hy?B6qgc9YxuYcfAld`=ULBd!-Q2eZC{Eg;Mr&dbJX_t0QFGr!RM0ns^bo zGVwS4sGS_YX&0w7UQ#|MPU3U2DtHgY-cTFRX>Vu;jVs+e9BbW6C6&){obvv@CEfPzD@J0Sry9bRQr4n zsn4bC3o2Hg=M6}IzpI`p8Q}d|txuuKqm~(qj7}3Ae=Glk_YFs{yxrax9NY1=suL?$ zy6auX{P?ThfXLjL|Mo^j&KE2bthTKiV>kMi;|r7D`RX<9ry&{-&1j8}aK~vp8%Aq< z);d~yvm~YadFuJGMDh{qXpN6nSySLY?06zn=AW$bGFgcfhxsp%a7_|!p%zGN_AhsA zGadyVNqgC^RC)Mgl)W@|7`Q8^z_CsHRoM~0a^9CX2F+J7N5Jd+V`w(+mstsKAmqfY zn4%o#r?E(2n^u>R1N2>x7_I1AQUm6IZKQ0eUbv_zh3;DzBPBqUlF?O@)?+$dp zithlYI+WEyV0^iPkBhcs^Rj@ZO&rz3gAh1^BZ#eMO@_Ezd zIj>J-;7gk43$xOus$KrQc*mrDJ18KI5ZMa47IuF=lJxkW(neY{+qg4OC8?aYEz zY5VYGTa&iLS&@5l+U*)2!*8{Nep&uZ+5`3scs6$*A`~0{N?Y#uxME-0Xz0I6Tc~j~ z4_!d@=^mO%gMg_f8ivbU8kL?-i)jpSDJ=(HM)v?$&?~@p%F0N`6F->|rYq?k;Prwd z)H@j(O;hh@6ysh0tyl%!MQgKr# zYR2Vs+76sVPXN!yj|6(tY{3PT5$jDYbV_W5R4@wP1g?mkOzY{Np_%yQ=89OO=x2+* zT{In{StXiPbOn4?)3wwQ>lEu|v2GFT7Fbg&Vq3_hSoYm;`aZNvoOX-TGvf4&gm?x% z!?F*G{zK7!DEbefpOYO?*V3!8QEHPQ$C(YeBQ_iQ??X+%j##_mbUPF`;2O1_-jA7F zDi!M#!)7sTkz!k<7*;6yI<`$*yVy0hOFVar=QHB@jCdXp{Xx-xDEbdYe@G%IjVn_c zSL_wJ*hbc*Dus*?^C-cwqG=R)w%|O`;D$k<4$-UiPI|X+M?sl>NZjld)d{AVi zvtH>ENB=dgi8bmxC)#zMD;@f^DUi*g+AXNuY%UfYA=oI`A-Gv^x8OlRP9cz*l2&(G-hjxX2?!p2>15)+nSyaI@fU!GnUzFZl|N5Ns6e5Zo+yP*4Td z)8Avo0rnpO`RiDt$Q^>41$PS`6f90-pVWvnF3>2XLvS&cg0oGzgS z8wEQAHw*5D&)2boB2$L+K?ZAz1xE-r0)5%-8L|>U{(Ee5DuaXW7Cex#2{Hv4=fK3ctDWC;vY`&Ww?-;g6)Exg1ZC{2vS4} z2o4vVDcCO9DY#4UfFMQ1UvRkKOu=1(lqvOQZmL7|Glj&nL?t*=uwAgz(#P1^E@-~q zG$8f1XRqh4p1Iyi|H=OQ{RjO2@Mi>y0`-CO0v8811%4m+IB+CzURqPyy=f|4!!dya z|9tofOa|c~3x|%AGYN-|Q-PNJWjV`Vl}rb|7oQFMC_Wc>W97xbqP!O1fGA^M#{T39 zUJ9}&deXX&t^X%)z_BDyCIc)A}sR!JL)imcT%I&#M<$7LGb)MgWufgXf z@R!s~d^+(N=Y2)Z@E%sZT}S9i?>hB?_arUiTcfId*Qt@dSJXwmleO)>Q?(a;^R#Ks zBb2~d#dH1zkauepX|HL$U9Um@o3_jGnO5!l0-vw&A=5u^a8~V%S{gEbS^I8@!Y+OESVPi`RDrs9_IO=BfHIFXNM#S99# zF+}S33!%(^T^vQyzi7%`#PRxZyfj=i7w zt)EdZk>)S%jW+iGrDAVLvF{h>`s&z$v+Zy0N@kh$OBVR+W(??VwE60iZ1c_~l{G)B zx!a+3#=u_+pWS>WYHs)?(~4%pQ9q-B6D-4(D>~jnNI$EmzP9UNvp1vb+m3#|uG+Of zsIIyj%3Zi^Mwxe-oi>XlP;EYHkn;p z%GDd@ds|B4-Z(+?wu+FBYk!q)DT-}HvFX`btll8LPrGkzG z#8*&#s4YFNg*#kaL&6+(cb-a^=iPmlD(>2T_Y#G2`S;ESw%=QkEg4I7nW2tMG^QhD z<@G=Jc4cwsPw*c%tv}1s#;&XHD^!Sh@3svp(KU4YZ#6Uc;7btqJy@!l(T7iiZN|fm z0V^BnfrR<;!xOg*encBq*SnUeUQwUEy=!~-udA9fr?H`5eM7^*frFar2Mp?4H)vqv zoZ5j6bLL#wzo~IfQ~m4#O|u$iHxU&p{y)W56?ARrx=!&DyL!yizbAFZcwY7H!RPi@ z@p%}6{l}{$4!8-&`ZV%2d>%0;K2{Pe{4sB*=cx}*+xUFu(_by=yw6rlS??|zo!>x#3qJ6QKzVl&4%3Nt{i-YU^cQMft^5B0e7a27 diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.pdb index edd92539ec507f134c17712ee3aff78e8944e84e..c881cae560937bfae3234629bd6097c665032677 100644 GIT binary patch delta 5300 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 RSh-gpbFq9_QqAol{|DAw#%urp delta 4764 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 MLp&_w47}g}06|=U`2YX_ diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.dll index 931e42dca46214e55bdd8529ea9bfc8aaebf47d1..7158570c906b0b5aeb861d4ee6048f000790f71d 100644 GIT binary patch literal 95232 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

    ?r7GU|3heHfu7LnAx2!xWV3b9Q}K`5XvRkxz6 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 ZbHEh%r-uSu3m*I{nckoO{LE3{{{cWh9$)|f diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.pdb index e1aa9f03792f573dfed8ec058fba2760cdd7a35a..e13f706dc082da6cd574d68b817e9b2f62651061 100644 GIT binary patch delta 79649 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 delta 78539 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 Date: Wed, 19 Aug 2026 02:17:38 +0200 Subject: [PATCH 105/283] Seal cache transactions and expose coherent generations --- .../DirectoryMessagePackBackingStore.cs | 83 +++++++++++++++--- src/GameCult.Caching/CultCache.cs | 69 +++++++++++++-- .../BackingStoreTests.cs | 52 +++++++++++ .../Plugins/GameCult.Caching.MessagePack.dll | Bin 49152 -> 50176 bytes .../Plugins/GameCult.Caching.MessagePack.pdb | Bin 21564 -> 21832 bytes .../Runtime/Plugins/GameCult.Caching.dll | Bin 95232 -> 96256 bytes .../Runtime/Plugins/GameCult.Caching.pdb | Bin 32688 -> 32928 bytes .../Runtime/Plugins/GameCult.Logging.dll | Bin 6656 -> 6656 bytes .../Runtime/Plugins/GameCult.Logging.pdb | Bin 9548 -> 9544 bytes .../Plugins/GameCult.Mesh.Quic.Native.dll | Bin 15872 -> 15872 bytes .../Plugins/GameCult.Mesh.Quic.Native.pdb | Bin 12320 -> 12316 bytes .../Runtime/Plugins/GameCult.Mesh.dll | Bin 695296 -> 695296 bytes .../Runtime/Plugins/GameCult.Mesh.pdb | Bin 205552 -> 205548 bytes .../GameCult.Networking.WebSockets.dll | Bin 14848 -> 14848 bytes .../Runtime/Plugins/GameCult.Networking.dll | Bin 517120 -> 517120 bytes .../Runtime/Plugins/GameCult.Networking.pdb | Bin 247876 -> 247872 bytes unity/org.gamecult.cultlib/package.json | 2 +- 17 files changed, 185 insertions(+), 21 deletions(-) diff --git a/src/GameCult.Caching.MessagePack/DirectoryMessagePackBackingStore.cs b/src/GameCult.Caching.MessagePack/DirectoryMessagePackBackingStore.cs index 454a8ed8..648ba09e 100644 --- a/src/GameCult.Caching.MessagePack/DirectoryMessagePackBackingStore.cs +++ b/src/GameCult.Caching.MessagePack/DirectoryMessagePackBackingStore.cs @@ -70,6 +70,37 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore /// public static string DefaultRecordDirectoryPath(string manifestPath) => manifestPath + ".records"; + ///

    + /// Reads one complete persisted generation without deserializing documents through a + /// runtime registry. Indexed manifests are resolved only through the pages they name; + /// orphaned pages from older generations are never included. + /// + public CultPersistedStoreSnapshot ReadPersistedGeneration() + { + lock (_mutationGate) + using (AcquireCommitLease()) + { + var manifest = ReadManifest(); + var indexed = string.Equals(manifest.FormatVersion, IndexedFormatVersion, StringComparison.Ordinal) || + string.Equals(manifest.FormatVersion, LegacyMetadataPageFormatVersion, StringComparison.Ordinal) || + string.Equals(manifest.FormatVersion, LegacyIndexedFormatVersion, StringComparison.Ordinal); + var records = indexed + ? manifest.Records + .OrderBy(record => record.Key, StringComparer.Ordinal) + .Select(record => ReadPersistedRecordPage(record, manifest.FormatVersion, out _)) + .ToArray() + : manifest.Records + .OrderBy(record => record.Key, StringComparer.Ordinal) + .ToArray(); + return new CultPersistedStoreSnapshot + { + FormatVersion = manifest.FormatVersion, + SchemaCatalog = manifest.SchemaCatalog.ToArray(), + Records = records + }; + } + } + /// public override void PullAll() { @@ -496,20 +527,11 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore { var started = tracePages ? Stopwatch.GetTimestamp() : 0L; var metadata = records[index]; - var path = _manifestUsesImmutablePages - ? ContentAddressedRecordPath(metadata) - : _manifestUsesMetadataPages - ? MetadataRecordPath(metadata) - : LegacyRecordPath(metadata.Key); - if (!File.Exists(path)) - throw new InvalidDataException($"Committed record page '{path}' is missing from the selected manifest generation."); - var pagePayload = ReadAllBytesShared(path); - if (_manifestUsesImmutablePages && - !HashPayload(pagePayload).SequenceEqual(metadata.Payload)) - throw new InvalidDataException($"Record page '{path}' does not match its committed content hash."); - var record = CultDocumentMessagePackSerialization.DeserializePersistedRecord(pagePayload); - if (!string.Equals(record.Key, metadata.Key, StringComparison.Ordinal)) - throw new InvalidDataException($"Record page '{path}' contains key '{record.Key}', expected '{metadata.Key}'."); + var record = ReadPersistedRecordPage( + metadata, + _manifestUsesImmutablePages, + _manifestUsesMetadataPages, + out var pagePayload); var catalog = ResolveLegacyUncataloguedRecordCatalog(record, catalogEntries); recordReports[index] = Registry.ResolvePersistedSchemaReport(record.SchemaId, catalog); storedRecords[index] = ToStoredDocument( @@ -797,6 +819,39 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore } } + private CultPersistedRecord ReadPersistedRecordPage( + CultPersistedRecord metadata, + string formatVersion, + out byte[] pagePayload) => + ReadPersistedRecordPage( + metadata, + string.Equals(formatVersion, IndexedFormatVersion, StringComparison.Ordinal), + string.Equals(formatVersion, LegacyMetadataPageFormatVersion, StringComparison.Ordinal), + out pagePayload); + + private CultPersistedRecord ReadPersistedRecordPage( + CultPersistedRecord metadata, + bool usesContentAddressedPages, + bool usesMetadataPages, + out byte[] pagePayload) + { + var path = usesContentAddressedPages + ? ContentAddressedRecordPath(metadata) + : usesMetadataPages + ? MetadataRecordPath(metadata) + : LegacyRecordPath(metadata.Key); + if (!File.Exists(path)) + throw new InvalidDataException($"Committed record page '{path}' is missing from the selected manifest generation."); + pagePayload = ReadAllBytesShared(path); + if (usesContentAddressedPages && + !HashPayload(pagePayload).SequenceEqual(metadata.Payload)) + throw new InvalidDataException($"Record page '{path}' does not match its committed content hash."); + var record = CultDocumentMessagePackSerialization.DeserializePersistedRecord(pagePayload); + if (!string.Equals(record.Key, metadata.Key, StringComparison.Ordinal)) + throw new InvalidDataException($"Record page '{path}' contains key '{record.Key}', expected '{metadata.Key}'."); + return record; + } + private static string HashKey(string key) { using var sha256 = SHA256.Create(); diff --git a/src/GameCult.Caching/CultCache.cs b/src/GameCult.Caching/CultCache.cs index 1d1dab81..396b8a3a 100644 --- a/src/GameCult.Caching/CultCache.cs +++ b/src/GameCult.Caching/CultCache.cs @@ -1577,10 +1577,12 @@ namespace GameCult.Caching try { await stageAsync().ConfigureAwait(false); + transaction.Seal(); changes = CommitTransaction(transaction, soft); } finally { + transaction.Seal(); _ambientTransaction.Value = null; _transactionGate.Release(); } @@ -1904,7 +1906,7 @@ namespace GameCult.Caching CultCacheTransaction transaction, bool soft) { - var mutations = transaction.Mutations + var mutations = transaction.SnapshotForCommit() .OrderBy(pair => pair.Key, StringComparer.Ordinal) .ToArray(); if (mutations.Length == 0) @@ -1978,16 +1980,71 @@ namespace GameCult.Caching private sealed class CultCacheTransaction { + private readonly object _gate = new(); private readonly Dictionary _mutations = new(StringComparer.Ordinal); + private bool _sealed; - public IReadOnlyDictionary Mutations => _mutations; + public IReadOnlyDictionary Mutations + { + get + { + lock (_gate) + { + ThrowIfSealedForAmbientAccess(); + return new Dictionary(_mutations, StringComparer.Ordinal); + } + } + } - public void Stage(CultStoredDocument stored) => _mutations[stored.Key.Value] = stored; + public void Stage(CultStoredDocument stored) + { + lock (_gate) + { + ThrowIfSealedForAmbientAccess(); + _mutations[stored.Key.Value] = stored; + } + } - public void Delete(CultRecordKey key) => _mutations[key.Value] = null; + public void Delete(CultRecordKey key) + { + lock (_gate) + { + ThrowIfSealedForAmbientAccess(); + _mutations[key.Value] = null; + } + } - public bool TryGet(CultRecordKey key, out CultStoredDocument? stored) => - _mutations.TryGetValue(key.Value, out stored); + public bool TryGet(CultRecordKey key, out CultStoredDocument? stored) + { + lock (_gate) + { + ThrowIfSealedForAmbientAccess(); + return _mutations.TryGetValue(key.Value, out stored); + } + } + + public void Seal() + { + lock (_gate) + _sealed = true; + } + + public IReadOnlyDictionary SnapshotForCommit() + { + lock (_gate) + { + if (!_sealed) + throw new InvalidOperationException("A CultCache transaction must be sealed before commit."); + return new Dictionary(_mutations, StringComparer.Ordinal); + } + } + + private void ThrowIfSealedForAmbientAccess() + { + if (_sealed) + throw new InvalidOperationException( + "This CultCache transaction has already completed; escaped async work cannot read or mutate it."); + } } internal CultStoredDocument CreateStoredDocument(Type documentType, object document, CultRecordKey? key = null, string? storedAt = null) diff --git a/tests/GameCult.Caching.Tests/BackingStoreTests.cs b/tests/GameCult.Caching.Tests/BackingStoreTests.cs index 39fe52ca..20f05a3f 100644 --- a/tests/GameCult.Caching.Tests/BackingStoreTests.cs +++ b/tests/GameCult.Caching.Tests/BackingStoreTests.cs @@ -1055,6 +1055,9 @@ namespace GameCult.Caching.Tests var compacted = CultDocumentMessagePackSerialization.DeserializeSnapshot(File.ReadAllBytes(filePath)); Assert.That(compacted.SchemaCatalog, Is.Empty); Assert.That(compacted.Records, Is.Empty); + var selectedGeneration = store.ReadPersistedGeneration(); + Assert.That(selectedGeneration.Records, Is.Empty, + "a raw generation reader must not resurrect an orphaned page left by another process"); } finally { @@ -1432,6 +1435,55 @@ namespace GameCult.Caching.Tests } } + [Test] + public async Task CultCache_Transaction_Rejects_Escaped_Async_Writes_After_Commit() + { + var root = Path.Combine(Path.GetTempPath(), $"cultcache-escaped-transaction-{Guid.NewGuid():N}"); + var manifest = Path.Combine(root, "state.cc"); + Directory.CreateDirectory(root); + try + { + using var cache = new CultCache(); + cache.AddBackingStore(new DirectoryMessagePackBackingStore(manifest)); + var committedKey = new CultRecordKey("transaction:committed-parent"); + var escapedKey = new CultRecordKey("transaction:escaped-child"); + var releaseChild = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + Task? escapedWrite = null; + + await cache.ExecuteTransactionAsync(async () => + { + await cache.UpsertAsync( + new NamedTestEntry { Name = "parent", Value = "committed" }, + new CultRecordHandle(committedKey)); + escapedWrite = Task.Run(async () => + { + await releaseChild.Task; + await cache.UpsertAsync( + new NamedTestEntry { Name = "child", Value = "must-fail" }, + new CultRecordHandle(escapedKey)); + }); + }); + + releaseChild.SetResult(true); + Assert.That(escapedWrite, Is.Not.Null); + Assert.That( + async () => await escapedWrite!, + Throws.TypeOf().With.Message.Contains("already completed")); + Assert.That(cache.Get(committedKey)?.Value, Is.EqualTo("committed")); + Assert.That(cache.Get(escapedKey), Is.Null); + + using var reopened = new CultCache(); + reopened.AddBackingStore(new DirectoryMessagePackBackingStore(manifest)); + await reopened.PullAllBackingStoresAsync(); + Assert.That(reopened.Get(committedKey)?.Value, Is.EqualTo("committed")); + Assert.That(reopened.Get(escapedKey), Is.Null); + } + finally + { + if (Directory.Exists(root)) Directory.Delete(root, recursive: true); + } + } + [Test] public async Task CultCache_Transaction_Observer_Writes_In_A_New_Commit() { diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.dll index 7284604e40cbebb6969c979999eed559cf05ec16..60e4a9a79526bec2695d2a4bfae6d016ddea4ef5 100644 GIT binary patch delta 22200 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 delta 20978 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 z zwr$<=b9~$Wd*e0QwvE5}tJ}E!?%VN~G+(VRFgC6K`!@Za<*M=BZ|~ps;Jue9fu=QI z4Ey5Jts`&fJMpt;u4@>w?a}+@*z@g9HCxq4Rk8!B9XD^;L!GIii=&}dMG3V!LalCN z--G?CU1U@J{$T4C2iDrw;jVVQI~r;^sro~$L5GL!y>Uf>u7+u&;-U1OjyOEWG6IS! z;#}%@w5(BcN#$ZKd)Uny6@=fI{7{Kg^O*Dv5A7@Z16&2UJ|Uc9=vPw$xKZtJX3TuJ z=b&+F4jgpEgA(m62(=u{52!Xs_9-1@#8EEga=33Oxr%Y~gIUJ5hu^kO;5M&%q)@rS z*z(ADpSL|UINxS}bcCWfj8U6rC{wp>-Bh9|`;5bn-H|ihg&>1X?af%HYH^$5_xr1y z-q390*3C2U2jt&wK2OxKLE256Lf`dH%&Hx#7Llj(*5sYh!Ke!?% zxFSEeBH;?IC~?A9j>F}0pp*Q5kJAR*Q0tH!M@rn@$y7t?Ln|uWP8*yJ=SK9{ay}OL zYqyL_cQ}<`>jkzrrQ|xD9?o-)185xEl4d;gczoM;TRv8Osz+;YtKazRQy&>`ZOtgO zX`umj4Xpz)!J%=A-7ss-N4LGfe5+%d>*fNvAs;m0e^sTAxS5;dzt?$h0>TORx_k_}G?6e2IB;|sOd8hC&eiy!j z-)DGVVE*vVB8*>rv`T63;`do&?T&)Lfp6#Df8e2yNB{nU>!|d2s#bMe9?qaW9!TY6i-;|0J1?ugOnS7rndfk>AZyj4yvT*zoUcabwG5Zk@K> zx$|R1sovJO>t$tZHEus@sRsWlX(qN+HTXJpKk7r(pr_-$qaUPI_)>Kxs9uougT+<& z*B4Lzt%jru9;#s57q-<@ZLHZ{>qU@4l5C*^(EFtcoD3qT&V$Vm=TNRFD)|Ra7(tDeb=dAaTj{CN9&Y zR^U>SNou+0Syn{Ql zi(8XCWrr_gVb3zQ(T}kkJj(fX^JmPddWzv_evB~zd00U{TZ*!s%2@^3BaxeWGB$iL zIK5`>bZ~>X)8+h{vWz`qzJIPY_w}DX1sBO1<(V}a2e z>jm|O;-LZ1P-ql17RrZ;pi-zBnhVuKi=k#{1+)&@1Z{=3Ls!(;H==nK*PCZeB9fP& zHt2Pz6FLZe0eu4*`|vCbiiawp7ogkF!Wf=yg04e3eR*~liit%W=ym8F=w0Zq(8sX? zy9ix@zJ-2(?m+*AL|vS~?n7KZfenCipoVyXt%gDq1U3+=fYw5eM1gIFVv_|n49bJH zK|v`3n+%mgGoU-rZ;-LSz&xN7s2Xa6_Cg1t6VS!}g2;YEA#H%bMna8HD|8d`O%+%+ zv?bNZwnIl!Ird&EU7GGgVEzNqITQiKLMhM?XcT0F3ZN3G0-6mifEGi~K`Wv414V)T z8HF}zH?$8r0-c0Dfc^nP9FNDK zka@FM+{6*^_5)7@$ARexhbC#*6VDKFJnFMi_Zl8s;skIA%ActIiC}LXV;`xU1P%nB zRyi4riz%`^)sOUhO5yjaT@B=QTH0$ioruv|Dmu= z(eMIr$s-o=@_^yVM+U~~5U`uQP&Y~C5eT>*T&nt~gZJ2f)2l9tqZ?E#7fT zyiwpZm8YV=Ofb&B>x`y#8^Apb6x5sLz##%YJzyiw1($*Qs5}l_0}fR=4@^_OO6Bq3 z$G|Nr7l3^+qjOa*1dBm1RH}v|82$mCqjE9$61W0fiUE{>>F5tl2S2HDA-D`YRprZY zBc296j=EyCz7$N?e*#pF`ZC7R`QxU+w2+}34wt|?5rDV?`~c;8*oZ5^I{4B6iL1fS zfpb)z0bULs0Iop&OfVgtD$fGXM|rr)HB7{77!V6pqQPvnK>)bQiK{jIPsAmj1OFiS z(#M5(E|_l6_f)P0C&8C)a;l#P9t5VFoOr$nLpuy~m(PIVDKH)B&`b@dfM;o#Ey6-MCw@-D9;ja;Y7Eq%#fg_X@iGllfaMyd_A8wDc@4Xwex-(~y|_wapa83# zc#RXUb>ekSENj?=crQ5ddJUsLk+o_JG^HCfOe5Z?VH)5jC*JJDe{$j%HB9mUtYIU) ze_zrVXvAAIOdW1@;%yqHDSTPO!PYr#{4*kw_ z|1);@cLQq!AJH&9hDV+Fm=nLN;ad2g0I$|`_@0L81W!F;InjHpc!}-{HUaM$j@6>f zD_Z~^JFM7?yX;5>MxF*`OVRBgulUy^)v<|41*Mgq4OToUf>Dh_o>=Uor!F5JYbGk& z@D0MzRZSi6EDLE@_W~)slZxbGOz}uMn;#z zg`I%i6|Z;N30>gj+8$Ps8WxD+~Fu&tPLu zM8Ktyd-(PfMWy%msS|vn$sUcgdknPV#tI*4*Upkt%N+YSiW+jv6pa-VPMFG{M$_|1 zFBP-GwY^=C(_4+6TaI0bqZbI>k@Vb)xFMnv5dLjr6aq{)Md7sGw(Q4D-s3){l)sDA zp}*o`WcO09c$k=BAQm@weK&C2{LUr*{dFPjh9}!6Pj!4B=6ay^uOIi`eXeY?M?&TK zB$v-_xvb0lWNPQ7o>MsS^6l8f)%CJ1sAg}*yCt{!#?F4#?Q_Guj=xNt{60Vb`!mvo ze4N1U7e1SLDc*C*e{_v4rEe7dYu_&c{f(CITAS1T)7Q=EH>TgIpDqOTdLlDv&aJRJ zDfi1q<#gV-%K|5r1oVA)`{B8M2{Q(zT}vH0Cjaf@g%9_HXL0L)YIs;~{l!;w3E0vj z?d9W{Y_idG{fO=5y0EE**T#5{^XM7lvR_E4pSH)BuRql?JTvqa%dt)mdt6J_e!oQi z`%%&gH(SipKUGS@18;xs9d}N=@#{w)TZ8wV=x9Ea^TPGpm%sSB)$&B<#Y4BFA1?1T zp=$r&2gPfq{Ptw={evUUm+UfpSkyMLX|w2K8(xvL@Zs#a%VXZIDO=xA{Ce@;=JbAC zO39VI=VH&C4c^mh)FfH{?b+uWa#svJ^V>C#@W|TRr`_MUa4tS$o3$|95pj8Iquup` zjIo8E7#$~!llB*GsNUsojof?Qr~Lf97oT7EYuaNs&;EMN5`2AV@mv4X9o=@a`ryXR z-@Uc*Y;}UzcCl|v&WzUF_pQ07tVk|TEK4cvpO9FY8lPB^nlP}m^LXeEKHx)R z)@ph#qu$@W@`_jU*jH|C`0SBmQRW;CAfeb{vy4(q+#MZs#CwXEwK;YPp?7o!_KS(u*BjM<&-% z&UJ|7+Odx7c!}#c#C4oTGq}=g=CLeW3hl|t-(hx{RKY7!bC<7MM zK2n5yYRq*dzC>g9{zH6e?c+-PaH+8K+!M>Vm>{MXq%-DVHpi9uF^+Ha3TC<>=~Hti z%P=tyvgC#^oqd<|rM$$J9fd()kDlh>&4Dc4gnefkk7O*5Ep0xM0C)Oic_hnsZH4Au zHn|{YfNzzVUUUhLnP&U)Fl7)1N3FaqXKBW&379Iwu`)+%0bC3=$JUSt?3kh* zyUf^~2qr(4$>VG6DVTT`ZJOuJYGBg~hQ`EjCC)6zNx3Gsk0FAw7{@pAi@5{FM`FX* zB$(ZJZ@P5YD>Ye?k@Lw-uA}{;7#rH;ZT4YhyeW{C@{J)ZooD`dhle%wG#gkLk0pEe zC21VfoAJ||Lga{XBS#{H5ZyG$oZN>AUda2uL4k zA1oJ4S-2k>tufTWWVv>nzo9SolTFj)mE-aZ*qGEdEs?(-*UJ!x-;GVHWY@en15UuB zsa+nPS0LOB_w6Td%CmCu^8UPGqDbF@N5?&s=#I5aj#jb~<#Q5gZ;hnWw%9i)Y_@Og zOYCajIGplG`>Sewn_Azl)Cbzz)%qK1{Y|z02ethVqT*n&|EN@0><+Z=o8bGC-paAu{E?P$`{*2uZ8l6d_VE%FsifKZz;18DJ@iDjg>Y~8(mMS#VaL= zv4IXxFK=24nT13idwZJ&R~-wz5S{%Tj~@;A2%A_R!Q{e*@bpLt^C;>#hgF%v5J&Ic z#$;wJb;Kwm@pbf5&cN!3_Z*~j??_0sVn1wk6v*xqtiHucvjB&r%bInOf>-i(+cVnC3F$*i5CRHaTjhPxF5-*Sd0_=YP)mz3+S8bMAib{rnx_&~{;E z^jM<@QSX$Zg>;ZrAaX|Sj(Xs#Py9`e04FGF z)ldE=j=Tyjl{|!GL$*$!Njgy~7Dh@{g5F}Fy}<_h2D%okq3iP?~p|wp{2)=w!fBqpy30wG#0uA=_9o?5E>6<4b;+9=wXzW9HX`52US2fp`aKo zML@C8-=H?A9l8vOv093Osv!&12(5tLhCYtfTF4ZK1kgfg8*~xsA8(*IC^KH5{CGYc zPc|(z$7`ttdLKFj9fR7Sub@lNb?7Ga3-lYLNzjr5)D`l9dP8AQ6qJ-;(NZcJBcVK~ z2r7ljpxMv@s2*AhNzi&|3$znzg$_c;pf>2M1fC=&f%eZz`&XqF618N))y;larS^iY zCK81OYJ^rm>!6KFKr`CMmG&v6Zcl8TqaCZW1R~WKa-(ousJyx0K46Xjj{xt)t;gIS z9DsH^Y|I0|ZW^Mq3P*x{z@I5R5R5ZJISNOC2ZNteI2ybIQ>Jb(6d+*?47~M$UQqEg z49c7ce+qm%5mpFJQsRfeR;1#&;IS&M0gqGh9OQe#t{9&R6hkr+u0e3I(qSmL8wQ)G z@G$TP;9d%+fOY7L=aZZ;6+B4c@fdJ8m^a>`2`cWY@8Ash`&bauRSC$1p%fgd@blnu za8HG^z<6BrZ~^!$aD~DzfGw9{m<+>2%&-Us-eRF* z@K}XMgG<2U6uyEm=JDVo@D(Zk31B||`A{kR#Y%iTjtX-L_%eJu(4V=K1PlEJn5T4@ zga8eKd4?P?1>69BUg4?WCU6{h68zJ^ytOJk9bAp}P=#lJId?y3GUCgWc)T)@o0*S4 zHa1LE1^gXm=5loKgRf2T&jj=NJg#sBI0~_Rm2-S0I1$WOIdc{GZ7^Tt)4;R9yrn?X znJtPT28J1`06qm}DqgB$H?;X0DTlvW>Awd&6FgU8K7vo!8SPO}1^n|Ae-gM7Y^hNU zJz=PV;R*9OpQYk5a5Z?o67LJ14X#y~-^!F1SwNB^_*`g)s2> z83@foz)MO1AAuUMRbjr5=Y#DEPwT`Jz_sw#D}LVV7fJI6`-2yN7b$*RMwpDn{D^e}js-|I3}Y(V{Z&Vq>w2Il&SYbAqN$ytET9>%^~g z;^itfBA;bNC&Nk=^MI>V%!h2Xih074iaGw(PQ0cQuYH;=v`%H<0bWxvCwyJSJmWW1 z%>MPAc!P@h2)?Oej{nP3jOYKxrwl}Ib>dAbc142CD&~Y+I`LK&^V)HniaGvmHDi3* zt}+Y)?@+M|c&Cc_-rv=UTT~nk|GO#<2EV7`kMaCz1ve>ofrVc_dsPM=;C&Tu1MgEY z-&P-V;{BcYfQqXSe-OM(8IZ^O=ub8i@8MxKNFTc8Sol?e7YJr45Wo3F`ZriZdu4l( zY_CFzbs;Qz+^m1bV=0XI3X~ekLaCK|=_pE$j=n)@koVp}E}i7mE^;E*r_vokQjsi(*U&!X z(b5`}I%|Vq`4kR(jkvfON~70DLEHE z<^>8tDUvr5Yp@XHUEve2lP?aE+k(;-s6Cjw3*-=@m1DSlF@*0tetei@-|W5)sGoe@ z33Mrf9~FEl;tr3&dm)m7F~~tfFb0`y493nLH1EUU4}|kviuX`9=&W4~v^d_{#Yk)8 zTi1H76Ix@s_tyk?QDbvr_2!ykIiqi1cJq8D`TKLv8E$C1d(2!A9NRo(dFvvdv4UmU zCucU?%)B!GLut(T_bNl~-YlyK`^BMp%RKY!n+pcrX|r9*)8S@+^~#J(LtPqfYib*h zj_J2+Tl~JUNv4MOKAW;r({t}{zFV@_dqnE!gHxuqzm;~Q?Cyz^p}Y3{rg5I%U;EAA zU*5dZ+P3wFJ8xZo5R!RKEc)NECSP5C=+%4Dtjm_K!zb1ayR%sI5x(sau>F4Ql5?-r zwT|b;yuM=mU zS}<~d`tN(bOHG?y*KR&&zLl6W<8+NhDhloAHTm}GEq5K7vZYJ6eyki;{cG9GYwKeU z+{%rqx*GaXcT4ovX=3R5qiwqv38ey0d3FzJ38sj!>?yp9HRPv*81h6 zIf-ZfTetR$_fFI;D~$>ZmL4yxwD&J;UFh-kg>1)OOGdoAbM>xM_rAN@T9_C=cdm8o z^`x-uS>KsqGg!ob*sn39tCnE06Jgs9@E()cOS(XEqvZ5O)-*Pr~5{wdHEySCuu zLESLx+IzxN z?lXK!E~FLDoSZthd`?70<l1D z2IaO+91$S&;wbB0g!za@#5@VJuHm~F0=2J(y~MKfka{Uvr5oHL z`&>{mO6eK|FQAnoG+4~njo&s^Fz2Y z)rNEBSUZ$=D9G9n#I@P_vi!I=SsTNdeXNa&{|m)`TJfKe{f^c%vfpeyC)>@|%Si@a zm>F%x4u{Q{D<`(44dGgEOUviFr!9|BVi)~B_*Dkg~*{-vVlWViB zwjbM#wk4@tn{Dd?I_eMQI>>fh?r*kz5`h1S*gxB+fm}PI`nMt&lhw7DXsQ#UhSrAX&VVaO!ZiTE5X)dCB} zS|g>2_$5*$8q+CLto5KVBK6c*&xsT-eUa}qK`$TT0DITIhDb6L+dbrodf2_>9rU$( vC(2W@`^5X=i_q7e>}o_CLIyeFoq#!(mW{GccV4$P5CaoFh07nM0{rL1L+?s9;%u8v=(?Gw(6I zb-e{w>t@-AW!)x7v&rsl&|BTqAgRnDGcD5$|7)%NFj)Qmzx%$Q&-)%feE0gUwVw6N z&wlnkdmrnM8S1|`+_%R5Pp?rMKz=&FZuJ!z0E+~Gx2BxDZsX(E1pK;Iz*VGZ7VwyU zqb=00O@JTrbN2|C>ai)Qo*5#^G<^Xkw4!>E=N^$F7JFV0N#Zuo5n&&YxeiVE8I6Am z7@%k~z>DVq#Fl60i@~jv6mMJ9w*dNtK@o{7j-k+Pd`Ez>>KOo2LjAX%sgr5%s39EWyEM=b7FVTWtUEQ8QZoX>RdxaxrNVJP%9a1_Ra71!vD^7)8LF&Imc zsCid@p&7sLXAJ4Hc4*c!o{NbCqfT8}?)Ur3eae%b6e~=giAf2F)kztN=~&tjQ0g-H z7*?0Y$68J8$j1VNKyA9`-K5yGZ0VZIM_pZxOp>J~(aeqlElGB3xZ@#_XOn5-WEwjk z^>y)l46C#9u~u_)6l!U0p5xAshUK$KsT;yaU0nem^>u}OG}IOGF|2MdA8R#t$1p8K zzUN}{Sh25lL`uHC@cS#<;{$4sAVC9$EGy1jY5tJR!E8R`*`5Ai+E1vUUJk&Fbd_%) zTk*q{Nj~a}_=88yxJo_W6T>kM%d_I_mF^#tRmVAy#W5Ux9ODVn5$XalpCf+3##FCh z12u{1kk<;F0{zGQ0g4dC5y;}0K)L+b>!YI7Z9Ldhh=h7FaZxx2Kd%)(_4=~wzx(2m zh2!B!{JAHBR*mylCi;Y|S~bYhuNtlUGqZ(w^H14RqJF+I&8L(`o2);37G-}oY#{fZ zQiqknaj2_{=A*tYhL482SU!f;4d7#~=I)q?^~G^Hu=T;5WD#}Y$~-=!Jh0ude=m5x z$c+-ecz(%^O2jVJD>b9g*SnTvhZp))reY%wx?QOmN&0T%B~MXafe7~8mRBqGdCult z7j^N<;QyiEI0G>FMbEs!cSrqlrTufV<4{HWFCPE=B~h2Iv>zh7i|vu#M;v{Mn`o{Ph_iP4^i ziU%UTRD5yZ7)}zINUKc*`Ik~_g_`Qdc;0t?tCsXc9F9V_F_=8A<06yAF@*+O>6Jbq zhZ#`idkL!sL^kQ|nCE@W}cqFlzZPiUgK+lZ^2vFZ-Clh$!P+LMP_x~rlvVS-Y3 zwWn(Il8C8&32;3$R^7!3rndevx>O%^4IA++G!2DrV-n@~C_7x^nK{8yc45Q>2dJdRYdIQ+@ymMeXVq>mn*Zt>hRB_V3=l@3Gug3N7wcS?!Q zXBcWsMt$8pPx!Sjh8B|@=ZvZH9xPGP#_Oa^J4*mm6|S`1*ULc zV~B9%Vwn`j9`sjgzCtw*rm7 z|M!@xu5u}!GW|jnUIuiP5g5LI^nSsUv-^VM85wY;{=Wwg6dct22SIxZJS;A?FDRZe z0ax(|J*e_6-^tgWiVOcAgR7fr-k+eNxny^io5% z$dp{D9Ti>OH>gaGRciQ{R`s?42T1)fPwFhEXZoz?CUj!Lm%* zQ~-qH=*5-*JQD?nfa6oD#tF33Ug{(tb#Q{g>oRL!ZgUtA>ma(RG z+^S_v%<&&;+n(0AL8&?CxqL%{*VUYTfG6d~gs90VS6#q1HsQ_|Pd9k(q>TyA;ESGH zZ_E`zo|YS<^6*5Xuf*;%Vv|H=7$H^x!1DuE;z!H|+YC2PCSPO0VQea6#1K50VqMRB zez-9+7ERfEl> zulyAi;g#Kpq23|hj>{x?g?Kq|K`;$+E8z*IIx2$_>{TaFrPL~jAzq4OA-2O|Jnv&k z$PntK)Y7p#4EF{?36tqCk{-2G>h%CN@bdbAMvKFREr(UW$iFYV`uoD09s986=5WVb zcnGgFP=>xCz78V^rVx|E3xz?$l!)Hqn(Dk!C5wv-;UX;Vkt(Hzw4tb{V|N(t5Tg3Z zYI69H)!!%Bhu1Z3Est$snA1BkMc~s$swXWx8IafNqaTUj{A$YQ%Vi%Y}h(pHMmaVpkc)_tb8SI z=}d{gQ%et8jjP_o5S4aLjPt4|@d(sMV5B zwwgYQqmtTxrcy)NP#>k1j@@Bndd3PR!Z1M?Myrb7kpb9E*yyEYsHfSNVzW=RgxQcbBd=#I$L^^1fV>-pL zm}UyDdN@U%(`70s8kH4CLYo8CXPbCBMxJD zdR%`W?jkc6l@_yfEcTb!Ux|mjD{(t+3N@s}2OBCQNi=!|8*2ujga_Q!(jm&T|K=2x zThPq)*E%fN%MpzZM+VZ^`<>MhgEpMhZk&}kxF8Q(`CdF?BZ32u^dbE@hvStpm~VG|hbNjPSc*SHv@% ziiACl6~Tox8IeZa5}M!(lp50F5T`@GAx=r;5Z8)QLq+jZk61$u)Y2T%tksD_;zfHZ zdK`)RL#wxA5E_$ddjt>wA9a9Lwj>ot=fG`$&mthOC9ma{#LE?01Tyd-ThhyOX6`Wc zJDlnL?u6lnzvt4CEDk4DtPan{`o1NPraiBCT6<7nY>!MjX!m@uJ#Z;bIdZj9Lt1PP zI`mubCl0=MPd(Us=_E^;MND|3y_P1FR~Jd#ozotHP>Q$*PhTt4fD{ zRiz}qttyA%^jB21PmNVgyEQ?j9Qsw&2)JW_>D-%x(S%hUf(NYXS*$AVF>r^4H7-D% z*?~9gOt?}0S76VYuGAEw0jGu4zfVQJnxQfsJ7ZA7(quddXfY~1AKjYb-{+y!6nRVw zlGJ{CCfZ_M#*9J@A%^~YCMum0Y^WPbNA0efL2*=LLmkGJ#xjxthkh*``^^(dhmq)1 zfb~h6<%RR~iUOcr{iEFwZQgh{M4PvMyCJP0UUkDTp)3e)-tg?6a%8?zLt5Io(Xrod zh)dzcyCLlY??^H(zJ7Ac=t*Db7te9IV!=L+Of0Up8R}DeJF+}CE-VVo$Iv=QHhSQ7 z0q%*6^~Ij27Fvxs^o{kyJqH%fEE!EMmAU8=-Yw7z7iweuI8^rTt&???dD47y@1@KH z^iUkQl$z?U@+?^tCMI}RFS1&2DKQ>WXnx?qTsN7#%ym=ffRk*3XWydai8FWzQ2<}B z)BvxDA=|K1!cB+q3JsL7I*zQ=OhUWkc5JH30?LFVS$<_}{wD54QdJguhE*1+S_YTc zn&MDuh*u84^AS$&V13<0q)G%^BTPreDi+OC`bDDOp!XC9mA$91H5{BQg|jYSzO26RFTEjvLhoGkBxXSNQFxtScUg8 zOn3HBx-=V%m7LkzRF>}SNTuc~^yNm+_Eo~QmNKPyh0{GBE8XC&xf&hnsOgN{eON~9 zQas5R>!*4CzBtvGLgEb1XNwc9v(QWS;0-7y^W6;W8*p=`vpkk18Fn08#zR2$%_0d~ zpq!GK>u#b0cIhn7k|inXby^bC`FimV&kN%`jDK@*O~9^QOG`so9cQW3+=zY_b7dp8 z&Wf2R^ZGvng>ECBc8pbc%f^&YPZq~=8UT2Q#-!zoElDv_rYJR3j>=(Z@$;_qL@iBG zuSW%TGT9?chiOfshUY9bXYS`_g(eL3GgqXyFsrFBc!#imVem9(tSaWhki~Ha6~;w{ z(Q1E5E6mMG4f05Rr5jEDK9y@Ql-V&HN$Pl?$`a4vrCIr0xJX&JBZFuJY9*scm0Ys* zS{uu@)dpF*XH=C_?W+R~9XR*uJ9 z!Yd~rhSL6SA_`QMtMDkRKUeX_`KqeXFdg^D3{onvCB~U5 zoB^;bV+G1{hU`c&ftjr<6RDujB>z2c1ALlAEw_QQEH(W-&j<}%xVeFp*I^TRt_wq1 zg%fsCO}CTkqR;9aFY$5)B_6_cD#;*yH+F{+24hP^N$YkF@g`bV%go9-v_8E#*a+_p zBAlN>xQuau|IO(}SkIk%ii_3E#Z|v_QR94@`Ql(BSgeGv+vj3tx4U+vtOm;Vu%3na8uuwK;fP+S2#_OJ(#-VcI7!Gty3P_0&y<5MZb@^r$^K{S+ZAIzF$!Y{e@ z)j=dzG0xx$)N&WpFz)19E@V8GLZ0{W2q-Ng`FU=qq;!838yLV7OepXl-C=(-;l4a~ zFZ%?i5HXy&Xd8>YMhxdKvU2QCH(CtL_TsR0qs0gUZ42ESoD)C~Ud%kqd~p#V+tygJ zg+dajM86qEGy*cv2rvSTSHnQu3z6*~PO`;FwzHU+1&TPs!$XKA;g=BPxiXuW6DF~3 z8nZkoW83;7vJHbJ%sRO+!{Ig%Dkj`-A>#=66B`c%6T24v1r2y7p(vi%O!%1DL}XKO z1wPH5;~X2DZkPj?n0=B+>=wAptV%K@n8Tgyc?%I_UTm8SI^iSKAXx9(;QSTlgAr*E z*i6K31wUpv%oac(C%iw2vRDYAq6LcaRP>_z_sZD@pxL)Yc zX^oxOHn@qIC!N@%a5J;Nr4f4yDw)0F*-%%h?n@z< z1DN@XbIjhvsWJfq#81o&941IyVD<#I_yh~z=$zNfBxXkRAKw?%Q z6l$JX?3pBV%wE7=L}QvTFb%Z^x5fch9NP&VU14)HVNE3D~cJRVM-&qV(f z@ngp1=#~f@EQop(@#&by5ygO!zBaC&jjLzF3ahID4_HeZ*U|=`4!Fu>gGaGgHkcUo z6ej!6z!wmWQLiH|i+&riH2NTBqt#w(iT}L~Y}f|=-Zr4x_Y|u*=CB%(347cf7_K<) z7={i_IE?s{`!wPQxn~iNVywOC03WeIhWDwT`d0Gm`Ro#5=mQ4V%e8H`cp^QeD%2n5?8G1(VU^YI%z3gwH@ zgAwnKE=IhETOuTSEy|a3p1^{>8AmPgaN%y0r>g~Rc$k|1HlmjJIoHQ1Ysv28R!NRI z6qyI}gS#Tb@eKMcqS5#R`d9{BLW~Ia8eoI?$Y8|&&0ZQEjT#!BJ<({8{Zcvm4i6eZv;IYAHVw$=LbB9xJ;q83DE68`AM%`h#tS!5x)!|jMTq{80AfP!jG^p@T~!AI85No znv5T!>hHdkrFQ_ye+?u|2_ozgpARs?*xW9}WBOBwUxwnifvwq(Mi}8V_NWm|u|J`H z^6+1<*%$LPesVC~@7`^ufkxwl>TMc`MG=9BZe8TSa1|cZ+mH)$eY^&oMF; zVx)ICyz85f==pMGyt*pS#~b(iF8^NCG`Gh;G!U-|Lfj_2EGycCsMS=nRu%pYt?M)Y zj;N*eBuqx1xf!bw_p!g``H1z;I8r|GzR4`0(Ek~;5qdnI#k8wb&ORjUA4q0cC`(rY zEjpigzlL&;>tmr*ls%My{hNl6Pl*5f*u)gN&odvh*9zU=bAfkP=x;qK=Bhl^$NP^m zyO{Nn%^>sO$h1&vWS2aX%o_Y1wHH?&sEcC0If z-pZjL!DKh(KE)wkMVX2f4nvKnu()NugcpHkNP_cFWM8LfP5mS`c%gF>ckbbEX)VJc zqnWiH8XhspirXDn6?rNPuZUp!6|Ah6y^Y0L-pk%cwz`**ZF3Lvbgpr#`>hT|f!8#h z_vh9iy!v`evhk@7MF;6ow^N%2l))-gX8)~I3vp7iS4Na02 z77Kg;f4yV}Z4Si;?w72~7K9JRJtWy9Xfwg1l09d`%Ow*$Eoq#k6ntT~WZ9Mzfxgft zS**JhpWuI6GN=0lKG*)CWWzD2KYS+HwV0tld?{JCtrWlBJT94!{X}2@oR#d2Y)76F z2){`BVRjG%f*!9_dOA4>>>Bf~b2*eCNS17+=hb_h>LY~?B?QJx-E)OO5CYRAvzhHd zp>VxqgUs(og~H7mlk7h1WHUS=*)iu=QDM+3*+u6GWUojz>86|? zaDeZXbXLyK$lli&XAuEENn4r4p+rEpWb-URcxmnxr;UKsXp4kE$vkL_gh-7=p7Ol4 zc7%EyM`#q3Ne=~EHwxxSHV|7r8kR_whPG(9Q?iKI%TY0Kmt@vheRK@0mF)HcQ*##ibe}ODe3IIuxKkhFWKU}C}eFK<4W7W8sF1@b{x8S8uK2Q zog5tp!z61ePDeJHStF*)LDnX1&%|{aGT?2=_FGklk^vt`N;5J8K9y`rD6tO7Xhvqh zG0A8SX2AE7J)c|(8St}Y`_st=2~^NV?}syQj?Tb6vDP19nU&F*5G2`EnRlqsSr92* z@5*nC&IYSwsreg`IW$*jazBXdm}Y}bDGwtXkf;Tv8JPn%$!JFAK(b^slXD?UGMdS` zFhnw%t!f^WNctQm%!Bcg(QF+IQzfI>IvB2(jAm;-%#n;{Yd$QJjAm;A+$I^#)&fu^ zquE*rt0kk^TByQ(lHzn#hQOaCquDwHS~SLeUj(oBvhC4D&?PVydnBF34lnfEk_$bU~Ts3NvzBquubS=IOmX z|F!7h5b5B?hdIec7!E~Fja@Rog|@f%%{KTl&xm*A(lq8>mvL9jEr7Q+DV_J4j5WwcOLpDxQkV-X zB>OsKL(E)Q#jL?w7y2Nw4brwxjW30Hutm~u;!gz5gJ#LbCp;Q6A3l|A2C`ehf4G+6 zW4X`9EPzPKKFj$BvL?yW3f@3QkJM1nUU0vM%%L%Owdez6ZIW4&)x$9h0lS)9VPEVi zWD_KNFZgoIBA6vvYP>0S5!^RI^L#vHk545WkZgTOP;4bwM{2fzd;B9c9WD7Cj?a(aQw2+k8<#4W-6~^8P zqep8Q#)M3ct%bix_8(*_Jl4w=#oh(_F`DO}t#`$)gsGB+5Anp}#onP_`atX&I4xP| zke1kcz;CRUaAL|6vFjjTvJnN(BYRA;_mW>n)+Jf2{mt0*FbE&MrxuN}?~mO8<0Z>= z9gN)w4@j2fIvl%6h24_6oZrN5fwv`_f`Y7}OYvpe=dXp?MMh~DxS_<-5h z0uu0=3&u|%&jyIVzTXO^6E*gEYOrN1e1A2uM!2OY!SXPSo~+q^O3t-x19iKkK`Et{ zM`7m_&G;IQ^&N0vs>c4}nqb)h8PhZto;S_%1a#o@ZIq!6*-mgw*O-chc@k24W*B5)VfN*m3==b=g3XbwIP>!q!k=HLr(zoe}=2Va1PB=ag< zX4wsoN_Mw-1+u3k8xTh91<3|8dyQEmeB@phvzuy)pM8dr_$|qc@Nc&56Ukv~EHA=I z$)1T-yJKI{JkfPw@-)jodf7t>(=0FZQydsZn3Fx0S9)#3QceWE4pZ^T39`{JXoLHh zHNicx+bwNyOtRXd=PYl)&{^c!1c`<3Sl)!0lKt6?U)$}2YK`)_Y#;oymj$8iOO1I$ z`p1^HCgD|Jp(+CGuSlFM!vR)Ph2cbzO{5$Rd{tfGTZ9dk2!{4NBHSXI! zg~ufe!wtx%@LaEF5VF0}cG}@kK7;+t_Q63XG4%k`uf?Uj?%2=Zq%>a2i}3jm1ka{A z?SrM3Al>H>$Bb(Djp=hp)fmpDKlvVl9O+3x55cs4o`>Luex8S6uExOS46+`Eooc^? zU%>ml3Dfba{De$cjy3F{lHg~bp<{4_wFA!edfJffs36-aZ`#8ihi4_D#y<`(Nk)x- z9NHzLjp=cCr$W^d($4fad?<~yGd&KUNmgL4j6MOKl1((<5q%QAmF%wk3D#3^MzYlW zYmr^h7`9V6vivz(4%CIG!6n(BFo)AHdJa(j)T9fnr(wS|(ysM99FUCmspsL4WVACq z4_%VcR`fial#Di?=i!`WwB0-pmn5SN=6TTHtQCfKl;^<@8RowkJ{Y{*dLC|JBeA=X zEtkw5x54@|q~1aaH^ZQm{ec(YKg_7u_ggQ*WsP}9#Qx3N4PJA#ENEPGL!e|cizeY$ zRS}XkGqV!Q;M#Y3cSBvjgo;=x*=fflP{f}!2G-=qJWoE5q@K#UGejp6=V@8h7ETH_ ziZsd2^O#nUV%Q6cFh=QNA2*dm#w_;QS&c!pU6oV9#l^%GxeHp~#eO&34+ zvUFr`-^!JMy5di*0b=|DjZJcXV+s=93pGYDgGJ;bVhsSpRs23kd?0C{>kDg$7+8{4#&B4iw&tDdt8< ziSx2WiSLyrC9ab!Bvs%yuoaS(6mPU;iv_BrQ;Q!&x=b=^wj5C>8C_84h*gqN?Q_MwlF{{T zuGk_OwMCwISTef2%@dDF#@E{78OiusTf9^)7j3@S7VXl=7u(`p$@pShd?XoPY>Uq& zJDqWJbfGvZ*~N_QwnA}IvI~}*qlbudlKEM;+lmC>GtV^CzfOP3HdK7Sj2G>V(2@P7 z%`M_?BjZLGIAp)AM9g5Ojpq@fT(j}47$Fv3VOz$m5#HAyw2csTl5Gk2+%{6Ik*w6~ zply`6PqL|g{{Ewd2N~AC5#AFWwlU%_()gCK!!}ktD%tnG-`K{9rzE>N;5*xR@uFn! z241vH5IMI~u^aLIGQ~bo6iKG@^08kfo{}uoFW5dwydYV1K&1U@@ftA|6RL{cHd*YG z#z5R)Y<4J@$F6tkGAjc_g2{yMQ-8t*l_?6brs$)5G?uw5^nlPn~_WxqkZBH7;q zUG^KrCz9m`x$I@)3(39{qwMA4C&|X?-ix_O{K`!0(3^ze4z7}CRCC}oTHI!fSWN@| zh6(oBB8!>kT_FmkZHHlsy+TasXPYCgleX1{8TL71QIE~@L~|6L-SAr*u}*qi3ff?t zE4FGL-fISz+2@PzH3kn`rde(kM6+a}L+0BTik~I>3U9_#ilQ3L z^RGk7?3H3Gvj%u0-w2DvvzjgPl#1Ce76*DL?)DaoqZ;Gg-V$+wnYP+55$Ah7jj%*q zW`=9MsIo5+UbWm{aGmZB`%)1o*>=5ZuM*LcjrUgV)goWAcLG$^zD!J!v`$xLzfD{x z*%*D5{dO^1vQLzi_T^%MWVd;3wBI3?N%pvIrTtE^LbA@FvA#8;NwVW!57}$QeUg3P zx6xiF9+1ou_>gK}As&%*Iwn-b6Ot_tuCmvQR>|%YQ|t}mWy#8w$L)8CwS|jELJm9@rgfi0- zt`QbyTEaCVNqYJ!5k6}~mSo3`nLc-m!hY%Q5hMGhyGKlvo}-j7-+NSXT|eVmFGq_lj#I zi}#;q*&x(gnQC>qPgG0eY5g9b`^4@mY_Ch(8-}sI_lZyX**1y}XzH+lBlu+H{o*8U#sE6S zt@d1Gmn0+GX0g1f&$d~tk&J9x#MIS&wk@JUGP3prC&iJJ)EgWPCt;dUs#K z2gEVS$o8N}UE61SP!vfWTusSyNG9|d2Sb}((^4iZQm{i_u2$J zBBnCy6f5J6@Tk};*^%N>WE~qQhXxquOSVhIRHTRSsn|!wfcwbU>GQGXmzZf`c8YfCSp?>|o#GwI&KaWOo)jPUdJ1?-oMfi8 z#nWQ(My?`|)&@g-4(_)RrxGkO*8>Efe;%V_` zX`7Yhhg2LAtN# z|4p%9bx|>1FQj5n@$@pzWsEIgLoVTIEUMt*X{dl7mg@>xWpj^#0^#!!c@$cc4`KrR zv6}?arw=DN2!rb6*T&S*J=tiP-8+ah)H({cjt;B&$C}D8@=?Fw5@|$}wLoXE?F4A} zX>m}Hfb(wB5GwEi7V&@UYHA^Y5A+b;9#42Ni{dm5(UA3Od{B^rsvakjf9sST(&y7B zQ{5@mz9O?rp7I6->3N9Z<4N3GGcb@2A8MjN zzt>QfJ>!O~nop1C^V|jvtf#6fJn~eX%;0}oBeY(>nAKPIXLuZFc)5TAeUVGW>ghQ0 zB&!0qm`VO9mSh_FI+(+nGMqI6>S*Mt;3y_?BA8H{idq{iXV;$0`i9IZo)MarWG%D4 zF;AYqW)p6XqmeO^i>p=d(G2q6%&Dji1WclX_7U)J3#pd!to{8mLu-nG*A#p=1=kTT zuAev82_K%pX=dtOQ?!xLfnI{2T~S~uRukLWMk_@L=3{^yESM1%pvDW#IJ&&y2cG`l zV~KhuwN~uwxdo}D+PKog^Sow}MuBK-C>=b5Q%Da zNgs$)So`!JC)$kZK`jHVS4bAnIgBtFWo;S=Ft8lSR*H{n%8z)^fdOl;eR{%aD~ndY z{_6`3>%I=8wA!LYZKiOc|GSnevyy*}id~_DI;@`_wqflJ@Gav1wp{&B6QEDuQyEP| z6;R+BUX2s*1gnQRSX}z3l$lmPGAoeD%iAZ|i$X5t+JgQ!Jbm?e_HU2>N!G@bhQIfr z*22+SjQRgR3Htj$pE@Xz)>+#8(~3)|eYCdxBbnA6Jg2_uq7bjTXtg9&kE^EF&IUbG zn>_o=npMN~JcIh9wy^crXtJi~RCvDhSe}hgwGeMwD1+almZjF0nzer+`pf+@>z57G z@G0Sc#FBpI{vrB@F5|Ooe~s2c+8psD;10$9N1bWnu{3!&RgJx}>FG^kTDSGb{%0a> zD$62!mOXbJ-m<}4@<2Ck1|XX7<*id$LHIi^gawRl#xaanGtOWvXPn2l1ThTmKs4eV z#Zy`MyqP$a<-~pSsjPJTX)L;!6AE1zIu-J{oACh!Z`q{dYe@7p><)A)#fQ;W51WMY zjd-cDLs^a6@_0CyRSwT82XPyo!`33!G;n5T6xZ<8(2jTyJiwY##Mj`0QtsM|zqhB! zzZ9NC%{-T{m|YS8B`7PTB` zfbMv5lc3P|2&e8)#>b+GvuuKu<}bxMnOS$-_h{Wc#7n7$AZM_WsXLK4P}zY`LOPT) z%7=xiiojOEx3FN9HBVKxveR~%_@6`ODLYx-#YK6Ai?Ww}_Ol*qocag{dRjTanrc{^ zau(wd9zutZ|vYmOV`YOT9ax`N+V=7}Xq7lE=35s>;2}kL31a(=Fpspm%Ed2xgrERIWE2T<5 zUeH%tQ#tJ{l@C;>SM(Jes6wnXzlZW8mJjs{*jgdxxxUd?v$dA7nthtsN(CKmSjSmz z;w-lcYW7<8Iiq}9xWYiVl5xFZt9aD)rKsjYR11|t*K!8iIrI(~ne&OkCO*S2nRapp z+d0qHM> z827Tz1tr*BYTVDoJs?)A*hCM2iXqM@VZ-k-V)nz=7@Z>2xd9WO%6d=l7V{GRYAn~~ z1#d(AC3lB$o^DX`)5aybgU%O>XOy$CuOMa@X@lzx;~~yw7Ix(a#x9ic4Q#}d#&axR zV$}2W^FvgPU}h4{csH6yc*V1P2abPyTp#7vpg}jueuvlHx>qbKy-;@E;g!SsBE}2K zWY>pYrJSl%p@-N@6?%}rRG~X>LO_Wqph8v)EdnlR}@j(MR2m3rjid#HD5uzMMfr&!)^vc-qIN++O@V;)BV1eBu@Q zGWTwAH!ezD*mIpeyV!phFIg?(V)0p@S1|N@`nyG4e30%Xu`O9KbqU?zFU4MrmT20q z%+1J0q_)|w&^rbD6?*Sr|6GM$OW4bq?ZwP)G#%gshcLlv(;-f9NTGKi4k`5Z!y)!R z!2So=zl;65SkuKCvqIzl92V#s(@8GYN&L;lCtr-f#r`$$<8JlS(Hj_kI=cU8Mh)sY z)g_)g(K?C{kNUHUp7p6Z`da*)LU=*(iEH)E(eWhLQN!KMD>(kl0j}ev9Bn+~RQ8$0 zJ{7vts-wiO0s~Eg1vrMj6bp2;WG&Fq3fsjK@`CbyajS1NC$2@L(Mg^s#RM!+6KYQS z)#|91P6|qER#uwND(iGQXDO`H(Ohd02c7=@n{?Fbn{?ENn{?Eyez@?fxJq(~wsVP2 z@=CA+{+f&L`GYRI!v9&E*bDt%(wQx{`|s3!n6c7-mo5^&@;@W)4r}&5!=Yc{!krWK z=1=|o6e`3Sh1S`~wrZ zR7cOTw(I5=mLk&GNA=Uw(qu+FX*BEUq~(YBo?efd*D#!xS#4o{U^Hvu880X^TsH@% zvYf+Mt~l%t}*gD!Ck4bUyMBn1`e>6NDsa&jCvbaOswLv>ziK`UPu`Rf??tmxlB&+FzXq~;*xg+R| za>V%*I?XQF6;#2==+yi+>hp&u3p%CYwo9?+9}XIzr$>Vp=;;l<1)Ti?J-xxVKu>S* zRkNmAPw(+n>*+ndYJDQU$5)HpF$t>mv~W~&ahvpqRP3j9dU~mEot|FmTc@Wt_15X> zF_2AqI(KZ<)5No3fr4NsVomTaJ-xxVOHVKU?b6f39Zvm)l>35TVb53eGyq>gPb0nr zN4THy0OCpGAw=y={&8>@rd1bxmGvVfC;Qzpb3Oou^i&KF!sRdh*{XXtcL0(awKk zv{2`vkR5P1g?cw^cxOm7#(51|lv{Im1$8Pe#A-Yd(xaZ#9_n5`kjguhRAHf{2@5R{ z^y~ngtP4VSfDHppMg42=ilBw131}g=@i}<`4$QF71-w3ze9{=r7>^m_Z$=pCmAD0Z zdT1z>HL0ix@X290M@8c2TV$ZKK#_sZkOq2VsT4I&BGL;@r3N}7EZ`wCo_(gW&s6m3 z3Z2Tja?mc}GcF;GbyM?+JA3%Od+&g5N zIaB#CW0tuFNdwz_miMWSLnOR)TDdQ|N5{d-Lk;)Fq=XlY>FL=W#j9J?OglqT>G8e zyxR@*X5MxKon3cIq?ZkM8t4nSb?BqM2HOpE+TG4I-i|fSH|^pY@8a6*;@a%u+U$VK z_6VOYE@BsF--X$~r|;tIFDM@sUko$rX=Jo0=YmV&ZvBZ+V>oT~BEnzc%IxLJY{bUL zX^GjtrosU>9AZNkso*4Q&aq~O&c^%7>+{!y?|?6G-QEF5W2rBx7cUv8JM>2C4nHGx zM=4h0aJZk5y2EUw7L7KNPdxjivd>iX86J_!KB_k?fJG7Buo$W$LSUm<6rn)7s6%{{ z@qNb67!Nak#dr!a1TLU|2pANK;KvxGP@G_v&B}6=SE3w(mv6oXvPEm=m)(W(ibbg-h_4Kk+bvvz)?)*=(4NH}0w; z=CHmB@lsL)>l-DKwGnFIedkK{X<_{~iDcb|)^pBB*xJteJrc>f2dz=bZ^A$o>-sUi za#j`5!RAiJqmYbQ9_7SeF@m7-3PznEt4>fm85pgsw=u@CHIDTOj4sx@8B5q&!uk=2 z>KjpIY$#`(!-jg68yFioK_lx|GB&fmg>f5Ox3T^a#vO>`65H6?&bWtt_OSI$#tznZ z5~>kL*?g1@Uon1*I4%)?-<4{tkSti%DO_*VV7(cwthX`7u{DnM35+h*yHOsO=w`Wu zeM;Cmf>AAFLpkGYHqU0m9L9RqH!wD`wUPBJ8CzJtjrH4D^9W-b>)RRkuyqgX-(>7y zeJA5lmCZ-la8#**;mK!F#@g$+_KZ3m=|gp-x3b2@7>D}l$=R%Tv8F_qj6Nl(c_XR> zt&5VUu(gb>v)MYEt+P38y-uZU8qshmsgVthx+hT6%n4c;x3Q*;<#xtB?7xTo_pr5t z^_`4I*?N?%M=_iGlj$c7u}XTb5~B_^my)ddWc+?M(aI_tV;mde^i%^EYut<_tS@1G z8EeWJXS04b>+4Y-msrpG2F6CVHnO#ut<9`&Vcdoq^-|I{Hn+3tW0c1wcCg&Zc$AYJ zWuLS7pUPB4fPw45s59`8G*EG^tg$i1u|AIVF4njiOAOSyrKlg5IEGM7EMr4C<7`eg zo0C--?2zW1$5_wS2F6DAX=I-!v=%z=W^86_3*$ES*~UKG*}8+VjjipBd)Pl)QFzHD#n9+7o*z;A4PDwee9sl zbe6EHjBz$&BjYy4HpV@S9gIgAg~<-{ojMa`V`YqEbTO7NmYS$V%UGVxSkKtN*hr{G zG&5;o+{W0(*v^UDS>D6g!Pv=olo5P+Ve#dLWz;cR8EuSlj4npEFBPbSzTgqm|Ld=<=u9yI6KJma(Rc<#NV)#scl@ay z9c<`eO(&xWpzM7D$ZBKR#pq^@o8>ab@&KxLIm`8o4X7z}Hn7~x*ut6?mfHh({J+D2 zI$0$GDKi_Rn{iAaZNJJ{o)>6`WzGhcn^1l_xrOC+#=WRn=j=rPafzL*>0+O65$l~I zh$9DaHCT=h!tuY(xg8Jdob9aYWE8>Vs>lD%25Zc+JD5g$1#9LpHZiuabvw&D7&}=b zLO4PQM?k!kWMfS{Yg{4JaqbYTjOui=p^Q~~+1$klp&TNV3TI_Go@Hk!1$D8;%~-}* z&RD@d^`U$wWK9EV>YWWNH-$FB%gIfsIh1@i$5ETvwVBN=sCpx+o$(z`*2(g>EYph# z*for9#!@pCrJUsk#wOOZu-wkrVO|SYCw8*j#a0Mg3x7%!VH{26gPXBDjKi_qz}Ui? z7M9x?_p+t~L;O3jlQj^&7Q&K5IEAyKd`*&#WjA9PYStu`v)sVg98PW1!g6~!kN-|4 zB7#d4!F|TEo3Wg+f%Oe6w=lLxP{X#f+=Z=%UP~xxq;=DC>ogCQO4aq>)To1!Ez_d5Y0u5=87@88Os@)5OM$0 z5>3sx9Wl+h7qQUU$;rA{7BQTd(al&I!;1{d6)5BK!g3SKEiAV)b}~XN7b2G9FuEDb z8Px_pG$G=kV7Z-fFKaqk78Xv-=(gBli?hr^XZR`RzMr)$YM&aUFcG-A& zVNE$|o_98|+-##e*b+as!8GOK1hf zArdK^E0IE%G1fCSBvP@OS#DvU4wmVu8(ayJD3y)T%~;M@kwmT4M5sEOlPG8#V>_zw z48~4f>;w)PXu?5(tSIA&gyncdtOsjc4vOGreHqK;ELR}njSH4r7~2^;8HJPbQf*EO z?Pe@zY+w}0Ty{oRGG~B4oP%A!ayiTOEH|)Eb8;(8cC@hE&e+K)QaBEyo3RZ4$1@yZ zEZ3_{I#MWuPF6uG$s(0&%(9JTH)9!V%2}>wxq;BXL3U_&y4YNba=o*R<@!O?i}frwaI$8WTUc&mYa46YS<}U7A&s)JGTPE8 zGZ)KlmdjYKXKYU6{ZAW{4n|1l#EdS+GRAtwX2v$g4o1je{|qXqm1P&pE|$v}>lvFe zXn|_Vu*0{>&8%rdRPn|WC+J`mWKtl=uw2h_Gh-WL2P5QAASS~(7|#S z%aF?%=W@m@yBNzD)p|ZOGqy2yFm`bQeI6x?XLRLpjTze*yHJm;3&`qXEMu%^Y-Vgz`Ov`#h2&~wbTO7O)-yIUwlQ`v!VvanY-WTa)-cvHHZ#Id zE(9Vj!$a4?T1PW$I)5Kpup^LGev5gVj ztY>U?Q`$C0>u`?4SjJdC9Pj_&O3tK1GnbH4SqX)xXM|Fct&A?lGRAtwj#Bc65rkI8 zdd6nPwh@%JgRyKR$7F0~Y(q>zGZWV+&X}>Dv6;~|nv)TFp7_L*IX$!@^w!YDp_@bB z4*e+fa;V;HGJk0P)jTKcFJWzArtrbxL&GCteiZ=@%cj#7Z$q_kFnD&hy}l;gI{JK|J;0hxCpnUc8zvJjJPFZFXFAksSsYF@5bTdk0;`Zypekl@o>%&#H@m^ z5l^}4xwzjqqo(i3IfvHYg@fH3%~^OEt?SL+_#}Hw7~v2`eR>GW{aZ*q&%L#lo6gOB znd79!dC5h!(Qpo1f8V^nZA^fnW@^jHX00tFF|+acc0?_gPq4v%)2`}&F_fmqreX-K zD6bY}p}d_@(_nE?^I+j%#EAti#LtJ(P#tNfYIx_3LCr5IS0QSe6LuOU;X|gQ=94(J zoDQK25gTmF5&JjJ`1~f+Xd^&N{NId&DOT#x>U^3za**~Lw#U=gV$5;eqT#7-8r9Q_ zH}+=Je+vD6f^}z50|r?Mw+(&}Q)zARucGZJHw~rXmNE2kO>RAWD8-=e6K!ExNxUxFMbDWqA3bLRKDvOo2t99ryD)v=3C60&5xPW!`xw4h20jmB5YNdGdv@Fbolh}vhca#%fsu# zUkZOS{KN2=h~$W@h{6bcJw1$y|LGt8X&?Hfe1&xypB1qJA7Ujhou)vX6LH)hzaRT; z(iNVUyH5K|!e`zi@xK&3*4p}&mk2(FPbuqRgF59Q}p>^*Xr*LOVK}tf4jrV^V~2>KoGSe949f9)+Br}GR{U+AIdC&n!csh1VKzz&@!vdr zEEV5#s(*DV{$koZsM=DHFVfYyn63)FC^h+)V}v_;Q!VD0)f{&SYUiNuZ1h>o8cJ1# z-iuIYh1)sDTRCkx>J}ldM%EM6%62Q3WEtwq@efO9)QYv`#85FmC~5zb>pOy*#&7$6 z%jXZp$CmG&J4{RujrH}?MJr(;*DC=brACs27wf&0XvILXvb*hSF)<`RHw|CY$ierW zGSf2Ba&uGWgzBxB%PJZ^BoSd6(E|`;3ku^KFJTEir=KPGTIr*6d<-12# z2%{kfpwLrw1jK|%3XUXtXL9sf0izcRl(Y{?q4<}CfB#0?zZY&g+9|c72?k$T%jhK>)Uu@68pI*#>Y{YDA|7`qs zGybMy4(qcKbMW6ys4HN(0>3VwjrMZukx+|DS78};Zx`2tGNO6S~MG)|J&UrTlb$`3Re}3`9_nq%K=bn3ReP!N^ z4JQo^-x$`faSm#F>t&FCUEs6_h)jS50>GpxpIEcu>8pY#tr2hqDOv0W~f1T{x+5U}h zTH>U#qnFy>Ao~k!CyOfwMOQjN>TSm^b$qkW@mSl5#Co9~M~&I2)cXn08+G+2I@A)T z2iz1A2urHdFxCo9rPPkZa8=y^MyYV!i*nV+y^5-XBwjS0pn5)}EDA7-WX-$k3(fd# zKVx{GwM(=9%Xcn$p!N8rdB4?{_i^9gLGi-myL?a*V$Gn;QeXj$*SWT$l@A~KCbZugAwY3u%3f~Va7DSFavdodB5Ln zxCHvo`41?9l_QYFHGyjRzSl=Z>7wz&o+OeQ$i%5|4S{~Qo$mEz*MIcIBMZmFnfOCb z1g#lATv})!S+!=6rC&4J_GaY>@!CB(ldV5qTIM4vqb=4SeT#GcH7tflPpKckM_v6u zKI-eSaX2px^|5@6tdHhno#yVk9NUZYGN$dp+!SFwb7>tPQytjvIKF3mU*uWEPrje? ztjQr5L8%>$zNR{oUAStERXE?x>9;7gqey?zc-B{vUnD|&%kt~QZr}I$*I0kLH25bJ z9H$%x|H*el!CLFtOYNVM9j7eX&-#K2ms-zVYX6Mv9=4xrd!X=nVg311htJ7D>!F|9 zDvO^J#ltXJ-tUH@aM5U1&_SENWVx;MQgZ;Awdq^hHlbvjA|ia}hHVz3e2fDQEx?<>qq=cYeaND1 zqEpCm#HEg*Gi}sXZwu{v9o+`j3QE^cHv3rXvmL+!6* zJ7%oKD5My;!J`jZTtVbB=Te^{>7z%dIlen4Ct2rS>QLMlWNzDAlSkhZb&d1U>!e5}*Vt_2tXx58t-zg}<8{TG_3Ozn3lxcsqMy*Xm=h)g{= z@rZjP_B36z=#*NMFSy(p{43S4a;vG=UQuoxjc2FcyiRicO8qH5M%MqEk9C^bb)%LK zG1uqR?LD1zol^U~Z+Cf;AD*nR`as`zI1?9Tm}-%;bxZ+h4f)cbZ_$JdOuVtbwfFOv*KEe*&nRNX~RX7IyzpA z#1oaZFLkraL{|SWe_p}WKl_%>j!Wd;;9dv|boryhL5pI$sC5#nO)j(VFSCaxP*pk? zp1{nwBCI%BaZ`nfJic`L$L0_4g;%=7K;MwcRF$q2xEdZYI+-iAtaD(4{c3T>;$&jQ z&DiLwIMgQpMlC&Pzo~u=LsU7rFiy*!!g%U2`e|;ix6#dyFBPf|_`a&N1khDVMo^du z?LPgSLBi@wo8ulpmHMaaEU89+7u6l*dKXctjrA>_W7G2Hl-yXC>ky7>RUmg;xW6k1 z1sn&OMAT#@%)cHJ*DKnEkH6xoqG6b!)RH#BU#X+x#mKQeGl&Xd7(5+gZ&4nB2M0u$ zsk=EGhKU7znAwG=VL1#vdc6E`h51}_Cnv;UF`Wy~u|2~u6Nh0E4?{efFtEe-=-e28 zI}*InIU4SJb#AmutSSNv$+e*m*Yny43fE~%qm)}k5fuOWL^^1f{W`_9gjU8rUKwNv zQtIf?Z(&d=j6)0Kz&*da6xH9Uk7o0Kt`ARjxDx+seM)r)&Vc#^%)qY}CnL@alB*&y z7cjFR%Jd(8he7u+cSmt1fjQr$`|&QiVW?>MOf55^gz2FLi-4yDvAoR!?C zzQl=@yx&w6g^5NOQWL`rRd`v1`7stBmF_-S$GWbW!(^=;`{&y{LnY2O8y;{|e+bJc)pjKH7=mUYqmvW~y^2~Ac~p1`Tn?*Yo&IKSl`2U%Qh zY)(Cv)A#L7w1|0Y(t3fyVK3lCF)reCMCt|HLsJh1;+CYR zws9CPAEwu4TEwMlSFG=a8FT$aHg#`bQ_1o_G?gmArsmS2E(?*GS}mJOT5KvE`Zbk`{JNsd(jsW0;2~Y-$l6u&Li;Q}GfZ6wOL)0qQKSckpzQ7I4#hA$>Ey5DmB( z>_L4h@>OcdP?dp$k)CwZFX6C6i&5o!c2R0*pNCRgjDEiOS<&|_4pRGF_|P@dMXWBu z5N_yy;X^qpVTSr4bkrWn7!+3xcGrRLcx=dk)4q<5{niMT!$|VNCu61`F4147q5j@Q z3|)coMGRem^}C4C67j1q=}QE!!0@b_dT@bKOIo`8qGP{n7|z0vuVMJYBJf}eZmxlH zKlKGv1txM_ZdjPV3$NMbNwiOGa%K63RFy>Feux8^O^Y$38ZUZ`4MTl*RN0NVii`~& z-}6;7)KTP8m5VM>7X^CZMr~{ui^|?h<`i93o;1(xy?MC|Jrq|y>gy+vGxn<$Gr9H5+GG)8AA2gBfCutFQRalbNvmK+`}^%E(grG63}a9LjF zdu&O{M~LOT20To~Cd+2-DY(r~0GW8f`u}PO)j8(k}-6(%;sS?@3k* zPL|@Czx?ux!Yz^wiZUO>5yumpaleswOTF)-r6DTk&E?VpWOC71KIJAwrma;+Moy27 zc&A9or3|db`(5*j9!fWD1=z@|db`SYF(*c;rD5R#$_Y@Sw4O4j`bE*h1v@=Sti1vq z>Z$Aa_6$#HbX$ohE@Q)FU(-!#Mm&QU8>abQxGC8_1HI&E&qOhW$NFllR2%CVzMpT( zbmBrb?gwh`V3M#0uBT#_`f@tpkk0T;s802p#(B>0snzx?Ij&NBEjrjNRe0t$-!>g( zJ}pc`;i3^wC&p^Ln>Qylkj1r}Mj7wt&028mE{c&lS*fMUs)qVbRcEQ!pon8gmT2<< z+N7voxiZa-hp|O*QOZ4e_NK9#(zqJS_Dds$(ip~Rki~T?rBO<0XpK9sr7>5jMINKC z@}McmziJJJvbelR(#HE&4fnlVlU>Nk#mM9irqcw|GNVXUoY`Gk7s{^F=1`h1;bynm z*9Mv!++>~`i*YgZMIjqU>zOxHXTN#Fl<)Rw;!M{D1YNX=LnGWbaX2bZ9K0MD#S`Z` zbf~8>R$Yd5M^%kS zjG&9Z2`EqlFUO;77!|~8fh$m>XpcMaTA+>^b~UbP@>lBUa4`}u&9&QNem0_WO+;;= zpQ)ZM{IGd^-N(^}avZ$k;|p!R{9!$-W&3(sS95!B>rQH|^W`s38Fn5oKND^Pn2#4= zCBspkTyxV6i|64r3cwb;BAOC`x~Y@lC%pHki^hb}Q^(@-UNF4@(3RqQba_VH61&d>%<6JeWk$+Fkdh8sWJ@!q8;G-Nl6Or{1UH;mZUf z-XOvkf|PJ0Bm@xV1d!%=JB4`5pESqKgnwY1ZYFCvQ6rYEUyT?&0_=|`lwi$oeayl`bUGV9cF}gxhJk?&6uE?Tr-?C9}63eIsckmKk-y16?SEiJ~NZ_CviB8Fc^EnDy>^M#9z?5T2@xUp-*MB zgc;$bbi!$=gtHhI22CDp1eFK(TTbg9PFMY-hdSrutj7zC5N#*i;hc(9=6dc+T@8Wh z0P}>_ni2WrxhkFTBOcK=-IQXCokD-=Pk4w2!p^BbkV)2^JXpVEQ_tlUP}zmt-;cA; zn<|@U@JN5jqczV>XY3@0rBR4Eg9+bFr>Rs~K=OhV z!hPKOnoyFf8L#FB)bSA1GH&5k&SCs0l|0w;3=kzGKgRuJ8GKGnqs8Y7BNX@_?RYzq z>hrz5>`h!k#Bk-JtprDn7_MJrlW{z~XfZH*5vQ#eEk+P%OYt_kCx9OOm`!9B08z{~ z#*-}q27yYhTZR#hhDE}@WZUK@TbyJ!loGQ+30L^w5MqO10(;(+L(EOj z^|0JddQAK)WSWdG#;-3a5D-N)5G2$MLOsaF(G&_`gJ&^bckBu+$PR|_2$ zjLj$30@pHYa1z@LvotoC*b^|9+1(k$o`ouATYWdGRcaef?Fn!gcCzjQeh4xFzJk~K z)$=uUG8^Vkw)5~$W@DKB0$(t@l9?h7ag>85^3;p3nf=JjD2_7Qfh%MJ_=)4pl2tC~ zFTP_M%q&2hV)l1jJ`-?=zh`FPFu~$SX3yX#OuzyEiCI0Cy8xl$95Y&`7a&@kXZCXl zv3PNj*-Z9K!i7p*_acrg8qpj&y{*gW|W9f znlR|YJUU}UWIxZb#L(8kjkrw2^mwXR@JiwA=Q{ZkHcbrTg4kU2oFP(s3L>izdHu@G zB8F8|aWeD75N2My`nUk|#V}@eW{ZSJNrt@qis)oeC%Na~VRhP-W&v%Ht8vr1Kbp{g zAYt18!qJ*+ogXcrBz7TUbsYImi6Lt-<4;jnpypT{;W>`5B!=WoR`Pi@j-zpW6U(Vl z6&S~*a_Ef%mLmDox-8mg+!l7F`KpGU#kJ8_HH;Wii~2|om&*7Khd9Z&oi(2^ei=oc zPsOT;Z!aKHiX{Czk-98k~w&HbUu zZh4i>za6394o6uO4aeLlZ8&PNvXaF%){3%#mgU?kyELIfMFzLm66E+|UI`vU19_|XZAr|{ZA&v_igxDblBknX3ejQMRI68O)VtdGyhy#^t5ziXu zA^Hd2gt#EM4)JD%`X*R+C(3{FyARP9*oydNFky^-E27mzcs!7>IArSpH3}whWzEJm zR6Q9$RhoiHek6o2HI(qM*g3!m1$lcAztO*k_+YczM}-9W}%-Iu|-Gn zC!wi`U4FTUdjd%x8A9^qtX~{PrB;a%sF|jWM~wBGiI^66BjP_XvhS7E*=lvZzsU$I zJVCvvX{r(%2I6g8xYvw#mqRupYVFai!;72Ix*}^WA(vg5bS3&s&0LMxR6_om=Ogy} zaXx%vDzo4@A?O~95qdm*ShiZ_>dlc4Bbj8QDhrcnYx%^~f^v`R9TAku<5YnCCl4W? z@Sx`gYN7i)3$bD?>HeMzO?x7K?MX4K^HqP-?^Sjrd%LXc*Vdh=-^C-_RPrj0vR2Is z&mNhI)=C=R_pqBQfdt%b(Ej9cS&i@%q5w}oI^qXGdFUURFpSHNM)`~~ z9`Qau!n(k#SYM8EHq5c&Oh0C*>KFRf-q2brU&gjl=-W8-YAkj|-g*x4N0ce8C>Uyd z57R9VAUp@O4x-(=V)_O}>*~9)!_(Xwd2nBilGbvZGMZT%p~UEkcD$&8RWYAuLg9yoz3fqyzYK$9gf;wsY*RW8X37RE4Gfd!%-FHd$j>Dz+!@ZL2ci=q@ zJSy2EXfwkTl0EIf8znP5C#ls|1_7``vQ*pgkN{|x?4O=8d^7wF$-ed+$M>Z_kgOPk z2Ek{NU4az_!IzT#=qSTaJ&#EyoX10g;d{xR%fW}IA@H-LyK+Jy1oU`6(lf}R;MAC@ z*yB?0=2x=ezQ@ zq*a?siGdKw?nGM*#Aqz$bKi4!ja0wHnP`P_>2VHcq7`nCEF60{7M4nuj6EC+D>}wq&$6^I(W%wEps8gk(=+xqKKe87;p8m?BxKO+6k`0M|-N>#q>zNJi_g z5Ee^D>#qowNk;3h2vo^v{T0J%$!Pr*!+ObZ{V7A>e#vP04S`mT(IBh%Jm}S4x+=B= z4olZ!&piPiI3XFWLl2ymjAnob&Px_uG8H_aA4I)&pXp=EdbEWy)3$LB6EXF)r?Wn3iIM;ZWk%*lEjFv_0O-o{t>?FG;pH;zeZN zOSV1imDn;+=o46c`ZB)sjo49OVb%mYEc;@|Kp{W3YlQ1_x?;zv@DkGvNRPx`1~1{$ z5P%KvXwIqF36O?QN{DSrI~#iiG)NYeqmR21-jFOC*%T4mpFsm>(t{mPPrZI^0#8tpg zlG)v(<7UA=dNUP08$%?Ao|FknAPTRq$TE5udna zVE+>}Ey%2ln+N#plG)9f3y_VGEM|BaK61NFvaiFJ#?6OS%o_XudWb{G} zc~*P>gv_NeSW)s9WbKlLr@R`s2ypnx6L!VFhirmmZ-;fqErywrB_^Igwtgh|Huxgd zf5%mUeUw(}$-LtsOW=LU#)bb9w-mZ0yEf4ne-o6CCeKDVpJ0ryfz`}b!HXHkLzcmM z$rfR`TcAaZL|hofM#i&9(!ckZi4`9NDv1%QYAl zN%Tc&9L#JNvnE{N)8ckemiV{Fkb@tCyaXS!ZI5t9F0j1>CnS3+zAOG^%@IAXPbskd zwU@0=DzN>HKk>yV!kBWi?G>_l@ZTOoYU=TjS7FLEq}jt0qaD^WYlhq7SJ~R(8_9}F zHrif;p)<*|8Ga~w#&`Xu0V>@v?16VREe=;GvM)7e`ZnVQ+w0_xf1QR`hyAS|`(W5> zwl_2r+J;)*w7uEOuC%;odkao*ls!Pr-V24-lX(wN)AquA$=0jbws+uuNvSdK!v1n{ z-2g9oKC!(AYbrF>Z8>QB0KQ??2m?b8+dc%CMK+pck@$JZRE?SFzU3phRx-L%`3UCp zdg4cUu&9^er=cIg&Al`fS+gv-5ibEghIPHR;0sA3WdQ#B+FtwlOez>lm=K+|nG01lR+jao9^(&`-0q^t{9E|tb$7R8* zv4vff3I6Rdyi;)2)&-|~J$3dj*jh=pRVKPxJqCZ4j5_}qyet`Y{xRr~j4n)%!JCrN zh3PRBK9H2IOpn25Jq0b3Vvj?&WS3j6i9G>FC95hNZ2uNcNj9Lc2-#VUVLy#PRyapX zjfU_$@JOa&4d1~SjiKk|_U}O5D~)v3dIt7MM%SrlV83K^WqJkWORXf2J~~aWayIe3YA>xsx?Hk>2}|uiLE1bjcpnT* z-5YWiK4(TV;THQj_(fx;koac%Mev)iRYCLOB7{g5T{00aLbPPpGP7$8qjZ}tLjC-t zzJiKaDP6l=6G0L8Xbi$r?(p6F&>-9?R)p(B@(o&v%Zew48AXOTeIZ5SZFmF)B4ef9z32WI!d*~|m>fx@(eVs3zhgrjz=ILYijsL1fqZM5Q2#TLnEUZjd`lF|B0RmFBmX#u8+S0tkam?}CYqXn2M_DV(z zFjef6j22+3*sn26d%7c4_}6GH9Bs#YW)UXYwS_NOGsOVO=!QR2s18Z#!9k{QOGb|h zGDVhT3kJ`1WQromZXUc4*>K4+ai7c*<0LCh7>plsPnPW4)KFcvxJI&HQUzp-O39$K z+L0p`s*;A4)*-!FGU~QmQ7;+YQ0IzOl2PmP#2+N1``bLRNiyn-eDO!g=>9feJS7?5 zY>Ve5qi0nOh279G;aH{0SZ$@peld?*>;Y>R(Nwm)-BY_T{b*^$guj$&~_ zvQxG(u|vdZ$@KPB4t$##UvQ?W{*S@y9Ye**oAGr8S{Co*Jn8U?gk@yh07r|Tb&L>K zGt=htNKv8LcvXxPi!QO<%&ZCC(eH4K6!nsA3f}1$CDuq*=C{N5NQ+f{%`sLyBz3PF zUvrETPe^t$;7!M6;#tWi1;6hYFJ6-Dt&shW2_p9v$`3ETmBWt9MTulOzvGT8#Iuq` z1b*+BC|;DTCit9VlGr7gs_0e6m12*iF*>7jvbZ4G4!>aM6p_1JtKyNsDCbmBAlZrF zDCbq8STd*H>YOHqOO|A^I;V?qlKl{9bzUv5l&mbo>YO2FN;XZr=D^oqmrMEwqtiK4 zY?SQJ0k1i(6@QT|JlN^HPP`)7lOay$_2LuB@MCrTMc>6N-?>gZH~A`+EyEe zIOmAP{cLl^GHGiGz1uifH21U37wS4`Jdeit;z7-5y18JubAi~RG1z1)u-z!$mTY~} z5%WUPCE1t71K;gReb-8IgoVvJ;4^cBvV#B|BVn<|{uqDHbegDadh;%>?6byJ-;i%pV^)lYRU z6MvNK6J?(B7V*>yUhYk>%&*$HT>M!YpVrND-YWhoS$F8TfEA)$vSWS?&RVfoviAe4 zops_P$!sAF&U(=;*>o&-n>Zrb^028+ReUGedXeXB5NB54+qATRDwK83Mxm?KCPuQ~ z1J2t;h-CSJk2{-$RkE+JP0b>KnbwIb#b9RI3|c7)r02eXD@-fJXvy+|A26*FSM)2l zT3mw+>(>gd7PF;mfD-M$S}d0Am@&(Ljab&N;97AzGp*cOafkFAtwaW_6`T6m?ht>J zwtpHX!X09}WPdRYFx?@3A*Rae?-Zswt@YW4D@=C^H#4n@bs|^V$_xdzb)r(TYEyyj zE^&`!i9rRnKZqy$mAhL!FKyrHcl+NhzQ4rwGc&abUNejfxLZWjQ}tSf>qRWHCRh_% z?OZR$NOmZs+POj8+RyVI(JXDHVdDbs5zqIt`NT`o_MmC1(2_aj1P!%$;kGgxc|;R+k@f>X4=$yNc@GF)@u)mzcOpWm*wU;9}>GI z3pG|d9~OK2m3u^d+EY%&%eY5GmvlXf@2EZ^zLl)nxXbyd_(8J!0y>?46c;2r6ST|O zB24QjwI)~>QsHbB3Cy%)9uuk3Hs7$*@t7!Krlq}EjOq1Mjj&lvl&-JC2hPpnnqH%T zEn+#dZc&fVq8=CDNcK=^88ZDJsQN~@EP!lw$@b$LtdEPK%)0&O5B=2nxEQH15i*2q z!9-qu}QMcc!Thy_#-nd@2A8w%(NChCEA!Z0qDMQJ|+Gp*&qGB zac&j6C0iNzo%3n&0W&SiGvWXmHGtl)FX&jqv zPIylIA{q6?^TO{QszPhUpG5>StrdS3R%T7G1&8p@B3ZIg#xdc45yK?AAz(~+n;0vZ zPK*iPF4QZTYGGawGo*2up)vLaQ7_qAQ)BFl;(lh@`h7{%_$ZlfUZO9FX31#9yeuYe z?6bWr06(ctbN>fa|C8bWlOFf~|4VlLl31IAUkrk#Qu5!GK=LXF&OEp_4ZoF%ueJbw z!hKl^z29D&fj_(e+fg?0#~}XjNEUvz2ONk2a4ljW++GOy3Gwhk*x-!7JI(xCM8GS0ggTtFRuk|OZE6hcZ*Lj^8!qevrVmCZc{3M3#spUj&4I<`cC z419zj;DncC69(16-<>qd^w(33R#`2+S}(YF6z&}zwexp1^CBsl`T65wf7^10!tdH0=PI3A)J+p;0I!>jp6nU=j&?ON6^<=ujqhJy=C;I;h7=ay5c&QcN zD#IaD3p#jmlDrJ+<_vtD@>(IE#DwK%3n?`G$t-d5YoJcX+fWVIUp8 zheUyXtD!1;<_%djpB~SfxDRe+Jq?P&Gf&mY3i{9O{<1deN3#2JU&Ql3!*`1)(B3>s zt7qWIldKBNvyl8&JjpckbufoDgK^d1*wf5Y;Vb;?P{8ppLTxE(eXyKedn)UjGRt{I zXjYQ7%KGL!c^=Cl{6hlG3>~MdHOYq`(hFF_rL>7Tkq+9QfOmPE7VxV5?KVT3ih(y3 zylTLW#E;u&;x_s7reem$w!vY+Jw=-d@1Pep%|Y!STuSYyms|8O1na>Ubg*Xp1_)~W zAP{Gl3BKUv|0mSro!9BiI;ikqCH=<&O}xMS^?Ex7ZpT z{2M#FrvmEDo;GRi>%YIywC)=~DywZ;)MpB>y#KA|rrXJXzFJ5j7GR69qp>tB zq7fe-ex8l5k%`Z<-SB6`!T8HnbeSp?y7P1^P1?N%jPYDX`C$AWkXY$ES#y(Ctzug1?Shd{+6Oc!a3r&6t*Gyfr)xyoi(Y57vDla>9La1yOGL;RE)P~2fkmhM3EKxHew*631B zDJ{imiojk8#diX3v*)YI!|b$07QS=H4azo_w{t45a4MbbvzPU!l=QU6InZ;;KGxL0 z^3?A!4&i>(D7wRp`=LH16lJ5$qT3H2WY~0_>~l&vn(x+ag@-&tbofIr)Lo|;&ok;V zJLnw(X2hQ{T&?@idjaM7D7(eS`1!+j=}9f4I0F0ccxklp6>;m3iIAn+ zmzQbmWS_IjyPh)RUQTzPC{wYE9)Mdg#3|)N@9oB|pc}r%=oSX|-B|eZ?6>t^QIYhB zu|k(0wi)r8ysgF?bheb|j7xQ|yI(Y(QjW*Jf_QR>Ho0Ci?&oS|;!wVCJd84aHx==O z@ifcl8TGvU0uk|XgoQ~g<61P2^h;#Q@sR=c21=`tqx*D3U%a2@+>M8rp2 zT<1oGp65Nx`c~Zs@pb+u#HqXu{#$SZseo;`rA)+cO3)N@C>2T1`8$-{(iafdrR?@k zROl1hwPHGMK8JCHy8XAa|90M*TEz~v^n3qTF!bB{wc_T)P~FSo-W0`rSe(rNQgmXt zWbUJ(DwuOD)jAvPOhvIE4$vjkNx+f|7!Do_TR72R~7av^d*J; z?7xrw_p$$B^jDM3hgo%)RThON`e{t)i1`Gkb%Lk2YSScuc-OR-Q#yVXJ+ZLWuTEuK~GC~XU<;j(pz zG%?BZgeb*?no)BiP_5I^$ej>W*rKeoe6Ot2{opEtbvjySt>SfeP|!vl4a7zrjq64o zb#)+a`nW-ILR&bY6TAs*g*)=D584VRvnzxCjB9#P(960&+bu!cbh|QF25r}UgfUNv z#>keSQylpfm9sl78Z4g%1uB%pDTVgfPS&4ieJrhq!K+%z%rCo+*6o@>8)v#Lc{dia;Jq(;p}G0e1G!Pg>Hom{P21!Jb>Hk zR(RY=a%?(nv18p^Lr*F1yPrj$?4s?Vm0XI>%5R|l2XBg?vzdTXN=V^>&;fdS1!$q3 zzG1hJQc+C{_4F0Hg?jpmT@7bfqo*(0)#&Mqb~SqXqFo&h$3&>n(`Hh`={BP#L9El$ zm+sc-=}UL(^z==-b$WW;W22r<8xQMg;W;oN{Hi=+ZP<1_eZy|Mp1zp3T~9A@sBZn& zsq4dDVb@pmGyz{hS0jE)jc_mHKExBo{fOFG{2yV5vG5Xcf;IcN>|QKu4e#WN_i>y~ zo(+2$JN0y)?qr|6Ebr6PQtVXqn~DWiL%0=QP8}2eFjw}lp62IiJx$N^*kasbu~>pQ zk9{yAutN#7T^HV=n7s4QpOQYUrzza2r<1SVKrg@q8eYqOCfs5u8#W^FVJ_RjD=SNX zytD)Ljv|C9>tih8YzR-zy z!q~}38dC&mA|pr>8BrwY9RWH|7e(MX9^*_w{VsS#(7w_Pw6#0il}1Q3;E4=p2E7-Q#+o$L1pDW*oQrZ`K#76Q2qgwSEgI-sMrEkE8yMg2#3-rJ_TcE}=2 zoncpIgQeM^dD1uKnhm%cs!(Hy$k=A7F?=!PZGDY_F6dttyE5OmjOCykbrfhU2imA3 z&y70r+^8eZbp~1&4uyOYmE$hdW@c! z6G<0%XCq(X)^u`fHel!Dg5>J=v3@`653}Y3YfiJ~YTZG;m>gHQAZjZ-iyQV<_-8x~ zB@NWHC~g#u~{fk)6_v&uVzddC zz|`n)*dQk2PkeTW>kZ*U5du{{genv$jAe^51Lc({ zhvQ8hh2E)9=nITRItnpWN7kzm@%c1rlJF-%wpa(@H~v0JNkKV1IRl^5-;yWvspiz^>bKXjd*ZSBkP+aQmH1Wh3DKW*{7BCYV>9{Z|1_A(fqOd zaW;3bez!y_yc?|-+<#~5KLC3nx{IydjE5ivt31TkuNXm4x`I(B$f^_6PXs1FI z64;!;h9pK0>%EL4*gAssBN@wCU%@zsH4Q8`GB&Y)6YEzpwy?gHaWh*tv;J|F4_gt_ zliS(c!MK~9cC+>Gj9sknW<12!L#+Rb@hDY{-Sl`Il#MUO(uVidx{bts0 zRtBn=*W+wxXF~_$ZZ_{`{ofh8Sl`Wfh^>cMe@Ll?#FXz*#@6e&^^7`v6C*JtLPvT# zYaEOTs4q^*VZ8@6D$ZwJ3ObEI)fVdrG*3*K%;s_~Fq^Hj**cpGH?Y15^#=zvvA#+7 z40d}9>suK&v!)Bq1_yo@7QKZ5n;tf^p}&HCA_R~tB70~;C{o7mjM<`%ZLu)dXX zGg~*awSzVPKsi0Ri{);{LtN?*`+Sf8Ly@V`VBlsj>I^(34V123WtD?5fei_4@UX_q zIKn{PTZa1d??r7ja= zM4bOe*$Mo(1&lgIJEMa!fziY0WgNj+;YSrzusoZwfw7UX$u9-_poQgD_H1Q&Gwa() zR--#uwVSbvv77M_BbYcXMjfM_(ZQI&=wTeeSk5?`v4OFPv4wFnV>{z+MzxC%hZw=1 zD$_CA850;ij9&jHaJjwyPW;m12-cJ{&Sq?4+|1a{xSO$y@erdhJ7K(AXQo>0j0q|q zJd7h4%gofJC@`LAPQ zXLK+oFnSoh0hG`PmdhDuGd3_bF}5&nX6#_>W(0f@8`lM+ozcPQ4y2f#z-krEURI68 zPwztAuzMZg|U@2tt@vizR7{QSr#EwnS;^GI5vbXzbaV1A;byO+>IJX-3Vil(ihFg*{u? z+KQSj)(*xuxl}jHM_Hz?9^lY0dKt?slu8B5jTWB&&8%u=RR?32+?q>NgTOsmJ zs7V%)9FEb;SP{wLSZ-u&Wlbx~9gLl<>B0yvC3mw1qV9w<$s&s9za2^8AO{j$ij3u` zSum)ApN67bTR2> z8DcrdSZ*1km$8DeF_t>88D$&}_S}M+PTalGHKTp6eG zR>Pzj4YBT4mOB``86ln%iswL#Ud9T>M#g4DOo-(U#!l9Bvn*^*xYg}o^xF6=it=iA zxh;jR|I2MuL4}PfXk=_*O)JaoEO)Tn&3G6Kk9P|@C&cKnQv@%|6^sq6X=J&D;YO>Riy5J^;6kBB!=tnnmK z5+0VlY%ODJIcpl&+Q4#qQX3o|)WJTUWQyiZri98_u1KcH4J@~)eCS|R7t7r&!yw)j z29c|Sv2qY^$%u>H%`CSJqR_2uZD+ZI;o>k1QjldV@Da!DJ&-mKtS-3elMlWLrV>hF~pSi&yVDzML{1oypXSssqh7{ia z8=17Ev_Y<`mE{h`Zbp&H)i9Rh|FsOejH}F-v6=zGC1oD&YEQpV>x33V+&(DV;3U~rc!oB4`VrF17izgJ7X6k zWU_xIrDbPX^)T@;DQB$Aq#dd<(+O{is^H>S6EJD*~4-f%jGOLFt#wZGj=gTE=902 zdKg<6x8zdH_FSC*TdbW-y4Y}-Wys@Vj2^~v#s3EAmI7d|S?V#JbW+h}#mbLhRodt@{2=dM1TZ+&P#cug|(B0pEKx zW>q5bWGzOlE?kaSRJaOJYpd4o|E7WwM((XPJjuqv5q|{cZRDx-;oAZ_V1jc!nvr?W`I`sf0+lD*=ay4 z3Tf?VleGV|{bcYWj5&gPRF{@81DzsEt9z^Izl46fz>a592b%1J>kI0zl-399N>-ul z9m>ApxcsJn$%C=jQNK(r|%5i^z1h}p_mF%I9GNP=9`zH-m%%xd z$K!h$Nr)Fw#-9?>Cm|~MgJhS39_7oyi1HO+Liq|XqdXA;QJx6FC|?EH`oV~~`Ygoa z8TuSNl<4yihv^FtJ^CWV;rbyk1E!E8??=1WT%AtYx|74og^MLS$Ct z^vLqa`H=xp;ZZ43#Zkkf#zoDDnicg>)RR$dQNKh5Mq8p|qxB8+9xDD1{_vmnN55yU zuukK{qL<+ttK_BA6o{jvj|Ji9V!tlB#Mk}xcm6^6vU?2RNAYc+9q|)kpX2MvdbnF5 zwH_W)g4#}f^Q4%3e?*&j4}awL-+l&txy7J=$P%aj*y7d?jGU@p66w~j$A1q*Ua#MS z|K5w7r+*ZGdE6Lv8RX!<$x--@VVGOLH_EL~$DdA(!vFn16hPb2V}G^yvi=?4_U13X z&>gcvMU`R4$C2XGpdEV?#7s9RVtT}m1yjZ4;f1*w_*#4}zNej)k(rT~n_7{Vmo+y(FT1E9H@|Xr(cGNE ztfK7vqP$tN3iAr{a*J{*a%LCK&CT6$a-J|6qS8P3v;o9~iTF}E(AVQ0UM=9^8#VdvKH3Cu=Y)V-qoT0mqK7H3c&X>pB{mP{7g3)W$O*0pX#%!r|g-9($drsYaamF$D zYF9>f;H?;;=g&v7eS;%PS-ED%pvA%`HU%#c4gNH+Jit3PEfK#6k-KBlO`=vz&c)AX zEAXcV^YDe?xj6jz6NLCXfCc!TZa!4PY?S9h4*rH<7E0NuD?*Q1_+KF&>0d5taxg*; t`WB*ZF63^SQzP;WxsU;wJ1Q27S;D_T;P#2MFf<3pfm;PQl)n*BG@CMsMtWFMxuCVgyXQkHL<=Io`NlE zG$>IM#YRk?C{Z6+&?u&;QH+H|ebMm#vmCJTzVElQ|C!lxyR+r)U^}f?#;psSaMX{G zK1&HX>`w^KV?KR;LGIk??-P8E4n!TwJ{jrcYs^=$`J{}Lc$5=@35icZj-8#CjokQG z%xltoVc41yMg6?J`Nm=5`#-E-*UO=Rq8~@dag^5RmxlRXC{HK|d2fAPx*luv5gll* z`c@xGeuQ7)8N7ma(CNZQPzi_N7@UUh;4<8R z7I+BH;5ATpH8$!_i3RiqXYd3+7!7k_AuNS@_%GaopWrdH!5iQ`C^3PaU=Mx43j!em zQXmb+!eq#Wc~GdvWEp5-J#2=5!yY&U$KW)42Tkx2+QGn+5;L#?CkTfLunsnXem`s& z;vo~>gK2OP6#Xg5fcHQ>9g{_H02-hjW_eL^1U~Sl#9;tV0~Eko*a($CeJC*nYj6ZN z7ytty(g$Nr`cRUHJPfA6QYeM>uo)_SaQ^qnI=?~XU|&kcz(%NsQ@))mVmcmz=r z1Zgk_7C;e{z-ssy{s~pEACABYsDq2p2)E&9XocT{I=00P#CXHSP1G#oTRF3Uawi(j zLj$zH6ClB8hX7ptfB)dTquwY4mne8cDr|#uAsnfPU!XOlb19CrA?t;5!~|SG?TLvm zL_i#*LK=*P$uJid!ctfXB23p{~8!a6qc7v@94c~TB1;2d0lD{uo|1Bu{?0hodL~dtl9ID<0q%n$iV|b61Um?ZC^aTYFdSCED%b$qpc3}MVfY%(!LRTf{s&w% zB}(W4w%`K&z#qaO7E)m(jDu{L2?g*WEC+QtCjWpfupRco7jPWTz<=NhJO)J!`(~XV zN>nkpLckY7AR3Zk1dM?!m;w2)2#TQ$*1;yIh{5&08#4#tD4c?C;d{6aci{m%g;zjg zas9@!9iYTYS32lQS6%6?D}!|9AS{yr*{}k3!dYmBx3OwGaN=;?gHK%dHw#9Nf+QFY zqhS(EhdlTI)S!X2un|6mUGO=43AJz@8sM62-FJ}hcV;!d$#1B5*;#?yF3sZ}&mQ^G z2lsku9{2lr-0#7?tBrNQ&gl-lrU?dqc-uVwQzS#(zR@x--~kj#^zkdfTEcAiW` z&XMIgy54%^bg~}#78;;Q>VZ3IGVZ9*s>{7os%I-z4r+D}JxOszGFx9mSMEck4Se5KL5LwbT$X2XzlW1r54Hc5)fyu=$}(H3NtRjrHCblM zUzcUJ8#ms`H)WYE-`t(mgjL+?u8{I=S!OG|E6eOSw8%1R|4EjW$Un<6Ykwfi?705g zmGR8&fr>}66BUKr+SP#&E9Bo~nVspU@8oB)%tpow+4|T>`(4&*iBo)%d03*DyJ+3g|A?Ce{Brpt$sS(^vAa{@V{+hMkY z9`9sNS!O5OOPuUwr)E8UWi9)$<<9JmwxX`gkvYiey8bnUBPz79VGzcdlP{6khkccB zS!UxhLY7(kpzb_Sx`9OD*mSPI1s$SgnfwM}an;V=8NB*fGUoA(N4TTL1VZ_G>&^g-H9G~&bwpX+w|OVAAGJhXu?KKxj!)F6jLy?pYjR?PoD67q^SZw zydU#tG5wXlZfr=F1zfjc(^t~8BFcz-5q}rcISHz0BVv)LidK@q#4OA&!c<8#i4~Z? zlz10Y*CbVp5vfR0B^wcCN*1O;Db@4+m3pdy#arFlJO`FL+n>J{pX6E8<4JS$G5d(! z6OXQoY}+<>c=f-6r*i77bD1?cy?N8s+fp*?TZcKlpFRBOsl9c@Pfya8x`D%+m;I7~ zc9Urr&he(C521)IRq4acqXY`c(3;gQv-O zGSxw~yKJb-eB()(4^ovCoNc&q4Ii{H>!83tUbSd=qVo==)0l{g3zN?_#U^ICdgLF< zxmxacB(!+f{zX1U8y`-Ja0=gYRUCM*f6GbZ)Zgp=$}31Jaoyqd#3eRris7i~HRInH zB_CMY^vTHJ2gmzoG>rYMZR!YdyZYJg+4{q4?d$I;2Q*)IovV4Y#%pp#yYtMjhMcPK zzISR*dwZVQGU36U^JR;@%FQ(CwL7ySf@?!3)MRd)(Qn+Tk=t@lxbOPDtaawIp>_I0 z_MIs`vV7e0rtKP&i`Oxe+GYc_QZths-V{gf6LimBHr-o?Re=$lhwUP zk?IA9+g+9(B2M!yzrhIYSt>i4LJ4I~^pW5qxJk!!Tcib15b3W;{ z=jx=LS6>yLAM11dx00>59jt=CZGHRMCv!|cjp*;~x@(rn+8l>nm&TYlYm1_YC`6Qa z3f6cOSe4!pjOj3r*bz5 zd$O{R)=4T2weC`BuJv&2=r06pBB>zZkjNd~wK}kLW7#`#Gwxt%3#q zZAjPd6D&z4M|!bC!d5v^dt9(%%UU3qYtP^d`EkUY)u>R@Uuz`xo2znaFw!S3yrD_w zR(S0-_u_i?imgv9wNJ#{x!=Z>dkMD0j12^~I=uAsD-ROvyK3x1hzVaFDJ;_`0rtd# zBy+@uSaDbZx~Jjo+q*nnoS&CQ7m45Gx#JhYlRR6TPNV#00fQDJRvNBVhSksV?@)7j z6-MpQ>bnI$a?0-7>Wd4uD%AF=c#de!TUihlZ>Ud3bHq}5$lxCnXAcLq_}_cj4`n@m?CcT5v42=Q7U$>LsHNo}qt%QvM6GVU z^PHvKdX9R5H#8&@IYVRYTcK><*ej`t=8c6REv{#+*j;wE+%&a`E`_=rL7Gr*&>yJr59Wc((v0%Q{t)|i3J5RO|!G<8Pxoo#iKRY{rZfJzN?H;fyqw;`qJO}0I-RWymQ(h|*Y#m~X&v zB%WO2XQE*5D}=q+4jL`~xg=Ggmo!>TE*fQOFl$UlcY*XS%@g+)&B-vDk8Z2j%8l4p zGSucv*S}JmKayqV@)+q{n3l)7vn-UyN!h$S-klu^v+^XV-oD%+mbF_JKj<4bR-C_h2@emR(TMtM+1NZ}_Z^5wKKP;g^P z)Hl5t@*6yWzu*P1-V8AZ8*qZ&-~)jW2CI1Asy zPjCnB!(Z?cI6pO3>cfDL5Gbl3~?f*9i7AEyB-pb=KWM&N=OVhcUN z1NuS;#6WT|t~K$;kSyd}D1jQ#!%|oU8-sEFcSt(FM&+;p3@L(@@HHG8&^Z__u?J#i zNE_OI2g?wgKJb9PkOjFg1u8%bOJNmU1e;KXxWPzR9*Xn7I?Oomjxg+PI75nI0klEC z2!=$%2$%_TK?6EyfX`qZY=Rcp3$5@iT!1#X1$W^QJc}@{OCE{q4L3JY(~Q0HrUB)b zX!s5;!5w%EvM97eB<}wI|KYr&-ZC1uC=7t1uog~5v*bM7gGbSwOR?lBvNDDx*5Cu` zKup3Q5z=8OjDXQF0cJrZ)W8y02Ag7Jqy;X<(1B&74f9U1GSVA-AP~YJ7Lp+ohQml0 z19PAXK8%&A$v(^+fzxmiuEEc64<5twSmR2VI2nnH<48TU!YMchSKudj39@*OsK6H7 zAQ%QiJ`}-t&_E-sg!S=ij%>!v9ykpb;VwJ^*MS@v4ojd7dL(cp0!G7J(10$1ZX8D% z66EAF*d}IL$B;t_3^@ts;CE0YGQh1Pp{U7zzb21}4HZsDNsy1$8|ppTcTrhHbDL4#Ele7hHjdph%{B z*7;+IS2FGp2!l9Cg~5;yMKB&pp&aJJLih*-_#D1S#{ItqGX~fX$KVWHhU@SP`~gqk z1;|ox|EAClV2HD+bT^g$rgDI(j5d`?SSAy4U=+LyQ(z{1kYc?5!~qwfq7hcYde{tK z!8dRezJp8fBix4H;lI!UY$_hfU}rgBM|F<(RZ4sGyFH&#@OC7q`~ z>{SN#D#Ms)wnKISPY8feu?>6H)kj8BB=gxB!q4VjeQ|#*$>7K`Sku+YkqyY(CHZSp zZ#hwA%84yFLmzzZh})RSkp2*9%Eg(6xhi)zwHaCuF&x>5?W4b5a9EPlRY8ax`JyCS2>bl|s4Y6P+GG9Z21{#VjYuav(exeszX@+Q-j=Y#wd`AbuFM}FR!>3z;aM`s1*d$Vsc zy=<>w<+Ob>2A~hGNv8f=kloOB6!|6Ex0+VqjpaKt-T2$+L-RJY-$8bVSIFCu>H5iN zEYMj&8yQpHfeyE@us7|*a-;>B{#;S8lFT4;lI()4kmRS5Om}FzDeokV3t55+`st>^ z0$-U{KrdYjp}t=)H9fo5k`{XQZMtRKZrM(f>D6T~$u`JNtg35G^y+evWV!*JIfWkT zrKS!Bv<$<%&Xji{(>8zbW_hyPwCQvMeY#~|Nv0>euO!p{0YZIXFZDL8I>^-GhuZ3{ z%#vxy`9RyhCM~X#iUAIh}|23LEI~3ylkr+C}u!yF!oxxA080x zYO||YsTKP-rmSo{uH`43OvaJNoR>J2;g9Es+%ZfaaBUV!@?lt;1D!q-r%8$CL_SD^ zY3ra?ObgRm6IG--jU<_qBbchlg|sBhJEdzdou1x`>Am#U40Dp7NixmJf=ok8s7mg> z;0&)#yFK0C-sX?Z&wZS(MZABvS`&0Rcj~jEasJslGsBNj6Ijok3Cr4FrEdCLURXC` zb4-)-vw1~FSDbtiQK(x#@ci!H`)ck9@5b7zZy%pM&Cfn>k9qBerN=A!WcNwm@=5rd z-Cplygmg5$Nt&byPBV|ZaKCVFMY+{vZPsOB;hJB*2(KM{f5fnW*>`fkoV)MP z;>o$?#7lleB`YHhPc`d2BlQ>fs&~HF;;&InxgU7VF1&5wk^VLfOhh z?HY$7ix_pyr|VjOts7c8@B81#n#kLwS$l`PzWw~dMb|zRHDlyYt8=FIe@`vM1qAh+ zILpblqi5il3fkyX?-$?wb z#aK?g5_$I0uHtR`<3lbr9Uijr@slM_cHf#8{8QP(O?#84KO9?8X7TLK+a>+wW9DyN z8C`L*SebSI1tX-#*ZPl(hzOY!84(&26&^WZe9WY<=#ZGu$e4)Y;^>Izi13)Oabe@5 zCxwR_p2Tlrotu{wUL_hrR&TU=XSwgt)RpJHD!Xv$TA9I+_|ny964Nw|Y5It1+Q2lm zFii)TrgKcwpG>m_)9l1F`!mgnOmmLm`_V-fy(aRu?u0nheZnhAC<(M+9oYg84?=9~ zRtectJbG{C>0Rkmw~ObAGb_G%Q|b=#eLQKG6M}w9AM?w+BcA>abvJ~aQye4i8#~(i z5GJRtoevKw;SYsrWE5)z`d7hX;YXZi^tB?(rUycuq85{-vu zpf*>iE{SHw3162CV#>dGQNq}3&tUvmmbh}RESVXEt(ZHwr=TfK?w!ip5PME( zMw}IuN)pQ{9Z8g;^6deH)oj=02{%heF%?2|S)O_gpGFu(WiR{}ZM?3T_c9A)@#5@Z zgQtZvr?eytH;cZ8a&-I66+}fxw5NM7P8hb5K9V`zF*jp*!qZru63a4O8}@;=-xx+q zGu^NDwDi*bCYDOwpZ4Onr;YAmZ)3;yI9gii+LMgA!`D>yqh&AM>$k+L=VFYdQtZ#^ zE#v4>&DPuSj(8(i(*M^v=v{f4cq;L_EKtyDx{R;ho7XJFzbi`gQT%Ws=%#6ye8GIW zySkXS#eWv^_2qmIGLpsK!BxY+(qPb(67?R^d*_G4w3|g;l+&H7MTuT$W4^nM!*& z&nz6TYVDDMG`nh#Mba`zd(xJc#oB{B-O+x!rM&4HF&%79w?b%~m#Cf~o-UPk!eH88 zshuNUA6D8A#nWr2)rZk~3$1=6E$y@)xzo~0TQBzGwT5)DUgtT2mP2$S9BG-Pd)LKS zP8UmFw=S4wr`p-#xHh%rel&XvIrDAR2jl6yMePhHx-X8kwZUeCak^_i3o(`}#BCT@ zyHYH}>rVTa4J9N&yU<5Pzh!tbNxRsCE}E)coJxms*ZGFLH5@Z|P4l?zvv5PwCkL*M z0&6meQx2i`uafj*i5-a%Zq1MH+0lq^kTvS24wbz7*s`cDUjXqbnUX^AO z%#t4T0>JkIM?4ftA+|axs^-;CSm1A{c{Q01LA|2iXk9=0Z5o<~h%Lgmg)1Ical+2( z5KHmz8}UFq-WhUVfBJ(1&TQscrkpSpnIv*M~U~M zN*|R+v&SN(cyO&2nTrRPU!*b~>_rxS^ypYGvJ&fE^>DYF%`zD&L#(5L_vjH-hQf>h^k_0vmr zX}vMOU8Hq$p`a`yr#S-y10xWdZ=No6n32(RbF@e`W3VZMHbW|d1%m;DF_1K7NCskK zhBO9K1{1KjF_1I?!X%)WC77MUU<6cU%8e|L0Ck{rl&F49OvIxvw&KEab&DVL>xlK72F5S%8e1o@v(ZWQ} zfPuk;kwM>3&p^-AL_5*c)G*D=)X37@#4IJ*GR@e+(9+1v(ljZ_!qmdl#L_s?IN2i2 z#ANaW{yQuTj~%~EE)WP1&{KDRIWy1GW7?DUuOi9wD<)qMXjFg-T3mw)0#%pDzdj<` zmzd~w)3Qx0cj%! zO9pcW6CgWFu1o(XPFUuduE@wx z3B>(Cyi^gWkb#L|n<5j#4Iq93#IJ$)6A=Fd%Yo!!fSG|oiJ5^Ni1~n6baFl8Yu8es zN(Kg?3MMYL1%?4&OFmM2AP9RoiU}Z37Q3s0O1(NIx#_ZF8>T?;l0m(!rW=0kU z!_DiN_A%8zNS5<#T)dV^WSg^5$HlLe7q&n0-8N(2*988{iu~UBCmPS01I=GM<#yL? z1A(^p;@@Q3VzzF{Rxb?N!_IYkN-Wpz0JGa)7JW(5>3_-?X>@5vw|r*&V*juwTNGb1 z#&o<>Ia~Ap!+DR)s^sedYifS`;T>|>^?VCrJU_HBmN5o=X;3&f zQ>E?Qp>WeEU&bSiN6vKdIyT#CykTODe!53pH6Wn({*6k9=tIKN%&d)tjt#42eY0+5 z6*Kr-e{>XDcWM8Xnw)Gu|6K>d4)5Z3I{WmYS>=LL6NJjX8MW0N6j-6@Q~xpDq3G}D zyr;9oa_e;;?R?P^=Tk2w6e8Dp^~uxg7e%5szDt_6xq1z|QA^`L_AB4!mFiYccz?dY zziES_blX3T^zGBnwSRo^U1ZAhZ`--9-`Uc(z;y1lh#5CZ)-GP2(^}KowV+5YZ0Af_#>RS$RmD+L zinksy-&{G>|M`^j=L+|{bANxz@9p-7V$xk^D&^7b$2QAF^2oMsv20pgIL%AMM&j}{ zR?3dDcFav*saU}j)eVrJk1VnHC5m|V~J+O-0x zl7WF4h#48KD6#@+HZYrkfdfc$0|Dr?m7G**n9F_i*LKigt%6EJ1I5_EPuD~i^1x-SNSrQy3WeI;eIOn%gL@c*Vg=I z-G>3arxqzWt=~)V3)bHcvPF!rkUjnzyUlo_W&i z`Q_f><{7)Q1~Pz)Cx`dlvas~tlv!jp=kvvB=dMe~U;M-UgKcw8%(+dUkKTT{CZM~%$VguQ zTza?8`R6xnX6vb01b!~El3n-vLF~mw5U?kxr^tq0Kk-1?-wNgrc^5iu3GL1x2Q^PbfQzJ`r6SI_L%QRyPLrWtw tOVgwz3sVbI6HDVn<7A686O+v>91CO^3nwpCiDoHeTzG0Si>eDF0|4P1GJOC5 diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.dll index a5468f11001f30778f1fcb3a72e1b93cddc978bb..902adced8e8d4e603450f234f6ad1047089f3834 100644 GIT binary patch delta 316 zcmXYou}i~17{%Wwb+9h2f)E68ajK-3++A~(q6iL(i_qeprpcs>t{pl!R4BA1h?7!u z5i*r?aqwS|g0oW*7ZK4(MDz^h<2@cfeqXEEYWCWh+C!&3>@bVG_}*F}Pmisyxm>n- zEAIvyJH3<5v;Fxz)32*nnRRJ1KoE+K&1@+Pp<-O|fb&R-Q1MWRdQ=WY!wsZga@~WI@}JRlHH5rt%KR0ZY^daUY@}3rwRPGi`4%Z zoF08Xj^1zdSR^##0U#4kpO+S=NNTMTs!9|PLV?r+qQ`<3)9}m~$w1f?&^OXhCRQaVp#eQ0y delta 316 zcmXv`Jxc>Y6nv{^VIzrxcmzaH3yECrvTrxL;jmLIL=-z4xw~+`B1I~(5d2s{M6eJ= z)2Y@A@v2=FXjE(std?(L(m} zFmkh34K+aW4M@nRz(G-~sgZOA h!~{k9OQeL;2Tof>TLd(DT?`?3;M-z2&MXVR*$)IoTJQh> diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.pdb index 2d70b0ebda4f9d99be3f2cbf41be1d292957ddd8..08d6e79051262458ae9d50cae0a907bdfe5cf22a 100644 GIT binary patch delta 1083 zcmZ3GFehO`fr5w@1B0?tPJR*t14BcuM>2!OYVWzlE;-zP`$OJwE$*K<;aHf28Y6=| z5UT;PE)bgl@d+S)3&dZ5__rERGXo<7lR6_q3=sDK@pd5I55&iT_<}k}9t0Q}ZUXuI z8jK8z8j~Fvg++iO?ivu8S5Uft^JT`%OpKc*FK1D-6=qRqU}M+|B-t5+*~1u^8DtsD zfTR?YG9wFvAd3PE2g7L%1r|<*n;Ho~cBAG3Ao&SMaxyS%W@Y`$RG;bWxG(XfQfk5a zWjqgdT(8&K!W*aOKG(rFepbQZQn}TQU#nOd7}kc|&bsX&P;34}p3PQuN#xI{Ioz#R zR2K$JHxvK9@Jr$rDNp9rv74>EE~tMs|CO5h^xBOrtfG7PnKIAMDK1HyVPb3lN|NuA z$hwV!<#Cf#`<;HyewS?1FUnqjK~KHnAcHkSimpOOv774)zI|&hOcQaC@mQmCL*UAd zrekUX8?K(KzQiOM`s2(w=36pxHzZDQ^l&r9yt%Pt(ONV14_k!at30&&+xU+2Ai#e3_U+mYgH9CKAnIqS3f z4_R6My*B%(Sd7`mQ#WnbRU5T5{%g;;T&1UdQ~Bpd*)SE3>`e<__m`DbzpQ!T|F^H{ z+aAl3ib*vt57V1Mf85#7mYSU6x{%2~qviFDf^5(3&jA+v{?nGe^|4raqFI%*$;^Fz zbAHYmj|Vvx9giomOr7&>Tlwj>Yfla*HYA(Y2Yuct_4WVR@7oIYy_0Hu7T=P-MZ#A+ z*mkbiXGz^|Roe{o12FFX_YA>op_-Uf^Nc9oO&G%XRj*>c)MH*%F)@U5#a^S@`-)I3-t z{ASwmyZ@A=yR*~2e%O{c`LOtTC-3Q(*B;-broDi-Z9&pq|H-mk^%|)b2F4b~$;QTM zrY5Nt#;GPINokg;CMibArio^TMrjrXMyVEtmWi8>aIIjHILGeZ&+veeLH*3y-Uos$ zK8rt0zdcVyE^+cnURe#tyu_T!s??%ly_B3BU~2C=Fl|3W0|UdCor*90mU*~MH12i^ zZm69PRIFT|F`IWHg90PN=0yi;qi#9+%sbFu_bcG#F89RTROiy15%^z_WUbf{U^ z-u_q$GRw1x<;%nK&mCGAk2YKQmgmEj`=%CWK-KnTDJ*4R;AY@VKGyfBZmw5j-k*g| zMJKD^YW-46CTH{UNi26_ILqL`!LU8{YHCB{1OFw{Bp*L0Yw_JYkx^)fD7viXXR4>JIUFt6AE delta 1049 zcmbP}upnVVfr5k<1B0?tPJR*t14E#d^mFFrJ{}V-T?M12%>Md1>CB#q6OM(+s4+4q z1F;qm8v?Nf5T60!k3jqbi2thrH8U_Wu&FaLBmnUQAl?nchk^Js5MNOT$%6nR!(AX> zSc8#4Rb#Rvqp%22#9IR*^A1W+-h7$yG85yr$;(+3ZN*vC8Q2&O0!elTarQ6}L7>+Bhdi6D>XOK#olkFh zYAn&?Y~8hG=MMg*{EM%8NJYGzbvLldZsq=q`r6vtk1f;P@t{_~qx#vL#m0x1ynN|+ zzF@+#g5I?|E_dlvifG;YBLBE@O}%A98S6oAwi^rz?-?BD7;8D1f2i!;wus@8LsII= zwgm_IOtv*PtS!4YS?t8hW9emb7sNgsI_BV)5F_xQ=&+jU+O3ui%X=&IIj_Hrw~@D+ z^>6`ij&{Y1rhwwDzgN9mX|kks?%u8o>m`^>cfQp7&$426e0lNpH5bavmF9g8d!dn8 z?-5Wfa_!{D?Rz70PKHXao^$unE_G*#7xf)sbDyu8raMXgexhU31{LXF|1#3APe0fG zcjf)S3-iKv^Yu^a*ZAYJfn$F3HG}+K9gQmwIC~3(rSo(%3+23?KRmgqWG|<>Y2^kL z#|vUFxIe7z73G}6!(JFOX~Cq&d*9yOv{3cu2I&X&9&=abtU34X|Jm=`O7^{!ZhRKs zqCO*aanYo?=i~a-Tjxy`zkKmcjnU~(HM4v-e|*EF|7D9z|M%;EpTu5#^>*LgL}x>P zQRYy?xUGEE^_SemoZFYi$SFLw=ws!2=kx0ntJw41>iLtxCtOilT`+T*sQ2AxUc1%) zzP0P^=b!Vv>F+1`9k=6B3eW1u-P@MK_2W@w#yhTEUn5LYShpM$2wC%+bFw5?y+)#` zsbQL#sgb3*iCIdrWty>tp{0?TrD;-zTq~F))SFN3WOx8f z%S|j1r*^YCHcb0=q(k1tV{!wpu7rx+{CI$2~DO)wwjMM9(+1I71I&&cuV0KQSE&aIB+oBdsJLnExgTbf%IPSOG356llVn8FXWSv6Lw)-=FPY)lyO-JKM(Zx7M@!%bGJF zfYE*gn-Rz~pZ>9)U7FFnowtD3&p^-AR6Etez}Uh#+1NPE)FjoyIMu`?Da|s~B*iG%G||k^D9ysa zDAmHyGI9H; z1*+$aofvTYf^_|!;IuOD?cXPIO=sc+`3LOw?bD}l2{SR8ZeKl(E15CaltG&zmBE6+ zfWa6@8Z#sVu`xp$gDHavSlk#$ngC%EP|Om{PGK+tsxoCrWH4he1hUh>x{bi94S{MB crzg(fGG#So&|@&zE;x%Tjd45UEUy2I0F=XSPXGV_ delta 384 zcmZqJq1CWMYeEOh#DkMRHTJajFt+wEwe~Q#_OP_}u(tNFZS7(IQO9UDy|td*U)GEP z0gUz|*o;7?+4PU~?9z;8?Ys@_K+Lh7w}Epzv%u66L6;sDe!u0Kes)YQzprn<(#*N< zo`s2?0Rw{xBZI!7o`IgJiFTr?sbQL#sgb3*iCIdrWty>tp{0?TrD;-0 z6r^5$)&iCb!V%AsYBJYs|2~mxIuj?zKVY|SpFV|4n2FJ3`|4?2$&A4!4B8Bd45mP6 z$dJZh2BeJ`EE&uhOn~eZhGZZ+jlr0~0w`+^?EnA( diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.pdb index 09bb1b130d18b8f50eb2f03e63594c0fb0494ca6..ab7c2c7de2bc496aa83be66397dac3c76ee16a55 100644 GIT binary patch delta 27098 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 P@z15t-Q-(ccLx3+?3Y+Z delta 27125 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 UD=GJnZ!UfA25xcO)$iW_4=;0X^Z)<= diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.WebSockets.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.WebSockets.dll index a01a7704523e60047b20e2c8498770d89d3b91e8..a3a774034539002ffecc6d67395e8e526c77e24d 100644 GIT binary patch delta 306 zcmZoDX(*Y{!Sd~${*H}3ITDQKlYdI6GMaCemsI2z5c>7)UfJ)t?t9KNH}mIj%-kHH zAVRWXKJdQYGGh(VVrDioMvj0YGIseVv>|*nQD?^lx&)4W@waV zVPKSMVQ87SdA6<~6H9`qe$V6$`T+t7Q^F%mwmo<4YI5m>b$P)*|G Yqh_Y8rVM%v2Ac&fm>4%RTKs1O08n692><{9 delta 306 zcmZoDX(*Y{!4joc-LSDIM}pC8@=pm>MzhWGl8XESF|QWy6srI2JynW*bDgt}>E-|p zVO9$hJp%>?6GjGoLp=jMQxok(Q&Yn9Vw3ZX!6ppa42cY;KxoL2 z#$X1djTkH$%o$98>=cG%AUlo0n85-lYYCJw1Cpi;NkC`;q(RsOC}IpW!5FC40;tx6 b!DRALGgDR*20aFY&4Lz8jGGxP{xbpqks?=P diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.dll index a68c628de93e648b986589b29f91377245cfbbab..9328d1646ad3496958ec1ed38474d025b9ab04af 100644 GIT binary patch delta 350 zcmZoTA>VL9enJP!awmqfjXkYBjIBLPtv$?Jdsue-WHg`d`isRCNOk{W(Fany!BqR} zUo6{S|6+aHD6l>DYHCB{1OFw{Bp*L0Yw_LwqK55my@jcs0Rw{xBZI!7o`IgJsdlP` zfw6^gvaxZRsY$AZajJ<)QkrF|Ns3XjX`-2-QJRH;QL2TZW#aa~f7ljZWU&m;?4Q2m z9D9I3)e-$31Et$8b6W$YK7I3DGM(i-d%FTu)I=643RKVU<@dsT&XoV16;Z*0+gG1w zf6T*a&cMLH2*l>wr{7_J%*bfEz4{(|J7cgZgEm7dg9U>DgE5daW=IBNV}>*aQw9^T zxG|740m3Apm?fB$6&Bs@DY0v L<95bJ?Ee`7i12W< delta 350 zcmZoTA>VL9enJO}+PZH~8hcuM7+ZUoT6>tc_OR^u$!Ip+^%sjPkm~-$q7S5YgQ@n{ zzgV`v{>A#XQQ+RA;?ip2ZEg#s_ljQtp{0?TrD;-STdM1m;l)+ z49P%t8iO%|1yI%!C}RdBO&OAa&;m$Ysk#QvWV0D<#xWB>pF diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.pdb index e13f706dc082da6cd574d68b817e9b2f62651061..ffef7b76db36fd7f7f74c7fd1f2a86f789cd7b3a 100644 GIT binary patch delta 23178 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 delta 23183 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 QnN6zc8rsPD<6wvUKX^@ Date: Wed, 19 Aug 2026 02:36:49 +0200 Subject: [PATCH 106/283] Gate cache hydration and preserve legacy generations --- .../DirectoryMessagePackBackingStore.cs | 26 +++++- src/GameCult.Caching/CultCache.cs | 42 ++++++--- .../BackingStoreTests.cs | 83 ++++++++++++++++++ .../Plugins/GameCult.Caching.MessagePack.dll | Bin 50176 -> 51200 bytes .../Plugins/GameCult.Caching.MessagePack.pdb | Bin 21832 -> 22044 bytes .../Runtime/Plugins/GameCult.Caching.dll | Bin 96256 -> 96256 bytes .../Runtime/Plugins/GameCult.Caching.pdb | Bin 32928 -> 32988 bytes .../Runtime/Plugins/GameCult.Logging.dll | Bin 6656 -> 6656 bytes .../Runtime/Plugins/GameCult.Logging.pdb | Bin 9544 -> 9544 bytes .../Plugins/GameCult.Mesh.Quic.Native.dll | Bin 15872 -> 15872 bytes .../Plugins/GameCult.Mesh.Quic.Native.pdb | Bin 12316 -> 12316 bytes .../Runtime/Plugins/GameCult.Mesh.dll | Bin 695296 -> 695296 bytes .../Runtime/Plugins/GameCult.Mesh.pdb | Bin 205548 -> 205548 bytes .../GameCult.Networking.WebSockets.dll | Bin 14848 -> 14848 bytes .../Runtime/Plugins/GameCult.Networking.dll | Bin 517120 -> 517120 bytes .../Runtime/Plugins/GameCult.Networking.pdb | Bin 247872 -> 247872 bytes unity/org.gamecult.cultlib/package.json | 2 +- 17 files changed, 137 insertions(+), 16 deletions(-) diff --git a/src/GameCult.Caching.MessagePack/DirectoryMessagePackBackingStore.cs b/src/GameCult.Caching.MessagePack/DirectoryMessagePackBackingStore.cs index 648ba09e..6af00795 100644 --- a/src/GameCult.Caching.MessagePack/DirectoryMessagePackBackingStore.cs +++ b/src/GameCult.Caching.MessagePack/DirectoryMessagePackBackingStore.cs @@ -89,9 +89,7 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore .OrderBy(record => record.Key, StringComparer.Ordinal) .Select(record => ReadPersistedRecordPage(record, manifest.FormatVersion, out _)) .ToArray() - : manifest.Records - .OrderBy(record => record.Key, StringComparer.Ordinal) - .ToArray(); + : ReadLegacyPersistedGenerationRecords(manifest); return new CultPersistedStoreSnapshot { FormatVersion = manifest.FormatVersion, @@ -101,6 +99,28 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore } } + private CultPersistedRecord[] ReadLegacyPersistedGenerationRecords(CultPersistedStoreSnapshot manifest) + { + var records = manifest.Records + .Where(record => !string.IsNullOrWhiteSpace(record.Key)) + .ToList(); + _recordDirectory.Refresh(); + if (_recordDirectory.Exists) + { + records.AddRange(_recordDirectory.EnumerateFiles("*.msgpack") + .OrderBy(file => file.Name, StringComparer.Ordinal) + .Select(file => CultDocumentMessagePackSerialization.DeserializePersistedRecord( + ReadAllBytesShared(file.FullName)))); + } + + return records + .Where(record => !string.IsNullOrWhiteSpace(record.Key)) + .GroupBy(record => record.Key, StringComparer.Ordinal) + .Select(group => group.Last()) + .OrderBy(record => record.Key, StringComparer.Ordinal) + .ToArray(); + } + /// public override void PullAll() { diff --git a/src/GameCult.Caching/CultCache.cs b/src/GameCult.Caching/CultCache.cs index 396b8a3a..cf24c47a 100644 --- a/src/GameCult.Caching/CultCache.cs +++ b/src/GameCult.Caching/CultCache.cs @@ -1446,13 +1446,22 @@ namespace GameCult.Caching /// public async Task PullAllBackingStoresAsync() { - foreach (var store in _backingStores) - { - store.PullAll(); - } + if (_ambientTransaction.Value != null) + throw new InvalidOperationException( + "CultCache hydration cannot run inside a mutation transaction; hydrate before opening the commit scope."); - _hasUnflushedMutations = _backingStores.Any(store => store.IsDirty); - await Task.CompletedTask; + await _transactionGate.WaitAsync().ConfigureAwait(false); + try + { + foreach (var store in _backingStores) + store.PullAll(); + + _hasUnflushedMutations = _backingStores.Any(store => store.IsDirty); + } + finally + { + _transactionGate.Release(); + } } /// @@ -1462,13 +1471,22 @@ namespace GameCult.Caching public async Task PullBackingStoreRecordsAsync(Func selector) { if (selector == null) throw new ArgumentNullException(nameof(selector)); - foreach (var store in _backingStores) - { - store.PullSelected(selector); - } + if (_ambientTransaction.Value != null) + throw new InvalidOperationException( + "CultCache hydration cannot run inside a mutation transaction; hydrate before opening the commit scope."); - _hasUnflushedMutations = _backingStores.Any(store => store.IsDirty); - await Task.CompletedTask; + await _transactionGate.WaitAsync().ConfigureAwait(false); + try + { + foreach (var store in _backingStores) + store.PullSelected(selector); + + _hasUnflushedMutations = _backingStores.Any(store => store.IsDirty); + } + finally + { + _transactionGate.Release(); + } } /// diff --git a/tests/GameCult.Caching.Tests/BackingStoreTests.cs b/tests/GameCult.Caching.Tests/BackingStoreTests.cs index 20f05a3f..31b37b40 100644 --- a/tests/GameCult.Caching.Tests/BackingStoreTests.cs +++ b/tests/GameCult.Caching.Tests/BackingStoreTests.cs @@ -574,6 +574,10 @@ namespace GameCult.Caching.Tests File.WriteAllBytes(recordPath, CultDocumentMessagePackSerialization.SerializePersistedRecord(record)); var readStore = new DirectoryMessagePackBackingStore(filePath, recordsPath); + var rawGeneration = readStore.ReadPersistedGeneration(); + Assert.That(rawGeneration.Records.Select(value => value.Key), + Is.EqualTo(new[] { "record:stale" }), + "v1 split record pages remain part of the selected legacy generation"); var readCache = new CultCache(); readCache.AddBackingStore(readStore); await readCache.PullAllBackingStoresAsync(); @@ -1484,6 +1488,85 @@ namespace GameCult.Caching.Tests } } + [Test] + public async Task CultCache_Transaction_Rejects_Hydration_Inside_Its_Mutation_Scope() + { + var root = Path.Combine(Path.GetTempPath(), $"cultcache-transaction-hydration-{Guid.NewGuid():N}"); + var manifest = Path.Combine(root, "state.cc"); + Directory.CreateDirectory(root); + try + { + using (var writer = new CultCache()) + { + writer.AddBackingStore(new DirectoryMessagePackBackingStore(manifest)); + await writer.UpsertAsync( + new NamedTestEntry { Name = "external", Value = "durable" }, + new CultRecordHandle(new CultRecordKey("transaction:external"))); + writer.FlushAllBackingStores(); + } + + using var reader = new CultCache(); + reader.AddBackingStore(new DirectoryMessagePackBackingStore(manifest)); + var observed = 0; + using var subscription = reader.Watch().Subscribe(_ => observed++); + + Assert.That( + async () => await reader.ExecuteTransactionAsync( + () => reader.PullAllBackingStoresAsync()), + Throws.TypeOf().With.Message.Contains("hydrate before")); + Assert.That(reader.Get(new CultRecordKey("transaction:external")), Is.Null); + Assert.That(observed, Is.Zero); + + await reader.PullAllBackingStoresAsync(); + Assert.That(reader.Get(new CultRecordKey("transaction:external"))?.Value, + Is.EqualTo("durable")); + Assert.That(observed, Is.EqualTo(1)); + } + finally + { + if (Directory.Exists(root)) Directory.Delete(root, recursive: true); + } + } + + [Test] + public async Task CultCache_Hydration_Waits_For_The_Active_Mutation_Transaction() + { + var root = Path.Combine(Path.GetTempPath(), $"cultcache-hydration-gate-{Guid.NewGuid():N}"); + var manifest = Path.Combine(root, "state.cc"); + Directory.CreateDirectory(root); + try + { + using var cache = new CultCache(); + cache.AddBackingStore(new DirectoryMessagePackBackingStore(manifest)); + var staged = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var release = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + + var transaction = cache.ExecuteTransactionAsync(async () => + { + await cache.UpsertAsync( + new NamedTestEntry { Name = "staged", Value = "committed" }, + new CultRecordHandle(new CultRecordKey("transaction:hydration-gate"))); + staged.SetResult(true); + await release.Task; + }); + + await staged.Task; + var hydration = cache.PullAllBackingStoresAsync(); + Assert.That(hydration.IsCompleted, Is.False, + "hydration must wait until the active mutation transaction has committed"); + + release.SetResult(true); + await transaction; + await hydration; + Assert.That(cache.Get(new CultRecordKey("transaction:hydration-gate"))?.Value, + Is.EqualTo("committed")); + } + finally + { + if (Directory.Exists(root)) Directory.Delete(root, recursive: true); + } + } + [Test] public async Task CultCache_Transaction_Observer_Writes_In_A_New_Commit() { diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.dll index 60e4a9a79526bec2695d2a4bfae6d016ddea4ef5..529f4d3db33eb1bcb35a54741b20b401b8a9c83d 100644 GIT binary patch delta 22456 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 Qga74c9oWy5HI<{9 diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.pdb index e8107ba8c3ddc20eb6547382b301c625c9e1e1c4..082f5c209f6e5461129dbd42715a5a0847442a27 100644 GIT binary patch delta 4990 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 TGE`fN4Kr-AOl_*+TFCzZ?o48) delta 4746 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 diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.dll index 902adced8e8d4e603450f234f6ad1047089f3834..d49d6f58f44aa425c51a86b0823206c98f0e19dd 100644 GIT binary patch delta 316 zcmZpuX{edd!E!Oc@WsX+14%}U$$KSL87($Hmi#Fs@Sb&T$ocp89k<;1SR;VyM5=6t=!v;Ha|95&B$rNz`(!=#1@;Un@KYVER hA%(#bD4xWSHhH6!DXSTS9)rPVK^rl~&5Snx83B7sWG(;z delta 316 zcmXYou}i~17{%Wwb+9h2f)E68ajK-3++A~(q6iL(i_qeprpcs>t{pl!R4BA1h?7!u z5i*r?aqwS|g0oW*7ZK4(MDz^h<2@cfeqXEEYWCWh+C!&3>@bVG_}*F}Pmisyxm>n- zEAIvyJH3<5v;Fxz)32*nnRRJ1KoE+K&1@+Pp<-O|fb&R-Q1MWRdQ=WY!wsZga@~WI@}JRlHH5rt%KR0ZY^daUY@}3rwRPGi`4%Z zoF08Xj^1zdSR^##0U#4kpO+S=NNTMTs!9|PLV?r+qQ`<3)9}m~$w1f?&^OXhCRQaVp#eQ0y diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.pdb index 08d6e79051262458ae9d50cae0a907bdfe5cf22a..076a4456a485c148fb52eccfe1ee4d4a901fcd05 100644 GIT binary patch delta 1034 zcmbP}FehO`jmXc(ZwjQBpK|HmsG3z|-tgpd(boqPCmaitRAXdN0Ah6@)&pWwAU+Ai z?|}F#5dTqQ00Kq^W_3n}SRn2N;vGPI0EkZj@kMozJP0r{+ye3iG#D9_G$uPT3X1?m zJTxFOuc7pW&6gQ3Gcj(SyqrbRR)j^JfsJ7wkYr~NVGmv%b_@mm!u1H;;o+gZ0A1ZvHH$g|n1E{SyQdwW4eBxrhzQ|zsnJMEX+ zFJ`Imt|>eFPQ!8jmHRKIPn{Z_d|52ygB`~b+v0Nn~+YSf9tlxWb zKM8qkY|Wp+U6Giqpl+bYQLr<0@+`AkG6yb)?U~;4`iuTNe%Z4XSJ<|R+LSo1*m7E>+bzO5UT8Yh3$ z=<^l|DYCh7Pggo>BL8p3wE9;*XP>>w`H{bG`_j+8_c=`dE7|Ovk+QjX&bh)#zMFVH zXS!Kk7Qg)SjZCTK@j1_qzK)FJyZ-k{?8R4i_uWl&HuM)|4mFJ1%2{pkQn`EK;h=SV z6AERHGqHYGt9{GV{rT=>^OM>hSrbcl_+0K@rKI&{KV7*(lMrsq&tppCOYkyfLOLEm~m>U_I8Yh~VB^ntT85$-gnHZ)f z8z!5Zm;ptT)65c+Qq58TCne!LMf^E~0|$f20nHv&@o3k+^8Cs1 qm(RIR;uqPxkWWTV*pYFW2jj9J#$|2!OYVWzlE;-zP`$OJwE$*K<;aHf28Y6=|5UT;PE)bgl@d+S) z3&dZ5__rDZ5HK<@sWURf0C5ixZwKQ2KztmCFQ|j$L4c9rCXmms!N{PfG1-w(SOh5I zt^tvG1*Q8pUuL|_#JFklau!8fVHR};Hio@GlAS@AJ&b{wL6)%$NJ=p&GqNxUvM8`{ zFr3yym5N& za~*u+XB8YSm0R8TwThL2VQt9mtlJI(wdOzM*=$vpME;DL!`*sCbz#7CGx6^Wza(yv z@?>5eyV=_7g8EnUU#Y22uie66htlKD99ydv~-|6S< zcgZ&WqU`k-^wcX3GFUUD=qhv+yScvL+qdSzG!X|Gk2N|s1g_j@I;JMD;p(~SOH7iX zKhB(Ez9kcPL*fKS4>wcHn;T0Otu7QYytlr&9Vx!XF;~Tuvp%c;kd@`%YqO7v#h7h8 zb<=iTwNXpszxIsFReIVtm4AMe4O8LB-n8&_e_2`e%bFMdfBTxg?XfJWm{jBPFuf`C z$DIvrsmUp>3z_^gT3+8M$oB019ALrkKW*t-AB&YInpHWQ%-rWU=jW{Pc#vb!@pux; z)H&a_m7i|A_T+G4L$Yao(C3{}U;m%|zO7*2JE_KJ@h$0FBz(n#ZRd)8megHlGCTDs z>)B78^B%wcxFn)SZHq*FLj7I;dry1sy}vDcP2_WkVSwo4(Ayh+Pqy16VWs!<7l-8W z!ZU#%5-yqRZLqj+S2=l4(-NVZEvHR%BUh;f-@5uT|9fUl&4V?Al;`%g)_J3H;` zhi!?I4~w67@}7Qq?eR@&+6#Ew79`#EpDe{yuaRnDU~FNWY;2rnYLaSUoN8i{lxCS~ zl46u>nrLQdlxAUIlxksUnYj5N*9sPmDSn6{sxfq~)6PQ{mg%RJmB8h1MdH`LAtO3KQmbzGA=7%Tvo%lte0`wlFb)&yqOsp0M=TWdjJ3c diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.dll index 476956c76d2ebc0373d6a465bdf66e8258b976f5..3de98925bea3db4a798257badbac810e1c983a55 100644 GIT binary patch delta 384 zcmZqJq1CWMYeEMLi=Xh+#-7$5#?~ID)*j~89+uV~*47@jtv&2N>KHAix7M@!%UUoX zfYE*gn-R#gnEtVzU7FFNowtDATrjKR=kOQhNK9X3l;0 zEX?!_7#K_#8T1YH4D?LRw9SnSO^p*x%o2?ZjSLMFlS~X#lMR#2P0WCz$!TVZNvUQj zmZnK*+fOBN>FKfj(5-Ks{$~PLfWVQ%-%c(|-R-vecFnmLZ&X{S$4um^R)C6%WkW?l z>Oajpt$!}p?sTV_P1W}A6S<}{af18)p!C<@KEUq-h?ToXy{xbpqFj{ce delta 384 zcmZqJq1CWMYeEN0UzWns#-7$5#?~ID)*j~89+uV~*47@jtv&2N>KM(Zx7M@!%bGJF zfYE*gn-Rz~pZ>9)U7FFnowtD3&p^-AR6Etez}Uh#+1NPE)FjoyIMu`?Da|s~B*iG%G||k^D9ysa zDAmHyGI9H; z1*+$aofvTYf^_|!;IuOD?cXPIO=sc+`3LOw?bD}l2{SR8ZeKl(E15CaltG&zmBE6+ zfWa6@8Z#sVu`xp$gDHavSlk#$ngC%EP|Om{PGK+tsxoCrWH4he1hUh>x{bi94S{MB crzg(fGG#So&|@&zE;x%Tjd45UEUy2I0F=XSPXGV_ diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.pdb index ab7c2c7de2bc496aa83be66397dac3c76ee16a55..c248f45a08fba86a41757731451d055a46d85c37 100644 GIT binary patch delta 827 zcmV-B1H}C7#SHAl43K;j#KZQ&=WcBm5y zsY^nkhLWW2L+Qh4HIlaM#q5k4^hx=Repy+?H8yQQrP&98cF&x1_UtfOcKV`gJjyb- z!dCogO^yNzm2djZxE>mR&7gcq@Q4gM02Cb{i1#Lq&>ei)psR^NJV>mpv>~wAfx?yv zv{OC=QUV1v_+9$|=t_9h#y~+}JPYV*$0iLuYiou;JMmr;uChOPe(7k&qn5R+;l5)b zdwKYq-ce;piT3U?Lcbt0*}`;--vR0M_H60x23>b85_HiD9VM231XV!MDmnf-n8j7P zZex{qdt7&92$}wcXwwBq|3*qU zIUa2DMjKjF;KLw)^Ykp8&C|2t*M09QA8hXv&EE)5E++Zx9H(=fVl**jV=-elG&VIeVPj@CVPa)AWH~ir zX1D9~0kr}c>qX?y0N?=t5VK=OaOZ7Jm+L}QXON2~1 zcW-iQX>MmOWNd5z00Bdk7v}mmy|DU2l-TSbm{Z+3rj+eJ= z0UduOH8yQQrQQdDcF&x1_UtfOc7D_~9Ap_>VI%&$B1Zv*iZ|V6To1KoP`)5|M1~yz z@)i)pdy_`!4!)|1w3kFASW=M1$4P% zlbW8jHAA4Ccqa*0*&jR~JDTC3VeKloZ&`oHULO9YcT^fuqP@F}&@aeLHaG3^cR+gm za<=kzi>|#E2|90tP7+IkDxheUoPO=i;!0gLvC6wWt~)Y>O#ec(ZG*0A*(3S!1Zxt6 z4LR=KM|t;r=mYnsen+f=-X1zUNmh-KHF3R!Li5XZ0fEqnwgi^Ah5`k1Wa`ve+s1!% z7mY@k95)Q54{(c?R*gyEY&eMRk_c>r|3*qUIqhxpMjP5t;KLxt=_sAg(^3EHzIUY$ zw)2VRZ-i&G7)=*bHJz6887-zXo8{#N&5DVd|ms})` zG505W&|>KSX*Ng5GPYmrfrHN8de%SUL;ES1GdMG2Gc#s2 zG-Wt5Wi&KmW;tavWHMtlVKy-`W;if1WjHZ8VYln_0kr}c&Id=20N?=tC(Nyl;1PsO zqwts8o+KV&m;Ltv9hcSj0T399z?Q!NfB*pWxgqIJrbtGSGmAn~fPJ5r{r3SQe`uQx zkpLh80JEaNeOlT@9x<_GcWkYprbS_M9XJ=_{XD(!HYybcO*6sME0Du4h zNrD9Q;m_wlgaO5aI8AqNM`3McLv?I)E>2~1cW-iQX>MmOWNd5z00E~$0L=hE2mrTT h)n$Nz;7_EM8ROt~giT3vZ*XsDhoATXx1aa|O)C4rZEXMm diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.WebSockets.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.WebSockets.dll index a3a774034539002ffecc6d67395e8e526c77e24d..afe9b4467c9d843b612bf920ed968af04743b622 100644 GIT binary patch delta 306 zcmZoDX(*Y{!J?i&dEUmJ90^8?$v-7j87(%;ODggUY*=_Z_TAaLemx9xm84Cd@7f%o zAVRWXKJQxZe(a`oM>W}Xk=()XqcE}Vwjq2m~3uh1{6(BGfPZL zHA}HHO-kE5TUU^Y#dmY`zsVc)0|aI^N}u1tDeBRXzh}yKW;?&h0tRyxpn@x4f*{os zSaNDUKg_=QXx6%Ko6i~?WaPA9U|?VbVvEhwjkuW@%{DJKInNku#-Pn$&S1n~$Y9D~ z%#g@n!e9m@L3|K41hSKWVulQ<49P$;8K@Sd0-`pVAq}iL2`FpEkiuXI6i;GEn|##F Vl+}zukHKKGpam1-W=4zui~!wGSor_| delta 306 zcmZoDX(*Y{!Sd~${*H}3ITDQKlYdI6GMaCemsI2z5c>7)UfJ)t?t9KNH}mIj%-kHH zAVRWXKJdQYGGh(VVrDioMvj0YGIseVv>|*nQD?^lx&)4W@waV zVPKSMVQ87SdA6<~6H9`qe$V6$`T+t7Q^F%mwmo<4YI5m>b$P)*|G Yqh_Y8rVM%v2Ac&fm>4%RTKs1O08n692><{9 diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.dll index 9328d1646ad3496958ec1ed38474d025b9ab04af..2130b83ecc0613c24df326fcb1d0dea5a8be1f98 100644 GIT binary patch delta 350 zcmZoTA>VL9enJO}^Az#tjXkYBjIBLPtv$?Jdsue-WVD#>`isRCNOk{W(Fany!BqR} zUo6{S|6+aHC}46xvqx1t+O@Ade{%fgbMD(;)Ue&Hw=mN)U|=v|WY9O%Gte_N(>6CU zG&N2%F-tTuG%_?yOfoS{O*Tw6H!%Z>Ca0MtCZ(FCSehoKZU6g+ZSh5x&VyG^OkZ-2 zJwPD&giz5p<}2=7|9N~@IU->_o#i}xy8=}7I7}3zzC^#_(FXT|5AvUMxwfx9&;FQ) z(}ID4ff0x;wokvq{+N-`YVL9enJP!awmqfjXkYBjIBLPtv$?Jdsue-WHg`d`isRCNOk{W(Fany!BqR} zUo6{S|6+aHD6l>DYHCB{1OFw{Bp*L0Yw_LwqK55my@jcs0Rw{xBZI!7o`IgJsdlP` zfw6^gvaxZRsY$AZajJ<)QkrF|Ns3XjX`-2-QJRH;QL2TZW#aa~f7ljZWU&m;?4Q2m z9D9I3)e-$31Et$8b6W$YK7I3DGM(i-d%FTu)I=643RKVU<@dsT&XoV16;Z*0+gG1w zf6T*a&cMLH2*l>wr{7_J%*bfEz4{(|J7cgZgEm7dg9U>DgE5daW=IBNV}>*aQw9^T zxG|740m3Apm?fB$6&Bs@DY0v L<95bJ?Ee`7i12W< diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.pdb index ffef7b76db36fd7f7f74c7fd1f2a86f789cd7b3a..8810690ae6771a9e7a33adabd312c0649e3afc46 100644 GIT binary patch delta 745 zcmVY)BDZf!<67006C&&uZI15XSF;yu;vAOJgZ=Y==6b zkh&xkno#1@J(M0stC2KxwJUZ;F?yuFMxU&#(;B;fzya@JVQ0VjeZ%ZBX*xXUIzCEM zxWrEVup&nRm5Mj(U|bJ>H47MD5UfyOBY?aI1ohq~QM!@OYjhO}s0WRiC0l|9dob7u z0XySEAfu2|jgRaDpeta-)LAG$TiN1d>%V9|?G zbFq6&?y0n7l)bx%(l01NO>XCy+;AN`KR1aAMRaNb$HBb~v5 zOc&?`YOd;GOQH0kL1zdW62U6Ax%2@lY)Dd}@JP=wzh+BI3bJdSC8x<`nw;*>dGFSB z#TeTE0biYuvdI~Lj;A=vMp=gWI3tsp^YL_YhNhfiPSfJ`Bro^({TO`FneA7(!G>b< zk~`9s58v2T`{N#1EgcHBJV0OL2P;r<=kK;&SbgX}1v@x_L9N=#EKMucy2}&eoAh_x zY1}?=zBXKsgPZNq6bHxc;%&#afX{)I=DwiofK@|I!B`XoNn+klhqg8Wx3)F{or@?p zGBGtXVKg>jGBGkSF=1jfF=b;hV>dK5H8WvjW;S7BWj16vHDYGBd%^;$0vPK>q+x&j@STEzko7}9JszW{&$00Gn$v=1WuPQGvca|spm z)R*qM0v(s1#R3Kxp(OwO03ZPX3YAQAA5#cUts%9!oU+;}m%YUT7Z_6khu8ps001!w bbeFs#jYowv1<+QZR;`EZ#R9kN#RF6VL5y8hx@Nr!{sD;DB`@(CDAb*^(bSqy}=t>e$4;nKIwgfeHV6YVe zcE*Q5Mj@jLAK3>$m&2N^g^a*@QQ%@r(~6$FSs>8Xd}9fh=|5^dc56;gT47hhvJ<8H zV*i-jQ(?&{dv_6~Ur>bV%y#p?12SC z7~1~zHW<-tc#enrehfZu&F-t*U`?@k z$sOt1hi~l4!*LI+mW~Bm9igxBgXO5W_jemFtUh#~g6*9_uTpJfo~9*h)nMwmF*0U2FfwI0F*#wkd%^;$0vOH*M~?vD z0RSh=t&QLjgiNFGm)o8s9$}a6x&j@STEzko7>dA_zW{&$0Q9*b=}x9dMv*g%LQ{Z! zpO@~s0v(s1#R3KxXqyd@03ZPXv!cL#TG~NOp1_ZO`cUb*m%YUT7Z}#<_@w}V002pX b1oYw0=Rkx3#e+CacW;O6#R9kN#RF6Vu{c~u diff --git a/unity/org.gamecult.cultlib/package.json b/unity/org.gamecult.cultlib/package.json index e5e5c57f..fd173021 100644 --- a/unity/org.gamecult.cultlib/package.json +++ b/unity/org.gamecult.cultlib/package.json @@ -1,7 +1,7 @@ { "name": "org.gamecult.cultlib", "displayName": "CultLib", - "version": "1.0.55", + "version": "1.0.56", "unity": "2021.3", "description": "CultCache, CultNet, and CultMesh managed runtime assemblies for Unity.", "license": "MIT", From 0a885afce7a833b25127bedfdf9bc70a5872a15f Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 19 Aug 2026 12:12:52 +0200 Subject: [PATCH 107/283] Authorize database subscription records --- .../CultNetDatabaseSubscriptionServer.cs | 52 ++++++++++++- .../NetworkingTests.cs | 75 +++++++++++++++++++ 2 files changed, 123 insertions(+), 4 deletions(-) diff --git a/src/GameCult.Networking/CultNetDatabaseSubscriptionServer.cs b/src/GameCult.Networking/CultNetDatabaseSubscriptionServer.cs index c5fe47bd..cd224816 100644 --- a/src/GameCult.Networking/CultNetDatabaseSubscriptionServer.cs +++ b/src/GameCult.Networking/CultNetDatabaseSubscriptionServer.cs @@ -20,6 +20,8 @@ namespace GameCult.Networking private readonly CultNetDatabase _database; private readonly Func _subscribe; private readonly Func _unsubscribe; + private readonly Func? _authorizeRequest; + private readonly Func? _authorizeRecord; private readonly ICultNetSchemaServerPeerLifecycle? _peerLifecycle; private readonly ConcurrentDictionary _subscriptions = new ConcurrentDictionary(SubscriptionKeyComparer.Instance); @@ -28,10 +30,16 @@ namespace GameCult.Networking private bool _disposed; /// Attaches live database subscription handlers to a schema server. - public CultNetDatabaseSubscriptionServer(ICultNetSchemaServer server, CultNetDatabase database) + public CultNetDatabaseSubscriptionServer( + ICultNetSchemaServer server, + CultNetDatabase database, + Func? authorizeRequest = null, + Func? authorizeRecord = null) { _server = server ?? throw new ArgumentNullException(nameof(server)); _database = database ?? throw new ArgumentNullException(nameof(database)); + _authorizeRequest = authorizeRequest; + _authorizeRecord = authorizeRecord; _subscribe = HandleSubscribeAsync; _unsubscribe = HandleUnsubscribeAsync; _server.OnCultNet(_subscribe); @@ -89,6 +97,11 @@ namespace GameCult.Networking peer.SendCultNet(new CultNetErrorMessage { Error = "Database subscription requires a subscriptionId or messageId." }); return Task.CompletedTask; } + if (_authorizeRequest?.Invoke(request, peer) == false) + { + peer.SendCultNet(new CultNetErrorMessage { Error = "Database subscription is not authorized for this peer." }); + return Task.CompletedTask; + } var key = new SubscriptionKey(peer, subscriptionId); if (_requests.TryGetValue(key, out var previous)) @@ -105,7 +118,7 @@ namespace GameCult.Networking PublishDemand(request, key, active: true); if (request.IncludeSnapshot) { - peer.SendCultNet(_database.Documents.CreateRawSnapshotResponse( + var snapshot = _database.Documents.CreateRawSnapshotResponse( _database.Cache, request.MessageId, new CultNetSnapshotRequestMessage @@ -113,7 +126,15 @@ namespace GameCult.Networking MessageId = request.MessageId, SchemaIds = request.SchemaIds, RecordKeys = request.RecordKeys - })); + }); + if (_authorizeRecord != null) + { + snapshot.Documents = snapshot.Documents + .Where(document => _authorizeRecord( + request, peer, document.RecordKey, document.SchemaId)) + .ToArray(); + } + peer.SendCultNet(snapshot); } else { @@ -183,15 +204,34 @@ namespace GameCult.Networking { return _database.WatchAllChanges().Subscribe(change => { - var message = CreateChange(change, request, subscriptionId); + var message = CreateAuthorizedChange(change, request, subscriptionId, peer); if (message != null) peer.SendCultNet(message); }); } + private CultNetDatabaseChangeRawMessage? CreateAuthorizedChange( + object change, + CultNetDatabaseSubscribeMessage request, + string subscriptionId, + ICultNetSchemaServerPeer peer) + { + return CreateChangeCore(change, request, subscriptionId, (recordKey, schemaId) => + _authorizeRecord?.Invoke(request, peer, recordKey, schemaId) != false); + } + private CultNetDatabaseChangeRawMessage? CreateChange( object change, CultNetDatabaseSubscribeMessage request, string subscriptionId) + { + return CreateChangeCore(change, request, subscriptionId, (_, _) => true); + } + + private CultNetDatabaseChangeRawMessage? CreateChangeCore( + object change, + CultNetDatabaseSubscribeMessage request, + string subscriptionId, + Func authorizeRecord) { var changeType = change.GetType(); var key = (CultRecordKey)(changeType.GetProperty("Key")?.GetValue(change) ?? new CultRecordKey("")); @@ -206,6 +246,8 @@ namespace GameCult.Networking var schemaId = ResolveWireSchemaId(previous, (string?)changeType.GetProperty("SchemaId")?.GetValue(change) ?? ""); if (!MatchesRequestedSchema(request.SchemaIds, previous, schemaId)) return null; + if (!authorizeRecord(key.Value, schemaId)) + return null; return new CultNetDatabaseChangeRawMessage { MessageId = Guid.NewGuid().ToString("N"), @@ -219,6 +261,8 @@ namespace GameCult.Networking var raw = CreateRawRecord(key, document); if (!MatchesRequestedSchema(request.SchemaIds, document, raw.SchemaId)) return null; + if (!authorizeRecord(key.Value, raw.SchemaId)) + return null; return new CultNetDatabaseChangeRawMessage { MessageId = Guid.NewGuid().ToString("N"), diff --git a/tests/GameCult.Networking.Tests/NetworkingTests.cs b/tests/GameCult.Networking.Tests/NetworkingTests.cs index 28245a3d..ae3265ca 100644 --- a/tests/GameCult.Networking.Tests/NetworkingTests.cs +++ b/tests/GameCult.Networking.Tests/NetworkingTests.cs @@ -1462,6 +1462,81 @@ namespace GameCult.Networking.Tests Assert.That(update.Document!.RecordKey, Is.EqualTo(recordKey)); } + [Test] + public async Task DatabaseSubscriptionServer_AuthorizesRequestAndFiltersSnapshotAndLiveRecords() + { + var cache = new CultCache(); + var database = new CultNetDatabase(cache); + using var server = new RudpCultNetSchemaServer(new RudpCultNetSchemaServerOptions + { + RuntimeId = "database-authorized-subscription-server", + Socket = BindUdpSocket() + }); + using var subscriptions = new CultNetDatabaseSubscriptionServer( + server, + database, + authorizeRequest: (request, _) => request.ConsumerRuntimeId == "allowed-runtime", + authorizeRecord: (_, _, recordKey, _) => recordKey.StartsWith("tests:public:", StringComparison.Ordinal)); + using var cancellation = new CancellationTokenSource(); + var serverThread = new Thread(() => + { + while (!cancellation.IsCancellationRequested) + { + _ = server.PollOnceAsync().GetAwaiter().GetResult(); + Thread.Sleep(1); + } + }) { IsBackground = true }; + serverThread.Start(); + + await database.PutAsync(new CultRecordKey("tests:public:initial"), new NetworkSchemaNote + { + Schema = "tests.networking_note.v1", + Text = "public-initial" + }); + await database.PutAsync(new CultRecordKey("tests:private:initial"), new NetworkSchemaNote + { + Schema = "tests.networking_note.v1", + Text = "private-initial" + }); + + using var client = CultNetSchemaClients.CreateRudp("database-authorized-subscription-client"); + var subscribed = new TaskCompletionSource( + TaskCreationOptions.RunContinuationsAsynchronously); + var changed = new TaskCompletionSource( + TaskCreationOptions.RunContinuationsAsynchronously); + client.OnCultNet(message => subscribed.TrySetResult(message)); + client.OnCultNet(message => changed.TrySetResult(message)); + client.Connect("127.0.0.1", server.LocalEndPoint.Port); + await WaitUntilAsync(() => client.Connected, TimeSpan.FromSeconds(2)); + client.SendCultNet(new CultNetDatabaseSubscribeMessage + { + MessageId = "subscribe-authorized", + SubscriptionId = "authorized", + ConsumerRuntimeId = "allowed-runtime", + IncludeSnapshot = true + }); + + var snapshot = await AwaitWithTimeout(subscribed.Task, TimeSpan.FromSeconds(2)); + Assert.That(snapshot.Documents.Select(document => document.RecordKey), + Is.EqualTo(new[] { "tests:public:initial" })); + + await database.PutAsync(new CultRecordKey("tests:private:live"), new NetworkSchemaNote + { + Schema = "tests.networking_note.v1", + Text = "private-live" + }); + await database.PutAsync(new CultRecordKey("tests:public:live"), new NetworkSchemaNote + { + Schema = "tests.networking_note.v1", + Text = "public-live" + }); + var update = await AwaitWithTimeout(changed.Task, TimeSpan.FromSeconds(2)); + + cancellation.Cancel(); + Assert.That(update.Document, Is.Not.Null); + Assert.That(update.Document!.RecordKey, Is.EqualTo("tests:public:live")); + } + [Test] public async Task DatabaseSubscriptionServer_ProjectsBodyDemandAndWithdrawalFromExactSubscription() { From eaf1189cc13ec357cb54e2722de2793faee2680c Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 19 Aug 2026 13:22:36 +0200 Subject: [PATCH 108/283] Project subscription records per peer --- .../CultNetDatabaseSubscriptionServer.cs | 20 ++++++++++++++++++- .../NetworkingTests.cs | 9 ++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/GameCult.Networking/CultNetDatabaseSubscriptionServer.cs b/src/GameCult.Networking/CultNetDatabaseSubscriptionServer.cs index cd224816..c1ca3c9d 100644 --- a/src/GameCult.Networking/CultNetDatabaseSubscriptionServer.cs +++ b/src/GameCult.Networking/CultNetDatabaseSubscriptionServer.cs @@ -13,6 +13,8 @@ namespace GameCult.Networking { /// /// Publishes live database changes through any schema-v0 server transport. + /// Optional record projection runs after authorization and owns both initial + /// snapshot and live-update delivery for a peer. /// public sealed class CultNetDatabaseSubscriptionServer : IDisposable { @@ -22,6 +24,7 @@ namespace GameCult.Networking private readonly Func _unsubscribe; private readonly Func? _authorizeRequest; private readonly Func? _authorizeRecord; + private readonly Func? _projectRecord; private readonly ICultNetSchemaServerPeerLifecycle? _peerLifecycle; private readonly ConcurrentDictionary _subscriptions = new ConcurrentDictionary(SubscriptionKeyComparer.Instance); @@ -34,12 +37,14 @@ namespace GameCult.Networking ICultNetSchemaServer server, CultNetDatabase database, Func? authorizeRequest = null, - Func? authorizeRecord = null) + Func? authorizeRecord = null, + Func? projectRecord = null) { _server = server ?? throw new ArgumentNullException(nameof(server)); _database = database ?? throw new ArgumentNullException(nameof(database)); _authorizeRequest = authorizeRequest; _authorizeRecord = authorizeRecord; + _projectRecord = projectRecord; _subscribe = HandleSubscribeAsync; _unsubscribe = HandleUnsubscribeAsync; _server.OnCultNet(_subscribe); @@ -134,6 +139,14 @@ namespace GameCult.Networking request, peer, document.RecordKey, document.SchemaId)) .ToArray(); } + if (_projectRecord != null) + { + snapshot.Documents = snapshot.Documents + .Select(document => _projectRecord(request, peer, document)) + .Where(document => document != null) + .Cast() + .ToArray(); + } peer.SendCultNet(snapshot); } else @@ -205,6 +218,11 @@ namespace GameCult.Networking return _database.WatchAllChanges().Subscribe(change => { var message = CreateAuthorizedChange(change, request, subscriptionId, peer); + if (message?.Document != null && _projectRecord != null) + { + message.Document = _projectRecord(request, peer, message.Document); + if (message.Document == null) return; + } if (message != null) peer.SendCultNet(message); }); } diff --git a/tests/GameCult.Networking.Tests/NetworkingTests.cs b/tests/GameCult.Networking.Tests/NetworkingTests.cs index ae3265ca..deac0d02 100644 --- a/tests/GameCult.Networking.Tests/NetworkingTests.cs +++ b/tests/GameCult.Networking.Tests/NetworkingTests.cs @@ -1476,7 +1476,12 @@ namespace GameCult.Networking.Tests server, database, authorizeRequest: (request, _) => request.ConsumerRuntimeId == "allowed-runtime", - authorizeRecord: (_, _, recordKey, _) => recordKey.StartsWith("tests:public:", StringComparison.Ordinal)); + authorizeRecord: (_, _, recordKey, _) => recordKey.StartsWith("tests:public:", StringComparison.Ordinal), + projectRecord: (request, _, record) => + { + record.SourceRuntimeId = "projection:" + request.ConsumerRuntimeId; + return record; + }); using var cancellation = new CancellationTokenSource(); var serverThread = new Thread(() => { @@ -1519,6 +1524,7 @@ namespace GameCult.Networking.Tests var snapshot = await AwaitWithTimeout(subscribed.Task, TimeSpan.FromSeconds(2)); Assert.That(snapshot.Documents.Select(document => document.RecordKey), Is.EqualTo(new[] { "tests:public:initial" })); + Assert.That(snapshot.Documents.Single().SourceRuntimeId, Is.EqualTo("projection:allowed-runtime")); await database.PutAsync(new CultRecordKey("tests:private:live"), new NetworkSchemaNote { @@ -1535,6 +1541,7 @@ namespace GameCult.Networking.Tests cancellation.Cancel(); Assert.That(update.Document, Is.Not.Null); Assert.That(update.Document!.RecordKey, Is.EqualTo("tests:public:live")); + Assert.That(update.Document.SourceRuntimeId, Is.EqualTo("projection:allowed-runtime")); } [Test] From 73ab8b65e12f9d63d96a85b266715320c67a4dfe Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 19 Aug 2026 13:55:03 +0200 Subject: [PATCH 109/283] Reconcile live subscription authority --- .../CultNetDatabaseSubscriptionServer.cs | 355 ++++++++++++++---- .../NetworkingTests.cs | 91 +++++ 2 files changed, 376 insertions(+), 70 deletions(-) diff --git a/src/GameCult.Networking/CultNetDatabaseSubscriptionServer.cs b/src/GameCult.Networking/CultNetDatabaseSubscriptionServer.cs index c1ca3c9d..3d284556 100644 --- a/src/GameCult.Networking/CultNetDatabaseSubscriptionServer.cs +++ b/src/GameCult.Networking/CultNetDatabaseSubscriptionServer.cs @@ -30,6 +30,9 @@ namespace GameCult.Networking new ConcurrentDictionary(SubscriptionKeyComparer.Instance); private readonly ConcurrentDictionary _requests = new ConcurrentDictionary(SubscriptionKeyComparer.Instance); + private readonly ConcurrentDictionary _projections = + new ConcurrentDictionary(SubscriptionKeyComparer.Instance); + private readonly object _lifecycleGate = new(); private bool _disposed; /// Attaches live database subscription handlers to a schema server. @@ -61,34 +64,48 @@ namespace GameCult.Networking /// public event Action? DemandChanged; + /// + /// Re-evaluates every live peer projection against current authorization and source state. + /// Records that lost visibility are explicitly removed and body demand is withdrawn while + /// the request is unauthorized. The subscription intent remains available for a later + /// authorized generation on the same established peer. + /// + public void Reconcile() + { + lock (_lifecycleGate) + { + if (_disposed) return; + foreach (var entry in _requests.ToArray()) + Reconcile(entry.Key, entry.Value); + } + } + /// Detaches handlers and releases all active watches. public void Dispose() { - if (_disposed) return; - _disposed = true; - _server.RemoveCultNetMessageListener(_subscribe); - _server.RemoveCultNetMessageListener(_unsubscribe); - if (_peerLifecycle != null) - _peerLifecycle.PeerDisconnected -= HandlePeerDisconnected; - foreach (var entry in _subscriptions) + lock (_lifecycleGate) { - entry.Value.Dispose(); - if (_requests.TryRemove(entry.Key, out var request)) - PublishDemand(request, entry.Key, active: false); + if (_disposed) return; + _disposed = true; + _server.RemoveCultNetMessageListener(_subscribe); + _server.RemoveCultNetMessageListener(_unsubscribe); + if (_peerLifecycle != null) + _peerLifecycle.PeerDisconnected -= HandlePeerDisconnected; + foreach (var entry in _subscriptions.ToArray()) + Withdraw(entry.Key, sendRemovals: false, forgetRequest: true); + _subscriptions.Clear(); + _requests.Clear(); + _projections.Clear(); } - _subscriptions.Clear(); - _requests.Clear(); } private void HandlePeerDisconnected(ICultNetSchemaServerPeer peer) { - foreach (var key in _subscriptions.Keys.Where(candidate => - SubscriptionKeyComparer.SamePeer(candidate.Peer, peer)).ToArray()) + lock (_lifecycleGate) { - if (_subscriptions.TryRemove(key, out var subscription)) - subscription.Dispose(); - if (_requests.TryRemove(key, out var request)) - PublishDemand(request, key, active: false); + foreach (var key in _subscriptions.Keys.Where(candidate => + SubscriptionKeyComparer.SamePeer(candidate.Peer, peer)).ToArray()) + Withdraw(key, sendRemovals: false, forgetRequest: true); } } @@ -108,54 +125,43 @@ namespace GameCult.Networking return Task.CompletedTask; } - var key = new SubscriptionKey(peer, subscriptionId); - if (_requests.TryGetValue(key, out var previous)) - PublishDemand(previous, key, active: false); - _subscriptions.AddOrUpdate( - key, - _ => Watch(request, subscriptionId, peer), - (_, current) => - { - current.Dispose(); - return Watch(request, subscriptionId, peer); - }); - _requests[key] = request; - PublishDemand(request, key, active: true); - if (request.IncludeSnapshot) + lock (_lifecycleGate) { - var snapshot = _database.Documents.CreateRawSnapshotResponse( - _database.Cache, - request.MessageId, - new CultNetSnapshotRequestMessage + var key = new SubscriptionKey(peer, subscriptionId); + Withdraw(key, sendRemovals: true, forgetRequest: true); + var projection = new SubscriptionProjectionState(); + _projections[key] = projection; + _requests[key] = request; + try + { + _subscriptions[key] = Watch(request, subscriptionId, peer, key); + if (request.IncludeSnapshot) { - MessageId = request.MessageId, - SchemaIds = request.SchemaIds, - RecordKeys = request.RecordKeys - }); - if (_authorizeRecord != null) - { - snapshot.Documents = snapshot.Documents - .Where(document => _authorizeRecord( - request, peer, document.RecordKey, document.SchemaId)) - .ToArray(); + var snapshot = CreateProjectedSnapshot(request, peer); + foreach (var entry in snapshot.BySourceRecordKey) + projection.DeliveredBySourceRecordKey[entry.Key] = entry.Value; + peer.SendCultNet(new CultNetSnapshotResponseRawMessage + { + MessageId = request.MessageId, + Documents = snapshot.Documents + }); + } + else + { + peer.SendCultNet(new CultNetSnapshotResponseRawMessage + { + MessageId = request.MessageId, + Documents = Array.Empty() + }); + } + PublishDemand(request, key, active: true); + projection.DemandActive = true; } - if (_projectRecord != null) + catch { - snapshot.Documents = snapshot.Documents - .Select(document => _projectRecord(request, peer, document)) - .Where(document => document != null) - .Cast() - .ToArray(); + Withdraw(key, sendRemovals: false, forgetRequest: true); + throw; } - peer.SendCultNet(snapshot); - } - else - { - peer.SendCultNet(new CultNetSnapshotResponseRawMessage - { - MessageId = request.MessageId, - Documents = Array.Empty() - }); } return Task.CompletedTask; } @@ -168,9 +174,8 @@ namespace GameCult.Networking if (!string.IsNullOrWhiteSpace(subscriptionId)) { var key = new SubscriptionKey(peer, subscriptionId); - if (_subscriptions.TryRemove(key, out var subscription)) subscription.Dispose(); - if (_requests.TryRemove(key, out var subscribed)) - PublishDemand(subscribed, key, active: false); + lock (_lifecycleGate) + Withdraw(key, sendRemovals: false, forgetRequest: true); } return Task.CompletedTask; } @@ -213,20 +218,209 @@ namespace GameCult.Networking private IDisposable Watch( CultNetDatabaseSubscribeMessage request, string subscriptionId, - ICultNetSchemaServerPeer peer) + ICultNetSchemaServerPeer peer, + SubscriptionKey key) { return _database.WatchAllChanges().Subscribe(change => { - var message = CreateAuthorizedChange(change, request, subscriptionId, peer); - if (message?.Document != null && _projectRecord != null) + lock (_lifecycleGate) { - message.Document = _projectRecord(request, peer, message.Document); - if (message.Document == null) return; + if (_disposed || !_requests.ContainsKey(key) || !_projections.TryGetValue(key, out var projection)) + return; + if (_authorizeRequest?.Invoke(request, peer) == false) + { + Reconcile(key, request); + return; + } + + var sourceRecordKey = ResolveChangeRecordKey(change); + var message = CreateAuthorizedChange(change, request, subscriptionId, peer); + var projected = message?.Document; + if (projected != null && _projectRecord != null) + projected = _projectRecord(request, peer, projected); + ApplyProjectedChange( + projection, + sourceRecordKey, + projected, + peer, + subscriptionId); } - if (message != null) peer.SendCultNet(message); }); } + private void Reconcile(SubscriptionKey key, CultNetDatabaseSubscribeMessage request) + { + if (!_projections.TryGetValue(key, out var projection)) return; + var authorized = _authorizeRequest?.Invoke(request, key.Peer) != false; + var next = authorized + ? CreateProjectedSnapshot(request, key.Peer) + : ProjectedSnapshot.Empty; + + foreach (var previous in projection.DeliveredBySourceRecordKey.ToArray()) + { + if (!next.BySourceRecordKey.TryGetValue(previous.Key, out var current)) + { + SendRemoval(key.Peer, key.Id, previous.Value); + continue; + } + if (!string.Equals(previous.Value.RecordKey, current.RecordKey, StringComparison.Ordinal) || + !string.Equals(previous.Value.SchemaId, current.SchemaId, StringComparison.Ordinal)) + { + SendRemoval(key.Peer, key.Id, previous.Value); + SendUpsert(key.Peer, key.Id, current, added: true); + } + else if (!Equivalent(previous.Value, current)) + { + SendUpsert(key.Peer, key.Id, current, added: false); + } + } + foreach (var current in next.BySourceRecordKey) + { + if (!projection.DeliveredBySourceRecordKey.ContainsKey(current.Key)) + SendUpsert(key.Peer, key.Id, current.Value, added: true); + } + + projection.DeliveredBySourceRecordKey.Clear(); + foreach (var current in next.BySourceRecordKey) + projection.DeliveredBySourceRecordKey[current.Key] = current.Value; + + if (projection.DemandActive != authorized) + { + projection.DemandActive = authorized; + PublishDemand(request, key, authorized); + } + } + + private ProjectedSnapshot CreateProjectedSnapshot( + CultNetDatabaseSubscribeMessage request, + ICultNetSchemaServerPeer peer) + { + var snapshot = _database.Documents.CreateRawSnapshotResponse( + _database.Cache, + request.MessageId, + new CultNetSnapshotRequestMessage + { + MessageId = request.MessageId, + SchemaIds = request.SchemaIds, + RecordKeys = request.RecordKeys + }); + var bySourceRecordKey = new Dictionary(StringComparer.Ordinal); + var projectedRecordKeys = new HashSet(StringComparer.Ordinal); + foreach (var source in snapshot.Documents) + { + var sourceRecordKey = source.RecordKey; + if (_authorizeRecord?.Invoke(request, peer, sourceRecordKey, source.SchemaId) == false) + continue; + var projected = _projectRecord == null ? source : _projectRecord(request, peer, source); + if (projected == null) continue; + if (!projectedRecordKeys.Add(projected.RecordKey)) + throw new InvalidOperationException( + $"Database subscription projection produced duplicate record key '{projected.RecordKey}'."); + bySourceRecordKey[sourceRecordKey] = projected; + } + return new ProjectedSnapshot(bySourceRecordKey); + } + + private void ApplyProjectedChange( + SubscriptionProjectionState projection, + string sourceRecordKey, + CultNetRawDocumentRecord? current, + ICultNetSchemaServerPeer peer, + string subscriptionId) + { + projection.DeliveredBySourceRecordKey.TryGetValue(sourceRecordKey, out var previous); + if (current == null) + { + if (previous != null) + { + projection.DeliveredBySourceRecordKey.Remove(sourceRecordKey); + SendRemoval(peer, subscriptionId, previous); + } + return; + } + if (previous == null) + { + projection.DeliveredBySourceRecordKey[sourceRecordKey] = current; + SendUpsert(peer, subscriptionId, current, added: true); + return; + } + if (!string.Equals(previous.RecordKey, current.RecordKey, StringComparison.Ordinal) || + !string.Equals(previous.SchemaId, current.SchemaId, StringComparison.Ordinal)) + { + SendRemoval(peer, subscriptionId, previous); + projection.DeliveredBySourceRecordKey[sourceRecordKey] = current; + SendUpsert(peer, subscriptionId, current, added: true); + return; + } + if (!Equivalent(previous, current)) + { + projection.DeliveredBySourceRecordKey[sourceRecordKey] = current; + SendUpsert(peer, subscriptionId, current, added: false); + } + } + + private static string ResolveChangeRecordKey(object change) + { + var value = change.GetType().GetProperty("Key")?.GetValue(change); + return value is CultRecordKey key ? key.Value : string.Empty; + } + + private static bool Equivalent(CultNetRawDocumentRecord left, CultNetRawDocumentRecord right) => + string.Equals(left.SchemaId, right.SchemaId, StringComparison.Ordinal) && + string.Equals(left.SchemaName, right.SchemaName, StringComparison.Ordinal) && + string.Equals(left.SchemaVersion, right.SchemaVersion, StringComparison.Ordinal) && + string.Equals(left.SchemaContentHash, right.SchemaContentHash, StringComparison.Ordinal) && + string.Equals(left.RecordKey, right.RecordKey, StringComparison.Ordinal) && + string.Equals(left.PayloadEncoding, right.PayloadEncoding, StringComparison.Ordinal) && + left.Payload.SequenceEqual(right.Payload) && + string.Equals(left.SourceRuntimeId, right.SourceRuntimeId, StringComparison.Ordinal) && + string.Equals(left.SourceAgentId, right.SourceAgentId, StringComparison.Ordinal) && + string.Equals(left.SourceRole, right.SourceRole, StringComparison.Ordinal); + + private static void SendUpsert( + ICultNetSchemaServerPeer peer, + string subscriptionId, + CultNetRawDocumentRecord document, + bool added) => + peer.SendCultNet(new CultNetDatabaseChangeRawMessage + { + MessageId = Guid.NewGuid().ToString("N"), + SubscriptionId = subscriptionId, + ChangeKind = added ? "added" : "updated", + Document = document + }); + + private static void SendRemoval( + ICultNetSchemaServerPeer peer, + string subscriptionId, + CultNetRawDocumentRecord document) => + peer.SendCultNet(new CultNetDatabaseChangeRawMessage + { + MessageId = Guid.NewGuid().ToString("N"), + SubscriptionId = subscriptionId, + ChangeKind = "removed", + RecordKey = document.RecordKey, + SchemaId = document.SchemaId + }); + + private void Withdraw(SubscriptionKey key, bool sendRemovals, bool forgetRequest) + { + if (_subscriptions.TryRemove(key, out var subscription)) + subscription.Dispose(); + if (_projections.TryRemove(key, out var projection)) + { + if (sendRemovals) + { + foreach (var delivered in projection.DeliveredBySourceRecordKey.Values) + SendRemoval(key.Peer, key.Id, delivered); + } + if (projection.DemandActive && _requests.TryGetValue(key, out var activeRequest)) + PublishDemand(activeRequest, key, active: false); + } + if (forgetRequest) + _requests.TryRemove(key, out _); + } + private CultNetDatabaseChangeRawMessage? CreateAuthorizedChange( object change, CultNetDatabaseSubscribeMessage request, @@ -320,6 +514,27 @@ namespace GameCult.Networking return ((CultNetDocumentPutRawMessage)put!).Document; } + private sealed class SubscriptionProjectionState + { + public Dictionary DeliveredBySourceRecordKey { get; } = + new(StringComparer.Ordinal); + public bool DemandActive { get; set; } + } + + private sealed class ProjectedSnapshot + { + public ProjectedSnapshot(Dictionary bySourceRecordKey) + { + BySourceRecordKey = bySourceRecordKey; + Documents = bySourceRecordKey.Values.ToArray(); + } + + public static ProjectedSnapshot Empty { get; } = + new(new Dictionary(StringComparer.Ordinal)); + public Dictionary BySourceRecordKey { get; } + public CultNetRawDocumentRecord[] Documents { get; } + } + private sealed class SubscriptionKey { public SubscriptionKey(ICultNetSchemaServerPeer peer, string id) diff --git a/tests/GameCult.Networking.Tests/NetworkingTests.cs b/tests/GameCult.Networking.Tests/NetworkingTests.cs index deac0d02..c87ec819 100644 --- a/tests/GameCult.Networking.Tests/NetworkingTests.cs +++ b/tests/GameCult.Networking.Tests/NetworkingTests.cs @@ -1544,6 +1544,97 @@ namespace GameCult.Networking.Tests Assert.That(update.Document.SourceRuntimeId, Is.EqualTo("projection:allowed-runtime")); } + [Test] + public async Task DatabaseSubscriptionServer_ReconcilesDeliveredProjectionAndBodyDemandWhenAuthorityChanges() + { + const string sourceRecordKey = "tests:authority:source"; + const string bodyId = "tests:authority:body"; + var authorized = true; + var projectionName = "one"; + var sourceCache = new CultCache(); + var sourceDatabase = new CultNetDatabase(sourceCache); + await sourceDatabase.PutAsync(new CultRecordKey(sourceRecordKey), new NetworkSchemaNote + { + Schema = "tests.networking_note.v1", + Text = "initial" + }); + using var server = new RudpCultNetSchemaServer(new RudpCultNetSchemaServerOptions + { + RuntimeId = "database-reconciled-subscription-server", + Socket = BindUdpSocket() + }); + using var subscriptions = new CultNetDatabaseSubscriptionServer( + server, + sourceDatabase, + authorizeRequest: (_, _) => authorized, + authorizeRecord: (_, _, _, _) => authorized, + projectRecord: (_, _, record) => + { + record.RecordKey = $"tests:authority:projected:{projectionName}"; + return record; + }); + using var bodyDemand = new CultMeshBodyDemandTracker(subscriptions); + using var cancellation = new CancellationTokenSource(); + var serverThread = new Thread(() => + { + while (!cancellation.IsCancellationRequested) + { + _ = server.PollOnceAsync().GetAwaiter().GetResult(); + Thread.Sleep(1); + } + }) { IsBackground = true }; + serverThread.Start(); + + var targetCache = new CultCache(); + var targetDocuments = new CultNetDocumentRegistry(targetCache.Registry) + .Register(CultNetDocumentBinding.ForDocument(targetCache.Registry)); + var transport = CultNetSchemaClients.CreateRudp("database-reconciled-subscription-client"); + using var client = new CultNetDatabaseSubscriptionClient(transport, targetCache, targetDocuments); + var changes = new ConcurrentQueue(); + client.Changed += changes.Enqueue; + transport.Connect("127.0.0.1", server.LocalEndPoint.Port); + await WaitUntilAsync(() => transport.Connected, TimeSpan.FromSeconds(2)); + await AwaitWithTimeout( + client.SubscribeAsync( + "authority", + recordKeys: [sourceRecordKey], + consumerRuntimeId: "authority-client", + bodyIds: [bodyId], + supportedBodyTransports: [CultMeshBodyTransportKind.SharedMemory.ToString()]), + TimeSpan.FromSeconds(2)); + Assert.That(targetCache.Get(new CultRecordKey("tests:authority:projected:one")), Is.Not.Null); + Assert.That(bodyDemand.Plan(bodyId).HasConsumers, Is.True); + + projectionName = "two"; + subscriptions.Reconcile(); + await WaitUntilAsync( + () => targetCache.Get(new CultRecordKey("tests:authority:projected:one")) == null && + targetCache.Get(new CultRecordKey("tests:authority:projected:two")) != null, + TimeSpan.FromSeconds(2)); + Assert.That(changes.Any(change => change.ChangeKind == "removed" && + change.RecordKey == "tests:authority:projected:one"), Is.True); + Assert.That(changes.Any(change => change.ChangeKind == "added" && + change.RecordKey == "tests:authority:projected:two"), Is.True); + + authorized = false; + subscriptions.Reconcile(); + await WaitUntilAsync( + () => targetCache.Get(new CultRecordKey("tests:authority:projected:two")) == null, + TimeSpan.FromSeconds(2)); + Assert.That(bodyDemand.Plan(bodyId).HasConsumers, Is.False); + var changeCountAfterRevocation = changes.Count; + await sourceDatabase.PutAsync(new CultRecordKey(sourceRecordKey), new NetworkSchemaNote + { + Schema = "tests.networking_note.v1", + Text = "must-not-escape" + }); + await Task.Delay(100); + cancellation.Cancel(); + + Assert.That(changes.Count, Is.EqualTo(changeCountAfterRevocation)); + Assert.That(targetCache.Get(new CultRecordKey("tests:authority:projected:two")), Is.Null); + } + [Test] public async Task DatabaseSubscriptionServer_ProjectsBodyDemandAndWithdrawalFromExactSubscription() { From 21fd4e07ebe0634b30b9da6aa63d983654cc9b62 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 19 Aug 2026 14:10:13 +0200 Subject: [PATCH 110/283] Version hot-body demand generations --- src/GameCult.Mesh/CultMeshBodyDemand.cs | 47 ++++++++++++++++++- .../CultMeshBodyTransportTests.cs | 8 ++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/src/GameCult.Mesh/CultMeshBodyDemand.cs b/src/GameCult.Mesh/CultMeshBodyDemand.cs index 55fa3807..9c9e17da 100644 --- a/src/GameCult.Mesh/CultMeshBodyDemand.cs +++ b/src/GameCult.Mesh/CultMeshBodyDemand.cs @@ -225,9 +225,11 @@ namespace GameCult.Mesh { internal CultMeshBodyDemandPlan( string bodyId, + long generation, IReadOnlyList consumers) { BodyId = bodyId; + Generation = generation; Consumers = consumers; RequiresSharedMemory = consumers.Any(value => value.Transport == CultMeshBodyTransportKind.SharedMemory); RequiresSharedFileMapping = consumers.Any(value => value.Transport == CultMeshBodyTransportKind.SharedFileMapping); @@ -235,6 +237,11 @@ namespace GameCult.Mesh } public string BodyId { get; } + /// + /// Monotone generation of the exact routed consumer set. Publishers must rotate any + /// retained capability before writing after this value changes. + /// + public long Generation { get; } public bool HasConsumers => Consumers.Count > 0; public bool RequiresSharedMemory { get; } public bool RequiresSharedFileMapping { get; } @@ -271,6 +278,8 @@ namespace GameCult.Mesh private readonly object _gate = new(); private readonly Dictionary _demands = new(StringComparer.Ordinal); + private readonly Dictionary _bodyGenerations = + new(StringComparer.Ordinal); private bool _disposed; public CultMeshBodyDemandTracker(CultNetDatabaseSubscriptionServer subscriptions) @@ -298,7 +307,10 @@ namespace GameCult.Mesh .OrderBy(value => value.ConsumerRuntimeId, StringComparer.Ordinal) .ThenBy(value => value.SubscriptionId, StringComparer.Ordinal) .ToArray(); - return new CultMeshBodyDemandPlan(bodyId, routes); + return new CultMeshBodyDemandPlan( + bodyId, + _bodyGenerations.TryGetValue(bodyId, out var generation) ? generation : 0, + routes); } } @@ -310,6 +322,7 @@ namespace GameCult.Mesh _disposed = true; if (_subscriptions != null) _subscriptions.DemandChanged -= OnDemandChanged; _demands.Clear(); + _bodyGenerations.Clear(); } } @@ -322,11 +335,43 @@ namespace GameCult.Mesh lock (_gate) { if (_disposed) return; + _demands.TryGetValue(key, out var previous); + var affectedBodyIds = (previous?.BodyIds ?? Array.Empty()) + .Concat(demand.BodyIds) + .Where(value => !string.IsNullOrWhiteSpace(value)) + .Distinct(StringComparer.Ordinal) + .ToArray(); + var before = affectedBodyIds.ToDictionary( + bodyId => bodyId, + RoutedConsumerSignature, + StringComparer.Ordinal); if (demand.Active) _demands[key] = demand; else _demands.Remove(key); + foreach (var bodyId in affectedBodyIds) + { + var after = RoutedConsumerSignature(bodyId); + if (string.Equals(before[bodyId], after, StringComparison.Ordinal)) continue; + _bodyGenerations[bodyId] = checked( + (_bodyGenerations.TryGetValue(bodyId, out var generation) ? generation : 0) + 1); + } } } + private string RoutedConsumerSignature(string bodyId) => string.Join( + "\u001e", + _demands.Values + .Where(value => value.BodyIds.Contains(bodyId, StringComparer.Ordinal)) + .Select(Route) + .Where(value => value != null) + .Cast() + .OrderBy(value => value.ConsumerRuntimeId, StringComparer.Ordinal) + .ThenBy(value => value.SubscriptionId, StringComparer.Ordinal) + .Select(value => string.Join( + "\u001f", + value.ConsumerRuntimeId, + value.SubscriptionId, + value.Transport.ToString()))); + private void OnDemandChanged(CultNetDatabaseSubscriptionDemand demand) => Observe(demand); private static CultMeshBodyConsumerRoute? Route(CultNetDatabaseSubscriptionDemand demand) diff --git a/tests/GameCult.Mesh.Tests/CultMeshBodyTransportTests.cs b/tests/GameCult.Mesh.Tests/CultMeshBodyTransportTests.cs index e644c3ff..0421aea7 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshBodyTransportTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshBodyTransportTests.cs @@ -318,7 +318,9 @@ public sealed class CultMeshBodyTransportTests public void BodyDemand_SelectsSharedMemoryLocallyAndNetworkRemotelyWithoutDuplicateFallbackWork() { using var tracker = new CultMeshBodyDemandTracker(); + tracker.Plan("eve:entity-soa:aetheria.daemon:pilot").Generation.Should().Be(0); tracker.Observe(Demand("unity-local", "local", sameMachine: true)); + tracker.Plan("eve:entity-soa:aetheria.daemon:pilot").Generation.Should().Be(1); tracker.Observe(Demand("unity-remote", "remote", sameMachine: false)); var mixed = tracker.Plan("eve:entity-soa:aetheria.daemon:pilot"); @@ -335,8 +337,14 @@ public sealed class CultMeshBodyTransportTests tracker.Observe(Demand("unity-remote", "remote", sameMachine: false, active: false)); var localOnly = tracker.Plan("eve:entity-soa:aetheria.daemon:pilot"); + localOnly.Generation.Should().Be(3); localOnly.RequiresSharedMemory.Should().BeTrue(); localOnly.RequiresNetwork.Should().BeFalse(); + + tracker.Observe(Demand("unity-local", "local", sameMachine: true, active: false)); + tracker.Plan("eve:entity-soa:aetheria.daemon:pilot").Generation.Should().Be(4); + tracker.Observe(Demand("unity-local", "local", sameMachine: true)); + tracker.Plan("eve:entity-soa:aetheria.daemon:pilot").Generation.Should().Be(5); } [Test] From 3cec5463b2c55d21f261cd68eeac56319d8e3e52 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 19 Aug 2026 14:27:22 +0200 Subject: [PATCH 111/283] Fence body commits by demand generation --- src/GameCult.Mesh/CultMeshBodyDemand.cs | 20 +++++++++ .../CultMeshBodyTransportTests.cs | 42 +++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/src/GameCult.Mesh/CultMeshBodyDemand.cs b/src/GameCult.Mesh/CultMeshBodyDemand.cs index 9c9e17da..2ab90617 100644 --- a/src/GameCult.Mesh/CultMeshBodyDemand.cs +++ b/src/GameCult.Mesh/CultMeshBodyDemand.cs @@ -357,6 +357,26 @@ namespace GameCult.Mesh } } + /// + /// Executes one synchronous capability commit only while the exact routed consumer + /// generation remains current. Demand transitions serialize against the callback, so + /// either this work linearizes before the transition or it is rejected without running. + /// + public bool TryExecuteAtGeneration(string bodyId, long generation, Action action) + { + if (string.IsNullOrWhiteSpace(bodyId)) throw new ArgumentException("Body identity is required.", nameof(bodyId)); + if (generation < 0) throw new ArgumentOutOfRangeException(nameof(generation)); + if (action == null) throw new ArgumentNullException(nameof(action)); + lock (_gate) + { + ThrowIfDisposed(); + var current = _bodyGenerations.TryGetValue(bodyId, out var value) ? value : 0; + if (current != generation) return false; + action(); + return true; + } + } + private string RoutedConsumerSignature(string bodyId) => string.Join( "\u001e", _demands.Values diff --git a/tests/GameCult.Mesh.Tests/CultMeshBodyTransportTests.cs b/tests/GameCult.Mesh.Tests/CultMeshBodyTransportTests.cs index 0421aea7..131bcf24 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshBodyTransportTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshBodyTransportTests.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Linq; +using System.Threading; using System.Threading.Tasks; using FluentAssertions; using NUnit.Framework; @@ -347,6 +348,47 @@ public sealed class CultMeshBodyTransportTests tracker.Plan("eve:entity-soa:aetheria.daemon:pilot").Generation.Should().Be(5); } + [Test] + public async Task BodyDemand_GenerationGuardLinearizesCommitAgainstWithdrawal() + { + const string bodyId = "eve:entity-soa:aetheria.daemon:pilot"; + using var tracker = new CultMeshBodyDemandTracker(); + tracker.Observe(Demand("unity-local", "local", sameMachine: true)); + var activeGeneration = tracker.Plan(bodyId).Generation; + using var commitEntered = new ManualResetEventSlim(); + using var releaseCommit = new ManualResetEventSlim(); + var committed = false; + + var commit = Task.Run(() => tracker.TryExecuteAtGeneration( + bodyId, + activeGeneration, + () => + { + commitEntered.Set(); + releaseCommit.Wait(); + committed = true; + })); + commitEntered.Wait(TimeSpan.FromSeconds(5)).Should().BeTrue(); + + var withdrawal = Task.Run(() => + tracker.Observe(Demand("unity-local", "local", sameMachine: true, active: false))); + await Task.Delay(50); + withdrawal.IsCompleted.Should().BeFalse( + "a withdrawal must serialize after an already-linearized synchronous commit"); + + releaseCommit.Set(); + (await commit).Should().BeTrue(); + await withdrawal; + committed.Should().BeTrue(); + tracker.Plan(bodyId).Generation.Should().BeGreaterThan(activeGeneration); + + var staleCallbackRan = false; + tracker.TryExecuteAtGeneration(bodyId, activeGeneration, () => staleCallbackRan = true) + .Should().BeFalse(); + staleCallbackRan.Should().BeFalse( + "work prepared for a withdrawn demand generation must be discarded before commit"); + } + [Test] public void BodyDemand_UnknownLocalityFailsTowardNetworkAndUnsupportedDemandCreatesNoRoute() { From 4f6e95bb3d04373ea57e31176a259cecfdf6d4f0 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sat, 22 Aug 2026 00:05:57 +0200 Subject: [PATCH 112/283] Carry editable field authority in CultMesh bindings --- packages/cultmesh-ts/src/index.ts | 97 +++++++++++++++++++ packages/cultmesh-ts/test/cultmesh.test.ts | 27 ++++++ src/GameCult.Mesh/CultMesh.cs | 31 +++++- src/GameCult.Mesh/CultMeshPrimitives.cs | 79 ++++++++++++++- .../CultMeshStreamingTests.cs | 31 ++++++ 5 files changed, 257 insertions(+), 8 deletions(-) diff --git a/packages/cultmesh-ts/src/index.ts b/packages/cultmesh-ts/src/index.ts index 76177269..ee1b4893 100644 --- a/packages/cultmesh-ts/src/index.ts +++ b/packages/cultmesh-ts/src/index.ts @@ -300,6 +300,13 @@ export interface CultMeshStateBindingDescriptor { readonly sourceId?: string; readonly schemaId?: string; readonly routeHint: CultMeshRouteHint; + readonly bindingName?: string; + readonly documentId?: string; + readonly fieldPath?: string; + readonly valueKind?: "string" | "number" | "boolean" | "choice" | "string-list"; + readonly accessMode?: "read" | "write" | "read-write" | "local-draft"; + readonly authority?: string; + readonly writeCommand?: string; } export interface CultMeshStateBindingRecord { @@ -309,6 +316,13 @@ export interface CultMeshStateBindingRecord { readonly schemaId: string; readonly routeKind: string; readonly routeDescription: string; + readonly bindingName: string; + readonly documentId: string; + readonly fieldPath: string; + readonly valueKind: string; + readonly accessMode: string; + readonly authority: string; + readonly writeCommand: string; } export interface CultMeshOperationBindingDescriptor { @@ -3351,6 +3365,15 @@ export function cultMeshDescribeStateRefResolver( }; } +function stateBindingMetadata( + options: Pick, +): Partial { + return Object.fromEntries( + Object.entries(options).filter(([, value]) => value !== undefined), + ) as Partial; +} + export function cultMeshStateBinding( targetProp: string, pointer: @@ -3364,6 +3387,13 @@ export function cultMeshStateBinding( sourceId?: string; schemaId?: string; routeHint?: CultMeshRouteHint; + bindingName?: string; + documentId?: string; + fieldPath?: string; + valueKind?: CultMeshStateBindingDescriptor["valueKind"]; + accessMode?: CultMeshStateBindingDescriptor["accessMode"]; + authority?: string; + writeCommand?: string; } = {}, ): CultMeshStateBindingDescriptor { requireNonEmpty(targetProp, "targetProp"); @@ -3375,6 +3405,7 @@ export function cultMeshStateBinding( sourceId: options.sourceId, schemaId: options.schemaId, routeHint: options.routeHint ?? cultMeshRouteHint(), + ...stateBindingMetadata(options), }; } @@ -3386,6 +3417,7 @@ export function cultMeshStateBinding( sourceId: options.sourceId ?? source?.sourceId, schemaId: options.schemaId ?? source?.schemaId, routeHint: options.routeHint ?? pointer.routeHint ?? cultMeshRouteHint(), + ...stateBindingMetadata(options), }; } @@ -3399,6 +3431,13 @@ export function cultMeshStateBindingRecord( schemaId?: string, routeKind?: string, routeDescription?: string, + bindingName?: string, + documentId?: string, + fieldPath?: string, + valueKind?: string, + accessMode?: string, + authority?: string, + writeCommand?: string, ): CultMeshStateBindingRecord; export function cultMeshStateBindingRecord( bindingOrTargetProp?: Partial | string, @@ -3407,6 +3446,13 @@ export function cultMeshStateBindingRecord( schemaId?: string, routeKind?: string, routeDescription?: string, + bindingName?: string, + documentId?: string, + fieldPath?: string, + valueKind?: string, + accessMode?: string, + authority?: string, + writeCommand?: string, ): CultMeshStateBindingRecord { if (typeof bindingOrTargetProp === "object" || bindingOrTargetProp === undefined) { const binding = bindingOrTargetProp; @@ -3418,6 +3464,13 @@ export function cultMeshStateBindingRecord( schemaId: binding?.schemaId ?? "", routeKind: route.kind, routeDescription: route.description, + bindingName: binding?.bindingName ?? "", + documentId: binding?.documentId ?? "", + fieldPath: binding?.fieldPath ?? "", + valueKind: binding?.valueKind ?? "", + accessMode: binding?.accessMode ?? "", + authority: binding?.authority ?? "", + writeCommand: binding?.writeCommand ?? "", }; } @@ -3428,6 +3481,13 @@ export function cultMeshStateBindingRecord( schemaId: schemaId ?? "", routeKind: routeKind ?? "", routeDescription: routeDescription ?? "", + bindingName: bindingName ?? "", + documentId: documentId ?? "", + fieldPath: fieldPath ?? "", + valueKind: valueKind ?? "", + accessMode: accessMode ?? "", + authority: authority ?? "", + writeCommand: writeCommand ?? "", }; } @@ -3451,6 +3511,15 @@ export function cultMeshStateBindingFromRecord( }, options.fallbackRouteHint, ), + ...stateBindingMetadata({ + bindingName: record.bindingName || undefined, + documentId: record.documentId || undefined, + fieldPath: record.fieldPath || undefined, + valueKind: (record.valueKind || undefined) as CultMeshStateBindingDescriptor["valueKind"], + accessMode: (record.accessMode || undefined) as CultMeshStateBindingDescriptor["accessMode"], + authority: record.authority || undefined, + writeCommand: record.writeCommand || undefined, + }), }; } @@ -5278,6 +5347,13 @@ export class CultMesh { sourceId?: string; schemaId?: string; routeHint?: CultMeshRouteHint; + bindingName?: string; + documentId?: string; + fieldPath?: string; + valueKind?: CultMeshStateBindingDescriptor["valueKind"]; + accessMode?: CultMeshStateBindingDescriptor["accessMode"]; + authority?: string; + writeCommand?: string; } = {}, ): CultMeshStateBindingDescriptor { return cultMeshStateBinding(targetProp, pointer, options); @@ -5293,6 +5369,13 @@ export class CultMesh { schemaId?: string, routeKind?: string, routeDescription?: string, + bindingName?: string, + documentId?: string, + fieldPath?: string, + valueKind?: string, + accessMode?: string, + authority?: string, + writeCommand?: string, ): CultMeshStateBindingRecord; public static stateBindingRecord( bindingOrTargetProp?: Partial | string, @@ -5301,6 +5384,13 @@ export class CultMesh { schemaId?: string, routeKind?: string, routeDescription?: string, + bindingName?: string, + documentId?: string, + fieldPath?: string, + valueKind?: string, + accessMode?: string, + authority?: string, + writeCommand?: string, ): CultMeshStateBindingRecord { return typeof bindingOrTargetProp === "object" || bindingOrTargetProp === undefined ? cultMeshStateBindingRecord(bindingOrTargetProp) @@ -5311,6 +5401,13 @@ export class CultMesh { schemaId, routeKind, routeDescription, + bindingName, + documentId, + fieldPath, + valueKind, + accessMode, + authority, + writeCommand, ); } diff --git a/packages/cultmesh-ts/test/cultmesh.test.ts b/packages/cultmesh-ts/test/cultmesh.test.ts index 653a1e95..ab1bc133 100644 --- a/packages/cultmesh-ts/test/cultmesh.test.ts +++ b/packages/cultmesh-ts/test/cultmesh.test.ts @@ -2147,6 +2147,13 @@ test("CultMesh TS flattens and rehydrates UI state binding records", () => { schemaId: "gamecult.aetheria.daemon_frame.v1", routeKind: "shared-memory", routeDescription: "co-located frame slab", + bindingName: "", + documentId: "", + fieldPath: "", + valueKind: "", + accessMode: "", + authority: "", + writeCommand: "", }); assert.deepEqual(CultMesh.stateBindingFromRecord({ @@ -2168,6 +2175,26 @@ test("CultMesh TS flattens and rehydrates UI state binding records", () => { }); }); +test("CultMesh TS preserves editable binding identity and authority through transport records", () => { + const binding = CultMesh.stateBinding("value", "ghostlight.session-zero.composer", { + sourceId: "session-zero:draft-7", + schemaId: "session_zero.v1", + routeHint: CultMesh.routeHint("network", "Ghostlight provider"), + bindingName: "composer.message", + documentId: "session-zero:draft-7", + fieldPath: "channels.private.messages.pending", + valueKind: "string", + accessMode: "local-draft", + authority: "SessionZeroKernel", + writeCommand: "edit.value", + }); + const record = CultMesh.stateBindingRecord(binding); + assert.equal(record.bindingName, "composer.message"); + assert.equal(record.fieldPath, "channels.private.messages.pending"); + assert.equal(record.accessMode, "local-draft"); + assert.deepEqual(CultMesh.stateBindingFromRecord(record), binding); +}); + test("CultMesh TS describes UI command bindings from typed operations", async () => { const operation = CultMesh.operation< { actor: string }, diff --git a/src/GameCult.Mesh/CultMesh.cs b/src/GameCult.Mesh/CultMesh.cs index 232f847e..6dd47f8c 100644 --- a/src/GameCult.Mesh/CultMesh.cs +++ b/src/GameCult.Mesh/CultMesh.cs @@ -1117,9 +1117,18 @@ namespace GameCult.Mesh string pointerId, string? sourceId = null, string? schemaId = null, - CultMeshRouteHint? routeHint = null) + CultMeshRouteHint? routeHint = null, + string? bindingName = null, + string? documentId = null, + string? fieldPath = null, + string? valueKind = null, + string? accessMode = null, + string? authority = null, + string? writeCommand = null) { - return new CultMeshStateBindingDescriptor(targetProp, pointerId, sourceId, schemaId, routeHint); + return new CultMeshStateBindingDescriptor( + targetProp, pointerId, sourceId, schemaId, routeHint, + bindingName, documentId, fieldPath, valueKind, accessMode, authority, writeCommand); } /// @@ -1139,7 +1148,14 @@ namespace GameCult.Mesh string? sourceId = null, string? schemaId = null, string? routeKind = null, - string? routeDescription = null) + string? routeDescription = null, + string? bindingName = null, + string? documentId = null, + string? fieldPath = null, + string? valueKind = null, + string? accessMode = null, + string? authority = null, + string? writeCommand = null) { return new CultMeshStateBindingRecord( targetProp, @@ -1147,7 +1163,14 @@ namespace GameCult.Mesh sourceId, schemaId, routeKind, - routeDescription); + routeDescription, + bindingName, + documentId, + fieldPath, + valueKind, + accessMode, + authority, + writeCommand); } /// diff --git a/src/GameCult.Mesh/CultMeshPrimitives.cs b/src/GameCult.Mesh/CultMeshPrimitives.cs index d136595f..a034e6e6 100644 --- a/src/GameCult.Mesh/CultMeshPrimitives.cs +++ b/src/GameCult.Mesh/CultMeshPrimitives.cs @@ -3329,13 +3329,27 @@ namespace GameCult.Mesh string pointerId, string? sourceId = null, string? schemaId = null, - CultMeshRouteHint? routeHint = null) + CultMeshRouteHint? routeHint = null, + string? bindingName = null, + string? documentId = null, + string? fieldPath = null, + string? valueKind = null, + string? accessMode = null, + string? authority = null, + string? writeCommand = null) { TargetProp = RequireNonEmpty(targetProp, nameof(targetProp)); PointerId = RequireNonEmpty(pointerId, nameof(pointerId)); SourceId = sourceId; SchemaId = schemaId; RouteHint = routeHint ?? CultMeshRouteHint.Automatic; + BindingName = bindingName ?? ""; + DocumentId = documentId ?? ""; + FieldPath = fieldPath ?? ""; + ValueKind = valueKind ?? ""; + AccessMode = accessMode ?? ""; + Authority = authority ?? ""; + WriteCommand = writeCommand ?? ""; } /// Gets the component property receiving the resolved state value. @@ -3353,6 +3367,27 @@ namespace GameCult.Mesh /// Gets the preferred route for resolving and watching the binding. public CultMeshRouteHint RouteHint { get; } + /// Gets the stable renderer-facing name used to capture this binding in an operation. + public string BindingName { get; } + + /// Gets the optional identity of the provider-owned backing document. + public string DocumentId { get; } + + /// Gets the optional typed field path inside the backing document. + public string FieldPath { get; } + + /// Gets the optional portable value kind. + public string ValueKind { get; } + + /// Gets the optional read, write, read-write, or local-draft access mode. + public string AccessMode { get; } + + /// Gets the authority responsible for accepting writes to this binding. + public string Authority { get; } + + /// Gets the optional typed operation id used for direct writes. + public string WriteCommand { get; } + /// Creates a binding from an existing state pointer. public static CultMeshStateBindingDescriptor FromPointer( string targetProp, @@ -3390,7 +3425,14 @@ namespace GameCult.Mesh string? sourceId = null, string? schemaId = null, string? routeKind = null, - string? routeDescription = null) + string? routeDescription = null, + string? bindingName = null, + string? documentId = null, + string? fieldPath = null, + string? valueKind = null, + string? accessMode = null, + string? authority = null, + string? writeCommand = null) { TargetProp = string.IsNullOrWhiteSpace(targetProp) ? "value" : targetProp!; PointerId = pointerId ?? ""; @@ -3398,6 +3440,13 @@ namespace GameCult.Mesh SchemaId = schemaId ?? ""; RouteKind = routeKind ?? ""; RouteDescription = routeDescription ?? ""; + BindingName = bindingName ?? ""; + DocumentId = documentId ?? ""; + FieldPath = fieldPath ?? ""; + ValueKind = valueKind ?? ""; + AccessMode = accessMode ?? ""; + Authority = authority ?? ""; + WriteCommand = writeCommand ?? ""; } /// Gets the component property receiving the resolved state value. @@ -3418,6 +3467,14 @@ namespace GameCult.Mesh /// Gets the flattened route description. [Key(5)] public string RouteDescription { get; } + [Key(6)] public string BindingName { get; } + [Key(7)] public string DocumentId { get; } + [Key(8)] public string FieldPath { get; } + [Key(9)] public string ValueKind { get; } + [Key(10)] public string AccessMode { get; } + [Key(11)] public string Authority { get; } + [Key(12)] public string WriteCommand { get; } + /// Creates transport-friendly fields from a state binding descriptor. public static CultMeshStateBindingRecord FromBinding(CultMeshStateBindingDescriptor? binding) { @@ -3428,7 +3485,14 @@ namespace GameCult.Mesh binding?.SourceId, binding?.SchemaId, route.Kind, - route.Description); + route.Description, + binding?.BindingName, + binding?.DocumentId, + binding?.FieldPath, + binding?.ValueKind, + binding?.AccessMode, + binding?.Authority, + binding?.WriteCommand); } /// Rehydrates this record as a state binding descriptor. @@ -3450,7 +3514,14 @@ namespace GameCult.Mesh pointerId, SourceId, SchemaId, - route); + route, + BindingName, + DocumentId, + FieldPath, + ValueKind, + AccessMode, + Authority, + WriteCommand); } } diff --git a/tests/GameCult.Mesh.Tests/CultMeshStreamingTests.cs b/tests/GameCult.Mesh.Tests/CultMeshStreamingTests.cs index 273d1e87..8ebccf57 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshStreamingTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshStreamingTests.cs @@ -298,6 +298,37 @@ public sealed class CultMeshStreamingTests fromTypescript.RouteHint.Description.Should().Be("browser-adjacent cache"); } + [Test] + public void StateBindingRecord_PreservesEditableFieldIdentityAndAuthority() + { + var binding = CultMesh.StateBinding( + "value", + "ghostlight.session-zero.composer", + sourceId: "session-zero:draft-7", + schemaId: "session_zero.v1", + routeHint: new CultMeshRouteHint(CultMeshLocalityKind.Network, "Ghostlight provider"), + bindingName: "composer.message", + documentId: "session-zero:draft-7", + fieldPath: "channels.private.messages.pending", + valueKind: "string", + accessMode: "local-draft", + authority: "SessionZeroKernel", + writeCommand: "edit.value"); + + var record = CultMesh.StateBindingRecord(binding); + record.BindingName.Should().Be("composer.message"); + record.FieldPath.Should().Be("channels.private.messages.pending"); + record.AccessMode.Should().Be("local-draft"); + var restored = record.ToBinding(); + restored.BindingName.Should().Be(binding.BindingName); + restored.DocumentId.Should().Be(binding.DocumentId); + restored.FieldPath.Should().Be(binding.FieldPath); + restored.ValueKind.Should().Be(binding.ValueKind); + restored.AccessMode.Should().Be(binding.AccessMode); + restored.Authority.Should().Be(binding.Authority); + restored.WriteCommand.Should().Be(binding.WriteCommand); + } + [Test] public void OperationBindingDescriptor_BindsUiCommandsToTypedOperations() { From 5cefa0db0079a8e3ee22f29d7b9e6e5aa60912a9 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sat, 22 Aug 2026 03:25:02 +0200 Subject: [PATCH 113/283] Resolve CultMesh URI RUDP bootstraps in TypeScript --- packages/cultmesh-ts/src/index.ts | 31 ++++++++++++++++++++++ packages/cultmesh-ts/test/cultmesh.test.ts | 13 +++++++++ 2 files changed, 44 insertions(+) diff --git a/packages/cultmesh-ts/src/index.ts b/packages/cultmesh-ts/src/index.ts index ee1b4893..0d1ba965 100644 --- a/packages/cultmesh-ts/src/index.ts +++ b/packages/cultmesh-ts/src/index.ts @@ -6002,6 +6002,37 @@ export class CultMesh { }; } + public static resolveRudpEndpoint( + endpoint: string, + environment: Record = process.env, + ): CultMeshRudpEndpoint { + requireNonEmpty(endpoint, "endpoint"); + const text = endpoint.trim(); + if (text.toLowerCase().startsWith("rudp://")) { + return CultMesh.parseRudpEndpoint(text); + } + if (!text.toLowerCase().startsWith("cultmesh://")) { + return CultMesh.parseRudpEndpoint(`rudp://${text}`); + } + + const uri = new URL(text); + const authority = uri.hostname.trim(); + if (!authority) throw new Error("CultMesh URI must include an authority."); + const slug = authority + .replace(/[^a-z0-9]+/gi, "_") + .replace(/^_+|_+$/g, "") + .toUpperCase(); + for (const key of [`CULTMESH_URI_${slug}_RUDP`, `${slug}_CULTMESH_RUDP_ENDPOINT`]) { + const resolved = environment[key]?.trim(); + if (resolved) { + return CultMesh.parseRudpEndpoint( + resolved.toLowerCase().startsWith("rudp://") ? resolved : `rudp://${resolved}`, + ); + } + } + throw new Error(`CultMesh URI ${text} did not resolve to a RUDP endpoint.`); + } + public static parseRudpEndpoint(endpoint: string): CultMeshRudpEndpoint { requireNonEmpty(endpoint, "endpoint"); const parsed = new URL(endpoint); diff --git a/packages/cultmesh-ts/test/cultmesh.test.ts b/packages/cultmesh-ts/test/cultmesh.test.ts index ab1bc133..07ac0559 100644 --- a/packages/cultmesh-ts/test/cultmesh.test.ts +++ b/packages/cultmesh-ts/test/cultmesh.test.ts @@ -2862,6 +2862,19 @@ test("CultMesh TS publishes one registered document to a RUDP catalog", async () } }); +test("CultMesh TS resolves a CultMesh URI through its authority bootstrap", () => { + assert.deepEqual( + CultMesh.resolveRudpEndpoint("cultmesh://odin/rendezvous/provider-catalog", { + CULTMESH_URI_ODIN_RUDP: "127.0.0.1:17871", + }), + { host: "127.0.0.1", port: 17871, uri: "rudp://127.0.0.1:17871" }, + ); + assert.throws( + () => CultMesh.resolveRudpEndpoint("cultmesh://missing/rendezvous/provider-catalog", {}), + /did not resolve/, + ); +}); + test("CultMesh TS returns a correlated provider receipt after a RUDP document mutation", async () => { const connectionId = 0x10203050; const commandBinding = defineCultNetDocumentBinding({ definition: noteDocument }); From f4dabfefb033dc38fbf781cd9f710454ddc82f94 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 23 Aug 2026 18:35:49 +0200 Subject: [PATCH 114/283] Bound RUDP reliable transmission windows --- docs/cultnet-transport-parity.md | 15 +- .../cultcache-py/src/cultmesh_py/server.py | 6 +- .../src/cultnet_py/interop_peer.py | 6 +- .../cultcache-py/src/cultnet_py/transport.py | 119 ++++++++++++-- packages/cultcache-py/tests/test_cultcache.py | 30 ++++ .../kotlin/org/gamecult/cultmesh/CultMesh.kt | 140 ++++++++++++++-- packages/cultmesh-ts/src/index.ts | 5 +- .../examples/cultnet_interop_peer.rs | 3 + packages/cultnet-rs/src/rudp.rs | 127 +++++++++++++- packages/cultnet-rs/tests/cultnet.rs | 132 +++++++++++++++ packages/cultnet-ts/src/index.ts | 1 + packages/cultnet-ts/src/operation-service.ts | 1 + packages/cultnet-ts/src/peer.ts | 4 + packages/cultnet-ts/src/rudp.ts | 99 +++++++++-- packages/cultnet-ts/src/transport.ts | 1 + packages/cultnet-ts/test/cultnet.test.ts | 36 ++++ src/GameCult.Networking/CultNetTransport.cs | 155 ++++++++++++++++-- .../NetworkingTests.cs | 45 +++++ 18 files changed, 846 insertions(+), 79 deletions(-) diff --git a/docs/cultnet-transport-parity.md b/docs/cultnet-transport-parity.md index 5f0fec91..e9fd0ef8 100644 --- a/docs/cultnet-transport-parity.md +++ b/docs/cultnet-transport-parity.md @@ -258,11 +258,16 @@ Current progress: echo against C#/Kotlin/Python/Rust UDP peers; local runtime tests prove timeout state transitions. - TypeScript, C#, Rust, Python, and Kotlin now share bounded reliable-send - backpressure for RUDP sessions. `maxPendingReliablePackets` is advertised on - RUDP transport-profile channels and enforced by the session before reliable - connect, accept, single-packet sends, or fragmented sends enqueue anything; - TCP-framed profiles do not publish the field because they do not own the RUDP - pending-reliable queue. + backpressure for RUDP sessions. At most 64 reliable packets are admitted to + the wire at once; later fragments remain in a session-owned FIFO and exact + acknowledgements promote the next packets. This keeps the send frontier well + inside the 4,096-sequence receive history instead of blasting an entire large + document and hoping the UDP buffers impersonate flow control. + `maxPendingReliablePackets` bounds both queued and in-flight packets before a + reliable frame is accepted. Socket transports expose an explicit reliable + flush where the runtime supports one, so callers that require confirmed + transport delivery do not substitute a fixed sleep. TCP-framed profiles do + not publish the field because they do not own the RUDP pending-reliable queue. - TypeScript, C#, Rust, Python, and Kotlin now share a portable `cultnet.reconnect_policy.v0` document and deterministic exponential delay helper, and RUDP transport profiles advertise that policy under diff --git a/packages/cultcache-py/src/cultmesh_py/server.py b/packages/cultcache-py/src/cultmesh_py/server.py index d560cc83..0de99729 100644 --- a/packages/cultcache-py/src/cultmesh_py/server.py +++ b/packages/cultcache-py/src/cultmesh_py/server.py @@ -245,6 +245,8 @@ class CultMeshLocalServer: result = peer.session.receive(packet, now_ms) if result.reply is not None: self._send_rudp_packet(rudp_socket, remote_addr, result.reply) + for ready in result.ready_to_send: + self._send_rudp_packet(rudp_socket, remote_addr, ready) if result.disconnected: peers.pop(remote_addr, None) continue @@ -265,8 +267,8 @@ class CultMeshLocalServer: peer.session, msgpack.packb(response, use_bin_type=True), ) - if packet.packet_type == CultNetRudpPacketType.DATA or result.delivered: - self._send_rudp_packet(rudp_socket, remote_addr, peer.session.create_ack()) + if packet.reliable or packet.packet_type == CultNetRudpPacketType.DATA or result.delivered: + self._send_rudp_packet(rudp_socket, remote_addr, peer.session.create_ack_for(packet.sequence)) def _poll_rudp_resends( self, diff --git a/packages/cultcache-py/src/cultnet_py/interop_peer.py b/packages/cultcache-py/src/cultnet_py/interop_peer.py index d26f1b70..98fcf219 100644 --- a/packages/cultcache-py/src/cultnet_py/interop_peer.py +++ b/packages/cultcache-py/src/cultnet_py/interop_peer.py @@ -306,6 +306,8 @@ def rudp_loop( result = peer.session.receive(packet, now_ms()) if result.reply is not None: send_rudp_packet(sock, remote, result.reply) + for ready in result.ready_to_send: + send_rudp_packet(sock, remote, ready) if result.disconnected: peers.pop(remote, None) continue @@ -317,8 +319,8 @@ def rudp_loop( continue for response in handle_server_message(state, message, peer.subscriptions): send_rudp_schema_frame(sock, remote, peer.session, response) - if packet.packet_type == CultNetRudpPacketType.DATA or result.delivered: - send_rudp_packet(sock, remote, peer.session.create_ack()) + if packet.reliable or packet.packet_type == CultNetRudpPacketType.DATA or result.delivered: + send_rudp_packet(sock, remote, peer.session.create_ack_for(packet.sequence)) except Exception as error: sys.stderr.write(json.dumps({ "event": "rudpMessageError", diff --git a/packages/cultcache-py/src/cultnet_py/transport.py b/packages/cultcache-py/src/cultnet_py/transport.py index 25a4c891..ca877a2a 100644 --- a/packages/cultcache-py/src/cultnet_py/transport.py +++ b/packages/cultcache-py/src/cultnet_py/transport.py @@ -280,6 +280,7 @@ class CultNetRudpDeliveredFrame: @dataclass(frozen=True) class CultNetRudpReceiveResult: delivered: tuple[CultNetRudpDeliveredFrame, ...] = field(default_factory=tuple) + ready_to_send: tuple[CultNetRudpPacket, ...] = field(default_factory=tuple) reply: CultNetRudpPacket | None = None pong: bool = False pong_payload: bytes = b"" @@ -395,6 +396,9 @@ def create_rudp_transport_profile( class CultNetRudpSession: + RELIABLE_SEND_WINDOW_PACKETS = 64 + RECEIVED_SEQUENCE_WINDOW = 4_096 + def __init__(self, options: CultNetRudpSessionOptions) -> None: self.connection_id = _uint32(options.connection_id, "connection_id") self.resend_delay_ms = options.resend_delay_ms @@ -408,6 +412,7 @@ class CultNetRudpSession: self._highest_received_sequence: int | None = None self._received_sequences: set[int] = set() self._pending_reliable: dict[int, _PendingReliablePacket] = {} + self._queued_reliable: deque[CultNetRudpPacket] = deque() self._ordered_next_sequence_by_channel: dict[str, int] = {} self._ordered_buffers: dict[str, dict[int, tuple[CultNetRudpDeliveredFrame, int]]] = {} self._fragment_buffers: dict[tuple[str, int], dict[str, Any]] = {} @@ -424,6 +429,14 @@ class CultNetRudpSession: def pending_reliable_sequences(self) -> tuple[int, ...]: return tuple(sorted(self._pending_reliable)) + @property + def queued_reliable_packet_count(self) -> int: + return len(self._queued_reliable) + + @property + def outstanding_reliable_packet_count(self) -> int: + return len(self._pending_reliable) + len(self._queued_reliable) + def create_connect(self, now_ms: int = 0, payload: bytes = b"") -> CultNetRudpPacket: self._ensure_reliable_capacity(1) packet = self._create_packet( @@ -465,7 +478,10 @@ class CultNetRudpSession: payload: bytes, options: CultNetRudpSendOptions | None = None, ) -> CultNetRudpPacket: - return self.send_many(channel_id, payload, options)[0] + resolved = options or CultNetRudpSendOptions() + if resolved.reliable and len(self._pending_reliable) >= self.RELIABLE_SEND_WINDOW_PACKETS: + raise ValueError("RUDP reliable send window is full; receive acknowledgements before sending") + return self.send_many(channel_id, payload, resolved)[0] def send_many( self, @@ -492,9 +508,7 @@ class CultNetRudpSession: ordered=options.ordered, sequenced=options.sequenced, ) - if packet.reliable: - self._track_reliable(packet, options.now_ms) - return (packet,) + return self._admit_reliable_packets((packet,), options.now_ms) if packet.reliable else (packet,) fragment_count = (len(payload) + max_fragment_bytes - 1) // max_fragment_bytes if fragment_count > 0xFFFF: @@ -516,14 +530,13 @@ class CultNetRudpSession: fragment_index=index, fragment_count=fragment_count, ) - if packet.reliable: - self._track_reliable(packet, options.now_ms) packets.append(packet) - return tuple(packets) + return self._admit_reliable_packets(tuple(packets), options.now_ms) if options.reliable else tuple(packets) def receive(self, packet: CultNetRudpPacket, now_ms: int = 0) -> CultNetRudpReceiveResult: self._require_connection(packet) self._apply_acknowledgements(packet) + ready_to_send = self._promote_queued_reliable(now_ms) self._last_received_at_ms = now_ms expected_sequence_if_uninitialized = ( packet.sequence @@ -534,17 +547,19 @@ class CultNetRudpSession: if packet.packet_type == CultNetRudpPacketType.ACCEPT: self._remember_received(packet.sequence) self._connected = True - return CultNetRudpReceiveResult() + return CultNetRudpReceiveResult(ready_to_send=ready_to_send) if packet.packet_type == CultNetRudpPacketType.PING: self._remember_received(packet.sequence) return CultNetRudpReceiveResult( + ready_to_send=ready_to_send, reply=self._create_packet(CultNetRudpPacketType.PONG, "control", packet.payload) ) if packet.packet_type in (CultNetRudpPacketType.ACK, CultNetRudpPacketType.PONG): self._remember_received(packet.sequence) return CultNetRudpReceiveResult( + ready_to_send=ready_to_send, pong=packet.packet_type == CultNetRudpPacketType.PONG, pong_payload=bytes(packet.payload) if packet.packet_type == CultNetRudpPacketType.PONG else b"", ) @@ -553,33 +568,50 @@ class CultNetRudpSession: self._remember_received(packet.sequence) self._connected = False return CultNetRudpReceiveResult( + ready_to_send=ready_to_send, disconnected=True, disconnect_reason=bytes(packet.payload), ) if packet.packet_type != CultNetRudpPacketType.DATA: - return CultNetRudpReceiveResult() + return CultNetRudpReceiveResult(ready_to_send=ready_to_send) - duplicate = packet.sequence in self._received_sequences + duplicate = packet.sequence in self._received_sequences or ( + self._highest_received_sequence is not None + and packet.sequence < self._highest_received_sequence + and self._highest_received_sequence - packet.sequence >= self.RECEIVED_SEQUENCE_WINDOW + ) self._remember_received(packet.sequence) if duplicate: - return CultNetRudpReceiveResult() + return CultNetRudpReceiveResult(ready_to_send=ready_to_send) reassembled = self._reassemble(packet) if reassembled is None: - return CultNetRudpReceiveResult() + return CultNetRudpReceiveResult(ready_to_send=ready_to_send) frame, ordered, next_sequence = reassembled if not ordered: - return CultNetRudpReceiveResult(delivered=(frame,)) + return CultNetRudpReceiveResult(delivered=(frame,), ready_to_send=ready_to_send) return CultNetRudpReceiveResult( delivered=tuple( self._deliver_ordered(frame, next_sequence, expected_sequence_if_uninitialized) - ) + ), + ready_to_send=ready_to_send, ) def create_ack(self) -> CultNetRudpPacket: return self._create_packet(CultNetRudpPacketType.ACK, "control", b"") + def create_ack_for(self, sequence: int) -> CultNetRudpPacket: + return CultNetRudpPacket( + packet_type=CultNetRudpPacketType.ACK, + connection_id=self.connection_id, + sequence=0, + ack=_uint32(sequence, "ack sequence"), + ack_mask=0, + channel_id="control", + payload=b"", + ) + def create_ping(self, payload: bytes = b"") -> CultNetRudpPacket: return self._create_packet(CultNetRudpPacketType.PING, "control", payload) @@ -655,10 +687,31 @@ class CultNetRudpSession: last_sent_at_ms=now_ms, ) + def _admit_reliable_packets( + self, + packets: tuple[CultNetRudpPacket, ...], + now_ms: int, + ) -> tuple[CultNetRudpPacket, ...]: + available = max(0, self.RELIABLE_SEND_WINDOW_PACKETS - len(self._pending_reliable)) + ready = packets[:available] + for packet in ready: + self._track_reliable(packet, now_ms) + self._queued_reliable.extend(packets[available:]) + return ready + + def _promote_queued_reliable(self, now_ms: int) -> tuple[CultNetRudpPacket, ...]: + available = max(0, self.RELIABLE_SEND_WINDOW_PACKETS - len(self._pending_reliable)) + ready: list[CultNetRudpPacket] = [] + while len(ready) < available and self._queued_reliable: + packet = self._queued_reliable.popleft() + self._track_reliable(packet, now_ms) + ready.append(packet) + return tuple(ready) + def _ensure_reliable_capacity(self, packet_count: int) -> None: if packet_count == 0 or self.max_pending_reliable_packets is None: return - if len(self._pending_reliable) + packet_count > self.max_pending_reliable_packets: + if self.outstanding_reliable_packet_count + packet_count > self.max_pending_reliable_packets: raise ValueError("RUDP reliable send queue is full") def _apply_acknowledgements(self, packet: CultNetRudpPacket) -> None: @@ -671,6 +724,9 @@ class CultNetRudpSession: self._received_sequences.add(sequence) if self._highest_received_sequence is None or sequence > self._highest_received_sequence: self._highest_received_sequence = sequence + if len(self._received_sequences) > self.RECEIVED_SEQUENCE_WINDOW: + keep_from = max(0, (self._highest_received_sequence or sequence) - self.RECEIVED_SEQUENCE_WINDOW + 1) + self._received_sequences = {received for received in self._received_sequences if received >= keep_from} def _ack_state(self) -> tuple[int, int]: ack = self._highest_received_sequence or 0 @@ -838,6 +894,10 @@ class CultNetRudpSocketTransportConnection: frames_sent=self._frames_sent, ) + @property + def outstanding_reliable_packet_count(self) -> int: + return self.session.outstanding_reliable_packet_count + def connect(self, payload: bytes = b"") -> None: if self.mode != CultNetRudpSocketMode.CLIENT: raise ValueError("Only a client RUDP socket transport can initiate connect") @@ -879,6 +939,8 @@ class CultNetRudpSocketTransportConnection: result = self.session.receive(packet, _now_ms()) if result.reply is not None: self._send_packet(result.reply) + for ready in result.ready_to_send: + self._send_packet(ready) if result.pong: self.pong_payloads.append(result.pong_payload) if result.disconnected: @@ -892,8 +954,8 @@ class CultNetRudpSocketTransportConnection: self._frames_received += 1 frame = self._delivered_frames.popleft() if self._delivered_frames else None - if packet.packet_type == CultNetRudpPacketType.ACCEPT or frame is not None: - self._send_packet(self.session.create_ack()) + if packet.reliable or packet.packet_type == CultNetRudpPacketType.ACCEPT or frame is not None: + self._send_packet(self.session.create_ack_for(packet.sequence)) return frame def receive(self, timeout_seconds: float | None = None) -> CultNetTransportFrame: @@ -906,6 +968,29 @@ class CultNetRudpSocketTransportConnection: if deadline is not None and time.monotonic() >= deadline: raise TimeoutError("Timed out waiting for RUDP schema frame") + def flush_reliable(self, timeout_seconds: float = 30.0) -> None: + deadline = time.monotonic() + max(0.0, timeout_seconds) + original_timeout = self.socket.gettimeout() + poll_timeout = min(original_timeout, 0.01) if original_timeout is not None else 0.01 + preserved = deque(self._delivered_frames) + self._delivered_frames.clear() + self.socket.settimeout(poll_timeout) + try: + while self.session.outstanding_reliable_packet_count > 0: + if time.monotonic() >= deadline: + raise TimeoutError( + "RUDP reliable flush timed out with " + f"{self.session.outstanding_reliable_packet_count} packets outstanding" + ) + frame = self.receive_once() + if frame is not None: + preserved.append(frame) + self.poll_resends() + finally: + preserved.extend(self._delivered_frames) + self._delivered_frames = preserved + self.socket.settimeout(original_timeout) + def disconnect(self, reason: bytes = b"") -> None: self._send_packet(self.session.create_disconnect(reason)) diff --git a/packages/cultcache-py/tests/test_cultcache.py b/packages/cultcache-py/tests/test_cultcache.py index 82a00845..c6dedd65 100644 --- a/packages/cultcache-py/tests/test_cultcache.py +++ b/packages/cultcache-py/tests/test_cultcache.py @@ -1157,6 +1157,36 @@ class CultCacheTests(unittest.TestCase): self.assertEqual(delivered[0].payload, b"fragment-me-please") self.assertEqual(delivered[0].sequence, packets[0].sequence) + def test_cultnet_rudp_session_advances_large_fragment_sets_through_bounded_window(self) -> None: + connection_id = 457 + sender = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=connection_id, initial_sequence=1)) + receiver = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=connection_id, initial_sequence=100)) + sender.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, connection_id, 0, 0, 0, "control")) + receiver.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, connection_id, 0, 0, 0, "control")) + + fragment_count = CultNetRudpSession.RELIABLE_SEND_WINDOW_PACKETS + 17 + payload = bytes(index % 251 for index in range(fragment_count * 8)) + wire = list(sender.send_many( + "schema", + payload, + CultNetRudpSendOptions(reliable=True, ordered=True, now_ms=1), + max_fragment_bytes=8, + )) + self.assertEqual(len(wire), CultNetRudpSession.RELIABLE_SEND_WINDOW_PACKETS) + self.assertEqual(len(sender.pending_reliable_sequences), len(wire)) + self.assertEqual(sender.queued_reliable_packet_count, 17) + + delivered = [] + while wire: + packet = wire.pop(0) + delivered.extend(receiver.receive(packet, 2).delivered) + acknowledged = sender.receive(receiver.create_ack_for(packet.sequence), 3) + wire.extend(acknowledged.ready_to_send) + + self.assertEqual(sender.outstanding_reliable_packet_count, 0) + self.assertEqual(len(delivered), 1) + self.assertEqual(delivered[0].payload, payload) + def test_cultnet_rudp_socket_transport_handshakes_and_carries_reliable_ordered_schema_frames(self) -> None: server_socket = bind_udp_socket() client_socket = bind_udp_socket() diff --git a/packages/cultmesh-kotlin/src/main/kotlin/org/gamecult/cultmesh/CultMesh.kt b/packages/cultmesh-kotlin/src/main/kotlin/org/gamecult/cultmesh/CultMesh.kt index 968e7669..a7f90610 100644 --- a/packages/cultmesh-kotlin/src/main/kotlin/org/gamecult/cultmesh/CultMesh.kt +++ b/packages/cultmesh-kotlin/src/main/kotlin/org/gamecult/cultmesh/CultMesh.kt @@ -2587,6 +2587,7 @@ data class CultNetRudpPacket( data class CultNetRudpDeliveredFrame(val channelId: String, val payload: ByteArray, val sequence: Long) data class CultNetRudpReceiveResult( val delivered: List = emptyList(), + val readyToSend: List = emptyList(), val reply: CultNetRudpPacket? = null, val pong: Boolean = false, val pongPayload: ByteArray = ByteArray(0), @@ -2619,6 +2620,11 @@ private data class FragmentBuffer( ) class CultNetRudpSession(options: CultNetRudpSessionOptions) { + companion object { + const val ReliableSendWindowPackets = 64 + private const val ReceivedSequenceWindow = 4_096 + } + val connectionId: Long = uint32(options.connectionId, "connectionId") val resendDelayMs: Long = options.resendDelayMs private val maxPendingReliablePackets: Int? = options.maxPendingReliablePackets @@ -2631,12 +2637,17 @@ class CultNetRudpSession(options: CultNetRudpSessionOptions) { private var highestReceivedSequence: Long? = null private val receivedSequences = linkedSetOf() private val pendingReliable = linkedMapOf() + private val queuedReliable = ArrayDeque() private val orderedNextSequenceByChannel = linkedMapOf() private val orderedBuffers = linkedMapOf>() private val fragmentBuffers = linkedMapOf, FragmentBuffer>() val pendingReliableSequences: List get() = pendingReliable.keys.sorted() + val queuedReliablePacketCount: Int + get() = queuedReliable.size + val outstandingReliablePacketCount: Int + get() = pendingReliable.size + queuedReliable.size init { if (maxPendingReliablePackets != null && maxPendingReliablePackets <= 0) { @@ -2663,6 +2674,9 @@ class CultNetRudpSession(options: CultNetRudpSessionOptions) { } fun send(channelId: String, payload: ByteArray, options: CultNetRudpSendOptions = CultNetRudpSendOptions()): CultNetRudpPacket { + if (options.reliable && pendingReliable.size >= ReliableSendWindowPackets) { + throw IOException("RUDP reliable send window is full; receive acknowledgements before sending") + } return sendMany(channelId, payload, options).first() } @@ -2679,7 +2693,7 @@ class CultNetRudpSession(options: CultNetRudpSessionOptions) { if (fragmentCount > 0xffff) throw IOException("RUDP payload requires more than 65535 fragments") ensureReliableCapacity(if (options.reliable) fragmentCount else 0) val fragmentId = allocateFragmentId() - return (0 until fragmentCount).map { index -> + val packets = (0 until fragmentCount).map { index -> val start = index * maxFragmentBytes val packet = createPacket( channelId = channelId, @@ -2692,14 +2706,13 @@ class CultNetRudpSession(options: CultNetRudpSessionOptions) { fragmentIndex = index, fragmentCount = fragmentCount, ) - if (packet.reliable) trackReliable(packet, options.nowMs) packet } + return if (options.reliable) admitReliablePackets(packets, options.nowMs) else packets } ensureReliableCapacity(if (options.reliable) 1 else 0) val packet = createPacket(channelId = channelId, packetType = CultNetRudpPacketType.Data, payload = payload, reliable = options.reliable, ordered = options.ordered, sequenced = options.sequenced) - if (packet.reliable) trackReliable(packet, options.nowMs) - return listOf(packet) + return if (packet.reliable) admitReliablePackets(listOf(packet), options.nowMs) else listOf(packet) } fun receive(packet: CultNetRudpPacket, nowMs: Long = 0): CultNetRudpReceiveResult { @@ -2707,21 +2720,23 @@ class CultNetRudpSession(options: CultNetRudpSessionOptions) { val ignoredNow = nowMs requireConnection(packet) applyAcknowledgements(packet) + val readyToSend = promoteQueuedReliable(nowMs) lastReceivedAtMs = nowMs val expectedSequenceIfUninitialized = (highestReceivedSequence ?: (packet.sequence - 1)) + 1 when (packet.packetType) { CultNetRudpPacketType.Accept -> { rememberReceived(packet.sequence) connected = true - return CultNetRudpReceiveResult() + return CultNetRudpReceiveResult(readyToSend = readyToSend) } CultNetRudpPacketType.Ping -> { rememberReceived(packet.sequence) - return CultNetRudpReceiveResult(reply = createPacket(CultNetRudpPacketType.Pong, "control", packet.payload)) + return CultNetRudpReceiveResult(readyToSend = readyToSend, reply = createPacket(CultNetRudpPacketType.Pong, "control", packet.payload)) } CultNetRudpPacketType.Ack, CultNetRudpPacketType.Pong -> { rememberReceived(packet.sequence) return CultNetRudpReceiveResult( + readyToSend = readyToSend, pong = packet.packetType == CultNetRudpPacketType.Pong, pongPayload = if (packet.packetType == CultNetRudpPacketType.Pong) packet.payload.copyOf() else ByteArray(0), ) @@ -2729,21 +2744,37 @@ class CultNetRudpSession(options: CultNetRudpSessionOptions) { CultNetRudpPacketType.Disconnect -> { rememberReceived(packet.sequence) connected = false - return CultNetRudpReceiveResult(disconnected = true, disconnectReason = packet.payload.copyOf()) + return CultNetRudpReceiveResult(readyToSend = readyToSend, disconnected = true, disconnectReason = packet.payload.copyOf()) } CultNetRudpPacketType.Data -> Unit - else -> return CultNetRudpReceiveResult() + else -> return CultNetRudpReceiveResult(readyToSend = readyToSend) } - val duplicate = receivedSequences.contains(packet.sequence) + val duplicate = receivedSequences.contains(packet.sequence) || ( + highestReceivedSequence != null && + packet.sequence < highestReceivedSequence!! && + highestReceivedSequence!! - packet.sequence >= ReceivedSequenceWindow.toLong() + ) rememberReceived(packet.sequence) - if (duplicate) return CultNetRudpReceiveResult() - val reassembled = reassemble(packet) ?: return CultNetRudpReceiveResult() - return CultNetRudpReceiveResult(delivered = if (reassembled.ordered) deliverOrdered(reassembled.frame, reassembled.nextSequence, expectedSequenceIfUninitialized) else listOf(reassembled.frame)) + if (duplicate) return CultNetRudpReceiveResult(readyToSend = readyToSend) + val reassembled = reassemble(packet) ?: return CultNetRudpReceiveResult(readyToSend = readyToSend) + return CultNetRudpReceiveResult( + delivered = if (reassembled.ordered) deliverOrdered(reassembled.frame, reassembled.nextSequence, expectedSequenceIfUninitialized) else listOf(reassembled.frame), + readyToSend = readyToSend, + ) } fun createAck(): CultNetRudpPacket = createPacket(CultNetRudpPacketType.Ack, "control", ByteArray(0)) + fun createAckFor(sequence: Long): CultNetRudpPacket = CultNetRudpPacket( + packetType = CultNetRudpPacketType.Ack, + connectionId = connectionId, + sequence = 0, + ack = uint32(sequence, "ack sequence"), + ackMask = 0, + channelId = "control", + ) + fun createPing(payload: ByteArray = ByteArray(0)): CultNetRudpPacket = createPacket(CultNetRudpPacketType.Ping, "control", payload) @@ -2787,9 +2818,28 @@ class CultNetRudpSession(options: CultNetRudpSessionOptions) { pendingReliable[packet.sequence] = PendingReliablePacket(packet.copy(payload = packet.payload.copyOf()), nowMs) } + private fun admitReliablePackets(packets: List, nowMs: Long): List { + val available = maxOf(0, ReliableSendWindowPackets - pendingReliable.size) + val ready = packets.take(available) + ready.forEach { trackReliable(it, nowMs) } + packets.drop(available).forEach { queuedReliable.addLast(it.copy(payload = it.payload.copyOf())) } + return ready + } + + private fun promoteQueuedReliable(nowMs: Long): List { + val available = maxOf(0, ReliableSendWindowPackets - pendingReliable.size) + val ready = mutableListOf() + while (ready.size < available && !queuedReliable.isEmpty()) { + val packet = queuedReliable.removeFirst() + trackReliable(packet, nowMs) + ready.add(packet) + } + return ready + } + private fun ensureReliableCapacity(packetCount: Int) { if (packetCount == 0 || maxPendingReliablePackets == null) return - if (pendingReliable.size + packetCount > maxPendingReliablePackets) { + if (outstandingReliablePacketCount + packetCount > maxPendingReliablePackets) { throw IOException("RUDP reliable send queue is full") } } @@ -2806,6 +2856,10 @@ class CultNetRudpSession(options: CultNetRudpSessionOptions) { private fun rememberReceived(sequence: Long) { receivedSequences.add(sequence) if (highestReceivedSequence == null || sequence > highestReceivedSequence!!) highestReceivedSequence = sequence + if (receivedSequences.size > ReceivedSequenceWindow) { + val keepFrom = maxOf(0L, (highestReceivedSequence ?: sequence) - ReceivedSequenceWindow.toLong() + 1) + receivedSequences.removeIf { it < keepFrom } + } } private fun ackState(): Pair { @@ -3010,6 +3064,7 @@ class CultNetRudpSocketTransportConnection( maxPendingReliablePackets = maxPendingReliablePackets, ) val connected: Boolean get() = session.connected + val outstandingReliablePacketCount: Int get() = session.outstandingReliablePacketCount val localPort: Int get() = socket.localPort override val stats: CultNetTransportStats get() = CultNetTransportStats(bytesReceived, bytesSent, framesReceived, framesSent) @@ -3093,6 +3148,27 @@ class CultNetRudpSocketTransportConnection( override fun receiveSchemaMessage(timeoutMs: Long, pollIntervalMs: Long): CultNetMessage? = receiveSchema(timeoutMs, pollIntervalMs)?.let { parseCultNetMessage(it) } + fun flushReliable(timeoutMs: Long = 30_000, pollIntervalMs: Long = 5) { + val deadline = System.nanoTime() + timeoutMs.coerceAtLeast(0) * 1_000_000L + val preserved = ArrayDeque() + while (!delivered.isEmpty()) preserved.addLast(delivered.removeFirst()) + try { + while (session.outstandingReliablePacketCount > 0) { + if (System.nanoTime() >= deadline) { + throw SocketTimeoutException( + "RUDP reliable flush timed out with ${session.outstandingReliablePacketCount} packets outstanding" + ) + } + receiveOnce()?.let { preserved.addLast(it) } + pollResends() + Thread.sleep(pollIntervalMs) + } + } finally { + while (!delivered.isEmpty()) preserved.addLast(delivered.removeFirst()) + while (!preserved.isEmpty()) delivered.addLast(preserved.removeFirst()) + } + } + fun receiveOnce(): CultNetTransportFrame? { if (!delivered.isEmpty()) return delivered.removeFirst() val buffer = ByteArray(65535) @@ -3116,6 +3192,7 @@ class CultNetRudpSocketTransportConnection( } val result = session.receive(packet, nowMs()) result.reply?.let { sendPacket(it) } + result.readyToSend.forEach { sendPacket(it) } if (result.pong) { pongPayloads.add(result.pongPayload.copyOf()) } @@ -3128,7 +3205,7 @@ class CultNetRudpSocketTransportConnection( framesReceived += 1 } val frame = if (delivered.isEmpty()) null else delivered.removeFirst() - if (packet.packetType == CultNetRudpPacketType.Accept || frame != null) sendPacket(session.createAck()) + if (packet.reliable || packet.packetType == CultNetRudpPacketType.Accept || frame != null) sendPacket(session.createAckFor(packet.sequence)) return frame } @@ -3252,6 +3329,7 @@ fun main(args: Array) { rudpSessionPingsAndDetectsReceiveTimeout() rudpSessionBoundsPendingReliablePacketsBeforeEnqueue() rudpSessionFragmentsAndReassemblesReliableOrderedPayloads() + rudpSessionAdvancesLargeFragmentSetsThroughBoundedReliableWindow() rudpSocketTransportErgonomicFactoriesCarrySchemaFrames() rudpSocketTransportHandshakesAndCarriesReliableOrderedSchemaFrames() rudpSocketTransportCarriesFragmentedReliableOrderedSchemaFrames() @@ -3893,7 +3971,8 @@ private fun startInteropRudpServer( } val result = session.receive(packet, nowMs()) result.reply?.let { sendInteropRudpPacket(socket, remote, it) } - if (packet.packetType == CultNetRudpPacketType.Data) sendInteropRudpPacket(socket, remote, session.createAck()) + result.readyToSend.forEach { sendInteropRudpPacket(socket, remote, it) } + if (packet.reliable || packet.packetType == CultNetRudpPacketType.Data) sendInteropRudpPacket(socket, remote, session.createAckFor(packet.sequence)) for (frame in result.delivered) { if (frame.channelId != "schema") continue val sender = InteropRudpSessionSender(socket, remote, session) @@ -5223,6 +5302,37 @@ private fun rudpSessionFragmentsAndReassemblesReliableOrderedPayloads() { check(delivered.first().sequence == packets.first().sequence) } +private fun rudpSessionAdvancesLargeFragmentSetsThroughBoundedReliableWindow() { + val connectionId = 457L + val sender = CultNetRudpSession(CultNetRudpSessionOptions(connectionId = connectionId, initialSequence = 1)) + val receiver = CultNetRudpSession(CultNetRudpSessionOptions(connectionId = connectionId, initialSequence = 100)) + sender.receive(CultNetRudpPacket(CultNetRudpPacketType.Accept, connectionId, 0, 0, 0, "control")) + receiver.receive(CultNetRudpPacket(CultNetRudpPacketType.Accept, connectionId, 0, 0, 0, "control")) + + val fragmentCount = CultNetRudpSession.ReliableSendWindowPackets + 17 + val payload = ByteArray(fragmentCount * 8) { index -> (index % 251).toByte() } + val wire = ArrayDeque(sender.sendMany( + "schema", + payload, + CultNetRudpSendOptions(reliable = true, ordered = true, nowMs = 1), + maxFragmentBytes = 8, + )) + check(wire.size == CultNetRudpSession.ReliableSendWindowPackets) + check(sender.pendingReliableSequences.size == wire.size) + check(sender.queuedReliablePacketCount == 17) + + val delivered = mutableListOf() + while (!wire.isEmpty()) { + val packet = wire.removeFirst() + delivered.addAll(receiver.receive(packet, 2).delivered) + val acknowledged = sender.receive(receiver.createAckFor(packet.sequence), 3) + acknowledged.readyToSend.forEach { wire.addLast(it) } + } + check(sender.outstandingReliablePacketCount == 0) + check(delivered.size == 1) + check(delivered.first().payload.contentEquals(payload)) +} + private fun rudpSocketTransportErgonomicFactoriesCarrySchemaFrames() { val connectionId = 0x10203042L CultMesh.createRudpServer( diff --git a/packages/cultmesh-ts/src/index.ts b/packages/cultmesh-ts/src/index.ts index 0d1ba965..2ed6e4b7 100644 --- a/packages/cultmesh-ts/src/index.ts +++ b/packages/cultmesh-ts/src/index.ts @@ -5816,6 +5816,9 @@ export class CultMesh { if (result.reply) { socket.send(encodeRudpPacket(result.reply), record.remote.port, record.remote.address); } + for (const ready of result.readyToSend ?? []) { + socket.send(encodeRudpPacket(ready), record.remote.port, record.remote.address); + } for (const frame of result.delivered) { if (frame.channelId !== "schema") { continue; @@ -6078,7 +6081,7 @@ export class CultMesh { tags: options.tags, }, )); - await new Promise((resolve) => setTimeout(resolve, Math.max(0, options.flushTimeoutMs ?? 150))); + await peer.flush(options.flushTimeoutMs ?? 30_000); } finally { peer.close(); } diff --git a/packages/cultnet-rs/examples/cultnet_interop_peer.rs b/packages/cultnet-rs/examples/cultnet_interop_peer.rs index ab00c6c8..1ed70a35 100644 --- a/packages/cultnet-rs/examples/cultnet_interop_peer.rs +++ b/packages/cultnet-rs/examples/cultnet_interop_peer.rs @@ -986,6 +986,9 @@ fn run_rudp_server( if let Some(reply) = result.reply { send_rudp_packet(&socket, remote_addr, &reply)?; } + for ready in result.ready_to_send { + send_rudp_packet(&socket, remote_addr, &ready)?; + } if packet.packet_type == CultNetRudpPacketType::Data { let ack = peer.session.create_ack(); send_rudp_packet(&socket, remote_addr, &ack)?; diff --git a/packages/cultnet-rs/src/rudp.rs b/packages/cultnet-rs/src/rudp.rs index ae1ef00b..7cae0b28 100644 --- a/packages/cultnet-rs/src/rudp.rs +++ b/packages/cultnet-rs/src/rudp.rs @@ -6,8 +6,7 @@ use std::collections::VecDeque; use std::io::ErrorKind; use std::net::SocketAddr; use std::net::UdpSocket; -use std::time::SystemTime; -use std::time::UNIX_EPOCH; +use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; use crate::CultNetMessage; use crate::CultNetReconnectController; @@ -30,6 +29,7 @@ const RUDP_MAGIC: [u8; 4] = [0x43, 0x4e, 0x52, 0x30]; const RUDP_VERSION: u8 = 0; const RUDP_FIXED_HEADER_BYTES: usize = 36; pub const CULTNET_RUDP_DEFAULT_MAX_PAYLOAD_BYTES: usize = 16 * 1024 * 1024; +pub const CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS: usize = 64; const RUDP_RECEIVED_SEQUENCE_WINDOW: usize = 4_096; #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -70,6 +70,7 @@ pub struct CultNetRudpDeliveredFrame { #[derive(Clone, Debug, PartialEq, Eq)] pub struct CultNetRudpReceiveResult { pub delivered: Vec, + pub ready_to_send: Vec, pub reply: Option, pub pong: bool, pub pong_payload: Vec, @@ -139,6 +140,7 @@ pub struct CultNetRudpSession { highest_received_sequence: Option, received_sequences: BTreeSet, pending_reliable: BTreeMap, + queued_reliable: VecDeque, ordered_next_sequence_by_channel: BTreeMap, ordered_buffers: BTreeMap>, fragment_buffers: BTreeMap<(String, u16), FragmentBuffer>, @@ -160,6 +162,7 @@ impl CultNetRudpSession { highest_received_sequence: None, received_sequences: BTreeSet::new(), pending_reliable: BTreeMap::new(), + queued_reliable: VecDeque::new(), ordered_next_sequence_by_channel: BTreeMap::new(), ordered_buffers: BTreeMap::new(), fragment_buffers: BTreeMap::new(), @@ -182,6 +185,14 @@ impl CultNetRudpSession { self.pending_reliable.keys().copied().collect() } + pub fn queued_reliable_packet_count(&self) -> usize { + self.queued_reliable.len() + } + + pub fn outstanding_reliable_packet_count(&self) -> usize { + self.pending_reliable.len() + self.queued_reliable.len() + } + fn pending_accept_for_resend(&mut self, now_ms: u64) -> Option { let pending = self .pending_reliable @@ -220,6 +231,7 @@ impl CultNetRudpSession { self.highest_received_sequence = None; self.received_sequences.clear(); self.pending_reliable.clear(); + self.queued_reliable.clear(); self.ordered_next_sequence_by_channel.clear(); self.ordered_buffers.clear(); self.fragment_buffers.clear(); @@ -275,6 +287,13 @@ impl CultNetRudpSession { payload: Vec, options: CultNetRudpSendOptions, ) -> Result { + if options.reliable + && self.pending_reliable.len() >= CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS + { + return Err(anyhow!( + "RUDP reliable send window is full; receive acknowledgements before sending" + )); + } self.send_many(channel_id, payload, options, None)? .into_iter() .next() @@ -321,12 +340,13 @@ impl CultNetRudpSession { index as u16, fragment_count as u16, ); - if packet.reliable { - self.track_reliable(packet.clone(), options.now_ms); - } packets.push(packet); } - return Ok(packets); + return Ok(if options.reliable { + self.admit_reliable_packets(packets, options.now_ms) + } else { + packets + }); } } @@ -340,7 +360,7 @@ impl CultNetRudpSession { options.sequenced, ); if packet.reliable { - self.track_reliable(packet.clone(), options.now_ms); + return Ok(self.admit_reliable_packets(vec![packet], options.now_ms)); } Ok(vec![packet]) } @@ -352,6 +372,7 @@ impl CultNetRudpSession { ) -> Result { self.require_connection(packet)?; self.apply_acknowledgements(packet); + let ready_to_send = self.promote_queued_reliable(now_ms); self.last_received_at_ms = Some(now_ms); let expected_sequence_if_uninitialized = self .highest_received_sequence @@ -363,6 +384,7 @@ impl CultNetRudpSession { self.connected = true; return Ok(CultNetRudpReceiveResult { delivered: Vec::new(), + ready_to_send, reply: None, pong: false, pong_payload: Vec::new(), @@ -375,6 +397,7 @@ impl CultNetRudpSession { self.remember_received(packet.sequence); return Ok(CultNetRudpReceiveResult { delivered: Vec::new(), + ready_to_send, reply: Some(self.create_packet( CultNetRudpPacketType::Pong, "control", @@ -398,6 +421,7 @@ impl CultNetRudpSession { } return Ok(CultNetRudpReceiveResult { delivered: Vec::new(), + ready_to_send, reply: None, pong: packet.packet_type == CultNetRudpPacketType::Pong, pong_payload: if packet.packet_type == CultNetRudpPacketType::Pong { @@ -415,6 +439,7 @@ impl CultNetRudpSession { self.connected = false; return Ok(CultNetRudpReceiveResult { delivered: Vec::new(), + ready_to_send, reply: None, pong: false, pong_payload: Vec::new(), @@ -426,6 +451,7 @@ impl CultNetRudpSession { if packet.packet_type != CultNetRudpPacketType::Data { return Ok(CultNetRudpReceiveResult { delivered: Vec::new(), + ready_to_send, reply: None, pong: false, pong_payload: Vec::new(), @@ -443,6 +469,7 @@ impl CultNetRudpSession { if duplicate { return Ok(CultNetRudpReceiveResult { delivered: Vec::new(), + ready_to_send, reply: None, pong: false, pong_payload: Vec::new(), @@ -454,6 +481,7 @@ impl CultNetRudpSession { let Some((frame, ordered, next_sequence)) = self.reassemble(packet)? else { return Ok(CultNetRudpReceiveResult { delivered: Vec::new(), + ready_to_send, reply: None, pong: false, pong_payload: Vec::new(), @@ -468,6 +496,7 @@ impl CultNetRudpSession { }; Ok(CultNetRudpReceiveResult { delivered, + ready_to_send, reply: None, pong: false, pong_payload: Vec::new(), @@ -630,12 +659,45 @@ impl CultNetRudpSession { ); } + fn admit_reliable_packets( + &mut self, + packets: Vec, + now_ms: u64, + ) -> Vec { + let available = + CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS.saturating_sub(self.pending_reliable.len()); + let mut ready = Vec::with_capacity(available.min(packets.len())); + for packet in packets { + if ready.len() < available { + self.track_reliable(packet.clone(), now_ms); + ready.push(packet); + } else { + self.queued_reliable.push_back(packet); + } + } + ready + } + + fn promote_queued_reliable(&mut self, now_ms: u64) -> Vec { + let available = + CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS.saturating_sub(self.pending_reliable.len()); + let mut ready = Vec::with_capacity(available.min(self.queued_reliable.len())); + for _ in 0..available { + let Some(packet) = self.queued_reliable.pop_front() else { + break; + }; + self.track_reliable(packet.clone(), now_ms); + ready.push(packet); + } + ready + } + fn ensure_reliable_capacity(&self, packet_count: usize) -> Result<()> { if packet_count == 0 { return Ok(()); } if let Some(limit) = self.max_pending_reliable_packets { - if self.pending_reliable.len() + packet_count > limit { + if self.outstanding_reliable_packet_count() + packet_count > limit { return Err(anyhow!("RUDP reliable send queue is full")); } } @@ -1283,6 +1345,9 @@ impl CultNetRudpServerHub { if let Some(reply) = result.reply { self.send_packet(remote_addr, &reply)?; } + for ready in result.ready_to_send { + self.send_packet(remote_addr, &ready)?; + } if let Some(ack) = ack { self.send_packet(remote_addr, &ack)?; } @@ -1474,6 +1539,49 @@ impl CultNetRudpSocketTransportConnection { self.session.check_timeout(now_ms(), timeout_ms) } + pub fn pending_reliable_packet_count(&self) -> usize { + self.session.pending_reliable_sequences().len() + } + + pub fn outstanding_reliable_packet_count(&self) -> usize { + self.session.outstanding_reliable_packet_count() + } + + pub fn flush_reliable(&mut self, timeout: Duration) -> Result<()> { + let original_timeout = self.socket.read_timeout()?; + let poll_timeout = original_timeout + .map(|configured| configured.min(Duration::from_millis(10))) + .unwrap_or(Duration::from_millis(10)); + self.socket.set_read_timeout(Some(poll_timeout))?; + + let deadline = Instant::now() + timeout; + let mut preserved_frames = VecDeque::new(); + let result = (|| { + while self.outstanding_reliable_packet_count() > 0 { + if Instant::now() >= deadline { + return Err(anyhow!( + "RUDP reliable flush timed out with {} packets outstanding", + self.outstanding_reliable_packet_count() + )); + } + if let Some(frame) = self.receive_once()? { + preserved_frames.push_back(frame); + } + self.poll_resends()?; + } + Ok(()) + })(); + + preserved_frames.append(&mut self.delivered_frames); + self.delivered_frames = preserved_frames; + let restore = self.socket.set_read_timeout(original_timeout); + match (result, restore) { + (Err(error), _) => Err(error), + (Ok(()), Err(error)) => Err(error.into()), + (Ok(()), Ok(())) => Ok(()), + } + } + pub fn receive_once(&mut self) -> Result> { if let Some(frame) = self.delivered_frames.pop_front() { return Ok(Some(frame)); @@ -1524,6 +1632,9 @@ impl CultNetRudpSocketTransportConnection { if let Some(reply) = result.reply { self.send_packet(&reply)?; } + for ready in result.ready_to_send { + self.send_packet(&ready)?; + } if result.pong { self.pong_payloads.push_back(result.pong_payload); } diff --git a/packages/cultnet-rs/tests/cultnet.rs b/packages/cultnet-rs/tests/cultnet.rs index 6511fdbd..32e643d3 100644 --- a/packages/cultnet-rs/tests/cultnet.rs +++ b/packages/cultnet-rs/tests/cultnet.rs @@ -4,6 +4,7 @@ use chrono::Utc; use cultcache_rs::CultCache; use cultcache_rs::DatabaseEntry; use cultcache_rs::SingleFileMessagePackBackingStore; +use cultnet_rs::CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS; use cultnet_rs::CultMesh; use cultnet_rs::CultMeshAuthorityLease; use cultnet_rs::CultMeshPeerCard; @@ -60,6 +61,7 @@ use cultnet_rs::encode_frame; use cultnet_rs::encode_rudp_packet; use pretty_assertions::assert_eq; use std::cell::RefCell; +use std::collections::VecDeque; use std::net::UdpSocket; use std::rc::Rc; use std::sync::atomic::{AtomicBool, Ordering}; @@ -1248,6 +1250,136 @@ fn rudp_socket_transport_carries_fragmented_reliable_ordered_schema_frames() -> Ok(()) } +#[test] +fn rudp_session_advances_large_fragment_sets_through_a_bounded_reliable_window() -> Result<()> { + let connection_id = 0x1020_3042; + let mut sender = CultNetRudpSession::new(CultNetRudpSessionOptions { + connection_id, + initial_sequence: 1, + resend_delay_ms: 25, + max_pending_reliable_packets: None, + }); + let mut receiver = CultNetRudpSession::new(CultNetRudpSessionOptions { + connection_id, + initial_sequence: 100, + resend_delay_ms: 25, + max_pending_reliable_packets: None, + }); + for session in [&mut sender, &mut receiver] { + session.receive( + &CultNetRudpPacket { + packet_type: CultNetRudpPacketType::Accept, + connection_id, + sequence: 0, + ack: 0, + ack_mask: 0, + channel_id: "control".into(), + reliable: false, + ordered: false, + sequenced: false, + fragment_id: 0, + fragment_index: 0, + fragment_count: 0, + payload: Vec::new(), + }, + 0, + )?; + } + + let fragment_count = CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS + 17; + let payload = (0..fragment_count * 8) + .map(|index| (index % 251) as u8) + .collect::>(); + let initial = sender.send_many( + "schema", + payload.clone(), + CultNetRudpSendOptions { + reliable: true, + ordered: true, + now_ms: 1, + ..CultNetRudpSendOptions::default() + }, + Some(8), + )?; + assert_eq!(initial.len(), CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS); + assert_eq!(sender.pending_reliable_sequences().len(), initial.len()); + assert_eq!(sender.queued_reliable_packet_count(), 17); + + let mut wire = VecDeque::from(initial); + let mut delivered = Vec::new(); + while let Some(packet) = wire.pop_front() { + let received = receiver.receive(&packet, 2)?; + delivered.extend(received.delivered); + let acknowledged = sender.receive(&receiver.create_ack_for(packet.sequence), 3)?; + wire.extend(acknowledged.ready_to_send); + } + + assert_eq!(sender.outstanding_reliable_packet_count(), 0); + assert_eq!(delivered.len(), 1); + assert_eq!(delivered[0].payload, payload); + Ok(()) +} + +#[test] +fn rudp_socket_flush_waits_for_large_fragment_delivery() -> Result<()> { + let server_socket = bind_udp_socket()?; + let client_socket = bind_udp_socket()?; + let server_addr = server_socket.local_addr()?; + let connection_id = 0x1020_3043; + let mut server = + CultNetRudpSocketTransportConnection::new(CultNetRudpSocketTransportOptions { + runtime_id: "rust-rudp-window-server".into(), + socket: server_socket, + mode: CultNetRudpSocketMode::Server, + remote_addr: None, + connection_id, + initial_sequence: 100, + resend_delay_ms: 25, + transport_id: None, + max_payload_bytes: None, + max_fragment_bytes: Some(8), + max_pending_reliable_packets: None, + reconnect_policy: None, + })?; + let mut client = + CultNetRudpSocketTransportConnection::new(CultNetRudpSocketTransportOptions { + runtime_id: "rust-rudp-window-client".into(), + socket: client_socket, + mode: CultNetRudpSocketMode::Client, + remote_addr: Some(server_addr), + connection_id, + initial_sequence: 1, + resend_delay_ms: 25, + transport_id: None, + max_payload_bytes: None, + max_fragment_bytes: Some(8), + max_pending_reliable_packets: None, + reconnect_policy: None, + })?; + client.connect(b"join".to_vec())?; + pump_rudp_handshake(&mut client, &mut server)?; + + let payload = vec![0x5a; (CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS + 17) * 8]; + client.send("schema", payload.clone())?; + assert_eq!( + client.pending_reliable_packet_count(), + CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS + ); + assert_eq!( + client.outstanding_reliable_packet_count(), + CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS + 17 + ); + + let server_worker = thread::spawn(move || receive_rudp_frame(&mut server)); + client.flush_reliable(StdDuration::from_secs(5))?; + let delivered = server_worker + .join() + .map_err(|_| anyhow::anyhow!("RUDP server worker panicked"))??; + assert_eq!(delivered.payload, payload); + assert_eq!(client.outstanding_reliable_packet_count(), 0); + Ok(()) +} + #[test] fn cultmesh_facade_creates_rudp_client_from_peer_endpoint() -> Result<()> { let connection_id = 0x2030_4050; diff --git a/packages/cultnet-ts/src/index.ts b/packages/cultnet-ts/src/index.ts index 64d9c2fd..731cafb5 100644 --- a/packages/cultnet-ts/src/index.ts +++ b/packages/cultnet-ts/src/index.ts @@ -83,6 +83,7 @@ export { createRudpTransportProfile, decodeRudpPacket, encodeRudpPacket, + CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS, CultNetRudpReconnectLoop, CultNetRudpSession, CultNetRudpSocketTransportConnection, diff --git a/packages/cultnet-ts/src/operation-service.ts b/packages/cultnet-ts/src/operation-service.ts index 362e4a06..0b6f6b31 100644 --- a/packages/cultnet-ts/src/operation-service.ts +++ b/packages/cultnet-ts/src/operation-service.ts @@ -145,6 +145,7 @@ async function handleServerDatagram( if (!peer) return; const result = peer.session.receive(packet, Date.now()); if (result.reply) sendPacket(remote, result.reply); + for (const ready of result.readyToSend ?? []) sendPacket(remote, ready); if (result.disconnected) { sessions.delete(key); return; diff --git a/packages/cultnet-ts/src/peer.ts b/packages/cultnet-ts/src/peer.ts index 816fcfd6..0e54ee58 100644 --- a/packages/cultnet-ts/src/peer.ts +++ b/packages/cultnet-ts/src/peer.ts @@ -106,6 +106,10 @@ export class CultNetPeer extends EventEmitter { this.#stream?.write(encodeFrame(payload)); } + async flush(timeoutMs?: number): Promise { + await this.#transport?.flush?.(timeoutMs); + } + sendHello(message: CultNetHelloMessage): void { this.send(message); } diff --git a/packages/cultnet-ts/src/rudp.ts b/packages/cultnet-ts/src/rudp.ts index 7a38cb1d..7a1a9e17 100644 --- a/packages/cultnet-ts/src/rudp.ts +++ b/packages/cultnet-ts/src/rudp.ts @@ -16,6 +16,8 @@ const RUDP_MAGIC = [0x43, 0x4e, 0x52, 0x30] as const; // CNR0 const RUDP_VERSION = 0; const RUDP_FIXED_HEADER_BYTES = 36; const MAX_CHANNEL_ID_BYTES = 255; +export const CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS = 64; +const RUDP_RECEIVED_SEQUENCE_WINDOW = 4_096; export type CultNetRudpPacketType = | "connect" @@ -57,6 +59,7 @@ export interface CultNetRudpSessionOptions { export interface CultNetRudpReceiveResult { delivered: CultNetRudpDeliveredFrame[]; + readyToSend?: CultNetRudpPacket[]; reply?: CultNetRudpPacket; pong?: boolean; pongPayload?: Uint8Array; @@ -151,6 +154,7 @@ export class CultNetRudpSession { #highestReceivedSequence: number | undefined; readonly #receivedSequences = new Set(); readonly #pendingReliable = new Map(); + readonly #queuedReliable: CultNetRudpPacket[] = []; readonly #orderedNextSequenceByChannel = new Map(); readonly #orderedBuffers = new Map>(); readonly #fragmentBuffers = new Map(); @@ -173,6 +177,14 @@ export class CultNetRudpSession { return [...this.#pendingReliable.keys()].sort((left, right) => left - right); } + get queuedReliablePacketCount(): number { + return this.#queuedReliable.length; + } + + get outstandingReliablePacketCount(): number { + return this.#pendingReliable.size + this.#queuedReliable.length; + } + get lastReceivedAtMs(): number | undefined { return this.#lastReceivedAtMs; } @@ -183,6 +195,7 @@ export class CultNetRudpSession { this.#highestReceivedSequence = undefined; this.#receivedSequences.clear(); this.#pendingReliable.clear(); + this.#queuedReliable.splice(0); this.#orderedNextSequenceByChannel.clear(); this.#orderedBuffers.clear(); this.#fragmentBuffers.clear(); @@ -238,6 +251,9 @@ export class CultNetRudpSession { payload: Uint8Array, options: { reliable?: boolean; ordered?: boolean; sequenced?: boolean; nowMs?: number } = {}, ): CultNetRudpPacket { + if (options.reliable && this.#pendingReliable.size >= CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS) { + throw new Error("RUDP reliable send window is full; receive acknowledgements before sending."); + } return this.sendMany(channelId, payload, options)[0]!; } @@ -271,10 +287,9 @@ export class CultNetRudpSession { ordered: options.ordered, sequenced: options.sequenced, }); - if (packet.reliable) { - this.#trackReliable(packet, options.nowMs ?? 0); - } - return [packet]; + return packet.reliable + ? this.#admitReliablePackets([packet], options.nowMs ?? 0) + : [packet]; } const fragmentCount = Math.ceil(payload.byteLength / maxFragmentBytes); @@ -298,17 +313,17 @@ export class CultNetRudpSession { fragmentIndex: index, fragmentCount, }); - if (packet.reliable) { - this.#trackReliable(packet, options.nowMs ?? 0); - } packets.push(packet); } - return packets; + return options.reliable + ? this.#admitReliablePackets(packets, options.nowMs ?? 0) + : packets; } receive(packet: CultNetRudpPacket, nowMs = 0): CultNetRudpReceiveResult { this.#requireConnection(packet); this.#applyAcknowledgements(packet); + const readyToSend = this.#promoteQueuedReliable(nowMs); this.#lastReceivedAtMs = nowMs; const expectedSequenceIfUninitialized = this.#highestReceivedSequence === undefined ? packet.sequence @@ -317,13 +332,14 @@ export class CultNetRudpSession { if (packet.packetType === "accept") { this.#rememberReceived(packet.sequence); this.#connected = true; - return { delivered: [] }; + return { delivered: [], readyToSend }; } if (packet.packetType === "ping") { this.#rememberReceived(packet.sequence); return { delivered: [], + readyToSend, reply: this.#createPacket({ packetType: "pong", channelId: "control", @@ -336,6 +352,7 @@ export class CultNetRudpSession { if (packet.packetType === "pong") this.#rememberReceived(packet.sequence); return { delivered: this.#drainUnblockedOrdered(), + readyToSend, pong: packet.packetType === "pong", pongPayload: packet.packetType === "pong" ? packet.payload ?? new Uint8Array() : undefined, }; @@ -346,31 +363,38 @@ export class CultNetRudpSession { this.#connected = false; return { delivered: [], + readyToSend, disconnected: true, disconnectReason: packet.payload ?? new Uint8Array(), }; } if (packet.packetType !== "data") { - return { delivered: [] }; + return { delivered: [], readyToSend }; } - const isDuplicate = this.#receivedSequences.has(packet.sequence); + const isDuplicate = this.#receivedSequences.has(packet.sequence) + || (this.#highestReceivedSequence !== undefined + && packet.sequence < this.#highestReceivedSequence + && this.#highestReceivedSequence - packet.sequence >= RUDP_RECEIVED_SEQUENCE_WINDOW); this.#rememberReceived(packet.sequence); if (isDuplicate) { - return { delivered: [] }; + return { delivered: [], readyToSend }; } const reassembled = this.#reassemble(packet); if (!reassembled) { - return { delivered: [] }; + return { delivered: [], readyToSend }; } if (!reassembled.ordered) { - return { delivered: [reassembled.frame] }; + return { delivered: [reassembled.frame], readyToSend }; } - return { delivered: this.#deliverOrdered(reassembled.frame, reassembled.nextSequence, expectedSequenceIfUninitialized) }; + return { + delivered: this.#deliverOrdered(reassembled.frame, reassembled.nextSequence, expectedSequenceIfUninitialized), + readyToSend, + }; } createAck(): CultNetRudpPacket { @@ -487,11 +511,26 @@ export class CultNetRudpSession { }); } + #admitReliablePackets(packets: CultNetRudpPacket[], nowMs: number): CultNetRudpPacket[] { + const available = Math.max(0, CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS - this.#pendingReliable.size); + const ready = packets.slice(0, available); + for (const packet of ready) this.#trackReliable(packet, nowMs); + this.#queuedReliable.push(...packets.slice(available)); + return ready; + } + + #promoteQueuedReliable(nowMs: number): CultNetRudpPacket[] { + const available = Math.max(0, CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS - this.#pendingReliable.size); + const ready = this.#queuedReliable.splice(0, available); + for (const packet of ready) this.#trackReliable(packet, nowMs); + return ready; + } + #ensureReliableCapacity(packetCount: number): void { if (packetCount === 0 || this.#maxPendingReliablePackets === undefined) { return; } - if (this.#pendingReliable.size + packetCount > this.#maxPendingReliablePackets) { + if (this.outstandingReliablePacketCount + packetCount > this.#maxPendingReliablePackets) { throw new Error("RUDP reliable send queue is full."); } } @@ -510,6 +549,12 @@ export class CultNetRudpSession { if (this.#highestReceivedSequence === undefined || sequence > this.#highestReceivedSequence) { this.#highestReceivedSequence = sequence; } + if (this.#receivedSequences.size > RUDP_RECEIVED_SEQUENCE_WINDOW) { + const keepFrom = Math.max(0, (this.#highestReceivedSequence ?? sequence) - RUDP_RECEIVED_SEQUENCE_WINDOW + 1); + for (const received of this.#receivedSequences) { + if (received < keepFrom) this.#receivedSequences.delete(received); + } + } } #ackState(): { ack: number; ackMask: number } { @@ -754,6 +799,10 @@ export class CultNetRudpSocketTransportConnection extends EventEmitter implement return { ...this.#stats }; } + get outstandingReliablePacketCount(): number { + return this.#session.outstandingReliablePacketCount; + } + connect(payload = new Uint8Array()): void { if (this.#mode !== "client") { throw new Error("Only a client RUDP socket transport can initiate connect."); @@ -773,6 +822,21 @@ export class CultNetRudpSocketTransportConnection extends EventEmitter implement this.#stats.framesSent += 1; } + async flush(timeoutMs = 30_000): Promise { + const deadline = Date.now() + Math.max(0, timeoutMs); + while (this.#session.outstandingReliablePacketCount > 0) { + if (this.#closed) { + throw new Error("RUDP transport closed before reliable packets were acknowledged."); + } + if (Date.now() >= deadline) { + throw new Error( + `RUDP reliable flush timed out with ${this.#session.outstandingReliablePacketCount} packets outstanding.`, + ); + } + await new Promise(resolve => setTimeout(resolve, 5)); + } + } + ping(payload = new Uint8Array()): void { this.#sendPacket(this.#session.createPing(payload)); } @@ -834,6 +898,9 @@ export class CultNetRudpSocketTransportConnection extends EventEmitter implement if (result.reply) { this.#sendPacket(result.reply); } + for (const ready of result.readyToSend ?? []) { + this.#sendPacket(ready); + } if (result.pong) { this.emit("pong", { payload: result.pongPayload ?? new Uint8Array() }); } diff --git a/packages/cultnet-ts/src/transport.ts b/packages/cultnet-ts/src/transport.ts index 53f64127..a1b9b3ce 100644 --- a/packages/cultnet-ts/src/transport.ts +++ b/packages/cultnet-ts/src/transport.ts @@ -131,6 +131,7 @@ export interface CultNetTransportConnection { readonly profile: CultNetTransportProfile; readonly stats: CultNetTransportStats; send(channelId: string, payload: Uint8Array): void; + flush?(timeoutMs?: number): Promise; close(): void; on( eventName: EventName, diff --git a/packages/cultnet-ts/test/cultnet.test.ts b/packages/cultnet-ts/test/cultnet.test.ts index 945e0a3b..621949aa 100644 --- a/packages/cultnet-ts/test/cultnet.test.ts +++ b/packages/cultnet-ts/test/cultnet.test.ts @@ -21,6 +21,7 @@ import { CultNetRudpReconnectLoop, CultNetRudpSession, CultNetRudpSocketTransportConnection, + CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS, CultNetSchemaCatalog, CultNetSchemaRegistry, CultNetSecret, @@ -1297,6 +1298,41 @@ test("operation envelopes preserve typed service routing and payload correlation assert.equal(response.messageId, request.messageId); }); +test("rudp session advances large fragment sets through a bounded reliable window", () => { + const connectionId = 457; + const sender = new CultNetRudpSession({ connectionId, initialSequence: 1, resendDelayMs: 25 }); + const receiver = new CultNetRudpSession({ connectionId, initialSequence: 100, resendDelayMs: 25 }); + sender.receive({ packetType: "accept", connectionId, sequence: 0, ack: 0, ackMask: 0, channelId: "control" }); + receiver.receive({ packetType: "accept", connectionId, sequence: 0, ack: 0, ackMask: 0, channelId: "control" }); + + const fragmentCount = CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS + 17; + const payload = Uint8Array.from( + { length: fragmentCount * 8 }, + (_, index) => index % 251, + ); + const wire = sender.sendMany("schema", payload, { + reliable: true, + ordered: true, + nowMs: 1, + maxFragmentBytes: 8, + }); + assert.equal(wire.length, CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS); + assert.equal(sender.pendingReliableSequences.length, wire.length); + assert.equal(sender.queuedReliablePacketCount, 17); + + const delivered = []; + while (wire.length > 0) { + const packet = wire.shift()!; + delivered.push(...receiver.receive(packet, 2).delivered); + const acknowledged = sender.receive(receiver.createAckFor(packet.sequence), 3); + wire.push(...(acknowledged.readyToSend ?? [])); + } + + assert.equal(sender.outstandingReliablePacketCount, 0); + assert.equal(delivered.length, 1); + assert.deepEqual(delivered[0]?.payload, payload); +}); + test("CultNet contracts encode legacy bytes without Node Buffer authority", () => { const originalBuffer = globalThis.Buffer; try { diff --git a/src/GameCult.Networking/CultNetTransport.cs b/src/GameCult.Networking/CultNetTransport.cs index fc72b2d4..b64399b0 100644 --- a/src/GameCult.Networking/CultNetTransport.cs +++ b/src/GameCult.Networking/CultNetTransport.cs @@ -723,6 +723,10 @@ namespace GameCult.Networking /// public IReadOnlyList Delivered { get; set; } = Array.Empty(); /// + /// Gets or sets queued reliable packets admitted by newly received acknowledgements. + /// + public IReadOnlyList ReadyToSend { get; set; } = Array.Empty(); + /// /// Gets or sets an optional immediate reply packet. /// public CultNetRudpPacket? Reply { get; set; } @@ -865,6 +869,9 @@ namespace GameCult.Networking /// public sealed class CultNetRudpSession { + /// Maximum reliable packets admitted to the wire before acknowledgements advance the window. + public const int ReliableSendWindowPackets = 64; + private const int ReceivedSequenceWindow = 4096; private sealed class PendingReliablePacket { public CultNetRudpPacket Packet { get; set; } = new CultNetRudpPacket(); @@ -895,6 +902,7 @@ namespace GameCult.Networking private readonly HashSet _receivedSequences = new HashSet(); private readonly object _pendingReliableGate = new object(); private readonly Dictionary _pendingReliable = new Dictionary(); + private readonly Queue _queuedReliable = new Queue(); private readonly Dictionary _orderedNextSequenceByChannel = new Dictionary(StringComparer.Ordinal); private readonly Dictionary> _orderedBuffers = new Dictionary>(StringComparer.Ordinal); @@ -947,6 +955,18 @@ namespace GameCult.Networking } } + /// Gets the number of reliable packets waiting for admission to the wire. + public int QueuedReliablePacketCount + { + get { lock (_pendingReliableGate) return _queuedReliable.Count; } + } + + /// Gets all reliable packets that have not yet been acknowledged. + public int OutstandingReliablePacketCount + { + get { lock (_pendingReliableGate) return _pendingReliable.Count + _queuedReliable.Count; } + } + /// /// Creates a reliable ordered connect packet. /// @@ -982,6 +1002,12 @@ namespace GameCult.Networking /// public CultNetRudpPacket Send(string channelId, byte[] payload, CultNetRudpSendOptions? options = null) { + options ??= new CultNetRudpSendOptions(); + lock (_pendingReliableGate) + { + if (options.Reliable && _pendingReliable.Count >= ReliableSendWindowPackets) + throw new InvalidOperationException("RUDP reliable send window is full; receive acknowledgements before sending."); + } return SendMany(channelId, payload, options).First(); } @@ -1029,13 +1055,11 @@ namespace GameCult.Networking fragmentId, (ushort)index, (ushort)fragmentCount); - if (fragmentPacket.Reliable) - { - TrackReliable(fragmentPacket, options.NowMs); - } packets.Add(fragmentPacket); } - return packets; + return options.Reliable + ? AdmitReliablePackets(packets, options.NowMs) + : packets; } EnsureReliableCapacity(options.Reliable ? 1 : 0); @@ -1048,7 +1072,7 @@ namespace GameCult.Networking options.Sequenced); if (packet.Reliable) { - TrackReliable(packet, options.NowMs); + return AdmitReliablePackets(new[] { packet }, options.NowMs); } return new[] { packet }; } @@ -1060,6 +1084,7 @@ namespace GameCult.Networking { RequireConnection(packet); ApplyAcknowledgements(packet); + var readyToSend = PromoteQueuedReliable(nowMs); _lastReceivedAtMs = nowMs; var expectedSequenceIfUninitialized = _highestReceivedSequence.HasValue ? _highestReceivedSequence.Value + 1 @@ -1069,7 +1094,7 @@ namespace GameCult.Networking { RememberReceived(packet.Sequence); _connected = true; - return new CultNetRudpReceiveResult(); + return new CultNetRudpReceiveResult { ReadyToSend = readyToSend }; } if (packet.PacketType == CultNetRudpPacketType.Ping) @@ -1077,6 +1102,7 @@ namespace GameCult.Networking RememberReceived(packet.Sequence); return new CultNetRudpReceiveResult { + ReadyToSend = readyToSend, Reply = CreatePacket( CultNetRudpPacketType.Pong, "control", @@ -1094,6 +1120,7 @@ namespace GameCult.Networking return new CultNetRudpReceiveResult { Delivered = DrainUnblockedOrdered(), + ReadyToSend = readyToSend, Pong = packet.PacketType == CultNetRudpPacketType.Pong, PongPayload = packet.PacketType == CultNetRudpPacketType.Pong ? packet.Payload ?? Array.Empty() @@ -1107,6 +1134,7 @@ namespace GameCult.Networking _connected = false; return new CultNetRudpReceiveResult { + ReadyToSend = readyToSend, Disconnected = true, DisconnectReason = packet.Payload ?? Array.Empty() }; @@ -1114,24 +1142,28 @@ namespace GameCult.Networking if (packet.PacketType != CultNetRudpPacketType.Data) { - return new CultNetRudpReceiveResult(); + return new CultNetRudpReceiveResult { ReadyToSend = readyToSend }; } - var duplicate = _receivedSequences.Contains(packet.Sequence); + var duplicate = _receivedSequences.Contains(packet.Sequence) + || (_highestReceivedSequence.HasValue + && packet.Sequence < _highestReceivedSequence.Value + && _highestReceivedSequence.Value - packet.Sequence >= ReceivedSequenceWindow); RememberReceived(packet.Sequence); if (duplicate) { - return new CultNetRudpReceiveResult(); + return new CultNetRudpReceiveResult { ReadyToSend = readyToSend }; } var reassembled = Reassemble(packet); if (reassembled == null) { - return new CultNetRudpReceiveResult(); + return new CultNetRudpReceiveResult { ReadyToSend = readyToSend }; } return new CultNetRudpReceiveResult { + ReadyToSend = readyToSend, Delivered = reassembled.Ordered ? DeliverOrdered(reassembled.Frame, reassembled.NextSequence, expectedSequenceIfUninitialized) : new[] { reassembled.Frame } @@ -1271,6 +1303,54 @@ namespace GameCult.Networking } } + private IReadOnlyList AdmitReliablePackets( + IReadOnlyList packets, + long nowMs) + { + lock (_pendingReliableGate) + { + var available = Math.Max(0, ReliableSendWindowPackets - _pendingReliable.Count); + var ready = new List(Math.Min(available, packets.Count)); + foreach (var packet in packets) + { + if (ready.Count < available) + { + _pendingReliable[packet.Sequence] = new PendingReliablePacket + { + Packet = ClonePacket(packet), + LastSentAtMs = nowMs + }; + ready.Add(packet); + } + else + { + _queuedReliable.Enqueue(ClonePacket(packet)); + } + } + return ready; + } + } + + private IReadOnlyList PromoteQueuedReliable(long nowMs) + { + lock (_pendingReliableGate) + { + var available = Math.Max(0, ReliableSendWindowPackets - _pendingReliable.Count); + var ready = new List(Math.Min(available, _queuedReliable.Count)); + while (ready.Count < available && _queuedReliable.Count > 0) + { + var packet = _queuedReliable.Dequeue(); + _pendingReliable[packet.Sequence] = new PendingReliablePacket + { + Packet = ClonePacket(packet), + LastSentAtMs = nowMs + }; + ready.Add(packet); + } + return ready; + } + } + private void EnsureReliableCapacity(int packetCount) { if (packetCount == 0 || !_maxPendingReliablePackets.HasValue) @@ -1280,7 +1360,7 @@ namespace GameCult.Networking lock (_pendingReliableGate) { - if (_pendingReliable.Count + packetCount > _maxPendingReliablePackets.Value) + if (_pendingReliable.Count + _queuedReliable.Count + packetCount > _maxPendingReliablePackets.Value) { throw new InvalidOperationException("RUDP reliable send queue is full."); } @@ -1309,6 +1389,13 @@ namespace GameCult.Networking { _highestReceivedSequence = sequence; } + if (_receivedSequences.Count > ReceivedSequenceWindow) + { + var keepFrom = (_highestReceivedSequence ?? sequence) >= ReceivedSequenceWindow - 1 + ? (_highestReceivedSequence ?? sequence) - (uint)(ReceivedSequenceWindow - 1) + : 0; + _receivedSequences.RemoveWhere(received => received < keepFrom); + } } private (uint Ack, uint AckMask) AckState() @@ -1698,6 +1785,46 @@ namespace GameCult.Networking _stats.FramesSent++; } + /// + /// Pumps acknowledgements and resends until every queued reliable packet is acknowledged. + /// + public void FlushReliable(TimeSpan? timeout = null) + { + var deadline = DateTimeOffset.UtcNow.Add(timeout ?? TimeSpan.FromSeconds(30)); + var preserved = new List(); + while (_deliveredFrames.Count > 0) + preserved.Add(_deliveredFrames.Dequeue()); + try + { + while (true) + { + lock (_sessionGate) + { + if (_session.OutstandingReliablePacketCount == 0) + return; + } + if (DateTimeOffset.UtcNow >= deadline) + { + int outstanding; + lock (_sessionGate) + outstanding = _session.OutstandingReliablePacketCount; + throw new TimeoutException($"RUDP reliable flush timed out with {outstanding} packets outstanding."); + } + if (TryReceiveOnce(out var delivered) && delivered != null) + preserved.Add(delivered); + PollResends(); + Thread.Sleep(5); + } + } + finally + { + while (_deliveredFrames.Count > 0) + preserved.Add(_deliveredFrames.Dequeue()); + foreach (var frame in preserved) + _deliveredFrames.Enqueue(frame); + } + } + /// /// Sends a reliable ordered schema-channel payload. /// @@ -1947,6 +2074,7 @@ namespace GameCult.Networking result = _session.Receive(packet, NowMs()); if (result.Reply != null) SendPacket(result.Reply); + SendPackets(result.ReadyToSend); if (packet.PacketType == CultNetRudpPacketType.Accept || packet.PacketType == CultNetRudpPacketType.Data) acknowledgement = _session.CreateAck(packet.Sequence); @@ -2126,7 +2254,7 @@ namespace GameCult.Networking /// /// Gets the number of reliable packets still awaiting acknowledgement. /// - public int PendingReliablePacketCount { get { lock (SessionGate) return Session.PendingReliableSequences.Count; } } + public int PendingReliablePacketCount { get { lock (SessionGate) return Session.OutstandingReliablePacketCount; } } /// /// Gets the last transport-level remote disconnect reason, if one was received. /// @@ -2356,6 +2484,7 @@ namespace GameCult.Networking result = existingPeer.Session.Receive(packet, NowMs()); if (result.Reply != null) SendPacket(existingPeer.RemoteEndPoint, result.Reply); + SendPackets(existingPeer, result.ReadyToSend); if (packet.PacketType == CultNetRudpPacketType.Data) acknowledgement = existingPeer.Session.CreateAck(packet.Sequence); } diff --git a/tests/GameCult.Networking.Tests/NetworkingTests.cs b/tests/GameCult.Networking.Tests/NetworkingTests.cs index dd4a63c9..12d397f0 100644 --- a/tests/GameCult.Networking.Tests/NetworkingTests.cs +++ b/tests/GameCult.Networking.Tests/NetworkingTests.cs @@ -1063,6 +1063,51 @@ namespace GameCult.Networking.Tests Assert.That(delivered[0].Sequence, Is.EqualTo(packets[0].Sequence)); } + [Test] + public void RudpSession_AdvancesLargeFragmentSetsThroughBoundedReliableWindow() + { + const uint connectionId = 457; + var sender = new CultNetRudpSession(new CultNetRudpSessionOptions + { + ConnectionId = connectionId, + InitialSequence = 1, + ResendDelayMs = 25 + }); + var receiver = new CultNetRudpSession(new CultNetRudpSessionOptions + { + ConnectionId = connectionId, + InitialSequence = 100, + ResendDelayMs = 25 + }); + sender.Receive(new CultNetRudpPacket { PacketType = CultNetRudpPacketType.Accept, ConnectionId = connectionId, Sequence = 0, ChannelId = "control" }); + receiver.Receive(new CultNetRudpPacket { PacketType = CultNetRudpPacketType.Accept, ConnectionId = connectionId, Sequence = 0, ChannelId = "control" }); + + var fragmentCount = CultNetRudpSession.ReliableSendWindowPackets + 17; + var payload = Enumerable.Range(0, fragmentCount * 8).Select(index => (byte)(index % 251)).ToArray(); + var wire = new Queue(sender.SendMany( + "schema", + payload, + new CultNetRudpSendOptions { Reliable = true, Ordered = true, NowMs = 1 }, + maxFragmentBytes: 8)); + Assert.That(wire, Has.Count.EqualTo(CultNetRudpSession.ReliableSendWindowPackets)); + Assert.That(sender.PendingReliableSequences, Has.Count.EqualTo(wire.Count)); + Assert.That(sender.QueuedReliablePacketCount, Is.EqualTo(17)); + + var delivered = new List(); + while (wire.Count > 0) + { + var packet = wire.Dequeue(); + delivered.AddRange(receiver.Receive(packet, 2).Delivered); + var acknowledged = sender.Receive(receiver.CreateAck(packet.Sequence), 3); + foreach (var ready in acknowledged.ReadyToSend) + wire.Enqueue(ready); + } + + Assert.That(sender.OutstandingReliablePacketCount, Is.Zero); + Assert.That(delivered, Has.Count.EqualTo(1)); + Assert.That(delivered[0].Payload, Is.EqualTo(payload)); + } + [Test] public void RudpSocketTransport_HandshakesAndCarriesReliableOrderedSchemaFrames() { From 21ce4f0ec6eb08ad18681f5632a7f937d46f6a81 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 23 Aug 2026 18:42:07 +0200 Subject: [PATCH 115/283] Repair CultNet interop workflow setup --- .github/workflows/cultnet-interop.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/cultnet-interop.yml b/.github/workflows/cultnet-interop.yml index 1bde67ef..19970a5a 100644 --- a/.github/workflows/cultnet-interop.yml +++ b/.github/workflows/cultnet-interop.yml @@ -33,10 +33,6 @@ jobs: uses: actions/setup-node@v4 with: node-version: 24 - cache: npm - cache-dependency-path: | - packages/cultcache-ts/package-lock.json - packages/cultnet-ts/package-lock.json - name: Set up Python uses: actions/setup-python@v5 From 289b792284c422b4b23cdfb2b9b4d57ae13ec1be Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 23 Aug 2026 18:43:17 +0200 Subject: [PATCH 116/283] Exercise RUDP reliability in fleet CI --- .github/workflows/cultnet-interop.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/cultnet-interop.yml b/.github/workflows/cultnet-interop.yml index 19970a5a..33699446 100644 --- a/.github/workflows/cultnet-interop.yml +++ b/.github/workflows/cultnet-interop.yml @@ -83,6 +83,18 @@ jobs: npm run build --workspace packages/cultnet-ts npx tsc -p packages/cultnet-ts/tsconfig.test.json --pretty false + - name: Verify TypeScript RUDP reliability + run: npm test --workspace packages/cultnet-ts + + - name: Verify Python RUDP reliability + run: python -m unittest packages/cultcache-py/tests/test_cultcache.py + + - name: Verify Rust RUDP reliability + run: cargo test --manifest-path packages/cultnet-rs/Cargo.toml rudp + + - name: Verify C# RUDP reliability + run: dotnet test tests/GameCult.Networking.Tests/GameCult.Networking.Tests.csproj --filter "FullyQualifiedName~Rudp" + - name: Interop RUDP Python lane timeout-minutes: 8 run: node --test --test-name-pattern "TypeScript and Python|Python and TypeScript" packages/cultnet-ts/dist-test/test/interop/cultnet-interop.test.js From b7949d31f206ce4061460f264e09f4be809fb70b Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 23 Aug 2026 18:46:35 +0200 Subject: [PATCH 117/283] Tolerate UDP reset advisories during RUDP polling --- packages/cultnet-rs/src/rudp.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/cultnet-rs/src/rudp.rs b/packages/cultnet-rs/src/rudp.rs index 7cae0b28..f14bf648 100644 --- a/packages/cultnet-rs/src/rudp.rs +++ b/packages/cultnet-rs/src/rudp.rs @@ -1265,7 +1265,9 @@ impl CultNetRudpServerHub { let (received, remote_addr) = match self.socket.recv_from(&mut wire) { Ok(value) => value, Err(error) - if error.kind() == ErrorKind::WouldBlock || error.kind() == ErrorKind::TimedOut => + if error.kind() == ErrorKind::WouldBlock + || error.kind() == ErrorKind::TimedOut + || error.kind() == ErrorKind::ConnectionReset => { return Ok(None); } @@ -1591,7 +1593,9 @@ impl CultNetRudpSocketTransportConnection { let (received, remote_addr) = match self.socket.recv_from(&mut wire) { Ok(value) => value, Err(error) - if error.kind() == ErrorKind::WouldBlock || error.kind() == ErrorKind::TimedOut => + if error.kind() == ErrorKind::WouldBlock + || error.kind() == ErrorKind::TimedOut + || error.kind() == ErrorKind::ConnectionReset => { return Ok(None); } From a2e3d3fa35acb47592a4a5c4fcaee1eda0c602fb Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 23 Aug 2026 18:54:18 +0200 Subject: [PATCH 118/283] Bind reliable windows to the RUDP ACK horizon --- docs/cultnet-transport-parity.md | 2 +- packages/cultcache-py/src/cultnet_py/transport.py | 2 +- .../src/main/kotlin/org/gamecult/cultmesh/CultMesh.kt | 2 +- packages/cultnet-rs/src/rudp.rs | 2 +- packages/cultnet-rs/tests/cultnet.rs | 11 ++++++++++- packages/cultnet-ts/src/rudp.ts | 2 +- src/GameCult.Networking/CultNetTransport.cs | 2 +- 7 files changed, 16 insertions(+), 7 deletions(-) diff --git a/docs/cultnet-transport-parity.md b/docs/cultnet-transport-parity.md index e9fd0ef8..35e33400 100644 --- a/docs/cultnet-transport-parity.md +++ b/docs/cultnet-transport-parity.md @@ -258,7 +258,7 @@ Current progress: echo against C#/Kotlin/Python/Rust UDP peers; local runtime tests prove timeout state transitions. - TypeScript, C#, Rust, Python, and Kotlin now share bounded reliable-send - backpressure for RUDP sessions. At most 64 reliable packets are admitted to + backpressure for RUDP sessions. At most 32 reliable packets are admitted to the wire at once; later fragments remain in a session-owned FIFO and exact acknowledgements promote the next packets. This keeps the send frontier well inside the 4,096-sequence receive history instead of blasting an entire large diff --git a/packages/cultcache-py/src/cultnet_py/transport.py b/packages/cultcache-py/src/cultnet_py/transport.py index ca877a2a..70af8f48 100644 --- a/packages/cultcache-py/src/cultnet_py/transport.py +++ b/packages/cultcache-py/src/cultnet_py/transport.py @@ -396,7 +396,7 @@ def create_rudp_transport_profile( class CultNetRudpSession: - RELIABLE_SEND_WINDOW_PACKETS = 64 + RELIABLE_SEND_WINDOW_PACKETS = 32 RECEIVED_SEQUENCE_WINDOW = 4_096 def __init__(self, options: CultNetRudpSessionOptions) -> None: diff --git a/packages/cultmesh-kotlin/src/main/kotlin/org/gamecult/cultmesh/CultMesh.kt b/packages/cultmesh-kotlin/src/main/kotlin/org/gamecult/cultmesh/CultMesh.kt index a7f90610..bd0f269f 100644 --- a/packages/cultmesh-kotlin/src/main/kotlin/org/gamecult/cultmesh/CultMesh.kt +++ b/packages/cultmesh-kotlin/src/main/kotlin/org/gamecult/cultmesh/CultMesh.kt @@ -2621,7 +2621,7 @@ private data class FragmentBuffer( class CultNetRudpSession(options: CultNetRudpSessionOptions) { companion object { - const val ReliableSendWindowPackets = 64 + const val ReliableSendWindowPackets = 32 private const val ReceivedSequenceWindow = 4_096 } diff --git a/packages/cultnet-rs/src/rudp.rs b/packages/cultnet-rs/src/rudp.rs index f14bf648..f84d8cae 100644 --- a/packages/cultnet-rs/src/rudp.rs +++ b/packages/cultnet-rs/src/rudp.rs @@ -29,7 +29,7 @@ const RUDP_MAGIC: [u8; 4] = [0x43, 0x4e, 0x52, 0x30]; const RUDP_VERSION: u8 = 0; const RUDP_FIXED_HEADER_BYTES: usize = 36; pub const CULTNET_RUDP_DEFAULT_MAX_PAYLOAD_BYTES: usize = 16 * 1024 * 1024; -pub const CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS: usize = 64; +pub const CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS: usize = 32; const RUDP_RECEIVED_SEQUENCE_WINDOW: usize = 4_096; #[derive(Clone, Copy, Debug, PartialEq, Eq)] diff --git a/packages/cultnet-rs/tests/cultnet.rs b/packages/cultnet-rs/tests/cultnet.rs index 32e643d3..1669fd0e 100644 --- a/packages/cultnet-rs/tests/cultnet.rs +++ b/packages/cultnet-rs/tests/cultnet.rs @@ -68,6 +68,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Mutex}; use std::thread; use std::time::Duration as StdDuration; +use std::time::Instant as StdInstant; const TS_HELLO_FRAME: &[u8] = include_bytes!("fixtures/cultnet-ts-hello.frame"); const TS_LEGACY_LOGIN_FRAME: &[u8] = include_bytes!("fixtures/cultnet-ts-legacy-login.frame"); @@ -1370,7 +1371,15 @@ fn rudp_socket_flush_waits_for_large_fragment_delivery() -> Result<()> { CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS + 17 ); - let server_worker = thread::spawn(move || receive_rudp_frame(&mut server)); + let server_worker = thread::spawn(move || -> Result { + let delivered = receive_rudp_frame(&mut server)?; + let linger_deadline = StdInstant::now() + StdDuration::from_millis(250); + while StdInstant::now() < linger_deadline { + let _ = server.receive_once()?; + server.poll_resends()?; + } + Ok(delivered) + }); client.flush_reliable(StdDuration::from_secs(5))?; let delivered = server_worker .join() diff --git a/packages/cultnet-ts/src/rudp.ts b/packages/cultnet-ts/src/rudp.ts index 7a1a9e17..6c69d1df 100644 --- a/packages/cultnet-ts/src/rudp.ts +++ b/packages/cultnet-ts/src/rudp.ts @@ -16,7 +16,7 @@ const RUDP_MAGIC = [0x43, 0x4e, 0x52, 0x30] as const; // CNR0 const RUDP_VERSION = 0; const RUDP_FIXED_HEADER_BYTES = 36; const MAX_CHANNEL_ID_BYTES = 255; -export const CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS = 64; +export const CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS = 32; const RUDP_RECEIVED_SEQUENCE_WINDOW = 4_096; export type CultNetRudpPacketType = diff --git a/src/GameCult.Networking/CultNetTransport.cs b/src/GameCult.Networking/CultNetTransport.cs index b64399b0..e65eb966 100644 --- a/src/GameCult.Networking/CultNetTransport.cs +++ b/src/GameCult.Networking/CultNetTransport.cs @@ -870,7 +870,7 @@ namespace GameCult.Networking public sealed class CultNetRudpSession { /// Maximum reliable packets admitted to the wire before acknowledgements advance the window. - public const int ReliableSendWindowPackets = 64; + public const int ReliableSendWindowPackets = 32; private const int ReceivedSequenceWindow = 4096; private sealed class PendingReliablePacket { From fda51fad50bee39106915fd37c842413f46efc7a Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 23 Aug 2026 19:00:33 +0200 Subject: [PATCH 119/283] Acknowledge reliable RUDP windows cumulatively --- .../cultcache-py/src/cultmesh_py/server.py | 2 +- .../src/cultnet_py/interop_peer.py | 2 +- .../cultcache-py/src/cultnet_py/transport.py | 13 ++++++++-- packages/cultcache-py/tests/test_cultcache.py | 8 ++++--- .../kotlin/org/gamecult/cultmesh/CultMesh.kt | 24 ++++++++++++++----- packages/cultnet-rs/src/rudp.rs | 6 ++--- packages/cultnet-rs/tests/cultnet.rs | 12 ++++++---- packages/cultnet-ts/test/cultnet.test.ts | 9 ++++--- src/GameCult.Networking/CultNetTransport.cs | 4 ++-- .../NetworkingTests.cs | 7 +++--- 10 files changed, 59 insertions(+), 28 deletions(-) diff --git a/packages/cultcache-py/src/cultmesh_py/server.py b/packages/cultcache-py/src/cultmesh_py/server.py index 0de99729..8d6653af 100644 --- a/packages/cultcache-py/src/cultmesh_py/server.py +++ b/packages/cultcache-py/src/cultmesh_py/server.py @@ -268,7 +268,7 @@ class CultMeshLocalServer: msgpack.packb(response, use_bin_type=True), ) if packet.reliable or packet.packet_type == CultNetRudpPacketType.DATA or result.delivered: - self._send_rudp_packet(rudp_socket, remote_addr, peer.session.create_ack_for(packet.sequence)) + self._send_rudp_packet(rudp_socket, remote_addr, peer.session.create_ack()) def _poll_rudp_resends( self, diff --git a/packages/cultcache-py/src/cultnet_py/interop_peer.py b/packages/cultcache-py/src/cultnet_py/interop_peer.py index 98fcf219..2fe62b60 100644 --- a/packages/cultcache-py/src/cultnet_py/interop_peer.py +++ b/packages/cultcache-py/src/cultnet_py/interop_peer.py @@ -320,7 +320,7 @@ def rudp_loop( for response in handle_server_message(state, message, peer.subscriptions): send_rudp_schema_frame(sock, remote, peer.session, response) if packet.reliable or packet.packet_type == CultNetRudpPacketType.DATA or result.delivered: - send_rudp_packet(sock, remote, peer.session.create_ack_for(packet.sequence)) + send_rudp_packet(sock, remote, peer.session.create_ack()) except Exception as error: sys.stderr.write(json.dumps({ "event": "rudpMessageError", diff --git a/packages/cultcache-py/src/cultnet_py/transport.py b/packages/cultcache-py/src/cultnet_py/transport.py index 70af8f48..2a83a218 100644 --- a/packages/cultcache-py/src/cultnet_py/transport.py +++ b/packages/cultcache-py/src/cultnet_py/transport.py @@ -599,7 +599,16 @@ class CultNetRudpSession: ) def create_ack(self) -> CultNetRudpPacket: - return self._create_packet(CultNetRudpPacketType.ACK, "control", b"") + ack, ack_mask = self._ack_state() + return CultNetRudpPacket( + packet_type=CultNetRudpPacketType.ACK, + connection_id=self.connection_id, + sequence=0, + ack=ack, + ack_mask=ack_mask, + channel_id="control", + payload=b"", + ) def create_ack_for(self, sequence: int) -> CultNetRudpPacket: return CultNetRudpPacket( @@ -955,7 +964,7 @@ class CultNetRudpSocketTransportConnection: frame = self._delivered_frames.popleft() if self._delivered_frames else None if packet.reliable or packet.packet_type == CultNetRudpPacketType.ACCEPT or frame is not None: - self._send_packet(self.session.create_ack_for(packet.sequence)) + self._send_packet(self.session.create_ack()) return frame def receive(self, timeout_seconds: float | None = None) -> CultNetTransportFrame: diff --git a/packages/cultcache-py/tests/test_cultcache.py b/packages/cultcache-py/tests/test_cultcache.py index c6dedd65..e6896f47 100644 --- a/packages/cultcache-py/tests/test_cultcache.py +++ b/packages/cultcache-py/tests/test_cultcache.py @@ -1178,9 +1178,11 @@ class CultCacheTests(unittest.TestCase): delivered = [] while wire: - packet = wire.pop(0) - delivered.extend(receiver.receive(packet, 2).delivered) - acknowledged = sender.receive(receiver.create_ack_for(packet.sequence), 3) + admitted = len(wire) + for _ in range(admitted): + packet = wire.pop(0) + delivered.extend(receiver.receive(packet, 2).delivered) + acknowledged = sender.receive(receiver.create_ack(), 3) wire.extend(acknowledged.ready_to_send) self.assertEqual(sender.outstanding_reliable_packet_count, 0) diff --git a/packages/cultmesh-kotlin/src/main/kotlin/org/gamecult/cultmesh/CultMesh.kt b/packages/cultmesh-kotlin/src/main/kotlin/org/gamecult/cultmesh/CultMesh.kt index bd0f269f..0c84cfa9 100644 --- a/packages/cultmesh-kotlin/src/main/kotlin/org/gamecult/cultmesh/CultMesh.kt +++ b/packages/cultmesh-kotlin/src/main/kotlin/org/gamecult/cultmesh/CultMesh.kt @@ -2764,7 +2764,17 @@ class CultNetRudpSession(options: CultNetRudpSessionOptions) { ) } - fun createAck(): CultNetRudpPacket = createPacket(CultNetRudpPacketType.Ack, "control", ByteArray(0)) + fun createAck(): CultNetRudpPacket { + val (ack, ackMask) = ackState() + return CultNetRudpPacket( + packetType = CultNetRudpPacketType.Ack, + connectionId = connectionId, + sequence = 0, + ack = ack, + ackMask = ackMask, + channelId = "control", + ) + } fun createAckFor(sequence: Long): CultNetRudpPacket = CultNetRudpPacket( packetType = CultNetRudpPacketType.Ack, @@ -3205,7 +3215,7 @@ class CultNetRudpSocketTransportConnection( framesReceived += 1 } val frame = if (delivered.isEmpty()) null else delivered.removeFirst() - if (packet.reliable || packet.packetType == CultNetRudpPacketType.Accept || frame != null) sendPacket(session.createAckFor(packet.sequence)) + if (packet.reliable || packet.packetType == CultNetRudpPacketType.Accept || frame != null) sendPacket(session.createAck()) return frame } @@ -3972,7 +3982,7 @@ private fun startInteropRudpServer( val result = session.receive(packet, nowMs()) result.reply?.let { sendInteropRudpPacket(socket, remote, it) } result.readyToSend.forEach { sendInteropRudpPacket(socket, remote, it) } - if (packet.reliable || packet.packetType == CultNetRudpPacketType.Data) sendInteropRudpPacket(socket, remote, session.createAckFor(packet.sequence)) + if (packet.reliable || packet.packetType == CultNetRudpPacketType.Data) sendInteropRudpPacket(socket, remote, session.createAck()) for (frame in result.delivered) { if (frame.channelId != "schema") continue val sender = InteropRudpSessionSender(socket, remote, session) @@ -5323,9 +5333,11 @@ private fun rudpSessionAdvancesLargeFragmentSetsThroughBoundedReliableWindow() { val delivered = mutableListOf() while (!wire.isEmpty()) { - val packet = wire.removeFirst() - delivered.addAll(receiver.receive(packet, 2).delivered) - val acknowledged = sender.receive(receiver.createAckFor(packet.sequence), 3) + val admitted = wire.size + repeat(admitted) { + delivered.addAll(receiver.receive(wire.removeFirst(), 2).delivered) + } + val acknowledged = sender.receive(receiver.createAck(), 3) acknowledged.readyToSend.forEach { wire.addLast(it) } } check(sender.outstandingReliablePacketCount == 0) diff --git a/packages/cultnet-rs/src/rudp.rs b/packages/cultnet-rs/src/rudp.rs index f84d8cae..a5c5107c 100644 --- a/packages/cultnet-rs/src/rudp.rs +++ b/packages/cultnet-rs/src/rudp.rs @@ -1288,7 +1288,7 @@ impl CultNetRudpServerHub { let reply = peer .session .pending_accept_for_resend(now_ms()) - .unwrap_or_else(|| peer.session.create_ack_for(packet.sequence)); + .unwrap_or_else(|| peer.session.create_ack()); self.send_packet(remote_addr, &reply)?; return Ok(None); } @@ -1340,7 +1340,7 @@ impl CultNetRudpServerHub { let result = peer.session.receive(&packet, now_ms())?; let context = peer.context.clone(); let ack = if packet.reliable { - Some(peer.session.create_ack_for(packet.sequence)) + Some(peer.session.create_ack()) } else { None }; @@ -1657,7 +1657,7 @@ impl CultNetRudpSocketTransportConnection { let frame = self.delivered_frames.pop_front(); if packet.reliable || packet.packet_type == CultNetRudpPacketType::Accept || frame.is_some() { - let ack = self.session.create_ack_for(packet.sequence); + let ack = self.session.create_ack(); self.send_packet(&ack)?; } Ok(frame) diff --git a/packages/cultnet-rs/tests/cultnet.rs b/packages/cultnet-rs/tests/cultnet.rs index 1669fd0e..8705cb4b 100644 --- a/packages/cultnet-rs/tests/cultnet.rs +++ b/packages/cultnet-rs/tests/cultnet.rs @@ -1308,10 +1308,14 @@ fn rudp_session_advances_large_fragment_sets_through_a_bounded_reliable_window() let mut wire = VecDeque::from(initial); let mut delivered = Vec::new(); - while let Some(packet) = wire.pop_front() { - let received = receiver.receive(&packet, 2)?; - delivered.extend(received.delivered); - let acknowledged = sender.receive(&receiver.create_ack_for(packet.sequence), 3)?; + while !wire.is_empty() { + let admitted = wire.len(); + for _ in 0..admitted { + let packet = wire.pop_front().expect("admitted packet remains queued"); + let received = receiver.receive(&packet, 2)?; + delivered.extend(received.delivered); + } + let acknowledged = sender.receive(&receiver.create_ack(), 3)?; wire.extend(acknowledged.ready_to_send); } diff --git a/packages/cultnet-ts/test/cultnet.test.ts b/packages/cultnet-ts/test/cultnet.test.ts index 621949aa..8b64a38e 100644 --- a/packages/cultnet-ts/test/cultnet.test.ts +++ b/packages/cultnet-ts/test/cultnet.test.ts @@ -1322,9 +1322,12 @@ test("rudp session advances large fragment sets through a bounded reliable windo const delivered = []; while (wire.length > 0) { - const packet = wire.shift()!; - delivered.push(...receiver.receive(packet, 2).delivered); - const acknowledged = sender.receive(receiver.createAckFor(packet.sequence), 3); + const admitted = wire.length; + for (let index = 0; index < admitted; index += 1) { + const packet = wire.shift()!; + delivered.push(...receiver.receive(packet, 2).delivered); + } + const acknowledged = sender.receive(receiver.createAck(), 3); wire.push(...(acknowledged.readyToSend ?? [])); } diff --git a/src/GameCult.Networking/CultNetTransport.cs b/src/GameCult.Networking/CultNetTransport.cs index e65eb966..f0e7f869 100644 --- a/src/GameCult.Networking/CultNetTransport.cs +++ b/src/GameCult.Networking/CultNetTransport.cs @@ -2077,7 +2077,7 @@ namespace GameCult.Networking SendPackets(result.ReadyToSend); if (packet.PacketType == CultNetRudpPacketType.Accept || packet.PacketType == CultNetRudpPacketType.Data) - acknowledgement = _session.CreateAck(packet.Sequence); + acknowledgement = _session.CreateAck(); } if (result.Pong) { @@ -2486,7 +2486,7 @@ namespace GameCult.Networking SendPacket(existingPeer.RemoteEndPoint, result.Reply); SendPackets(existingPeer, result.ReadyToSend); if (packet.PacketType == CultNetRudpPacketType.Data) - acknowledgement = existingPeer.Session.CreateAck(packet.Sequence); + acknowledgement = existingPeer.Session.CreateAck(); } if (result.Disconnected) { diff --git a/tests/GameCult.Networking.Tests/NetworkingTests.cs b/tests/GameCult.Networking.Tests/NetworkingTests.cs index 12d397f0..41bb2895 100644 --- a/tests/GameCult.Networking.Tests/NetworkingTests.cs +++ b/tests/GameCult.Networking.Tests/NetworkingTests.cs @@ -1096,9 +1096,10 @@ namespace GameCult.Networking.Tests var delivered = new List(); while (wire.Count > 0) { - var packet = wire.Dequeue(); - delivered.AddRange(receiver.Receive(packet, 2).Delivered); - var acknowledged = sender.Receive(receiver.CreateAck(packet.Sequence), 3); + var admitted = wire.Count; + for (var index = 0; index < admitted; index++) + delivered.AddRange(receiver.Receive(wire.Dequeue(), 2).Delivered); + var acknowledged = sender.Receive(receiver.CreateAck(), 3); foreach (var ready in acknowledged.ReadyToSend) wire.Enqueue(ready); } From ed273e6865c4ee4f4d4340e2dcd60439916c497b Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 23 Aug 2026 19:05:54 +0200 Subject: [PATCH 120/283] Keep large RUDP test receiver alive --- packages/cultnet-rs/tests/cultnet.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/cultnet-rs/tests/cultnet.rs b/packages/cultnet-rs/tests/cultnet.rs index 8705cb4b..ce291be2 100644 --- a/packages/cultnet-rs/tests/cultnet.rs +++ b/packages/cultnet-rs/tests/cultnet.rs @@ -1376,7 +1376,15 @@ fn rudp_socket_flush_waits_for_large_fragment_delivery() -> Result<()> { ); let server_worker = thread::spawn(move || -> Result { - let delivered = receive_rudp_frame(&mut server)?; + let delivery_deadline = StdInstant::now() + StdDuration::from_secs(5); + let delivered = loop { + if let Some(frame) = server.receive_once()? { + break frame; + } + if StdInstant::now() >= delivery_deadline { + anyhow::bail!("RUDP large socket frame was not delivered"); + } + }; let linger_deadline = StdInstant::now() + StdDuration::from_millis(250); while StdInstant::now() < linger_deadline { let _ = server.receive_once()?; From 75c180782aeba7cfd22d6412877397708a4ed28f Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 23 Aug 2026 19:15:22 +0200 Subject: [PATCH 121/283] Acknowledge retransmits across RUDP horizons --- docs/cultnet-transport-parity.md | 7 ++++-- .../cultcache-py/src/cultmesh_py/server.py | 6 ++++- .../src/cultnet_py/interop_peer.py | 2 +- .../cultcache-py/src/cultnet_py/transport.py | 9 +++++++- packages/cultcache-py/tests/test_cultcache.py | 4 ++++ .../kotlin/org/gamecult/cultmesh/CultMesh.kt | 22 +++++++++++++++++-- packages/cultnet-rs/src/rudp.rs | 13 +++++++++-- packages/cultnet-rs/tests/cultnet.rs | 4 ++++ packages/cultnet-ts/src/operation-service.ts | 4 +++- packages/cultnet-ts/src/rudp.ts | 10 ++++++++- packages/cultnet-ts/test/cultnet.test.ts | 4 ++++ src/GameCult.Networking/CultNetTransport.cs | 16 ++++++++++++-- .../NetworkingTests.cs | 20 +++++++++++------ 13 files changed, 101 insertions(+), 20 deletions(-) diff --git a/docs/cultnet-transport-parity.md b/docs/cultnet-transport-parity.md index 35e33400..aa962c46 100644 --- a/docs/cultnet-transport-parity.md +++ b/docs/cultnet-transport-parity.md @@ -259,8 +259,11 @@ Current progress: state transitions. - TypeScript, C#, Rust, Python, and Kotlin now share bounded reliable-send backpressure for RUDP sessions. At most 32 reliable packets are admitted to - the wire at once; later fragments remain in a session-owned FIFO and exact - acknowledgements promote the next packets. This keeps the send frontier well + the wire at once; later fragments remain in a session-owned FIFO and + acknowledgements promote the next packets. Receivers emit a cumulative ACK + for packets inside the 32-sequence ACK horizon and an exact ACK for an older + retransmit, so unrelated unreliable traffic cannot strand reliable work. + This keeps the send frontier well inside the 4,096-sequence receive history instead of blasting an entire large document and hoping the UDP buffers impersonate flow control. `maxPendingReliablePackets` bounds both queued and in-flight packets before a diff --git a/packages/cultcache-py/src/cultmesh_py/server.py b/packages/cultcache-py/src/cultmesh_py/server.py index 8d6653af..6f124480 100644 --- a/packages/cultcache-py/src/cultmesh_py/server.py +++ b/packages/cultcache-py/src/cultmesh_py/server.py @@ -268,7 +268,11 @@ class CultMeshLocalServer: msgpack.packb(response, use_bin_type=True), ) if packet.reliable or packet.packet_type == CultNetRudpPacketType.DATA or result.delivered: - self._send_rudp_packet(rudp_socket, remote_addr, peer.session.create_ack()) + self._send_rudp_packet( + rudp_socket, + remote_addr, + peer.session.create_ack_for_received(packet.sequence), + ) def _poll_rudp_resends( self, diff --git a/packages/cultcache-py/src/cultnet_py/interop_peer.py b/packages/cultcache-py/src/cultnet_py/interop_peer.py index 2fe62b60..7ee9995e 100644 --- a/packages/cultcache-py/src/cultnet_py/interop_peer.py +++ b/packages/cultcache-py/src/cultnet_py/interop_peer.py @@ -320,7 +320,7 @@ def rudp_loop( for response in handle_server_message(state, message, peer.subscriptions): send_rudp_schema_frame(sock, remote, peer.session, response) if packet.reliable or packet.packet_type == CultNetRudpPacketType.DATA or result.delivered: - send_rudp_packet(sock, remote, peer.session.create_ack()) + send_rudp_packet(sock, remote, peer.session.create_ack_for_received(packet.sequence)) except Exception as error: sys.stderr.write(json.dumps({ "event": "rudpMessageError", diff --git a/packages/cultcache-py/src/cultnet_py/transport.py b/packages/cultcache-py/src/cultnet_py/transport.py index 2a83a218..9ce4e4de 100644 --- a/packages/cultcache-py/src/cultnet_py/transport.py +++ b/packages/cultcache-py/src/cultnet_py/transport.py @@ -621,6 +621,13 @@ class CultNetRudpSession: payload=b"", ) + def create_ack_for_received(self, sequence: int) -> CultNetRudpPacket: + received_sequence = _uint32(sequence, "received sequence") + ack, _ = self._ack_state() + if ack >= received_sequence and ack - received_sequence <= 32: + return self.create_ack() + return self.create_ack_for(received_sequence) + def create_ping(self, payload: bytes = b"") -> CultNetRudpPacket: return self._create_packet(CultNetRudpPacketType.PING, "control", payload) @@ -964,7 +971,7 @@ class CultNetRudpSocketTransportConnection: frame = self._delivered_frames.popleft() if self._delivered_frames else None if packet.reliable or packet.packet_type == CultNetRudpPacketType.ACCEPT or frame is not None: - self._send_packet(self.session.create_ack()) + self._send_packet(self.session.create_ack_for_received(packet.sequence)) return frame def receive(self, timeout_seconds: float | None = None) -> CultNetTransportFrame: diff --git a/packages/cultcache-py/tests/test_cultcache.py b/packages/cultcache-py/tests/test_cultcache.py index e6896f47..2dbbeb2d 100644 --- a/packages/cultcache-py/tests/test_cultcache.py +++ b/packages/cultcache-py/tests/test_cultcache.py @@ -1173,6 +1173,7 @@ class CultCacheTests(unittest.TestCase): max_fragment_bytes=8, )) self.assertEqual(len(wire), CultNetRudpSession.RELIABLE_SEND_WINDOW_PACKETS) + oldest_sequence = wire[0].sequence self.assertEqual(len(sender.pending_reliable_sequences), len(wire)) self.assertEqual(sender.queued_reliable_packet_count, 17) @@ -1188,6 +1189,9 @@ class CultCacheTests(unittest.TestCase): self.assertEqual(sender.outstanding_reliable_packet_count, 0) self.assertEqual(len(delivered), 1) self.assertEqual(delivered[0].payload, payload) + old_ack = receiver.create_ack_for_received(oldest_sequence) + self.assertEqual(old_ack.ack, oldest_sequence) + self.assertEqual(old_ack.ack_mask, 0) def test_cultnet_rudp_socket_transport_handshakes_and_carries_reliable_ordered_schema_frames(self) -> None: server_socket = bind_udp_socket() diff --git a/packages/cultmesh-kotlin/src/main/kotlin/org/gamecult/cultmesh/CultMesh.kt b/packages/cultmesh-kotlin/src/main/kotlin/org/gamecult/cultmesh/CultMesh.kt index 0c84cfa9..6245fb9e 100644 --- a/packages/cultmesh-kotlin/src/main/kotlin/org/gamecult/cultmesh/CultMesh.kt +++ b/packages/cultmesh-kotlin/src/main/kotlin/org/gamecult/cultmesh/CultMesh.kt @@ -2785,6 +2785,16 @@ class CultNetRudpSession(options: CultNetRudpSessionOptions) { channelId = "control", ) + fun createAckForReceived(sequence: Long): CultNetRudpPacket { + val receivedSequence = uint32(sequence, "received sequence") + val (ack, _) = ackState() + return if (ack >= receivedSequence && ack - receivedSequence <= 32L) { + createAck() + } else { + createAckFor(receivedSequence) + } + } + fun createPing(payload: ByteArray = ByteArray(0)): CultNetRudpPacket = createPacket(CultNetRudpPacketType.Ping, "control", payload) @@ -3215,7 +3225,9 @@ class CultNetRudpSocketTransportConnection( framesReceived += 1 } val frame = if (delivered.isEmpty()) null else delivered.removeFirst() - if (packet.reliable || packet.packetType == CultNetRudpPacketType.Accept || frame != null) sendPacket(session.createAck()) + if (packet.reliable || packet.packetType == CultNetRudpPacketType.Accept || frame != null) { + sendPacket(session.createAckForReceived(packet.sequence)) + } return frame } @@ -3982,7 +3994,9 @@ private fun startInteropRudpServer( val result = session.receive(packet, nowMs()) result.reply?.let { sendInteropRudpPacket(socket, remote, it) } result.readyToSend.forEach { sendInteropRudpPacket(socket, remote, it) } - if (packet.reliable || packet.packetType == CultNetRudpPacketType.Data) sendInteropRudpPacket(socket, remote, session.createAck()) + if (packet.reliable || packet.packetType == CultNetRudpPacketType.Data) { + sendInteropRudpPacket(socket, remote, session.createAckForReceived(packet.sequence)) + } for (frame in result.delivered) { if (frame.channelId != "schema") continue val sender = InteropRudpSessionSender(socket, remote, session) @@ -5328,6 +5342,7 @@ private fun rudpSessionAdvancesLargeFragmentSetsThroughBoundedReliableWindow() { maxFragmentBytes = 8, )) check(wire.size == CultNetRudpSession.ReliableSendWindowPackets) + val oldestSequence = wire.first().sequence check(sender.pendingReliableSequences.size == wire.size) check(sender.queuedReliablePacketCount == 17) @@ -5343,6 +5358,9 @@ private fun rudpSessionAdvancesLargeFragmentSetsThroughBoundedReliableWindow() { check(sender.outstandingReliablePacketCount == 0) check(delivered.size == 1) check(delivered.first().payload.contentEquals(payload)) + val oldAck = receiver.createAckForReceived(oldestSequence) + check(oldAck.ack == oldestSequence) + check(oldAck.ackMask == 0L) } private fun rudpSocketTransportErgonomicFactoriesCarrySchemaFrames() { diff --git a/packages/cultnet-rs/src/rudp.rs b/packages/cultnet-rs/src/rudp.rs index a5c5107c..25382264 100644 --- a/packages/cultnet-rs/src/rudp.rs +++ b/packages/cultnet-rs/src/rudp.rs @@ -542,6 +542,15 @@ impl CultNetRudpSession { } } + pub fn create_ack_for_received(&mut self, sequence: u32) -> CultNetRudpPacket { + let (ack, _) = self.ack_state(); + if ack >= sequence && ack - sequence <= 32 { + self.create_ack() + } else { + self.create_ack_for(sequence) + } + } + pub fn create_ping(&mut self, payload: Vec) -> CultNetRudpPacket { self.create_packet( CultNetRudpPacketType::Ping, @@ -1340,7 +1349,7 @@ impl CultNetRudpServerHub { let result = peer.session.receive(&packet, now_ms())?; let context = peer.context.clone(); let ack = if packet.reliable { - Some(peer.session.create_ack()) + Some(peer.session.create_ack_for_received(packet.sequence)) } else { None }; @@ -1657,7 +1666,7 @@ impl CultNetRudpSocketTransportConnection { let frame = self.delivered_frames.pop_front(); if packet.reliable || packet.packet_type == CultNetRudpPacketType::Accept || frame.is_some() { - let ack = self.session.create_ack(); + let ack = self.session.create_ack_for_received(packet.sequence); self.send_packet(&ack)?; } Ok(frame) diff --git a/packages/cultnet-rs/tests/cultnet.rs b/packages/cultnet-rs/tests/cultnet.rs index ce291be2..a66411f0 100644 --- a/packages/cultnet-rs/tests/cultnet.rs +++ b/packages/cultnet-rs/tests/cultnet.rs @@ -1303,6 +1303,7 @@ fn rudp_session_advances_large_fragment_sets_through_a_bounded_reliable_window() Some(8), )?; assert_eq!(initial.len(), CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS); + let oldest_sequence = initial[0].sequence; assert_eq!(sender.pending_reliable_sequences().len(), initial.len()); assert_eq!(sender.queued_reliable_packet_count(), 17); @@ -1322,6 +1323,9 @@ fn rudp_session_advances_large_fragment_sets_through_a_bounded_reliable_window() assert_eq!(sender.outstanding_reliable_packet_count(), 0); assert_eq!(delivered.len(), 1); assert_eq!(delivered[0].payload, payload); + let old_ack = receiver.create_ack_for_received(oldest_sequence); + assert_eq!(old_ack.ack, oldest_sequence); + assert_eq!(old_ack.ack_mask, 0); Ok(()) } diff --git a/packages/cultnet-ts/src/operation-service.ts b/packages/cultnet-ts/src/operation-service.ts index 0b6f6b31..ee13457f 100644 --- a/packages/cultnet-ts/src/operation-service.ts +++ b/packages/cultnet-ts/src/operation-service.ts @@ -163,7 +163,9 @@ async function handleServerDatagram( maxFragmentBytes: options.maxFragmentBytes ?? 2048, })) sendPacket(remote, responsePacket); } - if (packet.packetType === "data" || result.delivered.length > 0) sendPacket(remote, peer.session.createAck()); + if (packet.packetType === "data" || result.delivered.length > 0) { + sendPacket(remote, peer.session.createAckForReceived(packet.sequence)); + } } function parseRudpEndpoint(endpoint: string): { host: string; port: number } { diff --git a/packages/cultnet-ts/src/rudp.ts b/packages/cultnet-ts/src/rudp.ts index 6c69d1df..51b5cc5b 100644 --- a/packages/cultnet-ts/src/rudp.ts +++ b/packages/cultnet-ts/src/rudp.ts @@ -434,6 +434,14 @@ export class CultNetRudpSession { }; } + createAckForReceived(sequence: number): CultNetRudpPacket { + const receivedSequence = toUint32(sequence, "received sequence"); + const { ack } = this.#ackState(); + return ack >= receivedSequence && ack - receivedSequence <= 32 + ? this.createAck() + : this.createAckFor(receivedSequence); + } + createPing(payload = new Uint8Array()): CultNetRudpPacket { return this.#createPacket({ packetType: "ping", @@ -917,7 +925,7 @@ export class CultNetRudpSocketTransportConnection extends EventEmitter implement return; } if (packet.packetType === "accept" || packet.packetType === "data" || result.delivered.length > 0) { - this.#sendPacket(this.#session.createAck()); + this.#sendPacket(this.#session.createAckForReceived(packet.sequence)); } } catch (error) { this.emit("error", error instanceof Error ? error : new Error(String(error))); diff --git a/packages/cultnet-ts/test/cultnet.test.ts b/packages/cultnet-ts/test/cultnet.test.ts index 8b64a38e..e213ef6f 100644 --- a/packages/cultnet-ts/test/cultnet.test.ts +++ b/packages/cultnet-ts/test/cultnet.test.ts @@ -1317,6 +1317,7 @@ test("rudp session advances large fragment sets through a bounded reliable windo maxFragmentBytes: 8, }); assert.equal(wire.length, CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS); + const oldestSequence = wire[0]!.sequence; assert.equal(sender.pendingReliableSequences.length, wire.length); assert.equal(sender.queuedReliablePacketCount, 17); @@ -1334,6 +1335,9 @@ test("rudp session advances large fragment sets through a bounded reliable windo assert.equal(sender.outstandingReliablePacketCount, 0); assert.equal(delivered.length, 1); assert.deepEqual(delivered[0]?.payload, payload); + const oldAck = receiver.createAckForReceived(oldestSequence); + assert.equal(oldAck.ack, oldestSequence); + assert.equal(oldAck.ackMask, 0); }); test("CultNet contracts encode legacy bytes without Node Buffer authority", () => { diff --git a/src/GameCult.Networking/CultNetTransport.cs b/src/GameCult.Networking/CultNetTransport.cs index f0e7f869..6e706fbc 100644 --- a/src/GameCult.Networking/CultNetTransport.cs +++ b/src/GameCult.Networking/CultNetTransport.cs @@ -1193,6 +1193,18 @@ namespace GameCult.Networking }; } + /// + /// Creates a cumulative acknowledgement when the received packet is inside the + /// acknowledgement horizon, or an exact acknowledgement for an older retransmit. + /// + public CultNetRudpPacket CreateAckForReceived(uint receivedSequence) + { + var (ack, _) = AckState(); + return ack >= receivedSequence && ack - receivedSequence <= 32 + ? CreateAck() + : CreateAck(receivedSequence); + } + /// /// Creates a packet carrying a keepalive ping payload. /// @@ -2077,7 +2089,7 @@ namespace GameCult.Networking SendPackets(result.ReadyToSend); if (packet.PacketType == CultNetRudpPacketType.Accept || packet.PacketType == CultNetRudpPacketType.Data) - acknowledgement = _session.CreateAck(); + acknowledgement = _session.CreateAckForReceived(packet.Sequence); } if (result.Pong) { @@ -2486,7 +2498,7 @@ namespace GameCult.Networking SendPacket(existingPeer.RemoteEndPoint, result.Reply); SendPackets(existingPeer, result.ReadyToSend); if (packet.PacketType == CultNetRudpPacketType.Data) - acknowledgement = existingPeer.Session.CreateAck(); + acknowledgement = existingPeer.Session.CreateAckForReceived(packet.Sequence); } if (result.Disconnected) { diff --git a/tests/GameCult.Networking.Tests/NetworkingTests.cs b/tests/GameCult.Networking.Tests/NetworkingTests.cs index 41bb2895..33aff57d 100644 --- a/tests/GameCult.Networking.Tests/NetworkingTests.cs +++ b/tests/GameCult.Networking.Tests/NetworkingTests.cs @@ -790,12 +790,15 @@ namespace GameCult.Networking.Tests receiver.Receive(new CultNetRudpPacket { PacketType = CultNetRudpPacketType.Accept, ConnectionId = 991, Sequence = 0, ChannelId = "control" }); - var packets = sender.SendMany( + var oldPacket = sender.Send( "snapshot", - Enumerable.Range(0, 80).Select(index => (byte)index).ToArray(), - new CultNetRudpSendOptions { Reliable = true, Ordered = true, NowMs = 0 }, - maxFragmentBytes: 1); - foreach (var packet in packets) + new byte[] { 1 }, + new CultNetRudpSendOptions { Reliable = true, Ordered = true, NowMs = 0 }); + receiver.Receive(oldPacket); + foreach (var packet in Enumerable.Range(0, 40).Select(index => sender.Send( + "activity", + new byte[] { (byte)index }, + new CultNetRudpSendOptions { Reliable = false, Ordered = false, NowMs = 0 }))) receiver.Receive(packet); sender.Receive(receiver.CreateAck()); @@ -803,7 +806,10 @@ namespace GameCult.Networking.Tests var oldRetransmit = sender.DueResends(10).Single(packet => packet.Sequence == 1); receiver.Receive(oldRetransmit); - sender.Receive(receiver.CreateAck(oldRetransmit.Sequence)); + var exactAck = receiver.CreateAckForReceived(oldRetransmit.Sequence); + Assert.That(exactAck.Ack, Is.EqualTo(oldRetransmit.Sequence)); + Assert.That(exactAck.AckMask, Is.Zero); + sender.Receive(exactAck); Assert.That(sender.PendingReliableSequences, Does.Not.Contain(1u)); } @@ -824,7 +830,7 @@ namespace GameCult.Networking.Tests Sequence = 5000, ChannelId = "control" }); - var packets = Enumerable.Range(0, 1000) + var packets = Enumerable.Range(0, CultNetRudpSession.ReliableSendWindowPackets) .Select(index => session.Send("schema", Encoding.UTF8.GetBytes(index.ToString()), new CultNetRudpSendOptions { Reliable = true, Ordered = true, NowMs = 0 })) .ToArray(); From 5b2c36329dbd74479c3ede5cdcec77c0d17ce534 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 26 Aug 2026 17:37:22 +0200 Subject: [PATCH 122/283] Add CultGeometry isosurface extraction --- .../CultGeometryIsoSurface.cs | 193 ++++++++++++++++++ .../GameCult.Geometry.csproj | 4 +- .../ISOSURFACE-PROVENANCE.md | 32 +++ src/GameCult.Geometry/README.md | 23 ++- .../GeometryDocumentTests.cs | 7 +- .../IsoSurfaceTests.cs | 89 ++++++++ 6 files changed, 337 insertions(+), 11 deletions(-) create mode 100644 src/GameCult.Geometry/CultGeometryIsoSurface.cs create mode 100644 src/GameCult.Geometry/ISOSURFACE-PROVENANCE.md create mode 100644 tests/GameCult.Geometry.Tests/IsoSurfaceTests.cs diff --git a/src/GameCult.Geometry/CultGeometryIsoSurface.cs b/src/GameCult.Geometry/CultGeometryIsoSurface.cs new file mode 100644 index 00000000..6fc9355c --- /dev/null +++ b/src/GameCult.Geometry/CultGeometryIsoSurface.cs @@ -0,0 +1,193 @@ +using System; +using System.Collections.Generic; +using CultMath; + +namespace GameCult.Geometry +{ + /// + /// Extracts engine-neutral triangle meshes from sampled scalar fields. + /// + public static class CultGeometryIsoSurface + { + private static readonly float3[] CubeCorners = + { + new(0f, 0f, 0f), + new(1f, 0f, 0f), + new(1f, 1f, 0f), + new(0f, 1f, 0f), + new(0f, 0f, 1f), + new(1f, 0f, 1f), + new(1f, 1f, 1f), + new(0f, 1f, 1f), + }; + + // A fixed six-tetrahedra decomposition keeps neighboring cube faces consistent. + private static readonly int[,] CubeTetrahedra = + { + { 0, 5, 1, 6 }, + { 0, 1, 2, 6 }, + { 0, 2, 3, 6 }, + { 0, 3, 7, 6 }, + { 0, 7, 4, 6 }, + { 0, 4, 5, 6 }, + }; + + /// + /// Extracts the surface with marching tetrahedra. + /// Values less than or equal to the isovalue are treated as inside. + /// + public static CultGeometryTriangleMesh Extract( + float[,,] samples, + float isoValue = 0f, + CultVec3 origin = default, + float cellSize = 1f) + { + if (samples == null) throw new ArgumentNullException(nameof(samples)); + if (samples.GetLength(0) < 2 || samples.GetLength(1) < 2 || samples.GetLength(2) < 2) + { + throw new ArgumentException("An isosurface field requires at least two samples on every axis.", nameof(samples)); + } + + if (!(cellSize > 0f) || float.IsInfinity(cellSize)) + { + throw new ArgumentOutOfRangeException(nameof(cellSize), "Cell size must be finite and positive."); + } + + var positions = new List(); + var normals = new List(); + var indices = new List(); + var originValue = new float3(origin.X, origin.Y, origin.Z); + var cornerPositions = new float3[8]; + var cornerValues = new float[8]; + var tetraPositions = new float3[4]; + var tetraValues = new float[4]; + + for (var x = 0; x < samples.GetLength(0) - 1; x++) + for (var y = 0; y < samples.GetLength(1) - 1; y++) + for (var z = 0; z < samples.GetLength(2) - 1; z++) + { + var cubeOrigin = originValue + new float3(x, y, z) * cellSize; + for (var corner = 0; corner < CubeCorners.Length; corner++) + { + var offset = CubeCorners[corner]; + cornerPositions[corner] = cubeOrigin + offset * cellSize; + cornerValues[corner] = samples[ + x + (int)offset.x, + y + (int)offset.y, + z + (int)offset.z]; + } + + for (var tetrahedron = 0; tetrahedron < CubeTetrahedra.GetLength(0); tetrahedron++) + { + for (var vertex = 0; vertex < 4; vertex++) + { + var corner = CubeTetrahedra[tetrahedron, vertex]; + tetraPositions[vertex] = cornerPositions[corner]; + tetraValues[vertex] = cornerValues[corner]; + } + + PolygonizeTetrahedron(tetraPositions, tetraValues, isoValue, positions, normals, indices); + } + } + + return new CultGeometryTriangleMesh + { + Positions = positions.ToArray(), + Normals = normals.ToArray(), + Indices = indices.ToArray(), + Uvs = Array.Empty(), + TriangleMaterials = new uint[indices.Count / 3], + }; + } + + private static void PolygonizeTetrahedron( + float3[] positions, + float[] values, + float isoValue, + List outputPositions, + List outputNormals, + List outputIndices) + { + Span inside = stackalloc int[4]; + Span outside = stackalloc int[4]; + var insideCount = 0; + var outsideCount = 0; + + for (var vertex = 0; vertex < 4; vertex++) + { + if (values[vertex] <= isoValue) inside[insideCount++] = vertex; + else outside[outsideCount++] = vertex; + } + + if (insideCount == 0 || insideCount == 4) return; + + var outward = Centroid(positions, outside, outsideCount) - Centroid(positions, inside, insideCount); + if (insideCount == 1 || outsideCount == 1) + { + var loneIsInside = insideCount == 1; + var lone = loneIsInside ? inside[0] : outside[0]; + var others = loneIsInside ? outside : inside; + var a = Interpolate(positions[lone], values[lone], positions[others[0]], values[others[0]], isoValue); + var b = Interpolate(positions[lone], values[lone], positions[others[1]], values[others[1]], isoValue); + var c = Interpolate(positions[lone], values[lone], positions[others[2]], values[others[2]], isoValue); + EmitOrientedTriangle(a, b, c, outward, outputPositions, outputNormals, outputIndices); + return; + } + + var p00 = Interpolate(positions[inside[0]], values[inside[0]], positions[outside[0]], values[outside[0]], isoValue); + var p01 = Interpolate(positions[inside[0]], values[inside[0]], positions[outside[1]], values[outside[1]], isoValue); + var p10 = Interpolate(positions[inside[1]], values[inside[1]], positions[outside[0]], values[outside[0]], isoValue); + var p11 = Interpolate(positions[inside[1]], values[inside[1]], positions[outside[1]], values[outside[1]], isoValue); + EmitOrientedTriangle(p00, p01, p11, outward, outputPositions, outputNormals, outputIndices); + EmitOrientedTriangle(p00, p11, p10, outward, outputPositions, outputNormals, outputIndices); + } + + private static float3 Interpolate(float3 first, float firstValue, float3 second, float secondValue, float isoValue) + { + var delta = secondValue - firstValue; + var amount = math.abs(delta) <= 1e-20f ? 0.5f : (isoValue - firstValue) / delta; + return math.lerp(first, second, amount); + } + + private static float3 Centroid(float3[] positions, Span vertices, int count) + { + var sum = float3.zero; + for (var index = 0; index < count; index++) sum += positions[vertices[index]]; + return sum / count; + } + + private static void EmitOrientedTriangle( + float3 a, + float3 b, + float3 c, + float3 outward, + List positions, + List normals, + List indices) + { + var normal = math.cross(b - a, c - a); + if (math.dot(normal, outward) < 0f) + { + (b, c) = (c, b); + normal = -normal; + } + + normal = math.normalize(normal); + var firstIndex = (uint)(positions.Count / 3); + Append(a, positions); + Append(b, positions); + Append(c, positions); + for (var vertex = 0; vertex < 3; vertex++) Append(normal, normals); + indices.Add(firstIndex); + indices.Add(firstIndex + 1); + indices.Add(firstIndex + 2); + } + + private static void Append(float3 value, List destination) + { + destination.Add(value.x); + destination.Add(value.y); + destination.Add(value.z); + } + } +} diff --git a/src/GameCult.Geometry/GameCult.Geometry.csproj b/src/GameCult.Geometry/GameCult.Geometry.csproj index a0192f69..a3ad9457 100644 --- a/src/GameCult.Geometry/GameCult.Geometry.csproj +++ b/src/GameCult.Geometry/GameCult.Geometry.csproj @@ -1,6 +1,6 @@ - Typed CultCache geometry domain and chunk artifact documents for VibeGeometry and Fensalir + CultGeometry algorithms and typed CultCache geometry artifacts GameCult.Geometry game;geometry;csg;lod;cultcache;cultmesh;vibegeometry;fensalir README.md @@ -8,6 +8,7 @@ + @@ -15,5 +16,6 @@ + diff --git a/src/GameCult.Geometry/ISOSURFACE-PROVENANCE.md b/src/GameCult.Geometry/ISOSURFACE-PROVENANCE.md new file mode 100644 index 00000000..a15a4933 --- /dev/null +++ b/src/GameCult.Geometry/ISOSURFACE-PROVENANCE.md @@ -0,0 +1,32 @@ +# Isosurface extraction provenance + +`CultGeometryIsoSurface` is a clean implementation of marching tetrahedra over +a regular scalar grid. The implementation follows the tetrahedral case shape +described by Peter Shirley and Allan Tuchman, “A Polygonal Approximation to +Direct Scalar Volume Rendering,” Computer Graphics 24(5), 1990, +doi:10.1145/99308.99322. + +The DELVE/HOLD port was behaviorally motivated by these unversioned local Unity +sources: + +- `D:\WIP4\Projects\VoxelTerrain\Assets\Scripts\Procedural\GenerateTerrain.cs` +- `D:\WIP4\Projects\VoxelTerrain\Assets\Plugins\MarchingCubes.cs` + +The source directory is not a Git checkout and the plugin carries no license or +author notice. Its code and lookup tables were therefore not copied. The +CultGeometry implementation uses a fresh six-tetrahedra decomposition, explicit +inside/outside classification, interpolation, winding, and flat-normal output. + +Deliberate behavior retained: + +- scalar samples less than or equal to the isovalue are inside; +- intersections are linearly interpolated along cell edges; +- vertices are emitted per triangle rather than welded; +- output is engine-neutral positions, normals, indices, and material slots. + +Deliberate changes: + +- no Unity mesh, physics, coroutine, navigation, or random dependency; +- no mutable global target, mode, or winding state; +- outward winding is derived from inside-to-outside direction; +- invalid fields and cell sizes fail at the public boundary. diff --git a/src/GameCult.Geometry/README.md b/src/GameCult.Geometry/README.md index 200f14ed..1ea60768 100644 --- a/src/GameCult.Geometry/README.md +++ b/src/GameCult.Geometry/README.md @@ -1,8 +1,17 @@ # GameCult.Geometry -`GameCult.Geometry` defines shared geometry values plus CultCache-native -documents for procedural geometry domains, LOD build requests, selected-cut -manifests, and mesh chunk artifacts. +The project is known as **CultGeometry**. `GameCult.Geometry` is its clean .NET +package and namespace identity. + +`GameCult.Geometry` owns reusable procedural geometry algorithms together with +the CultCache-native documents that carry their domains, build requests, +selected cuts, and mesh chunk artifacts. + +Its first engine-neutral algorithm is `CultGeometryIsoSurface.Extract`, a +marching-tetrahedra extractor over regular scalar grids. It uses CultMath for +numeric primitives and emits `CultGeometryTriangleMesh`; Godot, Unity, native +workers, and other consumers adapt that neutral result into their own runtime +objects. See `ISOSURFACE-PROVENANCE.md` for the clean-port boundary. The package is deliberately substrate-shaped: @@ -33,10 +42,10 @@ runtime equivalents instead of bespoke `{ minX, minY, maxX, maxY }` payloads. ## Runtime Path -`vg-csg` emits domain documents, selected-cut manifests, and chunk artifacts as -MessagePack CultCache documents. A Unity runtime, local worker, or remote -geometry process should receive the same records through CultMesh/CultNet and -read them back as `CultGeometry*` types. +CultGeometry CSG (`GameCult.Geometry.Csg`) emits domain documents, selected-cut +manifests, and chunk artifacts as MessagePack CultCache documents. A Godot +runtime, local worker, or remote geometry process receives the same records +through CultMesh/CultNet and reads them back as `CultGeometry*` types. ```csharp using GameCult.Caching; diff --git a/tests/GameCult.Geometry.Tests/GeometryDocumentTests.cs b/tests/GameCult.Geometry.Tests/GeometryDocumentTests.cs index b39b5182..16e66b8e 100644 --- a/tests/GameCult.Geometry.Tests/GeometryDocumentTests.cs +++ b/tests/GameCult.Geometry.Tests/GeometryDocumentTests.cs @@ -192,7 +192,7 @@ namespace GameCult.Geometry.Tests chunk, new CultNetDocumentMessageOptions { - SourceRuntimeId = "vg-csg", + SourceRuntimeId = "gamecult.geometry.csg", SourceRole = "geometry-worker", Tags = ["ragnarok", "chunk"] }); @@ -282,7 +282,7 @@ namespace GameCult.Geometry.Tests StartServer = false, DatabaseOptions = new CultNetDatabaseOptions { - RuntimeId = "unity-runtime", + RuntimeId = "godot-runtime", DocumentRegistry = registry } })) @@ -314,7 +314,7 @@ namespace GameCult.Geometry.Tests { DomainId = "ragnarok-column", RootKey = "ragnarok-column", - SourceRuntime = "vg-csg", + SourceRuntime = "gamecult.geometry.csg", CreatedAt = "2026-05-29T00:00:00.0000000Z", Root = new CultGeometryDomainNode { @@ -359,6 +359,7 @@ namespace GameCult.Geometry.Tests return Path.Combine( TestContext.CurrentContext.TestDirectory, "Fixtures", + // Immutable interoperability fixtures emitted before the CSG package rename. "vg-csg-ragnarok", fileName); } diff --git a/tests/GameCult.Geometry.Tests/IsoSurfaceTests.cs b/tests/GameCult.Geometry.Tests/IsoSurfaceTests.cs new file mode 100644 index 00000000..90d5f7f6 --- /dev/null +++ b/tests/GameCult.Geometry.Tests/IsoSurfaceTests.cs @@ -0,0 +1,89 @@ +using System; +using FluentAssertions; +using NUnit.Framework; + +namespace GameCult.Geometry.Tests +{ + [TestFixture] + public sealed class IsoSurfaceTests + { + [TestCase(-1f)] + [TestCase(1f)] + public void Uniform_field_has_no_surface(float value) + { + var samples = Filled(2, value); + + var mesh = CultGeometryIsoSurface.Extract(samples); + + mesh.Positions.Should().BeEmpty(); + mesh.Normals.Should().BeEmpty(); + mesh.Indices.Should().BeEmpty(); + } + + [Test] + public void Plane_field_interpolates_to_the_isovalue_and_faces_outward() + { + var samples = new float[2, 2, 2]; + for (var y = 0; y < 2; y++) + for (var z = 0; z < 2; z++) + { + samples[0, y, z] = -0.5f; + samples[1, y, z] = 0.5f; + } + + var mesh = CultGeometryIsoSurface.Extract(samples); + + mesh.TriangleCount.Should().BeGreaterThan(0); + for (var index = 0; index < mesh.Positions.Length; index += 3) + { + mesh.Positions[index].Should().BeApproximately(0.5f, 1e-6f); + } + + for (var index = 0; index < mesh.Normals.Length; index += 3) + { + mesh.Normals[index].Should().BeApproximately(1f, 1e-6f); + mesh.Normals[index + 1].Should().BeApproximately(0f, 1e-6f); + mesh.Normals[index + 2].Should().BeApproximately(0f, 1e-6f); + } + } + + [Test] + public void Extraction_is_deterministic_and_applies_origin_and_cell_size() + { + var samples = new float[2, 2, 2]; + samples[0, 0, 0] = -1f; + samples[1, 0, 0] = 1f; + samples[0, 1, 0] = 1f; + samples[1, 1, 0] = 1f; + samples[0, 0, 1] = 1f; + samples[1, 0, 1] = 1f; + samples[0, 1, 1] = 1f; + samples[1, 1, 1] = 1f; + + var first = CultGeometryIsoSurface.Extract(samples, origin: new CultVec3(10f, 20f, 30f), cellSize: 2f); + var second = CultGeometryIsoSurface.Extract(samples, origin: new CultVec3(10f, 20f, 30f), cellSize: 2f); + + second.Positions.Should().Equal(first.Positions); + second.Normals.Should().Equal(first.Normals); + second.Indices.Should().Equal(first.Indices); + first.Positions.Should().OnlyContain(value => value >= 10f); + } + + [Test] + public void Invalid_field_shape_is_rejected() + { + Action act = () => CultGeometryIsoSurface.Extract(new float[1, 2, 2]); + + act.Should().Throw(); + } + + private static float[,,] Filled(int size, float value) + { + var samples = new float[size, size, size]; + for (var x = 0; x < size; x++) + for (var y = 0; y < size; y++) + for (var z = 0; z < size; z++) samples[x, y, z] = value; + return samples; + } + } +} From 63d6094c9412808730ef5d8043a096c655ae901a Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 26 Aug 2026 17:47:06 +0200 Subject: [PATCH 123/283] Clarify CultMath and CultGeometry ownership --- packages/cultmath/README.md | 16 ++++++++-------- src/GameCult.Geometry/README.md | 6 +++++- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/cultmath/README.md b/packages/cultmath/README.md index edd24d37..8fd3888c 100644 --- a/packages/cultmath/README.md +++ b/packages/cultmath/README.md @@ -83,7 +83,7 @@ cargo build --release --manifest-path packages/cultmath/native/cultmath-core/Car ## Unity package CultMath's Unity 2021.3 surface is the tracked precompiled package at -`unity/org.gamecult.cultmath`. Unity consumes `CultMath.dll` and the numeric +`packages/cultmath/unity/org.gamecult.cultmath`. Unity consumes `CultMath.dll` and the numeric `CultMath.hlsl`; it does not compile the repository's current-language C# source tree and does not require a consumer `csc.rsp` workaround. @@ -92,22 +92,22 @@ tree and does not require a consumer `csc.rsp` workaround. ``` The repository root is not a Unity package. Build the tracked package with -`scripts/build-unity-package.ps1`; the script fresh-builds the netstandard2.1 +`packages/cultmath/scripts/build-unity-package.ps1`; the script fresh-builds the netstandard2.1 assembly and rejects stale binaries, missing metadata, unexpected assemblies, or leaked C# source. ## Shader Tooling -CultMath keeps portable DXC outside git under `.tools/`: +CultMath keeps portable DXC outside git under `packages/cultmath/.tools/`: ```powershell -.\tools\get-dxc.ps1 -.\tools\get-spirv-cross.ps1 -.\tools\compile-hlsl-spirv.ps1 ` +.\packages\cultmath\tools\get-dxc.ps1 +.\packages\cultmath\tools\get-spirv-cross.ps1 +.\packages\cultmath\tools\compile-hlsl-spirv.ps1 ` -ShaderPath E:\Projects\Odin\crates\muninn-move-tracker\shaders\MoveSphereCandidate.comp.hlsl ` -OutputPath E:\Projects\Odin\crates\muninn-move-tracker\artifacts\shader\MoveSphereCandidate.comp.spv ` - -IncludePath E:\Projects\CultMath\shaders -.\tools\compile-spirv-metal.ps1 ` + -IncludePath E:\Projects\CultLib\packages\cultmath\shaders +.\packages\cultmath\tools\compile-spirv-metal.ps1 ` -SpirvPath E:\Projects\Odin\crates\muninn-move-tracker\artifacts\shader\MoveSphereCandidate.comp.spv ` -OutputPath E:\Projects\Odin\crates\muninn-move-tracker\artifacts\shader\MoveSphereCandidate.comp.metal ``` diff --git a/src/GameCult.Geometry/README.md b/src/GameCult.Geometry/README.md index 1ea60768..2d12dc25 100644 --- a/src/GameCult.Geometry/README.md +++ b/src/GameCult.Geometry/README.md @@ -7,6 +7,10 @@ package and namespace identity. the CultCache-native documents that carry their domains, build requests, selected cuts, and mesh chunk artifacts. +It is the schema authority for the shared `CultGeometry*` records. +`GameCult.Geometry.Csg` owns CSG production behavior and proves wire parity +against those records; it does not independently evolve their identities. + Its first engine-neutral algorithm is `CultGeometryIsoSurface.Extract`, a marching-tetrahedra extractor over regular scalar grids. It uses CultMath for numeric primitives and emits `CultGeometryTriangleMesh`; Godot, Unity, native @@ -63,7 +67,7 @@ using var node = await CultMesh.CreateNodeAsync("ragnarok-geometry.ccmp", new Cu { DatabaseOptions = new CultNetDatabaseOptions { - RuntimeId = "unity-runtime", + RuntimeId = "godot-runtime", DocumentRegistry = geometryDocuments } }); From b672fb7a37a07ef499a644fcc1dbd7b7fcc538ab Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 3 Sep 2026 22:44:32 +0200 Subject: [PATCH 124/283] Return the Rust CultCache engine to CultLib packages/cultcache-rs forked from GameCult/cultcache-rs at the 5c69bfc monorepo import and the two lineages then diverged in both directions. The standalone repo took 28 commits of engine work CultLib never saw: typed SoA projection, atomic heterogeneous batch publication, single-entry and conditional batch CAS, a transactional keyed redb backend with serialized cross-process opens, lockless provider snapshot reads, RAII read-only shared snapshots, snapshot-fenced replace/append, crash-atomic single-file snapshots, compaction fences, portable and canonical byte fields, and unified retained storage authority. That body is 3,714 lines with 48 tests against CultLib's 1,554 with 18. CultLib is the canonical home because wire parity conformance lives here and nothing outside it is tested for cross-runtime agreement. A runtime-specific core-stack repo cannot hold the engine every other runtime must agree with. The standalone body lands as the base rather than merging 28 commits backward. It is already proven against a CultLib-derived cultnet-rs: Ghostlight vendors exactly this pairing and compiles. Here, cultcache-rs passes 46 tests and the cultnet-rs RUDP gate passes 20 with no source change. Retained debt, not carried forward: a0b31b8 recovered schema-stamped records missing catalog entries (SchemaStamped, infer_schema_name, infer_schema_version_from_payload) and 743eaa5 hardened snapshot replacement (SnapshotReplacementStage, CommittedSnapshotDurabilityUncertain, stale candidate cleanup, with_exclusive_lock_using_unlock). Their tests were white-box against internals this body does not have. The standalone independently made single-file snapshots crash atomic and cleaned abandoned staging files, so the durability guarantee is probably held under other names -- probably is not proven. Re-establish both as black-box tests against the new API before the standalone repo is retired. Co-Authored-By: Claude Opus 5 --- packages/cultcache-rs/Cargo.toml | 7 +- packages/cultcache-rs/README.md | 78 +- .../cultcache-rs-derive/src/lib.rs | 51 +- packages/cultcache-rs/src/lib.rs | 3538 +++++++++++++---- 4 files changed, 2935 insertions(+), 739 deletions(-) diff --git a/packages/cultcache-rs/Cargo.toml b/packages/cultcache-rs/Cargo.toml index ef06727d..e6ec5e59 100644 --- a/packages/cultcache-rs/Cargo.toml +++ b/packages/cultcache-rs/Cargo.toml @@ -17,14 +17,15 @@ chrono = { version = "0.4", features = ["serde"] } cultcache-rs-derive = { path = "cultcache-rs-derive" } fs2 = "0.4" rmp-serde = "1.3" +redb = "4.1.0" serde = { version = "1", features = ["derive"] } serde_bytes = "0.11" serde_json = "1" uuid = { version = "1", features = ["v4"] } -[target.'cfg(windows)'.dependencies] -windows-sys = { version = "0.59", features = ["Win32_Storage_FileSystem"] } - [dev-dependencies] pretty_assertions = "1.4" tempfile = "3" + +[target.'cfg(windows)'.dependencies] +windows-sys = { version = "0.59", features = ["Win32_Foundation", "Win32_Storage_FileSystem"] } diff --git a/packages/cultcache-rs/README.md b/packages/cultcache-rs/README.md index 74b20dd3..0176f474 100644 --- a/packages/cultcache-rs/README.md +++ b/packages/cultcache-rs/README.md @@ -53,7 +53,7 @@ struct Settings { let mut cache = CultCache::new(); cache.register_entry_type::()?; -cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new("cache.msgpack")); +cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new("cache.cc")); cache.pull_all_backing_stores()?; cache.put("app", &Settings { @@ -136,7 +136,7 @@ pub struct PlayerData { let mut cache = CultCache::builder() .with_generated_entries(game_entries()) - .with_generic_store(SingleFileMessagePackBackingStore::new("cache.msgpack")) + .with_generic_store(SingleFileMessagePackBackingStore::new("cache.cc")) .build()?; cache.pull_all_backing_stores()?; @@ -173,26 +173,59 @@ without pretending Rust has runtime reflection hiding under the floorboards. - `get_envelope::` - `get_required_envelope::` - `get_all::` +- `get_all_with_keys::` +- `soa::` - `put::` - `put_envelope::` - `update::` - `delete::` - `snapshot` +- `snapshot_soa` +- `load_soa` - `SingleFileMessagePackBackingStore` +## Structure Of Arrays + +The C# CultCache hot path exposes CPU-local SoA scans as: + +```csharp +Span x = cache.Soa() + .Column(nameof(PlayerTransform.PositionX)) + .Span; +``` + +Rust cannot discover those columns through runtime reflection, so each domain +type declares its column extractors explicitly with `SoaDocument` or the +`cultcache_soa!` helper: + +```rust +cultcache_soa!(PlayerTransform { + "position_x" => |row: &PlayerTransform| row.position_x, + "health" => |row: &PlayerTransform| row.health, +}); + +let table = cache.soa::()?; +let health = table.column::("health")?; +``` + +This is the same public shape as the C# rite: callers ask the cache for a typed +table, then pull contiguous typed columns by name. The Rust version is explicit +about the extractor table because the closed-world schema boundary is a virtue, +not a missing reflection party trick. + ## Backing Store Routing Generic store: ```rust -cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new("cache.msgpack")); +cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new("cache.cc")); ``` Type-specific store: ```rust cache.add_backing_store( - SingleFileMessagePackBackingStore::new("players.msgpack"), + SingleFileMessagePackBackingStore::new("players.cc"), ["player"], ); ``` @@ -250,38 +283,8 @@ marked `default` use `Default::default()` when older payloads are read. Deleted field slots should stay reserved until an explicit store migration rewrites the data. -The single-file MessagePack store rewrites one complete snapshot. Under the -exclusive sidecar lock it removes abandoned candidates without following them, -creates a unique same-directory candidate with create-new semantics, writes and -flushes it, and then replaces the committed pathname without deleting that -pathname first. A process interruption before replacement leaves the previous -snapshot authoritative. Once replacement succeeds, readers observe the complete -new snapshot rather than a partial file. - -Unix requests a parent-directory flush after replacement. Windows uses -`MoveFileExW` with replace-existing and write-through flags. If the final Unix -directory flush fails, the method returns a downcastable -`CommittedSnapshotDurabilityUncertain`: the complete new snapshot may already be -visible, so the caller must fail-stop or reopen and reconcile before issuing -higher-level work again. Treating that error as "not committed" and blindly -retrying can duplicate commands or receipts. - -Abandoned `..tmp` candidates are never read as committed state and are -removed by the next exclusive writer. Cleanup recognizes only the exact -canonical UUID form emitted for that target, including targets whose native -filename is not UTF-8; similar `.tmp` names remain untouched. Candidate creation -uses create-new semantics, so an unexpected file or symlink collision fails -instead of being opened or truncated. The canonical candidate filename namespace -is reserved to the store. - -These guarantees assume a local filesystem that honors the platform rename and -flush primitives, and writers that honor the sidecar lock. Network filesystems, -faulty storage hardware, and unrelated writers may provide weaker behavior. -Fault-injection tests prove the process-visible old-or-new outcomes around the -replacement boundary; they do not simulate sudden power loss or prove that a -device honored a successful flush. - -This is a sane starting point for small typed state surfaces, settings, Epiphany agent memory, +The single-file MessagePack store rewrites an atomic snapshot. That is a sane +starting point for small typed state surfaces, settings, Epiphany agent memory, heartbeat state, and other compact control-plane data. Large corpora should use a sharded store or a real database instead of asking one file to become a warehouse and then acting wounded when physics invoices us. @@ -290,9 +293,6 @@ The single-file store uses a sidecar lock file for shared reads and exclusive writes. That protects ordinary multi-process access to the same file. It is still not a multi-master replication protocol, and it is not a substitute for a coordinator when higher-level write ordering matters. -An explicit unlock error cannot replace the write outcome: dropping the lock-file -handle is the final OS lock-release path, so a committed-durability-uncertain -result remains inspectable rather than being masked by cleanup noise. ## Near-Term Ergonomic Improvements diff --git a/packages/cultcache-rs/cultcache-rs-derive/src/lib.rs b/packages/cultcache-rs/cultcache-rs-derive/src/lib.rs index f05a23f3..7d613194 100644 --- a/packages/cultcache-rs/cultcache-rs-derive/src/lib.rs +++ b/packages/cultcache-rs/cultcache-rs-derive/src/lib.rs @@ -75,6 +75,7 @@ pub fn derive_database_entry(input: TokenStream) -> TokenStream { }; let mut key: Option = None; let mut default = false; + let mut bytes = false; for attribute in field .attrs .iter() @@ -88,6 +89,9 @@ pub fn derive_database_entry(input: TokenStream) -> TokenStream { } else if meta.path.is_ident("default") { default = true; Ok(()) + } else if meta.path.is_ident("bytes") { + bytes = true; + Ok(()) } else { Err(meta.error("unsupported field cultcache attribute")) } @@ -117,6 +121,7 @@ pub fn derive_database_entry(input: TokenStream) -> TokenStream { ident: field_ident, ty: field.ty, default, + bytes, }); } slots.sort_by_key(|slot| slot.key); @@ -125,8 +130,14 @@ pub fn derive_database_entry(input: TokenStream) -> TokenStream { let serialize_elements = (0..=max_slot).map(|slot| { if let Some(field) = slots.iter().find(|field| field.key == slot) { let field_ident = &field.ident; - quote! { - tuple.serialize_element(&self.#field_ident)?; + if field.bytes { + quote! { + tuple.serialize_element(::serde_bytes::Bytes::new(&self.#field_ident))?; + } + } else { + quote! { + tuple.serialize_element(&self.#field_ident)?; + } } } else { quote! { @@ -138,8 +149,14 @@ pub fn derive_database_entry(input: TokenStream) -> TokenStream { let option_declarations = slots.iter().map(|field| { let variable = format_ident!("slot_{}", field.key); let ty = &field.ty; - quote! { - let mut #variable: ::std::option::Option<#ty> = ::std::option::Option::None; + if field.bytes { + quote! { + let mut #variable: ::std::option::Option<::serde_bytes::ByteBuf> = ::std::option::Option::None; + } + } else { + quote! { + let mut #variable: ::std::option::Option<#ty> = ::std::option::Option::None; + } } }); @@ -147,9 +164,17 @@ pub fn derive_database_entry(input: TokenStream) -> TokenStream { if let Some(field) = slots.iter().find(|field| field.key == slot) { let variable = format_ident!("slot_{}", field.key); let ty = &field.ty; - quote! { - #slot => { - #variable = seq.next_element::<#ty>()?; + if field.bytes { + quote! { + #slot => { + #variable = seq.next_element::<::serde_bytes::ByteBuf>()?; + } + } + } else { + quote! { + #slot => { + #variable = seq.next_element::<#ty>()?; + } } } } else { @@ -164,7 +189,16 @@ pub fn derive_database_entry(input: TokenStream) -> TokenStream { let build_fields = slots.iter().map(|field| { let field_ident = &field.ident; let variable = format_ident!("slot_{}", field.key); - if field.default { + if field.bytes && field.default { + quote! { + #field_ident: #variable.unwrap_or_default().into_vec() + } + } else if field.bytes { + let field_name = field_ident.to_string(); + quote! { + #field_ident: #variable.ok_or_else(|| ::serde::de::Error::missing_field(#field_name))?.into_vec() + } + } else if field.default { quote! { #field_ident: #variable.unwrap_or_default() } @@ -240,4 +274,5 @@ struct CultCacheSlot { ident: syn::Ident, ty: Type, default: bool, + bytes: bool, } diff --git a/packages/cultcache-rs/src/lib.rs b/packages/cultcache-rs/src/lib.rs index b85b763a..b8d6d8f9 100644 --- a/packages/cultcache-rs/src/lib.rs +++ b/packages/cultcache-rs/src/lib.rs @@ -1,18 +1,22 @@ use anyhow::Context; use anyhow::Result; use anyhow::anyhow; +use anyhow::bail; +use anyhow::ensure; use serde::Serialize; use serde::de::DeserializeOwned; +use std::any::Any; use std::collections::BTreeMap; use std::collections::BTreeSet; -use std::ffi::OsStr; -use std::fmt; use std::fs; use std::fs::File; use std::fs::OpenOptions; -use std::io::Write; +use std::marker::PhantomData; use std::path::Path; use std::path::PathBuf; +use std::sync::Arc; + +use redb::{Database, ReadableDatabase, ReadableTable, TableDefinition}; extern crate self as cultcache_rs; @@ -27,6 +31,83 @@ pub trait CultCacheRegistry { fn register_entries(&self, cache: &mut CultCache) -> Result<()>; } +pub trait SoaDocument: DatabaseEntry { + fn soa_columns(rows: &[Self]) -> BTreeMap<&'static str, CultSoaColumnValues>; +} + +pub struct CultSoaColumnValues { + type_name: &'static str, + values: Box, +} + +impl CultSoaColumnValues { + pub fn new(values: Vec) -> Self { + Self { + type_name: std::any::type_name::(), + values: Box::new(values), + } + } +} + +#[derive(Clone, Debug, PartialEq)] +pub struct CultSoaColumn { + name: String, + values: Vec, +} + +impl CultSoaColumn { + pub fn name(&self) -> &str { + &self.name + } + + pub fn values(&self) -> &[TValue] { + &self.values + } +} + +pub struct CultSoaTable { + keys: Vec, + documents: Vec, + columns: BTreeMap, + _document: PhantomData, +} + +impl CultSoaTable { + pub fn keys(&self) -> &[String] { + &self.keys + } + + pub fn documents(&self) -> &[TDocument] { + &self.documents + } + + pub fn len(&self) -> usize { + self.keys.len() + } + + pub fn is_empty(&self) -> bool { + self.keys.is_empty() + } + + pub fn column(&self, name: &str) -> Result> { + let Some(column) = self.columns.get(name) else { + return Err(anyhow!("SoA table has no column {name:?}")); + }; + let Some(values) = column.values.downcast_ref::>() else { + return Err(anyhow!( + "SoA table column {:?} stores {}, not {}", + name, + column.type_name, + std::any::type_name::() + )); + }; + Ok(CultSoaColumn { + name: name.to_string(), + values: values.clone(), + }) + } +} + #[macro_export] macro_rules! cultcache_registry { ($name:ident { $($entry:ty),* $(,)? }) => { @@ -44,6 +125,22 @@ macro_rules! cultcache_registry { }; } +#[macro_export] +macro_rules! cultcache_soa { + ($entry:ty { $($column:literal => $extractor:expr),* $(,)? }) => { + impl $crate::SoaDocument for $entry { + fn soa_columns(rows: &[Self]) -> ::std::collections::BTreeMap<&'static str, $crate::CultSoaColumnValues> { + let mut columns = ::std::collections::BTreeMap::new(); + $( + let values = rows.iter().map($extractor).collect::>(); + columns.insert($column, $crate::CultSoaColumnValues::new(values)); + )* + columns + } + } + }; +} + #[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub struct CultCacheEnvelope { @@ -57,6 +154,93 @@ pub struct CultCacheEnvelope { pub schema_id: Option, } +#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CultCacheSoaTable { + pub keys: Vec, + pub types: Vec, + pub payloads: Vec>, + pub stored_ats: Vec, + pub schema_ids: Vec>, +} + +impl CultCacheSoaTable { + pub fn from_envelopes(entries: impl IntoIterator) -> Self { + let mut table = Self::default(); + for entry in entries { + table.keys.push(entry.key); + table.types.push(entry.r#type); + table.payloads.push(entry.payload); + table.stored_ats.push(entry.stored_at); + table.schema_ids.push(entry.schema_id); + } + table + } + + pub fn len(&self) -> usize { + self.keys.len() + } + + pub fn is_empty(&self) -> bool { + self.keys.is_empty() + } + + pub fn validate(&self) -> Result<()> { + let len = self.keys.len(); + for (name, candidate) in [ + ("types", self.types.len()), + ("payloads", self.payloads.len()), + ("storedAts", self.stored_ats.len()), + ("schemaIds", self.schema_ids.len()), + ] { + if candidate != len { + return Err(anyhow!( + "CultCache SoA column {name} has length {candidate}, expected {len}" + )); + } + } + for (index, key) in self.keys.iter().enumerate() { + if key.trim().is_empty() { + return Err(anyhow!("CultCache SoA row {index} has an empty key")); + } + if self.types[index].trim().is_empty() { + return Err(anyhow!("CultCache SoA row {index} has an empty type")); + } + if self.stored_ats[index].trim().is_empty() { + return Err(anyhow!("CultCache SoA row {index} has an empty stored_at")); + } + } + Ok(()) + } + + pub fn into_envelopes(self) -> Result> { + self.validate()?; + let Self { + keys, + types, + payloads, + stored_ats, + schema_ids, + } = self; + Ok(keys + .into_iter() + .zip(types) + .zip(payloads) + .zip(stored_ats) + .zip(schema_ids) + .map( + |((((key, r#type), payload), stored_at), schema_id)| CultCacheEnvelope { + key, + r#type, + payload, + stored_at, + schema_id, + }, + ) + .collect()) + } +} + #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] struct PersistedStoreSnapshot( String, @@ -100,45 +284,6 @@ pub struct PushAllOptions { pub soft: bool, } -/// A complete new snapshot replaced the committed pathname, but its final -/// durability barrier failed. Callers must fail-stop or reopen and reconcile; -/// retrying as though the write never committed can duplicate higher-level work. -#[derive(Debug)] -pub struct CommittedSnapshotDurabilityUncertain { - path: PathBuf, - detail: String, -} - -impl CommittedSnapshotDurabilityUncertain { - fn new(path: PathBuf, error: impl fmt::Display) -> Self { - Self { - path, - detail: error.to_string(), - } - } - - pub fn path(&self) -> &Path { - &self.path - } - - pub fn detail(&self) -> &str { - &self.detail - } -} - -impl fmt::Display for CommittedSnapshotDurabilityUncertain { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - formatter, - "snapshot {} was committed but its durability is uncertain: {}", - self.path.display(), - self.detail - ) - } -} - -impl std::error::Error for CommittedSnapshotDurabilityUncertain {} - pub trait CacheBackingStore: Send { fn pull_all(&self) -> Result>; fn push(&mut self, entry: &CultCacheEnvelope) -> Result<()>; @@ -170,6 +315,305 @@ impl SingleFileMessagePackBackingStore { &self.path } + /// Holds the pre-created sibling lock shared while a read-only consumer + /// evaluates and acts on one snapshot. The reader never creates or writes + /// either file. Writers using the sibling lock cannot replace the snapshot + /// until `action` returns. + /// + /// Releasing the lock is RAII cleanup. A release failure therefore cannot + /// rewrite the completed action's result; consumers that need to observe + /// that cleanup failure can use + /// [`Self::with_read_only_shared_snapshot_and_unlock_diagnostic`]. + pub fn with_read_only_shared_snapshot( + &self, + action: impl FnOnce(Vec) -> Result, + ) -> Result { + self.with_read_only_shared_snapshot_and_unlock_diagnostic(action, |_| {}) + } + + /// The diagnostic-bearing form of + /// [`Self::with_read_only_shared_snapshot`]. `on_unlock_failure` observes a + /// cleanup failure separately and never changes the action result. + pub fn with_read_only_shared_snapshot_and_unlock_diagnostic( + &self, + action: impl FnOnce(Vec) -> Result, + on_unlock_failure: impl FnOnce(anyhow::Error), + ) -> Result { + self.with_read_only_shared_snapshot_using( + action, + |lock| { + fs2::FileExt::unlock(lock) + .with_context(|| format!("failed to unlock {}", self.lock_path().display())) + }, + on_unlock_failure, + ) + } + + fn with_read_only_shared_snapshot_using( + &self, + action: impl FnOnce(Vec) -> Result, + unlock: U, + on_unlock_failure: D, + ) -> Result + where + U: FnOnce(&File) -> Result<()>, + D: FnOnce(anyhow::Error), + { + let lock_path = self.lock_path(); + let lock = OpenOptions::new() + .read(true) + .open(&lock_path) + .with_context(|| format!("failed to open pre-created {}", lock_path.display()))?; + fs2::FileExt::lock_shared(&lock) + .with_context(|| format!("failed to lock {}", lock_path.display()))?; + let guard = ReadOnlySharedLockGuard::new(lock, unlock, on_unlock_failure); + let result = self.read_all_unlocked().and_then(action); + drop(guard); + result + } + + /// Replaces one exact envelope under the store's cross-process exclusive + /// lock. A changed or missing expected envelope returns false without a write. + pub fn compare_and_swap_entry( + &self, + expected: &CultCacheEnvelope, + replacement: CultCacheEnvelope, + ) -> Result { + self.with_exclusive_lock(|| { + let mut entries = self.read_all_unlocked()?; + let Some(index) = entries + .iter() + .position(|candidate| entry_id(candidate) == entry_id(expected)) + else { + return Ok(false); + }; + if entries[index] != *expected { + return Ok(false); + } + entries[index] = replacement; + entries.sort_by_key(entry_id); + self.write_all_unlocked(&entries)?; + Ok(true) + }) + } + + /// Inserts one envelope only when its polymorphic type/key identity is + /// absent, under the same cross-process lock used by all single-file writes. + pub fn insert_entry_if_absent(&self, entry: CultCacheEnvelope) -> Result { + self.with_exclusive_lock(|| { + let mut entries = self.read_all_unlocked()?; + if entries + .iter() + .any(|candidate| entry_id(candidate) == entry_id(&entry)) + { + return Ok(false); + } + entries.push(entry); + entries.sort_by_key(entry_id); + self.write_all_unlocked(&entries)?; + Ok(true) + }) + } + + /// Atomically replaces an exact set of existing envelopes and inserts any + /// additional companion envelopes. Every precondition is checked beneath + /// the same cross-process lock as the single snapshot write. + pub fn compare_and_swap_batch( + &self, + expected: &[CultCacheEnvelope], + replacements: Vec, + ) -> Result { + if replacements.is_empty() { + return Err(anyhow!( + "conditional batch requires a non-empty replacement set" + )); + } + let expected_ids = unique_batch_ids(expected, "expected")?; + let replacement_ids = unique_batch_ids(&replacements, "replacement")?; + if !expected_ids.is_subset(&replacement_ids) { + return Err(anyhow!( + "conditional batch must replace every expected identity" + )); + } + + self.with_exclusive_lock(|| { + let mut entries = self.read_all_unlocked()?; + for expected_entry in expected { + let Some(current) = entries + .iter() + .find(|candidate| entry_id(candidate) == entry_id(expected_entry)) + else { + return Ok(false); + }; + if current != expected_entry { + return Ok(false); + } + } + for replacement in &replacements { + let identity = entry_id(replacement); + if !expected_ids.contains(&identity) + && entries + .iter() + .any(|candidate| entry_id(candidate) == identity) + { + return Ok(false); + } + } + + entries.retain(|candidate| !expected_ids.contains(&entry_id(candidate))); + entries.extend(replacements); + entries.sort_by_key(entry_id); + self.write_all_unlocked(&entries)?; + Ok(true) + }) + } + + /// Atomically appends companions only when the complete backing-store + /// snapshot is byte-for-byte unchanged. Unlike identity-scoped CAS, this + /// fences predicate cardinality: a concurrently inserted unknown identity + /// makes the expected snapshot stale. + pub fn append_if_snapshot_unchanged( + &self, + expected_snapshot: &[CultCacheEnvelope], + additions: Vec, + ) -> Result { + if additions.is_empty() { + return Err(anyhow!("conditional snapshot append requires additions")); + } + unique_batch_ids(expected_snapshot, "expected snapshot")?; + let addition_ids = unique_batch_ids(&additions, "snapshot additions")?; + self.with_exclusive_lock(|| { + let mut current = self.read_all_unlocked()?; + let mut expected = expected_snapshot.to_vec(); + current.sort_by_key(entry_id); + expected.sort_by_key(entry_id); + if current != expected { + return Ok(false); + } + if current + .iter() + .any(|row| addition_ids.contains(&entry_id(row))) + { + return Ok(false); + } + current.extend(additions); + current.sort_by_key(entry_id); + self.write_all_unlocked(¤t)?; + Ok(true) + }) + } + + /// Atomically deletes an exact set of envelopes. Any changed or missing + /// member refuses the entire deletion without a partial write. + pub fn delete_batch_if_unchanged(&self, expected: &[CultCacheEnvelope]) -> Result { + if expected.is_empty() { + return Err(anyhow!( + "conditional delete requires a non-empty expected set" + )); + } + let expected_ids = unique_batch_ids(expected, "delete expected")?; + self.with_exclusive_lock(|| { + let mut entries = self.read_all_unlocked()?; + for expected_entry in expected { + let Some(current) = entries + .iter() + .find(|candidate| entry_id(candidate) == entry_id(expected_entry)) + else { + return Ok(false); + }; + if current != expected_entry { + return Ok(false); + } + } + entries.retain(|candidate| !expected_ids.contains(&entry_id(candidate))); + self.write_all_unlocked(&entries)?; + Ok(true) + }) + } + + /// Atomically replaces existing rows and appends companion rows only while + /// the complete backing-store snapshot remains byte-exact. + pub fn replace_and_append_if_snapshot_unchanged( + &self, + expected_snapshot: &[CultCacheEnvelope], + replacements: Vec, + ) -> Result { + if replacements.is_empty() { + return Err(anyhow!( + "conditional snapshot replacement requires replacements" + )); + } + unique_batch_ids(expected_snapshot, "expected snapshot")?; + let replacement_ids = unique_batch_ids(&replacements, "snapshot replacements")?; + self.with_exclusive_lock(|| { + let mut current = self.read_all_unlocked()?; + let mut expected = expected_snapshot.to_vec(); + current.sort_by_key(entry_id); + expected.sort_by_key(entry_id); + if current != expected { + return Ok(false); + } + current.retain(|row| !replacement_ids.contains(&entry_id(row))); + current.extend(replacements); + current.sort_by_key(entry_id); + self.write_all_unlocked(¤t)?; + Ok(true) + }) + } + + /// Atomically replaces and deletes rows only while the complete store + /// snapshot remains byte-exact. This is the single-file compaction + /// primitive: summary publication and history deletion share one write. + pub fn replace_and_delete_if_snapshot_unchanged( + &self, + expected_snapshot: &[CultCacheEnvelope], + replacements: Vec, + deletions: &[CultCacheEnvelope], + ) -> Result { + if replacements.is_empty() || deletions.is_empty() { + return Err(anyhow!( + "conditional compaction requires replacements and deletions" + )); + } + let expected_ids = unique_batch_ids(expected_snapshot, "expected snapshot")?; + let replacement_ids = unique_batch_ids(&replacements, "replacement")?; + let deletion_ids = unique_batch_ids(deletions, "deletion")?; + if !deletion_ids.is_subset(&expected_ids) { + return Err(anyhow!( + "compaction deletion is absent from expected snapshot" + )); + } + if !deletion_ids.is_disjoint(&replacement_ids) { + return Err(anyhow!("compaction cannot replace and delete one identity")); + } + self.with_exclusive_lock(|| { + let mut current = self.read_all_unlocked()?; + let mut expected = expected_snapshot.to_vec(); + current.sort_by_key(entry_id); + expected.sort_by_key(entry_id); + if current != expected { + return Ok(false); + } + for row in &replacements { + if !expected_ids.contains(&entry_id(row)) + && current + .iter() + .any(|candidate| entry_id(candidate) == entry_id(row)) + { + return Ok(false); + } + } + current.retain(|row| !deletion_ids.contains(&entry_id(row))); + for row in replacements { + current.retain(|candidate| entry_id(candidate) != entry_id(&row)); + current.push(row); + } + current.sort_by_key(entry_id); + self.write_all_unlocked(¤t)?; + Ok(true) + }) + } + fn read_all_unlocked(&self) -> Result> { if !self.path.exists() { return Ok(Vec::new()); @@ -179,57 +623,47 @@ impl SingleFileMessagePackBackingStore { if bytes.is_empty() { return Ok(Vec::new()); } - decode_store_snapshot(&bytes).or_else(|_| { - rmp_serde::from_slice(&bytes) - .with_context(|| format!("failed to decode MessagePack {}", self.path.display())) - }) + decode_store_snapshot(&bytes) + .or_else(|_| rmp_serde::from_slice(&bytes)) + .with_context(|| format!("failed to decode MessagePack {}", self.path.display())) + } + + /// Reads one filesystem snapshot without creating or opening the sibling + /// CultCache lock file. + /// + /// This is deliberately narrower than `pull_all`: use it only at a + /// provider-owned, read-only crossing where the producer replaces the + /// complete file atomically and the consumer has no authority to mutate + /// the provider directory. An absent file is an empty snapshot. Writers + /// and locally owned stores must continue to use the locked APIs. + pub fn pull_all_read_only_snapshot(&self) -> Result> { + self.read_all_unlocked() } fn write_all_unlocked(&self, entries: &[CultCacheEnvelope]) -> Result<()> { - self.write_all_unlocked_with_observer(entries, |_| Ok(())) - } - - fn write_all_unlocked_with_observer( - &self, - entries: &[CultCacheEnvelope], - mut observe: impl FnMut(SnapshotReplacementStage) -> Result<()>, - ) -> Result<()> { if let Some(parent) = self.path.parent() { fs::create_dir_all(parent) .with_context(|| format!("failed to create {}", parent.display()))?; } - remove_stale_candidates(&self.path)?; - let bytes = rmp_serde::to_vec(&encode_store_snapshot(entries)) + remove_abandoned_staging_files(&self.path)?; + let bytes = rmp_serde::to_vec(&encode_store_snapshot(entries)?) .context("failed to encode MessagePack")?; let tmp_path = temporary_path_for(&self.path); - let mut candidate = OpenOptions::new() + let mut staged = OpenOptions::new() .create_new(true) .write(true) .open(&tmp_path) - .with_context(|| format!("failed to open {}", tmp_path.display()))?; - candidate + .with_context(|| format!("failed to create {}", tmp_path.display()))?; + use std::io::Write; + staged .write_all(&bytes) .with_context(|| format!("failed to write {}", tmp_path.display()))?; - candidate + staged .sync_all() - .with_context(|| format!("failed to flush {}", tmp_path.display()))?; - drop(candidate); - - observe(SnapshotReplacementStage::CandidateSynced)?; - replace_file(&tmp_path, &self.path)?; - if let Err(error) = observe(SnapshotReplacementStage::TargetReplaced) { - return Err(anyhow::Error::new( - CommittedSnapshotDurabilityUncertain::new(self.path.clone(), error), - )); - } - - if let Some(parent) = self.path.parent() { - if let Err(error) = sync_parent_directory(parent) { - return Err(anyhow::Error::new( - CommittedSnapshotDurabilityUncertain::new(self.path.clone(), error), - )); - } - } + .with_context(|| format!("failed to sync {}", tmp_path.display()))?; + drop(staged); + replace_file_atomically(&tmp_path, &self.path)?; + sync_parent_directory(&self.path)?; Ok(()) } @@ -244,26 +678,13 @@ impl SingleFileMessagePackBackingStore { } fn with_exclusive_lock(&self, action: impl FnOnce() -> Result) -> Result { - self.with_exclusive_lock_using_unlock(action, |lock| fs2::FileExt::unlock(lock)) - } - - fn with_exclusive_lock_using_unlock( - &self, - action: impl FnOnce() -> Result, - unlock: impl FnOnce(&File) -> std::io::Result<()>, - ) -> Result { let lock = self.open_lock_file()?; fs2::FileExt::lock_exclusive(&lock) .with_context(|| format!("failed to lock {}", self.lock_path().display()))?; - let action_result = action(); - - // Closing the file handle releases the OS lock even when an explicit - // unlock reports an error. The action outcome remains authoritative: - // in particular, never replace a committed-durability-uncertain error - // with secondary lock-cleanup noise. - let _unlock_result = unlock(&lock); - drop(lock); - action_result + let result = action(); + fs2::FileExt::unlock(&lock) + .with_context(|| format!("failed to unlock {}", self.lock_path().display()))?; + result } fn open_lock_file(&self) -> Result { @@ -286,14 +707,71 @@ impl SingleFileMessagePackBackingStore { .path .file_name() .map(|value| value.to_os_string()) - .unwrap_or_else(|| "cultcache.msgpack".into()); + .unwrap_or_else(|| "cultcache.cc".into()); lock_name.push(".lock"); self.path.with_file_name(lock_name) } } +struct ReadOnlySharedLockGuard +where + U: FnOnce(&File) -> Result<()>, + D: FnOnce(anyhow::Error), +{ + lock: Option, + unlock: Option, + on_unlock_failure: Option, +} + +impl ReadOnlySharedLockGuard +where + U: FnOnce(&File) -> Result<()>, + D: FnOnce(anyhow::Error), +{ + fn new(lock: File, unlock: U, on_unlock_failure: D) -> Self { + Self { + lock: Some(lock), + unlock: Some(unlock), + on_unlock_failure: Some(on_unlock_failure), + } + } +} + +impl Drop for ReadOnlySharedLockGuard +where + U: FnOnce(&File) -> Result<()>, + D: FnOnce(anyhow::Error), +{ + fn drop(&mut self) { + let (Some(lock), Some(unlock)) = (self.lock.as_ref(), self.unlock.take()) else { + return; + }; + if let Err(error) = unlock(lock) + && let Some(on_unlock_failure) = self.on_unlock_failure.take() + { + on_unlock_failure(error); + } + } +} + +fn unique_batch_ids( + entries: &[CultCacheEnvelope], + label: &str, +) -> Result> { + let ids = entries.iter().map(entry_id).collect::>(); + if ids.len() != entries.len() { + return Err(anyhow!( + "conditional batch {label} set contains duplicate identities" + )); + } + Ok(ids) +} + impl CacheBackingStore for SingleFileMessagePackBackingStore { fn pull_all(&self) -> Result> { + if !self.path.exists() && !self.lock_path().exists() { + return Ok(Vec::new()); + } self.with_shared_lock(|| self.read_all_unlocked()) } @@ -324,6 +802,947 @@ impl CacheBackingStore for SingleFileMessagePackBackingStore { } } +const REDB_ENVELOPES: TableDefinition<&[u8], &[u8]> = TableDefinition::new("cultcache_envelopes"); + +/// Transactional keyed CultCache storage. Each polymorphic `(type, key)` +/// identity is an independent redb row whose value is the exact MessagePack +/// serialization of its `CultCacheEnvelope`. +#[derive(Clone)] +pub struct RedbMessagePackBackingStore { + path: PathBuf, +} + +impl std::fmt::Debug for RedbMessagePackBackingStore { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter + .debug_struct("RedbMessagePackBackingStore") + .field("path", &self.path) + .finish_non_exhaustive() + } +} + +impl RedbMessagePackBackingStore { + pub fn new(path: impl Into) -> Result { + let path = path.into(); + if let Some(parent) = path + .parent() + .filter(|parent| !parent.as_os_str().is_empty()) + { + fs::create_dir_all(parent) + .with_context(|| format!("failed to create {}", parent.display()))?; + } + let store = Self { path }; + store.with_database(|database| { + let write = database.begin_write()?; + { + write.open_table(REDB_ENVELOPES)?; + } + write.commit()?; + Ok(()) + })?; + Ok(store) + } + + pub fn path(&self) -> &Path { + &self.path + } + + fn open_database(&self) -> Result { + Database::create(&self.path) + .with_context(|| format!("failed to open redb CultCache {}", self.path.display())) + } + + /// redb permits one open writable database handle per path. The external + /// CultCache lock therefore owns the complete open/transaction/close + /// interval, preserving the fresh-handle and cross-process construction + /// model used by the other backing store. + fn with_database(&self, action: impl FnOnce(&Database) -> Result) -> Result { + let lock_path = self.lock_path(); + if let Some(parent) = lock_path + .parent() + .filter(|parent| !parent.as_os_str().is_empty()) + { + fs::create_dir_all(parent) + .with_context(|| format!("failed to create {}", parent.display()))?; + } + let lock = OpenOptions::new() + .create(true) + .read(true) + .truncate(false) + .write(true) + .open(&lock_path) + .with_context(|| format!("failed to open {}", lock_path.display()))?; + fs2::FileExt::lock_exclusive(&lock) + .with_context(|| format!("failed to lock {}", lock_path.display()))?; + let result = self.open_database().and_then(|database| action(&database)); + fs2::FileExt::unlock(&lock) + .with_context(|| format!("failed to unlock {}", lock_path.display()))?; + result + } + + fn lock_path(&self) -> PathBuf { + let mut lock_name = self + .path + .file_name() + .map(|value| value.to_os_string()) + .unwrap_or_else(|| "cultcache.cc".into()); + lock_name.push(".lock"); + self.path.with_file_name(lock_name) + } + + pub fn compare_and_swap_entry( + &self, + expected: &CultCacheEnvelope, + replacement: CultCacheEnvelope, + ) -> Result { + if entry_id(expected) != entry_id(&replacement) { + return Err(anyhow!("entry CAS replacement must preserve identity")); + } + self.with_database(|database| { + let write = database.begin_write()?; + let matched = { + let mut table = write.open_table(REDB_ENVELOPES)?; + if read_redb_entry(&table, expected)? != Some(expected.clone()) { + false + } else { + insert_redb_entry(&mut table, &replacement)?; + true + } + }; + if matched { + write.commit()?; + } else { + write.abort()?; + } + Ok(matched) + }) + } + + pub fn insert_entry_if_absent(&self, entry: CultCacheEnvelope) -> Result { + self.with_database(|database| { + let write = database.begin_write()?; + let inserted = { + let mut table = write.open_table(REDB_ENVELOPES)?; + let key = redb_identity(&entry)?; + if table.get(key.as_slice())?.is_some() { + false + } else { + insert_redb_entry(&mut table, &entry)?; + true + } + }; + if inserted { + write.commit()?; + } else { + write.abort()?; + } + Ok(inserted) + }) + } + + pub fn compare_and_swap_batch( + &self, + expected: &[CultCacheEnvelope], + replacements: Vec, + ) -> Result { + if replacements.is_empty() { + return Err(anyhow!( + "conditional batch requires a non-empty replacement set" + )); + } + let expected_ids = unique_batch_ids(expected, "expected")?; + let replacement_ids = unique_batch_ids(&replacements, "replacement")?; + if !expected_ids.is_subset(&replacement_ids) { + return Err(anyhow!( + "conditional batch must replace every expected identity" + )); + } + self.with_database(|database| { + let write = database.begin_write()?; + let matched = { + let mut table = write.open_table(REDB_ENVELOPES)?; + let mut valid = true; + for row in expected { + if read_redb_entry(&table, row)? != Some(row.clone()) { + valid = false; + break; + } + } + if valid { + for row in &replacements { + if !expected_ids.contains(&entry_id(row)) + && read_redb_entry(&table, row)?.is_some() + { + valid = false; + break; + } + } + } + if valid { + for row in &replacements { + insert_redb_entry(&mut table, row)?; + } + } + valid + }; + if matched { + write.commit()?; + } else { + write.abort()?; + } + Ok(matched) + }) + } + + pub fn append_if_snapshot_unchanged( + &self, + expected_snapshot: &[CultCacheEnvelope], + additions: Vec, + ) -> Result { + if additions.is_empty() { + return Err(anyhow!("conditional snapshot append requires additions")); + } + unique_batch_ids(expected_snapshot, "expected snapshot")?; + let addition_ids = unique_batch_ids(&additions, "snapshot additions")?; + self.with_database(|database| { + let write = database.begin_write()?; + let matched = { + let mut table = write.open_table(REDB_ENVELOPES)?; + let mut current = read_all_redb(&table)?; + let mut expected = expected_snapshot.to_vec(); + current.sort_by_key(entry_id); + expected.sort_by_key(entry_id); + let valid = current == expected + && !current + .iter() + .any(|row| addition_ids.contains(&entry_id(row))); + if valid { + for row in &additions { + insert_redb_entry(&mut table, row)?; + } + } + valid + }; + if matched { + write.commit()?; + } else { + write.abort()?; + } + Ok(matched) + }) + } + + pub fn replace_and_append_if_snapshot_unchanged( + &self, + expected_snapshot: &[CultCacheEnvelope], + replacements: Vec, + ) -> Result { + if replacements.is_empty() { + return Err(anyhow!( + "conditional snapshot replacement requires replacements" + )); + } + unique_batch_ids(expected_snapshot, "expected snapshot")?; + unique_batch_ids(&replacements, "snapshot replacements")?; + self.with_database(|database| { + let write = database.begin_write()?; + let matched = { + let mut table = write.open_table(REDB_ENVELOPES)?; + let mut current = read_all_redb(&table)?; + let mut expected = expected_snapshot.to_vec(); + current.sort_by_key(entry_id); + expected.sort_by_key(entry_id); + let valid = current == expected; + if valid { + for row in &replacements { + insert_redb_entry(&mut table, row)?; + } + } + valid + }; + if matched { + write.commit()?; + } else { + write.abort()?; + } + Ok(matched) + }) + } + + /// Atomically replaces and deletes rows only while the complete store + /// snapshot remains byte-exact. This is the compaction primitive for a + /// non-owning keyed handle: a stale reader cannot summarize one history + /// while deleting another. + pub fn replace_and_delete_if_snapshot_unchanged( + &self, + expected_snapshot: &[CultCacheEnvelope], + replacements: Vec, + deletions: &[CultCacheEnvelope], + ) -> Result { + if replacements.is_empty() || deletions.is_empty() { + return Err(anyhow!( + "conditional compaction requires replacements and deletions" + )); + } + let expected_ids = unique_batch_ids(expected_snapshot, "expected snapshot")?; + let replacement_ids = unique_batch_ids(&replacements, "replacement")?; + let deletion_ids = unique_batch_ids(deletions, "deletion")?; + if !deletion_ids.is_subset(&expected_ids) { + return Err(anyhow!( + "compaction deletion is absent from expected snapshot" + )); + } + if !deletion_ids.is_disjoint(&replacement_ids) { + return Err(anyhow!("compaction cannot replace and delete one identity")); + } + self.with_database(|database| { + let write = database.begin_write()?; + let matched = { + let mut table = write.open_table(REDB_ENVELOPES)?; + let mut current = read_all_redb(&table)?; + let mut expected = expected_snapshot.to_vec(); + current.sort_by_key(entry_id); + expected.sort_by_key(entry_id); + let mut valid = current == expected; + if valid { + for row in &replacements { + if !expected_ids.contains(&entry_id(row)) + && read_redb_entry(&table, row)?.is_some() + { + valid = false; + break; + } + } + } + if valid { + for identity in deletion_ids { + let key = rmp_serde::to_vec(&identity) + .context("failed to encode CultCache identity")?; + table.remove(key.as_slice())?; + } + for row in &replacements { + insert_redb_entry(&mut table, row)?; + } + } + valid + }; + if matched { + write.commit()?; + } else { + write.abort()?; + } + Ok(matched) + }) + } + + pub fn delete_batch_if_unchanged(&self, expected: &[CultCacheEnvelope]) -> Result { + if expected.is_empty() { + return Err(anyhow!( + "conditional delete requires a non-empty expected set" + )); + } + unique_batch_ids(expected, "delete expected")?; + self.with_database(|database| { + let write = database.begin_write()?; + let matched = { + let mut table = write.open_table(REDB_ENVELOPES)?; + let mut valid = true; + for row in expected { + if read_redb_entry(&table, row)? != Some(row.clone()) { + valid = false; + break; + } + } + if valid { + for row in expected { + let key = redb_identity(row)?; + table.remove(key.as_slice())?; + } + } + valid + }; + if matched { + write.commit()?; + } else { + write.abort()?; + } + Ok(matched) + }) + } +} + +struct OwnedRedbInner { + database: Database, + _owner_lock: File, + file_identity: String, +} + +/// A pinned redb store for one long-lived service owner. Unlike the transient +/// redb store, this handle holds the CultCache external lock, an open file +/// handle, and the redb database for its entire lifetime. Clones share that +/// exact ownership authority. +#[derive(Clone)] +pub struct OwnedRedbMessagePackBackingStore { + path: PathBuf, + inner: Arc, +} + +impl std::fmt::Debug for OwnedRedbMessagePackBackingStore { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter + .debug_struct("OwnedRedbMessagePackBackingStore") + .field("path", &self.path) + .field("file_identity", &self.inner.file_identity) + .finish_non_exhaustive() + } +} + +impl OwnedRedbMessagePackBackingStore { + pub fn new(path: impl Into) -> Result { + let path = path.into(); + if let Some(parent) = path + .parent() + .filter(|parent| !parent.as_os_str().is_empty()) + { + fs::create_dir_all(parent) + .with_context(|| format!("failed to create {}", parent.display()))?; + } + let lock_path = redb_lock_path(&path); + let owner_lock = OpenOptions::new() + .create(true) + .read(true) + .truncate(false) + .write(true) + .open(&lock_path) + .with_context(|| format!("failed to open {}", lock_path.display()))?; + fs2::FileExt::try_lock_exclusive(&owner_lock).with_context(|| { + format!( + "redb CultCache {} already has an active owner", + path.display() + ) + })?; + + // Give redb ownership of the already pinned file, structurally closing + // path substitution during database creation. The post-open identity + // comparison separately verifies that the pathname still names it. + let database_file = OpenOptions::new() + .create(true) + .read(true) + .truncate(false) + .write(true) + .open(&path) + .with_context(|| format!("failed to pin redb CultCache {}", path.display()))?; + let held_identity = file_identity_from_file(&database_file)?; + let database = Database::builder() + .create_file(database_file) + .with_context(|| format!("failed to open redb CultCache {}", path.display()))?; + let path_identity_file = File::open(&path)?; + let path_identity = file_identity_from_file(&path_identity_file)?; + if held_identity != path_identity { + bail!( + "redb CultCache path identity changed while opening: held {held_identity}, path {path_identity}" + ); + } + let write = database.begin_write()?; + { + write.open_table(REDB_ENVELOPES)?; + } + write.commit()?; + Ok(Self { + path, + inner: Arc::new(OwnedRedbInner { + database, + _owner_lock: owner_lock, + file_identity: held_identity, + }), + }) + } + + pub fn path(&self) -> &Path { + &self.path + } + + pub fn file_identity(&self) -> &str { + &self.inner.file_identity + } + + pub fn require_file_identity(&self, expected: &str) -> Result<()> { + if expected != self.file_identity() { + bail!( + "redb CultCache file identity mismatch: expected {expected}, owned {}", + self.file_identity() + ); + } + Ok(()) + } + + pub fn validate_path_identity(&self) -> Result<()> { + let current_file = File::open(&self.path) + .with_context(|| format!("owned redb path {} is missing", self.path.display()))?; + let current = file_identity_from_file(¤t_file)?; + self.require_file_identity(¤t).with_context(|| { + format!( + "owned redb path {} no longer names the pinned file", + self.path.display() + ) + }) + } + + pub fn compare_and_swap_entry( + &self, + expected: &CultCacheEnvelope, + replacement: CultCacheEnvelope, + ) -> Result { + if entry_id(expected) != entry_id(&replacement) { + return Err(anyhow!("entry CAS replacement must preserve identity")); + } + let write = self.inner.database.begin_write()?; + let matched = { + let mut table = write.open_table(REDB_ENVELOPES)?; + if read_redb_entry(&table, expected)? != Some(expected.clone()) { + false + } else { + insert_redb_entry(&mut table, &replacement)?; + true + } + }; + if matched { + write.commit()?; + } else { + write.abort()?; + } + Ok(matched) + } + + pub fn insert_entry_if_absent(&self, entry: CultCacheEnvelope) -> Result { + let write = self.inner.database.begin_write()?; + let inserted = { + let mut table = write.open_table(REDB_ENVELOPES)?; + let key = redb_identity(&entry)?; + if table.get(key.as_slice())?.is_some() { + false + } else { + insert_redb_entry(&mut table, &entry)?; + true + } + }; + if inserted { + write.commit()?; + } else { + write.abort()?; + } + Ok(inserted) + } + + pub fn compare_and_swap_batch( + &self, + expected: &[CultCacheEnvelope], + replacements: Vec, + ) -> Result { + if replacements.is_empty() { + return Err(anyhow!( + "conditional batch requires a non-empty replacement set" + )); + } + let expected_ids = unique_batch_ids(expected, "expected")?; + let replacement_ids = unique_batch_ids(&replacements, "replacement")?; + if !expected_ids.is_subset(&replacement_ids) { + return Err(anyhow!( + "conditional batch must replace every expected identity" + )); + } + let write = self.inner.database.begin_write()?; + let matched = { + let mut table = write.open_table(REDB_ENVELOPES)?; + let mut valid = true; + for row in expected { + if read_redb_entry(&table, row)? != Some(row.clone()) { + valid = false; + break; + } + } + if valid { + for row in &replacements { + if !expected_ids.contains(&entry_id(row)) + && read_redb_entry(&table, row)?.is_some() + { + valid = false; + break; + } + } + } + if valid { + for row in &replacements { + insert_redb_entry(&mut table, row)?; + } + } + valid + }; + if matched { + write.commit()?; + } else { + write.abort()?; + } + Ok(matched) + } + + pub fn append_if_snapshot_unchanged( + &self, + expected_snapshot: &[CultCacheEnvelope], + additions: Vec, + ) -> Result { + if additions.is_empty() { + return Err(anyhow!("conditional snapshot append requires additions")); + } + unique_batch_ids(expected_snapshot, "expected snapshot")?; + let addition_ids = unique_batch_ids(&additions, "snapshot additions")?; + let write = self.inner.database.begin_write()?; + let matched = { + let mut table = write.open_table(REDB_ENVELOPES)?; + let mut current = read_all_redb(&table)?; + let mut expected = expected_snapshot.to_vec(); + current.sort_by_key(entry_id); + expected.sort_by_key(entry_id); + let valid = current == expected + && !current + .iter() + .any(|row| addition_ids.contains(&entry_id(row))); + if valid { + for row in &additions { + insert_redb_entry(&mut table, row)?; + } + } + valid + }; + if matched { + write.commit()?; + } else { + write.abort()?; + } + Ok(matched) + } + + pub fn replace_and_append_if_snapshot_unchanged( + &self, + expected_snapshot: &[CultCacheEnvelope], + replacements: Vec, + ) -> Result { + if replacements.is_empty() { + return Err(anyhow!( + "conditional snapshot replacement requires replacements" + )); + } + unique_batch_ids(expected_snapshot, "expected snapshot")?; + unique_batch_ids(&replacements, "snapshot replacements")?; + let write = self.inner.database.begin_write()?; + let matched = { + let mut table = write.open_table(REDB_ENVELOPES)?; + let mut current = read_all_redb(&table)?; + let mut expected = expected_snapshot.to_vec(); + current.sort_by_key(entry_id); + expected.sort_by_key(entry_id); + let valid = current == expected; + if valid { + for row in &replacements { + insert_redb_entry(&mut table, row)?; + } + } + valid + }; + if matched { + write.commit()?; + } else { + write.abort()?; + } + Ok(matched) + } + + pub fn delete_batch_if_unchanged(&self, expected: &[CultCacheEnvelope]) -> Result { + if expected.is_empty() { + return Err(anyhow!( + "conditional delete requires a non-empty expected set" + )); + } + let expected_ids = unique_batch_ids(expected, "delete expected")?; + let write = self.inner.database.begin_write()?; + let matched = { + let mut table = write.open_table(REDB_ENVELOPES)?; + let mut valid = true; + for row in expected { + if read_redb_entry(&table, row)? != Some(row.clone()) { + valid = false; + break; + } + } + if valid { + for identity in expected_ids { + let key = rmp_serde::to_vec(&identity) + .context("failed to encode CultCache identity")?; + table.remove(key.as_slice())?; + } + } + valid + }; + if matched { + write.commit()?; + } else { + write.abort()?; + } + Ok(matched) + } + + /// Atomically replaces and deletes rows only while the complete store + /// snapshot remains byte-exact. This is the compaction primitive: a stale + /// reader cannot summarize one history while deleting another. + pub fn replace_and_delete_if_snapshot_unchanged( + &self, + expected_snapshot: &[CultCacheEnvelope], + replacements: Vec, + deletions: &[CultCacheEnvelope], + ) -> Result { + if replacements.is_empty() || deletions.is_empty() { + return Err(anyhow!( + "conditional compaction requires replacements and deletions" + )); + } + let expected_ids = unique_batch_ids(expected_snapshot, "expected snapshot")?; + let replacement_ids = unique_batch_ids(&replacements, "replacement")?; + let deletion_ids = unique_batch_ids(deletions, "deletion")?; + if !deletion_ids.is_subset(&expected_ids) { + return Err(anyhow!( + "compaction deletion is absent from expected snapshot" + )); + } + if !deletion_ids.is_disjoint(&replacement_ids) { + return Err(anyhow!("compaction cannot replace and delete one identity")); + } + let write = self.inner.database.begin_write()?; + let matched = { + let mut table = write.open_table(REDB_ENVELOPES)?; + let mut current = read_all_redb(&table)?; + let mut expected = expected_snapshot.to_vec(); + current.sort_by_key(entry_id); + expected.sort_by_key(entry_id); + let mut valid = current == expected; + if valid { + for row in &replacements { + if !expected_ids.contains(&entry_id(row)) + && read_redb_entry(&table, row)?.is_some() + { + valid = false; + break; + } + } + } + if valid { + for identity in deletion_ids { + let key = rmp_serde::to_vec(&identity) + .context("failed to encode CultCache identity")?; + table.remove(key.as_slice())?; + } + for row in &replacements { + insert_redb_entry(&mut table, row)?; + } + } + valid + }; + if matched { + write.commit()?; + } else { + write.abort()?; + } + Ok(matched) + } +} + +impl CacheBackingStore for OwnedRedbMessagePackBackingStore { + fn pull_all(&self) -> Result> { + let read = self.inner.database.begin_read()?; + let table = read.open_table(REDB_ENVELOPES)?; + read_all_redb(&table) + } + + fn push(&mut self, entry: &CultCacheEnvelope) -> Result<()> { + let write = self.inner.database.begin_write()?; + { + let mut table = write.open_table(REDB_ENVELOPES)?; + insert_redb_entry(&mut table, entry)?; + } + write.commit()?; + Ok(()) + } + + fn delete(&mut self, entry: &CultCacheEnvelope) -> Result<()> { + let write = self.inner.database.begin_write()?; + { + let mut table = write.open_table(REDB_ENVELOPES)?; + let key = redb_identity(entry)?; + table.remove(key.as_slice())?; + } + write.commit()?; + Ok(()) + } + + fn push_all(&mut self, entries: &[CultCacheEnvelope], _options: PushAllOptions) -> Result<()> { + unique_batch_ids(entries, "push all")?; + let write = self.inner.database.begin_write()?; + { + let mut table = write.open_table(REDB_ENVELOPES)?; + let keys = table + .iter()? + .map(|row| Ok(row?.0.value().to_vec())) + .collect::>>()?; + for key in keys { + table.remove(key.as_slice())?; + } + for entry in entries { + insert_redb_entry(&mut table, entry)?; + } + } + write.commit()?; + Ok(()) + } +} + +fn redb_lock_path(path: &Path) -> PathBuf { + let mut lock_name = path + .file_name() + .map(|value| value.to_os_string()) + .unwrap_or_else(|| "cultcache.cc".into()); + lock_name.push(".lock"); + path.with_file_name(lock_name) +} + +#[cfg(unix)] +fn file_identity_from_file(file: &File) -> Result { + use std::os::unix::fs::MetadataExt; + let metadata = file.metadata()?; + Ok(format!( + "unix:{:016x}:{:016x}", + metadata.dev(), + metadata.ino() + )) +} + +#[cfg(windows)] +fn file_identity_from_file(file: &File) -> Result { + use std::mem::zeroed; + use std::os::windows::io::AsRawHandle; + use windows_sys::Win32::Storage::FileSystem::{ + BY_HANDLE_FILE_INFORMATION, GetFileInformationByHandle, + }; + let mut information: BY_HANDLE_FILE_INFORMATION = unsafe { zeroed() }; + let success = + unsafe { GetFileInformationByHandle(file.as_raw_handle() as _, &mut information) }; + if success == 0 { + return Err(std::io::Error::last_os_error()) + .context("failed to read Windows file identity"); + } + let index = ((information.nFileIndexHigh as u64) << 32) | information.nFileIndexLow as u64; + Ok(format!( + "windows:{:08x}:{index:016x}", + information.dwVolumeSerialNumber + )) +} + +fn redb_identity(entry: &CultCacheEnvelope) -> Result> { + rmp_serde::to_vec(&entry_id(entry)).context("failed to encode CultCache identity") +} + +fn read_redb_entry( + table: &impl ReadableTable<&'static [u8], &'static [u8]>, + identity: &CultCacheEnvelope, +) -> Result> { + let key = redb_identity(identity)?; + table + .get(key.as_slice())? + .map(|value| { + rmp_serde::from_slice(value.value()).context("failed to decode redb CultCache envelope") + }) + .transpose() +} + +fn insert_redb_entry( + table: &mut redb::Table<&[u8], &[u8]>, + entry: &CultCacheEnvelope, +) -> Result<()> { + let key = redb_identity(entry)?; + let value = rmp_serde::to_vec(entry).context("failed to encode redb CultCache envelope")?; + table.insert(key.as_slice(), value.as_slice())?; + Ok(()) +} + +fn read_all_redb( + table: &impl ReadableTable<&'static [u8], &'static [u8]>, +) -> Result> { + let mut entries = table + .iter()? + .map(|row| { + let (_, value) = row?; + rmp_serde::from_slice(value.value()).context("failed to decode redb CultCache envelope") + }) + .collect::>>()?; + entries.sort_by_key(entry_id); + Ok(entries) +} + +impl CacheBackingStore for RedbMessagePackBackingStore { + fn pull_all(&self) -> Result> { + self.with_database(|database| { + let read = database.begin_read()?; + let table = read.open_table(REDB_ENVELOPES)?; + read_all_redb(&table) + }) + } + + fn push(&mut self, entry: &CultCacheEnvelope) -> Result<()> { + self.with_database(|database| { + let write = database.begin_write()?; + { + let mut table = write.open_table(REDB_ENVELOPES)?; + insert_redb_entry(&mut table, entry)?; + } + write.commit()?; + Ok(()) + }) + } + + fn delete(&mut self, entry: &CultCacheEnvelope) -> Result<()> { + self.with_database(|database| { + let write = database.begin_write()?; + { + let mut table = write.open_table(REDB_ENVELOPES)?; + let key = redb_identity(entry)?; + table.remove(key.as_slice())?; + } + write.commit()?; + Ok(()) + }) + } + + fn push_all(&mut self, entries: &[CultCacheEnvelope], _options: PushAllOptions) -> Result<()> { + unique_batch_ids(entries, "push all")?; + self.with_database(|database| { + let write = database.begin_write()?; + { + let mut table = write.open_table(REDB_ENVELOPES)?; + let keys = table + .iter()? + .map(|row| Ok(row?.0.value().to_vec())) + .collect::>>()?; + for key in keys { + table.remove(key.as_slice())?; + } + for entry in entries { + insert_redb_entry(&mut table, entry)?; + } + } + write.commit()?; + Ok(()) + }) + } +} + struct CultCacheStoreRegistration { store: Box, types: BTreeSet, @@ -331,8 +1750,7 @@ struct CultCacheStoreRegistration { pub struct CultCache { definitions: BTreeMap, - schema_name_definitions: BTreeMap, - entries: BTreeMap, + entries: BTreeMap<(String, String), CultCacheEnvelope>, stores: Vec, } @@ -340,7 +1758,6 @@ impl CultCache { pub fn new() -> Self { Self { definitions: BTreeMap::new(), - schema_name_definitions: BTreeMap::new(), entries: BTreeMap::new(), stores: Vec::new(), } @@ -360,18 +1777,7 @@ impl CultCache { T::TYPE )); } - if let Some(existing_type) = self.schema_name_definitions.get(T::SCHEMA_NAME) - && existing_type != T::TYPE - { - return Err(anyhow!( - "CultCache schema name {:?} is already registered for type {:?}", - T::SCHEMA_NAME, - existing_type - )); - } self.definitions.insert(T::TYPE.to_string(), T::SCHEMA_NAME); - self.schema_name_definitions - .insert(T::SCHEMA_NAME.to_string(), T::TYPE.to_string()); Ok(()) } @@ -379,6 +1785,10 @@ impl CultCache { self.register_entry_type::() } + pub fn registered_entry_types(&self) -> Vec { + self.definitions.keys().cloned().collect() + } + pub fn register_registry(&mut self, registry: R) -> Result<&mut Self> { registry.register_entries(self)?; Ok(self) @@ -402,26 +1812,27 @@ impl CultCache { pub fn pull_all_backing_stores(&mut self) -> Result<()> { self.entries.clear(); let known_types: BTreeSet = self.definitions.keys().cloned().collect(); - let schema_name_definitions = self.schema_name_definitions.clone(); for registration in &mut self.stores { - for mut entry in registration.store.pull_all()? { - let Some(canonical_type) = resolve_registered_type( - &known_types, - &schema_name_definitions, - &entry.r#type, - ) else { + for entry in registration.store.pull_all()? { + if !known_types.contains(&entry.r#type) { return Err(anyhow!( "No schema is registered for persisted entry type {:?}", entry.r#type )); - }; - entry.r#type = canonical_type; + } self.entries.insert(entry_id(&entry), entry); } } Ok(()) } + /// Returns the exact envelopes in the currently loaded cache image. + /// Callers that need optimistic concurrency can validate typed documents + /// and capture CAS expectations from one coherent read. + pub fn snapshot_envelopes(&self) -> Vec { + self.entries.values().cloned().collect() + } + pub fn get(&self, key: &str) -> Result> { self.require_entry_type::()?; let Some(entry) = self.entries.get(&entry_id_parts(T::TYPE, key)) else { @@ -472,32 +1883,45 @@ impl CultCache { Ok(values) } - pub fn put(&mut self, key: impl Into, value: &T) -> Result { + pub fn get_all_with_keys(&self) -> Result> { self.require_entry_type::()?; - let key = key.into(); - let payload = rmp_serde::to_vec(value).with_context(|| { - format!( - "failed to encode CultCache entry {:?} at key {:?} as {}", - T::TYPE, - key, - T::SCHEMA_NAME - ) - })?; - let parsed: T = rmp_serde::from_slice(&payload).with_context(|| { - format!( - "failed to validate CultCache entry {:?} at key {:?} as {}", - T::TYPE, - key, - T::SCHEMA_NAME - ) - })?; - let entry = CultCacheEnvelope { - key: key.clone(), - r#type: T::TYPE.to_string(), - payload, - stored_at: now_utc_second(), - schema_id: Some(T::TYPE.to_string()), - }; + let mut values = Vec::new(); + for entry in self.entries.values() { + if entry.r#type != T::TYPE { + continue; + } + values.push(( + entry.key.clone(), + rmp_serde::from_slice(&entry.payload).with_context(|| { + format!( + "failed to decode CultCache entry {:?} at key {:?} as {}", + T::TYPE, + entry.key, + T::SCHEMA_NAME + ) + })?, + )); + } + Ok(values) + } + + pub fn soa(&self) -> Result> { + let keyed_rows = self.get_all_with_keys::()?; + let (keys, documents): (Vec<_>, Vec<_>) = keyed_rows.into_iter().unzip(); + let columns = T::soa_columns(&documents) + .into_iter() + .map(|(name, values)| (name.to_string(), values)) + .collect(); + Ok(CultSoaTable { + keys, + documents, + columns, + _document: PhantomData, + }) + } + + pub fn put(&mut self, key: impl Into, value: &T) -> Result { + let (entry, parsed) = self.prepare_entry(key, value)?; let route = self.resolve_route_indices(T::TYPE); let Some(primary_index) = route.first().copied() else { return Err(anyhow!( @@ -513,7 +1937,176 @@ impl CultCache { Ok(parsed) } + pub fn prepare_entry( + &self, + key: impl Into, + value: &T, + ) -> Result<(CultCacheEnvelope, T)> { + self.require_entry_type::()?; + let key = key.into(); + let payload = rmp_serde::to_vec(value).with_context(|| { + format!( + "failed to encode CultCache entry {:?} at key {:?} as {}", + T::TYPE, + key, + T::SCHEMA_NAME + ) + })?; + self.finish_prepared_entry::(key, payload) + } + + /// Prepares a typed entry while encoding ordinary nested structs as + /// MessagePack maps. DatabaseEntry itself remains the stable numeric-slot + /// tuple; named nested fields prevent serde's omitted optional fields from + /// shifting later values into the wrong positions. + pub fn prepare_entry_named( + &self, + key: impl Into, + value: &T, + ) -> Result<(CultCacheEnvelope, T)> { + self.require_entry_type::()?; + let key = key.into(); + let payload = rmp_serde::to_vec_named(value).with_context(|| { + format!( + "failed to encode named CultCache entry {:?} at key {:?} as {}", + T::TYPE, + key, + T::SCHEMA_NAME + ) + })?; + self.finish_prepared_entry::(key, payload) + } + + fn finish_prepared_entry( + &self, + key: String, + payload: Vec, + ) -> Result<(CultCacheEnvelope, T)> { + let parsed: T = rmp_serde::from_slice(&payload).with_context(|| { + format!( + "failed to validate CultCache entry {:?} at key {:?} as {}", + T::TYPE, + key, + T::SCHEMA_NAME + ) + })?; + let entry = CultCacheEnvelope { + key: key.clone(), + r#type: T::TYPE.to_string(), + payload, + stored_at: now_utc_second(), + schema_id: Some(T::TYPE.to_string()), + }; + Ok((entry, parsed)) + } + + pub fn put_prepared_batch(&mut self, staged: Vec) -> Result<()> { + if staged.is_empty() { + return Err(anyhow!("CultCache batch must contain at least one entry")); + } + let mut store_index = None; + for entry in staged.iter().chain(self.entries.values()) { + if !self.definitions.contains_key(&entry.r#type) { + return Err(anyhow!( + "CultCache batch entry type {:?} is not registered", + entry.r#type + )); + } + let route = self.resolve_route_indices(&entry.r#type); + if route.len() != 1 { + return Err(anyhow!( + "CultCache atomic batch requires exactly one backing-store route for type {:?}, found {}", + entry.r#type, + route.len() + )); + } + match store_index { + Some(expected) if expected != route[0] => { + return Err(anyhow!("CultCache atomic batch cannot span backing stores")); + } + None => store_index = Some(route[0]), + _ => {} + } + } + let store_index = store_index.expect("non-empty batch establishes a store route"); + let mut next = self.entries.clone(); + for entry in staged { + next.insert(entry_id(&entry), entry); + } + let snapshot: Vec<_> = next.values().cloned().collect(); + self.stores[store_index] + .store + .push_all(&snapshot, PushAllOptions::default())?; + self.entries = next; + Ok(()) + } + pub fn put_envelope(&mut self, entry: CultCacheEnvelope) -> Result { + let parsed = self.validate_envelope::(&entry)?; + let route = self.resolve_route_indices(T::TYPE); + let Some(primary_index) = route.first().copied() else { + return Err(anyhow!( + "No backing store is registered for entry type {:?}", + T::TYPE + )); + }; + self.stores[primary_index].store.push(&entry)?; + for mirror_index in route.iter().skip(1).copied() { + self.stores[mirror_index].store.push(&entry)?; + } + self.entries.insert(entry_id(&entry), entry); + Ok(parsed) + } + + /// Publishes an envelope for a registered dynamic document type without + /// claiming compile-time knowledge of its payload schema. This is the + /// CultMesh/schema-registry boundary: callers own payload validation before + /// admission; CultCache still enforces registered type, identity, timestamp, + /// routing, and persistence. + pub fn put_raw_envelope(&mut self, entry: CultCacheEnvelope) -> Result<()> { + if !self.definitions.contains_key(&entry.r#type) { + return Err(anyhow!( + "No entry type registered for CultCache envelope type {:?}", + entry.r#type + )); + } + if entry.key.trim().is_empty() { + return Err(anyhow!( + "CultCache envelope keys for type {:?} must be non-empty", + entry.r#type + )); + } + if entry.stored_at.trim().is_empty() { + return Err(anyhow!( + "CultCache envelope stored_at for type {:?} must be non-empty", + entry.r#type + )); + } + let route = self.resolve_route_indices(&entry.r#type); + let Some(primary_index) = route.first().copied() else { + return Err(anyhow!( + "No backing store is registered for entry type {:?}", + entry.r#type + )); + }; + self.stores[primary_index].store.push(&entry)?; + for mirror_index in route.iter().skip(1).copied() { + self.stores[mirror_index].store.push(&entry)?; + } + self.entries.insert(entry_id(&entry), entry); + Ok(()) + } + + /// Validates and admits an existing envelope into this cache image without + /// publishing it to any backing store. This is the typed read primitive for + /// owner-filtered views over a shared polymorphic store. + pub fn load_envelope(&mut self, entry: CultCacheEnvelope) -> Result { + let parsed = self.validate_envelope::(&entry)?; + self.entries.insert(entry_id(&entry), entry); + Ok(parsed) + } + + fn validate_envelope(&self, entry: &CultCacheEnvelope) -> Result { self.require_entry_type::()?; if entry.r#type != T::TYPE { return Err(anyhow!( @@ -535,27 +2128,14 @@ impl CultCache { )); } - let parsed: T = rmp_serde::from_slice(&entry.payload).with_context(|| { + rmp_serde::from_slice(&entry.payload).with_context(|| { format!( "failed to validate CultCache envelope {:?} at key {:?} as {}", T::TYPE, entry.key, T::SCHEMA_NAME ) - })?; - let route = self.resolve_route_indices(T::TYPE); - let Some(primary_index) = route.first().copied() else { - return Err(anyhow!( - "No backing store is registered for entry type {:?}", - T::TYPE - )); - }; - self.stores[primary_index].store.push(&entry)?; - for mirror_index in route.iter().skip(1).copied() { - self.stores[mirror_index].store.push(&entry)?; - } - self.entries.insert(entry_id(&entry), entry); - Ok(parsed) + }) } pub fn update(&mut self, key: &str, updater: F) -> Result @@ -592,6 +2172,25 @@ impl CultCache { self.entries.values().cloned().collect() } + pub fn snapshot_soa(&self) -> CultCacheSoaTable { + CultCacheSoaTable::from_envelopes(self.snapshot()) + } + + pub fn load_soa(&mut self, table: CultCacheSoaTable) -> Result<()> { + let known_types: BTreeSet = self.definitions.keys().cloned().collect(); + self.entries.clear(); + for entry in table.into_envelopes()? { + if !known_types.contains(&entry.r#type) { + return Err(anyhow!( + "No schema is registered for SoA entry type {:?}", + entry.r#type + )); + } + self.entries.insert(entry_id(&entry), entry); + } + Ok(()) + } + fn require_entry_type(&self) -> Result<()> { match self.definitions.get(T::TYPE) { Some(schema_name) if *schema_name == T::SCHEMA_NAME => Ok(()), @@ -620,7 +2219,6 @@ impl CultCache { .filter_map(|(index, registration)| registration.types.is_empty().then_some(index)) .collect() } - } impl Default for CultCache { @@ -629,47 +2227,40 @@ impl Default for CultCache { } } -fn entry_id(entry: &CultCacheEnvelope) -> String { +fn entry_id(entry: &CultCacheEnvelope) -> (String, String) { entry_id_parts(&entry.r#type, &entry.key) } -fn entry_id_parts(r#type: &str, key: &str) -> String { - format!("{type}::{key}", type = r#type) -} - -fn resolve_registered_type( - known_types: &BTreeSet, - schema_name_definitions: &BTreeMap, - persisted_type: &str, -) -> Option { - if known_types.contains(persisted_type) { - return Some(persisted_type.to_string()); - } - - schema_name_definitions.get(persisted_type).cloned() +fn entry_id_parts(r#type: &str, key: &str) -> (String, String) { + (r#type.to_string(), key.to_string()) } fn now_utc_second() -> String { chrono::Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true) } -fn encode_store_snapshot(entries: &[CultCacheEnvelope]) -> PersistedStoreSnapshot { - let mut schema_names = BTreeSet::::new(); +fn encode_store_snapshot(entries: &[CultCacheEnvelope]) -> Result { + let mut schema_types = BTreeMap::::new(); for entry in entries { - schema_names.insert( - entry - .schema_id - .clone() - .unwrap_or_else(|| entry.r#type.clone()), - ); + let schema_id = entry + .schema_id + .clone() + .unwrap_or_else(|| entry.r#type.clone()); + if let Some(existing_type) = schema_types.insert(schema_id.clone(), entry.r#type.clone()) { + ensure!( + existing_type == entry.r#type, + "CultCache schema {schema_id:?} cannot identify both {existing_type:?} and {:?}", + entry.r#type + ); + } } - let catalog = schema_names + let catalog = schema_types .into_iter() - .map(|schema_id| { + .map(|(schema_id, document_type)| { PersistedSchemaCatalogEntry( schema_id.clone(), - schema_id.clone(), + document_type, format!("{schema_id}.v1"), schema_id.clone(), format!( @@ -697,7 +2288,11 @@ fn encode_store_snapshot(entries: &[CultCacheEnvelope]) -> PersistedStoreSnapsho }) .collect(); - PersistedStoreSnapshot("cultcache.store.v1".to_string(), catalog, records) + Ok(PersistedStoreSnapshot( + "cultcache.store.v1".to_string(), + catalog, + records, + )) } fn decode_store_snapshot(bytes: &[u8]) -> Result> { @@ -716,25 +2311,13 @@ fn decode_store_snapshot(bytes: &[u8]) -> Result> { .2 .into_iter() .map(|record| { - let r#type = match catalog.get(&record.1) { - Some(schema_name) => schema_name.clone(), - None => { - let schema_version = infer_schema_version_from_payload(&record.3).ok_or_else(|| { - anyhow!( - "CultCache record {:?} references missing schema {:?}", - record.0, - record.1 - ) - })?; - infer_schema_name(&schema_version).ok_or_else(|| { - anyhow!( - "CultCache record {:?} references missing schema {:?}", - record.0, - record.1 - ) - })? - } - }; + let r#type = catalog.get(&record.1).cloned().ok_or_else(|| { + anyhow!( + "CultCache record {:?} references missing schema {:?}", + record.0, + record.1 + ) + })?; Ok(CultCacheEnvelope { key: record.0, r#type, @@ -746,68 +2329,6 @@ fn decode_store_snapshot(bytes: &[u8]) -> Result> { .collect() } -fn infer_schema_version_from_payload(payload: &[u8]) -> Option { - let mut offset = 0usize; - read_array_header(payload, &mut offset)?; - read_string(payload, &mut offset) -} - -fn read_array_header(payload: &[u8], offset: &mut usize) -> Option { - let marker = *payload.get(*offset)?; - *offset += 1; - match marker { - 0x90..=0x9f => Some((marker & 0x0f) as u32), - 0xdc => { - let bytes = payload.get(*offset..(*offset + 2))?; - *offset += 2; - Some(u16::from_be_bytes([bytes[0], bytes[1]]) as u32) - } - 0xdd => { - let bytes = payload.get(*offset..(*offset + 4))?; - *offset += 4; - Some(u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]])) - } - _ => None, - } -} - -fn read_string(payload: &[u8], offset: &mut usize) -> Option { - let marker = *payload.get(*offset)?; - *offset += 1; - let length = match marker { - 0xa0..=0xbf => (marker & 0x1f) as usize, - 0xd9 => { - let length = *payload.get(*offset)? as usize; - *offset += 1; - length - } - 0xda => { - let bytes = payload.get(*offset..(*offset + 2))?; - *offset += 2; - u16::from_be_bytes([bytes[0], bytes[1]]) as usize - } - 0xdb => { - let bytes = payload.get(*offset..(*offset + 4))?; - *offset += 4; - u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) as usize - } - _ => return None, - }; - - let bytes = payload.get(*offset..(*offset + length))?; - std::str::from_utf8(bytes).ok().map(str::to_string) -} - -fn infer_schema_name(schema_version: &str) -> Option { - let marker = schema_version.rfind(".v")?; - let version = schema_version.get((marker + 2)..)?; - if marker == 0 || version.is_empty() || !version.bytes().all(|value| value.is_ascii_digit()) { - return None; - } - - Some(schema_version[..marker].to_string()) -} - fn escape_json_string(value: &str) -> String { value.replace('\\', "\\\\").replace('"', "\\\"") } @@ -816,188 +2337,108 @@ fn temporary_path_for(path: &Path) -> PathBuf { let mut file_name = path .file_name() .map(|value| value.to_os_string()) - .unwrap_or_else(|| "cultcache.msgpack".into()); + .unwrap_or_else(|| "cultcache.cc".into()); file_name.push(format!(".{}.tmp", uuid::Uuid::new_v4())); path.with_file_name(file_name) } -fn is_canonical_candidate_uuid(value: &[u8]) -> bool { - if value.len() != 36 || !value.is_ascii() { - return false; - } - let Ok(value) = std::str::from_utf8(value) else { - return false; +fn remove_abandoned_staging_files(destination: &Path) -> Result<()> { + let Some(parent) = destination.parent() else { + return Ok(()); }; - let Ok(uuid) = uuid::Uuid::parse_str(value) else { - return false; + let Some(destination_name) = destination.file_name().and_then(|value| value.to_str()) else { + return Ok(()); }; - uuid.hyphenated().to_string() == value -} - -#[cfg(unix)] -fn is_owned_candidate_name(target_name: &OsStr, candidate_name: &OsStr) -> bool { - use std::os::unix::ffi::OsStrExt; - - let target = target_name.as_bytes(); - let candidate = candidate_name.as_bytes(); - let Some(remainder) = candidate.strip_prefix(target) else { - return false; - }; - let Some(remainder) = remainder.strip_prefix(b".") else { - return false; - }; - let Some(uuid) = remainder.strip_suffix(b".tmp") else { - return false; - }; - is_canonical_candidate_uuid(uuid) -} - -#[cfg(windows)] -fn is_owned_candidate_name(target_name: &OsStr, candidate_name: &OsStr) -> bool { - use std::os::windows::ffi::OsStrExt; - - let target = target_name.encode_wide().collect::>(); - let candidate = candidate_name.encode_wide().collect::>(); - let Some(remainder) = candidate.strip_prefix(target.as_slice()) else { - return false; - }; - let Some(remainder) = remainder.strip_prefix(&[b'.' as u16]) else { - return false; - }; - let suffix = [b'.' as u16, b't' as u16, b'm' as u16, b'p' as u16]; - let Some(uuid_wide) = remainder.strip_suffix(&suffix) else { - return false; - }; - let Ok(uuid) = uuid_wide - .iter() - .map(|value| u8::try_from(*value)) - .collect::, _>>() - else { - return false; - }; - is_canonical_candidate_uuid(&uuid) -} - -#[cfg(not(any(unix, windows)))] -fn is_owned_candidate_name(target_name: &OsStr, candidate_name: &OsStr) -> bool { - let (Some(target), Some(candidate)) = (target_name.to_str(), candidate_name.to_str()) else { - return false; - }; - let Some(remainder) = candidate.strip_prefix(target) else { - return false; - }; - let Some(remainder) = remainder.strip_prefix('.') else { - return false; - }; - let Some(uuid) = remainder.strip_suffix(".tmp") else { - return false; - }; - is_canonical_candidate_uuid(uuid.as_bytes()) -} - -fn stale_candidate_paths(path: &Path) -> Result> { - let parent = path.parent().unwrap_or_else(|| Path::new(".")); - if !parent.exists() { - return Ok(Vec::new()); - } - let target_name = path - .file_name() - .unwrap_or_else(|| OsStr::new("cultcache.msgpack")); - let mut candidates = Vec::new(); - for entry in - fs::read_dir(parent).with_context(|| format!("failed to inspect {}", parent.display()))? - { - let entry = entry.with_context(|| format!("failed to inspect {}", parent.display()))?; - let name = entry.file_name(); - if is_owned_candidate_name(target_name, &name) { - candidates.push(entry.path()); + let prefix = format!("{destination_name}."); + for entry in fs::read_dir(parent).with_context(|| { + format!( + "failed to inspect {} for abandoned staging files", + parent.display() + ) + })? { + let entry = entry?; + let Some(name) = entry.file_name().to_str().map(str::to_owned) else { + continue; + }; + let Some(candidate) = name + .strip_prefix(&prefix) + .and_then(|value| value.strip_suffix(".tmp")) + else { + continue; + }; + if uuid::Uuid::parse_str(candidate).is_err() || !entry.file_type()?.is_file() { + continue; } - } - Ok(candidates) -} - -fn remove_stale_candidates(path: &Path) -> Result<()> { - for candidate in stale_candidate_paths(path)? { - fs::remove_file(&candidate) - .with_context(|| format!("failed to remove stale candidate {}", candidate.display()))?; + fs::remove_file(entry.path()).with_context(|| { + format!( + "failed to remove abandoned staging file {}", + entry.path().display() + ) + })?; } Ok(()) } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -enum SnapshotReplacementStage { - CandidateSynced, - TargetReplaced, -} - #[cfg(unix)] -fn replace_file(candidate: &Path, target: &Path) -> Result<()> { - fs::rename(candidate, target).with_context(|| { +fn replace_file_atomically(staged: &Path, destination: &Path) -> Result<()> { + fs::rename(staged, destination).with_context(|| { format!( "failed to atomically replace {} with {}", - target.display(), - candidate.display() + destination.display(), + staged.display() ) }) } #[cfg(windows)] -fn replace_file(candidate: &Path, target: &Path) -> Result<()> { +fn replace_file_atomically(staged: &Path, destination: &Path) -> Result<()> { use std::os::windows::ffi::OsStrExt; use windows_sys::Win32::Storage::FileSystem::{ MOVEFILE_REPLACE_EXISTING, MOVEFILE_WRITE_THROUGH, MoveFileExW, }; - let candidate_wide = candidate + let staged_wide = staged .as_os_str() .encode_wide() .chain(std::iter::once(0)) .collect::>(); - let target_wide = target + let destination_wide = destination .as_os_str() .encode_wide() .chain(std::iter::once(0)) .collect::>(); - let replaced = unsafe { + let success = unsafe { MoveFileExW( - candidate_wide.as_ptr(), - target_wide.as_ptr(), + staged_wide.as_ptr(), + destination_wide.as_ptr(), MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH, ) }; - if replaced == 0 { + if success == 0 { return Err(std::io::Error::last_os_error()).with_context(|| { format!( "failed to atomically replace {} with {}", - target.display(), - candidate.display() + destination.display(), + staged.display() ) }); } Ok(()) } -#[cfg(not(any(unix, windows)))] -fn replace_file(candidate: &Path, target: &Path) -> Result<()> { - fs::rename(candidate, target).with_context(|| { - format!( - "failed to replace {} with {}", - target.display(), - candidate.display() - ) - }) -} - #[cfg(unix)] -fn sync_parent_directory(parent: &Path) -> Result<()> { +fn sync_parent_directory(path: &Path) -> Result<()> { + let Some(parent) = path.parent() else { + return Ok(()); + }; File::open(parent) - .with_context(|| format!("failed to open directory {}", parent.display()))? - .sync_all() - .with_context(|| format!("failed to flush directory {}", parent.display())) + .and_then(|directory| directory.sync_all()) + .with_context(|| format!("failed to sync {}", parent.display())) } -#[cfg(not(unix))] -fn sync_parent_directory(_parent: &Path) -> Result<()> { +#[cfg(windows)] +fn sync_parent_directory(_path: &Path) -> Result<()> { + // MoveFileExW with MOVEFILE_WRITE_THROUGH owns publication durability. Ok(()) } @@ -1005,6 +2446,37 @@ fn sync_parent_directory(_parent: &Path) -> Result<()> { mod tests { use super::*; use pretty_assertions::assert_eq; + use std::sync::Arc; + use std::sync::atomic::{AtomicBool, Ordering}; + use std::sync::mpsc; + use std::time::Duration; + + struct RefusingBatchStore { + inner: SingleFileMessagePackBackingStore, + refuse_batch: Arc, + } + + impl CacheBackingStore for RefusingBatchStore { + fn pull_all(&self) -> Result> { + self.inner.pull_all() + } + fn push(&mut self, entry: &CultCacheEnvelope) -> Result<()> { + self.inner.push(entry) + } + fn delete(&mut self, entry: &CultCacheEnvelope) -> Result<()> { + self.inner.delete(entry) + } + fn push_all( + &mut self, + entries: &[CultCacheEnvelope], + options: PushAllOptions, + ) -> Result<()> { + if self.refuse_batch.load(Ordering::SeqCst) { + return Err(anyhow!("injected batch refusal")); + } + self.inner.push_all(entries, options) + } + } #[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] #[cultcache(type = "settings")] @@ -1025,279 +2497,111 @@ mod tests { } #[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] - #[cultcache(type = "runtime-policy", schema = "tests.schema_stamped_entry")] - struct SchemaStamped { - #[cultcache(key = 0)] - schema_version: String, - #[cultcache(key = 1)] - name: String, - #[cultcache(key = 2)] - value: String, + #[cultcache(type = "binary-record")] + struct BinaryRecord { + #[cultcache(key = 0, bytes)] + required: Vec, + #[cultcache(key = 1, bytes, default)] + optional: Vec, } + #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] + struct NestedOptionalValue { + label: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + symbol: Option, + } + + #[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] + #[cultcache(type = "nested-note")] + struct NestedNote { + #[cultcache(key = 0)] + value: NestedOptionalValue, + } + + cultcache_soa!(Settings { + "theme" => |row: &Settings| row.theme.clone(), + "retries" => |row: &Settings| row.retries, + }); + cultcache_registry!(TestEntries { Settings, Note }); - fn test_envelope(value: &str) -> CultCacheEnvelope { - CultCacheEnvelope { - key: "state".to_string(), - r#type: "test-state".to_string(), - payload: value.as_bytes().to_vec(), - stored_at: "2026-07-15T00:00:00Z".to_string(), - schema_id: Some("tests.test_state.v1".to_string()), - } - } - #[test] - fn interruption_before_replacement_preserves_committed_snapshot() -> Result<()> { + fn captured_snapshot_cannot_outlive_a_shared_consequence_gate() -> Result<()> { let temp = tempfile::tempdir()?; - let store_path = temp.path().join("cache.msgpack"); + let store_path = temp.path().join("authority.cc"); let mut store = SingleFileMessagePackBackingStore::new(&store_path); - let old = test_envelope("old"); - let new = test_envelope("new"); - store.push_all(std::slice::from_ref(&old), PushAllOptions::default())?; - - let result = store.write_all_unlocked_with_observer(std::slice::from_ref(&new), |stage| { - assert_eq!(stage, SnapshotReplacementStage::CandidateSynced); - assert!( - store_path.exists(), - "the committed pathname must never be removed" - ); - Err(anyhow!("simulated interruption before replacement")) - }); - - assert!(result.is_err()); - let recovered = store.pull_all()?; - assert_eq!(recovered.len(), 1); - assert_eq!(recovered[0].payload, old.payload); - assert_eq!(stale_candidate_paths(&store_path)?.len(), 1); - - store.push_all(std::slice::from_ref(&new), PushAllOptions::default())?; - let recovered = store.pull_all()?; - assert_eq!(recovered.len(), 1); - assert_eq!(recovered[0].payload, new.payload); - assert!(stale_candidate_paths(&store_path)?.is_empty()); - Ok(()) - } - - #[test] - fn interruption_after_replacement_recovers_new_snapshot() -> Result<()> { - let temp = tempfile::tempdir()?; - let store_path = temp.path().join("cache.msgpack"); - let mut store = SingleFileMessagePackBackingStore::new(&store_path); - let old = test_envelope("old"); - let new = test_envelope("new"); - store.push_all(std::slice::from_ref(&old), PushAllOptions::default())?; - - let result = store.write_all_unlocked_with_observer(std::slice::from_ref(&new), |stage| { - if stage == SnapshotReplacementStage::TargetReplaced { - return Err(anyhow!("simulated interruption after replacement")); - } - Ok(()) - }); - - let error = result.expect_err("the injected post-replacement failure must surface"); - let uncertain = error - .downcast_ref::() - .expect("post-replacement failures must be typed as committed but uncertain"); - assert_eq!(uncertain.path(), store_path.as_path()); - assert!(uncertain.detail().contains("simulated interruption")); - let recovered = store.pull_all()?; - assert_eq!(recovered.len(), 1); - assert_eq!(recovered[0].payload, new.payload); - assert!(stale_candidate_paths(&store_path)?.is_empty()); - Ok(()) - } - - #[test] - fn first_write_interruption_before_replacement_leaves_store_uncommitted() -> Result<()> { - let temp = tempfile::tempdir()?; - let store_path = temp.path().join("cache.msgpack"); - let store = SingleFileMessagePackBackingStore::new(&store_path); - let new = test_envelope("new"); - - let result = store.write_all_unlocked_with_observer(std::slice::from_ref(&new), |stage| { - assert_eq!(stage, SnapshotReplacementStage::CandidateSynced); - Err(anyhow!("simulated interruption before first replacement")) - }); - - assert!(result.is_err()); - assert!(!store_path.exists()); - assert!(store.pull_all()?.is_empty()); - assert_eq!(stale_candidate_paths(&store_path)?.len(), 1); - Ok(()) - } - - #[test] - fn first_write_interruption_after_replacement_exposes_complete_snapshot() -> Result<()> { - let temp = tempfile::tempdir()?; - let store_path = temp.path().join("cache.msgpack"); - let store = SingleFileMessagePackBackingStore::new(&store_path); - let new = test_envelope("new"); - - let result = store.write_all_unlocked_with_observer(std::slice::from_ref(&new), |stage| { - if stage == SnapshotReplacementStage::TargetReplaced { - return Err(anyhow!("simulated interruption after first replacement")); - } - Ok(()) - }); - - let error = result.expect_err("the injected post-replacement failure must surface"); - assert!( - error - .downcast_ref::() - .is_some() - ); - let recovered = store.pull_all()?; - assert_eq!(recovered.len(), 1); - assert_eq!(recovered[0].payload, new.payload); - assert!(stale_candidate_paths(&store_path)?.is_empty()); - Ok(()) - } - - #[test] - fn unlock_failure_never_masks_the_action_outcome() -> Result<()> { - let temp = tempfile::tempdir()?; - let store_path = temp.path().join("cache.msgpack"); - let store = SingleFileMessagePackBackingStore::new(&store_path); - - let completed = store.with_exclusive_lock_using_unlock( - || Ok(42_u32), - |_| Err(std::io::Error::other("simulated unlock failure")), - )?; - assert_eq!(completed, 42); - - let uncertain: Result<()> = store.with_exclusive_lock_using_unlock( - || { - Err(anyhow::Error::new( - CommittedSnapshotDurabilityUncertain::new( - store_path.clone(), - "primary post-commit failure", - ), - )) - }, - |_| Err(std::io::Error::other("secondary unlock failure")), - ); - let error = uncertain.expect_err("the action error must survive unlock cleanup"); - let error = error - .downcast_ref::() - .expect("the primary typed outcome must not be masked"); - assert!(error.detail().contains("primary post-commit failure")); - assert!(!error.detail().contains("secondary unlock failure")); - - // Both injected unlock failures still close their lock handles. A new - // exclusive operation must therefore acquire the lock normally. - store.with_exclusive_lock(|| Ok(()))?; - Ok(()) - } - - #[test] - fn stale_cleanup_preserves_non_uuid_lookalikes() -> Result<()> { - let temp = tempfile::tempdir()?; - let store_path = temp.path().join("cache.msgpack"); - let lookalike = temp.path().join("cache.msgpack.not-a-uuid.tmp"); - fs::write(&lookalike, b"belongs to somebody else")?; - - let mut store = SingleFileMessagePackBackingStore::new(&store_path); - store.push_all(&[test_envelope("new")], PushAllOptions::default())?; - - assert_eq!(fs::read(&lookalike)?, b"belongs to somebody else"); - assert!(stale_candidate_paths(&store_path)?.is_empty()); - Ok(()) - } - - #[cfg(unix)] - #[test] - fn stale_candidate_symlink_is_removed_without_clobbering_its_target() -> Result<()> { - use std::os::unix::fs::symlink; - - let temp = tempfile::tempdir()?; - let store_path = temp.path().join("cache.msgpack"); - let victim_path = temp.path().join("victim.txt"); - fs::write(&victim_path, b"untouched")?; - let stale_path = temporary_path_for(&store_path); - symlink(&victim_path, &stale_path)?; - - let mut store = SingleFileMessagePackBackingStore::new(&store_path); - store.push_all(&[test_envelope("new")], PushAllOptions::default())?; - - assert_eq!(fs::read(&victim_path)?, b"untouched"); - assert!(!stale_path.exists()); - assert!(stale_candidate_paths(&store_path)?.is_empty()); - Ok(()) - } - - #[cfg(unix)] - #[test] - fn non_utf8_target_names_recover_their_own_candidates() -> Result<()> { - use std::ffi::OsString; - use std::os::unix::ffi::OsStringExt; - - let temp = tempfile::tempdir()?; - let store_name = OsString::from_vec(b"cache-\xff.msgpack".to_vec()); - let store_path = temp.path().join(store_name); - let mut store = SingleFileMessagePackBackingStore::new(&store_path); - let new = test_envelope("new"); - - let interrupted = store - .write_all_unlocked_with_observer(std::slice::from_ref(&new), |_| { - Err(anyhow!("simulated interruption")) - }); - assert!(interrupted.is_err()); - assert_eq!(stale_candidate_paths(&store_path)?.len(), 1); - - store.push_all(std::slice::from_ref(&new), PushAllOptions::default())?; - assert!(stale_candidate_paths(&store_path)?.is_empty()); - assert_eq!(store.pull_all()?[0].payload, new.payload); - Ok(()) - } - - #[test] - fn two_contending_writers_leave_one_complete_snapshot() -> Result<()> { - use std::sync::{Arc, Barrier}; - - let temp = tempfile::tempdir()?; - let store_path = temp.path().join("cache.msgpack"); - let barrier = Arc::new(Barrier::new(3)); - let spawn_writer = |marker: u8| { - let store_path = store_path.clone(); - let barrier = Arc::clone(&barrier); - std::thread::spawn(move || -> Result<()> { - let mut entries = Vec::new(); - for index in 0..128 { - let mut entry = test_envelope(std::str::from_utf8(&[marker]).unwrap()); - entry.key = format!("state-{index:03}"); - entry.payload = vec![marker; 4096]; - entries.push(entry); - } - let mut store = SingleFileMessagePackBackingStore::new(store_path); - barrier.wait(); - store.push_all(&entries, PushAllOptions::default()) - }) + let released = CultCacheEnvelope { + key: "brake".into(), + r#type: "brake".into(), + payload: b"released".to_vec(), + stored_at: "2026-07-20T00:00:00Z".into(), + schema_id: Some("brake".into()), }; + store.push(&released)?; - let writer_a = spawn_writer(b'a'); - let writer_b = spawn_writer(b'b'); - barrier.wait(); - writer_a.join().expect("writer A panicked")?; - writer_b.join().expect("writer B panicked")?; + let writer_path = store_path.clone(); + let (started_tx, started_rx) = mpsc::channel(); + let (finished_tx, finished_rx) = mpsc::channel(); + store.with_read_only_shared_snapshot(|captured| { + assert_eq!(captured, vec![released.clone()]); + std::thread::spawn(move || { + started_tx.send(()).unwrap(); + let engaged = CultCacheEnvelope { + payload: b"engaged".to_vec(), + ..released + }; + let mut writer = SingleFileMessagePackBackingStore::new(writer_path); + writer.push(&engaged).unwrap(); + finished_tx.send(()).unwrap(); + }); + started_rx.recv_timeout(Duration::from_secs(1))?; + assert!( + finished_rx + .recv_timeout(Duration::from_millis(100)) + .is_err() + ); + Ok(()) + })?; + finished_rx.recv_timeout(Duration::from_secs(1))?; + assert_eq!(store.pull_all()?[0].payload, b"engaged"); + Ok(()) + } - let recovered = SingleFileMessagePackBackingStore::new(&store_path).pull_all()?; - assert_eq!(recovered.len(), 128); - let winner = recovered[0].payload[0]; - assert!(winner == b'a' || winner == b'b'); - assert!( - recovered - .iter() - .all(|entry| entry.payload == vec![winner; 4096]) + #[test] + fn post_action_unlock_failure_is_diagnostic_not_action_result() -> Result<()> { + let temp = tempfile::tempdir()?; + let store_path = temp.path().join("authority.cc"); + let mut store = SingleFileMessagePackBackingStore::new(&store_path); + store.push(&CultCacheEnvelope { + key: "brake".into(), + r#type: "brake".into(), + payload: b"released".to_vec(), + stored_at: "2026-07-20T00:00:00Z".into(), + schema_id: Some("brake".into()), + })?; + + let mut diagnostic = None; + let result = store.with_read_only_shared_snapshot_using( + |_| Ok(42), + |_| Err(anyhow!("injected post-action unlock failure")), + |error| diagnostic = Some(error.to_string()), + ); + + assert_eq!(result?, 42); + assert_eq!( + diagnostic.as_deref(), + Some("injected post-action unlock failure") ); - assert!(stale_candidate_paths(&store_path)?.is_empty()); Ok(()) } #[test] fn familiar_cultcache_flow_persists_and_reloads_typed_documents() -> Result<()> { let temp = tempfile::tempdir()?; - let store_path = temp.path().join("cache.msgpack"); + let store_path = temp.path().join("cache.cc"); let settings = Settings { theme: "ash".to_string(), retries: 3, @@ -1321,7 +2625,7 @@ mod tests { #[test] fn entry_identity_is_polymorphic_by_type_and_key() -> Result<()> { let temp = tempfile::tempdir()?; - let store_path = temp.path().join("cache.msgpack"); + let store_path = temp.path().join("cache.cc"); let mut cache = CultCache::new(); cache.register_registry(TestEntries)?; cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(&store_path)); @@ -1347,11 +2651,751 @@ mod tests { Ok(()) } + #[test] + fn prepared_batch_publishes_heterogeneous_entries_in_one_snapshot() -> Result<()> { + let temp = tempfile::tempdir()?; + let store_path = temp.path().join("batch.cc"); + let mut cache = CultCache::new(); + cache.register_registry(TestEntries)?; + cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(&store_path)); + + let (settings, _) = cache.prepare_entry( + "app", + &Settings { + theme: "iron".to_string(), + retries: 4, + }, + )?; + let (note, _) = cache.prepare_entry( + "receipt", + &Note { + title: "committed".to_string(), + body: "same snapshot".to_string(), + }, + )?; + cache.put_prepared_batch(vec![settings, note])?; + + let mut reloaded = CultCache::new(); + reloaded.register_registry(TestEntries)?; + reloaded.add_generic_backing_store(SingleFileMessagePackBackingStore::new(&store_path)); + reloaded.pull_all_backing_stores()?; + assert_eq!(reloaded.get_required::("app")?.theme, "iron"); + assert_eq!(reloaded.get_required::("receipt")?.title, "committed"); + Ok(()) + } + + #[test] + fn named_preparation_preserves_omitted_nested_optional_slots() -> Result<()> { + let temp = tempfile::tempdir()?; + let store_path = temp.path().join("named.cc"); + let mut cache = CultCache::new(); + cache.register_entry_type::()?; + cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(&store_path)); + cache.pull_all_backing_stores()?; + let note = NestedNote { + value: NestedOptionalValue { + label: "nested".into(), + count: None, + symbol: Some("kept-in-its-own-field".into()), + }, + }; + assert!(cache.prepare_entry("compact", ¬e).is_err()); + let (entry, parsed) = cache.prepare_entry_named("named", ¬e)?; + assert_eq!(parsed, note); + cache.put_prepared_batch(vec![entry])?; + assert_eq!(cache.get_required::("named")?, note); + Ok(()) + } + + #[test] + fn pulling_an_absent_store_does_not_create_its_parent_or_lock() -> Result<()> { + let temp = tempfile::tempdir()?; + let missing_parent = temp.path().join("missing-body"); + let store_path = missing_parent.join("cache.cc"); + let store = SingleFileMessagePackBackingStore::new(&store_path); + + assert!(store.pull_all()?.is_empty()); + assert!(!missing_parent.exists()); + assert!(!store_path.with_file_name("cache.cc.lock").exists()); + Ok(()) + } + + #[test] + fn provider_snapshot_read_does_not_create_or_open_a_lock() -> Result<()> { + let temp = tempfile::tempdir()?; + let store_path = temp.path().join("provider.cc"); + let lock_path = temp.path().join("provider.cc.lock"); + let mut store = SingleFileMessagePackBackingStore::new(&store_path); + let expected = test_envelope("provider.delivery", "one", b"payload"); + store.push(&expected)?; + std::fs::remove_file(&lock_path)?; + + assert_eq!(store.pull_all_read_only_snapshot()?, vec![expected]); + assert!(!lock_path.exists()); + Ok(()) + } + + #[test] + fn next_exclusive_write_removes_only_exact_abandoned_staging_files() -> Result<()> { + let temp = tempfile::tempdir()?; + let store_path = temp.path().join("cache.cc"); + let abandoned = temporary_path_for(&store_path); + let unknown = temp.path().join("cache.cc.not-a-uuid.tmp"); + let foreign = temp + .path() + .join("other.cc.00000000-0000-0000-0000-000000000000.tmp"); + fs::write(&abandoned, b"partial staging bytes")?; + fs::write(&unknown, b"operator-owned unknown file")?; + fs::write(&foreign, b"foreign store staging")?; + + let mut store = SingleFileMessagePackBackingStore::new(&store_path); + let expected = test_envelope("model", "current", b"one"); + store.push(&expected)?; + + assert!(!abandoned.exists()); + assert_eq!(fs::read(&unknown)?, b"operator-owned unknown file"); + assert_eq!(fs::read(&foreign)?, b"foreign store staging"); + assert_eq!(store.pull_all()?, vec![expected]); + Ok(()) + } + + #[test] + fn failed_snapshot_publication_preserves_the_committed_destination() -> Result<()> { + let temp = tempfile::tempdir()?; + let destination = temp.path().join("cache.cc"); + let absent_staging = temp.path().join("absent.tmp"); + let committed = b"committed snapshot"; + fs::write(&destination, committed)?; + + assert!(replace_file_atomically(&absent_staging, &destination).is_err()); + assert_eq!(fs::read(&destination)?, committed); + Ok(()) + } + + #[test] + fn snapshot_publication_atomically_replaces_an_existing_destination() -> Result<()> { + let temp = tempfile::tempdir()?; + let destination = temp.path().join("cache.cc"); + let staged = temp.path().join("cache.cc.staged"); + fs::write(&destination, b"old snapshot")?; + fs::write(&staged, b"new snapshot")?; + + replace_file_atomically(&staged, &destination)?; + + assert_eq!(fs::read(&destination)?, b"new snapshot"); + assert!(!staged.exists()); + Ok(()) + } + + #[test] + #[ignore = "operator SIGKILL probe; requires CULTCACHE_INTERRUPTION_STORE"] + fn snapshot_publication_interruption_probe_writer() -> Result<()> { + let store_path = std::env::var_os("CULTCACHE_INTERRUPTION_STORE") + .map(PathBuf::from) + .ok_or_else(|| anyhow!("CULTCACHE_INTERRUPTION_STORE is required"))?; + let marker_path = std::env::var_os("CULTCACHE_INTERRUPTION_MARKER") + .map(PathBuf::from) + .ok_or_else(|| anyhow!("CULTCACHE_INTERRUPTION_MARKER is required"))?; + let mut store = SingleFileMessagePackBackingStore::new(store_path); + for sequence in 0_u64.. { + store.push(&test_envelope( + "interruption.probe", + "current", + &rmp_serde::to_vec(&sequence)?, + ))?; + fs::write(&marker_path, sequence.to_string())?; + } + unreachable!("the interruption writer is stopped by the operator") + } + + #[test] + #[ignore = "operator SIGKILL probe; requires CULTCACHE_INTERRUPTION_STORE"] + fn snapshot_publication_interruption_probe_reader() -> Result<()> { + let store_path = std::env::var_os("CULTCACHE_INTERRUPTION_STORE") + .map(PathBuf::from) + .ok_or_else(|| anyhow!("CULTCACHE_INTERRUPTION_STORE is required"))?; + let rows = SingleFileMessagePackBackingStore::new(store_path).pull_all()?; + assert_eq!(rows.len(), 1); + assert_eq!(rows[0].r#type, "interruption.probe"); + assert_eq!(rows[0].key, "current"); + let _: u64 = rmp_serde::from_slice(&rows[0].payload)?; + Ok(()) + } + + fn test_envelope(r#type: &str, key: &str, payload: &[u8]) -> CultCacheEnvelope { + CultCacheEnvelope { + key: key.to_string(), + r#type: r#type.to_string(), + payload: payload.to_vec(), + stored_at: "2026-07-13T00:00:00Z".to_string(), + schema_id: Some(r#type.to_string()), + } + } + + #[test] + fn redb_store_crud_and_reopen_preserve_polymorphic_rows() -> Result<()> { + let temp = tempfile::tempdir()?; + let path = temp.path().join("keyed.cc"); + let model = test_envelope("model", "shared", b"one"); + let receipt = test_envelope("receipt", "shared", b"two"); + { + let mut store = RedbMessagePackBackingStore::new(&path)?; + store.push(&model)?; + store.push(&receipt)?; + assert_eq!(store.pull_all()?.len(), 2); + store.delete(&receipt)?; + } + let reopened = RedbMessagePackBackingStore::new(&path)?; + assert_eq!(reopened.pull_all()?, vec![model]); + Ok(()) + } + + #[test] + fn redb_exact_cas_refuses_stale_value_without_mutation() -> Result<()> { + let temp = tempfile::tempdir()?; + let mut store = RedbMessagePackBackingStore::new(temp.path().join("cas.cc"))?; + let current = test_envelope("model", "current", b"one"); + store.push(¤t)?; + let stale = test_envelope("model", "current", b"stale"); + let replacement = test_envelope("model", "current", b"two"); + assert!(!store.compare_and_swap_entry(&stale, replacement.clone())?); + assert_eq!(store.pull_all()?, vec![current.clone()]); + assert!(store.compare_and_swap_entry(¤t, replacement.clone())?); + assert_eq!(store.pull_all()?, vec![replacement]); + Ok(()) + } + + #[test] + fn redb_batch_is_atomic_and_stale_member_refuses_every_write() -> Result<()> { + let temp = tempfile::tempdir()?; + let mut store = RedbMessagePackBackingStore::new(temp.path().join("batch.cc"))?; + let first = test_envelope("model", "first", b"one"); + let second = test_envelope("model", "second", b"one"); + store.push(&first)?; + store.push(&second)?; + let stale_second = test_envelope("model", "second", b"stale"); + let first_two = test_envelope("model", "first", b"two"); + let second_two = test_envelope("model", "second", b"two"); + let receipt = test_envelope("receipt", "batch", b"committed"); + assert!(!store.compare_and_swap_batch( + &[first.clone(), stale_second], + vec![first_two.clone(), second_two.clone(), receipt.clone()], + )?); + assert_eq!(store.pull_all()?, vec![first.clone(), second.clone()]); + assert!(store.compare_and_swap_batch( + &[first, second], + vec![first_two.clone(), second_two.clone(), receipt.clone()], + )?); + assert_eq!(store.pull_all()?, vec![first_two, second_two, receipt]); + Ok(()) + } + + #[test] + fn redb_compaction_refuses_stale_snapshot_and_atomically_replaces_and_deletes() -> Result<()> { + let temp = tempfile::tempdir()?; + let mut store = RedbMessagePackBackingStore::new(temp.path().join("compact.cc"))?; + let old_head = test_envelope("retention", "current", b"one"); + let retired = test_envelope("receipt", "old", b"terminal"); + store.push(&old_head)?; + store.push(&retired)?; + let stale = store.pull_all()?; + let concurrent = test_envelope("receipt", "running", b"active"); + assert!(store.insert_entry_if_absent(concurrent.clone())?); + let new_head = test_envelope("retention", "current", b"two"); + assert!(!store.replace_and_delete_if_snapshot_unchanged( + &stale, + vec![new_head.clone()], + std::slice::from_ref(&retired), + )?); + assert!(store.pull_all()?.contains(&retired)); + let exact = store.pull_all()?; + assert!(store.replace_and_delete_if_snapshot_unchanged( + &exact, + vec![new_head.clone()], + &[retired], + )?); + assert_eq!(store.pull_all()?, vec![concurrent, new_head]); + Ok(()) + } + + #[test] + fn redb_entry_cas_does_not_depend_on_unrelated_snapshot_changes() -> Result<()> { + let temp = tempfile::tempdir()?; + let store = RedbMessagePackBackingStore::new(temp.path().join("independent.cc"))?; + let current = test_envelope("model", "current", b"one"); + assert!(store.insert_entry_if_absent(current.clone())?); + let unrelated = test_envelope("event", "later", b"noise"); + assert!(store.insert_entry_if_absent(unrelated.clone())?); + let replacement = test_envelope("model", "current", b"two"); + assert!(store.compare_and_swap_entry(¤t, replacement.clone())?); + assert_eq!(store.pull_all()?, vec![unrelated, replacement]); + Ok(()) + } + + #[test] + fn redb_fresh_handles_share_one_database_for_the_same_cultcache_path() -> Result<()> { + let temp = tempfile::tempdir()?; + let path = temp.path().join("shared.cc"); + let mut first = RedbMessagePackBackingStore::new(&path)?; + let second = RedbMessagePackBackingStore::new(&path)?; + let initial = test_envelope("model", "current", b"one"); + first.push(&initial)?; + assert_eq!(second.pull_all()?, vec![initial.clone()]); + let replacement = test_envelope("model", "current", b"two"); + assert!(second.compare_and_swap_entry(&initial, replacement.clone())?); + assert_eq!(first.pull_all()?, vec![replacement]); + Ok(()) + } + + #[test] + fn owned_redb_clones_share_authority_and_fresh_owner_is_refused() -> Result<()> { + let temp = tempfile::tempdir()?; + let path = temp.path().join("owned.cc"); + let owner = OwnedRedbMessagePackBackingStore::new(&path)?; + let clone = owner.clone(); + assert_eq!(owner.file_identity(), clone.file_identity()); + assert!(OwnedRedbMessagePackBackingStore::new(&path).is_err()); + drop(owner); + assert!(OwnedRedbMessagePackBackingStore::new(&path).is_err()); + drop(clone); + assert!(OwnedRedbMessagePackBackingStore::new(&path).is_ok()); + Ok(()) + } + + #[test] + fn owned_redb_file_identity_is_stable_across_writes_and_reopen() -> Result<()> { + let temp = tempfile::tempdir()?; + let path = temp.path().join("identity.cc"); + let identity = { + let mut owner = OwnedRedbMessagePackBackingStore::new(&path)?; + let identity = owner.file_identity().to_string(); + owner.push(&test_envelope("model", "current", b"one"))?; + owner.validate_path_identity()?; + owner.require_file_identity(&identity)?; + identity + }; + let reopened = OwnedRedbMessagePackBackingStore::new(&path)?; + assert_eq!(reopened.file_identity(), identity); + assert_eq!(reopened.pull_all()?.len(), 1); + Ok(()) + } + + #[test] + fn owned_redb_identity_helper_refuses_mismatch() -> Result<()> { + let temp = tempfile::tempdir()?; + let owner = OwnedRedbMessagePackBackingStore::new(temp.path().join("mismatch.cc"))?; + assert!(owner.require_file_identity("not-the-owned-file").is_err()); + owner.require_file_identity(owner.file_identity())?; + Ok(()) + } + + #[test] + fn owned_redb_batch_refuses_stale_member_and_commits_success_atomically() -> Result<()> { + let temp = tempfile::tempdir()?; + let mut owner = OwnedRedbMessagePackBackingStore::new(temp.path().join("batch-owned.cc"))?; + let first = test_envelope("model", "first", b"one"); + let second = test_envelope("model", "second", b"one"); + owner.push(&first)?; + owner.push(&second)?; + let first_two = test_envelope("model", "first", b"two"); + let second_two = test_envelope("model", "second", b"two"); + let companion = test_envelope("receipt", "batch", b"committed"); + let stale_second = test_envelope("model", "second", b"stale"); + assert!(!owner.compare_and_swap_batch( + &[first.clone(), stale_second], + vec![first_two.clone(), second_two.clone(), companion.clone()], + )?); + assert_eq!(owner.pull_all()?, vec![first.clone(), second.clone()]); + assert!(owner.compare_and_swap_batch( + &[first, second], + vec![first_two.clone(), second_two.clone(), companion.clone()], + )?); + assert_eq!(owner.pull_all()?, vec![first_two, second_two, companion]); + Ok(()) + } + + #[test] + fn owned_redb_compaction_refuses_stale_snapshot_and_atomically_replaces_and_deletes() + -> Result<()> { + let temp = tempfile::tempdir()?; + let mut owner = + OwnedRedbMessagePackBackingStore::new(temp.path().join("compact-owned.cc"))?; + let old_head = test_envelope("retention", "current", b"one"); + let retired_a = test_envelope("claim", "a", b"terminal"); + let retired_b = test_envelope("receipt", "a", b"terminal"); + owner.push(&old_head)?; + owner.push(&retired_a)?; + owner.push(&retired_b)?; + let stale = owner.pull_all()?; + let concurrent = test_envelope("claim", "concurrent", b"running"); + assert!(owner.insert_entry_if_absent(concurrent.clone())?); + let new_head = test_envelope("retention", "current", b"two"); + assert!(!owner.replace_and_delete_if_snapshot_unchanged( + &stale, + vec![new_head.clone()], + &[retired_a.clone(), retired_b.clone()], + )?); + assert!(owner.pull_all()?.contains(&retired_a)); + let exact = owner.pull_all()?; + assert!(owner.replace_and_delete_if_snapshot_unchanged( + &exact, + vec![new_head.clone()], + &[retired_a, retired_b], + )?); + assert_eq!(owner.pull_all()?, vec![concurrent, new_head]); + Ok(()) + } + + #[test] + fn owned_redb_path_replacement_cannot_redirect_pinned_authority() -> Result<()> { + let temp = tempfile::tempdir()?; + let path = temp.path().join("pinned.cc"); + let displaced = temp.path().join("displaced.cc"); + let mut owner = OwnedRedbMessagePackBackingStore::new(&path)?; + let identity = owner.file_identity().to_string(); + owner.push(&test_envelope("model", "before", b"one"))?; + fs::rename(&path, &displaced)?; + File::create(&path)?; + assert!(owner.validate_path_identity().is_err()); + assert_eq!(owner.file_identity(), identity); + owner.push(&test_envelope("model", "after", b"two"))?; + assert_eq!(owner.pull_all()?.len(), 2); + assert_ne!( + file_identity_from_file(&File::open(&path)?)?, + owner.file_identity() + ); + Ok(()) + } + + #[test] + fn redb_overlapping_fresh_handles_serialize_the_database_open_interval() -> Result<()> { + let temp = tempfile::tempdir()?; + let path = temp.path().join("contended.cc"); + let first = RedbMessagePackBackingStore::new(&path)?; + let second = RedbMessagePackBackingStore::new(&path)?; + let barrier = std::sync::Arc::new(std::sync::Barrier::new(3)); + let first_barrier = barrier.clone(); + let first_thread = std::thread::spawn(move || -> Result<()> { + first_barrier.wait(); + for index in 0..32 { + first.insert_entry_if_absent(test_envelope( + "event", + &format!("first-{index}"), + b"first", + ))?; + } + Ok(()) + }); + let second_barrier = barrier.clone(); + let second_thread = std::thread::spawn(move || -> Result<()> { + second_barrier.wait(); + for index in 0..32 { + second.insert_entry_if_absent(test_envelope( + "event", + &format!("second-{index}"), + b"second", + ))?; + } + Ok(()) + }); + barrier.wait(); + first_thread.join().expect("first redb writer")?; + second_thread.join().expect("second redb writer")?; + assert_eq!( + RedbMessagePackBackingStore::new(path)?.pull_all()?.len(), + 64 + ); + Ok(()) + } + + #[test] + fn redb_accepts_a_bare_relative_cultcache_path() -> Result<()> { + let name = format!("cultcache-redb-relative-{}.cc", uuid::Uuid::new_v4()); + let path = PathBuf::from(&name); + let lock_path = PathBuf::from(format!("{name}.lock")); + let store = RedbMessagePackBackingStore::new(&path)?; + assert!(store.insert_entry_if_absent(test_envelope("model", "current", b"one"))?); + assert_eq!(store.pull_all()?.len(), 1); + fs::remove_file(path)?; + fs::remove_file(lock_path)?; + Ok(()) + } + + #[test] + fn conditional_batch_replaces_expected_and_inserts_companion_atomically() -> Result<()> { + let temp = tempfile::tempdir()?; + let store_path = temp.path().join("conditional-batch.cc"); + let mut store = SingleFileMessagePackBackingStore::new(&store_path); + let current = test_envelope("model", "current", b"revision-1"); + store.push(¤t)?; + let replacement = test_envelope("model", "current", b"revision-2"); + let companion = test_envelope("receipt", "migration-1", b"applied"); + + assert!(store.compare_and_swap_batch( + std::slice::from_ref(¤t), + vec![replacement.clone(), companion.clone()], + )?); + assert_eq!(store.pull_all()?, vec![replacement, companion]); + Ok(()) + } + + #[test] + fn conditional_batch_allows_atomic_first_import_when_identities_are_absent() -> Result<()> { + let temp = tempfile::tempdir()?; + let store_path = temp.path().join("conditional-import.cc"); + let store = SingleFileMessagePackBackingStore::new(&store_path); + let model = test_envelope("model", "current", b"revision-1"); + let receipt = test_envelope("receipt", "migration-1", b"applied"); + + assert!(store.compare_and_swap_batch(&[], vec![model.clone(), receipt.clone()])?); + assert_eq!(store.pull_all()?, vec![model, receipt]); + Ok(()) + } + + #[test] + fn conditional_batch_stale_expected_and_companion_collision_preserve_exact_bytes() -> Result<()> + { + let temp = tempfile::tempdir()?; + let store_path = temp.path().join("conditional-refusal.cc"); + let mut store = SingleFileMessagePackBackingStore::new(&store_path); + let current = test_envelope("model", "current", b"revision-1"); + let occupied = test_envelope("receipt", "migration-1", b"someone-else"); + store.push(¤t)?; + store.push(&occupied)?; + let before = fs::read(&store_path)?; + + let stale = test_envelope("model", "current", b"stale-copy"); + let replacement = test_envelope("model", "current", b"revision-2"); + let fresh_companion = test_envelope("receipt", "migration-2", b"applied"); + assert!( + !store.compare_and_swap_batch(&[stale], vec![replacement.clone(), fresh_companion],)? + ); + assert_eq!(fs::read(&store_path)?, before); + + assert!(!store.compare_and_swap_batch( + &[current], + vec![ + replacement, + test_envelope("receipt", "migration-1", b"collision") + ], + )?); + assert_eq!(fs::read(&store_path)?, before); + Ok(()) + } + + #[test] + fn conditional_batch_rejects_empty_replacements_and_duplicate_identities() -> Result<()> { + let temp = tempfile::tempdir()?; + let store = SingleFileMessagePackBackingStore::new(temp.path().join("invalid-batch.cc")); + let entry = test_envelope("model", "current", b"one"); + + assert!( + store + .compare_and_swap_batch(&[entry.clone()], Vec::new()) + .is_err() + ); + assert!( + store + .compare_and_swap_batch(&[], vec![entry.clone(), entry.clone()]) + .is_err() + ); + assert!( + store + .compare_and_swap_batch( + &[entry.clone(), entry.clone()], + vec![test_envelope("model", "current", b"two")], + ) + .is_err() + ); + assert!(!store.path().exists()); + Ok(()) + } + + #[test] + fn full_snapshot_replacement_and_append_refuses_concurrent_rows() -> Result<()> { + let temp = tempfile::tempdir()?; + let snapshot_path = temp.path().join("snapshot-replace-append.cc"); + let mut snapshot_store = SingleFileMessagePackBackingStore::new(&snapshot_path); + let current = test_envelope("session", "current", b"active"); + snapshot_store.push(¤t)?; + let stale_snapshot = snapshot_store.pull_all()?; + let concurrent = test_envelope("event", "concurrent", b"live"); + snapshot_store.push(&concurrent)?; + let completed = test_envelope("session", "current", b"completed"); + let receipt = test_envelope("receipt", "terminal", b"done"); + assert!(!snapshot_store.replace_and_append_if_snapshot_unchanged( + &stale_snapshot, + vec![completed.clone(), receipt.clone()], + )?); + assert_eq!( + snapshot_store.pull_all()?, + vec![concurrent.clone(), current.clone()] + ); + let exact_snapshot = snapshot_store.pull_all()?; + assert!(snapshot_store.replace_and_append_if_snapshot_unchanged( + &exact_snapshot, + vec![completed.clone(), receipt.clone()], + )?); + assert_eq!( + snapshot_store.pull_all()?, + vec![concurrent.clone(), receipt.clone(), completed.clone()] + ); + + let keyed_path = temp.path().join("keyed-replace-append.redb"); + let mut keyed_store = RedbMessagePackBackingStore::new(&keyed_path)?; + keyed_store.push(¤t)?; + let stale_snapshot = keyed_store.pull_all()?; + keyed_store.push(&concurrent)?; + assert!(!keyed_store.replace_and_append_if_snapshot_unchanged( + &stale_snapshot, + vec![completed.clone(), receipt.clone()], + )?); + let exact_snapshot = keyed_store.pull_all()?; + assert!(keyed_store.replace_and_append_if_snapshot_unchanged( + &exact_snapshot, + vec![completed.clone(), receipt.clone()], + )?); + assert_eq!( + keyed_store.pull_all()?, + vec![concurrent, receipt, completed] + ); + Ok(()) + } + + #[test] + fn single_file_compaction_atomically_replaces_summary_and_deletes_history() -> Result<()> { + let temp = tempfile::tempdir()?; + let store_path = temp.path().join("conditional-compaction.cc"); + let mut store = SingleFileMessagePackBackingStore::new(&store_path); + let history = test_envelope("history", "old", b"closed"); + let head = test_envelope("retention", "head", b"revision-1"); + store.push(&history)?; + store.push(&head)?; + let snapshot = store.pull_all()?; + let next_head = test_envelope("retention", "head", b"revision-2"); + + assert!(store.replace_and_delete_if_snapshot_unchanged( + &snapshot, + vec![next_head.clone()], + std::slice::from_ref(&history), + )?); + assert_eq!(store.pull_all()?, vec![next_head]); + + let before = fs::read(&store_path)?; + assert!(!store.replace_and_delete_if_snapshot_unchanged( + &snapshot, + vec![test_envelope("retention", "head", b"revision-3")], + std::slice::from_ref(&history), + )?); + assert_eq!(fs::read(&store_path)?, before); + Ok(()) + } + + #[test] + fn snapshot_append_fences_concurrent_unknown_identity() -> Result<()> { + let temp = tempfile::tempdir()?; + let store_path = temp.path().join("snapshot-append.cc"); + let mut store = SingleFileMessagePackBackingStore::new(&store_path); + let model = test_envelope("model", "current", b"revision-1"); + store.push(&model)?; + let expected = store.pull_all()?; + let duplicate_admission = test_envelope("admission", "unexpected", b"also-current"); + store.push(&duplicate_admission)?; + let before = fs::read(&store_path)?; + + assert!(!store.append_if_snapshot_unchanged( + &expected, + vec![test_envelope("readiness", "proof", b"ready")], + )?); + assert_eq!(fs::read(&store_path)?, before); + Ok(()) + } + + #[test] + fn snapshot_append_is_order_insensitive_and_refuses_collisions() -> Result<()> { + let temp = tempfile::tempdir()?; + let store_path = temp.path().join("snapshot-order.cc"); + let mut store = SingleFileMessagePackBackingStore::new(&store_path); + let a = test_envelope("a", "one", b"1"); + let b = test_envelope("b", "two", b"2"); + store.push(&a)?; + store.push(&b)?; + assert!(store.append_if_snapshot_unchanged( + &[b.clone(), a.clone()], + vec![test_envelope("proof", "three", b"3")], + )?); + let current = store.pull_all()?; + assert!(!store.append_if_snapshot_unchanged( + ¤t, + vec![test_envelope("a", "one", b"collision")], + )?); + assert!( + store + .append_if_snapshot_unchanged(¤t, Vec::new()) + .is_err() + ); + Ok(()) + } + + #[test] + fn type_and_key_identity_is_not_delimiter_ambiguous() -> Result<()> { + let temp = tempfile::tempdir()?; + let store_path = temp.path().join("delimiter-identity.cc"); + let mut store = SingleFileMessagePackBackingStore::new(&store_path); + let left = test_envelope("a::b", "c", b"left"); + let right = test_envelope("a", "b::c", b"right"); + store.push(&left)?; + store.push(&right)?; + let rows = store.pull_all()?; + assert_eq!(rows.len(), 2); + assert!(rows.contains(&left)); + assert!(rows.contains(&right)); + Ok(()) + } + + #[test] + fn refused_batch_preserves_prior_snapshot() -> Result<()> { + let temp = tempfile::tempdir()?; + let store_path = temp.path().join("refused-batch.cc"); + let refusal = Arc::new(AtomicBool::new(false)); + let mut cache = CultCache::new(); + cache.register_registry(TestEntries)?; + cache.add_generic_backing_store(RefusingBatchStore { + inner: SingleFileMessagePackBackingStore::new(&store_path), + refuse_batch: refusal.clone(), + }); + cache.put( + "app", + &Settings { + theme: "before".to_string(), + retries: 1, + }, + )?; + let (note, _) = cache.prepare_entry( + "receipt", + &Note { + title: "after".to_string(), + body: "must not land".to_string(), + }, + )?; + refusal.store(true, Ordering::SeqCst); + assert!(cache.put_prepared_batch(vec![note]).is_err()); + assert!(cache.get::("receipt")?.is_none()); + + let mut reloaded = CultCache::new(); + reloaded.register_registry(TestEntries)?; + reloaded.add_generic_backing_store(SingleFileMessagePackBackingStore::new(&store_path)); + reloaded.pull_all_backing_stores()?; + assert_eq!(reloaded.get_required::("app")?.theme, "before"); + assert!(reloaded.get::("receipt")?.is_none()); + Ok(()) + } + #[test] fn type_specific_store_routes_before_generic_store() -> Result<()> { let temp = tempfile::tempdir()?; - let generic_path = temp.path().join("generic.msgpack"); - let settings_path = temp.path().join("settings.msgpack"); + let generic_path = temp.path().join("generic.cc"); + let settings_path = temp.path().join("settings.cc"); let mut cache = CultCache::new(); cache.register_entry_type::()?; cache.register_entry_type::()?; @@ -1386,7 +3430,7 @@ mod tests { #[test] fn update_and_delete_follow_the_cache_api() -> Result<()> { let temp = tempfile::tempdir()?; - let store_path = temp.path().join("cache.msgpack"); + let store_path = temp.path().join("cache.cc"); let mut cache = CultCache::new(); cache.register_entry_type::()?; cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(&store_path)); @@ -1408,7 +3452,7 @@ mod tests { #[test] fn pull_rejects_unregistered_persisted_entry_type() -> Result<()> { let temp = tempfile::tempdir()?; - let store_path = temp.path().join("cache.msgpack"); + let store_path = temp.path().join("cache.cc"); let mut store = SingleFileMessagePackBackingStore::new(&store_path); store.push(&CultCacheEnvelope { key: "unknown".to_string(), @@ -1432,7 +3476,7 @@ mod tests { #[test] fn payload_is_binary_messagepack_not_json_value() -> Result<()> { let temp = tempfile::tempdir()?; - let store_path = temp.path().join("cache.msgpack"); + let store_path = temp.path().join("cache.cc"); let mut cache = CultCache::new(); cache.register_entry_type::()?; cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(&store_path)); @@ -1451,10 +3495,23 @@ mod tests { Ok(()) } + #[test] + fn byte_slots_use_messagepack_binary_and_round_trip() -> Result<()> { + let record = BinaryRecord { + required: vec![1, 2, 3], + optional: Vec::new(), + }; + + let payload = rmp_serde::to_vec(&record)?; + assert_eq!(payload, vec![0x92, 0xc4, 3, 1, 2, 3, 0xc4, 0]); + assert_eq!(rmp_serde::from_slice::(&payload)?, record); + Ok(()) + } + #[test] fn corrupted_payload_fails_during_typed_retrieval() -> Result<()> { let temp = tempfile::tempdir()?; - let store_path = temp.path().join("cache.msgpack"); + let store_path = temp.path().join("cache.cc"); let mut store = SingleFileMessagePackBackingStore::new(&store_path); store.push(&CultCacheEnvelope { key: "app".to_string(), @@ -1480,8 +3537,8 @@ mod tests { #[test] fn put_envelope_reuses_existing_messagepack_payload() -> Result<()> { let temp = tempfile::tempdir()?; - let origin_store = temp.path().join("origin.msgpack"); - let target_store = temp.path().join("target.msgpack"); + let origin_store = temp.path().join("origin.cc"); + let target_store = temp.path().join("target.cc"); let mut origin = CultCache::new(); origin.register_entry_type::()?; @@ -1517,38 +3574,141 @@ mod tests { } #[test] - fn messagepack_store_recovers_schema_stamped_records_missing_catalog_entries() -> Result<()> { + fn raw_envelope_path_preserves_a_registered_dynamic_payload() -> Result<()> { let temp = tempfile::tempdir()?; - let store_path = temp.path().join("missing-catalog.msgpack"); - let expected = SchemaStamped { - schema_version: "tests.schema_stamped_entry.v1".to_string(), - name: "schema-stamped".to_string(), - value: "still readable".to_string(), + let store_path = temp.path().join("dynamic.cc"); + let envelope = CultCacheEnvelope { + key: "app".to_string(), + r#type: Settings::TYPE.to_string(), + payload: vec![0xc1], + stored_at: now_utc_second(), + schema_id: Some("dynamic.settings.v1".to_string()), }; - let snapshot = PersistedStoreSnapshot( - "cultcache.store.v1".to_string(), - Vec::new(), - vec![PersistedRecord( - "record-1".to_string(), - "sha256:stale-schema-id-from-cold-record".to_string(), - "2026-06-25T12:00:00Z".to_string(), - rmp_serde::to_vec(&expected)?, - )], - ); - fs::write(&store_path, rmp_serde::to_vec(&snapshot)?)?; let mut cache = CultCache::new(); - cache.register_entry_type::()?; + cache.register_entry_type::()?; + cache.register_entry_type::()?; cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(&store_path)); - cache.pull_all_backing_stores()?; + cache.put_raw_envelope(envelope.clone())?; - assert_eq!(cache.get_required::("record-1")?, expected); + assert_eq!(cache.snapshot(), vec![envelope.clone()]); assert_eq!( + SingleFileMessagePackBackingStore::new(&store_path).pull_all()?, + vec![envelope] + ); + assert!(cache.get_required::("app").is_err()); + let before_collision = fs::read(&store_path)?; + assert!( cache - .get_required_envelope::("record-1")? - .schema_id, - Some("sha256:stale-schema-id-from-cold-record".to_string()) + .put_raw_envelope(CultCacheEnvelope { + key: "note".to_string(), + r#type: Note::TYPE.to_string(), + payload: Vec::new(), + stored_at: now_utc_second(), + schema_id: Some("dynamic.settings.v1".to_string()), + }) + .is_err() + ); + assert_eq!(fs::read(&store_path)?, before_collision); + assert!( + cache + .put_raw_envelope(CultCacheEnvelope { + key: "foreign".to_string(), + r#type: "unregistered".to_string(), + payload: Vec::new(), + stored_at: now_utc_second(), + schema_id: None, + }) + .is_err() ); Ok(()) } + + #[test] + fn soa_snapshot_round_trips_registered_entries() -> Result<()> { + let temp = tempfile::tempdir()?; + let store_path = temp.path().join("cache.cc"); + let mut cache = CultCache::new(); + cache.register_registry(TestEntries)?; + cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(&store_path)); + cache.put( + "app", + &Settings { + theme: "ash".to_string(), + retries: 3, + }, + )?; + cache.put( + "memo", + &Note { + title: "machine".to_string(), + body: "awake".to_string(), + }, + )?; + + let soa = cache.snapshot_soa(); + assert_eq!(soa.len(), 2); + assert_eq!(soa.keys.len(), soa.payloads.len()); + + let mut restored = CultCache::new(); + restored.register_registry(TestEntries)?; + restored.add_generic_backing_store(SingleFileMessagePackBackingStore::new( + temp.path().join("restored.cc"), + )); + restored.load_soa(soa)?; + assert_eq!(restored.get_required::("app")?.theme, "ash"); + assert_eq!(restored.get_required::("memo")?.body, "awake"); + Ok(()) + } + + #[test] + fn typed_soa_columns_match_csharp_cache_ergonomics() -> Result<()> { + let temp = tempfile::tempdir()?; + let store_path = temp.path().join("cache.cc"); + let mut cache = CultCache::new(); + cache.register_registry(TestEntries)?; + cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(&store_path)); + cache.put( + "settings:a", + &Settings { + theme: "ash".to_string(), + retries: 3, + }, + )?; + cache.put( + "settings:b", + &Settings { + theme: "bone".to_string(), + retries: 5, + }, + )?; + + let table = cache.soa::()?; + assert_eq!( + table.keys(), + &["settings:a".to_string(), "settings:b".to_string()] + ); + assert_eq!( + table.column::("theme")?.values(), + &["ash".to_string(), "bone".to_string()] + ); + assert_eq!(table.column::("retries")?.values(), &[3, 5]); + + let error = table.column::("retries").unwrap_err(); + assert!(error.to_string().contains("not alloc::string::String")); + Ok(()) + } + + #[test] + fn soa_rejects_column_length_drift() { + let table = CultCacheSoaTable { + keys: vec!["app".to_string()], + types: Vec::new(), + payloads: Vec::new(), + stored_ats: Vec::new(), + schema_ids: Vec::new(), + }; + let error = table.validate().unwrap_err(); + assert!(error.to_string().contains("column types has length 0")); + } } From a539d4fb1ce90f86cc4f79d214dc48c1f8c369ab Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 3 Sep 2026 22:56:41 +0200 Subject: [PATCH 125/283] Return the Idunn and Odin authority contracts to CultLib The standalone GameCult/cultnet-rs holds six modules CultLib never received: runtime_authority_contracts, service_identity, provider_health_contracts, idunn_deployment_brake, idunn_lifecycle_brake, and snapshot_query. They own Idunn Expected incarnations, dual-proved runtime activation, process write leases, service-signed presence health, and Odin topology correlation -- the wire contracts every GameCult daemon must agree on. They belong here because wire parity conformance lives here and nothing outside it is checked for cross-runtime agreement. Held as source to be copied, this contract already forked: Ghostlight vendors it at e542225 while its own authority map names f4ab237, and the two disagree on whether Present may coexist with a disagreement. One copy makes them exclusive; the other separates presence from readiness and gates through into_undisputed_present. A single owner under the parity harness is the fix; re-vendoring is not. None of the six touch RUDP, so they land without disturbing the protocol core. rudp.rs remains genuinely forked -- 140 hunks between the lineages, with reliable windows and ACK horizons on this side and bounded session memory, exact acknowledgement receipts, and hostile rollover rejection on the other. That reconciliation needs the cross-runtime interop harness and is not attempted here. Adds ed25519-dalek, zeroize, and the Windows Foundation/Cryptography features the credential paths require. 96 tests pass. The two rudp_server_hub failures are pre-existing on this base and reproduce at 230ace6 untouched. Co-Authored-By: Claude Opus 5 --- packages/cultnet-rs/Cargo.toml | 5 + .../cultnet-rs/src/idunn_deployment_brake.rs | 492 +++ .../cultnet-rs/src/idunn_lifecycle_brake.rs | 325 ++ packages/cultnet-rs/src/lib.rs | 12 + .../src/provider_health_contracts.rs | 653 ++++ .../src/runtime_authority_contracts.rs | 3309 +++++++++++++++++ packages/cultnet-rs/src/service_identity.rs | 920 +++++ packages/cultnet-rs/src/snapshot_query.rs | 339 ++ 8 files changed, 6055 insertions(+) create mode 100644 packages/cultnet-rs/src/idunn_deployment_brake.rs create mode 100644 packages/cultnet-rs/src/idunn_lifecycle_brake.rs create mode 100644 packages/cultnet-rs/src/provider_health_contracts.rs create mode 100644 packages/cultnet-rs/src/runtime_authority_contracts.rs create mode 100644 packages/cultnet-rs/src/service_identity.rs create mode 100644 packages/cultnet-rs/src/snapshot_query.rs diff --git a/packages/cultnet-rs/Cargo.toml b/packages/cultnet-rs/Cargo.toml index 41d14b52..f289d86e 100644 --- a/packages/cultnet-rs/Cargo.toml +++ b/packages/cultnet-rs/Cargo.toml @@ -16,6 +16,7 @@ anyhow = "1" base64 = "0.22" chrono = { version = "0.4", features = ["serde"] } cultcache-rs = { path = "../cultcache-rs" } +ed25519-dalek = "2.2" hmac = "0.12" rand = "0.9" rmp-serde = "1.3" @@ -24,9 +25,13 @@ serde = { version = "1", features = ["derive"] } serde_bytes = "0.11" serde_json = "1" sha2 = "0.10" +zeroize = "1" socket2 = "0.5" uuid = { version = "1", features = ["v4"] } +[target.'cfg(windows)'.dependencies] +windows-sys = { version = "0.61", features = ["Win32_Foundation", "Win32_Security_Cryptography"] } + [dev-dependencies] pretty_assertions = "1.4" tempfile = "3" diff --git a/packages/cultnet-rs/src/idunn_deployment_brake.rs b/packages/cultnet-rs/src/idunn_deployment_brake.rs new file mode 100644 index 00000000..e790f2a1 --- /dev/null +++ b/packages/cultnet-rs/src/idunn_deployment_brake.rs @@ -0,0 +1,492 @@ +use anyhow::{Result, bail}; +use cultcache_rs::DatabaseEntry; + +use crate::{ + IdunnDeploymentBrakeOperatorIdentity, IdunnDeploymentBrakeReleasePurpose, + ServiceIdentitySignature, ServiceIdentityTrustAnchor, verify_service_identity_signature, +}; + +pub const IDUNN_DEPLOYMENT_BRAKE_SCHEMA: &str = "idunn.deployment_brake.v1"; +pub const IDUNN_DEPLOYMENT_BRAKE_TYPE: &str = "idunn.deployment_brake"; +pub const IDUNN_DEPLOYMENT_BRAKE_ID: &str = "idunn/deployment-brake"; +pub const IDUNN_DEPLOYMENT_BRAKE_AUTHORITY: &str = "idunn.deployment-brake"; +pub const IDUNN_DEPLOYMENT_BRAKE_SCOPE: &str = "deployment"; +pub const IDUNN_DEPLOYMENT_RELEASE_PURPOSE: &str = "idunn.deployment-release.v1"; +pub const IDUNN_DEPLOYMENT_RELEASE_MAX_LIFETIME_MILLIS: u64 = 15 * 60 * 1_000; + +/// Canonical deployment-facing brake projection consumed by Idunn. A released +/// status is not permission by itself: the authorization fields bind one +/// release and one deployment attempt for a short, explicit interval. +#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] +#[cultcache(type = "idunn.deployment_brake", schema = "idunn.deployment_brake.v1")] +pub struct IdunnDeploymentBrakeRecord { + #[cultcache(key = 0)] + pub schema_version: String, + #[cultcache(key = 1)] + pub brake_id: String, + #[cultcache(key = 2)] + pub authority: String, + #[cultcache(key = 3)] + pub runtime_id: String, + #[cultcache(key = 4)] + pub status: String, + #[cultcache(key = 5)] + pub scope: String, + #[cultcache(key = 6)] + pub reason: String, + #[cultcache(key = 7)] + pub observed_at_unix_millis: u64, + #[cultcache(key = 8)] + pub expires_at_unix_millis: Option, + #[cultcache(key = 9)] + pub authorization_id: Option, + #[cultcache(key = 10)] + pub authorization_purpose: Option, + #[cultcache(key = 11)] + pub authorized_release_id: Option, + #[cultcache(key = 12)] + pub authorized_deployment_id: Option, + #[cultcache(key = 13)] + pub authorized_by: Option, + #[cultcache(key = 14)] + pub authorization_issued_at_unix_millis: Option, + #[cultcache(key = 15)] + pub authorization_expires_at_unix_millis: Option, + #[cultcache(key = 16)] + pub signature_algorithm: Option, + #[cultcache(key = 17)] + pub signature: Option>, + #[cultcache(key = 18)] + pub private_state_exposed: bool, + /// Human/operator principal responsible for the latest transition. This is + /// distinct from `authorized_by`, which is the cryptographic identity id. + #[cultcache(key = 19)] + pub updated_by: String, +} + +impl IdunnDeploymentBrakeRecord { + pub fn validate(&self) -> Result<()> { + if self.schema_version != IDUNN_DEPLOYMENT_BRAKE_SCHEMA { + bail!("deployment brake schema is unsupported"); + } + identifier(&self.brake_id, "brake id")?; + identifier(&self.authority, "authority")?; + identifier(&self.runtime_id, "runtime id")?; + identifier(&self.reason, "reason")?; + identifier(&self.scope, "scope")?; + identifier(&self.updated_by, "updating operator")?; + if !matches!(self.status.as_str(), "engaged" | "released") + || self.observed_at_unix_millis == 0 + || self + .expires_at_unix_millis + .is_some_and(|v| v <= self.observed_at_unix_millis) + || self.private_state_exposed + { + bail!("deployment brake shape, lifetime, or privacy is invalid"); + } + + let authorization = [ + self.authorization_id.as_ref(), + self.authorization_purpose.as_ref(), + self.authorized_release_id.as_ref(), + self.authorized_deployment_id.as_ref(), + self.authorized_by.as_ref(), + self.signature_algorithm.as_ref(), + ]; + let has_authorization = authorization.iter().any(|v| v.is_some()) + || self.authorization_issued_at_unix_millis.is_some() + || self.authorization_expires_at_unix_millis.is_some() + || self.signature.is_some(); + if self.status == "engaged" { + if has_authorization { + bail!("engaged deployment brake must not carry release authorization"); + } + return Ok(()); + } + if authorization.iter().any(|v| v.is_none()) + || self.authorization_issued_at_unix_millis.is_none() + || self.authorization_expires_at_unix_millis.is_none() + || self.signature.is_none() + { + bail!("released deployment brake authorization is incomplete"); + } + for (value, label) in [ + (&self.authorization_id, "authorization id"), + (&self.authorized_release_id, "authorized release id"), + (&self.authorized_deployment_id, "authorized deployment id"), + (&self.authorized_by, "authorizer"), + ] { + identifier(value.as_deref().unwrap(), label)?; + } + let issued = self.authorization_issued_at_unix_millis.unwrap(); + let expires = self.authorization_expires_at_unix_millis.unwrap(); + if self.authorization_purpose.as_deref() != Some(IDUNN_DEPLOYMENT_RELEASE_PURPOSE) + || self.signature_algorithm.as_deref() != Some("ed25519") + || self.signature.as_ref().is_none_or(|v| v.len() != 64) + || issued < self.observed_at_unix_millis + || expires <= issued + || expires - issued > IDUNN_DEPLOYMENT_RELEASE_MAX_LIFETIME_MILLIS + || self + .expires_at_unix_millis + .is_some_and(|brake_expiry| expires > brake_expiry) + { + bail!("deployment release authorization purpose, signature, or lifetime is invalid"); + } + Ok(()) + } +} + +#[derive(Clone, Copy, Debug)] +pub enum IdunnDeploymentBrakeObservation<'a> { + Missing, + Corrupt, + Present(&'a IdunnDeploymentBrakeRecord), +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum IdunnDeploymentBrakeDenial { + Missing, + Corrupt, + Foreign, + WrongRuntime, + WrongScope, + Engaged, + Expired, + ReleaseMismatch, + DeploymentMismatch, + InvalidSignature, +} + +fn classify_idunn_deployment_brake( + observation: IdunnDeploymentBrakeObservation<'_>, + runtime_id: &str, + release_id: &str, + deployment_id: &str, + now_unix_millis: u64, +) -> std::result::Result<(), IdunnDeploymentBrakeDenial> { + let record = match observation { + IdunnDeploymentBrakeObservation::Missing => { + return Err(IdunnDeploymentBrakeDenial::Missing); + } + IdunnDeploymentBrakeObservation::Corrupt => { + return Err(IdunnDeploymentBrakeDenial::Corrupt); + } + IdunnDeploymentBrakeObservation::Present(record) => record, + }; + if record.validate().is_err() { + return Err(IdunnDeploymentBrakeDenial::Corrupt); + } + if record.brake_id != IDUNN_DEPLOYMENT_BRAKE_ID + || record.authority != IDUNN_DEPLOYMENT_BRAKE_AUTHORITY + { + return Err(IdunnDeploymentBrakeDenial::Foreign); + } + if record.runtime_id != runtime_id { + return Err(IdunnDeploymentBrakeDenial::WrongRuntime); + } + if !matches!(record.scope.as_str(), "all" | IDUNN_DEPLOYMENT_BRAKE_SCOPE) { + return Err(IdunnDeploymentBrakeDenial::WrongScope); + } + if record.status == "engaged" { + return Err(IdunnDeploymentBrakeDenial::Engaged); + } + if record + .expires_at_unix_millis + .is_some_and(|v| now_unix_millis >= v) + || record + .authorization_expires_at_unix_millis + .is_none_or(|v| now_unix_millis >= v) + || record + .authorization_issued_at_unix_millis + .is_none_or(|v| now_unix_millis < v) + { + return Err(IdunnDeploymentBrakeDenial::Expired); + } + if record.authorized_release_id.as_deref() != Some(release_id) { + return Err(IdunnDeploymentBrakeDenial::ReleaseMismatch); + } + if record.authorized_deployment_id.as_deref() != Some(deployment_id) { + return Err(IdunnDeploymentBrakeDenial::DeploymentMismatch); + } + Ok(()) +} + +pub fn evaluate_idunn_deployment_brake( + observation: IdunnDeploymentBrakeObservation<'_>, + operator_anchor: &ServiceIdentityTrustAnchor, + runtime_id: &str, + release_id: &str, + deployment_id: &str, + now_unix_millis: u64, +) -> std::result::Result<(), IdunnDeploymentBrakeDenial> { + classify_idunn_deployment_brake( + observation, + runtime_id, + release_id, + deployment_id, + now_unix_millis, + )?; + let IdunnDeploymentBrakeObservation::Present(record) = observation else { + unreachable!("successful classification always has a present record") + }; + verify_idunn_deployment_brake_authorization(record, operator_anchor) + .map_err(|_| IdunnDeploymentBrakeDenial::InvalidSignature) +} + +/// Verify the release grant using the dedicated operator public anchor. The +/// signed payload is the complete positional record with the signature field +/// empty, so authority, runtime, target IDs, and both time bounds are covered. +pub fn verify_idunn_deployment_brake_authorization( + record: &IdunnDeploymentBrakeRecord, + anchor: &ServiceIdentityTrustAnchor, +) -> Result<()> { + record.validate()?; + if record.status != "released" { + bail!("engaged deployment brake has no release authorization to verify"); + } + let identity_id = record + .authorized_by + .as_ref() + .ok_or_else(|| anyhow::anyhow!("deployment brake authorizer is absent"))?; + let signature = record + .signature + .as_ref() + .ok_or_else(|| anyhow::anyhow!("deployment brake signature is absent"))?; + let mut unsigned = record.clone(); + unsigned.signature = None; + verify_service_identity_signature::< + IdunnDeploymentBrakeOperatorIdentity, + IdunnDeploymentBrakeReleasePurpose, + >( + anchor, + &rmp_serde::to_vec(&unsigned)?, + &ServiceIdentitySignature { + identity_id: identity_id.clone(), + signature: signature.clone(), + }, + ) +} + +fn identifier(value: &str, label: &str) -> Result<()> { + if value.trim().is_empty() || value.len() > 256 || value.chars().any(char::is_control) { + bail!("{label} is empty, oversized, or contains control characters"); + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::enroll_service_identity_at; + + fn released() -> IdunnDeploymentBrakeRecord { + IdunnDeploymentBrakeRecord { + schema_version: IDUNN_DEPLOYMENT_BRAKE_SCHEMA.into(), + brake_id: IDUNN_DEPLOYMENT_BRAKE_ID.into(), + authority: IDUNN_DEPLOYMENT_BRAKE_AUTHORITY.into(), + runtime_id: "yggdrasil".into(), + status: "released".into(), + scope: "deployment".into(), + reason: "operator authorized one attempt".into(), + observed_at_unix_millis: 100, + expires_at_unix_millis: Some(1000), + authorization_id: Some("auth/r4".into()), + authorization_purpose: Some(IDUNN_DEPLOYMENT_RELEASE_PURPOSE.into()), + authorized_release_id: Some("release-4".into()), + authorized_deployment_id: Some("deployment-4".into()), + authorized_by: Some("operator/metacrat".into()), + authorization_issued_at_unix_millis: Some(100), + authorization_expires_at_unix_millis: Some(900), + signature_algorithm: Some("ed25519".into()), + signature: Some(vec![7; 64]), + private_state_exposed: false, + updated_by: "operator/metacrat".into(), + } + } + + #[test] + fn only_exact_bounded_release_is_permitted() { + let value = released(); + assert_eq!( + classify_idunn_deployment_brake( + IdunnDeploymentBrakeObservation::Present(&value), + "yggdrasil", + "release-4", + "deployment-4", + 500 + ), + Ok(()) + ); + assert_eq!( + classify_idunn_deployment_brake( + IdunnDeploymentBrakeObservation::Missing, + "yggdrasil", + "release-4", + "deployment-4", + 500 + ), + Err(IdunnDeploymentBrakeDenial::Missing) + ); + assert_eq!( + classify_idunn_deployment_brake( + IdunnDeploymentBrakeObservation::Corrupt, + "yggdrasil", + "release-4", + "deployment-4", + 500 + ), + Err(IdunnDeploymentBrakeDenial::Corrupt) + ); + assert_eq!( + classify_idunn_deployment_brake( + IdunnDeploymentBrakeObservation::Present(&value), + "yggdrasil", + "other", + "deployment-4", + 500 + ), + Err(IdunnDeploymentBrakeDenial::ReleaseMismatch) + ); + assert_eq!( + classify_idunn_deployment_brake( + IdunnDeploymentBrakeObservation::Present(&value), + "yggdrasil", + "release-4", + "other", + 500 + ), + Err(IdunnDeploymentBrakeDenial::DeploymentMismatch) + ); + assert_eq!( + classify_idunn_deployment_brake( + IdunnDeploymentBrakeObservation::Present(&value), + "yggdrasil", + "release-4", + "deployment-4", + 900 + ), + Err(IdunnDeploymentBrakeDenial::Expired) + ); + } + + #[test] + fn hostile_authority_scope_and_shape_substitutions_fail_closed() { + let mut value = released(); + value.authority = "idunn".into(); + assert_eq!( + classify_idunn_deployment_brake( + IdunnDeploymentBrakeObservation::Present(&value), + "yggdrasil", + "release-4", + "deployment-4", + 500 + ), + Err(IdunnDeploymentBrakeDenial::Foreign) + ); + let mut value = released(); + value.runtime_id = "nightwing".into(); + assert_eq!( + classify_idunn_deployment_brake( + IdunnDeploymentBrakeObservation::Present(&value), + "yggdrasil", + "release-4", + "deployment-4", + 500 + ), + Err(IdunnDeploymentBrakeDenial::WrongRuntime) + ); + let mut value = released(); + value.scope = "persona.public_speech".into(); + assert_eq!( + classify_idunn_deployment_brake( + IdunnDeploymentBrakeObservation::Present(&value), + "yggdrasil", + "release-4", + "deployment-4", + 500 + ), + Err(IdunnDeploymentBrakeDenial::WrongScope) + ); + let mut value = released(); + value.signature = Some(vec![0; 63]); + assert_eq!( + classify_idunn_deployment_brake( + IdunnDeploymentBrakeObservation::Present(&value), + "yggdrasil", + "release-4", + "deployment-4", + 500 + ), + Err(IdunnDeploymentBrakeDenial::Corrupt) + ); + let mut value = released(); + value.authorization_expires_at_unix_millis = + Some(100 + IDUNN_DEPLOYMENT_RELEASE_MAX_LIFETIME_MILLIS + 1); + assert!(value.validate().is_err()); + } + + #[test] + fn engaged_record_cannot_smuggle_authorization() { + let mut value = released(); + value.status = "engaged".into(); + assert!(value.validate().is_err()); + value.authorization_id = None; + value.authorization_purpose = None; + value.authorized_release_id = None; + value.authorized_deployment_id = None; + value.authorized_by = None; + value.authorization_issued_at_unix_millis = None; + value.authorization_expires_at_unix_millis = None; + value.signature_algorithm = None; + value.signature = None; + value.validate().unwrap(); + assert_eq!( + classify_idunn_deployment_brake( + IdunnDeploymentBrakeObservation::Present(&value), + "yggdrasil", + "release-4", + "deployment-4", + 500 + ), + Err(IdunnDeploymentBrakeDenial::Engaged) + ); + } + + #[test] + fn evaluation_requires_the_dedicated_operator_signature() -> Result<()> { + let temp = tempfile::tempdir()?; + let signer = enroll_service_identity_at::( + &temp.path().join("operator.cc"), + )?; + let anchor = signer.trust_anchor()?; + let mut value = released(); + value.authorized_by = Some(anchor.identity_id.clone()); + value.signature = None; + let proof = signer.sign::(&rmp_serde::to_vec(&value)?); + value.signature = Some(proof.signature); + assert_eq!( + evaluate_idunn_deployment_brake( + IdunnDeploymentBrakeObservation::Present(&value), + &anchor, + "yggdrasil", + "release-4", + "deployment-4", + 500, + ), + Ok(()) + ); + value.reason = "tampered after authorization".into(); + assert_eq!( + evaluate_idunn_deployment_brake( + IdunnDeploymentBrakeObservation::Present(&value), + &anchor, + "yggdrasil", + "release-4", + "deployment-4", + 500, + ), + Err(IdunnDeploymentBrakeDenial::InvalidSignature) + ); + Ok(()) + } +} diff --git a/packages/cultnet-rs/src/idunn_lifecycle_brake.rs b/packages/cultnet-rs/src/idunn_lifecycle_brake.rs new file mode 100644 index 00000000..86eefa64 --- /dev/null +++ b/packages/cultnet-rs/src/idunn_lifecycle_brake.rs @@ -0,0 +1,325 @@ +use anyhow::{Result, bail}; +use cultcache_rs::DatabaseEntry; + +pub const IDUNN_LIFECYCLE_BRAKE_SCHEMA: &str = "idunn.lifecycle_brake.v1"; +pub const IDUNN_LIFECYCLE_BRAKE_TYPE: &str = "idunn.lifecycle_brake"; +pub const IDUNN_LIFECYCLE_BRAKE_AUTHORITY: &str = "idunn.root"; +pub const IDUNN_LIFECYCLE_BRAKE_SCOPE: &str = "continuity-restart"; + +/// Root-owned, per-target continuity brake. This document has no authority over +/// Idunn startup, deployment, route admission, or any target other than the one +/// named in `target`. +#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] +#[cultcache(type = "idunn.lifecycle_brake", schema = "idunn.lifecycle_brake.v1")] +pub struct IdunnLifecycleBrakeRecord { + #[cultcache(key = 0)] + pub schema_version: String, + #[cultcache(key = 1)] + pub authority: String, + #[cultcache(key = 2)] + pub runtime_id: String, + #[cultcache(key = 3)] + pub target: String, + #[cultcache(key = 4)] + pub scope: String, + #[cultcache(key = 5)] + pub status: String, + #[cultcache(key = 6)] + pub reason: String, + #[cultcache(key = 7)] + pub updated_at_unix_millis: u64, + #[cultcache(key = 8)] + pub released_until_unix_millis: Option, +} + +impl IdunnLifecycleBrakeRecord { + pub fn validate(&self) -> Result<()> { + if self.schema_version != IDUNN_LIFECYCLE_BRAKE_SCHEMA { + bail!("lifecycle brake schema is unsupported"); + } + identifier(&self.authority, "authority")?; + identifier(&self.runtime_id, "runtime id")?; + identifier(&self.target, "target")?; + identifier(&self.scope, "scope")?; + identifier(&self.reason, "reason")?; + if !matches!(self.status.as_str(), "engaged" | "released") + || self.updated_at_unix_millis == 0 + { + bail!("lifecycle brake status or update time is invalid"); + } + if self.status == "engaged" && self.released_until_unix_millis.is_some() { + bail!("engaged lifecycle brake cannot carry a release expiry"); + } + if self + .released_until_unix_millis + .is_some_and(|expires| expires <= self.updated_at_unix_millis) + { + bail!("lifecycle brake release expiry is not after its update"); + } + Ok(()) + } + + pub fn canonical_bytes(&self) -> Result> { + self.validate()?; + Ok(rmp_serde::to_vec(self)?) + } + + pub fn decode_canonical(payload: &[u8]) -> Result { + if messagepack_array_len(payload) != Some(9) { + bail!("lifecycle brake is not the 9-field positional contract"); + } + let value: Self = rmp_serde::from_slice(payload)?; + value.validate()?; + if rmp_serde::to_vec(&value)? != payload { + bail!("lifecycle brake encoding is not canonical"); + } + Ok(value) + } +} + +#[derive(Clone, Copy, Debug)] +pub enum IdunnLifecycleBrakeObservation<'a> { + Missing, + Corrupt, + Present(&'a IdunnLifecycleBrakeRecord), +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum IdunnLifecycleBrakeDenial { + Corrupt, + Foreign, + WrongRuntime, + WrongTarget, + Engaged, + Expired, +} + +/// Decide only whether Idunn may restart one already-admitted target to keep it +/// alive. Absence is the default allow state; a present record must bind the +/// exact Idunn runtime and target and must be explicitly released. +pub fn evaluate_idunn_continuity_restart( + observation: IdunnLifecycleBrakeObservation<'_>, + runtime_id: &str, + target: &str, + now_unix_millis: u64, +) -> std::result::Result<(), IdunnLifecycleBrakeDenial> { + let record = match observation { + IdunnLifecycleBrakeObservation::Missing => return Ok(()), + IdunnLifecycleBrakeObservation::Corrupt => { + return Err(IdunnLifecycleBrakeDenial::Corrupt); + } + IdunnLifecycleBrakeObservation::Present(record) => record, + }; + if record.validate().is_err() { + return Err(IdunnLifecycleBrakeDenial::Corrupt); + } + if record.authority != IDUNN_LIFECYCLE_BRAKE_AUTHORITY + || record.scope != IDUNN_LIFECYCLE_BRAKE_SCOPE + { + return Err(IdunnLifecycleBrakeDenial::Foreign); + } + if record.runtime_id != runtime_id { + return Err(IdunnLifecycleBrakeDenial::WrongRuntime); + } + if record.target != target { + return Err(IdunnLifecycleBrakeDenial::WrongTarget); + } + if record.status == "engaged" { + return Err(IdunnLifecycleBrakeDenial::Engaged); + } + if record + .released_until_unix_millis + .is_some_and(|expires| now_unix_millis >= expires) + { + return Err(IdunnLifecycleBrakeDenial::Expired); + } + Ok(()) +} + +fn identifier(value: &str, label: &str) -> Result<()> { + if value.trim().is_empty() || value.len() > 256 || value.chars().any(char::is_control) { + bail!("{label} is empty, oversized, or contains control characters"); + } + Ok(()) +} + +fn messagepack_array_len(payload: &[u8]) -> Option { + match *payload.first()? { + marker @ 0x90..=0x9f => Some((marker & 0x0f) as usize), + 0xdc if payload.len() >= 3 => Some(u16::from_be_bytes([payload[1], payload[2]]) as usize), + 0xdd if payload.len() >= 5 => { + Some(u32::from_be_bytes([payload[1], payload[2], payload[3], payload[4]]) as usize) + } + _ => None, + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn released() -> IdunnLifecycleBrakeRecord { + IdunnLifecycleBrakeRecord { + schema_version: IDUNN_LIFECYCLE_BRAKE_SCHEMA.into(), + authority: IDUNN_LIFECYCLE_BRAKE_AUTHORITY.into(), + runtime_id: "idunn-yggdrasil".into(), + target: "ghostlight".into(), + scope: IDUNN_LIFECYCLE_BRAKE_SCOPE.into(), + status: "released".into(), + reason: "continuity restart permitted".into(), + updated_at_unix_millis: 100, + released_until_unix_millis: None, + } + } + + fn evaluate( + observation: IdunnLifecycleBrakeObservation<'_>, + target: &str, + now: u64, + ) -> std::result::Result<(), IdunnLifecycleBrakeDenial> { + evaluate_idunn_continuity_restart(observation, "idunn-yggdrasil", target, now) + } + + #[test] + fn lifecycle_brake_round_trips_only_as_the_canonical_positional_contract() -> Result<()> { + let value = released(); + let encoded = value.canonical_bytes()?; + assert_eq!(encoded[0], 0x99); + assert_eq!( + IdunnLifecycleBrakeRecord::decode_canonical(&encoded)?, + value + ); + + let mut noncanonical = vec![0xdc, 0, 9]; + noncanonical.extend_from_slice(&encoded[1..]); + assert!(IdunnLifecycleBrakeRecord::decode_canonical(&noncanonical).is_err()); + + let mut extended = encoded; + extended[0] = 0x9a; + extended.push(0xc0); + assert!(IdunnLifecycleBrakeRecord::decode_canonical(&extended).is_err()); + Ok(()) + } + + #[test] + fn absence_and_explicit_release_allow_only_the_named_continuity_restart() { + assert_eq!( + evaluate(IdunnLifecycleBrakeObservation::Missing, "ghostlight", 500), + Ok(()) + ); + + let mut value = released(); + assert_eq!( + evaluate( + IdunnLifecycleBrakeObservation::Present(&value), + "ghostlight", + 500 + ), + Ok(()) + ); + value.released_until_unix_millis = Some(900); + assert_eq!( + evaluate( + IdunnLifecycleBrakeObservation::Present(&value), + "ghostlight", + 899 + ), + Ok(()) + ); + assert_eq!( + evaluate( + IdunnLifecycleBrakeObservation::Present(&value), + "ghostlight", + 900 + ), + Err(IdunnLifecycleBrakeDenial::Expired) + ); + assert_eq!( + evaluate(IdunnLifecycleBrakeObservation::Missing, "odin", 900), + Ok(()) + ); + assert_eq!( + evaluate(IdunnLifecycleBrakeObservation::Present(&value), "odin", 500), + Err(IdunnLifecycleBrakeDenial::WrongTarget) + ); + } + + #[test] + fn corrupt_foreign_wrong_runtime_and_wrong_target_records_deny() { + assert_eq!( + evaluate(IdunnLifecycleBrakeObservation::Corrupt, "ghostlight", 500), + Err(IdunnLifecycleBrakeDenial::Corrupt) + ); + + let mut value = released(); + value.status = "paused".into(); + assert_eq!( + evaluate( + IdunnLifecycleBrakeObservation::Present(&value), + "ghostlight", + 500 + ), + Err(IdunnLifecycleBrakeDenial::Corrupt) + ); + + let mut value = released(); + value.authority = "service-owned".into(); + assert_eq!( + evaluate( + IdunnLifecycleBrakeObservation::Present(&value), + "ghostlight", + 500 + ), + Err(IdunnLifecycleBrakeDenial::Foreign) + ); + + let mut value = released(); + value.scope = "deployment".into(); + assert_eq!( + evaluate( + IdunnLifecycleBrakeObservation::Present(&value), + "ghostlight", + 500 + ), + Err(IdunnLifecycleBrakeDenial::Foreign) + ); + + let value = released(); + assert_eq!( + evaluate_idunn_continuity_restart( + IdunnLifecycleBrakeObservation::Present(&value), + "idunn-nightwing", + "ghostlight", + 500 + ), + Err(IdunnLifecycleBrakeDenial::WrongRuntime) + ); + assert_eq!( + evaluate(IdunnLifecycleBrakeObservation::Present(&value), "odin", 500), + Err(IdunnLifecycleBrakeDenial::WrongTarget) + ); + } + + #[test] + fn engaged_always_denies_and_cannot_smuggle_a_release_expiry() { + let mut value = released(); + value.status = "engaged".into(); + assert_eq!( + evaluate( + IdunnLifecycleBrakeObservation::Present(&value), + "ghostlight", + 500 + ), + Err(IdunnLifecycleBrakeDenial::Engaged) + ); + value.released_until_unix_millis = Some(900); + assert_eq!( + evaluate( + IdunnLifecycleBrakeObservation::Present(&value), + "ghostlight", + 500 + ), + Err(IdunnLifecycleBrakeDenial::Corrupt) + ); + } +} diff --git a/packages/cultnet-rs/src/lib.rs b/packages/cultnet-rs/src/lib.rs index 6fb1d38d..3e8a3c94 100644 --- a/packages/cultnet-rs/src/lib.rs +++ b/packages/cultnet-rs/src/lib.rs @@ -1,4 +1,10 @@ mod contracts; +mod idunn_deployment_brake; +mod idunn_lifecycle_brake; +mod provider_health_contracts; +mod runtime_authority_contracts; +mod service_identity; +mod snapshot_query; mod cultmesh; mod framing; mod operation_service; @@ -11,6 +17,12 @@ mod shard_catalog; mod transport; pub use contracts::*; +pub use idunn_deployment_brake::*; +pub use idunn_lifecycle_brake::*; +pub use provider_health_contracts::*; +pub use runtime_authority_contracts::*; +pub use service_identity::*; +pub use snapshot_query::*; pub use cultmesh::*; pub use framing::*; pub use operation_service::*; diff --git a/packages/cultnet-rs/src/provider_health_contracts.rs b/packages/cultnet-rs/src/provider_health_contracts.rs new file mode 100644 index 00000000..5ca320f0 --- /dev/null +++ b/packages/cultnet-rs/src/provider_health_contracts.rs @@ -0,0 +1,653 @@ +use anyhow::{Context, Result, anyhow, bail}; +use cultcache_rs::DatabaseEntry; +use serde::{Deserialize, Serialize}; + +use crate::runtime_authority_contracts::{ + GAMECULT_RUNTIME_PRESENCE_HEALTH_SCHEMA, GAMECULT_RUNTIME_PRESENCE_HEALTH_SIGNING_PURPOSE, + ODIN_RUNTIME_TOPOLOGY_CORRELATION_SCHEMA, ODIN_RUNTIME_TOPOLOGY_CORRELATION_SIGNING_PURPOSE, +}; +use crate::{ + GameCultProviderHealthIdentity, IdunnServiceIdentity, OdinTopologyIdentity, + derive_service_identity_id, +}; + +pub const GAMECULT_SERVICE_TRUST_ANCHOR_SCHEMA: &str = "gamecult.service_trust_anchor.v1"; +pub const IDUNN_AUTHENTICATED_PROVIDER_HEALTH_PROJECTION_SCHEMA: &str = + "idunn.authenticated_provider_health_projection.v1"; +pub const IDUNN_SIGNED_DAEMON_HEALTH_SCHEMA: &str = "idunn.signed_daemon_health.v1"; +pub const IDUNN_AUTHENTICATED_PROVIDER_HEALTH_PROJECTION_SIGNING_PURPOSE: &str = + "idunn.authenticated-provider-health-projection.v1"; +pub const IDUNN_PROVIDER_ACTIVE_REASON: &str = "authenticated_provider_active"; +pub const IDUNN_PROVIDER_WARMING_REASON: &str = "authenticated_provider_warming"; +pub const IDUNN_PROVIDER_DEGRADED_REASON: &str = "authenticated_provider_degraded"; +pub const IDUNN_PROVIDER_FAILED_REASON: &str = "authenticated_provider_failed"; + +/// Provider-owned health statement. Ingress verifies `signature` over the +/// complete positional record with this field empty before admitting it. +#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] +#[cultcache( + type = "idunn.signed_daemon_health", + schema = "idunn.signed_daemon_health.v1" +)] +pub struct IdunnSignedDaemonHealthRecord { + #[cultcache(key = 0)] + pub schema_version: String, + #[cultcache(key = 1)] + pub daemon_id: String, + #[cultcache(key = 2)] + pub health_contract: String, + #[cultcache(key = 3)] + pub source_runtime_id: String, + #[cultcache(key = 4)] + pub state: String, + #[cultcache(key = 5)] + pub detail: String, + #[cultcache(key = 6)] + pub signer_identity_id: String, + #[cultcache(key = 7)] + pub publisher_incarnation_id: String, + #[cultcache(key = 8)] + pub publisher_sequence: u64, + #[cultcache(key = 9)] + pub observed_at_unix_millis: u64, + #[cultcache(key = 10)] + pub release_id: Option, + #[cultcache(key = 11)] + pub release_witness_sha256: Option, + #[cultcache(key = 12)] + pub source_commit: Option, + #[cultcache(key = 13)] + pub deployment_id: Option, + #[cultcache(key = 14)] + pub signature_algorithm: String, + #[cultcache(key = 15, bytes)] + pub signature: Vec, + #[cultcache(key = 16)] + pub private_state_exposed: bool, + #[cultcache(key = 17, default)] + pub activation_witness_sha256: Option, +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +struct LegacyIdunnSignedDaemonHealthWire { + schema_version: String, + daemon_id: String, + health_contract: String, + source_runtime_id: String, + state: String, + detail: String, + signer_identity_id: String, + publisher_incarnation_id: String, + publisher_sequence: u64, + observed_at_unix_millis: u64, + release_id: Option, + release_witness_sha256: Option, + source_commit: Option, + deployment_id: Option, + signature_algorithm: String, + #[serde(with = "serde_bytes")] + signature: Vec, + private_state_exposed: bool, +} + +impl From for IdunnSignedDaemonHealthRecord { + fn from(value: LegacyIdunnSignedDaemonHealthWire) -> Self { + Self { + schema_version: value.schema_version, + daemon_id: value.daemon_id, + health_contract: value.health_contract, + source_runtime_id: value.source_runtime_id, + state: value.state, + detail: value.detail, + signer_identity_id: value.signer_identity_id, + publisher_incarnation_id: value.publisher_incarnation_id, + publisher_sequence: value.publisher_sequence, + observed_at_unix_millis: value.observed_at_unix_millis, + release_id: value.release_id, + release_witness_sha256: value.release_witness_sha256, + source_commit: value.source_commit, + deployment_id: value.deployment_id, + signature_algorithm: value.signature_algorithm, + signature: value.signature, + private_state_exposed: value.private_state_exposed, + activation_witness_sha256: None, + } + } +} + +impl IdunnSignedDaemonHealthRecord { + /// Decode the canonical current or pre-activation positional wire and + /// return the exact wire generation's unsigned signature payload. + pub fn decode_canonical_signed_payload(payload: &[u8]) -> Result<(Self, Vec)> { + match messagepack_array_len(payload) { + Some(18) => { + let statement: Self = rmp_serde::from_slice(payload) + .context("decoding generic signed daemon health")?; + if rmp_serde::to_vec(&statement)? != payload { + bail!("signed daemon health payload is not canonical positional MessagePack"); + } + let mut unsigned = statement.clone(); + unsigned.signature.clear(); + Ok((statement, rmp_serde::to_vec(&unsigned)?)) + } + Some(17) => { + let legacy: LegacyIdunnSignedDaemonHealthWire = rmp_serde::from_slice(payload) + .context("decoding legacy generic signed daemon health")?; + if rmp_serde::to_vec(&legacy)? != payload { + bail!("signed daemon health payload is not canonical positional MessagePack"); + } + let mut unsigned = legacy.clone(); + unsigned.signature.clear(); + let unsigned_payload = rmp_serde::to_vec(&unsigned)?; + Ok((legacy.into(), unsigned_payload)) + } + _ => bail!("signed daemon health payload is not canonical positional MessagePack"), + } + } + + pub fn validate(&self) -> Result<()> { + if self.schema_version != IDUNN_SIGNED_DAEMON_HEALTH_SCHEMA { + bail!("signed daemon health schema is unsupported"); + } + validate_identifier(&self.daemon_id, "daemon id")?; + validate_identifier(&self.health_contract, "health contract")?; + validate_identifier(&self.source_runtime_id, "source runtime id")?; + validate_identifier(&self.signer_identity_id, "signer identity id")?; + validate_identifier(&self.publisher_incarnation_id, "publisher incarnation id")?; + if !matches!( + self.state.as_str(), + "active" | "warming" | "degraded" | "failed" + ) || self.detail.len() > 512 + || self.signature_algorithm != "ed25519" + || self.signature.len() != 64 + || self.publisher_sequence == 0 + || self.observed_at_unix_millis == 0 + { + bail!("signed daemon health shape is invalid"); + } + validate_optional_release_binding( + &self.release_id, + &self.release_witness_sha256, + &self.source_commit, + )?; + validate_optional_identifier(&self.deployment_id, "deployment id")?; + validate_optional_sha256(&self.activation_witness_sha256, "activation witness sha256")?; + if self.private_state_exposed { + bail!("signed daemon health exposes private state"); + } + Ok(()) + } +} + +fn messagepack_array_len(payload: &[u8]) -> Option { + match *payload.first()? { + marker @ 0x90..=0x9f => Some(usize::from(marker & 0x0f)), + 0xdc => Some(usize::from(u16::from_be_bytes([ + *payload.get(1)?, + *payload.get(2)?, + ]))), + 0xdd => usize::try_from(u32::from_be_bytes([ + *payload.get(1)?, + *payload.get(2)?, + *payload.get(3)?, + *payload.get(4)?, + ])) + .ok(), + _ => None, + } +} + +/// Root-distributed public key binding for one service-owned signed contract. +/// Consumers pin this document; a self-declared key inside a signed projection +/// is never authority. +#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] +#[cultcache( + type = "gamecult.service_trust_anchor", + schema = "gamecult.service_trust_anchor.v1" +)] +pub struct GameCultServiceTrustAnchorRecord { + #[cultcache(key = 0)] + pub schema_version: String, + #[cultcache(key = 1)] + pub trust_anchor_id: String, + #[cultcache(key = 2)] + pub service_id: String, + #[cultcache(key = 3)] + pub runtime_id: String, + #[cultcache(key = 4)] + pub signer_identity_id: String, + #[cultcache(key = 5)] + pub signer_public_key: Vec, + #[cultcache(key = 6)] + pub signature_algorithm: String, + #[cultcache(key = 7)] + pub signing_purpose: String, + #[cultcache(key = 8)] + pub signed_schema: String, + #[cultcache(key = 9)] + pub binding_authority: String, + #[cultcache(key = 10)] + pub bound_at_unix_millis: u64, + #[cultcache(key = 11)] + pub expires_at_unix_millis: Option, + #[cultcache(key = 12)] + pub private_state_exposed: bool, +} + +impl GameCultServiceTrustAnchorRecord { + pub fn validate(&self) -> Result<()> { + if self.schema_version != GAMECULT_SERVICE_TRUST_ANCHOR_SCHEMA { + bail!("service trust anchor schema is unsupported"); + } + validate_identifier(&self.trust_anchor_id, "trust anchor id")?; + validate_identifier(&self.service_id, "service id")?; + validate_identifier(&self.runtime_id, "runtime id")?; + validate_identifier(&self.signer_identity_id, "signer identity id")?; + validate_identifier(&self.signing_purpose, "signing purpose")?; + validate_identifier(&self.signed_schema, "signed schema")?; + if self.signer_public_key.len() != 32 + || self.signature_algorithm != "ed25519" + || self.binding_authority != "root" + || self.bound_at_unix_millis == 0 + || self + .expires_at_unix_millis + .is_some_and(|expires_at| expires_at <= self.bound_at_unix_millis) + || self.private_state_exposed + { + bail!("service trust anchor authority, key, lifetime, or privacy is invalid"); + } + if self.signed_schema == IDUNN_AUTHENTICATED_PROVIDER_HEALTH_PROJECTION_SCHEMA + && (self.service_id != "idunn" + || self.signing_purpose + != IDUNN_AUTHENTICATED_PROVIDER_HEALTH_PROJECTION_SIGNING_PURPOSE + || self.signer_identity_id + != derive_service_identity_id::(&self.signer_public_key)?) + { + bail!("Idunn provider-health trust anchor profile is invalid"); + } + let is_runtime_presence_profile = self + .signed_schema + .starts_with("gamecult.runtime_presence_health.") + || self + .signing_purpose + .starts_with("gamecult.runtime_presence_health."); + if is_runtime_presence_profile + && (self.signed_schema != GAMECULT_RUNTIME_PRESENCE_HEALTH_SCHEMA + || self.signing_purpose != GAMECULT_RUNTIME_PRESENCE_HEALTH_SIGNING_PURPOSE + || self.signer_identity_id + != derive_service_identity_id::( + &self.signer_public_key, + )?) + { + bail!("runtime presence trust anchor profile is invalid"); + } + if (self.signed_schema == ODIN_RUNTIME_TOPOLOGY_CORRELATION_SCHEMA + || self.signing_purpose == ODIN_RUNTIME_TOPOLOGY_CORRELATION_SIGNING_PURPOSE) + && (self.signed_schema != ODIN_RUNTIME_TOPOLOGY_CORRELATION_SCHEMA + || self.signing_purpose != ODIN_RUNTIME_TOPOLOGY_CORRELATION_SIGNING_PURPOSE + || self.service_id != "odin" + || self.signer_identity_id + != derive_service_identity_id::(&self.signer_public_key)?) + { + bail!("Odin topology correlation trust anchor profile is invalid"); + } + Ok(()) + } +} + +/// Idunn-owned public projection of one current authenticated generic provider +/// admission. Absence and dependency failure produce no record; they are not +/// provider states Idunn may manufacture. +#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] +#[cultcache( + type = "idunn.authenticated_provider_health_projection", + schema = "idunn.authenticated_provider_health_projection.v1" +)] +pub struct IdunnAuthenticatedProviderHealthProjectionRecord { + #[cultcache(key = 0)] + pub schema_version: String, + #[cultcache(key = 1)] + pub projection_id: String, + #[cultcache(key = 2)] + pub daemon_id: String, + #[cultcache(key = 3)] + pub health_contract: String, + #[cultcache(key = 4)] + pub provider_state: String, + #[cultcache(key = 5)] + pub reason_code: String, + #[cultcache(key = 6)] + pub provider_observed_at_unix_millis: u64, + #[cultcache(key = 7)] + pub admitted_at_unix_millis: u64, + #[cultcache(key = 8)] + pub evaluated_at_unix_millis: u64, + #[cultcache(key = 9)] + pub trust_binding_id: String, + #[cultcache(key = 10)] + pub trust_binding_sha256: String, + #[cultcache(key = 11)] + pub signed_health_sha256: String, + #[cultcache(key = 12)] + pub authenticated_admission_sha256: String, + #[cultcache(key = 13)] + pub provider_signer_identity_id: String, + #[cultcache(key = 14)] + pub provider_incarnation_id: String, + #[cultcache(key = 15)] + pub provider_sequence: u64, + #[cultcache(key = 16)] + pub release_id: Option, + #[cultcache(key = 17)] + pub release_witness_sha256: Option, + #[cultcache(key = 18)] + pub source_commit: Option, + #[cultcache(key = 19)] + pub deployment_id: Option, + #[cultcache(key = 20)] + pub idunn_runtime_id: String, + #[cultcache(key = 21)] + pub idunn_signer_identity_id: String, + #[cultcache(key = 22)] + pub projection_incarnation_id: String, + #[cultcache(key = 23)] + pub projection_sequence: u64, + #[cultcache(key = 24)] + pub signature_algorithm: String, + #[cultcache(key = 25)] + pub signature: Vec, + #[cultcache(key = 26)] + pub private_state_exposed: bool, + #[cultcache(key = 27)] + pub expires_at_unix_millis: u64, +} + +/// Closed derivation for an authenticated provider state. `None` means no +/// provider-health projection may be published. +pub fn authenticated_provider_health_reason_code(state: &str) -> Option<&'static str> { + match state { + "active" => Some(IDUNN_PROVIDER_ACTIVE_REASON), + "warming" => Some(IDUNN_PROVIDER_WARMING_REASON), + "degraded" => Some(IDUNN_PROVIDER_DEGRADED_REASON), + "failed" => Some(IDUNN_PROVIDER_FAILED_REASON), + _ => None, + } +} + +impl IdunnAuthenticatedProviderHealthProjectionRecord { + pub fn validate(&self) -> Result<()> { + if self.schema_version != IDUNN_AUTHENTICATED_PROVIDER_HEALTH_PROJECTION_SCHEMA { + bail!("authenticated provider health projection schema is unsupported"); + } + validate_identifier(&self.projection_id, "projection id")?; + validate_identifier(&self.daemon_id, "daemon id")?; + validate_identifier(&self.health_contract, "health contract")?; + validate_identifier(&self.trust_binding_id, "trust binding id")?; + validate_identifier( + &self.provider_signer_identity_id, + "provider signer identity id", + )?; + validate_identifier(&self.provider_incarnation_id, "provider incarnation id")?; + validate_identifier(&self.idunn_runtime_id, "Idunn runtime id")?; + validate_identifier(&self.idunn_signer_identity_id, "Idunn signer identity id")?; + validate_identifier(&self.projection_incarnation_id, "projection incarnation id")?; + let reason_is_valid = authenticated_provider_health_reason_code(&self.provider_state) + .is_some_and(|reason| reason == self.reason_code); + if !reason_is_valid + || self.provider_observed_at_unix_millis == 0 + || self.admitted_at_unix_millis < self.provider_observed_at_unix_millis + || self.evaluated_at_unix_millis < self.admitted_at_unix_millis + || self.expires_at_unix_millis <= self.evaluated_at_unix_millis + || self.provider_sequence == 0 + || self.projection_sequence == 0 + || !is_sha256(&self.trust_binding_sha256) + || !is_sha256(&self.signed_health_sha256) + || !is_sha256(&self.authenticated_admission_sha256) + || self.signature_algorithm != "ed25519" + || self.signature.len() != 64 + || self.private_state_exposed + { + bail!( + "authenticated provider health projection shape, lineage, reason, signature, or privacy is invalid" + ); + } + validate_optional_release_binding( + &self.release_id, + &self.release_witness_sha256, + &self.source_commit, + )?; + validate_optional_identifier(&self.deployment_id, "deployment id")?; + if self.deployment_id.is_some() != self.release_id.is_some() { + bail!("authenticated provider health projection release lineage is partial"); + } + Ok(()) + } +} + +fn validate_identifier(value: &str, label: &str) -> Result<()> { + if value.trim().is_empty() || value.len() > 256 || value.chars().any(char::is_control) { + bail!("{label} is empty, oversized, or contains control characters"); + } + Ok(()) +} + +fn validate_optional_identifier(value: &Option, label: &str) -> Result<()> { + if let Some(value) = value { + validate_identifier(value, label)?; + } + Ok(()) +} + +fn validate_optional_sha256(value: &Option, label: &str) -> Result<()> { + if value.as_deref().is_some_and(|value| !is_sha256(value)) { + bail!("{label} is malformed"); + } + Ok(()) +} + +fn validate_optional_release_binding( + release_id: &Option, + witness: &Option, + source_commit: &Option, +) -> Result<()> { + if release_id.is_some() || witness.is_some() || source_commit.is_some() { + validate_optional_identifier(release_id, "release id")?; + let witness = witness + .as_deref() + .ok_or_else(|| anyhow!("release witness is absent"))?; + let commit = source_commit + .as_deref() + .ok_or_else(|| anyhow!("source commit is absent"))?; + if release_id.is_none() || !is_sha256(witness) || !is_lower_hex(commit, 40) { + bail!("release binding is incomplete or malformed"); + } + } + Ok(()) +} + +fn is_sha256(value: &str) -> bool { + value + .strip_prefix("sha256-") + .is_some_and(|digest| is_lower_hex(digest, 64)) +} + +fn is_lower_hex(value: &str, length: usize) -> bool { + value.len() == length + && value + .bytes() + .all(|byte| byte.is_ascii_hexdigit() && !byte.is_ascii_uppercase()) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn signed_health() -> IdunnSignedDaemonHealthRecord { + IdunnSignedDaemonHealthRecord { + schema_version: IDUNN_SIGNED_DAEMON_HEALTH_SCHEMA.into(), + daemon_id: "epiphany".into(), + health_contract: "epiphany.cultnet-rudp-runtime-health".into(), + source_runtime_id: "epiphany-yggdrasil".into(), + state: "active".into(), + detail: "managed-services-current".into(), + signer_identity_id: "provider-signing-key".into(), + publisher_incarnation_id: "9c2cba2e-c2de-4750-b222-b732f97d0435".into(), + publisher_sequence: 1, + observed_at_unix_millis: 100, + release_id: Some("release-1".into()), + release_witness_sha256: Some(format!("sha256-{}", "d".repeat(64))), + source_commit: Some("e".repeat(40)), + deployment_id: Some("deployment-1".into()), + signature_algorithm: "ed25519".into(), + signature: vec![6; 64], + private_state_exposed: false, + activation_witness_sha256: Some(format!("sha256-{}", "f".repeat(64))), + } + } + + fn anchor() -> GameCultServiceTrustAnchorRecord { + let public_key = vec![5; 32]; + GameCultServiceTrustAnchorRecord { + schema_version: GAMECULT_SERVICE_TRUST_ANCHOR_SCHEMA.into(), + trust_anchor_id: "root/idunn/provider-health".into(), + service_id: "idunn".into(), + runtime_id: "idunn-yggdrasil".into(), + signer_identity_id: derive_service_identity_id::(&public_key) + .unwrap(), + signer_public_key: public_key, + signature_algorithm: "ed25519".into(), + signing_purpose: IDUNN_AUTHENTICATED_PROVIDER_HEALTH_PROJECTION_SIGNING_PURPOSE.into(), + signed_schema: IDUNN_AUTHENTICATED_PROVIDER_HEALTH_PROJECTION_SCHEMA.into(), + binding_authority: "root".into(), + bound_at_unix_millis: 100, + expires_at_unix_millis: Some(200), + private_state_exposed: false, + } + } + + fn projection() -> IdunnAuthenticatedProviderHealthProjectionRecord { + IdunnAuthenticatedProviderHealthProjectionRecord { + schema_version: IDUNN_AUTHENTICATED_PROVIDER_HEALTH_PROJECTION_SCHEMA.into(), + projection_id: "authenticated-provider-health:epiphany".into(), + daemon_id: "epiphany".into(), + health_contract: "health.v1".into(), + provider_state: "active".into(), + reason_code: IDUNN_PROVIDER_ACTIVE_REASON.into(), + provider_observed_at_unix_millis: 100, + admitted_at_unix_millis: 101, + evaluated_at_unix_millis: 102, + trust_binding_id: "root/epiphany".into(), + trust_binding_sha256: format!("sha256-{}", "a".repeat(64)), + signed_health_sha256: format!("sha256-{}", "b".repeat(64)), + authenticated_admission_sha256: format!("sha256-{}", "c".repeat(64)), + provider_signer_identity_id: "provider-signing-key".into(), + provider_incarnation_id: "provider/boot/1".into(), + provider_sequence: 1, + release_id: Some("release-1".into()), + release_witness_sha256: Some(format!("sha256-{}", "d".repeat(64))), + source_commit: Some("e".repeat(40)), + deployment_id: Some("deployment-1".into()), + idunn_runtime_id: "idunn-yggdrasil".into(), + idunn_signer_identity_id: "idunn-signing-key".into(), + projection_incarnation_id: "idunn/boot/1".into(), + projection_sequence: 1, + signature_algorithm: "ed25519".into(), + signature: vec![6; 64], + private_state_exposed: false, + expires_at_unix_millis: 200, + } + } + + #[test] + fn contracts_accept_exact_root_and_lineage_shapes() -> Result<()> { + let anchor = anchor(); + let projection = projection(); + let health = signed_health(); + anchor.validate()?; + projection.validate()?; + health.validate()?; + let encoded = rmp_serde::to_vec(&health)?; + assert_eq!(encoded.first().copied(), Some(0xdc)); + assert_eq!(&encoded[1..3], &[0, 18]); + assert!( + encoded + .windows(4) + .any(|window| window == [0xc4, 0x40, 6, 6]), + "provider signature must use the portable MessagePack binary shape" + ); + assert_eq!( + rmp_serde::from_slice::(&encoded)?, + health + ); + assert_eq!( + rmp_serde::from_slice::(&rmp_serde::to_vec( + &anchor + )?)?, + anchor + ); + assert_eq!( + rmp_serde::from_slice::( + &rmp_serde::to_vec(&projection)? + )?, + projection + ); + assert_eq!(authenticated_provider_health_reason_code("missing"), None); + Ok(()) + } + + #[test] + fn activation_binding_is_additive_for_legacy_generic_health_records() -> Result<()> { + let mut health = signed_health(); + health.activation_witness_sha256 = None; + let mut legacy = rmp_serde::to_vec(&health)?; + assert_eq!(&legacy[..3], &[0xdc, 0, 18]); + assert_eq!(legacy.pop(), Some(0xc0)); + legacy[2] = 17; + let decoded: IdunnSignedDaemonHealthRecord = rmp_serde::from_slice(&legacy)?; + assert_eq!(decoded.activation_witness_sha256, None); + decoded.validate()?; + let (decoded, unsigned) = + IdunnSignedDaemonHealthRecord::decode_canonical_signed_payload(&legacy)?; + assert_eq!(decoded.activation_witness_sha256, None); + assert_eq!(&unsigned[..3], &[0xdc, 0, 17]); + Ok(()) + } + + #[test] + fn contracts_refuse_substitution_and_manufactured_states() { + let mut value = anchor(); + value.binding_authority = "idunn".into(); + assert!(value.validate().is_err()); + let mut value = anchor(); + value.signer_identity_id = "caller-selected".into(); + assert!(value.validate().is_err()); + let mut value = projection(); + value.reason_code = "release_drift".into(); + assert!(value.validate().is_err()); + let mut value = projection(); + value.provider_state = "missing".into(); + assert!(value.validate().is_err()); + let mut value = projection(); + value.deployment_id = None; + assert!(value.validate().is_err()); + let mut value = projection(); + value.signature.clear(); + assert!(value.validate().is_err()); + let mut value = projection(); + value.signed_health_sha256 = format!("sha256-{}", "A".repeat(64)); + assert!(value.validate().is_err()); + let mut value = signed_health(); + value.publisher_sequence = 0; + assert!(value.validate().is_err()); + let mut value = signed_health(); + value.activation_witness_sha256 = Some(format!("sha256-{}", "F".repeat(64))); + assert!(value.validate().is_err()); + let mut value = signed_health(); + value.release_witness_sha256 = None; + assert!(value.validate().is_err()); + let mut value = signed_health(); + value.private_state_exposed = true; + assert!(value.validate().is_err()); + } +} diff --git a/packages/cultnet-rs/src/runtime_authority_contracts.rs b/packages/cultnet-rs/src/runtime_authority_contracts.rs new file mode 100644 index 00000000..426be1fb --- /dev/null +++ b/packages/cultnet-rs/src/runtime_authority_contracts.rs @@ -0,0 +1,3309 @@ +use anyhow::{Context, Result, bail, ensure}; +use cultcache_rs::DatabaseEntry; +use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey}; +use rand::RngCore; +use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; +use std::io::{Read, Write}; +use zeroize::Zeroizing; + +pub const GAMECULT_RUNTIME_PRESENCE_HEALTH_SCHEMA: &str = "gamecult.runtime_presence_health.v2"; +pub const GAMECULT_RUNTIME_PRESENCE_HEALTH_SIGNING_PURPOSE: &str = + "gamecult.runtime_presence_health.v2"; +pub const GAMECULT_RUNTIME_ACTIVATION_PROOF_SIGNING_PURPOSE: &str = + "gamecult.runtime_presence.activation-proof.v1"; +pub const IDUNN_RUNTIME_ACTIVATION_SCHEMA: &str = "idunn.runtime_activation.v2"; +pub const IDUNN_RUNTIME_ACTIVATION_SIGNING_PURPOSE: &str = "idunn.runtime_activation.v2"; +pub const IDUNN_RUNTIME_ACTIVATION_CREDENTIAL_NAME: &str = "gamecult-idunn-runtime-activation-key"; +pub const IDUNN_PROCESS_WRITE_LEASE_SCHEMA: &str = "idunn.process_write_lease.v1"; +pub const IDUNN_EXPECTED_INCARNATION_SCHEMA: &str = "idunn.expected_incarnation.v2"; +pub const ODIN_RUNTIME_TOPOLOGY_CORRELATION_SCHEMA: &str = "odin.runtime_topology_correlation.v2"; +pub const ODIN_RUNTIME_TOPOLOGY_CORRELATION_SIGNING_PURPOSE: &str = + "odin.runtime_topology_correlation.v2"; + +const MAX_RUNTIME_CAPABILITIES: usize = 256; +const MAX_RUNTIME_DEPENDENCIES: usize = 256; +const MAX_TOPOLOGY_DISAGREEMENTS: usize = 256; +const IDUNN_RUNTIME_ACTIVATION_ID_DOMAIN: &[u8] = b"idunn.runtime-activation.id.v1\0"; +const IDUNN_RUNTIME_ACTIVATION_SIGNATURE_DOMAIN: &[u8] = b"idunn.runtime-activation.signature.v1\0"; + +/// One provider-owned capability claim inside a runtime-presence statement. +/// The enclosing vector is canonical only when these records are strictly +/// increasing by `(capability, schema, compatibility)`. Capacity describes +/// that one claim and does not create a second identity for the same claim. +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct GameCultRuntimeCapability { + pub capability: String, + pub schema: String, + pub compatibility: String, + pub capacity: u32, +} + +impl GameCultRuntimeCapability { + fn identity(&self) -> (&str, &str, &str) { + (&self.capability, &self.schema, &self.compatibility) + } +} + +/// Idunn's admitted requirement for one provider-owned runtime capability. +/// The provider reports actual capacity in `GameCultRuntimeCapability`; this +/// record states only the minimum needed for this incarnation to be Ready. +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct IdunnExpectedCapability { + pub capability: String, + pub schema: String, + pub compatibility: String, + pub minimum_capacity: u32, +} + +impl IdunnExpectedCapability { + fn identity(&self) -> (&str, &str, &str) { + (&self.capability, &self.schema, &self.compatibility) + } +} + +/// Dual-proved claim from one exact runtime launch. The stable provider key and +/// Idunn's activation-scoped ephemeral key both sign `canonical_proof_payload`: +/// the canonical positional encoding of this complete record with both proof +/// byte fields empty. Present authority requires a matching Idunn-published +/// current activation; neither proof can establish admission by itself. +#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] +#[cultcache( + type = "gamecult.runtime_presence_health", + schema = "gamecult.runtime_presence_health.v2" +)] +pub struct GameCultRuntimePresenceHealthRecord { + #[cultcache(key = 0)] + pub schema_version: String, + #[cultcache(key = 1)] + pub target: String, + #[cultcache(key = 2)] + pub expected_projection_sha256: String, + #[cultcache(key = 3)] + pub plan_id: String, + #[cultcache(key = 4)] + pub incarnation_id: String, + #[cultcache(key = 5)] + pub sealed_release_id: String, + #[cultcache(key = 6)] + pub activation_witness_sha256: String, + #[cultcache(key = 7)] + pub state_schema_generation: Option, + #[cultcache(key = 8)] + pub state_contract_sha256: Option, + #[cultcache(key = 9)] + pub runtime_id: String, + #[cultcache(key = 10)] + pub runtime_instance_id: String, + #[cultcache(key = 11)] + pub bound_endpoint: Option, + #[cultcache(key = 12)] + pub capabilities: Vec, + #[cultcache(key = 13)] + pub health_contract: String, + #[cultcache(key = 14)] + pub state: String, + #[cultcache(key = 15)] + pub detail: String, + #[cultcache(key = 16)] + pub write_lease_sha256: Option, + #[cultcache(key = 17)] + pub signer_identity_id: String, + #[cultcache(key = 18)] + pub publisher_sequence: u64, + #[cultcache(key = 19)] + pub observed_at_unix_millis: u64, + #[cultcache(key = 20)] + pub signature_algorithm: String, + #[cultcache(key = 21, bytes)] + pub signature: Vec, + #[cultcache(key = 22)] + pub activation_signer_identity_id: String, + #[cultcache(key = 23, bytes)] + pub activation_signature: Vec, +} + +impl GameCultRuntimePresenceHealthRecord { + /// Return the one canonical payload covered by both the stable provider + /// signature and the activation-scoped proof. Both signature fields are + /// empty in these bytes, avoiding circular signatures while binding every + /// authority-bearing statement field and both signer identities. + pub fn canonical_proof_payload(&self) -> Result> { + self.validate_shape(true)?; + let mut unsigned = self.clone(); + unsigned.signature.clear(); + unsigned.activation_signature.clear(); + Ok(rmp_serde::to_vec(&unsigned)?) + } + + /// Digest the complete signed presence record for an Odin correlation + /// receipt. An unsigned construction value is deliberately not digestible. + pub fn canonical_sha256(&self) -> Result { + self.validate()?; + Ok(prefixed_sha256(&rmp_serde::to_vec(self)?)) + } + + pub fn validate(&self) -> Result<()> { + self.validate_shape(false) + } + + fn validate_shape(&self, allow_unsigned: bool) -> Result<()> { + if self.schema_version != GAMECULT_RUNTIME_PRESENCE_HEALTH_SCHEMA { + bail!("runtime presence schema is unsupported"); + } + validate_authority_identifier(&self.target, "target")?; + validate_required_sha256( + &self.expected_projection_sha256, + "expected projection sha256", + )?; + validate_required_sha256(&self.plan_id, "plan id")?; + validate_authority_identifier(&self.incarnation_id, "incarnation id")?; + validate_required_sha256(&self.sealed_release_id, "sealed release id")?; + validate_required_sha256(&self.activation_witness_sha256, "activation witness sha256")?; + match (&self.state_schema_generation, &self.state_contract_sha256) { + (Some(generation), Some(contract_sha256)) => { + validate_authority_identifier(generation, "state schema generation")?; + validate_required_sha256(contract_sha256, "state contract sha256")?; + } + (None, None) => {} + _ => bail!("runtime presence state lineage is partial"), + } + validate_authority_identifier(&self.runtime_id, "runtime id")?; + validate_required_sha256(&self.runtime_instance_id, "runtime instance id")?; + validate_optional_endpoint(&self.bound_endpoint)?; + validate_runtime_capabilities(&self.capabilities)?; + validate_authority_identifier(&self.health_contract, "health contract")?; + validate_authority_identifier(&self.signer_identity_id, "signer identity id")?; + validate_authority_identifier( + &self.activation_signer_identity_id, + "activation signer identity id", + )?; + validate_optional_sha256(&self.write_lease_sha256, "write lease sha256")?; + + let signature_is_valid = + self.signature.len() == 64 || (allow_unsigned && self.signature.is_empty()); + let activation_signature_is_valid = self.activation_signature.len() == 64 + || (allow_unsigned && self.activation_signature.is_empty()); + if self.publisher_sequence == 0 + || self.observed_at_unix_millis == 0 + || !matches!( + self.state.as_str(), + "warming" | "active" | "degraded" | "failed" + ) + || self.detail.len() > 512 + || self.detail.chars().any(char::is_control) + || self.signature_algorithm != "ed25519" + || !signature_is_valid + || !activation_signature_is_valid + { + bail!("runtime presence state, sequence, detail, or signature is invalid"); + } + if self.state == "warming" && self.write_lease_sha256.is_some() { + bail!("warming runtime presence cannot claim a process write lease"); + } + if self.state_schema_generation.is_none() && self.write_lease_sha256.is_some() { + bail!("stateless runtime presence cannot claim a process write lease"); + } + Ok(()) + } +} + +/// Public route facts admitted for one incarnation. These are service-facing +/// endpoints only; actuator paths, unit files, container sockets, and runner +/// credentials do not belong in the Expected projection. +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct IdunnExpectedRoute { + pub route_id: String, + pub transport: String, + pub stable_endpoint: String, + pub candidate_endpoint: String, +} + +impl IdunnExpectedRoute { + fn validate(&self) -> Result<()> { + validate_authority_identifier(&self.route_id, "route id")?; + validate_endpoint(&self.stable_endpoint, "stable route endpoint")?; + validate_endpoint(&self.candidate_endpoint, "candidate route endpoint")?; + if self.stable_endpoint == self.candidate_endpoint { + bail!("stable and candidate route endpoints are identical"); + } + match self.transport.as_str() { + "http" => { + if !(self.stable_endpoint.starts_with("http://") + || self.stable_endpoint.starts_with("https://")) + || !self.candidate_endpoint.starts_with("http://") + { + bail!("HTTP route endpoints use an unsupported scheme"); + } + } + "tcp" => { + if !self.stable_endpoint.starts_with("tcp://") + || !self.candidate_endpoint.starts_with("tcp://") + { + bail!("TCP route endpoints use an unsupported scheme"); + } + } + "rudp" => { + if !self.stable_endpoint.starts_with("rudp://") + || !self.candidate_endpoint.starts_with("rudp://") + { + bail!("RUDP route endpoints use an unsupported scheme"); + } + } + _ => bail!("route transport is unsupported"), + } + Ok(()) + } +} + +/// One capability requirement and Idunn's exact admitted provider selection. +/// Provider fields are all absent while unresolved. Managed providers bind an +/// Expected digest; external operator bindings instead bind an endpoint. +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct IdunnExpectedDependency { + pub kind: String, + pub capability: String, + pub schema: String, + pub compatibility: String, + pub minimum_capacity: u32, + pub startup: String, + pub provider_id: Option, + pub provider_authority: Option, + pub provider_expected_projection_sha256: Option, + pub provider_endpoint: Option, +} + +impl IdunnExpectedDependency { + fn identity(&self) -> (&str, &str, &str) { + (&self.capability, &self.schema, &self.compatibility) + } + + fn validate(&self) -> Result<()> { + if !matches!( + self.kind.as_str(), + "bootstrap" + | "required" + | "optional" + | "shared-infrastructure" + | "private" + | "external-operator-binding" + ) { + bail!("dependency kind is unsupported"); + } + validate_authority_identifier(&self.capability, "dependency capability")?; + validate_authority_identifier(&self.schema, "dependency schema")?; + validate_authority_identifier(&self.compatibility, "dependency compatibility")?; + if self.minimum_capacity == 0 + || !matches!(self.startup.as_str(), "before-start" | "before-promotion") + { + bail!("dependency capacity or startup condition is invalid"); + } + if self.kind == "bootstrap" && self.startup != "before-start" { + bail!("bootstrap dependency must be satisfied before start"); + } + validate_optional_identifier(&self.provider_id, "dependency provider id")?; + validate_optional_identifier(&self.provider_authority, "dependency provider authority")?; + validate_optional_sha256( + &self.provider_expected_projection_sha256, + "dependency provider expected projection sha256", + )?; + validate_optional_endpoint_labeled( + &self.provider_endpoint, + "dependency provider endpoint", + )?; + + match ( + &self.provider_id, + &self.provider_authority, + &self.provider_expected_projection_sha256, + &self.provider_endpoint, + ) { + (None, None, None, None) => {} + (Some(_), Some(authority), Some(_), _) if authority == "managed-incarnation" => { + if self.kind == "external-operator-binding" { + bail!("external operator dependency cannot select a managed incarnation"); + } + } + (Some(_), Some(authority), None, Some(_)) + if authority == "external-operator-binding" + && self.kind == "external-operator-binding" => {} + _ => bail!("dependency provider binding is partial or authority-incoherent"), + } + Ok(()) + } +} + +/// Idunn-owned desired deployment identity published into CultMesh before +/// promotion. It describes the admitted incarnation and its public contracts, +/// never the private details needed to execute it on a particular host. +#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] +#[cultcache( + type = "idunn.expected_incarnation", + schema = "idunn.expected_incarnation.v2" +)] +pub struct IdunnExpectedIncarnationRecord { + #[cultcache(key = 0)] + pub schema_version: String, + #[cultcache(key = 1)] + pub target: String, + #[cultcache(key = 2)] + pub plan_id: String, + #[cultcache(key = 3)] + pub incarnation_id: String, + #[cultcache(key = 4)] + pub sealed_release_id: String, + #[cultcache(key = 5)] + pub source_repository: String, + #[cultcache(key = 6)] + pub source_revision: String, + #[cultcache(key = 7)] + pub recipe_sha256: String, + #[cultcache(key = 8)] + pub runtime_id: String, + #[cultcache(key = 9)] + pub expected_signer_identity_id: String, + #[cultcache(key = 10)] + pub health_contract: String, + #[cultcache(key = 11)] + pub artifact_sha256: String, + #[cultcache(key = 12)] + pub state_schema_generation: Option, + #[cultcache(key = 13)] + pub state_contract_sha256: Option, + #[cultcache(key = 14)] + pub write_lease_required: bool, + #[cultcache(key = 15)] + pub route: Option, + #[cultcache(key = 16)] + pub capabilities: Vec, + #[cultcache(key = 17)] + pub dependencies: Vec, +} + +impl IdunnExpectedIncarnationRecord { + pub fn decode_canonical(payload: &[u8]) -> Result { + if messagepack_array_len(payload) != Some(18) { + bail!("expected incarnation is not the 18-field positional contract"); + } + let expected: Self = + rmp_serde::from_slice(payload).context("decoding expected incarnation")?; + if rmp_serde::to_vec(&expected)? != payload { + bail!("expected incarnation is not canonical positional MessagePack"); + } + expected.validate()?; + Ok(expected) + } + + pub fn canonical_bytes(&self) -> Result> { + self.validate()?; + Ok(rmp_serde::to_vec(self)?) + } + + pub fn canonical_sha256(&self) -> Result { + Ok(prefixed_sha256(&self.canonical_bytes()?)) + } + + pub fn validate(&self) -> Result<()> { + if self.schema_version != IDUNN_EXPECTED_INCARNATION_SCHEMA { + bail!("expected incarnation schema is unsupported"); + } + validate_authority_identifier(&self.target, "target")?; + validate_required_sha256(&self.plan_id, "plan id")?; + validate_authority_identifier(&self.incarnation_id, "incarnation id")?; + validate_required_sha256(&self.sealed_release_id, "sealed release id")?; + validate_source_repository(&self.source_repository)?; + if !is_lower_hex(&self.source_revision, 40) { + bail!("source revision is not a lowercase Git object id"); + } + validate_required_sha256(&self.recipe_sha256, "recipe sha256")?; + validate_authority_identifier(&self.runtime_id, "runtime id")?; + validate_authority_identifier( + &self.expected_signer_identity_id, + "expected signer identity id", + )?; + validate_authority_identifier(&self.health_contract, "health contract")?; + validate_required_sha256(&self.artifact_sha256, "artifact sha256")?; + match (&self.state_schema_generation, &self.state_contract_sha256) { + (Some(generation), Some(contract_sha256)) => { + validate_authority_identifier(generation, "state schema generation")?; + validate_required_sha256(contract_sha256, "state contract sha256")?; + } + (None, None) => {} + _ => bail!("expected incarnation state lineage is partial"), + } + if self.write_lease_required && self.state_schema_generation.is_none() { + bail!("stateless incarnation cannot require a process write lease"); + } + if let Some(route) = &self.route { + route.validate()?; + } + validate_expected_capabilities(&self.capabilities)?; + validate_expected_dependencies(&self.dependencies)?; + Ok(()) + } +} + +/// Odin's observation of one dependency selected in the bound Expected +/// projection. Evidence digests identify the signed/provider-owned facts Odin +/// used; they do not copy those facts into Odin authority. +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct OdinRuntimeDependencyEvidence { + pub kind: String, + pub capability: String, + pub schema: String, + pub compatibility: String, + pub provider_id: Option, + pub provider_authority: Option, + pub provider_expected_projection_sha256: Option, + pub provider_endpoint: Option, + pub observed_capacity: Option, + pub provider_evidence_sha256: Option, + pub ready: bool, +} + +impl OdinRuntimeDependencyEvidence { + fn identity(&self) -> (&str, &str, &str) { + (&self.capability, &self.schema, &self.compatibility) + } + + fn validate(&self) -> Result<()> { + if !matches!( + self.kind.as_str(), + "bootstrap" + | "required" + | "optional" + | "shared-infrastructure" + | "private" + | "external-operator-binding" + ) { + bail!("dependency evidence kind is unsupported"); + } + validate_authority_identifier(&self.kind, "dependency evidence kind")?; + validate_authority_identifier(&self.capability, "dependency evidence capability")?; + validate_authority_identifier(&self.schema, "dependency evidence schema")?; + validate_authority_identifier(&self.compatibility, "dependency evidence compatibility")?; + validate_optional_identifier(&self.provider_id, "dependency evidence provider id")?; + validate_optional_identifier( + &self.provider_authority, + "dependency evidence provider authority", + )?; + validate_optional_sha256( + &self.provider_expected_projection_sha256, + "dependency evidence provider expected projection sha256", + )?; + validate_optional_endpoint_labeled( + &self.provider_endpoint, + "dependency evidence provider endpoint", + )?; + validate_optional_sha256( + &self.provider_evidence_sha256, + "dependency provider evidence sha256", + )?; + if self.observed_capacity == Some(0) { + bail!("dependency evidence capacity is zero"); + } + if self.provider_id.is_none() + && (self.provider_authority.is_some() + || self.provider_expected_projection_sha256.is_some() + || self.provider_endpoint.is_some() + || self.observed_capacity.is_some() + || self.provider_evidence_sha256.is_some() + || self.ready) + { + bail!("dependency evidence has facts without a provider"); + } + if self.provider_id.is_some() && self.provider_authority.is_none() { + bail!("dependency evidence provider authority is missing"); + } + match ( + &self.provider_id, + &self.provider_authority, + &self.provider_expected_projection_sha256, + &self.provider_endpoint, + ) { + (None, None, None, None) => {} + (Some(_), Some(authority), Some(_), _) if authority == "managed-incarnation" => { + if self.kind == "external-operator-binding" { + bail!("external dependency evidence names a managed incarnation"); + } + } + (Some(_), Some(authority), None, Some(_)) + if authority == "external-operator-binding" + && self.kind == "external-operator-binding" => {} + _ => bail!("dependency evidence provider binding is authority-incoherent"), + } + if self.ready + && (self.observed_capacity.is_none() || self.provider_evidence_sha256.is_none()) + { + bail!("ready dependency lacks capacity or signed evidence"); + } + Ok(()) + } +} + +/// One explicit Expected/observed disagreement. Codes are unique and sorted so +/// the signed receipt has one canonical explanation for each disagreement. +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct OdinTopologyDisagreement { + pub code: String, + pub expected: Option, + pub observed: Option, +} + +impl OdinTopologyDisagreement { + fn validate(&self) -> Result<()> { + validate_authority_identifier(&self.code, "topology disagreement code")?; + validate_optional_detail(&self.expected, "topology disagreement expected value")?; + validate_optional_detail(&self.observed, "topology disagreement observed value")?; + if self.expected.is_none() && self.observed.is_none() { + bail!("topology disagreement carries no expected or observed value"); + } + Ok(()) + } +} + +/// Odin-owned signed correlation of Idunn's exact Expected projection with +/// current Idunn activation and provider-signed presence. Presence state and +/// write-lease observation remain explicit so an opaque Ready bit cannot cross +/// Idunn's warming/fencing boundary. The signature covers the canonical +/// positional encoding with `signature` empty. +#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] +#[cultcache( + type = "odin.runtime_topology_correlation", + schema = "odin.runtime_topology_correlation.v2" +)] +pub struct OdinRuntimeTopologyCorrelationRecord { + #[cultcache(key = 0)] + pub schema_version: String, + #[cultcache(key = 1)] + pub target: String, + #[cultcache(key = 2)] + pub expected_projection_sha256: String, + #[cultcache(key = 3)] + pub expected: bool, + #[cultcache(key = 4)] + pub current_activation_sha256: Option, + #[cultcache(key = 5)] + pub signed_presence_sha256: Option, + #[cultcache(key = 6)] + pub observed_presence_state: Option, + #[cultcache(key = 7)] + pub observed_presence_publisher_sequence: Option, + #[cultcache(key = 8)] + pub observed_write_lease_sha256: Option, + #[cultcache(key = 9)] + pub observed_capabilities: Vec, + #[cultcache(key = 10)] + pub runtime_id: String, + #[cultcache(key = 11)] + pub runtime_instance_id: Option, + #[cultcache(key = 12)] + pub present: bool, + #[cultcache(key = 13)] + pub ready: bool, + #[cultcache(key = 14)] + pub dependencies: Vec, + #[cultcache(key = 15)] + pub disagreements: Vec, + #[cultcache(key = 16)] + pub signer_identity_id: String, + #[cultcache(key = 17)] + pub publisher_sequence: u64, + #[cultcache(key = 18)] + pub observed_at_unix_millis: u64, + #[cultcache(key = 19)] + pub signature_algorithm: String, + #[cultcache(key = 20, bytes)] + pub signature: Vec, +} + +impl OdinRuntimeTopologyCorrelationRecord { + pub fn decode_canonical_signed_payload(payload: &[u8]) -> Result<(Self, Vec)> { + if messagepack_array_len(payload) != Some(21) { + bail!("topology correlation is not the 21-field positional contract"); + } + let receipt: Self = + rmp_serde::from_slice(payload).context("decoding runtime topology correlation")?; + if rmp_serde::to_vec(&receipt)? != payload { + bail!("topology correlation is not canonical positional MessagePack"); + } + receipt.validate()?; + let unsigned = receipt.unsigned_signature_payload()?; + Ok((receipt, unsigned)) + } + + pub fn unsigned_signature_payload(&self) -> Result> { + self.validate_shape(true)?; + let mut unsigned = self.clone(); + unsigned.signature.clear(); + Ok(rmp_serde::to_vec(&unsigned)?) + } + + pub fn canonical_bytes(&self) -> Result> { + self.validate()?; + Ok(rmp_serde::to_vec(self)?) + } + + pub fn canonical_sha256(&self) -> Result { + Ok(prefixed_sha256(&self.canonical_bytes()?)) + } + + pub fn validate(&self) -> Result<()> { + self.validate_shape(false) + } + + pub fn validate_against_expected( + &self, + expected: &IdunnExpectedIncarnationRecord, + current_write_lease_sha256: Option<&str>, + ) -> Result<()> { + self.validate()?; + expected.validate()?; + if self.expected_projection_sha256 != expected.canonical_sha256()? + || self.target != expected.target + || self.runtime_id != expected.runtime_id + || self.dependencies.len() != expected.dependencies.len() + { + bail!("topology correlation substitutes or omits Expected authority"); + } + for (evidence, requirement) in self.dependencies.iter().zip(&expected.dependencies) { + if evidence.identity() != requirement.identity() + || evidence.kind != requirement.kind + || evidence.provider_id != requirement.provider_id + || evidence.provider_authority != requirement.provider_authority + || evidence.provider_expected_projection_sha256 + != requirement.provider_expected_projection_sha256 + || evidence.provider_endpoint != requirement.provider_endpoint + { + bail!("topology dependency evidence does not bind the Expected dependency"); + } + if evidence.ready + && evidence + .observed_capacity + .is_none_or(|capacity| capacity < requirement.minimum_capacity) + { + bail!("ready dependency does not meet Expected capacity"); + } + } + let mut capability_disagreements = Vec::new(); + correlate_capabilities( + &mut capability_disagreements, + &expected.capabilities, + &self.observed_capabilities, + ); + for disagreement in &capability_disagreements { + if !self.disagreements.contains(disagreement) { + bail!("topology correlation omits an observed capability disagreement"); + } + } + if let Some(current_write_lease_sha256) = current_write_lease_sha256 { + validate_required_sha256(current_write_lease_sha256, "current write lease sha256")?; + } + if expected.write_lease_required { + if self + .observed_write_lease_sha256 + .as_deref() + .is_some_and(|observed| Some(observed) != current_write_lease_sha256) + { + bail!("observed write lease is not the current Idunn grant"); + } + if self.ready + && (self.observed_write_lease_sha256.is_none() + || current_write_lease_sha256.is_none()) + { + bail!("Ready stateful topology lacks the exact current write lease"); + } + } else if self.observed_write_lease_sha256.is_some() || current_write_lease_sha256.is_some() + { + bail!("stateless Expected topology cannot carry a process write lease"); + } + Ok(()) + } + + fn validate_shape(&self, allow_unsigned: bool) -> Result<()> { + if self.schema_version != ODIN_RUNTIME_TOPOLOGY_CORRELATION_SCHEMA { + bail!("topology correlation schema is unsupported"); + } + validate_authority_identifier(&self.target, "target")?; + validate_required_sha256( + &self.expected_projection_sha256, + "correlation expected projection sha256", + )?; + if !self.expected { + bail!("topology correlation cannot deny the Expected record it binds"); + } + validate_optional_sha256(&self.current_activation_sha256, "current activation sha256")?; + validate_optional_sha256(&self.signed_presence_sha256, "signed presence sha256")?; + validate_optional_identifier(&self.observed_presence_state, "observed presence state")?; + if self.observed_presence_publisher_sequence == Some(0) { + bail!("observed presence publisher sequence is zero"); + } + validate_optional_sha256( + &self.observed_write_lease_sha256, + "observed write lease sha256", + )?; + validate_runtime_capabilities(&self.observed_capabilities)?; + if self.signed_presence_sha256.is_none() && !self.observed_capabilities.is_empty() { + bail!("topology correlation has capabilities without signed presence"); + } + match ( + &self.signed_presence_sha256, + &self.observed_presence_state, + self.observed_presence_publisher_sequence, + &self.observed_write_lease_sha256, + ) { + (None, None, None, None) => {} + (Some(_), Some(state), Some(_), write_lease) + if matches!(state.as_str(), "warming" | "active" | "degraded" | "failed") => + { + if state == "warming" && write_lease.is_some() { + bail!("warming topology presence cannot carry a process write lease"); + } + } + _ => bail!("signed presence state, sequence, or write-lease observation is partial"), + } + validate_authority_identifier(&self.runtime_id, "runtime id")?; + validate_optional_sha256(&self.runtime_instance_id, "runtime instance id")?; + let has_runtime_evidence = + self.current_activation_sha256.is_some() || self.signed_presence_sha256.is_some(); + if self.runtime_instance_id.is_some() != has_runtime_evidence { + bail!("runtime instance identity and observation evidence are partial"); + } + if self.present + && (self.current_activation_sha256.is_none() + || self.signed_presence_sha256.is_none() + || self.observed_presence_publisher_sequence.is_none() + || self.runtime_instance_id.is_none()) + { + bail!("Present topology state lacks an authenticated runtime session"); + } + validate_dependency_evidence(&self.dependencies)?; + validate_topology_disagreements(&self.disagreements)?; + let has_activation = self.current_activation_sha256.is_some(); + let has_presence = self.signed_presence_sha256.is_some(); + if has_activation && has_presence && !self.present { + bail!("authenticated runtime session cannot be projected as not Present"); + } + if has_activation != has_presence && self.disagreements.is_empty() { + bail!("partial or rejected runtime evidence lacks an explicit disagreement"); + } + if self.ready + && (!self.present + || self.observed_presence_state.as_deref() != Some("active") + || !self.disagreements.is_empty() + || self + .dependencies + .iter() + .any(|dependency| dependency.kind != "optional" && !dependency.ready)) + { + bail!("Ready topology state is not supported by correlated evidence"); + } + validate_authority_identifier(&self.signer_identity_id, "signer identity id")?; + let signature_is_valid = + self.signature.len() == 64 || (allow_unsigned && self.signature.is_empty()); + if self.publisher_sequence == 0 + || self.observed_at_unix_millis == 0 + || self.signature_algorithm != "ed25519" + || !signature_is_valid + { + bail!("topology correlation sequence, time, or signature is invalid"); + } + Ok(()) + } +} + +/// An in-memory activation-scoped signer reconstructed by the launched service +/// from its protected systemd credential. The stable service identity never +/// receives this key, and the public activation record never contains it. +pub struct IdunnRuntimeActivationSigner { + signing_key: SigningKey, +} + +impl IdunnRuntimeActivationSigner { + fn generate() -> Self { + let mut seed = Zeroizing::new([0_u8; 32]); + rand::rng().fill_bytes(seed.as_mut()); + Self { + signing_key: SigningKey::from_bytes(&*seed), + } + } + + /// Open the exact raw 32-byte Ed25519 seed supplied through Idunn's systemd + /// credential without retaining an ordinary heap copy. No persistent key + /// schema exists: this authority lives for one activation and is replaced + /// on every launch. + pub fn from_credential_reader(mut credential: impl Read) -> Result { + let mut seed = Zeroizing::new([0_u8; 32]); + credential + .read_exact(seed.as_mut()) + .context("reading runtime activation credential")?; + let mut extra = [0_u8; 1]; + if credential.read(&mut extra)? != 0 { + bail!("runtime activation credential is longer than 32 bytes"); + } + Ok(Self { + signing_key: SigningKey::from_bytes(&*seed), + }) + } + + fn write_credential(&self, mut destination: impl Write) -> Result<()> { + let seed = Zeroizing::new(self.signing_key.to_bytes()); + destination + .write_all(seed.as_ref()) + .context("writing runtime activation credential") + } + + pub fn public_key(&self) -> Vec { + self.signing_key.verifying_key().to_bytes().to_vec() + } + + pub fn identity_id(&self) -> String { + derive_idunn_runtime_activation_identity_id(&self.public_key()) + .expect("an Ed25519 activation signer always has a 32-byte public key") + } + + pub fn sign_presence_proof( + &self, + presence: &GameCultRuntimePresenceHealthRecord, + ) -> Result> { + if presence.activation_signer_identity_id != self.identity_id() { + bail!("runtime presence names a different activation signer"); + } + let payload = presence.canonical_proof_payload()?; + Ok(self + .signing_key + .sign(&runtime_activation_signing_message(&payload)) + .to_bytes() + .to_vec()) + } +} + +/// Idunn's one-shot launch material. Issuance always creates a fresh key, and +/// writing the protected credential consumes the only Idunn-side signer. +pub struct IdunnRuntimeActivationLaunch { + activation: IdunnRuntimeActivationRecord, + signer: IdunnRuntimeActivationSigner, +} + +impl IdunnRuntimeActivationLaunch { + pub fn issue( + expected: &IdunnExpectedIncarnationRecord, + runtime_instance_id: String, + issued_at_unix_millis: u64, + idunn_signer: &crate::ServiceIdentitySigner, + ) -> Result { + let signer = IdunnRuntimeActivationSigner::generate(); + let activation = IdunnRuntimeActivationRecord::issue_with_signer( + expected, + runtime_instance_id, + &signer, + issued_at_unix_millis, + idunn_signer, + )?; + Ok(Self { activation, signer }) + } + + pub fn activation(&self) -> &IdunnRuntimeActivationRecord { + &self.activation + } + + pub fn write_credential(self, destination: impl Write) -> Result { + self.signer.write_credential(destination)?; + Ok(self.activation) + } +} + +/// Derive the activation-scoped identity from the Idunn-issued public key. The +/// domain is dedicated to runtime activation and cannot be substituted for a +/// stable provider, Idunn, or Odin service identity. +pub fn derive_idunn_runtime_activation_identity_id(public_key: &[u8]) -> Result { + if public_key.len() != 32 { + bail!("runtime activation public key has invalid length"); + } + Ok(format!( + "{:x}", + Sha256::digest([IDUNN_RUNTIME_ACTIVATION_ID_DOMAIN, public_key].concat()) + )) +} + +/// Current Idunn authority for one launch. Idunn's stable signature binds the +/// complete Expected digest and activation key; Expected in turn pins the +/// provider signer identity. The provider public key is lookup material, not a +/// second authority: its profile-derived identity must equal Idunn's signed +/// selection exactly. +#[derive(Clone, Debug)] +pub struct VerifiedRuntimeAuthority { + expected: IdunnExpectedIncarnationRecord, + activation: IdunnRuntimeActivationRecord, + provider_signer_public_key: Vec, + expected_sha256: String, + activation_sha256: String, +} + +impl VerifiedRuntimeAuthority { + pub fn expected(&self) -> &IdunnExpectedIncarnationRecord { + &self.expected + } + + pub fn activation(&self) -> &IdunnRuntimeActivationRecord { + &self.activation + } + + pub fn expected_sha256(&self) -> &str { + &self.expected_sha256 + } + + pub fn activation_sha256(&self) -> &str { + &self.activation_sha256 + } +} + +pub fn verify_runtime_authority( + expected: &IdunnExpectedIncarnationRecord, + activation: &IdunnRuntimeActivationRecord, + idunn_anchor: &crate::ServiceIdentityTrustAnchor, + provider_signer_public_key: &[u8], +) -> Result { + expected.validate()?; + activation.verify_for_expected(expected, idunn_anchor)?; + if crate::derive_service_identity_id::( + provider_signer_public_key, + )? != expected.expected_signer_identity_id + { + bail!("provider public key is not Idunn's Expected signer selection"); + } + Ok(VerifiedRuntimeAuthority { + expected: expected.clone(), + activation: activation.clone(), + provider_signer_public_key: provider_signer_public_key.to_vec(), + expected_sha256: expected.canonical_sha256()?, + activation_sha256: activation.canonical_sha256()?, + }) +} + +#[derive(Clone, Copy, Debug)] +pub struct RuntimePresenceAuthenticationContext { + pub trusted_received_at_unix_millis: u64, + pub maximum_age_millis: u64, + pub maximum_future_skew_millis: u64, +} + +/// Canonical runtime bytes authenticated by both the Expected provider key and +/// the current activation key. No semantic claim has yet been accepted as +/// Present; Odin must correlate this observation against current authority. +#[derive(Clone, Debug)] +pub struct AuthenticatedRuntimePresenceClaim { + record: GameCultRuntimePresenceHealthRecord, + canonical_bytes: Vec, + signed_presence_sha256: String, + received_at_unix_millis: u64, +} + +impl AuthenticatedRuntimePresenceClaim { + pub fn record(&self) -> &GameCultRuntimePresenceHealthRecord { + &self.record + } + + pub fn canonical_bytes(&self) -> &[u8] { + &self.canonical_bytes + } + + pub fn signed_presence_sha256(&self) -> &str { + &self.signed_presence_sha256 + } + + pub fn received_at_unix_millis(&self) -> u64 { + self.received_at_unix_millis + } +} + +/// A signed Odin receipt authenticated against the exact current Expected, +/// activation, write lease, Idunn-admitted topology key, and trusted receipt +/// time. This is evidence, not a replay cursor or route-promotion grant. The +/// caller must source the key from Idunn's admitted Odin binding. Idunn's +/// durable admission owner must atomically check and advance Odin's publisher +/// sequence before treating the receipt as current. +#[derive(Clone, Debug)] +pub struct AuthenticatedOdinRuntimeTopologyCorrelation { + record: OdinRuntimeTopologyCorrelationRecord, + canonical_bytes: Vec, +} + +impl AuthenticatedOdinRuntimeTopologyCorrelation { + pub fn record(&self) -> &OdinRuntimeTopologyCorrelationRecord { + &self.record + } + + pub fn canonical_bytes(&self) -> &[u8] { + &self.canonical_bytes + } +} + +#[derive(Clone, Copy, Debug)] +pub struct OdinTopologyAuthenticationContext { + pub trusted_received_at_unix_millis: u64, + pub maximum_age_millis: u64, + pub maximum_future_skew_millis: u64, +} + +pub fn authenticate_odin_runtime_topology_correlation( + canonical_correlation: &[u8], + authority: &VerifiedRuntimeAuthority, + current_write_lease_sha256: Option<&str>, + admitted_odin_signer_public_key: &[u8], + context: OdinTopologyAuthenticationContext, +) -> Result { + ensure!( + context.trusted_received_at_unix_millis > 0 && context.maximum_age_millis > 0, + "Odin topology trusted time and maximum age must be positive" + ); + let (record, unsigned) = OdinRuntimeTopologyCorrelationRecord::decode_canonical_signed_payload( + canonical_correlation, + )?; + record.validate_against_expected(authority.expected(), current_write_lease_sha256)?; + if record.current_activation_sha256.as_deref() != Some(authority.activation_sha256()) + || record.runtime_instance_id.as_deref() + != Some(authority.activation.runtime_instance_id.as_str()) + { + bail!("topology correlation does not bind the current activation"); + } + let latest_trusted_timestamp = context + .trusted_received_at_unix_millis + .saturating_add(context.maximum_future_skew_millis); + if record.observed_at_unix_millis > latest_trusted_timestamp + || context + .trusted_received_at_unix_millis + .saturating_sub(record.observed_at_unix_millis) + > context.maximum_age_millis + { + bail!("Odin topology correlation is outside the trusted observation window"); + } + crate::verify_service_identity_signature_with_public_key::< + crate::OdinTopologyIdentity, + crate::OdinRuntimeTopologyCorrelationPurpose, + >( + admitted_odin_signer_public_key, + &unsigned, + &crate::ServiceIdentitySignature { + identity_id: record.signer_identity_id.clone(), + signature: record.signature.clone(), + }, + )?; + Ok(AuthenticatedOdinRuntimeTopologyCorrelation { + record, + canonical_bytes: canonical_correlation.to_vec(), + }) +} + +/// Odin's deterministic interpretation of an authenticated provider claim. +/// Authentication of the stable provider and current activation establishes +/// Present. Correlation disagreements remain explicit and deny Ready; they do +/// not erase the observed session that produced them. +#[derive(Clone, Debug)] +pub struct RuntimePresenceCorrelation { + presence: VerifiedRuntimePresence, + disagreements: Vec, +} + +impl RuntimePresenceCorrelation { + pub fn claim(&self) -> &AuthenticatedRuntimePresenceClaim { + &self.presence.claim + } + + pub fn disagreements(&self) -> &[OdinTopologyDisagreement] { + &self.disagreements + } + + pub fn into_present(self) -> VerifiedRuntimePresence { + self.presence + } + + pub fn into_undisputed_present(self) -> Result { + if !self.disagreements.is_empty() { + bail!("runtime presence disagrees with current Expected projection"); + } + Ok(self.presence) + } +} + +/// A dual-authenticated claim that matches current authority. This is the only +/// value that represents semantic Present. Replay admission deliberately does +/// not live here: Odin's durable store must atomically check and advance every +/// authenticated provider sequence, including disagreement-bearing claims, +/// before it signs a topology correlation. +#[derive(Clone, Debug)] +pub struct VerifiedRuntimePresence { + claim: AuthenticatedRuntimePresenceClaim, +} + +impl VerifiedRuntimePresence { + pub fn record(&self) -> &GameCultRuntimePresenceHealthRecord { + self.claim.record() + } + + pub fn canonical_bytes(&self) -> &[u8] { + self.claim.canonical_bytes() + } + + pub fn signed_presence_sha256(&self) -> &str { + self.claim.signed_presence_sha256() + } + + pub fn accepted_at_unix_millis(&self) -> u64 { + self.claim.received_at_unix_millis() + } +} + +pub fn authenticate_runtime_presence_claim( + canonical_presence: &[u8], + authority: &VerifiedRuntimeAuthority, + context: RuntimePresenceAuthenticationContext, +) -> Result { + ensure!( + context.trusted_received_at_unix_millis > 0 && context.maximum_age_millis > 0, + "runtime presence trusted time and maximum age must be positive" + ); + if messagepack_array_len(canonical_presence) != Some(24) { + bail!("runtime presence payload is not the 24-field positional contract"); + } + let presence: GameCultRuntimePresenceHealthRecord = + rmp_serde::from_slice(canonical_presence).context("decoding runtime presence health")?; + if rmp_serde::to_vec(&presence)? != canonical_presence { + bail!("runtime presence payload is not canonical positional MessagePack"); + } + presence.validate()?; + let latest_trusted_timestamp = context + .trusted_received_at_unix_millis + .saturating_add(context.maximum_future_skew_millis); + if presence.observed_at_unix_millis > latest_trusted_timestamp + || authority.activation.issued_at_unix_millis > latest_trusted_timestamp + || context + .trusted_received_at_unix_millis + .saturating_sub(presence.observed_at_unix_millis) + > context.maximum_age_millis + { + bail!("runtime presence is outside the trusted observation window"); + } + if presence.signer_identity_id != authority.expected.expected_signer_identity_id { + bail!("runtime presence signer is not Idunn's Expected signer selection"); + } + + let proof_payload = presence.canonical_proof_payload()?; + crate::verify_service_identity_signature_with_public_key::< + crate::GameCultProviderHealthIdentity, + crate::GameCultRuntimePresenceHealthPurpose, + >( + &authority.provider_signer_public_key, + &proof_payload, + &crate::ServiceIdentitySignature { + identity_id: presence.signer_identity_id.clone(), + signature: presence.signature.clone(), + }, + )?; + let activation_public_key: [u8; 32] = authority + .activation + .activation_signer_public_key + .as_slice() + .try_into() + .map_err(|_| anyhow::anyhow!("runtime activation public key has invalid length"))?; + let activation_signature = Signature::from_slice(&presence.activation_signature) + .map_err(|_| anyhow::anyhow!("runtime activation signature has invalid length"))?; + VerifyingKey::from_bytes(&activation_public_key)? + .verify( + &runtime_activation_signing_message(&proof_payload), + &activation_signature, + ) + .map_err(|_| anyhow::anyhow!("runtime activation proof verification failed"))?; + + Ok(AuthenticatedRuntimePresenceClaim { + record: presence, + canonical_bytes: canonical_presence.to_vec(), + signed_presence_sha256: prefixed_sha256(canonical_presence), + received_at_unix_millis: context.trusted_received_at_unix_millis, + }) +} + +pub fn correlate_runtime_presence_claim( + claim: AuthenticatedRuntimePresenceClaim, + authority: &VerifiedRuntimeAuthority, +) -> Result { + let expected = authority.expected(); + let activation = authority.activation(); + let presence = claim.record(); + let expected_endpoint = expected + .route + .as_ref() + .map(|route| route.candidate_endpoint.clone()); + let mut disagreements = Vec::new(); + push_disagreement( + &mut disagreements, + "activation-signer-identity", + Some(&activation.activation_signer_identity_id), + Some(&presence.activation_signer_identity_id), + ); + push_disagreement( + &mut disagreements, + "activation-witness", + Some(authority.activation_sha256()), + Some(&presence.activation_witness_sha256), + ); + push_disagreement( + &mut disagreements, + "bound-endpoint", + expected_endpoint.as_deref(), + presence.bound_endpoint.as_deref(), + ); + push_disagreement( + &mut disagreements, + "expected-projection", + Some(authority.expected_sha256()), + Some(&presence.expected_projection_sha256), + ); + push_disagreement( + &mut disagreements, + "health-contract", + Some(&expected.health_contract), + Some(&presence.health_contract), + ); + push_disagreement( + &mut disagreements, + "incarnation-id", + Some(&expected.incarnation_id), + Some(&presence.incarnation_id), + ); + push_disagreement( + &mut disagreements, + "plan-id", + Some(&expected.plan_id), + Some(&presence.plan_id), + ); + push_disagreement( + &mut disagreements, + "runtime-id", + Some(&expected.runtime_id), + Some(&presence.runtime_id), + ); + push_disagreement( + &mut disagreements, + "runtime-instance-id", + Some(&activation.runtime_instance_id), + Some(&presence.runtime_instance_id), + ); + push_disagreement( + &mut disagreements, + "sealed-release-id", + Some(&expected.sealed_release_id), + Some(&presence.sealed_release_id), + ); + push_disagreement( + &mut disagreements, + "signer-identity", + Some(&expected.expected_signer_identity_id), + Some(&presence.signer_identity_id), + ); + push_disagreement( + &mut disagreements, + "state-contract", + expected.state_contract_sha256.as_deref(), + presence.state_contract_sha256.as_deref(), + ); + push_disagreement( + &mut disagreements, + "state-schema-generation", + expected.state_schema_generation.as_deref(), + presence.state_schema_generation.as_deref(), + ); + push_disagreement( + &mut disagreements, + "target", + Some(&expected.target), + Some(&presence.target), + ); + if activation.issued_at_unix_millis > presence.observed_at_unix_millis { + disagreements.push(OdinTopologyDisagreement { + code: "activation-issued-after-presence".into(), + expected: Some(format!("at-most:{}", presence.observed_at_unix_millis)), + observed: Some(activation.issued_at_unix_millis.to_string()), + }); + } + correlate_capabilities( + &mut disagreements, + &expected.capabilities, + &presence.capabilities, + ); + disagreements.sort_by(|left, right| left.code.cmp(&right.code)); + validate_topology_disagreements(&disagreements)?; + Ok(RuntimePresenceCorrelation { + presence: VerifiedRuntimePresence { claim }, + disagreements, + }) +} + +fn push_disagreement( + disagreements: &mut Vec, + code: &str, + expected: Option<&str>, + observed: Option<&str>, +) { + if expected != observed { + disagreements.push(OdinTopologyDisagreement { + code: code.into(), + expected: expected.map(str::to_string), + observed: observed.map(str::to_string), + }); + } +} + +fn correlate_capabilities( + disagreements: &mut Vec, + expected: &[IdunnExpectedCapability], + observed: &[GameCultRuntimeCapability], +) { + for (index, required) in expected.iter().enumerate() { + let actual = observed + .iter() + .find(|actual| actual.identity() == required.identity()); + let requirement = format!( + "{}/{}/{} capacity>={}", + required.capability, required.schema, required.compatibility, required.minimum_capacity + ); + match actual { + None => disagreements.push(OdinTopologyDisagreement { + code: format!("expected-capability-{index:03}-missing"), + expected: Some(requirement), + observed: None, + }), + Some(actual) if actual.capacity < required.minimum_capacity => { + disagreements.push(OdinTopologyDisagreement { + code: format!("expected-capability-{index:03}-capacity"), + expected: Some(requirement), + observed: Some(format!("capacity={}", actual.capacity)), + }); + } + Some(_) => {} + } + } +} + +fn runtime_activation_signing_message(payload: &[u8]) -> Vec { + let purpose = GAMECULT_RUNTIME_ACTIVATION_PROOF_SIGNING_PURPOSE.as_bytes(); + let mut out = Vec::with_capacity( + IDUNN_RUNTIME_ACTIVATION_SIGNATURE_DOMAIN.len() + purpose.len() + payload.len() + 16, + ); + out.extend_from_slice(IDUNN_RUNTIME_ACTIVATION_SIGNATURE_DOMAIN); + out.extend_from_slice(&(purpose.len() as u64).to_be_bytes()); + out.extend_from_slice(purpose); + out.extend_from_slice(&(payload.len() as u64).to_be_bytes()); + out.extend_from_slice(payload); + out +} + +/// Idunn-issued launch identity. Idunn's stable service identity signs the +/// complete activation, including the ephemeral public key, before the private +/// credential is passed to one workload alongside Expected. Odin still treats +/// it as current only after Idunn publishes an observed native process. +#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] +#[cultcache( + type = "idunn.runtime_activation", + schema = "idunn.runtime_activation.v2" +)] +pub struct IdunnRuntimeActivationRecord { + #[cultcache(key = 0)] + pub schema_version: String, + #[cultcache(key = 1)] + pub expected_projection_sha256: String, + #[cultcache(key = 2)] + pub runtime_id: String, + #[cultcache(key = 3)] + pub runtime_instance_id: String, + #[cultcache(key = 4)] + pub activation_signer_identity_id: String, + #[cultcache(key = 5, bytes)] + pub activation_signer_public_key: Vec, + #[cultcache(key = 6)] + pub issued_at_unix_millis: u64, + #[cultcache(key = 7)] + pub idunn_signer_identity_id: String, + #[cultcache(key = 8)] + pub signature_algorithm: String, + #[cultcache(key = 9, bytes)] + pub signature: Vec, +} + +impl IdunnRuntimeActivationRecord { + fn issue_with_signer( + expected: &IdunnExpectedIncarnationRecord, + runtime_instance_id: String, + activation_signer: &IdunnRuntimeActivationSigner, + issued_at_unix_millis: u64, + idunn_signer: &crate::ServiceIdentitySigner, + ) -> Result { + expected.validate()?; + let mut activation = Self { + schema_version: IDUNN_RUNTIME_ACTIVATION_SCHEMA.into(), + expected_projection_sha256: expected.canonical_sha256()?, + runtime_id: expected.runtime_id.clone(), + runtime_instance_id, + activation_signer_identity_id: activation_signer.identity_id(), + activation_signer_public_key: activation_signer.public_key(), + issued_at_unix_millis, + idunn_signer_identity_id: idunn_signer.entry().identity_id.clone(), + signature_algorithm: "ed25519".into(), + signature: Vec::new(), + }; + let proof = idunn_signer.sign::( + &activation.unsigned_signature_payload()?, + ); + activation.signature = proof.signature; + activation.validate()?; + Ok(activation) + } + + pub fn decode_canonical(payload: &[u8]) -> Result { + if messagepack_array_len(payload) != Some(10) { + bail!("runtime activation is not the 10-field positional contract"); + } + let activation: Self = + rmp_serde::from_slice(payload).context("decoding runtime activation")?; + if rmp_serde::to_vec(&activation)? != payload { + bail!("runtime activation is not canonical positional MessagePack"); + } + activation.validate()?; + Ok(activation) + } + + pub fn canonical_bytes(&self) -> Result> { + self.validate()?; + Ok(rmp_serde::to_vec(self)?) + } + + pub fn canonical_sha256(&self) -> Result { + Ok(prefixed_sha256(&self.canonical_bytes()?)) + } + + pub fn unsigned_signature_payload(&self) -> Result> { + self.validate_shape(true)?; + let mut unsigned = self.clone(); + unsigned.signature.clear(); + Ok(rmp_serde::to_vec(&unsigned)?) + } + + pub fn verify_for_expected( + &self, + expected: &IdunnExpectedIncarnationRecord, + idunn_anchor: &crate::ServiceIdentityTrustAnchor, + ) -> Result<()> { + self.validate()?; + expected.validate()?; + if self.expected_projection_sha256 != expected.canonical_sha256()? + || self.runtime_id != expected.runtime_id + { + bail!("runtime activation does not bind the current Expected incarnation"); + } + crate::verify_service_identity_signature::< + crate::IdunnServiceIdentity, + crate::IdunnRuntimeActivationPurpose, + >( + idunn_anchor, + &self.unsigned_signature_payload()?, + &crate::ServiceIdentitySignature { + identity_id: self.idunn_signer_identity_id.clone(), + signature: self.signature.clone(), + }, + ) + .context("verifying Idunn runtime activation signature") + } + + pub fn validate(&self) -> Result<()> { + self.validate_shape(false) + } + + fn validate_shape(&self, allow_unsigned: bool) -> Result<()> { + if self.schema_version != IDUNN_RUNTIME_ACTIVATION_SCHEMA { + bail!("runtime activation schema is unsupported"); + } + validate_required_sha256( + &self.expected_projection_sha256, + "activation expected projection sha256", + )?; + validate_authority_identifier(&self.runtime_id, "activation runtime id")?; + validate_required_sha256(&self.runtime_instance_id, "runtime instance id")?; + validate_authority_identifier( + &self.activation_signer_identity_id, + "activation signer identity id", + )?; + if self.activation_signer_identity_id + != derive_idunn_runtime_activation_identity_id(&self.activation_signer_public_key)? + { + bail!("runtime activation signer identity does not match its public key"); + } + validate_authority_identifier( + &self.idunn_signer_identity_id, + "Idunn activation signer identity id", + )?; + let signature_is_valid = + self.signature.len() == 64 || (allow_unsigned && self.signature.is_empty()); + if self.issued_at_unix_millis == 0 + || self.signature_algorithm != "ed25519" + || !signature_is_valid + { + bail!("runtime activation issue time or signature is invalid"); + } + Ok(()) + } +} + +/// Unsigned Idunn-owned local file that grants one exact process incarnation +/// state-write authority. It is authoritative only when read through the +/// root-owned admitted path and lock protocol; its bytes carry no route or +/// traffic authority. +#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] +#[cultcache( + type = "idunn.process_write_lease", + schema = "idunn.process_write_lease.v1" +)] +pub struct IdunnProcessWriteLeaseRecord { + #[cultcache(key = 0)] + pub schema_version: String, + #[cultcache(key = 1)] + pub target: String, + #[cultcache(key = 2)] + pub expected_projection_sha256: String, + #[cultcache(key = 3)] + pub plan_id: String, + #[cultcache(key = 4)] + pub incarnation_id: String, + #[cultcache(key = 5)] + pub sealed_release_id: String, + #[cultcache(key = 6)] + pub activation_witness_sha256: String, + #[cultcache(key = 7)] + pub state_schema_generation: String, + #[cultcache(key = 8)] + pub state_contract_sha256: String, + #[cultcache(key = 9)] + pub runtime_id: String, + #[cultcache(key = 10)] + pub runtime_instance_id: String, + #[cultcache(key = 11)] + pub warming_presence_sha256: String, + #[cultcache(key = 12)] + pub lease_epoch: u64, + #[cultcache(key = 13)] + pub issued_at_unix_millis: u64, +} + +impl IdunnProcessWriteLeaseRecord { + pub fn decode_canonical(payload: &[u8]) -> Result { + if messagepack_array_len(payload) != Some(14) { + bail!("process write lease is not the 14-field positional contract"); + } + let lease: Self = rmp_serde::from_slice(payload).context("decoding process write lease")?; + if rmp_serde::to_vec(&lease)? != payload { + bail!("process write lease is not canonical positional MessagePack"); + } + lease.validate()?; + Ok(lease) + } + + pub fn canonical_bytes(&self) -> Result> { + self.validate()?; + Ok(rmp_serde::to_vec(self)?) + } + + pub fn canonical_sha256(&self) -> Result { + Ok(prefixed_sha256(&self.canonical_bytes()?)) + } + + pub fn validate(&self) -> Result<()> { + if self.schema_version != IDUNN_PROCESS_WRITE_LEASE_SCHEMA { + bail!("process write lease schema is unsupported"); + } + validate_authority_identifier(&self.target, "target")?; + validate_required_sha256( + &self.expected_projection_sha256, + "lease expected projection sha256", + )?; + validate_required_sha256(&self.plan_id, "plan id")?; + validate_authority_identifier(&self.incarnation_id, "incarnation id")?; + validate_required_sha256(&self.sealed_release_id, "sealed release id")?; + validate_required_sha256(&self.activation_witness_sha256, "activation witness sha256")?; + validate_authority_identifier(&self.state_schema_generation, "state schema generation")?; + validate_required_sha256(&self.state_contract_sha256, "state contract sha256")?; + validate_authority_identifier(&self.runtime_id, "runtime id")?; + validate_required_sha256(&self.runtime_instance_id, "runtime instance id")?; + validate_required_sha256(&self.warming_presence_sha256, "warming presence sha256")?; + if self.lease_epoch == 0 || self.issued_at_unix_millis == 0 { + bail!("process write lease epoch or issue time is invalid"); + } + Ok(()) + } +} + +fn messagepack_array_len(payload: &[u8]) -> Option { + match *payload.first()? { + marker @ 0x90..=0x9f => Some(usize::from(marker & 0x0f)), + 0xdc => Some(usize::from(u16::from_be_bytes([ + *payload.get(1)?, + *payload.get(2)?, + ]))), + 0xdd => usize::try_from(u32::from_be_bytes([ + *payload.get(1)?, + *payload.get(2)?, + *payload.get(3)?, + *payload.get(4)?, + ])) + .ok(), + _ => None, + } +} + +fn validate_authority_identifier(value: &str, label: &str) -> Result<()> { + if value.is_empty() + || value.len() > 256 + || value.trim() != value + || value.chars().any(char::is_control) + { + bail!("{label} is empty, oversized, padded, or contains control characters"); + } + Ok(()) +} + +fn validate_optional_identifier(value: &Option, label: &str) -> Result<()> { + if let Some(value) = value { + validate_authority_identifier(value, label)?; + } + Ok(()) +} + +fn validate_source_repository(value: &str) -> Result<()> { + validate_authority_identifier(value, "source repository")?; + let segments: Vec<&str> = value.split('/').collect(); + if segments.len() < 3 + || !segments[0].contains('.') + || segments.iter().any(|segment| { + segment.is_empty() + || matches!(*segment, "." | "..") + || !segment + .bytes() + .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'-' | b'_' | b'.')) + }) + { + bail!("source repository is not a canonical host/owner/repository identity"); + } + Ok(()) +} + +fn validate_endpoint(value: &str, label: &str) -> Result<()> { + if value.is_empty() + || value.len() > 2048 + || value.trim() != value + || value.chars().any(char::is_control) + { + bail!("{label} is empty, oversized, padded, or contains control characters"); + } + Ok(()) +} + +fn validate_optional_endpoint_labeled(value: &Option, label: &str) -> Result<()> { + if let Some(endpoint) = value { + validate_endpoint(endpoint, label)?; + } + Ok(()) +} + +fn validate_optional_endpoint(value: &Option) -> Result<()> { + validate_optional_endpoint_labeled(value, "bound endpoint") +} + +fn validate_runtime_capabilities(capabilities: &[GameCultRuntimeCapability]) -> Result<()> { + if capabilities.len() > MAX_RUNTIME_CAPABILITIES { + bail!("runtime presence capability count exceeds its contract bound"); + } + let mut previous: Option<(&str, &str, &str)> = None; + for capability in capabilities { + validate_authority_identifier(&capability.capability, "capability")?; + validate_authority_identifier(&capability.schema, "capability schema")?; + validate_authority_identifier(&capability.compatibility, "capability compatibility")?; + if capability.capacity == 0 { + bail!("runtime capability capacity is zero"); + } + let identity = ( + capability.capability.as_str(), + capability.schema.as_str(), + capability.compatibility.as_str(), + ); + if previous.is_some_and(|previous| previous >= identity) { + bail!("runtime capabilities are not strictly sorted and unique"); + } + previous = Some(identity); + } + Ok(()) +} + +fn validate_expected_capabilities(capabilities: &[IdunnExpectedCapability]) -> Result<()> { + if capabilities.len() > MAX_RUNTIME_CAPABILITIES { + bail!("Expected capability count exceeds its contract bound"); + } + let mut previous: Option<(&str, &str, &str)> = None; + for capability in capabilities { + validate_authority_identifier(&capability.capability, "Expected capability")?; + validate_authority_identifier(&capability.schema, "Expected capability schema")?; + validate_authority_identifier( + &capability.compatibility, + "Expected capability compatibility", + )?; + if capability.minimum_capacity == 0 { + bail!("Expected capability minimum capacity is zero"); + } + let identity = capability.identity(); + if previous.is_some_and(|previous| previous >= identity) { + bail!("Expected capabilities are not strictly sorted and unique"); + } + previous = Some(identity); + } + Ok(()) +} + +fn validate_expected_dependencies(dependencies: &[IdunnExpectedDependency]) -> Result<()> { + if dependencies.len() > MAX_RUNTIME_DEPENDENCIES { + bail!("Expected dependency count exceeds its contract bound"); + } + let mut previous: Option<(&str, &str, &str)> = None; + for dependency in dependencies { + dependency.validate()?; + let identity = dependency.identity(); + if previous.is_some_and(|previous| previous >= identity) { + bail!("Expected dependencies are not strictly sorted and unique"); + } + previous = Some(identity); + } + Ok(()) +} + +fn validate_dependency_evidence(dependencies: &[OdinRuntimeDependencyEvidence]) -> Result<()> { + if dependencies.len() > MAX_RUNTIME_DEPENDENCIES { + bail!("dependency evidence count exceeds its contract bound"); + } + let mut previous: Option<(&str, &str, &str)> = None; + for dependency in dependencies { + dependency.validate()?; + let identity = dependency.identity(); + if previous.is_some_and(|previous| previous >= identity) { + bail!("dependency evidence is not strictly sorted and unique"); + } + previous = Some(identity); + } + Ok(()) +} + +fn validate_topology_disagreements(disagreements: &[OdinTopologyDisagreement]) -> Result<()> { + if disagreements.len() > MAX_TOPOLOGY_DISAGREEMENTS { + bail!("topology disagreement count exceeds its contract bound"); + } + let mut previous: Option<&str> = None; + for disagreement in disagreements { + disagreement.validate()?; + if previous.is_some_and(|previous| previous >= disagreement.code.as_str()) { + bail!("topology disagreements are not strictly sorted and unique by code"); + } + previous = Some(&disagreement.code); + } + Ok(()) +} + +fn validate_optional_detail(value: &Option, label: &str) -> Result<()> { + if value.as_deref().is_some_and(|value| { + value.is_empty() + || value.len() > 1024 + || value.trim() != value + || value.chars().any(char::is_control) + }) { + bail!("{label} is empty, oversized, padded, or contains control characters"); + } + Ok(()) +} + +fn validate_required_sha256(value: &str, label: &str) -> Result<()> { + if !is_sha256(value) { + bail!("{label} is malformed"); + } + Ok(()) +} + +fn validate_optional_sha256(value: &Option, label: &str) -> Result<()> { + if value.as_deref().is_some_and(|value| !is_sha256(value)) { + bail!("{label} is malformed"); + } + Ok(()) +} + +fn prefixed_sha256(bytes: &[u8]) -> String { + format!("sha256-{:x}", Sha256::digest(bytes)) +} + +fn is_sha256(value: &str) -> bool { + value + .strip_prefix("sha256-") + .is_some_and(|digest| is_lower_hex(digest, 64)) +} + +fn is_lower_hex(value: &str, length: usize) -> bool { + value.len() == length + && value + .bytes() + .all(|byte| byte.is_ascii_hexdigit() && !byte.is_ascii_uppercase()) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + GAMECULT_SERVICE_TRUST_ANCHOR_SCHEMA, GameCultProviderHealthIdentity, + GameCultRuntimePresenceHealthPurpose, GameCultServiceTrustAnchorRecord, + IDUNN_SIGNED_DAEMON_HEALTH_SCHEMA, IdunnServiceIdentity, + OdinRuntimeTopologyCorrelationPurpose, OdinTopologyIdentity, ServiceIdentitySignature, + ServiceIdentitySigner, ServiceSignaturePurpose, derive_service_identity_id, + enroll_service_identity_at, verify_service_identity_signature, + }; + + struct WrongOdinTopologyPurpose; + + impl ServiceSignaturePurpose for WrongOdinTopologyPurpose { + const PURPOSE: &'static [u8] = b"odin.not-runtime-topology-correlation.v1"; + } + + fn digest(byte: char) -> String { + format!("sha256-{}", byte.to_string().repeat(64)) + } + + fn runtime_capability(name: &str) -> GameCultRuntimeCapability { + GameCultRuntimeCapability { + capability: name.into(), + schema: format!("{name}.v1"), + compatibility: "v1".into(), + capacity: 1, + } + } + + fn expected_capability(name: &str) -> IdunnExpectedCapability { + IdunnExpectedCapability { + capability: name.into(), + schema: format!("{name}.v1"), + compatibility: "v1".into(), + minimum_capacity: 1, + } + } + + fn runtime_presence() -> GameCultRuntimePresenceHealthRecord { + GameCultRuntimePresenceHealthRecord { + schema_version: GAMECULT_RUNTIME_PRESENCE_HEALTH_SCHEMA.into(), + target: "ghostlight".into(), + expected_projection_sha256: digest('9'), + plan_id: digest('e'), + incarnation_id: "ghostlight/2026-09-02/1".into(), + sealed_release_id: digest('f'), + activation_witness_sha256: digest('a'), + state_schema_generation: Some("world-v2".into()), + state_contract_sha256: Some(digest('b')), + runtime_id: "ghostlight-yggdrasil-1".into(), + runtime_instance_id: digest('8'), + bound_endpoint: Some("http://127.0.0.1:14103".into()), + capabilities: vec![ + runtime_capability("conversation"), + runtime_capability("state"), + ], + health_contract: "ghostlight.runtime-health.v1".into(), + state: "active".into(), + detail: "ready".into(), + write_lease_sha256: Some(digest('c')), + signer_identity_id: "provider-signing-key".into(), + publisher_sequence: 1, + observed_at_unix_millis: 100, + signature_algorithm: "ed25519".into(), + signature: vec![6; 64], + activation_signer_identity_id: "activation-signing-key".into(), + activation_signature: vec![7; 64], + } + } + + fn runtime_activation() -> IdunnRuntimeActivationRecord { + let signer = IdunnRuntimeActivationSigner::from_credential_reader(&[8; 32][..]).unwrap(); + IdunnRuntimeActivationRecord { + schema_version: IDUNN_RUNTIME_ACTIVATION_SCHEMA.into(), + expected_projection_sha256: digest('9'), + runtime_id: "ghostlight-yggdrasil-1".into(), + runtime_instance_id: digest('8'), + activation_signer_identity_id: signer.identity_id(), + activation_signer_public_key: signer.public_key(), + issued_at_unix_millis: 99, + idunn_signer_identity_id: "idunn-signing-key".into(), + signature_algorithm: "ed25519".into(), + signature: vec![5; 64], + } + } + + fn process_write_lease() -> IdunnProcessWriteLeaseRecord { + IdunnProcessWriteLeaseRecord { + schema_version: IDUNN_PROCESS_WRITE_LEASE_SCHEMA.into(), + target: "ghostlight".into(), + expected_projection_sha256: digest('9'), + plan_id: digest('e'), + incarnation_id: "ghostlight/2026-09-02/1".into(), + sealed_release_id: digest('f'), + activation_witness_sha256: digest('a'), + state_schema_generation: "world-v2".into(), + state_contract_sha256: digest('b'), + runtime_id: "ghostlight-yggdrasil-1".into(), + runtime_instance_id: digest('8'), + warming_presence_sha256: digest('d'), + lease_epoch: 1, + issued_at_unix_millis: 101, + } + } + + fn expected_dependency( + kind: &str, + capability: &str, + provider_id: Option<&str>, + ) -> IdunnExpectedDependency { + IdunnExpectedDependency { + kind: kind.into(), + capability: capability.into(), + schema: format!("{capability}.v1"), + compatibility: "v1".into(), + minimum_capacity: 1, + startup: if kind == "bootstrap" { + "before-start".into() + } else { + "before-promotion".into() + }, + provider_id: provider_id.map(str::to_string), + provider_authority: provider_id.map(|_| "managed-incarnation".into()), + provider_expected_projection_sha256: provider_id.map(|_| digest('1')), + provider_endpoint: provider_id.map(|_| "tcp://127.0.0.1:14100".into()), + } + } + + fn expected_incarnation() -> IdunnExpectedIncarnationRecord { + IdunnExpectedIncarnationRecord { + schema_version: IDUNN_EXPECTED_INCARNATION_SCHEMA.into(), + target: "ghostlight".into(), + plan_id: digest('2'), + incarnation_id: "ghostlight/2026-09-02/1".into(), + sealed_release_id: digest('3'), + source_repository: "github.com/GameCult/Ghostlight".into(), + source_revision: "4".repeat(40), + recipe_sha256: digest('5'), + runtime_id: "ghostlight-yggdrasil-1".into(), + expected_signer_identity_id: "ghostlight-provider-signing-key".into(), + health_contract: "ghostlight.runtime-health.v1".into(), + artifact_sha256: digest('6'), + state_schema_generation: Some("world-v2".into()), + state_contract_sha256: Some(digest('7')), + write_lease_required: true, + route: Some(IdunnExpectedRoute { + route_id: "ghostlight-public".into(), + transport: "http".into(), + stable_endpoint: "https://ghostlight.gamecult.net".into(), + candidate_endpoint: "http://127.0.0.1:14103".into(), + }), + capabilities: vec![ + expected_capability("conversation"), + expected_capability("state"), + ], + dependencies: vec![ + expected_dependency("shared-infrastructure", "rendezvous", Some("odin-ygg-1")), + expected_dependency("optional", "telemetry", None), + ], + } + } + + fn dependency_evidence(requirement: &IdunnExpectedDependency) -> OdinRuntimeDependencyEvidence { + let selected = requirement.provider_id.is_some(); + OdinRuntimeDependencyEvidence { + kind: requirement.kind.clone(), + capability: requirement.capability.clone(), + schema: requirement.schema.clone(), + compatibility: requirement.compatibility.clone(), + provider_id: requirement.provider_id.clone(), + provider_authority: requirement.provider_authority.clone(), + provider_expected_projection_sha256: requirement + .provider_expected_projection_sha256 + .clone(), + provider_endpoint: requirement.provider_endpoint.clone(), + observed_capacity: selected.then_some(1), + provider_evidence_sha256: selected.then(|| digest('8')), + ready: selected, + } + } + + fn topology_correlation( + expected: &IdunnExpectedIncarnationRecord, + ) -> OdinRuntimeTopologyCorrelationRecord { + OdinRuntimeTopologyCorrelationRecord { + schema_version: ODIN_RUNTIME_TOPOLOGY_CORRELATION_SCHEMA.into(), + target: expected.target.clone(), + expected_projection_sha256: expected.canonical_sha256().unwrap(), + expected: true, + current_activation_sha256: Some(digest('9')), + signed_presence_sha256: Some(digest('a')), + observed_presence_state: Some("active".into()), + observed_presence_publisher_sequence: Some(1), + observed_write_lease_sha256: Some(digest('c')), + observed_capabilities: expected + .capabilities + .iter() + .map(|capability| GameCultRuntimeCapability { + capability: capability.capability.clone(), + schema: capability.schema.clone(), + compatibility: capability.compatibility.clone(), + capacity: capability.minimum_capacity, + }) + .collect(), + runtime_id: expected.runtime_id.clone(), + runtime_instance_id: Some(digest('b')), + present: true, + ready: true, + dependencies: expected + .dependencies + .iter() + .map(dependency_evidence) + .collect(), + disagreements: vec![], + signer_identity_id: "odin-topology-signing-key".into(), + publisher_sequence: 1, + observed_at_unix_millis: 102, + signature_algorithm: "ed25519".into(), + signature: vec![7; 64], + } + } + + fn validate_against_current_lease( + receipt: &OdinRuntimeTopologyCorrelationRecord, + expected: &IdunnExpectedIncarnationRecord, + ) -> Result<()> { + let current_lease = digest('c'); + receipt.validate_against_expected(expected, Some(¤t_lease)) + } + + fn topology_anchor() -> GameCultServiceTrustAnchorRecord { + let public_key = vec![9; 32]; + GameCultServiceTrustAnchorRecord { + schema_version: GAMECULT_SERVICE_TRUST_ANCHOR_SCHEMA.into(), + trust_anchor_id: "root/odin/runtime-topology".into(), + service_id: "odin".into(), + runtime_id: "odin-yggdrasil-1".into(), + signer_identity_id: derive_service_identity_id::(&public_key) + .unwrap(), + signer_public_key: public_key, + signature_algorithm: "ed25519".into(), + signing_purpose: ODIN_RUNTIME_TOPOLOGY_CORRELATION_SIGNING_PURPOSE.into(), + signed_schema: ODIN_RUNTIME_TOPOLOGY_CORRELATION_SCHEMA.into(), + binding_authority: "root".into(), + bound_at_unix_millis: 100, + expires_at_unix_millis: Some(200), + private_state_exposed: false, + } + } + + fn runtime_presence_anchor() -> GameCultServiceTrustAnchorRecord { + let public_key = vec![7; 32]; + GameCultServiceTrustAnchorRecord { + schema_version: GAMECULT_SERVICE_TRUST_ANCHOR_SCHEMA.into(), + trust_anchor_id: "root/ghostlight/runtime-presence".into(), + service_id: "ghostlight".into(), + runtime_id: "ghostlight-yggdrasil-1".into(), + signer_identity_id: derive_service_identity_id::( + &public_key, + ) + .unwrap(), + signer_public_key: public_key, + signature_algorithm: "ed25519".into(), + signing_purpose: GAMECULT_RUNTIME_PRESENCE_HEALTH_SIGNING_PURPOSE.into(), + signed_schema: GAMECULT_RUNTIME_PRESENCE_HEALTH_SCHEMA.into(), + binding_authority: "root".into(), + bound_at_unix_millis: 100, + expires_at_unix_millis: Some(200), + private_state_exposed: false, + } + } + + struct DualProofFixture { + stable_signer: ServiceIdentitySigner, + activation_signer: IdunnRuntimeActivationSigner, + odin_signer: ServiceIdentitySigner, + idunn_anchor: crate::ServiceIdentityTrustAnchor, + stable_public_key: Vec, + odin_anchor: GameCultServiceTrustAnchorRecord, + expected: IdunnExpectedIncarnationRecord, + activation: IdunnRuntimeActivationRecord, + presence: GameCultRuntimePresenceHealthRecord, + } + + fn dual_proof_fixture(identity_path: &std::path::Path) -> Result { + let stable_signer = + enroll_service_identity_at::(identity_path)?; + let stable_public = stable_signer.trust_anchor()?; + let idunn_signer = enroll_service_identity_at::( + &identity_path.with_extension("idunn.cc"), + )?; + let idunn_anchor = idunn_signer.trust_anchor()?; + let odin_signer = enroll_service_identity_at::( + &identity_path.with_extension("odin.cc"), + )?; + let odin_public = odin_signer.trust_anchor()?; + let mut expected = expected_incarnation(); + expected.expected_signer_identity_id = stable_public.identity_id.clone(); + expected.capabilities[0].minimum_capacity = 2; + let launch = + IdunnRuntimeActivationLaunch::issue(&expected, digest('8'), 99, &idunn_signer)?; + let activation = launch.activation().clone(); + let mut activation_credential = Vec::new(); + assert_eq!( + launch.write_credential(&mut activation_credential)?, + activation + ); + let activation_signer = + IdunnRuntimeActivationSigner::from_credential_reader(&activation_credential[..])?; + + let stable_public_key = stable_public.public_key.clone(); + let odin_anchor = GameCultServiceTrustAnchorRecord { + schema_version: GAMECULT_SERVICE_TRUST_ANCHOR_SCHEMA.into(), + trust_anchor_id: "root/odin/runtime-topology".into(), + service_id: "odin".into(), + runtime_id: "odin-yggdrasil-1".into(), + signer_identity_id: odin_public.identity_id, + signer_public_key: odin_public.public_key, + signature_algorithm: "ed25519".into(), + signing_purpose: ODIN_RUNTIME_TOPOLOGY_CORRELATION_SIGNING_PURPOSE.into(), + signed_schema: ODIN_RUNTIME_TOPOLOGY_CORRELATION_SCHEMA.into(), + binding_authority: "root".into(), + bound_at_unix_millis: 1, + expires_at_unix_millis: Some(1_000), + private_state_exposed: false, + }; + + let mut presence = runtime_presence(); + presence.target = expected.target.clone(); + presence.plan_id = expected.plan_id.clone(); + presence.incarnation_id = expected.incarnation_id.clone(); + presence.sealed_release_id = expected.sealed_release_id.clone(); + presence.state_schema_generation = expected.state_schema_generation.clone(); + presence.state_contract_sha256 = expected.state_contract_sha256.clone(); + presence.bound_endpoint = expected + .route + .as_ref() + .map(|route| route.candidate_endpoint.clone()); + presence.capabilities = expected + .capabilities + .iter() + .map(|capability| GameCultRuntimeCapability { + capability: capability.capability.clone(), + schema: capability.schema.clone(), + compatibility: capability.compatibility.clone(), + capacity: capability.minimum_capacity, + }) + .collect(); + presence.health_contract = expected.health_contract.clone(); + presence.runtime_id = activation.runtime_id.clone(); + presence.runtime_instance_id = activation.runtime_instance_id.clone(); + presence.expected_projection_sha256 = activation.expected_projection_sha256.clone(); + presence.activation_witness_sha256 = activation.canonical_sha256()?; + presence.signer_identity_id = stable_public.identity_id; + presence.activation_signer_identity_id = activation_signer.identity_id(); + presence.observed_at_unix_millis = 110; + presence.signature.clear(); + presence.activation_signature.clear(); + let proof_payload = presence.canonical_proof_payload()?; + presence.signature = stable_signer + .sign::(&proof_payload) + .signature; + presence.activation_signature = activation_signer.sign_presence_proof(&presence)?; + + Ok(DualProofFixture { + stable_signer, + activation_signer, + odin_signer, + idunn_anchor, + stable_public_key, + odin_anchor, + expected, + activation, + presence, + }) + } + + fn resign_presence(fixture: &mut DualProofFixture) -> Result> { + fixture.presence.signature.clear(); + fixture.presence.activation_signature.clear(); + let proof_payload = fixture.presence.canonical_proof_payload()?; + fixture.presence.signature = fixture + .stable_signer + .sign::(&proof_payload) + .signature; + fixture.presence.activation_signature = fixture + .activation_signer + .sign_presence_proof(&fixture.presence)?; + Ok(rmp_serde::to_vec(&fixture.presence)?) + } + + fn fixture_authority(fixture: &DualProofFixture) -> Result { + verify_runtime_authority( + &fixture.expected, + &fixture.activation, + &fixture.idunn_anchor, + &fixture.stable_public_key, + ) + } + + fn authenticate_fixture( + fixture: &DualProofFixture, + ) -> Result { + authenticate_runtime_presence_claim( + &rmp_serde::to_vec(&fixture.presence)?, + &fixture_authority(fixture)?, + RuntimePresenceAuthenticationContext { + trusted_received_at_unix_millis: 120, + maximum_age_millis: 30, + maximum_future_skew_millis: 5, + }, + ) + } + + fn correlate_fixture(fixture: &DualProofFixture) -> Result { + correlate_runtime_presence_claim( + authenticate_fixture(fixture)?, + &fixture_authority(fixture)?, + ) + } + + fn verify_fixture(fixture: &DualProofFixture) -> Result { + correlate_fixture(fixture)?.into_undisputed_present() + } + + fn authenticated_topology_receipt( + fixture: &DualProofFixture, + presence: &VerifiedRuntimePresence, + present: bool, + disagreements: Vec, + ) -> Result { + let authority = fixture_authority(fixture)?; + let mut receipt = topology_correlation(&fixture.expected); + receipt.current_activation_sha256 = Some(authority.activation_sha256().into()); + receipt.signed_presence_sha256 = Some(presence.signed_presence_sha256().into()); + receipt.observed_presence_state = Some(presence.record().state.clone()); + receipt.observed_presence_publisher_sequence = Some(presence.record().publisher_sequence); + receipt.observed_write_lease_sha256 = presence.record().write_lease_sha256.clone(); + receipt.observed_capabilities = presence.record().capabilities.clone(); + receipt.runtime_instance_id = Some(fixture.activation.runtime_instance_id.clone()); + receipt.present = present; + receipt.ready = present && presence.record().state == "active"; + receipt.disagreements = disagreements; + receipt.signer_identity_id = fixture.odin_anchor.signer_identity_id.clone(); + receipt.signature.clear(); + receipt.signature = fixture + .odin_signer + .sign::(&receipt.unsigned_signature_payload()?) + .signature; + let encoded = receipt.canonical_bytes()?; + authenticate_odin_runtime_topology_correlation( + &encoded, + &authority, + presence.record().write_lease_sha256.as_deref(), + &fixture.odin_anchor.signer_public_key, + OdinTopologyAuthenticationContext { + trusted_received_at_unix_millis: 120, + maximum_age_millis: 30, + maximum_future_skew_millis: 5, + }, + ) + } + + #[test] + fn runtime_authority_contracts_round_trip_as_canonical_positional_records() -> Result<()> { + let presence = runtime_presence(); + presence.validate()?; + let encoded_presence = rmp_serde::to_vec(&presence)?; + assert_eq!(messagepack_array_len(&encoded_presence), Some(24)); + let decoded_presence: GameCultRuntimePresenceHealthRecord = + rmp_serde::from_slice(&encoded_presence)?; + assert_eq!(decoded_presence, presence); + let unsigned = presence.canonical_proof_payload()?; + let unsigned_presence: GameCultRuntimePresenceHealthRecord = + rmp_serde::from_slice(&unsigned)?; + assert!(unsigned_presence.signature.is_empty()); + assert!(unsigned_presence.activation_signature.is_empty()); + + let activation = runtime_activation(); + let encoded_activation = activation.canonical_bytes()?; + assert_eq!(messagepack_array_len(&encoded_activation), Some(10)); + assert_eq!( + IdunnRuntimeActivationRecord::decode_canonical(&encoded_activation)?, + activation + ); + assert_eq!( + activation.canonical_sha256()?, + prefixed_sha256(&encoded_activation) + ); + + let lease = process_write_lease(); + lease.validate()?; + let encoded_lease = lease.canonical_bytes()?; + assert_eq!(messagepack_array_len(&encoded_lease), Some(14)); + assert_eq!( + IdunnProcessWriteLeaseRecord::decode_canonical(&encoded_lease)?, + lease + ); + assert_eq!(lease.canonical_sha256()?, prefixed_sha256(&encoded_lease)); + Ok(()) + } + + #[test] + fn exact_stable_and_activation_proofs_admit_runtime_presence() -> Result<()> { + let temp = tempfile::tempdir()?; + let fixture = dual_proof_fixture(&temp.path().join("runtime-presence.cc"))?; + assert_eq!(fixture.activation.activation_signer_public_key.len(), 32); + let verified = verify_fixture(&fixture)?; + assert_eq!(verified.record(), &fixture.presence); + Ok(()) + } + + #[test] + fn authenticated_expected_disagreements_remain_typed_present_and_not_ready() -> Result<()> { + type Mutation = fn(&mut GameCultRuntimePresenceHealthRecord); + let cases: &[(&str, &str, Mutation)] = &[ + ("target", "target", |value| value.target = "epiphany".into()), + ("projection", "expected-projection", |value| { + value.expected_projection_sha256 = digest('0') + }), + ("plan", "plan-id", |value| value.plan_id = digest('0')), + ("incarnation", "incarnation-id", |value| { + value.incarnation_id = "ghostlight/other/1".into() + }), + ("release", "sealed-release-id", |value| { + value.sealed_release_id = digest('0') + }), + ("runtime", "runtime-id", |value| { + value.runtime_id = "ghostlight-other-runtime".into() + }), + ("process", "runtime-instance-id", |value| { + value.runtime_instance_id = digest('0') + }), + ("endpoint", "bound-endpoint", |value| { + value.bound_endpoint = Some("http://127.0.0.1:14104".into()) + }), + ("health", "health-contract", |value| { + value.health_contract = "ghostlight.other-health.v1".into() + }), + ("state-generation", "state-schema-generation", |value| { + value.state_schema_generation = Some("world-v3".into()) + }), + ("state-contract", "state-contract", |value| { + value.state_contract_sha256 = Some(digest('0')) + }), + ("activation", "activation-witness", |value| { + value.activation_witness_sha256 = digest('0') + }), + ]; + + let temp = tempfile::tempdir()?; + for (name, expected_code, mutate) in cases { + let mut fixture = dual_proof_fixture(&temp.path().join(format!("{name}.cc")))?; + mutate(&mut fixture.presence); + resign_presence(&mut fixture)?; + let correlation = correlate_fixture(&fixture)?; + assert!( + correlation + .disagreements() + .iter() + .any(|disagreement| disagreement.code == *expected_code), + "missing {expected_code} disagreement for {name}" + ); + assert_eq!( + correlation.claim().record().runtime_instance_id, + fixture.presence.runtime_instance_id + ); + assert!(correlation.into_undisputed_present().is_err()); + } + Ok(()) + } + + #[test] + fn provider_owns_observed_capacity_while_expected_owns_only_the_minimum() -> Result<()> { + let temp = tempfile::tempdir()?; + let mut fixture = dual_proof_fixture(&temp.path().join("runtime-presence.cc"))?; + fixture.presence.capabilities[0].capacity = 50; + fixture + .presence + .capabilities + .push(runtime_capability("telemetry")); + resign_presence(&mut fixture)?; + verify_fixture(&fixture)?; + + fixture.presence.capabilities[0].capacity = 1; + fixture + .presence + .capabilities + .retain(|capability| capability.capability != "state"); + resign_presence(&mut fixture)?; + let correlation = correlate_fixture(&fixture)?; + let codes = correlation + .disagreements() + .iter() + .map(|disagreement| disagreement.code.as_str()) + .collect::>(); + assert!(codes.contains(&"expected-capability-000-capacity")); + assert!(codes.contains(&"expected-capability-001-missing")); + assert!(!codes.iter().any(|code| code.contains("unexpected"))); + Ok(()) + } + + #[test] + fn stable_proof_and_provider_key_substitution_fail_closed() -> Result<()> { + let temp = tempfile::tempdir()?; + let mut fixture = dual_proof_fixture(&temp.path().join("runtime-presence.cc"))?; + fixture.presence.detail = "tampered after signing".into(); + assert!(authenticate_fixture(&fixture).is_err()); + + let other_idunn = enroll_service_identity_at::( + &temp.path().join("other-idunn.cc"), + )?; + assert!( + verify_runtime_authority( + &fixture.expected, + &fixture.activation, + &other_idunn.trust_anchor()?, + &fixture.stable_public_key, + ) + .is_err() + ); + + fixture.stable_public_key = vec![9; 32]; + assert!(fixture_authority(&fixture).is_err()); + Ok(()) + } + + #[test] + fn incumbent_stable_key_without_activation_key_cannot_claim_presence() -> Result<()> { + let temp = tempfile::tempdir()?; + let mut fixture = dual_proof_fixture(&temp.path().join("runtime-presence.cc"))?; + fixture.presence.activation_signature = vec![0; 64]; + let proof_payload = fixture.presence.canonical_proof_payload()?; + fixture.presence.signature = fixture + .stable_signer + .sign::(&proof_payload) + .signature; + + let error = verify_fixture(&fixture).unwrap_err(); + assert!(error.to_string().contains("activation proof verification")); + Ok(()) + } + + #[test] + fn activation_cannot_substitute_another_expected_runtime_id() -> Result<()> { + let temp = tempfile::tempdir()?; + let mut fixture = dual_proof_fixture(&temp.path().join("runtime-presence.cc"))?; + fixture.activation.runtime_id = "ghostlight-yggdrasil-2".into(); + fixture.presence.runtime_id = fixture.activation.runtime_id.clone(); + fixture.presence.activation_witness_sha256 = fixture.activation.canonical_sha256()?; + + // The stable service key can re-sign the altered canonical statement, + // but the activation proof still came from the other runtime id. + let proof_payload = fixture.presence.canonical_proof_payload()?; + fixture.presence.signature = fixture + .stable_signer + .sign::(&proof_payload) + .signature; + let error = fixture_authority(&fixture).unwrap_err(); + assert!(error.to_string().contains("current Expected")); + Ok(()) + } + + #[test] + fn idunn_signature_prevents_provider_minted_activation() -> Result<()> { + let temp = tempfile::tempdir()?; + let mut fixture = dual_proof_fixture(&temp.path().join("runtime-presence.cc"))?; + fixture.activation.issued_at_unix_millis += 1; + fixture.presence.activation_witness_sha256 = fixture.activation.canonical_sha256()?; + resign_presence(&mut fixture)?; + let error = fixture_authority(&fixture).unwrap_err(); + assert!( + error + .to_string() + .contains("Idunn runtime activation signature") + ); + Ok(()) + } + + #[test] + fn authenticated_odin_receipt_is_fresh_evidence_not_replay_authority() -> Result<()> { + let temp = tempfile::tempdir()?; + let fixture = dual_proof_fixture(&temp.path().join("runtime-presence.cc"))?; + let authority = fixture_authority(&fixture)?; + let presence = verify_fixture(&fixture)?; + let accepted = authenticated_topology_receipt(&fixture, &presence, true, Vec::new())?; + assert_eq!( + accepted.record().observed_presence_publisher_sequence, + Some(fixture.presence.publisher_sequence) + ); + assert_eq!( + accepted.record().signed_presence_sha256.as_deref(), + Some(presence.signed_presence_sha256()) + ); + + let mut tampered = accepted.record().clone(); + tampered.signature = vec![0; 64]; + assert!( + authenticate_odin_runtime_topology_correlation( + &tampered.canonical_bytes()?, + &authority, + presence.record().write_lease_sha256.as_deref(), + &fixture.odin_anchor.signer_public_key, + OdinTopologyAuthenticationContext { + trusted_received_at_unix_millis: 120, + maximum_age_millis: 30, + maximum_future_skew_millis: 5, + }, + ) + .is_err() + ); + assert!( + authenticate_odin_runtime_topology_correlation( + accepted.canonical_bytes(), + &authority, + presence.record().write_lease_sha256.as_deref(), + &fixture.odin_anchor.signer_public_key, + OdinTopologyAuthenticationContext { + trusted_received_at_unix_millis: 200, + maximum_age_millis: 30, + maximum_future_skew_millis: 5, + }, + ) + .is_err() + ); + Ok(()) + } + + #[test] + fn separate_launches_receive_distinct_activation_identities() -> Result<()> { + let temp = tempfile::tempdir()?; + let idunn = + enroll_service_identity_at::(&temp.path().join("idunn.cc"))?; + let expected = expected_incarnation(); + let first = IdunnRuntimeActivationLaunch::issue(&expected, digest('8'), 99, &idunn)?; + let second = IdunnRuntimeActivationLaunch::issue(&expected, digest('9'), 100, &idunn)?; + assert_ne!( + first.activation().activation_signer_identity_id, + second.activation().activation_signer_identity_id + ); + Ok(()) + } + + #[test] + fn trusted_time_rejects_stale_and_future_presence() -> Result<()> { + let temp = tempfile::tempdir()?; + let mut fixture = dual_proof_fixture(&temp.path().join("runtime-presence.cc"))?; + let authority = fixture_authority(&fixture)?; + let canonical = rmp_serde::to_vec(&fixture.presence)?; + assert!( + authenticate_runtime_presence_claim( + &canonical, + &authority, + RuntimePresenceAuthenticationContext { + trusted_received_at_unix_millis: 200, + maximum_age_millis: 10, + maximum_future_skew_millis: 5, + }, + ) + .is_err() + ); + + fixture.presence.observed_at_unix_millis = 126; + resign_presence(&mut fixture)?; + assert!( + authenticate_runtime_presence_claim( + &rmp_serde::to_vec(&fixture.presence)?, + &authority, + RuntimePresenceAuthenticationContext { + trusted_received_at_unix_millis: 120, + maximum_age_millis: 30, + maximum_future_skew_millis: 5, + }, + ) + .is_err() + ); + + Ok(()) + } + + #[test] + fn runtime_authority_decoders_reject_malformed_and_noncanonical_bytes() -> Result<()> { + let temp = tempfile::tempdir()?; + let fixture = dual_proof_fixture(&temp.path().join("runtime-presence.cc"))?; + assert!( + authenticate_runtime_presence_claim( + &[0x91, 0xc0], + &fixture_authority(&fixture)?, + RuntimePresenceAuthenticationContext { + trusted_received_at_unix_millis: 120, + maximum_age_millis: 30, + maximum_future_skew_millis: 5, + }, + ) + .is_err() + ); + assert!(IdunnRuntimeActivationRecord::decode_canonical(&[0x91, 0xc0]).is_err()); + assert!(IdunnProcessWriteLeaseRecord::decode_canonical(&[0x91, 0xc0]).is_err()); + + let mut legacy_presence = fixture.presence.clone(); + legacy_presence.schema_version = "gamecult.runtime_presence_health.v1".into(); + assert!( + authenticate_runtime_presence_claim( + &rmp_serde::to_vec(&legacy_presence)?, + &fixture_authority(&fixture)?, + RuntimePresenceAuthenticationContext { + trusted_received_at_unix_millis: 120, + maximum_age_millis: 30, + maximum_future_skew_millis: 5, + }, + ) + .is_err() + ); + let mut legacy_activation = fixture.activation.clone(); + legacy_activation.schema_version = "idunn.runtime_activation.v1".into(); + assert!( + IdunnRuntimeActivationRecord::decode_canonical(&rmp_serde::to_vec(&legacy_activation)?) + .is_err() + ); + let mut legacy_expected = fixture.expected.clone(); + legacy_expected.schema_version = "idunn.expected_incarnation.v1".into(); + assert!( + IdunnExpectedIncarnationRecord::decode_canonical(&rmp_serde::to_vec(&legacy_expected)?) + .is_err() + ); + let mut legacy_topology = topology_correlation(&fixture.expected); + legacy_topology.schema_version = "odin.runtime_topology_correlation.v1".into(); + assert!( + OdinRuntimeTopologyCorrelationRecord::decode_canonical_signed_payload( + &rmp_serde::to_vec(&legacy_topology)?, + ) + .is_err() + ); + + let presence = rmp_serde::to_vec(&runtime_presence())?; + assert_eq!(&presence[..3], &[0xdc, 0, 24]); + let mut noncanonical_presence = vec![0xdd, 0, 0, 0, 24]; + noncanonical_presence.extend_from_slice(&presence[3..]); + assert!( + authenticate_runtime_presence_claim( + &noncanonical_presence, + &fixture_authority(&fixture)?, + RuntimePresenceAuthenticationContext { + trusted_received_at_unix_millis: 120, + maximum_age_millis: 30, + maximum_future_skew_millis: 5, + }, + ) + .is_err() + ); + + let activation = runtime_activation().canonical_bytes()?; + assert_eq!(activation[0], 0x9a); + let mut noncanonical_activation = vec![0xdc, 0, 10]; + noncanonical_activation.extend_from_slice(&activation[1..]); + assert!(IdunnRuntimeActivationRecord::decode_canonical(&noncanonical_activation).is_err()); + + let lease = process_write_lease().canonical_bytes()?; + assert_eq!(lease[0], 0x9e); + let mut noncanonical_lease = vec![0xdc, 0, 14]; + noncanonical_lease.extend_from_slice(&lease[1..]); + assert!(IdunnProcessWriteLeaseRecord::decode_canonical(&noncanonical_lease).is_err()); + Ok(()) + } + + #[test] + fn runtime_presence_refuses_capability_and_warming_lease_ambiguity() { + let mut value = runtime_presence(); + value.capabilities.reverse(); + assert!(value.validate().is_err()); + + let mut value = runtime_presence(); + let mut duplicate = runtime_capability("state"); + duplicate.capacity = 2; + value.capabilities.push(duplicate); + assert!(value.validate().is_err()); + + let mut value = runtime_presence(); + value.capabilities[0].capacity = 0; + assert!(value.validate().is_err()); + + let mut value = runtime_presence(); + value.state = "warming".into(); + assert!(value.validate().is_err()); + value.write_lease_sha256 = None; + assert!(value.validate().is_ok()); + + let mut value = runtime_presence(); + value.state_schema_generation = None; + assert!(value.validate().is_err()); + value.state_contract_sha256 = None; + assert!(value.validate().is_err()); + value.write_lease_sha256 = None; + assert!(value.validate().is_ok()); + } + + #[test] + fn runtime_authority_refuses_malformed_digest_process_and_epoch_bindings() { + let mut value = runtime_presence(); + value.activation_witness_sha256 = digest('A'); + assert!(value.validate().is_err()); + + let mut value = runtime_presence(); + value.plan_id = "plan-1".into(); + assert!(value.validate().is_err()); + + let mut value = runtime_presence(); + value.sealed_release_id = "release-1".into(); + assert!(value.validate().is_err()); + + let mut value = runtime_presence(); + value.runtime_instance_id = "systemd-invocation-1".into(); + assert!(value.validate().is_err()); + + let mut value = runtime_presence(); + value.expected_projection_sha256 = "expected-1".into(); + assert!(value.validate().is_err()); + + let mut value = runtime_presence(); + value.write_lease_sha256 = Some("lease-1".into()); + assert!(value.validate().is_err()); + + let mut value = process_write_lease(); + value.warming_presence_sha256 = digest('D'); + assert!(value.validate().is_err()); + + let mut value = process_write_lease(); + value.plan_id = "plan-1".into(); + assert!(value.validate().is_err()); + + let mut value = process_write_lease(); + value.runtime_instance_id = "pid-4242".into(); + assert!(value.validate().is_err()); + + let mut value = process_write_lease(); + value.lease_epoch = 0; + assert!(value.validate().is_err()); + + let mut value = runtime_activation(); + value.runtime_instance_id = digest('A'); + assert!(value.validate().is_err()); + + let mut value = runtime_activation(); + value.expected_projection_sha256 = "expected-1".into(); + assert!(value.validate().is_err()); + } + + #[test] + fn runtime_presence_trust_anchor_is_provider_profile_and_purpose_bound() -> Result<()> { + let anchor = runtime_presence_anchor(); + anchor.validate()?; + + let mut value = anchor.clone(); + value.signing_purpose = "idunn.signed_daemon_health.v1".into(); + assert!(value.validate().is_err()); + + let mut value = anchor.clone(); + value.signed_schema = IDUNN_SIGNED_DAEMON_HEALTH_SCHEMA.into(); + assert!(value.validate().is_err()); + + let mut value = anchor.clone(); + value.signing_purpose = "gamecult.runtime_presence_health.v1".into(); + value.signed_schema = "gamecult.runtime_presence_health.v1".into(); + assert!(value.validate().is_err()); + + let mut value = anchor; + value.signer_identity_id = + derive_service_identity_id::(&value.signer_public_key)?; + assert!(value.validate().is_err()); + Ok(()) + } + + #[test] + fn process_write_lease_cannot_encode_route_or_traffic_authority() -> Result<()> { + let canonical = process_write_lease().canonical_bytes()?; + assert_eq!(messagepack_array_len(&canonical), Some(14)); + + for forbidden in ["route", "traffic"] { + let mut with_extra_authority = vec![0xdc, 0, 15]; + with_extra_authority.extend_from_slice(&canonical[1..]); + with_extra_authority.extend_from_slice(&rmp_serde::to_vec(&forbidden)?); + assert!(IdunnProcessWriteLeaseRecord::decode_canonical(&with_extra_authority).is_err()); + } + Ok(()) + } + + #[test] + fn expected_and_topology_correlation_round_trip_canonically() -> Result<()> { + let expected = expected_incarnation(); + let expected_bytes = expected.canonical_bytes()?; + assert_eq!(&expected_bytes[..3], &[0xdc, 0, 18]); + assert_eq!( + IdunnExpectedIncarnationRecord::decode_canonical(&expected_bytes)?, + expected + ); + assert_eq!( + expected.canonical_sha256()?, + prefixed_sha256(&expected_bytes) + ); + + let receipt = topology_correlation(&expected); + validate_against_current_lease(&receipt, &expected)?; + let receipt_bytes = receipt.canonical_bytes()?; + assert_eq!(&receipt_bytes[..3], &[0xdc, 0, 21]); + let (decoded, unsigned) = + OdinRuntimeTopologyCorrelationRecord::decode_canonical_signed_payload(&receipt_bytes)?; + assert_eq!(decoded, receipt); + let unsigned_receipt: OdinRuntimeTopologyCorrelationRecord = + rmp_serde::from_slice(&unsigned)?; + assert!(unsigned_receipt.signature.is_empty()); + assert_eq!(unsigned, receipt.unsigned_signature_payload()?); + assert_eq!(receipt.canonical_sha256()?, prefixed_sha256(&receipt_bytes)); + Ok(()) + } + + #[test] + fn expected_and_topology_decoders_reject_noncanonical_or_extended_records() -> Result<()> { + assert!(IdunnExpectedIncarnationRecord::decode_canonical(&[0x91, 0xc0]).is_err()); + assert!( + OdinRuntimeTopologyCorrelationRecord::decode_canonical_signed_payload(&[0x91, 0xc0]) + .is_err() + ); + + let expected = expected_incarnation().canonical_bytes()?; + let mut noncanonical_expected = vec![0xdd, 0, 0, 0, 18]; + noncanonical_expected.extend_from_slice(&expected[3..]); + assert!(IdunnExpectedIncarnationRecord::decode_canonical(&noncanonical_expected).is_err()); + + let receipt = topology_correlation(&expected_incarnation()).canonical_bytes()?; + let mut noncanonical_receipt = vec![0xdd, 0, 0, 0, 21]; + noncanonical_receipt.extend_from_slice(&receipt[3..]); + assert!( + OdinRuntimeTopologyCorrelationRecord::decode_canonical_signed_payload( + &noncanonical_receipt, + ) + .is_err() + ); + + for forbidden in ["private-host-path", "runner-secret"] { + let mut extended = vec![0xdc, 0, 19]; + extended.extend_from_slice(&expected[3..]); + extended.extend_from_slice(&rmp_serde::to_vec(&forbidden)?); + assert!(IdunnExpectedIncarnationRecord::decode_canonical(&extended).is_err()); + } + Ok(()) + } + + #[test] + fn expected_refuses_partial_state_and_noncanonical_claim_sets() { + let mut value = expected_incarnation(); + value.state_contract_sha256 = None; + assert!(value.validate().is_err()); + + let mut value = expected_incarnation(); + value.state_schema_generation = None; + assert!(value.validate().is_err()); + + let mut value = expected_incarnation(); + value.state_schema_generation = None; + value.state_contract_sha256 = None; + assert!(value.validate().is_err()); + value.write_lease_required = false; + assert!(value.validate().is_ok()); + + let mut value = expected_incarnation(); + value.capabilities.reverse(); + assert!(value.validate().is_err()); + + let mut value = expected_incarnation(); + value.capabilities.push(expected_capability("state")); + assert!(value.validate().is_err()); + + let mut value = expected_incarnation(); + value.dependencies.reverse(); + assert!(value.validate().is_err()); + + let mut value = expected_incarnation(); + value.dependencies.push(value.dependencies[1].clone()); + assert!(value.validate().is_err()); + + let mut value = expected_incarnation(); + let mut duplicate = value.dependencies[1].clone(); + duplicate.kind = "required".into(); + value.dependencies.push(duplicate); + assert!(value.validate().is_err()); + + let mut value = expected_incarnation(); + value.dependencies[0].provider_authority = None; + assert!(value.validate().is_err()); + + let mut value = expected_incarnation(); + value.source_revision = "A".repeat(40); + assert!(value.validate().is_err()); + + for private_source in [ + "F:\\Projects\\Ghostlight", + "/srv/build/Ghostlight", + "https://token@github.com/GameCult/Ghostlight", + ] { + let mut value = expected_incarnation(); + value.source_repository = private_source.into(); + assert!(value.validate().is_err()); + } + + let mut value = expected_incarnation(); + let stable_endpoint = value.route.as_ref().unwrap().stable_endpoint.clone(); + value.route.as_mut().unwrap().candidate_endpoint = stable_endpoint; + assert!(value.validate().is_err()); + } + + #[test] + fn expected_route_keeps_rudp_distinct_and_scheme_exact() { + let mut value = expected_incarnation(); + value.route = Some(IdunnExpectedRoute { + route_id: "odin-rendezvous".into(), + transport: "rudp".into(), + stable_endpoint: "rudp://10.77.0.1:17871".into(), + candidate_endpoint: "rudp://127.0.0.1:24171".into(), + }); + assert!(value.validate().is_ok()); + + value.route.as_mut().unwrap().candidate_endpoint = "tcp://127.0.0.1:24171".into(); + assert!(value.validate().is_err()); + + value.route.as_mut().unwrap().candidate_endpoint = "udp://127.0.0.1:24171".into(); + assert!(value.validate().is_err()); + } + + #[test] + fn topology_correlation_refuses_expected_substitution_and_dependency_omission() { + let expected = expected_incarnation(); + + let mut value = topology_correlation(&expected); + value.target = "epiphany".into(); + assert!(value.validate().is_ok()); + assert!(validate_against_current_lease(&value, &expected).is_err()); + + let mut value = topology_correlation(&expected); + value.runtime_id = "ghostlight-other-runtime".into(); + assert!(validate_against_current_lease(&value, &expected).is_err()); + + let mut value = topology_correlation(&expected); + value.expected_projection_sha256 = digest('c'); + assert!(validate_against_current_lease(&value, &expected).is_err()); + + let mut value = topology_correlation(&expected); + value.dependencies.pop(); + assert!(value.validate().is_ok()); + assert!(validate_against_current_lease(&value, &expected).is_err()); + + let mut value = topology_correlation(&expected); + value.dependencies[0].provider_id = Some("odin-substitute".into()); + assert!(value.validate().is_ok()); + assert!(validate_against_current_lease(&value, &expected).is_err()); + + let mut value = topology_correlation(&expected); + value.dependencies[0].kind = "required".into(); + assert!(value.validate().is_ok()); + assert!(validate_against_current_lease(&value, &expected).is_err()); + + let mut value = topology_correlation(&expected); + value.dependencies[0].observed_capacity = Some(0); + assert!(value.validate().is_err()); + + let mut value = topology_correlation(&expected); + value.dependencies[0].observed_capacity = Some(1); + let mut stricter = expected.clone(); + stricter.dependencies[0].minimum_capacity = 2; + value.expected_projection_sha256 = stricter.canonical_sha256().unwrap(); + assert!(validate_against_current_lease(&value, &stricter).is_err()); + } + + #[test] + fn topology_correlation_requires_explicit_coherent_partial_states() { + let expected = expected_incarnation(); + let mut value = topology_correlation(&expected); + value.signed_presence_sha256 = None; + value.observed_presence_state = None; + value.observed_presence_publisher_sequence = None; + value.observed_write_lease_sha256 = None; + value.observed_capabilities.clear(); + value.present = false; + value.ready = false; + assert!(value.validate().is_err()); + + value.disagreements.push(OdinTopologyDisagreement { + code: "presence-missing".into(), + expected: Some("signed-runtime-presence".into()), + observed: None, + }); + assert!(value.validate().is_ok()); + + let mut value = topology_correlation(&expected); + value.runtime_instance_id = None; + assert!(value.validate().is_err()); + + let mut value = topology_correlation(&expected); + value.current_activation_sha256 = None; + value.present = true; + value.ready = false; + value.disagreements.push(OdinTopologyDisagreement { + code: "activation-missing".into(), + expected: Some("current-activation".into()), + observed: None, + }); + assert!(value.validate().is_err()); + + let mut value = topology_correlation(&expected); + value.expected = false; + value.present = false; + value.ready = false; + assert!(value.validate().is_err()); + } + + #[test] + fn topology_correlation_refuses_unsorted_or_duplicate_claims() { + let expected = expected_incarnation(); + let mut value = topology_correlation(&expected); + value.dependencies.reverse(); + assert!(value.validate().is_err()); + + let mut value = topology_correlation(&expected); + value.dependencies.push(value.dependencies[1].clone()); + assert!(value.validate().is_err()); + + let mut value = topology_correlation(&expected); + value.ready = false; + value.disagreements = vec![ + OdinTopologyDisagreement { + code: "schema-mismatch".into(), + expected: Some("state.v2".into()), + observed: Some("state.v1".into()), + }, + OdinTopologyDisagreement { + code: "endpoint-mismatch".into(), + expected: Some("route-a".into()), + observed: Some("route-b".into()), + }, + ]; + assert!(value.validate().is_err()); + + value.disagreements[1].code = "schema-mismatch".into(); + assert!(value.validate().is_err()); + } + + #[test] + fn topology_correlation_preserves_warming_and_exact_write_lease_authority() { + let expected = expected_incarnation(); + let value = topology_correlation(&expected); + validate_against_current_lease(&value, &expected).unwrap(); + assert!( + value + .validate_against_expected(&expected, Some(&digest('d'))) + .is_err() + ); + assert!(value.validate_against_expected(&expected, None).is_err()); + + let mut digest_only_ready = topology_correlation(&expected); + digest_only_ready.observed_write_lease_sha256 = None; + digest_only_ready.validate().unwrap(); + assert!( + digest_only_ready + .validate_against_expected(&expected, Some(&digest('c'))) + .is_err() + ); + + let mut warming = topology_correlation(&expected); + warming.observed_presence_state = Some("warming".into()); + warming.ready = false; + assert!(warming.validate().is_err()); + warming.observed_write_lease_sha256 = None; + warming.validate().unwrap(); + warming.validate_against_expected(&expected, None).unwrap(); + warming.ready = true; + assert!(warming.validate().is_err()); + + let mut partial = topology_correlation(&expected); + partial.observed_presence_state = None; + assert!(partial.validate().is_err()); + let mut partial = topology_correlation(&expected); + partial.signed_presence_sha256 = None; + assert!(partial.validate().is_err()); + + let mut stateless = expected.clone(); + stateless.state_schema_generation = None; + stateless.state_contract_sha256 = None; + stateless.write_lease_required = false; + let mut stateless_receipt = topology_correlation(&stateless); + stateless_receipt.observed_write_lease_sha256 = None; + stateless_receipt + .validate_against_expected(&stateless, None) + .unwrap(); + stateless_receipt.observed_write_lease_sha256 = Some(digest('c')); + assert!( + stateless_receipt + .validate_against_expected(&stateless, Some(&digest('c'))) + .is_err() + ); + } + + #[test] + fn topology_correlation_cannot_manufacture_ready() { + let expected = expected_incarnation(); + let mut value = topology_correlation(&expected); + value.dependencies[0].ready = false; + assert!(value.validate().is_err()); + + let mut value = topology_correlation(&expected); + value.disagreements.push(OdinTopologyDisagreement { + code: "capability-mismatch".into(), + expected: Some("conversation.v1".into()), + observed: Some("conversation.v0".into()), + }); + assert!(value.validate().is_err()); + + let mut value = topology_correlation(&expected); + value.present = false; + value.disagreements.push(OdinTopologyDisagreement { + code: "identity-mismatch".into(), + expected: Some("expected-runtime".into()), + observed: Some("other-runtime".into()), + }); + assert!(value.validate().is_err()); + + let mut value = topology_correlation(&expected); + value.dependencies[0].provider_evidence_sha256 = None; + assert!(value.validate().is_err()); + + let mut missing_capability = topology_correlation(&expected); + missing_capability.observed_capabilities.pop(); + assert!(missing_capability.validate().is_ok()); + assert!( + missing_capability + .validate_against_expected(&expected, Some(&digest('c'))) + .is_err() + ); + missing_capability.present = true; + missing_capability.ready = false; + missing_capability.disagreements = vec![OdinTopologyDisagreement { + code: "generic-mismatch".into(), + expected: Some("expected".into()), + observed: Some("observed".into()), + }]; + assert!( + missing_capability + .validate_against_expected(&expected, Some(&digest('c'))) + .is_err() + ); + correlate_capabilities( + &mut missing_capability.disagreements, + &expected.capabilities, + &missing_capability.observed_capabilities, + ); + missing_capability + .disagreements + .sort_by(|left, right| left.code.cmp(&right.code)); + missing_capability + .validate_against_expected(&expected, Some(&digest('c'))) + .unwrap(); + + let mut additional_capability = topology_correlation(&expected); + additional_capability + .observed_capabilities + .push(runtime_capability("telemetry")); + additional_capability + .validate_against_expected(&expected, Some(&digest('c'))) + .unwrap(); + } + + #[test] + fn topology_signature_is_exact_and_purpose_bound() -> Result<()> { + let temp = tempfile::tempdir()?; + let signer = enroll_service_identity_at::( + &temp.path().join("odin-topology.cc"), + )?; + let anchor = signer.trust_anchor()?; + let expected = expected_incarnation(); + let mut receipt = topology_correlation(&expected); + receipt.signer_identity_id = anchor.identity_id.clone(); + receipt.signature.clear(); + let unsigned = receipt.unsigned_signature_payload()?; + let proof = signer.sign::(&unsigned); + receipt.signature = proof.signature.clone(); + + let encoded = receipt.canonical_bytes()?; + let (decoded, decoded_unsigned) = + OdinRuntimeTopologyCorrelationRecord::decode_canonical_signed_payload(&encoded)?; + verify_service_identity_signature::< + OdinTopologyIdentity, + OdinRuntimeTopologyCorrelationPurpose, + >( + &anchor, + &decoded_unsigned, + &ServiceIdentitySignature { + identity_id: decoded.signer_identity_id, + signature: decoded.signature, + }, + )?; + + let mut substituted = decoded_unsigned.clone(); + substituted.push(0); + assert!( + verify_service_identity_signature::< + OdinTopologyIdentity, + OdinRuntimeTopologyCorrelationPurpose, + >(&anchor, &substituted, &proof) + .is_err() + ); + + let wrong_purpose = signer.sign::(&decoded_unsigned); + assert!( + verify_service_identity_signature::< + OdinTopologyIdentity, + OdinRuntimeTopologyCorrelationPurpose, + >(&anchor, &decoded_unsigned, &wrong_purpose) + .is_err() + ); + Ok(()) + } + + #[test] + fn topology_trust_anchor_is_odin_profile_and_purpose_bound() -> Result<()> { + let anchor = topology_anchor(); + anchor.validate()?; + + let mut value = anchor.clone(); + value.service_id = "idunn".into(); + assert!(value.validate().is_err()); + + let mut value = anchor.clone(); + value.signing_purpose = GAMECULT_RUNTIME_PRESENCE_HEALTH_SIGNING_PURPOSE.into(); + assert!(value.validate().is_err()); + + let mut value = anchor.clone(); + value.signed_schema = GAMECULT_RUNTIME_PRESENCE_HEALTH_SCHEMA.into(); + assert!(value.validate().is_err()); + + let mut value = anchor; + value.signer_identity_id = + derive_service_identity_id::(&value.signer_public_key)?; + assert!(value.validate().is_err()); + Ok(()) + } +} diff --git a/packages/cultnet-rs/src/service_identity.rs b/packages/cultnet-rs/src/service_identity.rs new file mode 100644 index 00000000..81b91a8c --- /dev/null +++ b/packages/cultnet-rs/src/service_identity.rs @@ -0,0 +1,920 @@ +use anyhow::{Context, Result, anyhow, bail}; +use cultcache_rs::{CacheBackingStore, CultCacheEnvelope, SingleFileMessagePackBackingStore}; +use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey}; +use rand::RngCore; +use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; +use std::io::{Read, Write}; +use std::marker::PhantomData; +use std::path::Path; +#[cfg(windows)] +use zeroize::Zeroize; +use zeroize::Zeroizing; + +pub const WINDOWS_SERVICE_IDENTITY_ASSURANCE: &str = "os_user_installation_bound_best_effort"; +pub const LINUX_SERVICE_IDENTITY_ASSURANCE: &str = "os_installation_file_bound_cloneable_baseline"; + +/// Fixes every authority-bearing name at the call site. A service cannot open +/// another service's identity by supplying a convenient runtime string. +pub trait ServiceIdentityProfile: Send + Sync + 'static { + const PRIVATE_TYPE: &'static str; + const PRIVATE_SCHEMA: &'static str; + const PRIVATE_KEY: &'static str; + const TRUST_ANCHOR_TYPE: &'static str; + const TRUST_ANCHOR_SCHEMA: &'static str; + const TRUST_ANCHOR_KEY: &'static str; + const ID_DOMAIN: &'static [u8]; + const SIGNATURE_DOMAIN: &'static [u8]; + const PROTECTOR_CONTEXT: &'static str; +} + +/// A purpose is a type, not caller-provided prose. Protocol implementations +/// define one zero-sized type per signed statement kind. +pub trait ServiceSignaturePurpose: Send + Sync + 'static { + const PURPOSE: &'static [u8]; +} + +pub enum IdunnServiceIdentity {} + +/// Odin-owned identity dedicated to signed Expected/Present/Ready topology +/// correlation. It is not a provider-health key and cannot issue Idunn +/// admission or lifecycle authority. +pub enum OdinTopologyIdentity {} + +pub struct OdinRuntimeTopologyCorrelationPurpose; + +impl ServiceSignaturePurpose for OdinRuntimeTopologyCorrelationPurpose { + const PURPOSE: &'static [u8] = b"odin.runtime_topology_correlation.v2"; +} + +impl ServiceIdentityProfile for OdinTopologyIdentity { + const PRIVATE_TYPE: &'static str = "odin.topology_identity.private.v1"; + const PRIVATE_SCHEMA: &'static str = "odin.topology_identity.private.v1"; + const PRIVATE_KEY: &'static str = "odin-topology-identity"; + const TRUST_ANCHOR_TYPE: &'static str = "odin.topology_identity.trust_anchor.v1"; + const TRUST_ANCHOR_SCHEMA: &'static str = "odin.topology_identity.trust_anchor.v1"; + const TRUST_ANCHOR_KEY: &'static str = "odin-topology-identity-public"; + const ID_DOMAIN: &'static [u8] = b"odin.topology-identity.id.v1\0"; + const SIGNATURE_DOMAIN: &'static [u8] = b"odin.topology-identity.signature.v1\0"; + const PROTECTOR_CONTEXT: &'static str = "odin-topology-identity-v1"; +} + +/// Root-operated identity dedicated to deployment-brake release grants. The +/// Idunn daemon receives only this profile's public trust anchor; opening the +/// private store is a provisioning operation, never daemon startup work. +pub enum IdunnDeploymentBrakeOperatorIdentity {} + +pub struct IdunnDeploymentBrakeReleasePurpose; + +impl ServiceSignaturePurpose + for IdunnDeploymentBrakeReleasePurpose +{ + const PURPOSE: &'static [u8] = b"idunn.deployment-release.v1"; +} + +impl ServiceIdentityProfile for IdunnDeploymentBrakeOperatorIdentity { + const PRIVATE_TYPE: &'static str = "idunn.deployment_brake_operator.private.v1"; + const PRIVATE_SCHEMA: &'static str = "idunn.deployment_brake_operator.private.v1"; + const PRIVATE_KEY: &'static str = "idunn-deployment-brake-operator"; + const TRUST_ANCHOR_TYPE: &'static str = "idunn.deployment_brake_operator.trust_anchor.v1"; + const TRUST_ANCHOR_SCHEMA: &'static str = "idunn.deployment_brake_operator.trust_anchor.v1"; + const TRUST_ANCHOR_KEY: &'static str = "idunn-deployment-brake-operator-public"; + const ID_DOMAIN: &'static [u8] = b"idunn.deployment-brake-operator.id.v1\0"; + const SIGNATURE_DOMAIN: &'static [u8] = b"idunn.deployment-brake-operator.signature.v1\0"; + const PROTECTOR_CONTEXT: &'static str = "idunn-deployment-brake-operator-v1"; +} + +/// Dedicated provider-owned identity for generic daemon-health statements. +/// It is intentionally independent of any one provider runtime or repository. +pub enum GameCultProviderHealthIdentity {} + +/// The only generic health statement purpose accepted from provider-health +/// identities by Idunn admission. +pub struct IdunnSignedDaemonHealthPurpose; + +impl ServiceSignaturePurpose for IdunnSignedDaemonHealthPurpose { + const PURPOSE: &'static [u8] = b"idunn.signed_daemon_health.v1"; +} + +/// Provider-owned runtime presence and health. This is deliberately distinct +/// from the legacy daemon-health purpose so an old signature cannot acquire +/// deployment-incarnation authority by substitution. +pub struct GameCultRuntimePresenceHealthPurpose; + +impl ServiceSignaturePurpose + for GameCultRuntimePresenceHealthPurpose +{ + const PURPOSE: &'static [u8] = b"gamecult.runtime_presence_health.v2"; +} + +impl ServiceIdentityProfile for GameCultProviderHealthIdentity { + const PRIVATE_TYPE: &'static str = "gamecult.provider_health_identity.private.v1"; + const PRIVATE_SCHEMA: &'static str = "gamecult.provider_health_identity.private.v1"; + const PRIVATE_KEY: &'static str = "gamecult-provider-health-identity"; + const TRUST_ANCHOR_TYPE: &'static str = "gamecult.provider_health_identity.trust_anchor.v1"; + const TRUST_ANCHOR_SCHEMA: &'static str = "gamecult.provider_health_identity.trust_anchor.v1"; + const TRUST_ANCHOR_KEY: &'static str = "gamecult-provider-health-identity-public"; + const ID_DOMAIN: &'static [u8] = b"gamecult.provider-health.identity.v1\0"; + const SIGNATURE_DOMAIN: &'static [u8] = b"gamecult.provider-health.signature.v1\0"; + const PROTECTOR_CONTEXT: &'static str = "gamecult-provider-health-identity-v1"; +} + +/// The only signing purpose accepted for Idunn's public projection of a +/// provider-authenticated health admission. Keeping this profile here makes +/// purpose selection a compile-time protocol choice rather than caller text. +pub struct IdunnAuthenticatedProviderHealthProjectionPurpose; + +impl ServiceSignaturePurpose + for IdunnAuthenticatedProviderHealthProjectionPurpose +{ + const PURPOSE: &'static [u8] = b"idunn.authenticated-provider-health-projection.v1"; +} + +/// Idunn's stable identity signs every activation before its ephemeral key is +/// handed to a workload. This makes the launch witness portable without +/// allowing a configuration file or provider to mint its own activation. +pub struct IdunnRuntimeActivationPurpose; + +impl ServiceSignaturePurpose for IdunnRuntimeActivationPurpose { + const PURPOSE: &'static [u8] = b"idunn.runtime_activation.v2"; +} + +impl ServiceIdentityProfile for IdunnServiceIdentity { + const PRIVATE_TYPE: &'static str = "idunn.service_identity.private.v1"; + const PRIVATE_SCHEMA: &'static str = "idunn.service_identity.private.v1"; + const PRIVATE_KEY: &'static str = "idunn-service-identity"; + const TRUST_ANCHOR_TYPE: &'static str = "idunn.service_identity.trust_anchor.v1"; + const TRUST_ANCHOR_SCHEMA: &'static str = "idunn.service_identity.trust_anchor.v1"; + const TRUST_ANCHOR_KEY: &'static str = "idunn-service-identity-public"; + const ID_DOMAIN: &'static [u8] = b"idunn.service-identity.id.v1\0"; + const SIGNATURE_DOMAIN: &'static [u8] = b"idunn.service-identity.signature.v1\0"; + const PROTECTOR_CONTEXT: &'static str = "idunn-service-identity-v1"; +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct ServiceIdentityPrivateEntry { + pub schema_version: String, + pub identity_id: String, + pub public_key: Vec, + pub protected_private_seed: Vec, + pub protector_kind: String, + pub protector_binding: String, + pub protector_version: String, + pub assurance: String, + pub created_at: String, + pub enrollment_nonce: Vec, +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct ServiceIdentityTrustAnchor { + pub schema_version: String, + pub identity_id: String, + pub public_key: Vec, + pub assurance: String, + pub identity_created_at: String, + pub source_identity_record_sha256: String, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ServiceIdentitySignature { + pub identity_id: String, + pub signature: Vec, +} + +/// The only value holding unprotected key material. It exposes signing, never +/// seed export or access to the underlying signing key. +pub struct ServiceIdentitySigner { + entry: ServiceIdentityPrivateEntry, + signing_key: SigningKey, + profile: PhantomData

    , +} + +impl ServiceIdentitySigner

    { + pub fn entry(&self) -> &ServiceIdentityPrivateEntry { + &self.entry + } + + pub fn trust_anchor(&self) -> Result { + Ok(ServiceIdentityTrustAnchor { + schema_version: P::TRUST_ANCHOR_SCHEMA.into(), + identity_id: self.entry.identity_id.clone(), + public_key: self.entry.public_key.clone(), + assurance: self.entry.assurance.clone(), + identity_created_at: self.entry.created_at.clone(), + source_identity_record_sha256: format!( + "sha256-{}", + hex(&Sha256::digest(rmp_serde::to_vec(&self.entry)?)) + ), + }) + } + + pub fn sign>(&self, payload: &[u8]) -> ServiceIdentitySignature { + ServiceIdentitySignature { + identity_id: self.entry.identity_id.clone(), + signature: self + .signing_key + .sign(&signing_message::(payload)) + .to_bytes() + .to_vec(), + } + } +} + +pub fn enroll_service_identity_at( + path: &Path, +) -> Result> { + if path.exists() { + bail!( + "service identity store {} already exists; enrollment is immutable", + path.display() + ); + } + prepare_parent(path)?; + let mut seed = Zeroizing::new([0u8; 32]); + rand::rng().fill_bytes(seed.as_mut()); + let signing_key = SigningKey::from_bytes(&*seed); + let mut nonce = [0u8; 32]; + rand::rng().fill_bytes(&mut nonce); + let public_key = signing_key.verifying_key().to_bytes(); + let binding = platform_binding::

    ()?; + let entry = ServiceIdentityPrivateEntry { + schema_version: P::PRIVATE_SCHEMA.into(), + identity_id: identity_id::

    (&public_key), + public_key: public_key.to_vec(), + protected_private_seed: protect_seed::

    (&*seed, &binding)?, + protector_kind: platform_protector_kind().into(), + protector_binding: binding, + protector_version: "v1".into(), + assurance: platform_assurance().into(), + created_at: chrono::Utc::now().to_rfc3339(), + enrollment_nonce: nonce.to_vec(), + }; + validate_private::

    (&entry)?; + let envelope = private_envelope::

    (&entry)?; + atomic_create_private_store(path, &envelope)?; + harden_store_permissions(path)?; + open_service_identity_at::

    (path) +} + +pub fn open_service_identity_at( + path: &Path, +) -> Result> { + if !path.is_file() { + bail!("service identity store {} does not exist", path.display()); + } + let entries = SingleFileMessagePackBackingStore::new(path).pull_all()?; + open_service_identity_envelopes::

    (&entries) +} + +/// Opens an immutable service-identity credential from a read-only stream. +/// +/// Unlike [`open_service_identity_at`], this path has no sibling-lock or +/// writable-filesystem requirement. It is intended for immutable credential +/// copies such as systemd `LoadCredential` files. +pub fn open_service_identity_credential_reader( + mut reader: impl Read, +) -> Result> { + let mut bytes = Zeroizing::new(Vec::new()); + reader + .read_to_end(&mut bytes) + .context("failed to read immutable service identity credential")?; + open_service_identity_credential_bytes::

    (&bytes) +} + +/// Opens an immutable service-identity credential from its exact bytes. +pub fn open_service_identity_credential_bytes( + bytes: &[u8], +) -> Result> { + let mut decoder = rmp_serde::Deserializer::new(std::io::Cursor::new(bytes)); + let entries = Vec::::deserialize(&mut decoder) + .context("immutable service identity credential is malformed MessagePack")?; + if decoder.position() != bytes.len() as u64 { + bail!("immutable service identity credential contains trailing data"); + } + open_service_identity_envelopes::

    (&entries) +} + +fn open_service_identity_envelopes( + entries: &[CultCacheEnvelope], +) -> Result> { + let [envelope] = entries else { + bail!("service identity store must contain exactly one immutable envelope"); + }; + if envelope.r#type != P::PRIVATE_TYPE + || envelope.key != P::PRIVATE_KEY + || envelope.schema_id.as_deref() != Some(P::PRIVATE_SCHEMA) + { + bail!("service identity store belongs to a different profile or schema"); + } + let entry: ServiceIdentityPrivateEntry = rmp_serde::from_slice(&envelope.payload) + .context("service identity private payload is malformed MessagePack")?; + validate_private::

    (&entry)?; + if entry.protector_kind != platform_protector_kind() || entry.assurance != platform_assurance() + { + bail!("service identity protector does not belong to this platform implementation"); + } + let binding = platform_binding::

    ()?; + if entry.protector_binding != binding { + bail!("service identity protector binding does not match this OS installation or profile"); + } + let seed = unprotect_seed::

    (&entry.protected_private_seed, &binding)?; + let seed: &[u8; 32] = seed + .as_slice() + .try_into() + .map_err(|_| anyhow!("unprotected service identity seed has invalid length"))?; + let signing_key = SigningKey::from_bytes(seed); + if signing_key.verifying_key().to_bytes().as_slice() != entry.public_key.as_slice() { + bail!("service identity private seed does not match enrolled public key"); + } + Ok(ServiceIdentitySigner { + entry, + signing_key, + profile: PhantomData, + }) +} + +pub fn export_service_identity_trust_anchor( + signer: &ServiceIdentitySigner

    , + path: &Path, +) -> Result { + let anchor = signer.trust_anchor()?; + prepare_parent(path)?; + let envelope = CultCacheEnvelope { + key: P::TRUST_ANCHOR_KEY.into(), + r#type: P::TRUST_ANCHOR_TYPE.into(), + payload: rmp_serde::to_vec(&anchor)?, + stored_at: anchor.identity_created_at.clone(), + schema_id: Some(P::TRUST_ANCHOR_SCHEMA.into()), + }; + let mut backing = SingleFileMessagePackBackingStore::new(path); + match backing.pull_all()?.as_slice() { + [] => backing.push(&envelope)?, + [current] if current == &envelope => {} + _ => bail!("service identity trust anchor output already contains different state"), + } + Ok(anchor) +} + +pub fn verify_service_identity_signature( + anchor: &ServiceIdentityTrustAnchor, + payload: &[u8], + proof: &ServiceIdentitySignature, +) -> Result<()> +where + P: ServiceIdentityProfile, + S: ServiceSignaturePurpose

    , +{ + validate_anchor::

    (anchor)?; + if proof.identity_id != anchor.identity_id { + bail!("service identity signature names a different identity"); + } + let key: [u8; 32] = anchor + .public_key + .as_slice() + .try_into() + .map_err(|_| anyhow!("service identity public key has invalid length"))?; + let signature = Signature::from_slice(&proof.signature) + .map_err(|_| anyhow!("service identity signature has invalid length"))?; + VerifyingKey::from_bytes(&key)? + .verify(&signing_message::(payload), &signature) + .map_err(|_| anyhow!("service identity signature verification failed")) +} + +/// Verify against a public key already admitted by an owning trust store. +/// The profile derives the identity, so callers cannot substitute a convenient +/// identity string while retaining the same signature bytes. +pub fn verify_service_identity_signature_with_public_key( + public_key: &[u8], + payload: &[u8], + proof: &ServiceIdentitySignature, +) -> Result<()> +where + P: ServiceIdentityProfile, + S: ServiceSignaturePurpose

    , +{ + if proof.identity_id != derive_service_identity_id::

    (public_key)? { + bail!("service identity signature names a different identity"); + } + let key: [u8; 32] = public_key + .try_into() + .map_err(|_| anyhow!("service identity public key has invalid length"))?; + let signature = Signature::from_slice(&proof.signature) + .map_err(|_| anyhow!("service identity signature has invalid length"))?; + VerifyingKey::from_bytes(&key)? + .verify(&signing_message::(payload), &signature) + .map_err(|_| anyhow!("service identity signature verification failed")) +} + +fn validate_private(entry: &ServiceIdentityPrivateEntry) -> Result<()> { + if entry.schema_version != P::PRIVATE_SCHEMA + || entry.public_key.len() != 32 + || entry.enrollment_nonce.len() != 32 + || entry.protected_private_seed.is_empty() + || entry.protector_version != "v1" + { + bail!("service identity private entry violates its profile schema"); + } + chrono::DateTime::parse_from_rfc3339(&entry.created_at) + .map_err(|_| anyhow!("service identity created_at is not RFC3339"))?; + if identity_id::

    (&entry.public_key) != entry.identity_id { + bail!("service identity id does not match public key"); + } + Ok(()) +} + +fn validate_anchor(anchor: &ServiceIdentityTrustAnchor) -> Result<()> { + if anchor.schema_version != P::TRUST_ANCHOR_SCHEMA + || anchor.public_key.len() != 32 + || derive_service_identity_id::

    (&anchor.public_key)? != anchor.identity_id + { + bail!("service identity trust anchor violates its profile schema"); + } + Ok(()) +} + +/// Derives the profile-bound identity id from an exact Ed25519 public key. +/// Consumers use this instead of accepting a caller-supplied identity string. +pub fn derive_service_identity_id(public_key: &[u8]) -> Result { + if public_key.len() != 32 { + bail!("service identity public key has invalid length"); + } + Ok(hex(&Sha256::digest([P::ID_DOMAIN, public_key].concat()))) +} + +fn identity_id(key: &[u8]) -> String { + derive_service_identity_id::

    (key).expect("internal service identity key is Ed25519") +} + +fn signing_message>( + payload: &[u8], +) -> Vec { + let mut out = + Vec::with_capacity(P::SIGNATURE_DOMAIN.len() + S::PURPOSE.len() + payload.len() + 16); + out.extend_from_slice(P::SIGNATURE_DOMAIN); + out.extend_from_slice(&(S::PURPOSE.len() as u64).to_be_bytes()); + out.extend_from_slice(S::PURPOSE); + out.extend_from_slice(&(payload.len() as u64).to_be_bytes()); + out.extend_from_slice(payload); + out +} + +fn private_envelope( + entry: &ServiceIdentityPrivateEntry, +) -> Result { + Ok(CultCacheEnvelope { + key: P::PRIVATE_KEY.into(), + r#type: P::PRIVATE_TYPE.into(), + payload: rmp_serde::to_vec(entry)?, + stored_at: entry.created_at.clone(), + schema_id: Some(P::PRIVATE_SCHEMA.into()), + }) +} + +fn prepare_parent(path: &Path) -> Result<()> { + let parent = path + .parent() + .ok_or_else(|| anyhow!("service identity path has no parent"))?; + std::fs::create_dir_all(parent)?; + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + std::fs::set_permissions(parent, std::fs::Permissions::from_mode(0o700))?; + } + Ok(()) +} + +/// Enrollment is a one-shot authority transition. `create_new` makes two +/// simultaneous enrollments unable to overwrite one another, while the encoded +/// envelope vector remains a supported CultCache single-file representation. +fn atomic_create_private_store(path: &Path, envelope: &CultCacheEnvelope) -> Result<()> { + let bytes = rmp_serde::to_vec(&vec![envelope.clone()]) + .context("failed to encode immutable service identity store")?; + let mut file = std::fs::OpenOptions::new() + .create_new(true) + .write(true) + .open(path) + .with_context(|| { + format!( + "service identity store {} already exists or cannot be created; enrollment is immutable", + path.display() + ) + })?; + if let Err(error) = file.write_all(&bytes).and_then(|()| file.sync_all()) { + drop(file); + let _ = std::fs::remove_file(path); + return Err(error).context("failed to persist immutable service identity store"); + } + Ok(()) +} +fn harden_store_permissions(_path: &Path) -> Result<()> { + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + std::fs::set_permissions(_path, std::fs::Permissions::from_mode(0o600))?; + } + Ok(()) +} + +#[cfg(windows)] +fn platform_protector_kind() -> &'static str { + "windows_dpapi_current_user" +} +#[cfg(target_os = "linux")] +fn platform_protector_kind() -> &'static str { + "linux_file_mode_machine_id_binding" +} +#[cfg(windows)] +fn platform_assurance() -> &'static str { + WINDOWS_SERVICE_IDENTITY_ASSURANCE +} +#[cfg(target_os = "linux")] +fn platform_assurance() -> &'static str { + LINUX_SERVICE_IDENTITY_ASSURANCE +} + +#[cfg(windows)] +fn platform_binding() -> Result { + Ok(format!("dpapi-current-user:{}", P::PROTECTOR_CONTEXT)) +} +#[cfg(target_os = "linux")] +fn platform_binding() -> Result { + let raw = std::fs::read_to_string("/etc/machine-id") + .or_else(|_| std::fs::read_to_string("/var/lib/dbus/machine-id")) + .context("Linux machine-id is unavailable")?; + let id = raw.trim(); + if id.is_empty() { + bail!("Linux machine-id is empty"); + } + Ok(format!( + "{}:machine-id-sha256:{}", + P::PROTECTOR_CONTEXT, + hex(&Sha256::digest(id.as_bytes())) + )) +} + +#[cfg(windows)] +fn protect_seed(seed: &[u8; 32], binding: &str) -> Result> { + Ok(dpapi::

    (seed, binding, true)?.to_vec()) +} +#[cfg(windows)] +fn unprotect_seed( + seed: &[u8], + binding: &str, +) -> Result>> { + dpapi::

    (seed, binding, false) +} +#[cfg(windows)] +fn dpapi( + input: &[u8], + binding: &str, + protect: bool, +) -> Result>> { + use windows_sys::Win32::Foundation::LocalFree; + use windows_sys::Win32::Security::Cryptography::{ + CRYPT_INTEGER_BLOB, CRYPTPROTECT_UI_FORBIDDEN, CryptProtectData, CryptUnprotectData, + }; + let mut input = Zeroizing::new(input.to_vec()); + let mut entropy = Zeroizing::new( + Sha256::digest( + [ + b"gamecult-service-identity-dpapi-v1\0".as_slice(), + P::PROTECTOR_CONTEXT.as_bytes(), + binding.as_bytes(), + ] + .concat(), + ) + .to_vec(), + ); + let ib = CRYPT_INTEGER_BLOB { + cbData: input.len() as u32, + pbData: input.as_mut_ptr(), + }; + let eb = CRYPT_INTEGER_BLOB { + cbData: entropy.len() as u32, + pbData: entropy.as_mut_ptr(), + }; + let mut output = CRYPT_INTEGER_BLOB { + cbData: 0, + pbData: std::ptr::null_mut(), + }; + let ok = unsafe { + if protect { + CryptProtectData( + &ib, + std::ptr::null(), + &eb, + std::ptr::null(), + std::ptr::null(), + CRYPTPROTECT_UI_FORBIDDEN, + &mut output, + ) + } else { + CryptUnprotectData( + &ib, + std::ptr::null_mut(), + &eb, + std::ptr::null(), + std::ptr::null(), + CRYPTPROTECT_UI_FORBIDDEN, + &mut output, + ) + } + }; + if ok == 0 { + return Err(std::io::Error::last_os_error()) + .context("DPAPI service identity operation failed"); + } + if output.pbData.is_null() { + bail!("DPAPI service identity operation returned a null output"); + } + let output = unsafe { std::slice::from_raw_parts_mut(output.pbData, output.cbData as usize) }; + let bytes = Zeroizing::new(output.to_vec()); + output.zeroize(); + unsafe { + LocalFree(output.as_mut_ptr().cast()); + } + Ok(bytes) +} + +#[cfg(target_os = "linux")] +fn protect_seed(seed: &[u8; 32], binding: &str) -> Result> { + xor_linux::

    (seed, binding) +} +#[cfg(target_os = "linux")] +fn unprotect_seed( + seed: &[u8], + binding: &str, +) -> Result>> { + if seed.len() != 32 { + bail!("protected Linux service seed has invalid length"); + } + let mask = Sha256::digest( + [ + b"gamecult-linux-service-seed-v1\0".as_slice(), + P::PROTECTOR_CONTEXT.as_bytes(), + binding.as_bytes(), + ] + .concat(), + ); + let mut clear_seed = Zeroizing::new(Vec::with_capacity(seed.len())); + clear_seed.extend(seed.iter().zip(mask).map(|(a, b)| a ^ b)); + Ok(clear_seed) +} +#[cfg(target_os = "linux")] +fn xor_linux(seed: &[u8], binding: &str) -> Result> { + let mask = Sha256::digest( + [ + b"gamecult-linux-service-seed-v1\0".as_slice(), + P::PROTECTOR_CONTEXT.as_bytes(), + binding.as_bytes(), + ] + .concat(), + ); + Ok(seed.iter().zip(mask).map(|(a, b)| a ^ b).collect()) +} + +fn hex(bytes: &[u8]) -> String { + const D: &[u8; 16] = b"0123456789abcdef"; + let mut s = String::with_capacity(bytes.len() * 2); + for b in bytes { + s.push(D[(b >> 4) as usize] as char); + s.push(D[(b & 15) as usize] as char); + } + s +} + +#[cfg(test)] +mod tests { + use super::*; + enum OtherPurpose {} + impl ServiceSignaturePurpose for OtherPurpose { + const PURPOSE: &'static [u8] = b"idunn.other.v1"; + } + + #[test] + fn immutable_enrollment_reopens_and_is_purpose_and_payload_bound() -> Result<()> { + let temp = tempfile::tempdir()?; + let path = temp.path().join("idunn.ccmp"); + let signer = enroll_service_identity_at::(&path)?; + let proof = signer.sign::(b"healthy"); + let anchor = signer.trust_anchor()?; + verify_service_identity_signature::< + IdunnServiceIdentity, + IdunnAuthenticatedProviderHealthProjectionPurpose, + >(&anchor, b"healthy", &proof)?; + assert!( + verify_service_identity_signature::< + IdunnServiceIdentity, + IdunnAuthenticatedProviderHealthProjectionPurpose, + >(&anchor, b"unhealthy", &proof) + .is_err() + ); + assert!( + verify_service_identity_signature::( + &anchor, b"healthy", &proof + ) + .is_err() + ); + assert!(enroll_service_identity_at::(&path).is_err()); + assert_eq!( + derive_service_identity_id::(&anchor.public_key)?, + anchor.identity_id + ); + assert!(derive_service_identity_id::(&[0; 31]).is_err()); + assert_eq!( + open_service_identity_at::(&path)?.entry(), + signer.entry() + ); + Ok(()) + } + + #[test] + fn immutable_credential_reader_opens_without_a_path_and_retains_signing_authority() -> Result<()> + { + let temp = tempfile::tempdir()?; + let path = temp.path().join("provider-health.cc"); + let enrolled = enroll_service_identity_at::(&path)?; + let bytes = std::fs::read(path)?; + + let from_reader = open_service_identity_credential_reader::( + std::io::Cursor::new(bytes.clone()), + )?; + let from_bytes = + open_service_identity_credential_bytes::(&bytes)?; + assert_eq!(from_reader.entry(), enrolled.entry()); + assert_eq!(from_bytes.entry(), enrolled.entry()); + + let payload = b"runtime-presence"; + let proof = from_reader.sign::(payload); + verify_service_identity_signature::< + GameCultProviderHealthIdentity, + GameCultRuntimePresenceHealthPurpose, + >(&enrolled.trust_anchor()?, payload, &proof)?; + Ok(()) + } + + #[test] + fn immutable_credential_reader_rejects_ambiguous_profile_or_machine_state() -> Result<()> { + let temp = tempfile::tempdir()?; + let path = temp.path().join("idunn.ccmp"); + enroll_service_identity_at::(&path)?; + let bytes = std::fs::read(path)?; + + assert!( + open_service_identity_credential_bytes::(&bytes) + .is_err() + ); + + let mut envelopes: Vec = rmp_serde::from_slice(&bytes)?; + let mut duplicated = envelopes.clone(); + duplicated.push(envelopes[0].clone()); + assert!( + open_service_identity_credential_bytes::(&rmp_serde::to_vec( + &duplicated + )?) + .is_err() + ); + + let mut trailing = bytes.clone(); + trailing.push(0xc0); + assert!(open_service_identity_credential_bytes::(&trailing).is_err()); + + let mut wrong_seed_envelopes = envelopes.clone(); + let mut wrong_seed: ServiceIdentityPrivateEntry = + rmp_serde::from_slice(&wrong_seed_envelopes[0].payload)?; + wrong_seed.protected_private_seed[0] ^= 1; + wrong_seed_envelopes[0].payload = rmp_serde::to_vec(&wrong_seed)?; + assert!( + open_service_identity_credential_bytes::(&rmp_serde::to_vec( + &wrong_seed_envelopes + )?) + .is_err() + ); + + let mut entry: ServiceIdentityPrivateEntry = rmp_serde::from_slice(&envelopes[0].payload)?; + entry.protector_binding.push_str(":another-machine"); + envelopes[0].payload = rmp_serde::to_vec(&entry)?; + assert!( + open_service_identity_credential_bytes::(&rmp_serde::to_vec( + &envelopes + )?) + .is_err() + ); + Ok(()) + } + + #[test] + fn malformed_or_profile_substituted_state_fails_closed_without_replacement() -> Result<()> { + enum Alien {} + impl ServiceIdentityProfile for Alien { + const PRIVATE_TYPE: &'static str = "alien.private.v1"; + const PRIVATE_SCHEMA: &'static str = "alien.private.v1"; + const PRIVATE_KEY: &'static str = "alien"; + const TRUST_ANCHOR_TYPE: &'static str = "alien.anchor.v1"; + const TRUST_ANCHOR_SCHEMA: &'static str = "alien.anchor.v1"; + const TRUST_ANCHOR_KEY: &'static str = "alien-public"; + const ID_DOMAIN: &'static [u8] = b"alien.id\0"; + const SIGNATURE_DOMAIN: &'static [u8] = b"alien.sig\0"; + const PROTECTOR_CONTEXT: &'static str = "alien-v1"; + } + let temp = tempfile::tempdir()?; + let malformed = temp.path().join("bad.ccmp"); + std::fs::write(&malformed, b"rot")?; + let before = std::fs::read(&malformed)?; + assert!(open_service_identity_at::(&malformed).is_err()); + assert!(enroll_service_identity_at::(&malformed).is_err()); + assert_eq!(before, std::fs::read(&malformed)?); + let good = temp.path().join("good.ccmp"); + enroll_service_identity_at::(&good)?; + assert!(open_service_identity_at::(&good).is_err()); + Ok(()) + } + + #[test] + fn exported_anchor_is_public_only_immutable_and_rejects_identity_substitution() -> Result<()> { + let temp = tempfile::tempdir()?; + let signer = + enroll_service_identity_at::(&temp.path().join("private.ccmp"))?; + let output = temp.path().join("public.ccmp"); + let anchor = export_service_identity_trust_anchor(&signer, &output)?; + let bytes = std::fs::read(&output)?; + assert!( + !bytes + .windows(signer.entry().protected_private_seed.len()) + .any(|w| w == signer.entry().protected_private_seed) + ); + export_service_identity_trust_anchor(&signer, &output)?; + assert_eq!(bytes, std::fs::read(&output)?); + let other = + enroll_service_identity_at::(&temp.path().join("other.ccmp"))?; + let proof = other.sign::(b"healthy"); + assert!( + verify_service_identity_signature::< + IdunnServiceIdentity, + IdunnAuthenticatedProviderHealthProjectionPurpose, + >(&anchor, b"healthy", &proof) + .is_err() + ); + Ok(()) + } + + #[test] + fn provider_health_profile_is_domain_separated_and_purpose_bound() -> Result<()> { + let temp = tempfile::tempdir()?; + let signer = enroll_service_identity_at::( + &temp.path().join("provider-health.cc"), + )?; + let proof = signer.sign::(b"signed-health-record"); + let anchor = signer.trust_anchor()?; + verify_service_identity_signature::< + GameCultProviderHealthIdentity, + IdunnSignedDaemonHealthPurpose, + >(&anchor, b"signed-health-record", &proof)?; + verify_service_identity_signature_with_public_key::< + GameCultProviderHealthIdentity, + IdunnSignedDaemonHealthPurpose, + >(&anchor.public_key, b"signed-health-record", &proof)?; + assert_eq!( + anchor.schema_version, + "gamecult.provider_health_identity.trust_anchor.v1" + ); + assert_ne!( + derive_service_identity_id::(&anchor.public_key)?, + derive_service_identity_id::(&anchor.public_key)? + ); + Ok(()) + } + + #[test] + fn runtime_presence_and_legacy_health_purposes_cannot_be_substituted() -> Result<()> { + let temp = tempfile::tempdir()?; + let signer = enroll_service_identity_at::( + &temp.path().join("provider-runtime-presence.cc"), + )?; + let anchor = signer.trust_anchor()?; + let payload = b"runtime-presence"; + + let presence = signer.sign::(payload); + verify_service_identity_signature::< + GameCultProviderHealthIdentity, + GameCultRuntimePresenceHealthPurpose, + >(&anchor, payload, &presence)?; + assert!( + verify_service_identity_signature::< + GameCultProviderHealthIdentity, + IdunnSignedDaemonHealthPurpose, + >(&anchor, payload, &presence) + .is_err() + ); + + let legacy = signer.sign::(payload); + assert!( + verify_service_identity_signature::< + GameCultProviderHealthIdentity, + GameCultRuntimePresenceHealthPurpose, + >(&anchor, payload, &legacy) + .is_err() + ); + Ok(()) + } +} diff --git a/packages/cultnet-rs/src/snapshot_query.rs b/packages/cultnet-rs/src/snapshot_query.rs new file mode 100644 index 00000000..f6150d1d --- /dev/null +++ b/packages/cultnet-rs/src/snapshot_query.rs @@ -0,0 +1,339 @@ +use anyhow::{Result, anyhow}; +use std::collections::{BTreeMap, BTreeSet}; + +use crate::{CultNetDocumentRegistry, CultNetMessage, CultNetRawDocumentRecord}; + +/// Read-only backing surface for a CultNet snapshot server. +/// +/// Records returned here are already the stored wire records. The snapshot +/// server selects and clones them; it never decodes payloads, rewrites source +/// metadata, or applies them to another cache. +pub trait CultNetRawSnapshotSource { + fn raw_snapshot(&self) -> Result>; +} + +impl CultNetRawSnapshotSource for Vec { + fn raw_snapshot(&self) -> Result> { + Ok(self.clone()) + } +} + +impl CultNetRawSnapshotSource for F +where + F: Fn() -> Result>, +{ + fn raw_snapshot(&self) -> Result> { + self() + } +} + +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct CultNetReadOnlySnapshotPolicy { + allowed_records: BTreeSet<(String, String)>, +} + +impl CultNetReadOnlySnapshotPolicy { + pub fn new() -> Self { + Self::default() + } + + pub fn allow( + &mut self, + schema_id: impl Into, + record_key: impl Into, + ) -> Result<&mut Self> { + let schema_id = schema_id.into(); + let record_key = record_key.into(); + require_non_empty(&schema_id, "schema_id")?; + require_non_empty(&record_key, "record_key")?; + self.allowed_records.insert((schema_id, record_key)); + Ok(self) + } + + fn allows(&self, schema_id: &str, record_key: &str) -> bool { + self.allowed_records + .contains(&(schema_id.to_string(), record_key.to_string())) + } +} + +/// Serve one raw snapshot request from an explicitly bounded, read-only view. +/// +/// The document registry proves that every exposed schema belongs to the +/// runtime. The policy grants individual `(schema_id, record_key)` pairs. The +/// source owns the bytes and metadata; this function only selects records. +pub fn serve_read_only_raw_snapshot( + document_registry: &CultNetDocumentRegistry, + policy: &CultNetReadOnlySnapshotPolicy, + source: &S, + request: &CultNetMessage, +) -> Result { + let CultNetMessage::SnapshotRequest { + message_id, + schema_ids, + record_keys, + } = request + else { + return Err(anyhow!("expected cultnet.snapshot_request.v0")); + }; + require_non_empty(message_id, "message_id")?; + reject_duplicates(schema_ids.as_deref(), "requested schema id")?; + reject_duplicates(record_keys.as_deref(), "requested record key")?; + + let requested_schemas = schema_ids + .as_ref() + .map(|values| values.iter().map(String::as_str).collect::>()); + let requested_keys = record_keys + .as_ref() + .map(|values| values.iter().map(String::as_str).collect::>()); + let mut selected = Vec::new(); + let mut seen = BTreeSet::new(); + + for document in source.raw_snapshot()? { + let identity = (document.schema_id.clone(), document.record_key.clone()); + if !seen.insert(identity.clone()) { + return Err(anyhow!( + "snapshot source contains duplicate record {:?}/{:?}", + identity.0, + identity.1 + )); + } + if document_registry + .binding_by_schema_id(&document.schema_id) + .is_none() + { + return Err(anyhow!( + "snapshot source record {:?}/{:?} uses an unregistered schema", + document.schema_id, + document.record_key + )); + } + if !policy.allows(&document.schema_id, &document.record_key) { + continue; + } + if requested_schemas + .as_ref() + .is_some_and(|schemas| !schemas.contains(document.schema_id.as_str())) + { + continue; + } + if requested_keys + .as_ref() + .is_some_and(|keys| !keys.contains(document.record_key.as_str())) + { + continue; + } + selected.push(document); + } + + Ok(CultNetMessage::SnapshotResponseRaw { + message_id: message_id.clone(), + documents: selected, + }) +} + +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct CultNetSnapshotSourceExpectation { + pub runtime_id: Option, + pub agent_id: Option, + pub role: Option, + pub tags: Option>, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CultNetSnapshotRecordExpectation { + pub schema_id: String, + pub record_key: String, + pub source: CultNetSnapshotSourceExpectation, +} + +impl CultNetSnapshotRecordExpectation { + pub fn new(schema_id: impl Into, record_key: impl Into) -> Self { + Self { + schema_id: schema_id.into(), + record_key: record_key.into(), + source: CultNetSnapshotSourceExpectation::default(), + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CultNetRawSnapshotQuery { + message_id: String, + expectations: BTreeMap<(String, String), CultNetSnapshotSourceExpectation>, +} + +impl CultNetRawSnapshotQuery { + pub fn new( + message_id: impl Into, + records: Vec, + ) -> Result { + let message_id = message_id.into(); + require_non_empty(&message_id, "message_id")?; + if records.is_empty() { + return Err(anyhow!("snapshot query must request at least one record")); + } + let mut expectations = BTreeMap::new(); + for record in records { + require_non_empty(&record.schema_id, "schema_id")?; + require_non_empty(&record.record_key, "record_key")?; + let identity = (record.schema_id, record.record_key); + if expectations + .insert(identity.clone(), record.source) + .is_some() + { + return Err(anyhow!( + "snapshot query contains duplicate requested record {:?}/{:?}", + identity.0, + identity.1 + )); + } + } + Ok(Self { + message_id, + expectations, + }) + } + + pub fn request(&self) -> CultNetMessage { + CultNetMessage::SnapshotRequest { + message_id: self.message_id.clone(), + schema_ids: Some( + self.expectations + .keys() + .map(|(schema_id, _)| schema_id.clone()) + .collect::>() + .into_iter() + .collect(), + ), + record_keys: Some( + self.expectations + .keys() + .map(|(_, record_key)| record_key.clone()) + .collect::>() + .into_iter() + .collect(), + ), + } + } + + /// Validate a response and return records without mutating any local cache. + pub fn accept_response( + &self, + response: CultNetMessage, + ) -> Result> { + let CultNetMessage::SnapshotResponseRaw { + message_id, + documents, + } = response + else { + return Err(anyhow!("expected cultnet.snapshot_response_raw.v0")); + }; + if message_id != self.message_id { + return Err(anyhow!( + "snapshot response message id {:?} does not match request {:?}", + message_id, + self.message_id + )); + } + + let mut seen = BTreeSet::new(); + for document in &documents { + let identity = (document.schema_id.clone(), document.record_key.clone()); + if !seen.insert(identity.clone()) { + return Err(anyhow!( + "snapshot response contains duplicate record {:?}/{:?}", + identity.0, + identity.1 + )); + } + let expected = self.expectations.get(&identity).ok_or_else(|| { + anyhow!( + "snapshot response contains unexpected record {:?}/{:?}", + identity.0, + identity.1 + ) + })?; + require_expected_metadata( + "source_runtime_id", + expected.runtime_id.as_deref(), + document.source_runtime_id.as_deref(), + &identity, + )?; + require_expected_metadata( + "source_agent_id", + expected.agent_id.as_deref(), + document.source_agent_id.as_deref(), + &identity, + )?; + require_expected_metadata( + "source_role", + expected.role.as_deref(), + document.source_role.as_deref(), + &identity, + )?; + if let Some(expected_tags) = expected.tags.as_ref() + && document.tags.as_ref() != Some(expected_tags) + { + return Err(anyhow!( + "snapshot response record {:?}/{:?} has unexpected tags: expected {:?}, got {:?}", + identity.0, + identity.1, + expected_tags, + document.tags + )); + } + } + Ok(documents) + } +} + +pub fn query_read_only_raw_snapshot( + query: &CultNetRawSnapshotQuery, + exchange: F, +) -> Result> +where + F: FnOnce(CultNetMessage) -> Result, +{ + query.accept_response(exchange(query.request())?) +} + +fn require_expected_metadata( + field: &str, + expected: Option<&str>, + actual: Option<&str>, + identity: &(String, String), +) -> Result<()> { + if let Some(expected) = expected + && actual != Some(expected) + { + return Err(anyhow!( + "snapshot response record {:?}/{:?} has unexpected {field}: expected {:?}, got {:?}", + identity.0, + identity.1, + expected, + actual + )); + } + Ok(()) +} + +fn reject_duplicates(values: Option<&[String]>, label: &str) -> Result<()> { + let Some(values) = values else { + return Ok(()); + }; + let mut seen = BTreeSet::new(); + for value in values { + require_non_empty(value, label)?; + if !seen.insert(value) { + return Err(anyhow!("duplicate {label} {value:?}")); + } + } + Ok(()) +} + +fn require_non_empty(value: &str, field: &str) -> Result<()> { + if value.trim().is_empty() { + return Err(anyhow!("{field} must be non-empty")); + } + Ok(()) +} From 67cbb4ea36b1c9952e7e3408e1bbb57267f5325f Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 3 Sep 2026 23:09:45 +0200 Subject: [PATCH 126/283] Give the Rust CultMesh runtime a home The only Rust CultMesh implementation in existence was 1,363 lines inside Ghostlight's vendor directory. It was in no library repo and no standalone repo, so it had never been checked against the browser, Kotlin, and TypeScript CultMesh bodies it must interoperate with. It is not a duplicate of the facade in cultnet-rs. That one is the small surface the parity table claims for Rust: peer cards, authority leases, endpoint parsing. This is the stream and session layer -- node, document sets, RUDP document publication, stream descriptors, negotiation, stream catalog, and shared-memory frame rings -- which the same table lists under Rust's "Not claimed". A consumer grew the unclaimed surface because there was nowhere else to put it. Its path dependencies already matched this layout and it builds against CultLib's cultnet-rs unchanged, so it does not depend on the forked RUDP extras. Seven runtime-local tests pass, and CI now runs them. The parity table gains no claim from this. The Rust row says plainly that no interop lane exercises the stream surface, and expansion work records that runtime-local tests are not a parity claim. Landing code is not evidence. packages/cultmesh-rs needed an explicit .gitignore re-include; the NuGet packages rule hides every language package until one is added by name. Co-Authored-By: Claude Opus 5 --- .github/workflows/cultnet-interop.yml | 3 + .gitignore | 2 + docs/runtime-parity-scope.md | 6 +- packages/cultmesh-rs/Cargo.lock | 1183 +++++++++++++++++++++ packages/cultmesh-rs/Cargo.toml | 20 + packages/cultmesh-rs/src/lib.rs | 1363 +++++++++++++++++++++++++ 6 files changed, 2576 insertions(+), 1 deletion(-) create mode 100644 packages/cultmesh-rs/Cargo.lock create mode 100644 packages/cultmesh-rs/Cargo.toml create mode 100644 packages/cultmesh-rs/src/lib.rs diff --git a/.github/workflows/cultnet-interop.yml b/.github/workflows/cultnet-interop.yml index 33699446..3437add3 100644 --- a/.github/workflows/cultnet-interop.yml +++ b/.github/workflows/cultnet-interop.yml @@ -92,6 +92,9 @@ jobs: - name: Verify Rust RUDP reliability run: cargo test --manifest-path packages/cultnet-rs/Cargo.toml rudp + - name: Verify Rust CultMesh runtime-local surface + run: cargo test --manifest-path packages/cultmesh-rs/Cargo.toml + - name: Verify C# RUDP reliability run: dotnet test tests/GameCult.Networking.Tests/GameCult.Networking.Tests.csproj --filter "FullyQualifiedName~Rudp" diff --git a/.gitignore b/.gitignore index d639c709..ce48c2dc 100644 --- a/.gitignore +++ b/.gitignore @@ -307,6 +307,8 @@ node_modules/ !packages/cultcache-rs/** !packages/cultnet-rs/ !packages/cultnet-rs/** +!packages/cultmesh-rs/ +!packages/cultmesh-rs/** packages/**/node_modules/ packages/**/dist/ packages/**/dist-test/ diff --git a/docs/runtime-parity-scope.md b/docs/runtime-parity-scope.md index cd3761d7..681f1ad3 100644 --- a/docs/runtime-parity-scope.md +++ b/docs/runtime-parity-scope.md @@ -33,7 +33,7 @@ CultMesh. | C# | Reference implementation and production game/server substrate | CultCache typed documents and SoA, CultNet schema-v0, LiteNetLib production path with adapter profile, shared transport profiles, shared RUDP socket transport, C# multi-peer RUDP listener and schema service host, C# interop RUDP serve/dial path, connected RUDP CultMesh client helpers, RUDP-backed schema-client selection for `rudp://` service endpoints, RUDP reconnect policy/controller and reconnect-loop helper, LiteNetLib client reconnect-controller adoption, schema-client transport port for service request/response clients, CultMesh node/session/catalog/stream/simulation/RUDP surfaces, authorized peer lookup | No need to abandon LiteNetLib before the CultNet adapter fully owns production service adoption | | Python | Package runtime, local daemon endpoint, raw interop peer, typed state participant | CultCache/CultNet/CultMesh package surface, branded CultMesh node/schema/shard/Verse/peer/authority/stream/RUDP ergonomics, authorized peer lookup, shard catalogs/logs, schema-transport factory for raw client request/subscription flows, local TCP and RUDP CultMesh server listeners, Python interop RUDP serve/dial path, session/prediction/simulation fact helpers, RUDP codec/session/socket transport, RUDP reconnect policy/controller and reconnect-loop helper, schema-v0 MessagePack over RUDP evidence, benchmark evidence against C# cache paths | Universal C# throughput, full C# daemon/server stack, and RUDP as the only public service pipe | | TypeScript | Node/browser-adjacent projection and interop runtime | CultCache parity tests, CultNet schema-v0 peer, advertised schema/shard catalog wire contracts plus request/sync helpers, transport profiles, TCP-framed transport port and peer helper, shared RUDP socket transport, RUDP interop serve/dial path, RUDP reconnect policy/controller, RUDP reconnect-loop helper, branded CultMesh node/schema/shard/Verse/peer/authority/stream/RUDP ergonomics, authorized peer lookup | Full C# game session/server stack | -| Rust | Low-level cache/transport/runtime substrate | CultCache/CultNet interop lane, schema and shard catalog helpers, typed same-schema alias hydration from raw snapshots, transport profiles, TCP-framed port, shared RUDP codec/session/socket transport, Rust interop RUDP serve/dial path, connected RUDP CultMesh client helpers, RUDP reconnect policy/controller and reconnect-loop helper, schema-v0 MessagePack over RUDP evidence, small CultMesh facade for schema registry, shard catalog, peer cards, authority leases, authorized peer lookup, RUDP endpoint parsing, and peer-card/authorized-peer RUDP client construction | Full CultMesh game-session/server facade, stream catalog, or production game-session server | +| Rust | Low-level cache/transport/runtime substrate | CultCache/CultNet interop lane, schema and shard catalog helpers, typed same-schema alias hydration from raw snapshots, transport profiles, TCP-framed port, shared RUDP codec/session/socket transport, Rust interop RUDP serve/dial path, connected RUDP CultMesh client helpers, RUDP reconnect policy/controller and reconnect-loop helper, schema-v0 MessagePack over RUDP evidence, small CultMesh facade for schema registry, shard catalog, peer cards, authority leases, authorized peer lookup, RUDP endpoint parsing, and peer-card/authorized-peer RUDP client construction | Full CultMesh game-session/server facade or production game-session server. `packages/cultmesh-rs` now holds a Rust stream and session surface -- node, document sets, RUDP document publication, stream descriptors, negotiation, stream catalog, and shared-memory frame rings -- but no interop lane exercises it, so it carries no cross-runtime parity claim | | Kotlin | JVM/Android client substrate | Typed MessagePack cache, one-call typed snapshot document sync through local same-schema aliases, built-in schema catalog advertisement, schema/shard catalogs with shared schema-message transport fetch/sync helpers, authority leases, authorized peer lookup, stream catalog, branded `CultMesh` facade, WebSocket transport profile/connection helper, RUDP client/server sugar, connected RUDP CultMesh client helpers, Kotlin interop RUDP serve/dial path, RUDP reconnect policy/controller and reconnect-loop helper, schema-v0 MessagePack over RUDP evidence | C# SoA store, full C# server daemon, or Unity hot-loop memory layout | ## Evidence Gates @@ -85,6 +85,10 @@ server body, is deliberately not made. backfilling C# server responsibilities it should not own. Kotlin WebSocket and RUDP adapters now share one `CultNetSchemaMessageTransport` helper shape for schema/shard catalog request and sync flows. +- Bring `packages/cultmesh-rs` under the wire claim. It arrived from a consumer repo where it grew + outside any conformance harness, and its stream, negotiation, and shared-memory frame-ring + surfaces have never been checked against the browser, Kotlin, and TypeScript CultMesh bodies + they must interoperate with. Runtime-local tests pass; that is not a parity claim. - Keep performance claims evidence-bound: C# owns SoA; Python has benchmark comparison gates; other runtimes should advertise measured native hot paths only when those paths exist. diff --git a/packages/cultmesh-rs/Cargo.lock b/packages/cultmesh-rs/Cargo.lock new file mode 100644 index 00000000..c515ded2 --- /dev/null +++ b/packages/cultmesh-rs/Cargo.lock @@ -0,0 +1,1183 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "android_system_properties" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bitflags" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "cc" +version = "1.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ad534f4357a5264cce5019c989cf66a4f0dc4e0d1b1d15f8aacec0ff7360273" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "typenum", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "cultcache-rs" +version = "0.1.0" +dependencies = [ + "anyhow", + "chrono", + "cultcache-rs-derive", + "fs2", + "redb", + "rmp-serde", + "serde", + "serde_bytes", + "serde_json", + "uuid", + "windows-sys 0.59.0", +] + +[[package]] +name = "cultcache-rs-derive" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "cultmesh-rs" +version = "0.1.0" +dependencies = [ + "anyhow", + "cultcache-rs", + "cultnet-rs", + "pretty_assertions", + "rmp-serde", + "serde", + "tempfile", +] + +[[package]] +name = "cultnet-rs" +version = "0.1.0" +dependencies = [ + "aes-gcm", + "anyhow", + "base64", + "chrono", + "cultcache-rs", + "ed25519-dalek", + "hmac", + "rand", + "rmp-serde", + "rmpv", + "serde", + "serde_bytes", + "serde_json", + "sha2", + "socket2", + "uuid", + "windows-sys 0.61.2", + "zeroize", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +dependencies = [ + "curve25519-dalek", + "ed25519", + "serde", + "sha2", + "subtle", + "zeroize", +] + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "fastrand" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "find-msvc-tools" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d45db016d36b838f563236e9193d0ee6ce38f3f68b6c94e914b4929c96bbb890" + +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "futures-core" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" + +[[package]] +name = "futures-task" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" + +[[package]] +name = "futures-util" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", +] + +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "js-sys" +version = "0.3.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0c1080212aad755ea003d18543e8768dd432c48819efd73a7bf1e39b7a5a3a" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "log" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "pretty_assertions" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" +dependencies = [ + "diff", + "yansi", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" +dependencies = [ + "rand_chacha", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "redb" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de6c3b63e007e90ce536ec2ae4690826136a20ec8dbbbb400daef1bb999d2e36" +dependencies = [ + "libc", +] + +[[package]] +name = "rmp" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ba8be72d372b2c9b35542551678538b562e7cf86c3315773cae48dfbfe7790c" +dependencies = [ + "num-traits", +] + +[[package]] +name = "rmp-serde" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f81bee8c8ef9b577d1681a70ebbc962c232461e397b22c208c43c04b67a155" +dependencies = [ + "rmp", + "serde", +] + +[[package]] +name = "rmpv" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a4e1d4b9b938a26d2996af33229f0ca0956c652c1375067f0b45291c1df8417" +dependencies = [ + "rmp", + "serde", + "serde_bytes", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.4", +] + +[[package]] +name = "serde_json" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6275cddf4610d1775e6d1fe9469b2e77d0f39fd98fb7450901b821e0c53649f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.4.3", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "uuid" +version = "1.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5772d71c9be8a8a6ac2117d949c5b224c1b72241bb611d9a3012edcf8af7812" +dependencies = [ + "getrandom 0.4.3", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b70935747edd64d89de3efa29d73789b806c15798f8e7dca4d8ac356b50ce70" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77775f8f3f7217702089053b94958f8f54061a3f663417df76e19cbdcca29bc1" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e11d33f857dc2fb11b8bc75aee111aa9cbeb12cd9f25efd3d4c2a3dd4e235284" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.119", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef64dbcc55df09c7e5a46182d181c2cfa3e925f3da937ea764728b4bbb9dcbf" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + +[[package]] +name = "zerocopy" +version = "0.8.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556764e583adb45a9f8d413c2a147fa7e8d821e48e12b14fd560b607998b75eb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ab42fc20575779bd240faa45f94a74256f755c0fa9e89f0ede20d91d0cdfc1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zeroize" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/packages/cultmesh-rs/Cargo.toml b/packages/cultmesh-rs/Cargo.toml new file mode 100644 index 00000000..9a719d32 --- /dev/null +++ b/packages/cultmesh-rs/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "cultmesh-rs" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +name = "cultmesh_rs" +path = "src/lib.rs" + +[dependencies] +anyhow = "1" +cultcache-rs = { path = "../cultcache-rs" } +cultnet-rs = { path = "../cultnet-rs" } +serde = { version = "1", features = ["derive"] } + +[dev-dependencies] +pretty_assertions = "1.4.1" +rmp-serde = "1" +tempfile = "3" diff --git a/packages/cultmesh-rs/src/lib.rs b/packages/cultmesh-rs/src/lib.rs new file mode 100644 index 00000000..5adbb53f --- /dev/null +++ b/packages/cultmesh-rs/src/lib.rs @@ -0,0 +1,1363 @@ +use anyhow::{Context, Result}; +use cultcache_rs::CultCache; +use cultcache_rs::CultCacheEnvelope; +use cultcache_rs::DatabaseEntry; +use cultcache_rs::SingleFileMessagePackBackingStore; +use cultnet_rs::CultNetDocumentPutOptions; +use cultnet_rs::CultNetDocumentRegistry; +use cultnet_rs::CultNetRudpSocketTransportConnection; +use cultnet_rs::CultNetRudpSocketTransportOptions; +use cultnet_rs::CultNetWireContract; +use cultnet_rs::decode_cultnet_message_from_slice; +use cultnet_rs::encode_cultnet_message_to_vec; +use serde::Serialize; +use std::collections::BTreeMap; +use std::env; +use std::net::SocketAddr; +use std::net::UdpSocket; +use std::path::Path; +use std::thread; +use std::time::Duration; +use std::time::Instant; + +pub const CULTMESH_RUDP_DOCUMENT_CATALOG_CONNECTION_ID: u32 = 0x0d1d_0002; + +pub trait CultMeshDocumentSet: Clone + Send + Sync + 'static { + fn register_cache(&self, cache: &mut CultCache) -> Result<()>; + fn register_documents(&self, registry: &mut CultNetDocumentRegistry) -> Result<()>; +} + +#[macro_export] +macro_rules! cultmesh_documents { + ($name:ident { $($entry:ty => $schema_version:expr),* $(,)? }) => { + #[derive(Clone, Copy, Debug, Default)] + pub struct $name; + + impl $crate::CultMeshDocumentSet for $name { + fn register_cache( + &self, + cache: &mut cultcache_rs::CultCache, + ) -> ::anyhow::Result<()> { + $( + cache.register_entry_type::<$entry>()?; + )* + Ok(()) + } + + fn register_documents( + &self, + registry: &mut cultnet_rs::CultNetDocumentRegistry, + ) -> ::anyhow::Result<()> { + $( + registry.register( + cultnet_rs::CultNetDocumentBinding::for_entry_with_schema_id::<$entry>( + $schema_version.to_string(), + $schema_version.to_string(), + ), + ); + )* + Ok(()) + } + } + }; +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CultMeshNodeOptions { + pub runtime_id: String, + pub pull_on_start: bool, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CultMeshRudpDocumentPublishOptions { + pub target: SocketAddr, + pub runtime_id: String, + pub connection_id: u32, + pub connect_timeout: Duration, + pub flush_timeout: Duration, + pub poll_interval: Duration, + pub resend_delay_ms: u64, + pub source_agent_id: Option, + pub source_role: Option, + pub tags: Vec, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CultMeshRudpSnapshotOptions { + pub target: SocketAddr, + pub runtime_id: String, + pub connection_id: u32, + pub connect_timeout: Duration, + pub response_timeout: Duration, + pub poll_interval: Duration, + pub resend_delay_ms: u64, + pub schema_ids: Option>, + pub record_keys: Option>, +} + +impl CultMeshRudpSnapshotOptions { + pub fn odin(target: SocketAddr, runtime_id: impl Into) -> Self { + Self { + target, + runtime_id: runtime_id.into(), + ..Self::default() + } + } +} + +impl Default for CultMeshRudpSnapshotOptions { + fn default() -> Self { + Self { + target: SocketAddr::from(([0, 0, 0, 0], 0)), + runtime_id: "cultmesh-rudp-snapshot-client".to_string(), + connection_id: CULTMESH_RUDP_DOCUMENT_CATALOG_CONNECTION_ID, + connect_timeout: Duration::from_secs(3), + response_timeout: Duration::from_secs(3), + poll_interval: Duration::from_millis(10), + resend_delay_ms: 50, + schema_ids: None, + record_keys: None, + } + } +} + +impl CultMeshRudpDocumentPublishOptions { + pub fn odin(target: SocketAddr, runtime_id: impl Into) -> Self { + Self { + target, + runtime_id: runtime_id.into(), + ..Self::default() + } + } +} + +impl Default for CultMeshRudpDocumentPublishOptions { + fn default() -> Self { + Self { + target: SocketAddr::from(([0, 0, 0, 0], 0)), + runtime_id: "cultmesh-rudp-document-publisher".to_string(), + connection_id: CULTMESH_RUDP_DOCUMENT_CATALOG_CONNECTION_ID, + connect_timeout: Duration::from_secs(3), + flush_timeout: Duration::from_secs(30), + poll_interval: Duration::from_millis(10), + resend_delay_ms: 50, + source_agent_id: None, + source_role: None, + tags: Vec::new(), + } + } +} + +impl Default for CultMeshNodeOptions { + fn default() -> Self { + Self { + runtime_id: "cultmesh-local".to_string(), + pull_on_start: true, + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CultMeshRudpEndpoint { + pub host: String, + pub port: u16, + pub addr: SocketAddr, +} + +pub struct CultMeshNode { + runtime_id: String, + cache: CultCache, + documents: CultNetDocumentRegistry, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum CultMeshStreamKind { + Audio, + Video, + Tensor, + Bytes, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum CultMeshStreamBodyTransport { + SharedMemory, + SharedD3d12Texture, + SharedD3d11Texture, + DmaBuf, + IoSurface, + AHardwareBuffer, + CultCachePage, + InlineBytes, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum CultMeshStreamAccess { + Read, + Write, + ReadWrite, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum CultMeshStreamCopyBudget { + ZeroCopyTarget, + OneCopyFallback, + OpaqueRuntime, +} + +#[derive(Clone, Debug, PartialEq)] +pub struct CultMeshStreamClock { + pub clock_domain_id: String, + pub source_id: Option, + pub sample_rate: i32, + pub offset_to_verse_time_ns: i64, + pub confidence: f64, + pub evidence_kind: Option, +} + +impl CultMeshStreamClock { + pub fn new(clock_domain_id: impl Into) -> Result { + let clock_domain_id = require_non_empty(clock_domain_id.into(), "clock_domain_id")?; + Ok(Self { + clock_domain_id, + source_id: None, + sample_rate: 0, + offset_to_verse_time_ns: 0, + confidence: 0.0, + evidence_kind: None, + }) + } + + pub fn source_id(mut self, source_id: impl Into) -> Result { + self.source_id = Some(require_non_empty(source_id.into(), "source_id")?); + Ok(self) + } + + pub fn confidence(mut self, confidence: f64) -> Self { + self.confidence = confidence; + self + } + + pub fn evidence_kind(mut self, evidence_kind: impl Into) -> Result { + self.evidence_kind = Some(require_non_empty(evidence_kind.into(), "evidence_kind")?); + Ok(self) + } +} + +#[derive(Clone, Debug, PartialEq)] +pub struct CultMeshStreamDescriptor { + pub stream_id: String, + pub verse_id: String, + pub owner_peer_id: String, + pub kind: CultMeshStreamKind, + pub clock: CultMeshStreamClock, + pub preferred_transports: Vec, + pub label: Option, + pub required_access: CultMeshStreamAccess, + pub max_in_flight_frames: u32, + pub metadata_schema_id: Option, +} + +impl CultMeshStreamDescriptor { + pub fn new( + stream_id: impl Into, + verse_id: impl Into, + owner_peer_id: impl Into, + kind: CultMeshStreamKind, + clock: CultMeshStreamClock, + preferred_transports: Vec, + ) -> Result { + if preferred_transports.is_empty() { + anyhow::bail!("preferred_transports must not be empty"); + } + Ok(Self { + stream_id: require_non_empty(stream_id.into(), "stream_id")?, + verse_id: require_non_empty(verse_id.into(), "verse_id")?, + owner_peer_id: require_non_empty(owner_peer_id.into(), "owner_peer_id")?, + kind, + clock, + preferred_transports, + label: None, + required_access: CultMeshStreamAccess::Read, + max_in_flight_frames: 0, + metadata_schema_id: None, + }) + } + + pub fn label(mut self, label: impl Into) -> Result { + self.label = Some(require_non_empty(label.into(), "label")?); + Ok(self) + } + + pub fn max_in_flight_frames(mut self, max_in_flight_frames: u32) -> Self { + self.max_in_flight_frames = max_in_flight_frames; + self + } + + pub fn metadata_schema_id(mut self, metadata_schema_id: impl Into) -> Result { + self.metadata_schema_id = Some(require_non_empty( + metadata_schema_id.into(), + "metadata_schema_id", + )?); + Ok(self) + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CultMeshStreamConsumerProfile { + pub peer_id: String, + pub verse_id: String, + pub supported_transports: Vec, + pub accepted_kinds: Vec, + pub max_in_flight_frames: u32, +} + +impl CultMeshStreamConsumerProfile { + pub fn new( + peer_id: impl Into, + verse_id: impl Into, + supported_transports: Vec, + ) -> Result { + if supported_transports.is_empty() { + anyhow::bail!("supported_transports must not be empty"); + } + Ok(Self { + peer_id: require_non_empty(peer_id.into(), "peer_id")?, + verse_id: require_non_empty(verse_id.into(), "verse_id")?, + supported_transports, + accepted_kinds: Vec::new(), + max_in_flight_frames: 0, + }) + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CultMeshStreamNegotiation { + pub stream_id: String, + pub producer_peer_id: String, + pub consumer_peer_id: String, + pub transport: CultMeshStreamBodyTransport, + pub access: CultMeshStreamAccess, + pub max_in_flight_frames: u32, + pub copy_budget: CultMeshStreamCopyBudget, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CultMeshStreamFrameHandle { + pub stream_id: String, + pub sequence: u64, + pub timestamp_ns: i64, + pub duration_ns: i64, + pub transport: CultMeshStreamBodyTransport, + pub byte_length: usize, + pub resource_key: Option, + pub unavoidable_copy_count: u32, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CultMeshSharedMemoryFrameRingStats { + pub stream_id: String, + pub slot_count: usize, + pub slot_byte_length: usize, + pub published_frames: u64, + pub dropped_frames: u64, + pub blocked_writes: u64, + pub latest_sequence: u64, + pub unavoidable_copy_count: u64, +} + +pub struct CultMeshFrameReadLease<'a> { + pub handle: CultMeshStreamFrameHandle, + bytes: &'a [u8], +} + +impl CultMeshFrameReadLease<'_> { + pub fn bytes(&self) -> &[u8] { + self.bytes + } +} + +#[derive(Clone, Debug)] +pub struct CultMeshSharedMemoryFrameRing { + stream_id: String, + slot_byte_length: usize, + slots: Vec)>>, + write_cursor: usize, + latest_slot: Option, + next_sequence: u64, + published_frames: u64, + dropped_frames: u64, + blocked_writes: u64, + unavoidable_copy_count: u64, +} + +impl CultMeshSharedMemoryFrameRing { + pub fn new( + stream_id: impl Into, + slot_count: usize, + slot_byte_length: usize, + ) -> Result { + let stream_id = require_non_empty(stream_id.into(), "stream_id")?; + if slot_count == 0 { + anyhow::bail!("slot_count must be greater than zero"); + } + if slot_byte_length == 0 { + anyhow::bail!("slot_byte_length must be greater than zero"); + } + Ok(Self { + stream_id, + slot_byte_length, + slots: vec![None; slot_count], + write_cursor: 0, + latest_slot: None, + next_sequence: 0, + published_frames: 0, + dropped_frames: 0, + blocked_writes: 0, + unavoidable_copy_count: 0, + }) + } + + pub fn try_publish_copy( + &mut self, + bytes: &[u8], + timestamp_ns: i64, + duration_ns: i64, + ) -> Result> { + if bytes.len() > self.slot_byte_length { + anyhow::bail!("frame byte length exceeds slot size"); + } + if self.slots.is_empty() { + self.blocked_writes += 1; + return Ok(None); + } + + let slot_index = self.write_cursor; + if self.slots[slot_index].is_some() { + self.dropped_frames += 1; + } + let handle = CultMeshStreamFrameHandle { + stream_id: self.stream_id.clone(), + sequence: self.next_sequence, + timestamp_ns, + duration_ns, + transport: CultMeshStreamBodyTransport::SharedMemory, + byte_length: bytes.len(), + resource_key: Some(format!("{}:slot:{slot_index}", self.stream_id)), + unavoidable_copy_count: 1, + }; + self.slots[slot_index] = Some((handle.clone(), bytes.to_vec())); + self.latest_slot = Some(slot_index); + self.write_cursor = (slot_index + 1) % self.slots.len(); + self.next_sequence = self.next_sequence.saturating_add(1); + self.published_frames = self.published_frames.saturating_add(1); + self.unavoidable_copy_count = self.unavoidable_copy_count.saturating_add(1); + Ok(Some(handle)) + } + + pub fn try_acquire_latest_read(&self) -> Option> { + let slot_index = self.latest_slot?; + let (handle, bytes) = self.slots[slot_index].as_ref()?; + Some(CultMeshFrameReadLease { + handle: handle.clone(), + bytes, + }) + } + + pub fn stats(&self) -> CultMeshSharedMemoryFrameRingStats { + let latest_sequence = self + .latest_slot + .and_then(|slot| self.slots[slot].as_ref().map(|(handle, _)| handle.sequence)) + .unwrap_or(0); + CultMeshSharedMemoryFrameRingStats { + stream_id: self.stream_id.clone(), + slot_count: self.slots.len(), + slot_byte_length: self.slot_byte_length, + published_frames: self.published_frames, + dropped_frames: self.dropped_frames, + blocked_writes: self.blocked_writes, + latest_sequence, + unavoidable_copy_count: self.unavoidable_copy_count, + } + } +} + +#[derive(Clone, Debug, Default)] +pub struct CultMeshStreamCatalog { + streams: BTreeMap, + latest_frames: BTreeMap, + rings: BTreeMap, +} + +impl CultMeshStreamCatalog { + pub fn declare(&mut self, stream: CultMeshStreamDescriptor) { + self.streams.insert(stream.stream_id.clone(), stream); + } + + pub fn get(&self, stream_id: &str) -> Option<&CultMeshStreamDescriptor> { + self.streams.get(stream_id) + } + + pub fn streams(&self) -> Vec<&CultMeshStreamDescriptor> { + self.streams.values().collect() + } + + pub fn find( + &self, + verse_id: &str, + kind: Option, + ) -> Vec<&CultMeshStreamDescriptor> { + self.streams + .values() + .filter(|stream| stream.verse_id == verse_id && kind.is_none_or(|k| stream.kind == k)) + .collect() + } + + pub fn negotiate( + &self, + stream_id: &str, + consumer: &CultMeshStreamConsumerProfile, + ) -> Result { + let stream = self + .streams + .get(stream_id) + .ok_or_else(|| anyhow::anyhow!("unknown CultMesh stream '{stream_id}'"))?; + if stream.verse_id != consumer.verse_id { + anyhow::bail!("stream and consumer must belong to the same Verse"); + } + if !consumer.accepted_kinds.is_empty() && !consumer.accepted_kinds.contains(&stream.kind) { + anyhow::bail!("consumer does not accept stream kind"); + } + let transport = stream + .preferred_transports + .iter() + .copied() + .find(|candidate| consumer.supported_transports.contains(candidate)) + .ok_or_else(|| { + anyhow::anyhow!("stream and consumer have no compatible body transport") + })?; + let producer_max = if stream.max_in_flight_frames == 0 { + u32::MAX + } else { + stream.max_in_flight_frames + }; + let consumer_max = if consumer.max_in_flight_frames == 0 { + u32::MAX + } else { + consumer.max_in_flight_frames + }; + Ok(CultMeshStreamNegotiation { + stream_id: stream.stream_id.clone(), + producer_peer_id: stream.owner_peer_id.clone(), + consumer_peer_id: consumer.peer_id.clone(), + transport, + access: stream.required_access, + max_in_flight_frames: producer_max.min(consumer_max), + copy_budget: copy_budget_for(transport), + }) + } + + pub fn create_shared_memory_ring( + &mut self, + stream_id: &str, + slot_count: usize, + slot_byte_length: usize, + ) -> Result<&mut CultMeshSharedMemoryFrameRing> { + if !self.streams.contains_key(stream_id) { + anyhow::bail!("unknown CultMesh stream '{stream_id}'"); + } + self.rings.insert( + stream_id.to_string(), + CultMeshSharedMemoryFrameRing::new(stream_id, slot_count, slot_byte_length)?, + ); + Ok(self + .rings + .get_mut(stream_id) + .expect("ring was inserted for stream")) + } + + pub fn ring(&self, stream_id: &str) -> Option<&CultMeshSharedMemoryFrameRing> { + self.rings.get(stream_id) + } + + pub fn ring_mut(&mut self, stream_id: &str) -> Option<&mut CultMeshSharedMemoryFrameRing> { + self.rings.get_mut(stream_id) + } + + pub fn publish_frame(&mut self, handle: CultMeshStreamFrameHandle) -> Result<()> { + if !self.streams.contains_key(&handle.stream_id) { + anyhow::bail!("unknown CultMesh stream '{}'", handle.stream_id); + } + self.latest_frames.insert(handle.stream_id.clone(), handle); + Ok(()) + } + + pub fn latest_frame(&self, stream_id: &str) -> Option<&CultMeshStreamFrameHandle> { + self.latest_frames.get(stream_id) + } +} + +fn copy_budget_for(transport: CultMeshStreamBodyTransport) -> CultMeshStreamCopyBudget { + match transport { + CultMeshStreamBodyTransport::SharedMemory + | CultMeshStreamBodyTransport::SharedD3d12Texture + | CultMeshStreamBodyTransport::SharedD3d11Texture + | CultMeshStreamBodyTransport::DmaBuf + | CultMeshStreamBodyTransport::IoSurface + | CultMeshStreamBodyTransport::AHardwareBuffer => CultMeshStreamCopyBudget::ZeroCopyTarget, + CultMeshStreamBodyTransport::CultCachePage => CultMeshStreamCopyBudget::OneCopyFallback, + CultMeshStreamBodyTransport::InlineBytes => CultMeshStreamCopyBudget::OpaqueRuntime, + } +} + +fn require_non_empty(value: String, name: &str) -> Result { + if value.trim().is_empty() { + anyhow::bail!("{name} must be non-empty"); + } + Ok(value) +} + +impl CultMeshNode { + pub fn runtime_id(&self) -> &str { + &self.runtime_id + } + + pub fn cache(&self) -> &CultCache { + &self.cache + } + + pub fn documents(&self) -> &CultNetDocumentRegistry { + &self.documents + } + + pub fn get(&self, key: &str) -> Result> { + self.cache.get::(key) + } + + pub fn get_required(&self, key: &str) -> Result { + self.cache.get_required::(key) + } + + pub fn put(&mut self, key: impl Into, value: &T) -> Result { + self.cache.put(key, value) + } + + pub fn pull_all_backing_stores(&mut self) -> Result<()> { + self.cache.pull_all_backing_stores() + } + + pub fn delete(&mut self, key: &str) -> Result { + self.cache.delete::(key) + } + + pub fn flush(&mut self) -> Result<()> { + Ok(()) + } + + pub fn publish_document_to_rudp_catalog( + &self, + key: impl Into, + value: &T, + options: CultMeshRudpDocumentPublishOptions, + ) -> Result<()> + where + T: DatabaseEntry + Serialize, + { + let message = self.create_rudp_document_message(key, value, &options)?; + publish_cultnet_messages_to_rudp_catalog(std::slice::from_ref(&message), options) + } + + pub fn create_rudp_document_message( + &self, + key: impl Into, + value: &T, + options: &CultMeshRudpDocumentPublishOptions, + ) -> Result + where + T: DatabaseEntry + Serialize, + { + let key = key.into(); + self.documents.create_raw_document_put_message( + format!("{}:{}:{}", options.runtime_id, T::TYPE, key), + key, + value, + CultNetDocumentPutOptions { + source_runtime_id: Some(options.runtime_id.clone()), + source_agent_id: options.source_agent_id.clone(), + source_role: options.source_role.clone(), + tags: if options.tags.is_empty() { + None + } else { + Some(options.tags.clone()) + }, + ..CultNetDocumentPutOptions::default() + }, + ) + } + + pub fn pull_rudp_catalog_snapshot( + &mut self, + options: CultMeshRudpSnapshotOptions, + ) -> Result { + let response = request_raw_snapshot_from_rudp_catalog(options)?; + let cultnet_rs::CultNetMessage::SnapshotResponseRaw { documents, .. } = response else { + anyhow::bail!("expected cultnet.snapshot_response_raw.v0"); + }; + let mut applied = 0usize; + for document in documents { + let Some(document_type) = + registered_document_type_for_schema(&self.documents, &document.schema_id) + else { + continue; + }; + self.cache.put_raw_envelope(CultCacheEnvelope { + key: document.record_key, + r#type: document_type, + payload: document.payload, + stored_at: document.stored_at, + schema_id: Some(document.schema_id), + })?; + applied += 1; + } + Ok(applied) + } +} + +fn registered_document_type_for_schema( + documents: &CultNetDocumentRegistry, + schema_id: &str, +) -> Option { + let normalized = strip_schema_version_suffix(schema_id); + if normalized != schema_id { + return Some(normalized.to_string()); + } + documents + .binding_by_schema_id(schema_id) + .map(|binding| binding.document_type.clone()) + .or_else(|| documents.binding(schema_id).map(|_| schema_id.to_string())) +} + +fn strip_schema_version_suffix(value: &str) -> &str { + let Some((prefix, suffix)) = value.rsplit_once(".v") else { + return value; + }; + if suffix.chars().all(|character| character.is_ascii_digit()) { + prefix + } else { + value + } +} + +fn request_raw_snapshot_from_rudp_catalog( + options: CultMeshRudpSnapshotOptions, +) -> Result { + if options.runtime_id.trim().is_empty() { + anyhow::bail!("runtime_id must be non-empty"); + } + let bind_addr = if options.target.is_ipv4() { + SocketAddr::from(([0, 0, 0, 0], 0)) + } else { + SocketAddr::from(([0, 0, 0, 0, 0, 0, 0, 0], 0)) + }; + let socket = UdpSocket::bind(bind_addr)?; + socket.set_read_timeout(Some(options.poll_interval))?; + let mut client = + CultNetRudpSocketTransportConnection::new(CultNetRudpSocketTransportOptions { + runtime_id: options.runtime_id.clone(), + socket, + mode: cultnet_rs::CultNetRudpSocketMode::Client, + remote_addr: Some(options.target), + connection_id: options.connection_id, + initial_sequence: 1, + resend_delay_ms: options.resend_delay_ms, + transport_id: Some("cultmesh-rudp-snapshot-client".to_string()), + max_payload_bytes: None, + max_fragment_bytes: Some(1200), + max_pending_reliable_packets: None, + reconnect_policy: None, + })?; + client.connect(Vec::new())?; + let connect_deadline = Instant::now() + options.connect_timeout; + while !client.connected() && Instant::now() < connect_deadline { + let _ = client.receive_once()?; + client.poll_resends()?; + thread::sleep(options.poll_interval); + } + if !client.connected() { + anyhow::bail!( + "timed out connecting CultMesh RUDP snapshot client {} to {}", + options.runtime_id, + options.target + ); + } + + let message_id = format!("{}:snapshot:{}", options.runtime_id, unix_millis()); + let request = cultnet_rs::CultNetMessage::SnapshotRequest { + message_id: message_id.clone(), + schema_ids: options.schema_ids, + record_keys: options.record_keys, + }; + let payload = encode_cultnet_message_to_vec(&request, CultNetWireContract::CultNetSchemaV0)?; + client.send("schema", payload)?; + let response_deadline = Instant::now() + options.response_timeout; + let mut snapshot_response = None; + while Instant::now() < response_deadline { + if let Some(frame) = client.receive_once()? { + if frame.channel_id == "schema" { + let message = decode_cultnet_message_from_slice( + &frame.payload, + CultNetWireContract::CultNetSchemaV0, + )?; + match &message { + cultnet_rs::CultNetMessage::SnapshotResponseRaw { + message_id: received, + .. + } if received == &message_id => { + snapshot_response = Some(message); + break; + } + cultnet_rs::CultNetMessage::Error { error } => { + let _ = client.disconnect(b"snapshot-error".to_vec()); + anyhow::bail!("CultMesh RUDP snapshot failed: {error}"); + } + _ => {} + } + } + } + client.poll_resends()?; + thread::sleep(options.poll_interval); + } + if let Some(message) = snapshot_response { + let _ = client.disconnect(b"snapshot-complete".to_vec()); + return Ok(message); + } + let _ = client.disconnect(b"snapshot-timeout".to_vec()); + anyhow::bail!( + "timed out waiting for CultMesh RUDP snapshot from {}", + options.target + ) +} + +fn unix_millis() -> u128 { + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap_or_default() + .as_millis() +} + +pub fn publish_cultnet_messages_to_rudp_catalog( + messages: &[cultnet_rs::CultNetMessage], + options: CultMeshRudpDocumentPublishOptions, +) -> Result<()> { + if options.runtime_id.trim().is_empty() { + anyhow::bail!("runtime_id must be non-empty"); + } + let bind_addr = if options.target.is_ipv4() { + SocketAddr::from(([0, 0, 0, 0], 0)) + } else { + SocketAddr::from(([0, 0, 0, 0, 0, 0, 0, 0], 0)) + }; + let socket = UdpSocket::bind(bind_addr)?; + socket.set_read_timeout(Some(options.poll_interval))?; + let mut client = + CultNetRudpSocketTransportConnection::new(CultNetRudpSocketTransportOptions { + runtime_id: options.runtime_id.clone(), + socket, + mode: cultnet_rs::CultNetRudpSocketMode::Client, + remote_addr: Some(options.target), + connection_id: options.connection_id, + initial_sequence: 1, + resend_delay_ms: options.resend_delay_ms, + transport_id: Some("cultmesh-rudp-document-publisher".to_string()), + max_payload_bytes: None, + max_fragment_bytes: Some(1200), + max_pending_reliable_packets: None, + reconnect_policy: None, + })?; + client.connect(Vec::new())?; + let connect_deadline = Instant::now() + options.connect_timeout; + while !client.connected() && Instant::now() < connect_deadline { + let _ = client.receive_once()?; + client.poll_resends()?; + thread::sleep(options.poll_interval); + } + if !client.connected() { + anyhow::bail!( + "timed out connecting CultMesh RUDP document publisher {} to {}", + options.runtime_id, + options.target + ); + } + + for message in messages { + let payload = encode_cultnet_message_to_vec(message, CultNetWireContract::CultNetSchemaV0)?; + client.send("schema", payload)?; + } + client.flush_reliable(options.flush_timeout) +} + +#[derive(Clone, Copy, Debug, Default)] +pub struct CultMesh; + +impl CultMesh { + pub fn resolve_rudp_endpoint(endpoint: &str) -> Result { + let text = require_non_empty(endpoint.trim().to_string(), "endpoint")?; + if text.starts_with("rudp://") { + return parse_rudp_socket_addr(&text); + } + if text.starts_with("cultmesh://") { + let resolved = default_cultmesh_rudp_endpoint_resolver(&text)?.ok_or_else(|| { + anyhow::anyhow!("CultMesh URI {text} did not resolve to a RUDP endpoint") + })?; + return parse_rudp_socket_addr(&resolved); + } + parse_socket_addr(&text) + } + + pub fn create_node( + store_path: impl AsRef, + documents: D, + options: CultMeshNodeOptions, + ) -> Result + where + D: CultMeshDocumentSet, + { + let mut cache = CultCache::new(); + documents.register_cache(&mut cache)?; + cache + .add_generic_backing_store(SingleFileMessagePackBackingStore::new(store_path.as_ref())); + if options.pull_on_start { + cache.pull_all_backing_stores()?; + } + + let mut registry = CultNetDocumentRegistry::new(); + documents.register_documents(&mut registry)?; + + Ok(CultMeshNode { + runtime_id: options.runtime_id, + cache, + documents: registry, + }) + } + + pub fn start_node( + store_path: impl AsRef, + documents: D, + options: CultMeshNodeOptions, + ) -> Result + where + D: CultMeshDocumentSet, + { + Self::create_node(store_path, documents, options) + } + + pub fn create_stream_catalog() -> CultMeshStreamCatalog { + CultMeshStreamCatalog::default() + } +} + +pub fn create_node( + store_path: impl AsRef, + documents: D, + options: CultMeshNodeOptions, +) -> Result +where + D: CultMeshDocumentSet, +{ + CultMesh::create_node(store_path, documents, options) +} + +pub fn start_node( + store_path: impl AsRef, + documents: D, + options: CultMeshNodeOptions, +) -> Result +where + D: CultMeshDocumentSet, +{ + CultMesh::start_node(store_path, documents, options) +} + +pub fn create_stream_catalog() -> CultMeshStreamCatalog { + CultMesh::create_stream_catalog() +} + +pub fn resolve_rudp_endpoint(endpoint: &str) -> Result { + CultMesh::resolve_rudp_endpoint(endpoint) +} + +fn parse_rudp_socket_addr(value: &str) -> Result { + let text = value.trim().strip_prefix("rudp://").unwrap_or(value.trim()); + parse_socket_addr(text) +} + +fn parse_socket_addr(value: &str) -> Result { + value + .parse() + .with_context(|| format!("RUDP endpoint must be a socket address, got {value:?}")) +} + +fn default_cultmesh_rudp_endpoint_resolver(uri: &str) -> Result> { + let authority = cultmesh_uri_authority(uri)?; + let slug = authority + .chars() + .map(|ch| { + if ch.is_ascii_alphanumeric() { + ch.to_ascii_uppercase() + } else { + '_' + } + }) + .collect::() + .trim_matches('_') + .to_string(); + if slug.is_empty() { + return Ok(None); + } + + for key in [ + format!("CULTMESH_URI_{slug}_RUDP"), + format!("{slug}_CULTMESH_RUDP_ENDPOINT"), + ] { + if let Ok(value) = env::var(&key) { + let text = value.trim(); + if !text.is_empty() { + return Ok(Some(if text.starts_with("rudp://") { + text.to_string() + } else { + format!("rudp://{text}") + })); + } + } + } + Ok(None) +} + +fn cultmesh_uri_authority(uri: &str) -> Result { + let rest = uri + .strip_prefix("cultmesh://") + .ok_or_else(|| anyhow::anyhow!("CultMesh URI must start with cultmesh://"))?; + let authority = rest.split(['/', '?', '#']).next().unwrap_or("").trim(); + if authority.is_empty() { + anyhow::bail!("CultMesh URI must include an authority"); + } + Ok(authority.to_string()) +} + +#[cfg(test)] +mod tests { + use super::*; + use pretty_assertions::assert_eq; + + #[derive(Clone, Debug, PartialEq, Eq, cultcache_rs::DatabaseEntry)] + #[cultcache(type = "cultmesh.test.note", schema = "CultMeshTestNote")] + struct Note { + #[cultcache(key = 0)] + body: String, + } + + cultmesh_documents!(TestDocuments { + Note => "cultmesh.test.note.v0", + }); + + #[test] + fn node_round_trips_registered_documents() -> Result<()> { + let temp = tempfile::tempdir()?; + let store_path = temp.path().join("cultmesh.cc"); + let note = Note { + body: "blessed circuit".to_string(), + }; + + let mut node = CultMesh::create_node( + &store_path, + TestDocuments, + CultMeshNodeOptions { + runtime_id: "test-runtime".to_string(), + ..CultMeshNodeOptions::default() + }, + )?; + assert_eq!(node.runtime_id(), "test-runtime"); + node.put("note", ¬e)?; + node.flush()?; + + let reloaded = CultMesh::create_node(&store_path, TestDocuments, Default::default())?; + assert_eq!(reloaded.get_required::("note")?, note); + assert!( + reloaded + .documents() + .binding_by_schema_id("cultmesh.test.note.v0") + .is_some() + ); + Ok(()) + } + + #[test] + fn node_publishes_registered_document_to_rudp_catalog() -> Result<()> { + let temp = tempfile::tempdir()?; + let store_path = temp.path().join("cultmesh.cc"); + let note = Note { + body: "respect odin once".to_string(), + }; + let node = CultMesh::create_node( + &store_path, + TestDocuments, + CultMeshNodeOptions { + runtime_id: "muninn-test".to_string(), + ..CultMeshNodeOptions::default() + }, + )?; + + let socket = UdpSocket::bind("127.0.0.1:0")?; + socket.set_read_timeout(Some(Duration::from_millis(10)))?; + let target = socket.local_addr()?; + let (sender, receiver) = std::sync::mpsc::channel(); + let server = thread::spawn(move || -> Result<()> { + let mut server = CultNetRudpSocketTransportConnection::new( + CultNetRudpSocketTransportOptions::server( + "odin-test-catalog", + socket, + CULTMESH_RUDP_DOCUMENT_CATALOG_CONNECTION_ID, + ), + )?; + let deadline = Instant::now() + Duration::from_secs(2); + while Instant::now() < deadline { + if let Some(frame) = server.receive_once()? { + let message = cultnet_rs::decode_cultnet_message_from_slice( + &frame.payload, + CultNetWireContract::CultNetSchemaV0, + )?; + if let cultnet_rs::CultNetMessage::DocumentPutRaw { document, .. } = message { + sender + .send(( + document.schema_id, + document.record_key, + document.source_runtime_id, + )) + .ok(); + return Ok(()); + } + } + server.poll_resends()?; + } + anyhow::bail!("timed out waiting for RUDP document put") + }); + + node.publish_document_to_rudp_catalog( + "note", + ¬e, + CultMeshRudpDocumentPublishOptions::odin(target, "muninn-test"), + )?; + let received = receiver.recv_timeout(Duration::from_secs(2))?; + server.join().expect("server thread should not panic")?; + + assert_eq!(received.0, "cultmesh.test.note.v0"); + assert_eq!(received.1, "note"); + assert_eq!(received.2.as_deref(), Some("muninn-test")); + Ok(()) + } + + #[test] + fn large_rudp_publication_waits_for_acknowledged_delivery() -> Result<()> { + let temp = tempfile::tempdir()?; + let node = CultMesh::create_node( + temp.path().join("cultmesh.cc"), + TestDocuments, + CultMeshNodeOptions { + runtime_id: "large-publisher-test".into(), + ..CultMeshNodeOptions::default() + }, + )?; + let socket = UdpSocket::bind("127.0.0.1:0")?; + socket.set_read_timeout(Some(Duration::from_millis(10)))?; + let target = socket.local_addr()?; + let options = CultMeshRudpDocumentPublishOptions::odin(target, "large-publisher-test"); + let messages = [ + node.create_rudp_document_message( + "large-a", + &Note { + body: "a".repeat(256 * 1024), + }, + &options, + )?, + node.create_rudp_document_message( + "large-b", + &Note { + body: "b".repeat(256 * 1024), + }, + &options, + )?, + ]; + + let server = thread::spawn(move || -> Result> { + thread::sleep(Duration::from_millis(500)); + let mut server = CultNetRudpSocketTransportConnection::new( + CultNetRudpSocketTransportOptions::server( + "delayed-odin-test", + socket, + CULTMESH_RUDP_DOCUMENT_CATALOG_CONNECTION_ID, + ), + )?; + let deadline = Instant::now() + Duration::from_secs(5); + let mut record_keys = Vec::new(); + while Instant::now() < deadline && record_keys.len() < 2 { + if let Some(frame) = server.receive_once()? { + let message = decode_cultnet_message_from_slice( + &frame.payload, + CultNetWireContract::CultNetSchemaV0, + )?; + if let cultnet_rs::CultNetMessage::DocumentPutRaw { document, .. } = message { + record_keys.push(document.record_key); + } + } + server.poll_resends()?; + } + let linger_deadline = Instant::now() + Duration::from_millis(250); + while Instant::now() < linger_deadline { + let _ = server.receive_once()?; + server.poll_resends()?; + } + if record_keys.len() != 2 { + anyhow::bail!("timed out waiting for both large RUDP documents"); + } + Ok(record_keys) + }); + + publish_cultnet_messages_to_rudp_catalog(&messages, options)?; + assert_eq!( + server.join().expect("server thread should not panic")?, + vec!["large-a", "large-b"] + ); + Ok(()) + } + + #[test] + fn resolves_rudp_endpoint_from_cultmesh_uri_bootstrap_env() -> Result<()> { + let previous = env::var("CULTMESH_URI_ODIN_RUDP").ok(); + unsafe { + env::set_var("CULTMESH_URI_ODIN_RUDP", "127.0.0.1:17871"); + } + let result = CultMesh::resolve_rudp_endpoint("cultmesh://odin/rendezvous/provider-catalog"); + unsafe { + if let Some(value) = previous { + env::set_var("CULTMESH_URI_ODIN_RUDP", value); + } else { + env::remove_var("CULTMESH_URI_ODIN_RUDP"); + } + } + + assert_eq!(result?, "127.0.0.1:17871".parse()?); + Ok(()) + } + + #[test] + fn rejects_unresolved_cultmesh_rudp_endpoint() { + let previous = env::var("CULTMESH_URI_MISSING_ODIN_RUDP").ok(); + unsafe { + env::remove_var("CULTMESH_URI_MISSING_ODIN_RUDP"); + } + let error = + CultMesh::resolve_rudp_endpoint("cultmesh://missing-odin/rendezvous/provider-catalog") + .expect_err("unresolved CultMesh URI should fail"); + unsafe { + if let Some(value) = previous { + env::set_var("CULTMESH_URI_MISSING_ODIN_RUDP", value); + } + } + assert!(error.to_string().contains("did not resolve")); + } + + #[test] + fn raw_snapshot_application_uses_registered_document_type() -> Result<()> { + let temp = tempfile::tempdir()?; + let store_path = temp.path().join("cultmesh.cc"); + let mut node = CultMesh::create_node( + &store_path, + TestDocuments, + CultMeshNodeOptions { + runtime_id: "snapshot-apply-test".to_string(), + ..CultMeshNodeOptions::default() + }, + )?; + let payload = rmp_serde::to_vec(&Note { + body: "catalog truth".to_string(), + })?; + + node.cache + .put_raw_envelope(cultcache_rs::CultCacheEnvelope { + key: "note".to_string(), + r#type: node + .documents + .binding_by_schema_id("cultmesh.test.note.v0") + .expect("test binding") + .document_type + .clone(), + payload, + stored_at: "2026-07-03T00:00:00Z".to_string(), + schema_id: Some("cultmesh.test.note.v0".to_string()), + })?; + node.flush()?; + + let reloaded = CultMesh::create_node(&store_path, TestDocuments, Default::default())?; + assert_eq!(reloaded.get_required::("note")?.body, "catalog truth"); + assert_eq!(reloaded.cache().snapshot()[0].r#type, Note::TYPE); + Ok(()) + } + + #[test] + fn stream_catalog_negotiates_and_publishes_latest_shared_memory_frame() -> Result<()> { + let mut catalog = CultMesh::create_stream_catalog(); + let stream = CultMeshStreamDescriptor::new( + "muninn:nightwing:move-evidence", + "mimir-live", + "muninn:nightwing", + CultMeshStreamKind::Bytes, + CultMeshStreamClock::new("muninn:nightwing:clock")? + .source_id("muninn:nightwing:move-evidence")? + .confidence(1.0) + .evidence_kind("muninn-move-evidence")?, + vec![ + CultMeshStreamBodyTransport::SharedMemory, + CultMeshStreamBodyTransport::CultCachePage, + ], + )? + .label("Muninn Move evidence")? + .max_in_flight_frames(4) + .metadata_schema_id("mimir.muninn_move_evidence_stream_frame.v1")?; + catalog.declare(stream); + + let consumer = CultMeshStreamConsumerProfile::new( + "mimir:starfire", + "mimir-live", + vec![CultMeshStreamBodyTransport::SharedMemory], + )?; + let negotiation = catalog.negotiate("muninn:nightwing:move-evidence", &consumer)?; + + assert_eq!( + negotiation.transport, + CultMeshStreamBodyTransport::SharedMemory + ); + assert_eq!( + negotiation.copy_budget, + CultMeshStreamCopyBudget::ZeroCopyTarget + ); + + let handle = { + let ring = + catalog.create_shared_memory_ring("muninn:nightwing:move-evidence", 4, 128)?; + ring.try_publish_copy(&[1, 2, 3], 42, 0)? + .expect("frame should publish") + }; + catalog.publish_frame(handle.clone())?; + + assert_eq!( + catalog.latest_frame("muninn:nightwing:move-evidence"), + Some(&handle) + ); + let lease = catalog + .ring("muninn:nightwing:move-evidence") + .and_then(CultMeshSharedMemoryFrameRing::try_acquire_latest_read) + .expect("latest frame should be readable"); + assert_eq!(lease.handle.sequence, 0); + assert_eq!(lease.bytes(), &[1, 2, 3]); + Ok(()) + } +} From 9f822b75780225f13ca239a0670d8666ab975e8b Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 3 Sep 2026 05:15:51 +0200 Subject: [PATCH 127/283] Expose exact RUDP acknowledgement receipts Ported from GameCult/cultnet-rs 9dcb88d into CultLib, where the wire contract belongs. Ghostlight's committed idunn_health.rs imports CultNetRudpReliableSendStatus to hold an Idunn process write lease current, and the symbol existed only in the standalone lineage, so nothing could consume this contract from its canonical home. Three reconciliations were needed because both lineages reworked RUDP independently since the 014f998 copy-in: - reset_peer_state: kept this lineage's version, which also resets the sequence and fragment counters and clears queued_reliable, and folded in only the imported change that matters -- rotating session_scope so a peer reset invalidates outstanding receipts. The imported body also cleared highest_delivered_sequenced_by_channel, a field the sequence-domain work renamed away here. - channel_send_options is a free function in this lineage, not a method. - The imported guard rejected reliable channels with an expiry. This lineage has no reliable-expiry concept at all -- the only mentions of expiry in the file arrived with this patch -- so every reliable channel is already non-expiring and the guard reduces to the reliability check. A comment marks where to restore the expiry half if expiry is ever added. 94 tests pass. The one rudp_server_hub failure is pre-existing and reproduces on clean origin/main. The other two standalone RUDP commits are deliberately not ported. Bounding session memory and rejecting hostile sequence rollover rebuild the receive path -- stale-sequence rejection, per-channel tracking caps, reassembly and ordered-buffer byte accounting -- in the same code this lineage reworked with sequence domains and ACK horizons. Merging them changes wire-observable drop and reassembly behavior, which needs the cross-runtime interop harness to validate, not a local build. Co-Authored-By: Claude Opus 5 --- packages/cultnet-rs/src/rudp.rs | 111 +++++++++++++++++++++++++++++++- 1 file changed, 108 insertions(+), 3 deletions(-) diff --git a/packages/cultnet-rs/src/rudp.rs b/packages/cultnet-rs/src/rudp.rs index 25382264..674b2996 100644 --- a/packages/cultnet-rs/src/rudp.rs +++ b/packages/cultnet-rs/src/rudp.rs @@ -6,7 +6,9 @@ use std::collections::VecDeque; use std::io::ErrorKind; use std::net::SocketAddr; use std::net::UdpSocket; +use std::thread; use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; +use uuid::Uuid; use crate::CultNetMessage; use crate::CultNetReconnectController; @@ -105,6 +107,28 @@ pub struct CultNetRudpSendOptions { pub now_ms: u64, } +/// Identifies every transport packet belonging to one non-expiring reliable +/// send. Receipts are local to the session that issued them and cannot survive +/// a peer reset. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CultNetRudpReliableSendReceipt { + session_scope: Uuid, + sequences: Vec, +} + +impl CultNetRudpReliableSendReceipt { + pub fn packet_sequences(&self) -> &[u32] { + &self.sequences + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum CultNetRudpReliableSendStatus { + Pending, + Acknowledged, + Invalidated, +} + #[derive(Clone, Debug, PartialEq, Eq)] struct PendingReliablePacket { packet: CultNetRudpPacket, @@ -127,6 +151,7 @@ struct FragmentBuffer { } pub struct CultNetRudpSession { + session_scope: Uuid, connection_id: u32, resend_delay_ms: u64, max_pending_reliable_packets: Option, @@ -149,6 +174,7 @@ pub struct CultNetRudpSession { impl CultNetRudpSession { pub fn new(options: CultNetRudpSessionOptions) -> Self { Self { + session_scope: Uuid::new_v4(), connection_id: options.connection_id, resend_delay_ms: options.resend_delay_ms, max_pending_reliable_packets: options.max_pending_reliable_packets, @@ -181,6 +207,11 @@ impl CultNetRudpSession { self.connected } + pub fn assume_connected(&mut self, now_ms: u64) { + self.connected = true; + self.last_received_at_ms = Some(now_ms); + } + pub fn pending_reliable_sequences(&self) -> Vec { self.pending_reliable.keys().copied().collect() } @@ -202,6 +233,39 @@ impl CultNetRudpSession { Some(pending.packet.clone()) } + fn reliable_send_status( + &self, + receipt: &CultNetRudpReliableSendReceipt, + ) -> CultNetRudpReliableSendStatus { + if receipt.session_scope != self.session_scope { + return CultNetRudpReliableSendStatus::Invalidated; + } + if receipt + .sequences + .iter() + .any(|sequence| self.pending_reliable.contains_key(sequence)) + { + CultNetRudpReliableSendStatus::Pending + } else { + CultNetRudpReliableSendStatus::Acknowledged + } + } + + fn non_expiring_reliable_receipt( + &self, + packets: &[CultNetRudpPacket], + ) -> Result { + if packets.is_empty() || packets.iter().any(|packet| !packet.reliable) { + return Err(anyhow!( + "RUDP acknowledgement receipts require a non-empty reliable packet set" + )); + } + Ok(CultNetRudpReliableSendReceipt { + session_scope: self.session_scope, + sequences: packets.iter().map(|packet| packet.sequence).collect(), + }) + } + pub fn last_received_at_ms(&self) -> Option { self.last_received_at_ms } @@ -224,6 +288,7 @@ impl CultNetRudpSession { } pub fn reset_peer_state(&mut self) { + self.session_scope = Uuid::new_v4(); self.next_sequence = self.initial_sequence; self.next_fragment_id = 1; self.connected = false; @@ -1508,13 +1573,53 @@ impl CultNetRudpSocketTransportConnection { let packets = self.session .send_many(channel_id, payload, options, self.max_fragment_bytes)?; - for packet in packets { - self.send_packet(&packet)?; - } + self.send_data_packets(&packets)?; self.stats.frames_sent += 1; Ok(()) } + /// Sends one frame on a reliable channel whose packets cannot expire and + /// returns the transport receipt used to observe its exact acknowledgement. + pub fn send_reliable( + &mut self, + channel_id: &str, + payload: Vec, + ) -> Result { + let options = channel_send_options(channel_id, now_ms()); + // This lineage has no reliable-expiry concept, so every reliable channel is + // already non-expiring. Restore the expiry half of this guard if one is added. + if !options.reliable { + return Err(anyhow!( + "RUDP acknowledgement receipts require a non-expiring reliable channel" + )); + } + let packets = + self.session + .send_many(channel_id, payload, options, self.max_fragment_bytes)?; + self.send_data_packets(&packets)?; + let receipt = self.session.non_expiring_reliable_receipt(&packets)?; + self.stats.frames_sent += 1; + Ok(receipt) + } + + pub fn reliable_send_status( + &self, + receipt: &CultNetRudpReliableSendReceipt, + ) -> CultNetRudpReliableSendStatus { + self.session.reliable_send_status(receipt) + } + + fn send_data_packets(&mut self, packets: &[CultNetRudpPacket]) -> Result<()> { + let fragmented = packets.len() > 1; + for (index, packet) in packets.iter().enumerate() { + self.send_packet(packet)?; + if fragmented && (index + 1) % 16 == 0 { + thread::sleep(Duration::from_millis(1)); + } + } + Ok(()) + } + pub fn send_schema_message(&mut self, message: &CultNetMessage) -> Result<()> { let payload = encode_cultnet_message_to_vec(message, CultNetWireContract::CultNetSchemaV0)?; self.send("schema", payload) From 62ac7e348394346e4873a45d4f70c754980ce5c5 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 3 Sep 2026 23:14:45 +0200 Subject: [PATCH 128/283] Record the unported RUDP hardening as owed work Exact acknowledgement receipts landed; bounded session memory and hostile sequence rollover rejection did not. Until they do, this runtime accepts sequence and reassembly input the retiring lineage rejects, so its repository cannot be deleted yet. Co-Authored-By: Claude Opus 5 --- docs/runtime-parity-scope.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/runtime-parity-scope.md b/docs/runtime-parity-scope.md index 681f1ad3..9d351ac2 100644 --- a/docs/runtime-parity-scope.md +++ b/docs/runtime-parity-scope.md @@ -89,6 +89,14 @@ server body, is deliberately not made. outside any conformance harness, and its stream, negotiation, and shared-memory frame-ring surfaces have never been checked against the browser, Kotlin, and TypeScript CultMesh bodies they must interoperate with. Runtime-local tests pass; that is not a parity claim. +- Finish porting RUDP hardening from the retiring GameCult/cultnet-rs lineage. Its exact + acknowledgement receipts are in. Two commits are not: bounded session memory (4a54f46) and + hostile sequence rollover rejection (91609ff). They rebuild the receive path -- stale-sequence + rejection, per-channel tracking caps, reassembly and ordered-buffer byte accounting -- in the + same code this lineage reworked with sequence domains and ACK horizons, and they change when + packets are dropped and reassembly refused. That is wire-observable, so the interop lanes are + the gate, not a local build. Until they land, this runtime accepts sequence and reassembly + input the other lineage rejects. Do not delete that repository before this is resolved. - Keep performance claims evidence-bound: C# owns SoA; Python has benchmark comparison gates; other runtimes should advertise measured native hot paths only when those paths exist. From 4c0dc07ba5b19c85d3942bab0163df3ef6c5b2a6 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Fri, 4 Sep 2026 00:01:17 +0200 Subject: [PATCH 129/283] Make the Rust suite green and stop silently ignoring packages exact_reliable_acks_clear_more_than_one_ack_window_of_fragments has been failing on main. It was not a defect: send_many returned 32 packets where the test expected 40, and 32 is exactly CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS. The reliable send window landed and this test kept asserting the pre-window behaviour, so a test whose name is about crossing an ack window had stopped crossing one. It now asserts that a window's worth leaves immediately, that the remaining eight fragments queue, and that acknowledgements promote them until every fragment is delivered -- the same loop packages/cultnet-rs/tests /cultnet.rs already uses for this contract. All three Rust crates are green: 46, 95 and 7. The NuGet packages rule hides every language package until one is named in the re-include list, and cultmath, cultmesh-browser and cultmesh-kotlin were never added. Nothing is currently lost -- every source file in them is tracked -- but any new file added to those three would have been dropped in silence. cultmesh-rs hit this on the way in. Co-Authored-By: Claude Opus 5 --- .gitignore | 6 +++++ packages/cultnet-rs/tests/rudp_server_hub.rs | 27 ++++++++++++++++---- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index ce48c2dc..656fafa0 100644 --- a/.gitignore +++ b/.gitignore @@ -309,6 +309,12 @@ node_modules/ !packages/cultnet-rs/** !packages/cultmesh-rs/ !packages/cultmesh-rs/** +!packages/cultmath/ +!packages/cultmath/** +!packages/cultmesh-browser/ +!packages/cultmesh-browser/** +!packages/cultmesh-kotlin/ +!packages/cultmesh-kotlin/** packages/**/node_modules/ packages/**/dist/ packages/**/dist-test/ diff --git a/packages/cultnet-rs/tests/rudp_server_hub.rs b/packages/cultnet-rs/tests/rudp_server_hub.rs index a8a2c114..cdc6e390 100644 --- a/packages/cultnet-rs/tests/rudp_server_hub.rs +++ b/packages/cultnet-rs/tests/rudp_server_hub.rs @@ -1,3 +1,4 @@ +use std::collections::VecDeque; use std::net::UdpSocket; use std::time::Duration; @@ -317,16 +318,32 @@ fn exact_reliable_acks_clear_more_than_one_ack_window_of_fragments() -> Result<( }, Some(1), )?; - assert_eq!(packets.len(), 40); + // Forty one-byte fragments cannot leave inside one reliable send window. The + // window's worth goes out now and the rest queue until acknowledgements free + // space, which is the crossing this test exists to prove. + assert_eq!(packets.len(), CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS); + assert_eq!( + sender.queued_reliable_packet_count(), + 40 - CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS + ); + + let mut wire = VecDeque::from(packets); let mut delivered = Vec::new(); - for packet in &packets { - let result = receiver.receive(packet, 2)?; - delivered.extend(result.delivered); - sender.receive(&receiver.create_ack_for(packet.sequence), 3)?; + while !wire.is_empty() { + let admitted = wire.len(); + for _ in 0..admitted { + let packet = wire.pop_front().expect("admitted packet remains queued"); + let received = receiver.receive(&packet, 2)?; + delivered.extend(received.delivered); + } + let acknowledged = sender.receive(&receiver.create_ack(), 3)?; + wire.extend(acknowledged.ready_to_send); } + assert_eq!(delivered.len(), 1); assert_eq!(delivered[0].payload, vec![0x5a; 40]); assert!(sender.pending_reliable_sequences().is_empty()); + assert_eq!(sender.outstanding_reliable_packet_count(), 0); Ok(()) } From ca9895c06ac852a17cdbcef8a8cecfb49fba1100 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 3 Sep 2026 22:22:36 +0200 Subject: [PATCH 130/283] Wire AGENTS.md into Claude Code memory Claude Code reads CLAUDE.md, not AGENTS.md, so this repo's doctrine was invisible to it. This one-line import makes the existing AGENTS.md load without duplicating or renaming it. Codex is unaffected. Co-Authored-By: Claude Opus 5 --- CLAUDE.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..640c1a14 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,3 @@ +Repository doctrine for this project lives in AGENTS.md, shared with Codex. + +@AGENTS.md From 0736ae4824e7effab73cdd3619c0bcea29caad5d Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 26 Aug 2026 17:16:57 +0200 Subject: [PATCH 131/283] Separate RUDP reliable and lossy sequence domains --- packages/cultnet-rs/src/rudp.rs | 65 ++++++--- packages/cultnet-rs/tests/cultnet.rs | 127 ++++++++++++++++++ packages/cultnet-ts/src/rudp.ts | 55 +++++--- packages/cultnet-ts/test/cultnet.test.ts | 47 +++++++ src/GameCult.Networking/CultNetTransport.cs | 68 ++++++---- .../NetworkingTests.cs | 118 +++++++++------- 6 files changed, 372 insertions(+), 108 deletions(-) diff --git a/packages/cultnet-rs/src/rudp.rs b/packages/cultnet-rs/src/rudp.rs index 674b2996..ab16bf0d 100644 --- a/packages/cultnet-rs/src/rudp.rs +++ b/packages/cultnet-rs/src/rudp.rs @@ -159,11 +159,13 @@ pub struct CultNetRudpSession { max_pending_fragment_sets: usize, initial_sequence: u32, next_sequence: u32, + next_sequenced_by_channel: BTreeMap, next_fragment_id: u16, connected: bool, last_received_at_ms: Option, highest_received_sequence: Option, received_sequences: BTreeSet, + latest_sequenced_by_channel: BTreeMap, pending_reliable: BTreeMap, queued_reliable: VecDeque, ordered_next_sequence_by_channel: BTreeMap, @@ -182,11 +184,13 @@ impl CultNetRudpSession { max_pending_fragment_sets: 64, initial_sequence: options.initial_sequence, next_sequence: options.initial_sequence, + next_sequenced_by_channel: BTreeMap::new(), next_fragment_id: 1, connected: false, last_received_at_ms: None, highest_received_sequence: None, received_sequences: BTreeSet::new(), + latest_sequenced_by_channel: BTreeMap::new(), pending_reliable: BTreeMap::new(), queued_reliable: VecDeque::new(), ordered_next_sequence_by_channel: BTreeMap::new(), @@ -290,11 +294,13 @@ impl CultNetRudpSession { pub fn reset_peer_state(&mut self) { self.session_scope = Uuid::new_v4(); self.next_sequence = self.initial_sequence; + self.next_sequenced_by_channel.clear(); self.next_fragment_id = 1; self.connected = false; self.last_received_at_ms = None; self.highest_received_sequence = None; self.received_sequences.clear(); + self.latest_sequenced_by_channel.clear(); self.pending_reliable.clear(); self.queued_reliable.clear(); self.ordered_next_sequence_by_channel.clear(); @@ -377,6 +383,9 @@ impl CultNetRudpSession { "Cannot send RUDP data before the session is connected" )); } + if options.ordered && !options.reliable { + return Err(anyhow!("RUDP ordered delivery requires reliability")); + } self.require_payload_size(payload.len())?; if let Some(max_fragment_bytes) = max_fragment_bytes { @@ -459,7 +468,6 @@ impl CultNetRudpSession { } if packet.packet_type == CultNetRudpPacketType::Ping { - self.remember_received(packet.sequence); return Ok(CultNetRudpReceiveResult { delivered: Vec::new(), ready_to_send, @@ -481,9 +489,6 @@ impl CultNetRudpSession { if packet.packet_type == CultNetRudpPacketType::Ack || packet.packet_type == CultNetRudpPacketType::Pong { - if packet.packet_type == CultNetRudpPacketType::Pong { - self.remember_received(packet.sequence); - } return Ok(CultNetRudpReceiveResult { delivered: Vec::new(), ready_to_send, @@ -500,7 +505,6 @@ impl CultNetRudpSession { } if packet.packet_type == CultNetRudpPacketType::Disconnect { - self.remember_received(packet.sequence); self.connected = false; return Ok(CultNetRudpReceiveResult { delivered: Vec::new(), @@ -525,12 +529,15 @@ impl CultNetRudpSession { }); } - let duplicate = self.received_sequences.contains(&packet.sequence) - || self.highest_received_sequence.is_some_and(|highest| { - packet.sequence < highest - && highest - packet.sequence >= RUDP_RECEIVED_SEQUENCE_WINDOW as u32 - }); - self.remember_received(packet.sequence); + let duplicate = packet.reliable + && (self.received_sequences.contains(&packet.sequence) + || self.highest_received_sequence.is_some_and(|highest| { + packet.sequence < highest + && highest - packet.sequence >= RUDP_RECEIVED_SEQUENCE_WINDOW as u32 + })); + if packet.reliable { + self.remember_received(packet.sequence); + } if duplicate { return Ok(CultNetRudpReceiveResult { delivered: Vec::new(), @@ -556,6 +563,19 @@ impl CultNetRudpSession { }; let delivered = if ordered { self.deliver_ordered(frame, next_sequence, expected_sequence_if_uninitialized) + } else if packet.sequenced { + let latest = self + .latest_sequenced_by_channel + .get(&frame.channel_id) + .copied(); + let newest_sequence = next_sequence.saturating_sub(1); + if latest.is_some_and(|latest| newest_sequence <= latest) { + Vec::new() + } else { + self.latest_sequenced_by_channel + .insert(frame.channel_id.clone(), newest_sequence); + vec![frame] + } } else { vec![frame] }; @@ -700,11 +720,24 @@ impl CultNetRudpSession { fragment_index: u16, fragment_count: u16, ) -> CultNetRudpPacket { - let sequence = self.next_sequence; - self.next_sequence = self - .next_sequence - .checked_add(1) - .expect("sequence overflow"); + let sequence = if reliable { + let sequence = self.next_sequence; + self.next_sequence = self + .next_sequence + .checked_add(1) + .expect("reliable sequence overflow"); + sequence + } else if sequenced { + let next = self + .next_sequenced_by_channel + .entry(channel_id.to_string()) + .or_insert(1); + let sequence = *next; + *next = next.checked_add(1).expect("sequenced channel overflow"); + sequence + } else { + 0 + }; let (ack, ack_mask) = self.ack_state(); CultNetRudpPacket { packet_type, diff --git a/packages/cultnet-rs/tests/cultnet.rs b/packages/cultnet-rs/tests/cultnet.rs index a66411f0..293b63a6 100644 --- a/packages/cultnet-rs/tests/cultnet.rs +++ b/packages/cultnet-rs/tests/cultnet.rs @@ -757,6 +757,133 @@ fn rudp_session_pings_and_detects_receive_timeout() -> Result<()> { Ok(()) } +#[test] +fn rudp_lossy_packets_cannot_create_reliable_ordered_gaps() -> Result<()> { + let mut client = CultNetRudpSession::new(CultNetRudpSessionOptions { + connection_id: 198, + initial_sequence: 1, + ..CultNetRudpSessionOptions::default() + }); + let mut server = CultNetRudpSession::new(CultNetRudpSessionOptions { + connection_id: 198, + initial_sequence: 100, + ..CultNetRudpSessionOptions::default() + }); + let connect = client.create_connect(0, Vec::new())?; + let accept = server.accept_connect(&connect, 1, Vec::new())?; + client.receive(&accept, 2)?; + + let ping = client.create_ping(b"pulse".to_vec()); + let pong = server + .receive(&ping, 3)? + .reply + .expect("ping should produce pong"); + let realtime = server.send( + "realtime", + b"discarded realtime".to_vec(), + CultNetRudpSendOptions::default(), + )?; + let latest = server.send( + "latest", + b"discarded latest state".to_vec(), + CultNetRudpSendOptions { + sequenced: true, + ..CultNetRudpSendOptions::default() + }, + )?; + let schema = server.send( + "schema", + b"committed response".to_vec(), + CultNetRudpSendOptions { + reliable: true, + ordered: true, + ..CultNetRudpSendOptions::default() + }, + )?; + + assert_eq!(ping.sequence, 0); + assert_eq!(pong.sequence, 0); + assert_eq!(realtime.sequence, 0); + assert_eq!(latest.sequence, 1); + assert_eq!(schema.sequence, accept.sequence + 1); + assert_eq!( + client.receive(&schema, 4)?.delivered[0].payload, + b"committed response" + ); + Ok(()) +} + +#[test] +fn rudp_unreliable_sequenced_delivery_is_scoped_to_its_channel() -> Result<()> { + let mut sender = CultNetRudpSession::new(CultNetRudpSessionOptions { + connection_id: 197, + initial_sequence: 50, + ..CultNetRudpSessionOptions::default() + }); + let mut receiver = CultNetRudpSession::new(CultNetRudpSessionOptions { + connection_id: 197, + initial_sequence: 100, + ..CultNetRudpSessionOptions::default() + }); + let connect = sender.create_connect(0, Vec::new())?; + let accept = receiver.accept_connect(&connect, 1, Vec::new())?; + sender.receive(&accept, 2)?; + let options = CultNetRudpSendOptions { + sequenced: true, + ..CultNetRudpSendOptions::default() + }; + let older = sender.send("latest", b"older".to_vec(), options.clone())?; + let newer = sender.send("latest", b"newer".to_vec(), options)?; + + assert_eq!(older.sequence, 1); + assert_eq!(newer.sequence, 2); + assert_eq!(receiver.receive(&newer, 3)?.delivered[0].payload, b"newer"); + assert!(receiver.receive(&older, 4)?.delivered.is_empty()); + Ok(()) +} + +#[test] +fn rudp_rejects_unreliable_ordered_delivery() -> Result<()> { + let mut session = CultNetRudpSession::new(CultNetRudpSessionOptions { + connection_id: 196, + ..CultNetRudpSessionOptions::default() + }); + session.receive( + &CultNetRudpPacket { + packet_type: CultNetRudpPacketType::Accept, + connection_id: 196, + sequence: 50, + ack: 0, + ack_mask: 0, + channel_id: "control".to_string(), + reliable: false, + ordered: false, + sequenced: false, + fragment_id: 0, + fragment_index: 0, + fragment_count: 0, + payload: Vec::new(), + }, + 0, + )?; + let error = session + .send( + "schema", + b"cannot order what will not retransmit".to_vec(), + CultNetRudpSendOptions { + ordered: true, + ..CultNetRudpSendOptions::default() + }, + ) + .unwrap_err(); + assert!( + error + .to_string() + .contains("ordered delivery requires reliability") + ); + Ok(()) +} + #[test] fn rudp_session_bounds_pending_reliable_packets_before_enqueue() -> Result<()> { let mut session = CultNetRudpSession::new(CultNetRudpSessionOptions { diff --git a/packages/cultnet-ts/src/rudp.ts b/packages/cultnet-ts/src/rudp.ts index 51b5cc5b..b6cae87d 100644 --- a/packages/cultnet-ts/src/rudp.ts +++ b/packages/cultnet-ts/src/rudp.ts @@ -147,12 +147,14 @@ export class CultNetRudpSession { readonly connectionId: number; readonly resendDelayMs: number; #nextSequence: number; + readonly #nextSequencedByChannel = new Map(); #nextFragmentId = 1; #connected = false; readonly #maxPendingReliablePackets: number | undefined; #lastReceivedAtMs: number | undefined; #highestReceivedSequence: number | undefined; readonly #receivedSequences = new Set(); + readonly #latestSequencedByChannel = new Map(); readonly #pendingReliable = new Map(); readonly #queuedReliable: CultNetRudpPacket[] = []; readonly #orderedNextSequenceByChannel = new Map(); @@ -194,6 +196,8 @@ export class CultNetRudpSession { this.#lastReceivedAtMs = undefined; this.#highestReceivedSequence = undefined; this.#receivedSequences.clear(); + this.#nextSequencedByChannel.clear(); + this.#latestSequencedByChannel.clear(); this.#pendingReliable.clear(); this.#queuedReliable.splice(0); this.#orderedNextSequenceByChannel.clear(); @@ -271,6 +275,9 @@ export class CultNetRudpSession { if (!this.#connected) { throw new Error("Cannot send RUDP data before the session is connected."); } + if (options.ordered && !options.reliable) { + throw new Error("RUDP ordered delivery requires reliability."); + } const maxFragmentBytes = options.maxFragmentBytes; if (maxFragmentBytes !== undefined && maxFragmentBytes <= 0) { @@ -336,7 +343,6 @@ export class CultNetRudpSession { } if (packet.packetType === "ping") { - this.#rememberReceived(packet.sequence); return { delivered: [], readyToSend, @@ -349,9 +355,8 @@ export class CultNetRudpSession { } if (packet.packetType === "ack" || packet.packetType === "pong") { - if (packet.packetType === "pong") this.#rememberReceived(packet.sequence); return { - delivered: this.#drainUnblockedOrdered(), + delivered: [], readyToSend, pong: packet.packetType === "pong", pongPayload: packet.packetType === "pong" ? packet.payload ?? new Uint8Array() : undefined, @@ -359,7 +364,6 @@ export class CultNetRudpSession { } if (packet.packetType === "disconnect") { - this.#rememberReceived(packet.sequence); this.#connected = false; return { delivered: [], @@ -373,11 +377,12 @@ export class CultNetRudpSession { return { delivered: [], readyToSend }; } - const isDuplicate = this.#receivedSequences.has(packet.sequence) - || (this.#highestReceivedSequence !== undefined - && packet.sequence < this.#highestReceivedSequence - && this.#highestReceivedSequence - packet.sequence >= RUDP_RECEIVED_SEQUENCE_WINDOW); - this.#rememberReceived(packet.sequence); + const isDuplicate = (packet.reliable ?? false) + && (this.#receivedSequences.has(packet.sequence) + || (this.#highestReceivedSequence !== undefined + && packet.sequence < this.#highestReceivedSequence + && this.#highestReceivedSequence - packet.sequence >= RUDP_RECEIVED_SEQUENCE_WINDOW)); + if (packet.reliable ?? false) this.#rememberReceived(packet.sequence); if (isDuplicate) { return { delivered: [], readyToSend }; } @@ -387,6 +392,16 @@ export class CultNetRudpSession { return { delivered: [], readyToSend }; } + if (!reassembled.ordered && (packet.sequenced ?? false)) { + const newestSequence = reassembled.nextSequence - 1; + const latestSequence = this.#latestSequencedByChannel.get(reassembled.frame.channelId); + if (latestSequence !== undefined && newestSequence <= latestSequence) { + return { delivered: [], readyToSend }; + } + this.#latestSequencedByChannel.set(reassembled.frame.channelId, newestSequence); + return { delivered: [reassembled.frame], readyToSend }; + } + if (!reassembled.ordered) { return { delivered: [reassembled.frame], readyToSend }; } @@ -492,8 +507,17 @@ export class CultNetRudpSession { fragmentIndex?: number; fragmentCount?: number; }): CultNetRudpPacket { - const sequence = this.#nextSequence; - this.#nextSequence = toUint32(this.#nextSequence + 1, "sequence"); + let sequence = 0; + if (packet.reliable ?? false) { + sequence = this.#nextSequence; + this.#nextSequence = toUint32(this.#nextSequence + 1, "reliable sequence"); + } else if (packet.sequenced ?? false) { + sequence = this.#nextSequencedByChannel.get(packet.channelId) ?? 1; + this.#nextSequencedByChannel.set( + packet.channelId, + toUint32(sequence + 1, "sequenced channel sequence"), + ); + } const { ack, ackMask } = this.#ackState(); return { packetType: packet.packetType, @@ -712,15 +736,6 @@ export class CultNetRudpSession { return delivered; } - #drainUnblockedOrdered(): CultNetRudpDeliveredFrame[] { - const delivered: CultNetRudpDeliveredFrame[] = []; - for (const channelId of this.#orderedBuffers.keys()) { - this.#skipReceivedNonChannelSequences(channelId); - delivered.push(...this.#drainOrdered(channelId)); - } - return delivered; - } - #skipReceivedNonChannelSequences(channelId: string): void { let next = this.#orderedNextSequenceByChannel.get(channelId); while (next !== undefined && this.#receivedSequences.has(next) && !this.#orderedBuffers.get(channelId)?.has(next)) { diff --git a/packages/cultnet-ts/test/cultnet.test.ts b/packages/cultnet-ts/test/cultnet.test.ts index 111b7361..7ffbafb9 100644 --- a/packages/cultnet-ts/test/cultnet.test.ts +++ b/packages/cultnet-ts/test/cultnet.test.ts @@ -553,6 +553,53 @@ test("rudp session pings and detects receive timeout", () => { assert.equal(client.connected, false); }); +test("rudp lossy packets cannot create reliable ordered gaps", () => { + const client = new CultNetRudpSession({ connectionId: 198, initialSequence: 1 }); + const server = new CultNetRudpSession({ connectionId: 198, initialSequence: 100 }); + const connect = client.createConnect(0); + const accept = server.acceptConnect(connect, 1); + client.receive(accept, 2); + + const ping = client.createPing(Buffer.from("pulse")); + const pong = server.receive(ping, 3).reply!; + const realtime = server.send("realtime", Buffer.from("discarded realtime")); + const latest = server.send("latest", Buffer.from("discarded latest state"), { sequenced: true }); + const schema = server.send("schema", Buffer.from("committed response"), { reliable: true, ordered: true }); + + assert.equal(ping.sequence, 0); + assert.equal(pong.sequence, 0); + assert.equal(realtime.sequence, 0); + assert.equal(latest.sequence, 1); + assert.equal(schema.sequence, accept.sequence + 1); + assert.deepEqual(client.receive(schema, 4).delivered.map(frame => Buffer.from(frame.payload).toString("utf8")), [ + "committed response", + ]); +}); + +test("rudp unreliable sequenced delivery is scoped to its channel", () => { + const sender = new CultNetRudpSession({ connectionId: 197, initialSequence: 50 }); + const receiver = new CultNetRudpSession({ connectionId: 197, initialSequence: 100 }); + const connect = sender.createConnect(0); + const accept = receiver.acceptConnect(connect, 1); + sender.receive(accept, 2); + const older = sender.send("latest", Buffer.from("older"), { sequenced: true }); + const newer = sender.send("latest", Buffer.from("newer"), { sequenced: true }); + + assert.equal(older.sequence, 1); + assert.equal(newer.sequence, 2); + assert.deepEqual(receiver.receive(newer, 3).delivered.map(frame => Buffer.from(frame.payload).toString("utf8")), ["newer"]); + assert.deepEqual(receiver.receive(older, 4).delivered, []); +}); + +test("rudp rejects unreliable ordered delivery", () => { + const session = new CultNetRudpSession({ connectionId: 196 }); + session.receive({ packetType: "accept", connectionId: 196, sequence: 50, ack: 0, ackMask: 0, channelId: "control" }); + assert.throws( + () => session.send("schema", Buffer.from("cannot order what will not retransmit"), { ordered: true }), + /ordered delivery requires reliability/, + ); +}); + test("rudp session bounds pending reliable packets before enqueue", () => { const session = new CultNetRudpSession({ connectionId: 102, initialSequence: 1, maxPendingReliablePackets: 2 }); session.receive({ packetType: "accept", connectionId: 102, sequence: 50, ack: 0, ackMask: 0, channelId: "control" }); diff --git a/src/GameCult.Networking/CultNetTransport.cs b/src/GameCult.Networking/CultNetTransport.cs index 6e706fbc..f549f735 100644 --- a/src/GameCult.Networking/CultNetTransport.cs +++ b/src/GameCult.Networking/CultNetTransport.cs @@ -894,12 +894,14 @@ namespace GameCult.Networking } private uint _nextSequence; + private readonly Dictionary _nextSequencedByChannel = new Dictionary(StringComparer.Ordinal); private ushort _nextFragmentId = 1; private readonly int? _maxPendingReliablePackets; private volatile bool _connected; private long? _lastReceivedAtMs; private uint? _highestReceivedSequence; private readonly HashSet _receivedSequences = new HashSet(); + private readonly Dictionary _latestSequencedByChannel = new Dictionary(StringComparer.Ordinal); private readonly object _pendingReliableGate = new object(); private readonly Dictionary _pendingReliable = new Dictionary(); private readonly Queue _queuedReliable = new Queue(); @@ -1022,6 +1024,10 @@ namespace GameCult.Networking } options ??= new CultNetRudpSendOptions(); + if (options.Ordered && !options.Reliable) + { + throw new InvalidOperationException("RUDP ordered delivery requires reliability."); + } payload ??= Array.Empty(); if (maxFragmentBytes.HasValue && maxFragmentBytes.Value <= 0) { @@ -1099,7 +1105,6 @@ namespace GameCult.Networking if (packet.PacketType == CultNetRudpPacketType.Ping) { - RememberReceived(packet.Sequence); return new CultNetRudpReceiveResult { ReadyToSend = readyToSend, @@ -1115,11 +1120,9 @@ namespace GameCult.Networking if (packet.PacketType == CultNetRudpPacketType.Ack || packet.PacketType == CultNetRudpPacketType.Pong) { - if (packet.PacketType == CultNetRudpPacketType.Pong) - RememberReceived(packet.Sequence); return new CultNetRudpReceiveResult { - Delivered = DrainUnblockedOrdered(), + Delivered = Array.Empty(), ReadyToSend = readyToSend, Pong = packet.PacketType == CultNetRudpPacketType.Pong, PongPayload = packet.PacketType == CultNetRudpPacketType.Pong @@ -1130,7 +1133,6 @@ namespace GameCult.Networking if (packet.PacketType == CultNetRudpPacketType.Disconnect) { - RememberReceived(packet.Sequence); _connected = false; return new CultNetRudpReceiveResult { @@ -1145,11 +1147,15 @@ namespace GameCult.Networking return new CultNetRudpReceiveResult { ReadyToSend = readyToSend }; } - var duplicate = _receivedSequences.Contains(packet.Sequence) - || (_highestReceivedSequence.HasValue - && packet.Sequence < _highestReceivedSequence.Value - && _highestReceivedSequence.Value - packet.Sequence >= ReceivedSequenceWindow); - RememberReceived(packet.Sequence); + var duplicate = packet.Reliable + && (_receivedSequences.Contains(packet.Sequence) + || (_highestReceivedSequence.HasValue + && packet.Sequence < _highestReceivedSequence.Value + && _highestReceivedSequence.Value - packet.Sequence >= ReceivedSequenceWindow)); + if (packet.Reliable) + { + RememberReceived(packet.Sequence); + } if (duplicate) { return new CultNetRudpReceiveResult { ReadyToSend = readyToSend }; @@ -1161,6 +1167,17 @@ namespace GameCult.Networking return new CultNetRudpReceiveResult { ReadyToSend = readyToSend }; } + if (!reassembled.Ordered && packet.Sequenced) + { + var newestSequence = reassembled.NextSequence - 1; + if (_latestSequencedByChannel.TryGetValue(reassembled.Frame.ChannelId, out var latestSequence) + && newestSequence <= latestSequence) + { + return new CultNetRudpReceiveResult { ReadyToSend = readyToSend }; + } + _latestSequencedByChannel[reassembled.Frame.ChannelId] = newestSequence; + } + return new CultNetRudpReceiveResult { ReadyToSend = readyToSend, @@ -1282,8 +1299,24 @@ namespace GameCult.Networking ushort fragmentIndex, ushort fragmentCount) { - var sequence = _nextSequence; - _nextSequence = checked(_nextSequence + 1); + uint sequence; + if (reliable) + { + sequence = _nextSequence; + _nextSequence = checked(_nextSequence + 1); + } + else if (sequenced) + { + if (!_nextSequencedByChannel.TryGetValue(channelId, out sequence)) + { + sequence = 1; + } + _nextSequencedByChannel[channelId] = checked(sequence + 1); + } + else + { + sequence = 0; + } var (ack, ackMask) = AckState(); return new CultNetRudpPacket { @@ -1563,17 +1596,6 @@ namespace GameCult.Networking return delivered; } - private IReadOnlyList DrainUnblockedOrdered() - { - var delivered = new List(); - foreach (var channelId in _orderedBuffers.Keys.ToArray()) - { - SkipReceivedNonChannelSequences(channelId); - delivered.AddRange(DrainOrdered(channelId)); - } - return delivered; - } - private void SkipReceivedNonChannelSequences(string channelId) { if (!_orderedNextSequenceByChannel.TryGetValue(channelId, out var next)) diff --git a/tests/GameCult.Networking.Tests/NetworkingTests.cs b/tests/GameCult.Networking.Tests/NetworkingTests.cs index 9ff8953e..c065d0af 100644 --- a/tests/GameCult.Networking.Tests/NetworkingTests.cs +++ b/tests/GameCult.Networking.Tests/NetworkingTests.cs @@ -889,6 +889,75 @@ namespace GameCult.Networking.Tests Assert.That(client.Connected, Is.False); } + [Test] + public void RudpSession_LossyPacketsCannotCreateReliableOrderedGaps() + { + var client = new CultNetRudpSession(new CultNetRudpSessionOptions { ConnectionId = 198, InitialSequence = 1 }); + var server = new CultNetRudpSession(new CultNetRudpSessionOptions { ConnectionId = 198, InitialSequence = 100 }); + var connect = client.CreateConnect(0); + var accept = server.AcceptConnect(connect, 1); + client.Receive(accept, 2); + + var ping = client.CreatePing(Encoding.UTF8.GetBytes("pulse")); + var pong = server.Receive(ping, 3).Reply!; + var realtime = server.Send("realtime", Encoding.UTF8.GetBytes("discarded realtime")); + var latest = server.Send( + "latest", + Encoding.UTF8.GetBytes("discarded latest state"), + new CultNetRudpSendOptions { Sequenced = true }); + var schema = server.Send( + "schema", + Encoding.UTF8.GetBytes("committed response"), + new CultNetRudpSendOptions { Reliable = true, Ordered = true }); + + Assert.That(ping.Sequence, Is.Zero); + Assert.That(pong.Sequence, Is.Zero); + Assert.That(realtime.Sequence, Is.Zero); + Assert.That(latest.Sequence, Is.EqualTo(1)); + Assert.That(schema.Sequence, Is.EqualTo(accept.Sequence + 1)); + Assert.That( + client.Receive(schema, 4).Delivered.Select(frame => Encoding.UTF8.GetString(frame.Payload)).ToArray(), + Is.EqualTo(new[] { "committed response" })); + } + + [Test] + public void RudpSession_UnreliableSequencedDeliveryIsScopedToItsChannel() + { + var sender = new CultNetRudpSession(new CultNetRudpSessionOptions { ConnectionId = 197, InitialSequence = 50 }); + var receiver = new CultNetRudpSession(new CultNetRudpSessionOptions { ConnectionId = 197, InitialSequence = 100 }); + var connect = sender.CreateConnect(0); + var accept = receiver.AcceptConnect(connect, 1); + sender.Receive(accept, 2); + var older = sender.Send("latest", Encoding.UTF8.GetBytes("older"), new CultNetRudpSendOptions { Sequenced = true }); + var newer = sender.Send("latest", Encoding.UTF8.GetBytes("newer"), new CultNetRudpSendOptions { Sequenced = true }); + + Assert.That(older.Sequence, Is.EqualTo(1)); + Assert.That(newer.Sequence, Is.EqualTo(2)); + Assert.That( + receiver.Receive(newer, 3).Delivered.Select(frame => Encoding.UTF8.GetString(frame.Payload)).ToArray(), + Is.EqualTo(new[] { "newer" })); + Assert.That(receiver.Receive(older, 4).Delivered, Is.Empty); + } + + [Test] + public void RudpSession_RejectsUnreliableOrderedDelivery() + { + var session = new CultNetRudpSession(new CultNetRudpSessionOptions { ConnectionId = 196 }); + session.Receive(new CultNetRudpPacket + { + PacketType = CultNetRudpPacketType.Accept, + ConnectionId = 196, + Sequence = 50, + ChannelId = "control" + }); + var error = Assert.Throws(() => + session.Send( + "schema", + Encoding.UTF8.GetBytes("cannot order what will not retransmit"), + new CultNetRudpSendOptions { Ordered = true })); + Assert.That(error!.Message, Does.Contain("ordered delivery requires reliability")); + } + [Test] public void RudpSession_BoundsPendingReliablePacketsBeforeEnqueue() { @@ -955,55 +1024,6 @@ namespace GameCult.Networking.Tests Is.EqualTo(new[] { "second", "third" })); } - [Test] - public void RudpSession_SequencedControlPacketReleasesBufferedOrderedFrame() - { - var receiver = new CultNetRudpSession(new CultNetRudpSessionOptions - { - ConnectionId = 199, - InitialSequence = 1 - }); - receiver.Receive(new CultNetRudpPacket - { - PacketType = CultNetRudpPacketType.Accept, - ConnectionId = 199, - Sequence = 100, - ChannelId = "control" - }); - var first = receiver.Receive(new CultNetRudpPacket - { - PacketType = CultNetRudpPacketType.Data, - ConnectionId = 199, - Sequence = 101, - ChannelId = "schema", - Reliable = true, - Ordered = true, - Payload = Encoding.UTF8.GetBytes("first") - }); - var buffered = receiver.Receive(new CultNetRudpPacket - { - PacketType = CultNetRudpPacketType.Data, - ConnectionId = 199, - Sequence = 103, - ChannelId = "schema", - Reliable = true, - Ordered = true, - Payload = Encoding.UTF8.GetBytes("second") - }); - var released = receiver.Receive(new CultNetRudpPacket - { - PacketType = CultNetRudpPacketType.Pong, - ConnectionId = 199, - Sequence = 102, - ChannelId = "control" - }); - - Assert.That(first.Delivered, Has.Count.EqualTo(1)); - Assert.That(buffered.Delivered, Is.Empty); - Assert.That(released.Delivered, Has.Count.EqualTo(1)); - Assert.That(Encoding.UTF8.GetString(released.Delivered[0].Payload), Is.EqualTo("second")); - } - [Test] public void RudpSession_SkipsControlPacketsWhileOrderingSchemaPayloads() { From 8d3025816dc71b0091cacad20bfa07cf94f09829 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 26 Aug 2026 17:39:55 +0200 Subject: [PATCH 132/283] Align RUDP reliability tests with sequence domains --- .../NetworkingTests.cs | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/tests/GameCult.Networking.Tests/NetworkingTests.cs b/tests/GameCult.Networking.Tests/NetworkingTests.cs index c065d0af..56681839 100644 --- a/tests/GameCult.Networking.Tests/NetworkingTests.cs +++ b/tests/GameCult.Networking.Tests/NetworkingTests.cs @@ -708,7 +708,10 @@ namespace GameCult.Networking.Tests Assert.That(ack.Ack, Is.EqualTo(100)); server.Receive(ack, 30); Assert.That(server.PendingReliableSequences, Is.Empty); - var firstData = client.Send("schema", Encoding.UTF8.GetBytes("after-ack")); + var firstData = client.Send( + "schema", + Encoding.UTF8.GetBytes("after-ack"), + new CultNetRudpSendOptions { Reliable = true, Ordered = true }); Assert.That(firstData.Sequence, Is.EqualTo(2)); } @@ -795,11 +798,19 @@ namespace GameCult.Networking.Tests new byte[] { 1 }, new CultNetRudpSendOptions { Reliable = true, Ordered = true, NowMs = 0 }); receiver.Receive(oldPacket); - foreach (var packet in Enumerable.Range(0, 40).Select(index => sender.Send( - "activity", - new byte[] { (byte)index }, - new CultNetRudpSendOptions { Reliable = false, Ordered = false, NowMs = 0 }))) - receiver.Receive(packet); + foreach (var sequence in Enumerable.Range(2, 40).Select(value => (uint)value)) + { + receiver.Receive(new CultNetRudpPacket + { + PacketType = CultNetRudpPacketType.Data, + ConnectionId = 991, + Sequence = sequence, + ChannelId = "activity", + Reliable = true, + Ordered = false, + Payload = new[] { (byte)sequence } + }); + } sender.Receive(receiver.CreateAck()); Assert.That(sender.PendingReliableSequences.First(), Is.EqualTo(1u)); From 85bc4c71b55d1e49d972ad885a55e8c5aba9fd12 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Fri, 4 Sep 2026 00:36:36 +0200 Subject: [PATCH 133/283] Align the replay-window test with the reliable sequence domain Separating the sequence domains gated duplicate suppression on packet.reliable in Rust, TypeScript and C# alike, so lossy datagrams are remembered nowhere and a replayed one is delivered again. That is the intended contract -- lossy traffic is fire-and-forget and its history is bounded by not existing -- but replay_history_is_bounded_and_idle_hub_sessions_expire still asserted the old behaviour with a lossy packet and had been left failing on the branch. The three tests the change added in each runtime cover ordered-requires- reliable, per-channel sequenced scope, and lossy gaps. None covers the bounded replay window, which was this test's real subject, so removing the assertion would have dropped the only coverage of a security property. The lossy assertion now states the new contract, and the reliable domain gets its own replay check: 4,100 acknowledged reliable sends, then the oldest replayed and rejected by the window. Rust 151, C# 148, TypeScript 48, Python 138 all pass. Co-Authored-By: Claude Opus 5 --- packages/cultnet-rs/tests/rudp_server_hub.rs | 34 +++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/packages/cultnet-rs/tests/rudp_server_hub.rs b/packages/cultnet-rs/tests/rudp_server_hub.rs index cdc6e390..801312aa 100644 --- a/packages/cultnet-rs/tests/rudp_server_hub.rs +++ b/packages/cultnet-rs/tests/rudp_server_hub.rs @@ -453,10 +453,42 @@ fn replay_history_is_bounded_and_idle_hub_sessions_expire() -> Result<()> { } assert_eq!(receiver.receive(&packet, sequence)?.delivered.len(), 1); } - assert!( + // Separating the sequence domains moved duplicate suppression onto the + // reliable domain, so a replayed lossy datagram is delivered again rather + // than silently dropped. Lossy traffic is remembered nowhere, which is what + // bounds its history. + assert_eq!( receiver .receive(&oldest.expect("oldest packet"), 4_101)? .delivered + .len(), + 1 + ); + + // The bounded replay window still guards the reliable domain, and nothing + // else asserts it once the lossy path stopped being remembered. + let mut oldest_reliable = None; + for step in 0..4_100u64 { + let packet = sender.send( + "schema", + vec![(step % 251) as u8], + CultNetRudpSendOptions { + reliable: true, + ordered: false, + sequenced: false, + now_ms: step, + }, + )?; + if oldest_reliable.is_none() { + oldest_reliable = Some(packet.clone()); + } + assert_eq!(receiver.receive(&packet, step)?.delivered.len(), 1); + sender.receive(&receiver.create_ack_for(packet.sequence), step)?; + } + assert!( + receiver + .receive(&oldest_reliable.expect("oldest reliable packet"), 4_101)? + .delivered .is_empty() ); From fd676ce74da1dc06cfd903049e5d438134ae1248 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Fri, 4 Sep 2026 00:40:05 +0200 Subject: [PATCH 134/283] Finish the sequence-domain split in Python and Kotlin Separating the reliable and lossy sequence domains landed in Rust, TypeScript and C# on a branch. The Python and Kotlin halves were written at the same time and left uncommitted in the worktree, so three runtimes spoke the new contract and two spoke the old one -- the exact cross-runtime disagreement this repository exists to prevent. Both were already complete and implement the same three rules as the others: ordered delivery requires reliability, sequenced channels carry their own per-channel counters with latest-wins delivery, and duplicate suppression is gated on packet.reliable so lossy datagrams are remembered nowhere. Python also gains the three tests Rust, TypeScript and C# each received and it did not: lossy packets cannot create reliable ordered gaps, unreliable sequenced delivery is scoped to its channel, and unreliable ordered delivery is rejected. Python passes 141. Kotlin is committed unverified. This machine has no JVM or Gradle, and the package carries no runtime-local test file, so its only gate is the interop lane in CI. The change mirrors the four runtimes proven here line for line, but mirroring is not evidence and CI is the witness. Co-Authored-By: Claude Opus 5 --- .../cultcache-py/src/cultnet_py/transport.py | 40 ++++++++++++---- packages/cultcache-py/tests/test_cultcache.py | 46 +++++++++++++++++++ .../kotlin/org/gamecult/cultmesh/CultMesh.kt | 31 +++++++++---- 3 files changed, 99 insertions(+), 18 deletions(-) diff --git a/packages/cultcache-py/src/cultnet_py/transport.py b/packages/cultcache-py/src/cultnet_py/transport.py index 9ce4e4de..2b9fe462 100644 --- a/packages/cultcache-py/src/cultnet_py/transport.py +++ b/packages/cultcache-py/src/cultnet_py/transport.py @@ -406,11 +406,13 @@ class CultNetRudpSession: raise ValueError("RUDP max_pending_reliable_packets must be greater than zero") self.max_pending_reliable_packets = options.max_pending_reliable_packets self._next_sequence = _uint32(options.initial_sequence, "initial_sequence") + self._next_sequenced_by_channel: dict[str, int] = {} self._next_fragment_id = 1 self._connected = False self._last_received_at_ms: int | None = None self._highest_received_sequence: int | None = None self._received_sequences: set[int] = set() + self._latest_sequenced_by_channel: dict[str, int] = {} self._pending_reliable: dict[int, _PendingReliablePacket] = {} self._queued_reliable: deque[CultNetRudpPacket] = deque() self._ordered_next_sequence_by_channel: dict[str, int] = {} @@ -495,6 +497,8 @@ class CultNetRudpSession: raise ValueError("Cannot send RUDP data before the session is connected") options = options or CultNetRudpSendOptions() + if options.ordered and not options.reliable: + raise ValueError("RUDP ordered delivery requires reliability") if max_fragment_bytes is not None and max_fragment_bytes <= 0: raise ValueError("RUDP max_fragment_bytes must be greater than zero") @@ -550,14 +554,12 @@ class CultNetRudpSession: return CultNetRudpReceiveResult(ready_to_send=ready_to_send) if packet.packet_type == CultNetRudpPacketType.PING: - self._remember_received(packet.sequence) return CultNetRudpReceiveResult( ready_to_send=ready_to_send, reply=self._create_packet(CultNetRudpPacketType.PONG, "control", packet.payload) ) if packet.packet_type in (CultNetRudpPacketType.ACK, CultNetRudpPacketType.PONG): - self._remember_received(packet.sequence) return CultNetRudpReceiveResult( ready_to_send=ready_to_send, pong=packet.packet_type == CultNetRudpPacketType.PONG, @@ -565,7 +567,6 @@ class CultNetRudpSession: ) if packet.packet_type == CultNetRudpPacketType.DISCONNECT: - self._remember_received(packet.sequence) self._connected = False return CultNetRudpReceiveResult( ready_to_send=ready_to_send, @@ -576,12 +577,15 @@ class CultNetRudpSession: if packet.packet_type != CultNetRudpPacketType.DATA: return CultNetRudpReceiveResult(ready_to_send=ready_to_send) - duplicate = packet.sequence in self._received_sequences or ( - self._highest_received_sequence is not None - and packet.sequence < self._highest_received_sequence - and self._highest_received_sequence - packet.sequence >= self.RECEIVED_SEQUENCE_WINDOW + duplicate = packet.reliable and ( + packet.sequence in self._received_sequences or ( + self._highest_received_sequence is not None + and packet.sequence < self._highest_received_sequence + and self._highest_received_sequence - packet.sequence >= self.RECEIVED_SEQUENCE_WINDOW + ) ) - self._remember_received(packet.sequence) + if packet.reliable: + self._remember_received(packet.sequence) if duplicate: return CultNetRudpReceiveResult(ready_to_send=ready_to_send) @@ -589,6 +593,13 @@ class CultNetRudpSession: if reassembled is None: return CultNetRudpReceiveResult(ready_to_send=ready_to_send) frame, ordered, next_sequence = reassembled + if not ordered and packet.sequenced: + newest_sequence = next_sequence - 1 + latest_sequence = self._latest_sequenced_by_channel.get(frame.channel_id) + if latest_sequence is not None and newest_sequence <= latest_sequence: + return CultNetRudpReceiveResult(ready_to_send=ready_to_send) + self._latest_sequenced_by_channel[frame.channel_id] = newest_sequence + return CultNetRudpReceiveResult(delivered=(frame,), ready_to_send=ready_to_send) if not ordered: return CultNetRudpReceiveResult(delivered=(frame,), ready_to_send=ready_to_send) return CultNetRudpReceiveResult( @@ -664,8 +675,17 @@ class CultNetRudpSession: fragment_index: int = 0, fragment_count: int = 0, ) -> CultNetRudpPacket: - sequence = self._next_sequence - self._next_sequence = _uint32(self._next_sequence + 1, "sequence") + if reliable: + sequence = self._next_sequence + self._next_sequence = _uint32(self._next_sequence + 1, "reliable sequence") + elif sequenced: + sequence = self._next_sequenced_by_channel.get(channel_id, 1) + self._next_sequenced_by_channel[channel_id] = _uint32( + sequence + 1, + "sequenced channel sequence", + ) + else: + sequence = 0 ack, ack_mask = self._ack_state() return CultNetRudpPacket( packet_type=packet_type, diff --git a/packages/cultcache-py/tests/test_cultcache.py b/packages/cultcache-py/tests/test_cultcache.py index 2dbbeb2d..29fdefef 100644 --- a/packages/cultcache-py/tests/test_cultcache.py +++ b/packages/cultcache-py/tests/test_cultcache.py @@ -1110,6 +1110,52 @@ class CultCacheTests(unittest.TestCase): ["second", "third"], ) + def test_cultnet_rudp_lossy_packets_cannot_create_reliable_ordered_gaps(self) -> None: + sender = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=198, initial_sequence=1)) + receiver = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=198, initial_sequence=100)) + sender.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 198, 90, 0, 0, "control")) + receiver.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 198, 91, 0, 0, "control")) + + realtime = sender.send("realtime", b"discarded realtime", CultNetRudpSendOptions()) + latest = sender.send("latest", b"discarded latest state", CultNetRudpSendOptions(sequenced=True)) + schema = sender.send("schema", b"committed response", CultNetRudpSendOptions(reliable=True, ordered=True)) + + self.assertEqual(realtime.sequence, 0) + self.assertEqual(latest.sequence, 1) + self.assertEqual( + [frame.payload.decode("utf-8") for frame in receiver.receive(schema).delivered], + ["committed response"], + ) + + def test_cultnet_rudp_unreliable_sequenced_delivery_is_scoped_to_its_channel(self) -> None: + sender = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=197, initial_sequence=50)) + receiver = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=197, initial_sequence=100)) + sender.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 197, 90, 0, 0, "control")) + receiver.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 197, 91, 0, 0, "control")) + + older = sender.send("latest", b"older", CultNetRudpSendOptions(sequenced=True)) + newer = sender.send("latest", b"newer", CultNetRudpSendOptions(sequenced=True)) + + self.assertEqual(older.sequence, 1) + self.assertEqual(newer.sequence, 2) + self.assertEqual( + [frame.payload.decode("utf-8") for frame in receiver.receive(newer).delivered], + ["newer"], + ) + self.assertEqual(receiver.receive(older).delivered, ()) + + def test_cultnet_rudp_rejects_unreliable_ordered_delivery(self) -> None: + session = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=196, initial_sequence=1)) + session.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 196, 50, 0, 0, "control")) + + with self.assertRaises(ValueError) as raised: + session.send( + "schema", + b"cannot order what will not retransmit", + CultNetRudpSendOptions(ordered=True), + ) + self.assertIn("ordered delivery requires reliability", str(raised.exception)) + def test_cultnet_rudp_session_skips_control_packets_while_ordering_schema_payloads(self) -> None: sender = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=124, initial_sequence=1)) receiver = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=124, initial_sequence=100)) diff --git a/packages/cultmesh-kotlin/src/main/kotlin/org/gamecult/cultmesh/CultMesh.kt b/packages/cultmesh-kotlin/src/main/kotlin/org/gamecult/cultmesh/CultMesh.kt index 6245fb9e..104bd1b9 100644 --- a/packages/cultmesh-kotlin/src/main/kotlin/org/gamecult/cultmesh/CultMesh.kt +++ b/packages/cultmesh-kotlin/src/main/kotlin/org/gamecult/cultmesh/CultMesh.kt @@ -2629,6 +2629,7 @@ class CultNetRudpSession(options: CultNetRudpSessionOptions) { val resendDelayMs: Long = options.resendDelayMs private val maxPendingReliablePackets: Int? = options.maxPendingReliablePackets private var nextSequence = uint32(options.initialSequence, "initialSequence") + private val nextSequencedByChannel = linkedMapOf() private var nextFragmentId = 1 var connected: Boolean = false private set @@ -2636,6 +2637,7 @@ class CultNetRudpSession(options: CultNetRudpSessionOptions) { private set private var highestReceivedSequence: Long? = null private val receivedSequences = linkedSetOf() + private val latestSequencedByChannel = linkedMapOf() private val pendingReliable = linkedMapOf() private val queuedReliable = ArrayDeque() private val orderedNextSequenceByChannel = linkedMapOf() @@ -2687,6 +2689,7 @@ class CultNetRudpSession(options: CultNetRudpSessionOptions) { maxFragmentBytes: Int? = null, ): List { if (!connected) throw IOException("Cannot send RUDP data before the session is connected") + if (options.ordered && !options.reliable) throw IOException("RUDP ordered delivery requires reliability") if (maxFragmentBytes != null && maxFragmentBytes <= 0) throw IOException("RUDP maxFragmentBytes must be greater than zero") if (maxFragmentBytes != null && payload.size > maxFragmentBytes) { val fragmentCount = (payload.size + maxFragmentBytes - 1) / maxFragmentBytes @@ -2730,11 +2733,9 @@ class CultNetRudpSession(options: CultNetRudpSessionOptions) { return CultNetRudpReceiveResult(readyToSend = readyToSend) } CultNetRudpPacketType.Ping -> { - rememberReceived(packet.sequence) return CultNetRudpReceiveResult(readyToSend = readyToSend, reply = createPacket(CultNetRudpPacketType.Pong, "control", packet.payload)) } CultNetRudpPacketType.Ack, CultNetRudpPacketType.Pong -> { - rememberReceived(packet.sequence) return CultNetRudpReceiveResult( readyToSend = readyToSend, pong = packet.packetType == CultNetRudpPacketType.Pong, @@ -2742,7 +2743,6 @@ class CultNetRudpSession(options: CultNetRudpSessionOptions) { ) } CultNetRudpPacketType.Disconnect -> { - rememberReceived(packet.sequence) connected = false return CultNetRudpReceiveResult(readyToSend = readyToSend, disconnected = true, disconnectReason = packet.payload.copyOf()) } @@ -2750,14 +2750,22 @@ class CultNetRudpSession(options: CultNetRudpSessionOptions) { else -> return CultNetRudpReceiveResult(readyToSend = readyToSend) } - val duplicate = receivedSequences.contains(packet.sequence) || ( + val duplicate = packet.reliable && (receivedSequences.contains(packet.sequence) || ( highestReceivedSequence != null && packet.sequence < highestReceivedSequence!! && highestReceivedSequence!! - packet.sequence >= ReceivedSequenceWindow.toLong() - ) - rememberReceived(packet.sequence) + )) + if (packet.reliable) rememberReceived(packet.sequence) if (duplicate) return CultNetRudpReceiveResult(readyToSend = readyToSend) val reassembled = reassemble(packet) ?: return CultNetRudpReceiveResult(readyToSend = readyToSend) + if (!reassembled.ordered && packet.sequenced) { + val newestSequence = reassembled.nextSequence - 1 + val latestSequence = latestSequencedByChannel[reassembled.frame.channelId] + if (latestSequence != null && newestSequence <= latestSequence) { + return CultNetRudpReceiveResult(readyToSend = readyToSend) + } + latestSequencedByChannel[reassembled.frame.channelId] = newestSequence + } return CultNetRudpReceiveResult( delivered = if (reassembled.ordered) deliverOrdered(reassembled.frame, reassembled.nextSequence, expectedSequenceIfUninitialized) else listOf(reassembled.frame), readyToSend = readyToSend, @@ -2828,8 +2836,15 @@ class CultNetRudpSession(options: CultNetRudpSessionOptions) { fragmentIndex: Int = 0, fragmentCount: Int = 0, ): CultNetRudpPacket { - val sequence = nextSequence - nextSequence = uint32(nextSequence + 1, "sequence") + val sequence = when { + reliable -> nextSequence.also { + nextSequence = uint32(nextSequence + 1, "reliable sequence") + } + sequenced -> (nextSequencedByChannel[channelId] ?: 1).also { + nextSequencedByChannel[channelId] = uint32(it + 1, "sequenced channel sequence") + } + else -> 0 + } val (ack, ackMask) = ackState() return CultNetRudpPacket(packetType, connectionId, sequence, ack, ackMask, channelId, reliable, ordered, sequenced, fragmentId, fragmentIndex, fragmentCount, payload.copyOf()) } From eb74ead837ceba288304da9403acf8f2590bdaf4 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Fri, 4 Sep 2026 00:45:48 +0200 Subject: [PATCH 135/283] Restore cross-runtime schema recovery and prove staging cleanup Taking the standalone body as the CultCache base dropped a0b31b8, and it was a real regression rather than a missing convenience. A record whose catalog entry is absent -- written by another runtime, or older than the catalog it was stamped against -- made decode_store_snapshot fail, and one such record failed the entire pull. Recovering the type from the payload is what "across runtimes" meant in that commit's title. Restored in full: the payload is a MessagePack array whose first field is the schema version, so the schema name is recoverable from the record itself; the registry now also indexes schema name to entry type and refuses a name claimed by a second type; and pull resolves a persisted type that is either a registered type or a recovered schema name. The stale schema id is preserved on the envelope rather than rewritten. 743eaa5's durability half needed no code. The standalone lineage reached the same place independently through crash-atomic single-file snapshots and abandoned staging cleanup, and its cleanup carries the same protections: only a candidate named for this exact store plus a canonical UUID is removed, and anything that is not a regular file is skipped. Untested, though, which is how a careful deletion rule quietly becomes a careless one. Now asserted: an abandoned canonical candidate is removed while a non-UUID lookalike, a bare .tmp suffix, and another store's candidate all survive, and the committed snapshot still reloads. 48 tests pass. This clears the cultcache half of the retained debt from b672fb7. Co-Authored-By: Claude Opus 5 --- packages/cultcache-rs/src/lib.rs | 235 +++++++++++++++++++++++++++++-- 1 file changed, 225 insertions(+), 10 deletions(-) diff --git a/packages/cultcache-rs/src/lib.rs b/packages/cultcache-rs/src/lib.rs index b8d6d8f9..576270a0 100644 --- a/packages/cultcache-rs/src/lib.rs +++ b/packages/cultcache-rs/src/lib.rs @@ -1750,6 +1750,7 @@ struct CultCacheStoreRegistration { pub struct CultCache { definitions: BTreeMap, + schema_name_definitions: BTreeMap, entries: BTreeMap<(String, String), CultCacheEnvelope>, stores: Vec, } @@ -1758,6 +1759,7 @@ impl CultCache { pub fn new() -> Self { Self { definitions: BTreeMap::new(), + schema_name_definitions: BTreeMap::new(), entries: BTreeMap::new(), stores: Vec::new(), } @@ -1777,7 +1779,18 @@ impl CultCache { T::TYPE )); } + if let Some(existing_type) = self.schema_name_definitions.get(T::SCHEMA_NAME) + && existing_type != T::TYPE + { + return Err(anyhow!( + "CultCache schema name {:?} is already registered for type {:?}", + T::SCHEMA_NAME, + existing_type + )); + } self.definitions.insert(T::TYPE.to_string(), T::SCHEMA_NAME); + self.schema_name_definitions + .insert(T::SCHEMA_NAME.to_string(), T::TYPE.to_string()); Ok(()) } @@ -1812,14 +1825,20 @@ impl CultCache { pub fn pull_all_backing_stores(&mut self) -> Result<()> { self.entries.clear(); let known_types: BTreeSet = self.definitions.keys().cloned().collect(); + let schema_name_definitions = self.schema_name_definitions.clone(); for registration in &mut self.stores { - for entry in registration.store.pull_all()? { - if !known_types.contains(&entry.r#type) { + for mut entry in registration.store.pull_all()? { + let Some(canonical_type) = resolve_registered_type( + &known_types, + &schema_name_definitions, + &entry.r#type, + ) else { return Err(anyhow!( "No schema is registered for persisted entry type {:?}", entry.r#type )); - } + }; + entry.r#type = canonical_type; self.entries.insert(entry_id(&entry), entry); } } @@ -2311,13 +2330,32 @@ fn decode_store_snapshot(bytes: &[u8]) -> Result> { .2 .into_iter() .map(|record| { - let r#type = catalog.get(&record.1).cloned().ok_or_else(|| { - anyhow!( - "CultCache record {:?} references missing schema {:?}", - record.0, - record.1 - ) - })?; + let r#type = match catalog.get(&record.1) { + Some(schema_name) => schema_name.clone(), + None => { + // A record can outlive its catalog entry when another runtime + // wrote it, or when the record is older than the catalog it + // was stamped against. The payload is a MessagePack array + // whose first field is the schema version, so the type can be + // recovered from the record itself rather than failing the + // whole snapshot. + let schema_version = + infer_schema_version_from_payload(&record.3).ok_or_else(|| { + anyhow!( + "CultCache record {:?} references missing schema {:?}", + record.0, + record.1 + ) + })?; + infer_schema_name(&schema_version).ok_or_else(|| { + anyhow!( + "CultCache record {:?} references missing schema {:?}", + record.0, + record.1 + ) + })? + } + }; Ok(CultCacheEnvelope { key: record.0, r#type, @@ -2329,6 +2367,83 @@ fn decode_store_snapshot(bytes: &[u8]) -> Result> { .collect() } +/// A record recovered from its payload carries a schema name, while the +/// registry is keyed by entry type. Accept either, so a snapshot whose catalog +/// entry is gone still resolves to the registered definition. +fn resolve_registered_type( + known_types: &BTreeSet, + schema_name_definitions: &BTreeMap, + persisted_type: &str, +) -> Option { + if known_types.contains(persisted_type) { + return Some(persisted_type.to_string()); + } + + schema_name_definitions.get(persisted_type).cloned() +} + +fn infer_schema_version_from_payload(payload: &[u8]) -> Option { + let mut offset = 0usize; + read_array_header(payload, &mut offset)?; + read_string(payload, &mut offset) +} + +fn read_array_header(payload: &[u8], offset: &mut usize) -> Option { + let marker = *payload.get(*offset)?; + *offset += 1; + match marker { + 0x90..=0x9f => Some((marker & 0x0f) as u32), + 0xdc => { + let bytes = payload.get(*offset..(*offset + 2))?; + *offset += 2; + Some(u16::from_be_bytes([bytes[0], bytes[1]]) as u32) + } + 0xdd => { + let bytes = payload.get(*offset..(*offset + 4))?; + *offset += 4; + Some(u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]])) + } + _ => None, + } +} + +fn read_string(payload: &[u8], offset: &mut usize) -> Option { + let marker = *payload.get(*offset)?; + *offset += 1; + let length = match marker { + 0xa0..=0xbf => (marker & 0x1f) as usize, + 0xd9 => { + let length = *payload.get(*offset)? as usize; + *offset += 1; + length + } + 0xda => { + let bytes = payload.get(*offset..(*offset + 2))?; + *offset += 2; + u16::from_be_bytes([bytes[0], bytes[1]]) as usize + } + 0xdb => { + let bytes = payload.get(*offset..(*offset + 4))?; + *offset += 4; + u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) as usize + } + _ => return None, + }; + + let bytes = payload.get(*offset..(*offset + length))?; + std::str::from_utf8(bytes).ok().map(str::to_string) +} + +fn infer_schema_name(schema_version: &str) -> Option { + let marker = schema_version.rfind(".v")?; + let version = schema_version.get((marker + 2)..)?; + if marker == 0 || version.is_empty() || !version.bytes().all(|value| value.is_ascii_digit()) { + return None; + } + + Some(schema_version[..marker].to_string()) +} + fn escape_json_string(value: &str) -> String { value.replace('\\', "\\\\").replace('"', "\\\"") } @@ -2514,6 +2629,17 @@ mod tests { symbol: Option, } + #[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] + #[cultcache(type = "runtime-policy", schema = "tests.schema_stamped_entry")] + struct SchemaStamped { + #[cultcache(key = 0)] + schema_version: String, + #[cultcache(key = 1)] + name: String, + #[cultcache(key = 2)] + value: String, + } + #[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] #[cultcache(type = "nested-note")] struct NestedNote { @@ -3711,4 +3837,93 @@ mod tests { let error = table.validate().unwrap_err(); assert!(error.to_string().contains("column types has length 0")); } + + #[test] + fn messagepack_store_recovers_schema_stamped_records_missing_catalog_entries() -> Result<()> { + let temp = tempfile::tempdir()?; + let store_path = temp.path().join("missing-catalog.msgpack"); + let expected = SchemaStamped { + schema_version: "tests.schema_stamped_entry.v1".to_string(), + name: "schema-stamped".to_string(), + value: "still readable".to_string(), + }; + // An empty catalog with a stale schema id is what a record written by + // another runtime, or one older than its catalog, looks like on disk. + let snapshot = PersistedStoreSnapshot( + "cultcache.store.v1".to_string(), + Vec::new(), + vec![PersistedRecord( + "record-1".to_string(), + "sha256:stale-schema-id-from-cold-record".to_string(), + "2026-06-25T12:00:00Z".to_string(), + rmp_serde::to_vec(&expected)?, + )], + ); + std::fs::write(&store_path, rmp_serde::to_vec(&snapshot)?)?; + + let mut cache = CultCache::new(); + cache.register_entry_type::()?; + cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(&store_path)); + cache.pull_all_backing_stores()?; + + assert_eq!(cache.get_required::("record-1")?, expected); + assert_eq!( + cache + .get_required_envelope::("record-1")? + .schema_id, + Some("sha256:stale-schema-id-from-cold-record".to_string()) + ); + Ok(()) + } + + #[test] + fn abandoned_staging_cleanup_removes_only_canonical_candidates() -> Result<()> { + let temp = tempfile::tempdir()?; + let store_path = temp.path().join("store.cc"); + let mut cache = CultCache::new(); + cache.register_entry_type::()?; + cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(&store_path)); + cache.put( + "primary", + &Settings { + theme: "dark".to_string(), + retries: 2, + }, + )?; + + // A crashed writer leaves a canonically named candidate behind. + let abandoned = temp + .path() + .join(format!("store.cc.{}.tmp", uuid::Uuid::new_v4())); + std::fs::write(&abandoned, b"partial snapshot")?; + // These only look like candidates. Cleanup must not touch them: the + // staging name is the store's own file name plus a canonical UUID, and + // anything else is somebody's file. + let lookalike = temp.path().join("store.cc.not-a-uuid.tmp"); + std::fs::write(&lookalike, b"keep me")?; + let bare_suffix = temp.path().join("store.cc.tmp"); + std::fs::write(&bare_suffix, b"keep me too")?; + let neighbour = temp.path().join("other.cc.00000000-0000-0000-0000-000000000000.tmp"); + std::fs::write(&neighbour, b"not this store")?; + + cache.put( + "primary", + &Settings { + theme: "light".to_string(), + retries: 3, + }, + )?; + + assert!(!abandoned.exists(), "canonical abandoned candidate survived"); + assert!(lookalike.exists(), "non-UUID lookalike was deleted"); + assert!(bare_suffix.exists(), "bare .tmp suffix was deleted"); + assert!(neighbour.exists(), "another store's candidate was deleted"); + + let mut reloaded = CultCache::new(); + reloaded.register_entry_type::()?; + reloaded.add_generic_backing_store(SingleFileMessagePackBackingStore::new(&store_path)); + reloaded.pull_all_backing_stores()?; + assert_eq!(reloaded.get_required::("primary")?.theme, "light"); + Ok(()) + } } From 5dbc0c29f58414ce52f4ca74f9eb975a2d5e9381 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Fri, 4 Sep 2026 00:57:07 +0200 Subject: [PATCH 136/283] Bound the RUDP receive path and refuse hostile sequences Clears the cultnet half of the retained debt. The two unported commits from the retiring GameCult/cultnet-rs lineage were not portable as patches: this lineage had reworked the same receive path with sequence domains and ACK horizons, and applying them raised nine conflicts that would have reverted that work. Most of what they added already existed here by another route -- received-sequence history, fragment-set count and reassembly bytes are all bounded already. So the gaps were taken rather than the patches. Three were real. The per-channel maps grew without limit, and a peer picks its own channel ids, so ordered and sequenced channel tracking is now capped at 64 each. The out-of-order hold buffer grew without limit, and a peer picks its own send order, so it is capped at 1024 frames and 4 MB; sizes are computed from the buffer rather than tracked in counters, which cannot drift. The fourth was the sharpest. remember_received ran before the duplicate early-return, so a single forged packet far past the current highest advanced the receive state beyond every sequence still in flight and starved the session. Such a packet is now refused without being remembered. Reliable sequence exhaustion aborted the process through expect(). The capacity gate that already guards the send window now also refuses when the sequence space cannot cover the request, and allocation saturates rather than panicking so no future path can reintroduce the abort. Five tests cover the bounds and both refusals. cultnet-rs passes 103, cultcache-rs 48, cultmesh-rs 7, and the TypeScript-Rust RUDP interop lanes pass 5 of 5 with the hardened peer, so legitimate traffic is unchanged. The parity ledger now records what this actually leaves owed: these are refusals, not wire-format changes, so the interop lanes stay green whether or not the other four runtimes match. The gap will not announce itself. Co-Authored-By: Claude Opus 5 --- docs/runtime-parity-scope.md | 14 +- packages/cultnet-rs/src/rudp.rs | 81 +++++++++- packages/cultnet-rs/tests/cultnet.rs | 219 +++++++++++++++++++++++++++ 3 files changed, 298 insertions(+), 16 deletions(-) diff --git a/docs/runtime-parity-scope.md b/docs/runtime-parity-scope.md index 9d351ac2..75d980d8 100644 --- a/docs/runtime-parity-scope.md +++ b/docs/runtime-parity-scope.md @@ -89,14 +89,12 @@ server body, is deliberately not made. outside any conformance harness, and its stream, negotiation, and shared-memory frame-ring surfaces have never been checked against the browser, Kotlin, and TypeScript CultMesh bodies they must interoperate with. Runtime-local tests pass; that is not a parity claim. -- Finish porting RUDP hardening from the retiring GameCult/cultnet-rs lineage. Its exact - acknowledgement receipts are in. Two commits are not: bounded session memory (4a54f46) and - hostile sequence rollover rejection (91609ff). They rebuild the receive path -- stale-sequence - rejection, per-channel tracking caps, reassembly and ordered-buffer byte accounting -- in the - same code this lineage reworked with sequence domains and ACK horizons, and they change when - packets are dropped and reassembly refused. That is wire-observable, so the interop lanes are - the gate, not a local build. Until they land, this runtime accepts sequence and reassembly - input the other lineage rejects. Do not delete that repository before this is resolved. +- Carry the RUDP receive-path bounds to the other runtimes. Rust now caps tracked ordered + and sequenced channels, caps the out-of-order hold buffer by frames and bytes, refuses a + packet far ahead of the highest received so a forged sequence cannot starve a session, and + reports reliable sequence exhaustion instead of aborting. C#, TypeScript, Python and Kotlin + still accept all of it. These are refusals rather than wire-format changes, so the interop + lanes stay green either way -- which is exactly why the gap will not announce itself. - Keep performance claims evidence-bound: C# owns SoA; Python has benchmark comparison gates; other runtimes should advertise measured native hot paths only when those paths exist. diff --git a/packages/cultnet-rs/src/rudp.rs b/packages/cultnet-rs/src/rudp.rs index ab16bf0d..0ff9f322 100644 --- a/packages/cultnet-rs/src/rudp.rs +++ b/packages/cultnet-rs/src/rudp.rs @@ -33,6 +33,15 @@ const RUDP_FIXED_HEADER_BYTES: usize = 36; pub const CULTNET_RUDP_DEFAULT_MAX_PAYLOAD_BYTES: usize = 16 * 1024 * 1024; pub const CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS: usize = 32; const RUDP_RECEIVED_SEQUENCE_WINDOW: usize = 4_096; +/// A peer chooses its own channel ids and its own send order, so the per-channel +/// maps and the out-of-order hold buffer are both attacker-sized unless capped. +const RUDP_MAX_TRACKED_CHANNELS: usize = 64; +/// A peer cannot be trusted to pick the next sequence honestly. One packet far +/// ahead of the current highest would otherwise advance the receive state past +/// every legitimate sequence still in flight and starve the session. +const RUDP_RECEIVE_AHEAD_WINDOW: u32 = 1_024; +const RUDP_MAX_ORDERED_BUFFERED_FRAMES: usize = 1_024; +const RUDP_MAX_ORDERED_BUFFERED_BYTES: usize = 4 * 1024 * 1024; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum CultNetRudpPacketType { @@ -529,6 +538,25 @@ impl CultNetRudpSession { }); } + let far_ahead = packet.reliable + && self.highest_received_sequence.is_some_and(|highest| { + packet.sequence > highest + && packet.sequence - highest > RUDP_RECEIVE_AHEAD_WINDOW + }); + if far_ahead { + // Refuse without remembering. Recording it would move the highest + // received sequence out of reach of everything still in flight. + return Ok(CultNetRudpReceiveResult { + delivered: Vec::new(), + ready_to_send, + reply: None, + pong: false, + pong_payload: Vec::new(), + disconnected: false, + disconnect_reason: Vec::new(), + }); + } + let duplicate = packet.reliable && (self.received_sequences.contains(&packet.sequence) || self.highest_received_sequence.is_some_and(|highest| { @@ -562,8 +590,15 @@ impl CultNetRudpSession { }); }; let delivered = if ordered { - self.deliver_ordered(frame, next_sequence, expected_sequence_if_uninitialized) + self.deliver_ordered(frame, next_sequence, expected_sequence_if_uninitialized)? } else if packet.sequenced { + if !self + .latest_sequenced_by_channel + .contains_key(&frame.channel_id) + && self.latest_sequenced_by_channel.len() >= RUDP_MAX_TRACKED_CHANNELS + { + return Err(anyhow!("RUDP session has too many sequenced channels")); + } let latest = self .latest_sequenced_by_channel .get(&frame.channel_id) @@ -724,8 +759,7 @@ impl CultNetRudpSession { let sequence = self.next_sequence; self.next_sequence = self .next_sequence - .checked_add(1) - .expect("reliable sequence overflow"); + .saturating_add(1); sequence } else if sequenced { let next = self @@ -733,7 +767,7 @@ impl CultNetRudpSession { .entry(channel_id.to_string()) .or_insert(1); let sequence = *next; - *next = next.checked_add(1).expect("sequenced channel overflow"); + *next = next.saturating_add(1); sequence } else { 0 @@ -808,6 +842,14 @@ impl CultNetRudpSession { return Err(anyhow!("RUDP reliable send queue is full")); } } + // Refuse before allocation rather than at it. A session that runs out of + // reliable sequence space must report it, not abort the process. + let required = u32::try_from(packet_count) + .ok() + .filter(|required| self.next_sequence.checked_add(*required).is_some()); + if required.is_none() { + return Err(anyhow!("RUDP reliable sequence space is exhausted")); + } Ok(()) } @@ -958,13 +1000,30 @@ impl CultNetRudpSession { Ok(()) } + fn ordered_buffered_frames(&self) -> usize { + self.ordered_buffers.values().map(BTreeMap::len).sum() + } + + fn ordered_buffered_bytes(&self) -> usize { + self.ordered_buffers + .values() + .flat_map(BTreeMap::values) + .map(|pending| pending.frame.payload.len()) + .sum() + } + fn deliver_ordered( &mut self, frame: CultNetRudpDeliveredFrame, next_sequence_after_frame: u32, expected_sequence_if_uninitialized: u32, - ) -> Vec { + ) -> Result> { let channel_id = frame.channel_id.clone(); + if !self.ordered_next_sequence_by_channel.contains_key(&channel_id) + && self.ordered_next_sequence_by_channel.len() >= RUDP_MAX_TRACKED_CHANNELS + { + return Err(anyhow!("RUDP session has too many ordered channels")); + } let mut next = if let Some(next) = self .ordered_next_sequence_by_channel .get(&channel_id) @@ -992,10 +1051,16 @@ impl CultNetRudpSession { } if frame.sequence < next { - return Vec::new(); + return Ok(Vec::new()); } if frame.sequence > next { + if self.ordered_buffered_frames() >= RUDP_MAX_ORDERED_BUFFERED_FRAMES + || self.ordered_buffered_bytes() + frame.payload.len() + > RUDP_MAX_ORDERED_BUFFERED_BYTES + { + return Err(anyhow!("RUDP ordered hold buffer is full")); + } self.ordered_buffers.entry(channel_id).or_default().insert( frame.sequence, PendingOrderedFrame { @@ -1003,14 +1068,14 @@ impl CultNetRudpSession { next_sequence: next_sequence_after_frame, }, ); - return Vec::new(); + return Ok(Vec::new()); } self.ordered_next_sequence_by_channel .insert(channel_id.clone(), next_sequence_after_frame); let mut delivered = vec![frame]; delivered.extend(self.drain_ordered(&channel_id)); - delivered + Ok(delivered) } fn drain_ordered(&mut self, channel_id: &str) -> Vec { diff --git a/packages/cultnet-rs/tests/cultnet.rs b/packages/cultnet-rs/tests/cultnet.rs index 293b63a6..b56c14ba 100644 --- a/packages/cultnet-rs/tests/cultnet.rs +++ b/packages/cultnet-rs/tests/cultnet.rs @@ -2417,3 +2417,222 @@ fn schema_discovery_round_trips_over_legacy_gamecult_contract_when_inline_schema ); Ok(()) } + +#[test] +fn rudp_sequenced_channel_tracking_is_bounded() -> Result<()> { + let mut sender = CultNetRudpSession::new(CultNetRudpSessionOptions { + connection_id: 401, + initial_sequence: 1, + ..CultNetRudpSessionOptions::default() + }); + let mut receiver = CultNetRudpSession::new(CultNetRudpSessionOptions { + connection_id: 401, + initial_sequence: 100, + ..CultNetRudpSessionOptions::default() + }); + let connect = sender.create_connect(0, Vec::new())?; + let accept = receiver.accept_connect(&connect, 1, Vec::new())?; + sender.receive(&accept, 2)?; + + // A peer picks its own channel ids, so the sequenced map is attacker-sized. + let mut error = None; + for channel in 0..256u32 { + let packet = sender.send( + &format!("channel-{channel}"), + b"state".to_vec(), + CultNetRudpSendOptions { + sequenced: true, + ..CultNetRudpSendOptions::default() + }, + )?; + if let Err(refused) = receiver.receive(&packet, 3) { + error = Some(refused); + break; + } + } + let error = error.expect("unbounded sequenced channel tracking"); + assert!( + error.to_string().contains("too many sequenced channels"), + "unexpected refusal: {error}" + ); + Ok(()) +} + +#[test] +fn rudp_ordered_channel_tracking_is_bounded() -> Result<()> { + let mut sender = CultNetRudpSession::new(CultNetRudpSessionOptions { + connection_id: 402, + initial_sequence: 1, + ..CultNetRudpSessionOptions::default() + }); + let mut receiver = CultNetRudpSession::new(CultNetRudpSessionOptions { + connection_id: 402, + initial_sequence: 100, + ..CultNetRudpSessionOptions::default() + }); + let connect = sender.create_connect(0, Vec::new())?; + let accept = receiver.accept_connect(&connect, 1, Vec::new())?; + sender.receive(&accept, 2)?; + + let mut error = None; + for channel in 0..256u32 { + let packet = sender.send( + &format!("ordered-{channel}"), + b"state".to_vec(), + CultNetRudpSendOptions { + reliable: true, + ordered: true, + ..CultNetRudpSendOptions::default() + }, + )?; + match receiver.receive(&packet, 3) { + Ok(_) => { + sender.receive(&receiver.create_ack_for(packet.sequence), 3)?; + } + Err(refused) => { + error = Some(refused); + break; + } + } + } + let error = error.expect("unbounded ordered channel tracking"); + assert!( + error.to_string().contains("too many ordered channels"), + "unexpected refusal: {error}" + ); + Ok(()) +} + +#[test] +fn rudp_ordered_hold_buffer_is_bounded() -> Result<()> { + let mut sender = CultNetRudpSession::new(CultNetRudpSessionOptions { + connection_id: 403, + initial_sequence: 1, + ..CultNetRudpSessionOptions::default() + }); + let mut receiver = CultNetRudpSession::new(CultNetRudpSessionOptions { + connection_id: 403, + initial_sequence: 100, + ..CultNetRudpSessionOptions::default() + }); + let connect = sender.create_connect(0, Vec::new())?; + let accept = receiver.accept_connect(&connect, 1, Vec::new())?; + sender.receive(&accept, 2)?; + + let options = CultNetRudpSendOptions { + reliable: true, + ordered: true, + ..CultNetRudpSendOptions::default() + }; + // Withhold the first frame so every later one has to be held. + let withheld = sender.send("schema", b"first".to_vec(), options.clone())?; + sender.receive(&receiver.create_ack_for(withheld.sequence), 3)?; + + let mut error = None; + for step in 0..4_096u32 { + let packet = sender.send("schema", vec![(step % 251) as u8], options.clone())?; + match receiver.receive(&packet, 4) { + Ok(result) => { + assert!(result.delivered.is_empty(), "gap should hold every frame"); + sender.receive(&receiver.create_ack_for(packet.sequence), 4)?; + } + Err(refused) => { + error = Some(refused); + break; + } + } + } + let error = error.expect("unbounded ordered hold buffer"); + assert!( + error.to_string().contains("ordered hold buffer is full"), + "unexpected refusal: {error}" + ); + Ok(()) +} + +#[test] +fn rudp_far_ahead_sequence_cannot_starve_the_session() -> Result<()> { + let mut sender = CultNetRudpSession::new(CultNetRudpSessionOptions { + connection_id: 404, + initial_sequence: 1, + ..CultNetRudpSessionOptions::default() + }); + let mut receiver = CultNetRudpSession::new(CultNetRudpSessionOptions { + connection_id: 404, + initial_sequence: 100, + ..CultNetRudpSessionOptions::default() + }); + let connect = sender.create_connect(0, Vec::new())?; + let accept = receiver.accept_connect(&connect, 1, Vec::new())?; + sender.receive(&accept, 2)?; + + let options = CultNetRudpSendOptions { + reliable: true, + ..CultNetRudpSendOptions::default() + }; + let first = sender.send("schema", b"before".to_vec(), options.clone())?; + assert_eq!(receiver.receive(&first, 3)?.delivered.len(), 1); + sender.receive(&receiver.create_ack_for(first.sequence), 3)?; + + // A forged packet far past the current highest. Recording it would push the + // receive state beyond every sequence still in flight. + let forged = CultNetRudpPacket { + packet_type: CultNetRudpPacketType::Data, + connection_id: 404, + sequence: first.sequence.saturating_add(500_000), + ack: 0, + ack_mask: 0, + channel_id: "schema".to_string(), + reliable: true, + ordered: false, + sequenced: false, + fragment_id: 0, + fragment_index: 0, + fragment_count: 0, + payload: b"hostile".to_vec(), + }; + assert!(receiver.receive(&forged, 4)?.delivered.is_empty()); + + // The session must still accept the next legitimate packet. + let second = sender.send("schema", b"after".to_vec(), options)?; + assert_eq!( + receiver.receive(&second, 5)?.delivered[0].payload, + b"after".to_vec() + ); + Ok(()) +} + +#[test] +fn rudp_reliable_sequence_exhaustion_is_reported_not_fatal() -> Result<()> { + let mut sender = CultNetRudpSession::new(CultNetRudpSessionOptions { + connection_id: 405, + // One sequence left: the handshake takes it, so the next send is the + // first allocation with nowhere to go. + initial_sequence: u32::MAX - 1, + ..CultNetRudpSessionOptions::default() + }); + let mut receiver = CultNetRudpSession::new(CultNetRudpSessionOptions { + connection_id: 405, + initial_sequence: 100, + ..CultNetRudpSessionOptions::default() + }); + let connect = sender.create_connect(0, Vec::new())?; + let accept = receiver.accept_connect(&connect, 1, Vec::new())?; + sender.receive(&accept, 2)?; + + let error = sender + .send( + "schema", + b"one past the end".to_vec(), + CultNetRudpSendOptions { + reliable: true, + ..CultNetRudpSendOptions::default() + }, + ) + .unwrap_err(); + assert!( + error.to_string().contains("sequence space is exhausted"), + "unexpected error: {error}" + ); + Ok(()) +} From 85f7024a35ea42cf9f0a0199a064526427150191 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Fri, 4 Sep 2026 01:09:11 +0200 Subject: [PATCH 137/283] Refuse a framed length beyond the advertised maximum Found while checking what would be lost by deleting Ghostlight's vendored fork. Its copy of transport.rs carried a guard CultLib never had: tcp_framed receive compared the declared payload length against the max_payload_bytes the profile advertises for the schema channel, and refused before allocating. Without it the length in a four-byte header is taken on trust and used directly to size a buffer, so one header reserves whatever the peer names before a single payload byte arrives. The guard sits ahead of the allocation, which is the only place it does any good. It is inert unless a profile advertises a maximum, so the test advertises one. This is the last thing unique to that fork. Everything else in it is now here or was already here, which is what makes the fork safe to delete. Co-Authored-By: Claude Opus 5 --- packages/cultnet-rs/src/transport.rs | 21 ++++++++++++++++ packages/cultnet-rs/tests/cultnet.rs | 36 ++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/packages/cultnet-rs/src/transport.rs b/packages/cultnet-rs/src/transport.rs index d7aad261..ec16cbf1 100644 --- a/packages/cultnet-rs/src/transport.rs +++ b/packages/cultnet-rs/src/transport.rs @@ -258,6 +258,27 @@ where let mut header = [0_u8; FRAME_HEADER_BYTES]; self.stream.read_exact(&mut header)?; let payload_len = u32::from_be_bytes(header) as usize; + // Refuse before allocating. The length is the peer's claim, so honouring + // it without checking the advertised maximum lets one header reserve as + // much memory as the peer cares to name. + if let Some(max_payload_bytes) = self + .profile + .transports + .iter() + .find(|transport| transport.protocol == CultNetTransportProtocol::TcpFramed) + .and_then(|transport| { + transport + .channels + .iter() + .find(|channel| channel.channel_id == "schema") + }) + .and_then(|channel| channel.max_payload_bytes) + && payload_len > max_payload_bytes as usize + { + return Err(anyhow!( + "tcp_framed payload length {payload_len} exceeds advertised maximum {max_payload_bytes}" + )); + } let mut payload = vec![0_u8; payload_len]; self.stream.read_exact(&mut payload)?; self.stats.bytes_received += (FRAME_HEADER_BYTES + payload_len) as u64; diff --git a/packages/cultnet-rs/tests/cultnet.rs b/packages/cultnet-rs/tests/cultnet.rs index b56c14ba..d9baaac7 100644 --- a/packages/cultnet-rs/tests/cultnet.rs +++ b/packages/cultnet-rs/tests/cultnet.rs @@ -2636,3 +2636,39 @@ fn rudp_reliable_sequence_exhaustion_is_reported_not_fatal() -> Result<()> { ); Ok(()) } + +#[test] +fn tcp_framed_receive_refuses_a_length_beyond_the_advertised_maximum() -> Result<()> { + let profile = create_tcp_framed_transport_profile( + "rust-transport", + TcpFramedTransportProfileOptions { + transport_id: Some("bounded-tcp".to_string()), + max_payload_bytes: Some(64), + ..TcpFramedTransportProfileOptions::default() + }, + ); + let advertised = profile + .transports + .iter() + .find(|transport| transport.protocol == CultNetTransportProtocol::TcpFramed) + .and_then(|transport| { + transport + .channels + .iter() + .find(|channel| channel.channel_id == "schema") + }) + .and_then(|channel| channel.max_payload_bytes) + .expect("tcp_framed schema channel advertises a maximum payload"); + + // Only a header, declaring more than the profile allows. Honouring it would + // reserve the peer's number before a single payload byte arrives. + let mut header = ((advertised as u64 + 1) as u32).to_be_bytes().to_vec(); + header.extend_from_slice(b"short"); + let mut receiver = TcpFramedTransportConnection::new(std::io::Cursor::new(header), profile); + let error = receiver.receive().unwrap_err(); + assert!( + error.to_string().contains("exceeds advertised maximum"), + "unexpected error: {error}" + ); + Ok(()) +} From bac5be88b909ed5736ff9f557d3245b3b00af35f Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Fri, 4 Sep 2026 03:21:01 +0200 Subject: [PATCH 138/283] Restore reliable expiry and snapshot compare-exchange to the Rust core Two capabilities existed only in Odin's vendored forks, which is why the forks could not be deleted. Both are ported here with tests so Odin can consume CultLib instead. cultnet-rs gains reliable send expiry. A reliable packet may now carry a deadline; past it the packet is dropped instead of retransmitted, and the count is reported through session and transport stats. Live media tolerates loss but not lateness -- a frame retransmitted after its moment has passed is worse than a missing one -- so the media channel takes a 75ms default while state channels never expire. Handshake packets never expire either: a dropped connect is not a late frame. The deadline is fixed when a send is admitted, so time spent waiting in the backlog spends it exactly as time spent awaiting an acknowledgement does. This lineage has a queued_reliable backlog that Odin's does not, and a queued packet promoted after its moment had passed would be as useless as a retransmitted one. Expiry runs before the window is measured, so an expiring stream is not refused for a backlog it no longer owns. cultcache-rs gains compare_exchange_snapshot and a nonblocking try_compare_exchange_snapshot. CultLib had neither, despite carrying the larger body -- the two lineages had diverged in both directions. Contention is returned as data rather than waited on, so the caller keeps retry and scheduling authority. This is the primitive an admitted-generation CAS needs. No wire format changes. Expiry is a sender-side policy and compare-exchange is local storage, so the other four runtimes stay in agreement without matching these refusals. They are still worth carrying eventually, and the parity ledger already tracks that this kind of gap does not announce itself. cultnet-rs: 106 tests. cultcache-rs: 51 tests. Co-Authored-By: Claude Opus 5 --- packages/cultcache-rs/src/lib.rs | 162 ++++++++++++++++++ .../examples/cultnet_interop_peer.rs | 1 + packages/cultnet-rs/src/cultmesh.rs | 2 + packages/cultnet-rs/src/rudp.rs | 106 ++++++++++-- packages/cultnet-rs/src/transport.rs | 3 + packages/cultnet-rs/tests/cultnet.rs | 145 ++++++++++++++++ packages/cultnet-rs/tests/rudp_server_hub.rs | 5 + 7 files changed, 408 insertions(+), 16 deletions(-) diff --git a/packages/cultcache-rs/src/lib.rs b/packages/cultcache-rs/src/lib.rs index 576270a0..352c5e22 100644 --- a/packages/cultcache-rs/src/lib.rs +++ b/packages/cultcache-rs/src/lib.rs @@ -284,6 +284,16 @@ pub struct PushAllOptions { pub soft: bool, } +/// Result of one nonblocking whole-snapshot compare-and-exchange. Contention is +/// reported rather than waited on, so the caller keeps retry and scheduling +/// authority instead of blocking inside the store. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum TryCompareExchangeSnapshotOutcome { + Exchanged, + Mismatch, + LockContended, +} + pub trait CacheBackingStore: Send { fn pull_all(&self) -> Result>; fn push(&mut self, entry: &CultCacheEnvelope) -> Result<()>; @@ -687,6 +697,80 @@ impl SingleFileMessagePackBackingStore { result } + /// Replaces the whole snapshot only if it still equals `expected`, waiting + /// for the exclusive lock. Returns false when another writer has moved the + /// snapshot on, which is a lost race rather than an error. + pub fn compare_exchange_snapshot( + &self, + expected: &[CultCacheEnvelope], + replacements: &[CultCacheEnvelope], + ) -> Result { + self.with_exclusive_lock(|| self.compare_exchange_snapshot_unlocked(expected, replacements)) + } + + /// Makes one nonblocking attempt at the same exchange. Once the lock is + /// held, comparison, validation, ordering and persistence are identical to + /// [`Self::compare_exchange_snapshot`]. + pub fn try_compare_exchange_snapshot( + &self, + expected: &[CultCacheEnvelope], + replacements: &[CultCacheEnvelope], + ) -> Result { + let Some(exchanged) = self.try_with_exclusive_lock(|| { + self.compare_exchange_snapshot_unlocked(expected, replacements) + })? + else { + return Ok(TryCompareExchangeSnapshotOutcome::LockContended); + }; + Ok(if exchanged { + TryCompareExchangeSnapshotOutcome::Exchanged + } else { + TryCompareExchangeSnapshotOutcome::Mismatch + }) + } + + fn compare_exchange_snapshot_unlocked( + &self, + expected: &[CultCacheEnvelope], + replacements: &[CultCacheEnvelope], + ) -> Result { + let current = self.read_all_unlocked()?; + if current != expected { + return Ok(false); + } + let mut replacement_ids = BTreeSet::new(); + for replacement in replacements { + if replacement.key.trim().is_empty() || replacement.r#type.trim().is_empty() { + return Err(anyhow!("CultCache snapshot replacement identity is empty")); + } + if !replacement_ids.insert(entry_id(replacement)) { + return Err(anyhow!( + "CultCache snapshot replacement contains a duplicate identity" + )); + } + } + let mut ordered = replacements.to_vec(); + ordered.sort_by_key(entry_id); + self.write_all_unlocked(&ordered)?; + Ok(true) + } + + fn try_with_exclusive_lock(&self, action: impl FnOnce() -> Result) -> Result> { + let lock = self.open_lock_file()?; + match fs2::FileExt::try_lock_exclusive(&lock) { + Ok(()) => {} + Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => return Ok(None), + Err(error) => { + return Err(error) + .with_context(|| format!("failed to lock {}", self.lock_path().display())); + } + } + let result = action(); + fs2::FileExt::unlock(&lock) + .with_context(|| format!("failed to unlock {}", self.lock_path().display()))?; + result.map(Some) + } + fn open_lock_file(&self) -> Result { let lock_path = self.lock_path(); if let Some(parent) = lock_path.parent() { @@ -3926,4 +4010,82 @@ mod tests { assert_eq!(reloaded.get_required::("primary")?.theme, "light"); Ok(()) } + + fn snapshot_envelope(key: &str, payload: &[u8]) -> CultCacheEnvelope { + CultCacheEnvelope { + key: key.to_string(), + r#type: "snapshot.record".to_string(), + payload: payload.to_vec(), + stored_at: "2026-01-01T00:00:00Z".to_string(), + // The store stamps the schema id from the type on write, so a + // fixture that omits it would not survive its own round trip. + schema_id: Some("snapshot.record".to_string()), + } + } + + #[test] + fn snapshot_exchange_commits_only_against_the_observed_snapshot() -> Result<()> { + let temp = tempfile::tempdir()?; + let store = SingleFileMessagePackBackingStore::new(temp.path().join("generation.cc")); + + let first = vec![snapshot_envelope("admitted", b"one")]; + assert!(store.compare_exchange_snapshot(&[], &first)?); + assert_eq!(store.pull_all_read_only_snapshot()?, first); + + // A writer holding a stale view loses the race instead of clobbering it. + let stale = vec![snapshot_envelope("admitted", b"stale")]; + assert!(!store.compare_exchange_snapshot(&[], &stale)?); + assert_eq!(store.pull_all_read_only_snapshot()?, first); + + let second = vec![snapshot_envelope("admitted", b"two")]; + assert!(store.compare_exchange_snapshot(&first, &second)?); + assert_eq!(store.pull_all_read_only_snapshot()?, second); + Ok(()) + } + + #[test] + fn try_snapshot_exchange_separates_a_lost_race_from_a_commit() -> Result<()> { + let temp = tempfile::tempdir()?; + let store = SingleFileMessagePackBackingStore::new(temp.path().join("generation.cc")); + + let first = vec![snapshot_envelope("admitted", b"one")]; + assert_eq!( + store.try_compare_exchange_snapshot(&[], &first)?, + TryCompareExchangeSnapshotOutcome::Exchanged + ); + assert_eq!( + store.try_compare_exchange_snapshot(&[], &first)?, + TryCompareExchangeSnapshotOutcome::Mismatch, + "a stale expectation is a lost race, not contention" + ); + assert_eq!(store.pull_all_read_only_snapshot()?, first); + Ok(()) + } + + #[test] + fn snapshot_exchange_refuses_replacements_that_cannot_be_addressed() -> Result<()> { + let temp = tempfile::tempdir()?; + let store = SingleFileMessagePackBackingStore::new(temp.path().join("generation.cc")); + + assert!( + store + .compare_exchange_snapshot(&[], &[snapshot_envelope(" ", b"one")]) + .is_err(), + "an unaddressable record must not reach the store" + ); + assert!( + store + .compare_exchange_snapshot( + &[], + &[ + snapshot_envelope("admitted", b"one"), + snapshot_envelope("admitted", b"two"), + ], + ) + .is_err(), + "a duplicate identity would make the snapshot ambiguous" + ); + assert_eq!(store.pull_all_read_only_snapshot()?, Vec::new()); + Ok(()) + } } diff --git a/packages/cultnet-rs/examples/cultnet_interop_peer.rs b/packages/cultnet-rs/examples/cultnet_interop_peer.rs index 1ed70a35..562756b8 100644 --- a/packages/cultnet-rs/examples/cultnet_interop_peer.rs +++ b/packages/cultnet-rs/examples/cultnet_interop_peer.rs @@ -1474,6 +1474,7 @@ impl SchemaMessageSender for RudpSessionSender<'_> { ordered: true, sequenced: false, now_ms: rudp_now_ms(), + reliable_expire_after_ms: None, }, Some(RUDP_INTEROP_MAX_FRAGMENT_BYTES), )?; diff --git a/packages/cultnet-rs/src/cultmesh.rs b/packages/cultnet-rs/src/cultmesh.rs index 20d21232..efc8acad 100644 --- a/packages/cultnet-rs/src/cultmesh.rs +++ b/packages/cultnet-rs/src/cultmesh.rs @@ -318,6 +318,7 @@ impl CultMesh { ) -> Result { let socket = bind_rudp_socket(&options)?; CultNetRudpSocketTransportConnection::new(CultNetRudpSocketTransportOptions { + media_reliable_expire_after_ms: None, runtime_id: runtime_id.into(), socket, mode: CultNetRudpSocketMode::Server, @@ -341,6 +342,7 @@ impl CultMesh { ) -> Result { let socket = bind_rudp_socket(&options)?; CultNetRudpSocketTransportConnection::new(CultNetRudpSocketTransportOptions { + media_reliable_expire_after_ms: None, runtime_id: runtime_id.into(), socket, mode: CultNetRudpSocketMode::Client, diff --git a/packages/cultnet-rs/src/rudp.rs b/packages/cultnet-rs/src/rudp.rs index 0ff9f322..e54cae54 100644 --- a/packages/cultnet-rs/src/rudp.rs +++ b/packages/cultnet-rs/src/rudp.rs @@ -33,6 +33,10 @@ const RUDP_FIXED_HEADER_BYTES: usize = 36; pub const CULTNET_RUDP_DEFAULT_MAX_PAYLOAD_BYTES: usize = 16 * 1024 * 1024; pub const CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS: usize = 32; const RUDP_RECEIVED_SEQUENCE_WINDOW: usize = 4_096; +/// Live media tolerates loss but not lateness: a frame retransmitted after this +/// long describes a moment that has already passed. State channels never +/// expire, so this default applies only to the media channel. +const DEFAULT_MEDIA_RELIABLE_EXPIRE_AFTER_MS: u64 = 75; /// A peer chooses its own channel ids and its own send order, so the per-channel /// maps and the out-of-order hold buffer are both attacker-sized unless capped. const RUDP_MAX_TRACKED_CHANNELS: usize = 64; @@ -114,6 +118,11 @@ pub struct CultNetRudpSendOptions { pub ordered: bool, pub sequenced: bool, pub now_ms: u64, + /// Drop a reliable packet instead of retransmitting it once this many + /// milliseconds have passed since the send call. `None` retransmits until + /// acknowledged, which is correct for state and wrong for live media, where + /// a late frame is worse than a missing one. + pub reliable_expire_after_ms: Option, } /// Identifies every transport packet belonging to one non-expiring reliable @@ -142,6 +151,7 @@ pub enum CultNetRudpReliableSendStatus { struct PendingReliablePacket { packet: CultNetRudpPacket, last_sent_at_ms: u64, + expires_at_ms: Option, } #[derive(Clone, Debug, PartialEq, Eq)] @@ -176,7 +186,8 @@ pub struct CultNetRudpSession { received_sequences: BTreeSet, latest_sequenced_by_channel: BTreeMap, pending_reliable: BTreeMap, - queued_reliable: VecDeque, + queued_reliable: VecDeque<(CultNetRudpPacket, Option)>, + reliable_packets_expired: u64, ordered_next_sequence_by_channel: BTreeMap, ordered_buffers: BTreeMap>, fragment_buffers: BTreeMap<(String, u16), FragmentBuffer>, @@ -202,6 +213,7 @@ impl CultNetRudpSession { latest_sequenced_by_channel: BTreeMap::new(), pending_reliable: BTreeMap::new(), queued_reliable: VecDeque::new(), + reliable_packets_expired: 0, ordered_next_sequence_by_channel: BTreeMap::new(), ordered_buffers: BTreeMap::new(), fragment_buffers: BTreeMap::new(), @@ -229,6 +241,12 @@ impl CultNetRudpSession { self.pending_reliable.keys().copied().collect() } + /// Reliable packets dropped by their expiry deadline rather than + /// acknowledged. A rising count means the peer is not keeping up. + pub fn reliable_packets_expired(&self) -> u64 { + self.reliable_packets_expired + } + pub fn queued_reliable_packet_count(&self) -> usize { self.queued_reliable.len() } @@ -327,7 +345,7 @@ impl CultNetRudpSession { true, false, ); - self.track_reliable(packet.clone(), now_ms); + self.track_reliable(packet.clone(), now_ms, None); Ok(packet) } @@ -357,7 +375,7 @@ impl CultNetRudpSession { true, false, ); - self.track_reliable(response.clone(), now_ms); + self.track_reliable(response.clone(), now_ms, None); Ok(response) } @@ -396,6 +414,12 @@ impl CultNetRudpSession { return Err(anyhow!("RUDP ordered delivery requires reliability")); } self.require_payload_size(payload.len())?; + // Reclaim deadline-passed sends before measuring window capacity, so an + // expiring stream cannot be refused for a backlog it no longer owns. + self.purge_expired_reliable(options.now_ms); + let expires_at_ms = options + .reliable_expire_after_ms + .map(|ttl| options.now_ms.saturating_add(ttl)); if let Some(max_fragment_bytes) = max_fragment_bytes { if max_fragment_bytes == 0 { @@ -426,7 +450,7 @@ impl CultNetRudpSession { packets.push(packet); } return Ok(if options.reliable { - self.admit_reliable_packets(packets, options.now_ms) + self.admit_reliable_packets(packets, options.now_ms, expires_at_ms) } else { packets }); @@ -443,7 +467,7 @@ impl CultNetRudpSession { options.sequenced, ); if packet.reliable { - return Ok(self.admit_reliable_packets(vec![packet], options.now_ms)); + return Ok(self.admit_reliable_packets(vec![packet], options.now_ms, expires_at_ms)); } Ok(vec![packet]) } @@ -455,6 +479,7 @@ impl CultNetRudpSession { ) -> Result { self.require_connection(packet)?; self.apply_acknowledgements(packet); + self.purge_expired_reliable(now_ms); let ready_to_send = self.promote_queued_reliable(now_ms); self.last_received_at_ms = Some(now_ms); let expected_sequence_if_uninitialized = self @@ -790,30 +815,52 @@ impl CultNetRudpSession { } } - fn track_reliable(&mut self, packet: CultNetRudpPacket, now_ms: u64) { + fn track_reliable( + &mut self, + packet: CultNetRudpPacket, + now_ms: u64, + expires_at_ms: Option, + ) { self.pending_reliable.insert( packet.sequence, PendingReliablePacket { packet, last_sent_at_ms: now_ms, + expires_at_ms, }, ); } + /// Drop pending and queued reliable packets past their deadline. The + /// deadline is fixed when the send is admitted, so time spent waiting in + /// the backlog counts against it exactly as time spent awaiting an ACK does. + fn purge_expired_reliable(&mut self, now_ms: u64) { + let before = self.pending_reliable.len() + self.queued_reliable.len(); + self.pending_reliable + .retain(|_, pending| pending.expires_at_ms.is_none_or(|at| now_ms <= at)); + self.queued_reliable + .retain(|(_, expires_at_ms)| expires_at_ms.is_none_or(|at| now_ms <= at)); + let after = self.pending_reliable.len() + self.queued_reliable.len(); + self.reliable_packets_expired = self + .reliable_packets_expired + .saturating_add((before - after) as u64); + } + fn admit_reliable_packets( &mut self, packets: Vec, now_ms: u64, + expires_at_ms: Option, ) -> Vec { let available = CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS.saturating_sub(self.pending_reliable.len()); let mut ready = Vec::with_capacity(available.min(packets.len())); for packet in packets { if ready.len() < available { - self.track_reliable(packet.clone(), now_ms); + self.track_reliable(packet.clone(), now_ms, expires_at_ms); ready.push(packet); } else { - self.queued_reliable.push_back(packet); + self.queued_reliable.push_back((packet, expires_at_ms)); } } ready @@ -824,10 +871,10 @@ impl CultNetRudpSession { CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS.saturating_sub(self.pending_reliable.len()); let mut ready = Vec::with_capacity(available.min(self.queued_reliable.len())); for _ in 0..available { - let Some(packet) = self.queued_reliable.pop_front() else { + let Some((packet, expires_at_ms)) = self.queued_reliable.pop_front() else { break; }; - self.track_reliable(packet.clone(), now_ms); + self.track_reliable(packet.clone(), now_ms, expires_at_ms); ready.push(packet); } ready @@ -1162,6 +1209,7 @@ pub struct CultNetRudpSocketTransportOptions { pub max_fragment_bytes: Option, pub max_pending_reliable_packets: Option, pub reconnect_policy: Option, + pub media_reliable_expire_after_ms: Option, } impl CultNetRudpSocketTransportOptions { @@ -1172,6 +1220,7 @@ impl CultNetRudpSocketTransportOptions { connection_id: u32, ) -> Self { Self { + media_reliable_expire_after_ms: Some(DEFAULT_MEDIA_RELIABLE_EXPIRE_AFTER_MS), runtime_id: runtime_id.into(), socket, mode: CultNetRudpSocketMode::Client, @@ -1189,6 +1238,7 @@ impl CultNetRudpSocketTransportOptions { pub fn server(runtime_id: impl Into, socket: UdpSocket, connection_id: u32) -> Self { Self { + media_reliable_expire_after_ms: Some(DEFAULT_MEDIA_RELIABLE_EXPIRE_AFTER_MS), runtime_id: runtime_id.into(), socket, mode: CultNetRudpSocketMode::Server, @@ -1216,6 +1266,7 @@ pub struct CultNetRudpSocketTransportConnection { max_fragment_bytes: Option, disconnect_reason: Option>, pong_payloads: VecDeque>, + media_reliable_expire_after_ms: Option, } pub struct CultNetRudpServerHubOptions { @@ -1229,11 +1280,13 @@ pub struct CultNetRudpServerHubOptions { pub max_fragment_bytes: Option, pub max_pending_reliable_packets: Option, pub max_peers: usize, + pub media_reliable_expire_after_ms: Option, } impl CultNetRudpServerHubOptions { pub fn new(runtime_id: impl Into, socket: UdpSocket, connection_id: u32) -> Self { Self { + media_reliable_expire_after_ms: Some(DEFAULT_MEDIA_RELIABLE_EXPIRE_AFTER_MS), runtime_id: runtime_id.into(), socket, connection_id, @@ -1298,6 +1351,7 @@ pub struct CultNetRudpServerHub { max_payload_bytes: usize, max_fragment_bytes: Option, max_peers: usize, + media_reliable_expire_after_ms: Option, next_session_generation: u64, peers: BTreeMap, pending_events: VecDeque, @@ -1329,6 +1383,7 @@ impl CultNetRudpServerHub { }, ); Ok(Self { + media_reliable_expire_after_ms: options.media_reliable_expire_after_ms, socket: options.socket, connection_id: options.connection_id, initial_sequence: options.initial_sequence, @@ -1353,7 +1408,13 @@ impl CultNetRudpServerHub { } pub fn stats(&self) -> CultNetTransportStats { - self.stats.clone() + let mut stats = self.stats.clone(); + stats.reliable_packets_expired = self + .peers + .values() + .map(|peer| peer.session.reliable_packets_expired()) + .fold(0_u64, |total, expired| total.saturating_add(expired)); + stats } pub fn sessions(&self) -> Vec { @@ -1388,7 +1449,7 @@ impl CultNetRudpServerHub { peer.session.send_many( channel_id, payload, - channel_send_options(channel_id, now_ms()), + channel_send_options(channel_id, now_ms(), self.media_reliable_expire_after_ms), self.max_fragment_bytes, )? }; @@ -1627,6 +1688,7 @@ impl CultNetRudpSocketTransportConnection { }); session.set_max_payload_bytes(max_payload_bytes.map(|value| value as usize)); Ok(Self { + media_reliable_expire_after_ms: options.media_reliable_expire_after_ms, socket: options.socket, session, mode: options.mode, @@ -1645,7 +1707,9 @@ impl CultNetRudpSocketTransportConnection { } pub fn stats(&self) -> CultNetTransportStats { - self.stats.clone() + let mut stats = self.stats.clone(); + stats.reliable_packets_expired = self.session.reliable_packets_expired(); + stats } pub fn disconnect_reason(&self) -> Option<&[u8]> { @@ -1667,7 +1731,8 @@ impl CultNetRudpSocketTransportConnection { } pub fn send(&mut self, channel_id: &str, payload: Vec) -> Result<()> { - let options = channel_send_options(channel_id, now_ms()); + let options = + channel_send_options(channel_id, now_ms(), self.media_reliable_expire_after_ms); let packets = self.session .send_many(channel_id, payload, options, self.max_fragment_bytes)?; @@ -1683,7 +1748,8 @@ impl CultNetRudpSocketTransportConnection { channel_id: &str, payload: Vec, ) -> Result { - let options = channel_send_options(channel_id, now_ms()); + let options = + channel_send_options(channel_id, now_ms(), self.media_reliable_expire_after_ms); // This lineage has no reliable-expiry concept, so every reliable channel is // already non-expiring. Restore the expiry half of this guard if one is added. if !options.reliable { @@ -2158,31 +2224,39 @@ fn packet_type_to_code(packet_type: CultNetRudpPacketType) -> u8 { } } -fn channel_send_options(channel_id: &str, now_ms: u64) -> CultNetRudpSendOptions { +fn channel_send_options( + channel_id: &str, + now_ms: u64, + media_reliable_expire_after_ms: Option, +) -> CultNetRudpSendOptions { match channel_id { "schema" => CultNetRudpSendOptions { reliable: true, ordered: true, sequenced: false, now_ms, + reliable_expire_after_ms: None, }, "latest" => CultNetRudpSendOptions { reliable: false, ordered: false, sequenced: true, now_ms, + reliable_expire_after_ms: None, }, "media" => CultNetRudpSendOptions { reliable: true, ordered: false, sequenced: false, now_ms, + reliable_expire_after_ms: media_reliable_expire_after_ms, }, _ => CultNetRudpSendOptions { reliable: false, ordered: false, sequenced: false, now_ms, + reliable_expire_after_ms: None, }, } } diff --git a/packages/cultnet-rs/src/transport.rs b/packages/cultnet-rs/src/transport.rs index ec16cbf1..f10ad87d 100644 --- a/packages/cultnet-rs/src/transport.rs +++ b/packages/cultnet-rs/src/transport.rs @@ -19,6 +19,9 @@ pub struct CultNetTransportStats { pub bytes_sent: u64, pub frames_received: u64, pub frames_sent: u64, + /// Reliable packets dropped by a send-side expiry deadline instead of being + /// retransmitted. Always zero for transports without reliable expiry. + pub reliable_packets_expired: u64, } #[derive(Clone, Debug, PartialEq, Eq)] diff --git a/packages/cultnet-rs/tests/cultnet.rs b/packages/cultnet-rs/tests/cultnet.rs index d9baaac7..de84d2d9 100644 --- a/packages/cultnet-rs/tests/cultnet.rs +++ b/packages/cultnet-rs/tests/cultnet.rs @@ -1258,6 +1258,7 @@ fn rudp_socket_transport_handshakes_and_carries_reliable_ordered_schema_frames() max_fragment_bytes: None, max_pending_reliable_packets: None, reconnect_policy: None, + media_reliable_expire_after_ms: None, })?; let mut client = CultNetRudpSocketTransportConnection::new(CultNetRudpSocketTransportOptions { @@ -1273,6 +1274,7 @@ fn rudp_socket_transport_handshakes_and_carries_reliable_ordered_schema_frames() max_fragment_bytes: None, max_pending_reliable_packets: None, reconnect_policy: None, + media_reliable_expire_after_ms: None, })?; client.connect(b"join".to_vec())?; @@ -1348,6 +1350,7 @@ fn rudp_socket_transport_carries_fragmented_reliable_ordered_schema_frames() -> max_fragment_bytes: Some(8), max_pending_reliable_packets: None, reconnect_policy: None, + media_reliable_expire_after_ms: None, })?; let mut client = CultNetRudpSocketTransportConnection::new(CultNetRudpSocketTransportOptions { @@ -1363,6 +1366,7 @@ fn rudp_socket_transport_carries_fragmented_reliable_ordered_schema_frames() -> max_fragment_bytes: Some(8), max_pending_reliable_packets: None, reconnect_policy: None, + media_reliable_expire_after_ms: None, })?; client.connect(b"join".to_vec())?; @@ -1476,6 +1480,7 @@ fn rudp_socket_flush_waits_for_large_fragment_delivery() -> Result<()> { max_fragment_bytes: Some(8), max_pending_reliable_packets: None, reconnect_policy: None, + media_reliable_expire_after_ms: None, })?; let mut client = CultNetRudpSocketTransportConnection::new(CultNetRudpSocketTransportOptions { @@ -1491,6 +1496,7 @@ fn rudp_socket_flush_waits_for_large_fragment_delivery() -> Result<()> { max_fragment_bytes: Some(8), max_pending_reliable_packets: None, reconnect_policy: None, + media_reliable_expire_after_ms: None, })?; client.connect(b"join".to_vec())?; pump_rudp_handshake(&mut client, &mut server)?; @@ -2672,3 +2678,142 @@ fn tcp_framed_receive_refuses_a_length_beyond_the_advertised_maximum() -> Result ); Ok(()) } + +#[test] +fn rudp_reliable_expiry_drops_late_packets_and_leaves_durable_sends_alone() -> Result<()> { + let mut sender = CultNetRudpSession::new(CultNetRudpSessionOptions { + connection_id: 7, + initial_sequence: 10, + resend_delay_ms: 100, + ..CultNetRudpSessionOptions::default() + }); + accept_rudp_session(&mut sender, 7)?; + + let expiring = sender.send( + "media", + b"late".to_vec(), + CultNetRudpSendOptions { + reliable: true, + now_ms: 0, + reliable_expire_after_ms: Some(50), + ..CultNetRudpSendOptions::default() + }, + )?; + let durable = sender.send( + "schema", + b"state".to_vec(), + CultNetRudpSendOptions { + reliable: true, + now_ms: 0, + ..CultNetRudpSendOptions::default() + }, + )?; + assert_eq!(sender.pending_reliable_sequences().len(), 2); + assert_eq!(sender.reliable_packets_expired(), 0); + + // One millisecond before the deadline nothing is dropped: the boundary is + // inclusive, so a packet is never discarded early. + sender.send( + "schema", + b"tick".to_vec(), + CultNetRudpSendOptions { + reliable: false, + now_ms: 50, + ..CultNetRudpSendOptions::default() + }, + )?; + assert_eq!(sender.reliable_packets_expired(), 0); + + sender.send( + "schema", + b"tick".to_vec(), + CultNetRudpSendOptions { + reliable: false, + now_ms: 51, + ..CultNetRudpSendOptions::default() + }, + )?; + assert_eq!(sender.reliable_packets_expired(), 1); + assert_eq!( + sender.pending_reliable_sequences(), + vec![durable.sequence], + "a send without an expiry deadline is never dropped" + ); + assert_ne!(expiring.sequence, durable.sequence); + Ok(()) +} + +#[test] +fn rudp_reliable_expiry_also_reclaims_the_send_backlog() -> Result<()> { + let mut sender = CultNetRudpSession::new(CultNetRudpSessionOptions { + connection_id: 9, + initial_sequence: 10, + resend_delay_ms: 100, + ..CultNetRudpSessionOptions::default() + }); + accept_rudp_session(&mut sender, 9)?; + + let fragment_count = CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS + 5; + let payload = (0..fragment_count * 8) + .map(|index| (index % 251) as u8) + .collect::>(); + sender.send_many( + "media", + payload, + CultNetRudpSendOptions { + reliable: true, + now_ms: 0, + reliable_expire_after_ms: Some(30), + ..CultNetRudpSendOptions::default() + }, + Some(8), + )?; + assert_eq!( + sender.pending_reliable_sequences().len(), + CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS + ); + assert_eq!(sender.queued_reliable_packet_count(), 5); + + // The deadline is fixed at admission, so waiting in the backlog spends it + // exactly as waiting for an acknowledgement does. A queued packet promoted + // after its moment has passed would be as useless as a retransmitted one. + sender.send( + "schema", + b"tick".to_vec(), + CultNetRudpSendOptions { + reliable: false, + now_ms: 31, + ..CultNetRudpSendOptions::default() + }, + )?; + assert_eq!(sender.pending_reliable_sequences().len(), 0); + assert_eq!(sender.queued_reliable_packet_count(), 0); + assert_eq!( + sender.reliable_packets_expired(), + fragment_count as u64, + "both the in-flight window and the backlog are counted" + ); + Ok(()) +} + +fn accept_rudp_session(session: &mut CultNetRudpSession, connection_id: u32) -> Result<()> { + session.receive( + &CultNetRudpPacket { + packet_type: CultNetRudpPacketType::Accept, + connection_id, + sequence: 0, + ack: 0, + ack_mask: 0, + channel_id: "control".into(), + reliable: false, + ordered: false, + sequenced: false, + fragment_id: 0, + fragment_index: 0, + fragment_count: 0, + payload: Vec::new(), + }, + 0, + )?; + Ok(()) +} diff --git a/packages/cultnet-rs/tests/rudp_server_hub.rs b/packages/cultnet-rs/tests/rudp_server_hub.rs index 801312aa..cb765a33 100644 --- a/packages/cultnet-rs/tests/rudp_server_hub.rs +++ b/packages/cultnet-rs/tests/rudp_server_hub.rs @@ -315,6 +315,7 @@ fn exact_reliable_acks_clear_more_than_one_ack_window_of_fragments() -> Result<( ordered: true, sequenced: false, now_ms: 1, + reliable_expire_after_ms: None, }, Some(1), )?; @@ -375,6 +376,7 @@ fn session_and_hub_reject_configured_memory_bounds() -> Result<()> { ordered: true, sequenced: false, now_ms: 1, + reliable_expire_after_ms: None, }, Some(2), )?; @@ -387,6 +389,7 @@ fn session_and_hub_reject_configured_memory_bounds() -> Result<()> { ordered: true, sequenced: false, now_ms: 2, + reliable_expire_after_ms: None, }; let first_set = sender.send_many( "schema", @@ -446,6 +449,7 @@ fn replay_history_is_bounded_and_idle_hub_sessions_expire() -> Result<()> { ordered: false, sequenced: false, now_ms: sequence, + reliable_expire_after_ms: None, }, )?; if oldest.is_none() { @@ -477,6 +481,7 @@ fn replay_history_is_bounded_and_idle_hub_sessions_expire() -> Result<()> { ordered: false, sequenced: false, now_ms: step, + reliable_expire_after_ms: None, }, )?; if oldest_reliable.is_none() { From 8f29ee568d8dbc100d72a444feb57f0e29387a94 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Fri, 4 Sep 2026 03:32:07 +0200 Subject: [PATCH 139/283] Add the per-entry snapshot compare-exchange Odin consumes A first pass at Odin's vendored CultCache compared only its uncommitted diff against CultLib and concluded nothing else was missing. That was wrong: a whole-file symbol comparison found CultCacheExpectedEnvelope and a per-entry compare_exchange that CultLib lacks and Odin's crates import. Comparing a diff tells you what changed recently, not what the fork uniquely holds. Unlike the snapshot form this constrains only the identities it names, so an unrelated concurrent write does not lose the race. Expecting `None` makes it a create-once claim, which is what an admitted-generation owner needs. The expectation-identity guard is carried over as written even though it is unreachable: a condition whose envelope names a different identity is already rejected by the value comparison above it. Left in place rather than quietly dropped, since it costs nothing and the lookup it depends on may change. cultcache-rs: 53 tests. Co-Authored-By: Claude Opus 5 --- packages/cultcache-rs/src/lib.rs | 149 +++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) diff --git a/packages/cultcache-rs/src/lib.rs b/packages/cultcache-rs/src/lib.rs index 352c5e22..ba7088e5 100644 --- a/packages/cultcache-rs/src/lib.rs +++ b/packages/cultcache-rs/src/lib.rs @@ -284,6 +284,16 @@ pub struct PushAllOptions { pub soft: bool, } +/// One per-entry expectation for [`SingleFileMessagePackBackingStore::compare_exchange`]. +/// `current` is the envelope the caller believes is stored, or `None` when it +/// believes the identity is absent. +#[derive(Clone, Debug, PartialEq)] +pub struct CultCacheExpectedEnvelope { + pub key: String, + pub r#type: String, + pub current: Option, +} + /// Result of one nonblocking whole-snapshot compare-and-exchange. Contention is /// reported rather than waited on, so the caller keeps retry and scheduling /// authority instead of blocking inside the store. @@ -697,6 +707,52 @@ impl SingleFileMessagePackBackingStore { result } + /// Replaces the named entries only if each still matches its expectation. + /// Unlike the snapshot form this constrains only the identities named, so + /// unrelated concurrent writes do not lose the race. + pub fn compare_exchange( + &self, + expected: &[CultCacheExpectedEnvelope], + replacements: &[CultCacheEnvelope], + ) -> Result { + self.with_exclusive_lock(|| { + let mut entries = self.read_all_unlocked()?; + for condition in expected { + let current = entries + .iter() + .find(|entry| entry.r#type == condition.r#type && entry.key == condition.key); + if current != condition.current.as_ref() { + return Ok(false); + } + if let Some(envelope) = condition.current.as_ref() + && (envelope.r#type != condition.r#type || envelope.key != condition.key) + { + return Err(anyhow!( + "CultCache compare-exchange expectation identity differs from its envelope" + )); + } + } + let mut replacement_ids = BTreeSet::new(); + for replacement in replacements { + if replacement.key.trim().is_empty() || replacement.r#type.trim().is_empty() { + return Err(anyhow!( + "CultCache compare-exchange replacement identity is empty" + )); + } + if !replacement_ids.insert(entry_id(replacement)) { + return Err(anyhow!( + "CultCache compare-exchange contains a duplicate replacement" + )); + } + } + entries.retain(|entry| !replacement_ids.contains(&entry_id(entry))); + entries.extend_from_slice(replacements); + entries.sort_by_key(entry_id); + self.write_all_unlocked(&entries)?; + Ok(true) + }) + } + /// Replaces the whole snapshot only if it still equals `expected`, waiting /// for the exclusive lock. Returns false when another writer has moved the /// snapshot on, which is a lost race rather than an error. @@ -4088,4 +4144,97 @@ mod tests { assert_eq!(store.pull_all_read_only_snapshot()?, Vec::new()); Ok(()) } + + #[test] + fn per_entry_exchange_constrains_only_the_identities_it_names() -> Result<()> { + let temp = tempfile::tempdir()?; + let store = SingleFileMessagePackBackingStore::new(temp.path().join("generation.cc")); + + let admitted = snapshot_envelope("admitted", b"one"); + let unrelated = snapshot_envelope("unrelated", b"other"); + assert!(store.compare_exchange( + &[ + CultCacheExpectedEnvelope { + key: "admitted".into(), + r#type: "snapshot.record".into(), + current: None, + }, + CultCacheExpectedEnvelope { + key: "unrelated".into(), + r#type: "snapshot.record".into(), + current: None, + }, + ], + &[admitted.clone(), unrelated.clone()], + )?); + + // The snapshot moved, but an expectation naming only `admitted` still + // holds. A whole-snapshot exchange would have lost this race. + let next = snapshot_envelope("admitted", b"two"); + assert!(store.compare_exchange( + &[CultCacheExpectedEnvelope { + key: "admitted".into(), + r#type: "snapshot.record".into(), + current: Some(admitted.clone()), + }], + &[next.clone()], + )?); + assert_eq!( + store.pull_all_read_only_snapshot()?, + vec![next.clone(), unrelated.clone()] + ); + + // A stale expectation for that identity now loses. + assert!(!store.compare_exchange( + &[CultCacheExpectedEnvelope { + key: "admitted".into(), + r#type: "snapshot.record".into(), + current: Some(admitted), + }], + &[snapshot_envelope("admitted", b"three")], + )?); + assert_eq!(store.pull_all_read_only_snapshot()?, vec![next, unrelated]); + Ok(()) + } + + #[test] + fn per_entry_exchange_distinguishes_absent_from_stored() -> Result<()> { + let temp = tempfile::tempdir()?; + let store = SingleFileMessagePackBackingStore::new(temp.path().join("generation.cc")); + let admitted = snapshot_envelope("admitted", b"one"); + + // Expecting a stored value where nothing is stored must not commit. + assert!(!store.compare_exchange( + &[CultCacheExpectedEnvelope { + key: "admitted".into(), + r#type: "snapshot.record".into(), + current: Some(admitted.clone()), + }], + &[admitted.clone()], + )?); + assert_eq!(store.pull_all_read_only_snapshot()?, Vec::new()); + + // Expecting absence commits the first writer. + assert!(store.compare_exchange( + &[CultCacheExpectedEnvelope { + key: "admitted".into(), + r#type: "snapshot.record".into(), + current: None, + }], + &[admitted.clone()], + )?); + + // And the second writer expecting absence now loses, which is what + // makes this usable as a create-once claim. + assert!(!store.compare_exchange( + &[CultCacheExpectedEnvelope { + key: "admitted".into(), + r#type: "snapshot.record".into(), + current: None, + }], + &[snapshot_envelope("admitted", b"two")], + )?); + assert_eq!(store.pull_all_read_only_snapshot()?, vec![admitted]); + Ok(()) + } } From cbde940df2f5ee0ccac50e8dbfe9f36ffbebb585 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Fri, 4 Sep 2026 03:57:44 +0200 Subject: [PATCH 140/283] Let the advertised profile own each channel's reliable expiry The first pass put the media deadline on the transport options and carried it as a runtime field on the connection and hub. That is a second answer to what a channel does, able to disagree with the profile the peer was actually shown. CultNetTransportChannel now carries reliable_expire_after_ms and the send path resolves the deadline from the profile, so there is one answer. The runtime fields are deleted rather than left as a shadow copy. The transport option remains as the knob that populates the profile, not as a parallel authority. Odin's fork had the field in exactly this place, which is how the gap surfaced: its muninn test reads it off the channel descriptor. This is wire-visible, unlike the rest of the expiry work. The field is optional and skipped when absent, so a profile that does not set it is byte-identical to one from a runtime that has never heard of it -- but the RUDP profile does set it on the media channel, so Rust peers now advertise it. Verified against the interop lane: TypeScript, C# and Kotlin all accept the profile unchanged, in five passing lanes each. The Python lanes cannot run here because this machine's Python runtime has no msgpack, and they fail identically before and after this change. The other four runtimes should grow the field so a profile round-trips through them without losing the channel's declared behaviour. cultnet-rs: 107 tests. Co-Authored-By: Claude Opus 5 --- packages/cultnet-rs/src/contracts.rs | 6 ++++ packages/cultnet-rs/src/rudp.rs | 48 ++++++++++++++++++++++------ packages/cultnet-rs/src/transport.rs | 1 + packages/cultnet-rs/tests/cultnet.rs | 32 +++++++++++++++++++ 4 files changed, 78 insertions(+), 9 deletions(-) diff --git a/packages/cultnet-rs/src/contracts.rs b/packages/cultnet-rs/src/contracts.rs index e637883c..b5c89ff7 100644 --- a/packages/cultnet-rs/src/contracts.rs +++ b/packages/cultnet-rs/src/contracts.rs @@ -142,6 +142,12 @@ pub struct CultNetTransportChannel { pub max_fragment_bytes: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub max_pending_reliable_packets: Option, + /// Drop a reliable packet on this channel instead of retransmitting it once + /// this many milliseconds have passed since the send. Omitted when absent, + /// so a profile that does not set it is byte-identical to one from a + /// runtime that does not know the field. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub reliable_expire_after_ms: Option, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] diff --git a/packages/cultnet-rs/src/rudp.rs b/packages/cultnet-rs/src/rudp.rs index e54cae54..f1fd4ca4 100644 --- a/packages/cultnet-rs/src/rudp.rs +++ b/packages/cultnet-rs/src/rudp.rs @@ -1266,7 +1266,6 @@ pub struct CultNetRudpSocketTransportConnection { max_fragment_bytes: Option, disconnect_reason: Option>, pong_payloads: VecDeque>, - media_reliable_expire_after_ms: Option, } pub struct CultNetRudpServerHubOptions { @@ -1351,7 +1350,6 @@ pub struct CultNetRudpServerHub { max_payload_bytes: usize, max_fragment_bytes: Option, max_peers: usize, - media_reliable_expire_after_ms: Option, next_session_generation: u64, peers: BTreeMap, pending_events: VecDeque, @@ -1373,6 +1371,7 @@ impl CultNetRudpServerHub { let profile = create_rudp_transport_profile( options.runtime_id, RudpTransportProfileOptions { + media_reliable_expire_after_ms: options.media_reliable_expire_after_ms, transport_id: options.transport_id, host: Some(local_addr.ip().to_string()), port: Some(local_addr.port()), @@ -1383,7 +1382,6 @@ impl CultNetRudpServerHub { }, ); Ok(Self { - media_reliable_expire_after_ms: options.media_reliable_expire_after_ms, socket: options.socket, connection_id: options.connection_id, initial_sequence: options.initial_sequence, @@ -1449,7 +1447,11 @@ impl CultNetRudpServerHub { peer.session.send_many( channel_id, payload, - channel_send_options(channel_id, now_ms(), self.media_reliable_expire_after_ms), + channel_send_options( + channel_id, + now_ms(), + channel_reliable_expire_after_ms(&self.profile, channel_id), + ), self.max_fragment_bytes, )? }; @@ -1668,6 +1670,7 @@ impl CultNetRudpSocketTransportConnection { let profile = create_rudp_transport_profile( options.runtime_id, RudpTransportProfileOptions { + media_reliable_expire_after_ms: options.media_reliable_expire_after_ms, transport_id: options.transport_id, host: Some(local_addr.ip().to_string()), port: Some(local_addr.port()), @@ -1688,7 +1691,6 @@ impl CultNetRudpSocketTransportConnection { }); session.set_max_payload_bytes(max_payload_bytes.map(|value| value as usize)); Ok(Self { - media_reliable_expire_after_ms: options.media_reliable_expire_after_ms, socket: options.socket, session, mode: options.mode, @@ -1732,7 +1734,11 @@ impl CultNetRudpSocketTransportConnection { pub fn send(&mut self, channel_id: &str, payload: Vec) -> Result<()> { let options = - channel_send_options(channel_id, now_ms(), self.media_reliable_expire_after_ms); + channel_send_options( + channel_id, + now_ms(), + channel_reliable_expire_after_ms(&self.profile, channel_id), + ); let packets = self.session .send_many(channel_id, payload, options, self.max_fragment_bytes)?; @@ -1749,7 +1755,11 @@ impl CultNetRudpSocketTransportConnection { payload: Vec, ) -> Result { let options = - channel_send_options(channel_id, now_ms(), self.media_reliable_expire_after_ms); + channel_send_options( + channel_id, + now_ms(), + channel_reliable_expire_after_ms(&self.profile, channel_id), + ); // This lineage has no reliable-expiry concept, so every reliable channel is // already non-expiring. Restore the expiry half of this guard if one is added. if !options.reliable { @@ -2062,6 +2072,7 @@ pub struct RudpTransportProfileOptions { pub max_fragment_bytes: Option, pub max_pending_reliable_packets: Option, pub reconnect_policy: Option, + pub media_reliable_expire_after_ms: Option, } pub fn create_rudp_transport_profile( @@ -2092,6 +2103,7 @@ pub fn create_rudp_transport_profile( max_payload_bytes: options.max_payload_bytes, max_fragment_bytes: options.max_fragment_bytes, max_pending_reliable_packets: options.max_pending_reliable_packets, + reliable_expire_after_ms: None, }, CultNetTransportChannel { channel_id: "latest".to_string(), @@ -2100,6 +2112,7 @@ pub fn create_rudp_transport_profile( max_payload_bytes: options.max_payload_bytes, max_fragment_bytes: options.max_fragment_bytes, max_pending_reliable_packets: options.max_pending_reliable_packets, + reliable_expire_after_ms: None, }, CultNetTransportChannel { channel_id: "realtime".to_string(), @@ -2108,6 +2121,7 @@ pub fn create_rudp_transport_profile( max_payload_bytes: options.max_payload_bytes, max_fragment_bytes: options.max_fragment_bytes, max_pending_reliable_packets: options.max_pending_reliable_packets, + reliable_expire_after_ms: None, }, CultNetTransportChannel { channel_id: "media".to_string(), @@ -2116,6 +2130,7 @@ pub fn create_rudp_transport_profile( max_payload_bytes: options.max_payload_bytes, max_fragment_bytes: options.max_fragment_bytes, max_pending_reliable_packets: options.max_pending_reliable_packets, + reliable_expire_after_ms: options.media_reliable_expire_after_ms, }, ], }], @@ -2224,10 +2239,25 @@ fn packet_type_to_code(packet_type: CultNetRudpPacketType) -> u8 { } } +/// The advertised profile owns each channel's expiry. Resolving it here keeps +/// one answer for what a channel does, rather than a runtime field that can +/// disagree with the profile the peer was shown. +fn channel_reliable_expire_after_ms( + profile: &CultNetTransportProfile, + channel_id: &str, +) -> Option { + profile + .transports + .iter() + .flat_map(|transport| transport.channels.iter()) + .find(|channel| channel.channel_id == channel_id) + .and_then(|channel| channel.reliable_expire_after_ms) +} + fn channel_send_options( channel_id: &str, now_ms: u64, - media_reliable_expire_after_ms: Option, + reliable_expire_after_ms: Option, ) -> CultNetRudpSendOptions { match channel_id { "schema" => CultNetRudpSendOptions { @@ -2249,7 +2279,7 @@ fn channel_send_options( ordered: false, sequenced: false, now_ms, - reliable_expire_after_ms: media_reliable_expire_after_ms, + reliable_expire_after_ms, }, _ => CultNetRudpSendOptions { reliable: false, diff --git a/packages/cultnet-rs/src/transport.rs b/packages/cultnet-rs/src/transport.rs index f10ad87d..cf28079e 100644 --- a/packages/cultnet-rs/src/transport.rs +++ b/packages/cultnet-rs/src/transport.rs @@ -204,6 +204,7 @@ pub fn create_tcp_framed_transport_profile( max_payload_bytes: options.max_payload_bytes, max_fragment_bytes: options.max_fragment_bytes, max_pending_reliable_packets: None, + reliable_expire_after_ms: None, }], }], } diff --git a/packages/cultnet-rs/tests/cultnet.rs b/packages/cultnet-rs/tests/cultnet.rs index de84d2d9..851646cf 100644 --- a/packages/cultnet-rs/tests/cultnet.rs +++ b/packages/cultnet-rs/tests/cultnet.rs @@ -258,6 +258,7 @@ fn cultnet_schema_messages_round_trip_through_messagepack_frames() -> Result<()> max_payload_bytes: None, max_fragment_bytes: None, max_pending_reliable_packets: None, + reliable_expire_after_ms: None, }], }], }]), @@ -365,6 +366,7 @@ fn rudp_transport_profile_advertises_state_and_realtime_channels() { max_fragment_bytes: Some(1000), max_pending_reliable_packets: Some(64), reconnect_policy: None, + media_reliable_expire_after_ms: None, }, ); @@ -2817,3 +2819,33 @@ fn accept_rudp_session(session: &mut CultNetRudpSession, connection_id: u32) -> )?; Ok(()) } + +#[test] +fn rudp_profile_expires_only_the_media_channel() -> Result<()> { + let socket = std::net::UdpSocket::bind("127.0.0.1:0")?; + let peer = socket.local_addr()?; + let options = CultNetRudpSocketTransportOptions::client("expiry-profile", socket, peer, 11); + let connection = CultNetRudpSocketTransportConnection::new(options)?; + + let channels = connection + .profile + .transports + .iter() + .flat_map(|transport| transport.channels.iter()) + .map(|channel| (channel.channel_id.as_str(), channel.reliable_expire_after_ms)) + .collect::>(); + + assert!( + channels.contains(&("media", Some(75))), + "the media channel advertises its expiry so a peer can see it: {channels:?}" + ); + for (channel_id, expiry) in &channels { + if *channel_id != "media" { + assert_eq!( + *expiry, None, + "state channel {channel_id} must never expire a reliable send" + ); + } + } + Ok(()) +} From e171eca32329baa928f4a1d810401a8b4c857029 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Fri, 4 Sep 2026 04:15:59 +0200 Subject: [PATCH 141/283] Expose what the consumer forks had to reach for Surveying the swarm's vendored copies, the divergence is far smaller than the number of forks suggests. Against CultLib, Epiphany's CultCache holds nothing unique, CodexConnector's holds nothing, VoidBot's CultCache-TS holds nothing, and Ghostlight's CultCache-Py holds nothing. What the forks did hold was mostly reach: things CultLib has but does not expose. raw_document_record_from_envelope was private here and public in every Rust consumer fork. It is public now. A first pass called it missing, which was a visibility difference read as an absence -- a `pub fn` scan cannot tell those apart. CultMesh gains get_all_with_keys and soa, thin delegations to CultCache, which does support both. Those were genuinely absent rather than hidden. cultmesh-rs also needed the media expiry field on its document transports; it was not rebuilt when cultnet-rs grew that field because the earlier pass tested only two of the three Rust packages. cultcache-rs 53, cultnet-rs 107, cultmesh-rs 7. Co-Authored-By: Claude Opus 5 --- packages/cultmesh-rs/src/lib.rs | 12 ++++++++++++ packages/cultnet-rs/src/replication.rs | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/cultmesh-rs/src/lib.rs b/packages/cultmesh-rs/src/lib.rs index 5adbb53f..e460ac78 100644 --- a/packages/cultmesh-rs/src/lib.rs +++ b/packages/cultmesh-rs/src/lib.rs @@ -1,7 +1,9 @@ use anyhow::{Context, Result}; use cultcache_rs::CultCache; use cultcache_rs::CultCacheEnvelope; +use cultcache_rs::CultSoaTable; use cultcache_rs::DatabaseEntry; +use cultcache_rs::SoaDocument; use cultcache_rs::SingleFileMessagePackBackingStore; use cultnet_rs::CultNetDocumentPutOptions; use cultnet_rs::CultNetDocumentRegistry; @@ -637,6 +639,14 @@ impl CultMeshNode { self.cache.get_required::(key) } + pub fn get_all_with_keys(&self) -> Result> { + self.cache.get_all_with_keys::() + } + + pub fn soa(&self) -> Result> { + self.cache.soa::() + } + pub fn put(&mut self, key: impl Into, value: &T) -> Result { self.cache.put(key, value) } @@ -762,6 +772,7 @@ fn request_raw_snapshot_from_rudp_catalog( socket.set_read_timeout(Some(options.poll_interval))?; let mut client = CultNetRudpSocketTransportConnection::new(CultNetRudpSocketTransportOptions { + media_reliable_expire_after_ms: None, runtime_id: options.runtime_id.clone(), socket, mode: cultnet_rs::CultNetRudpSocketMode::Client, @@ -860,6 +871,7 @@ pub fn publish_cultnet_messages_to_rudp_catalog( socket.set_read_timeout(Some(options.poll_interval))?; let mut client = CultNetRudpSocketTransportConnection::new(CultNetRudpSocketTransportOptions { + media_reliable_expire_after_ms: None, runtime_id: options.runtime_id.clone(), socket, mode: cultnet_rs::CultNetRudpSocketMode::Client, diff --git a/packages/cultnet-rs/src/replication.rs b/packages/cultnet-rs/src/replication.rs index d02a141f..7073f1a9 100644 --- a/packages/cultnet-rs/src/replication.rs +++ b/packages/cultnet-rs/src/replication.rs @@ -540,7 +540,7 @@ impl CultNetDocumentRegistry { }) } - fn raw_document_record_from_envelope( + pub fn raw_document_record_from_envelope( &self, envelope: &CultCacheEnvelope, ) -> Result { From 8cb3b7282b62129d23e6e5bd58bc7060f8ae7a8b Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Fri, 4 Sep 2026 04:41:44 +0200 Subject: [PATCH 142/283] Publish the non-Rust packages and make the licensing uniform Rust consumers pin a CultLib revision through cargo git dependencies, which is how Ghostlight, Epiphany, CodexConnector and Odin already consume the core stack. npm and pip cannot take a package from a subdirectory of a git repo at all, which is why the TypeScript and Python consumers vendored forks instead: there was nothing else to depend on. This gives them a versioned artifact. Tagging cultcache-ts-v* or cultcache-py-v* builds, tests and publishes. The tag version must match the manifest version or the workflow refuses rather than shipping a mislabelled artifact. PyPI uses trusted publishing, so no long-lived token is stored; npm needs an NPM_TOKEN secret. cultcache-ts is now @gamecult/cultcache-ts. The scope is not cosmetic: it makes the package unambiguously org-owned on a public registry, and it is what lets CultLib hold the name rather than racing for an unscoped one. CultLib's own cultmesh-ts and cultnet-ts and their imports move with it; all three packages typecheck and cultcache-ts passes 12 of 13 tests, the exception being the cross-runtime store test that shells out to Python, which cannot run on this machine because its Python has no msgpack. Licensing was inconsistent with the repo. cultcache-py declared itself "Private GameCult infrastructure" and cultcache-rs and cultmesh-rs declared nothing, inside a repo whose LICENSE is MIT and whose every other package says MIT. All three now say MIT. That was load-bearing here: a package that calls itself private is not one to push to a public registry. Co-Authored-By: Claude Opus 5 --- .github/workflows/publish-packages.yml | 114 ++++++++++++++++++ package-lock.json | 15 +-- packages/cultcache-py/pyproject.toml | 3 +- packages/cultcache-rs/Cargo.toml | 1 + packages/cultcache-ts/package.json | 2 +- packages/cultmesh-rs/Cargo.toml | 1 + packages/cultmesh-ts/package.json | 2 +- packages/cultmesh-ts/src/index.ts | 2 +- packages/cultmesh-ts/test/cultmesh.test.ts | 2 +- packages/cultnet-ts/package.json | 2 +- .../cultnet-ts/src/json-schema-contract.ts | 2 +- packages/cultnet-ts/src/replication.ts | 2 +- packages/cultnet-ts/test/cultnet.test.ts | 2 +- .../test/interop/cultnet-interop-peer.ts | 2 +- 14 files changed, 135 insertions(+), 17 deletions(-) create mode 100644 .github/workflows/publish-packages.yml diff --git a/.github/workflows/publish-packages.yml b/.github/workflows/publish-packages.yml new file mode 100644 index 00000000..f92868aa --- /dev/null +++ b/.github/workflows/publish-packages.yml @@ -0,0 +1,114 @@ +name: Publish packages + +# Non-Rust consumers cannot take a package from a subdirectory of a git repo the +# way cargo can, which is why they ended up vendoring forks instead. This gives +# them a versioned artifact to depend on so CultLib stays the only source. +# +# Rust needs nothing here: cargo git dependencies pin a CultLib revision +# directly, which is already how Ghostlight, Epiphany, CodexConnector and Odin +# consume the core stack. +# +# Tag a release to publish, for example `cultcache-ts-v0.13.6`. The tag's +# version must match the version in the package manifest; the workflow refuses +# the publish otherwise rather than shipping a mislabelled artifact. + +on: + push: + tags: + - "cultcache-ts-v*" + - "cultcache-py-v*" + workflow_dispatch: + inputs: + package: + description: Package to build and test (publishes nothing on manual runs) + required: true + type: choice + options: + - cultcache-ts + - cultcache-py + +permissions: + contents: read + +jobs: + cultcache-ts: + name: "@gamecult/cultcache-ts to npm" + if: startsWith(github.ref, 'refs/tags/cultcache-ts-v') || inputs.package == 'cultcache-ts' + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - name: Check out CultLib + uses: actions/checkout@v4 + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: 24.x + registry-url: https://registry.npmjs.org + + - name: Install workspace dependencies + run: npm ci + + - name: Verify the tag matches the manifest version + if: startsWith(github.ref, 'refs/tags/cultcache-ts-v') + run: | + manifest="$(node -p "require('./packages/cultcache-ts/package.json').version")" + tagged="${GITHUB_REF_NAME#cultcache-ts-v}" + if [ "$manifest" != "$tagged" ]; then + echo "tag $GITHUB_REF_NAME does not match manifest version $manifest" >&2 + exit 1 + fi + + - name: Build and test + working-directory: packages/cultcache-ts + run: npm test + + # Scoped packages default to restricted even on public npm, and this is + # MIT like the rest of the repo, so say public explicitly. + - name: Publish + if: startsWith(github.ref, 'refs/tags/cultcache-ts-v') + working-directory: packages/cultcache-ts + run: npm publish --access public + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + cultcache-py: + name: cultcache-py to PyPI + if: startsWith(github.ref, 'refs/tags/cultcache-py-v') || inputs.package == 'cultcache-py' + runs-on: ubuntu-latest + timeout-minutes: 20 + environment: pypi + permissions: + contents: read + # PyPI trusted publishing exchanges this for a short-lived token, so no + # long-lived API token is stored in the repository. + id-token: write + steps: + - name: Check out CultLib + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Verify the tag matches the manifest version + if: startsWith(github.ref, 'refs/tags/cultcache-py-v') + run: | + manifest="$(python -c "import tomllib,pathlib;print(tomllib.loads(pathlib.Path('packages/cultcache-py/pyproject.toml').read_text())['project']['version'])")" + tagged="${GITHUB_REF_NAME#cultcache-py-v}" + if [ "$manifest" != "$tagged" ]; then + echo "tag $GITHUB_REF_NAME does not match manifest version $manifest" >&2 + exit 1 + fi + + - name: Build sdist and wheel + run: | + python -m pip install --upgrade build + python -m build packages/cultcache-py + + - name: Publish + if: startsWith(github.ref, 'refs/tags/cultcache-py-v') + uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: packages/cultcache-py/dist diff --git a/package-lock.json b/package-lock.json index b105fb5c..391f8dfe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -478,6 +478,10 @@ "node": ">=18" } }, + "node_modules/@gamecult/cultcache-ts": { + "resolved": "packages/cultcache-ts", + "link": true + }, "node_modules/@jsdevtools/ono": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", @@ -541,10 +545,6 @@ "dev": true, "license": "Python-2.0" }, - "node_modules/cultcache-ts": { - "resolved": "packages/cultcache-ts", - "link": true - }, "node_modules/cultmesh-browser": { "resolved": "packages/cultmesh-browser", "link": true @@ -831,6 +831,7 @@ } }, "packages/cultcache-ts": { + "name": "@gamecult/cultcache-ts", "version": "0.13.5", "license": "MIT", "dependencies": { @@ -864,8 +865,8 @@ "version": "0.1.1", "license": "MIT", "dependencies": { + "@gamecult/cultcache-ts": "^0.13.5", "@msgpack/msgpack": "^3.1.2", - "cultcache-ts": "^0.13.5", "cultnet-ts": "^0.2.0" }, "devDependencies": { @@ -881,9 +882,9 @@ "version": "0.2.0", "license": "MIT", "dependencies": { + "@gamecult/cultcache-ts": "^0.13.5", "@msgpack/msgpack": "^3.1.3", - "ajv": "^8.17.1", - "cultcache-ts": "^0.13.5" + "ajv": "^8.17.1" }, "devDependencies": { "@types/node": "^24.0.0", diff --git a/packages/cultcache-py/pyproject.toml b/packages/cultcache-py/pyproject.toml index 93ebf849..9f515ac2 100644 --- a/packages/cultcache-py/pyproject.toml +++ b/packages/cultcache-py/pyproject.toml @@ -8,9 +8,10 @@ version = "0.1.0" description = "Python CultCache, CultNet, and CultMesh runtime package for GameCult typed state." readme = "README.md" requires-python = ">=3.10" -license = { text = "Private GameCult infrastructure" } +license = "MIT" authors = [{ name = "GameCult" }] classifiers = [ + "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", diff --git a/packages/cultcache-rs/Cargo.toml b/packages/cultcache-rs/Cargo.toml index e6ec5e59..6ca593bc 100644 --- a/packages/cultcache-rs/Cargo.toml +++ b/packages/cultcache-rs/Cargo.toml @@ -2,6 +2,7 @@ name = "cultcache-rs" version = "0.1.0" edition = "2024" +license = "MIT" publish = false [workspace] diff --git a/packages/cultcache-ts/package.json b/packages/cultcache-ts/package.json index b9df4300..93db0237 100644 --- a/packages/cultcache-ts/package.json +++ b/packages/cultcache-ts/package.json @@ -1,5 +1,5 @@ { - "name": "cultcache-ts", + "name": "@gamecult/cultcache-ts", "version": "0.13.5", "description": "CultCache-style typed persistence for TypeScript with schema-backed polymorphic MessagePack storage.", "main": "dist/index.js", diff --git a/packages/cultmesh-rs/Cargo.toml b/packages/cultmesh-rs/Cargo.toml index 9a719d32..820050c3 100644 --- a/packages/cultmesh-rs/Cargo.toml +++ b/packages/cultmesh-rs/Cargo.toml @@ -2,6 +2,7 @@ name = "cultmesh-rs" version = "0.1.0" edition = "2024" +license = "MIT" publish = false [lib] diff --git a/packages/cultmesh-ts/package.json b/packages/cultmesh-ts/package.json index 58a3c159..eff7fec4 100644 --- a/packages/cultmesh-ts/package.json +++ b/packages/cultmesh-ts/package.json @@ -43,7 +43,7 @@ }, "dependencies": { "@msgpack/msgpack": "^3.1.2", - "cultcache-ts": "^0.13.5", + "@gamecult/cultcache-ts": "^0.13.5", "cultnet-ts": "^0.2.0" }, "devDependencies": { diff --git a/packages/cultmesh-ts/src/index.ts b/packages/cultmesh-ts/src/index.ts index 2ed6e4b7..5cf26466 100644 --- a/packages/cultmesh-ts/src/index.ts +++ b/packages/cultmesh-ts/src/index.ts @@ -8,7 +8,7 @@ import { type CacheBackingStore, type CultCacheEnvelope, type CultCacheDocumentValue, -} from "cultcache-ts"; +} from "@gamecult/cultcache-ts"; import { CultNetDocumentRegistry, CultNetRudpSession, diff --git a/packages/cultmesh-ts/test/cultmesh.test.ts b/packages/cultmesh-ts/test/cultmesh.test.ts index 07ac0559..16d51e1e 100644 --- a/packages/cultmesh-ts/test/cultmesh.test.ts +++ b/packages/cultmesh-ts/test/cultmesh.test.ts @@ -5,7 +5,7 @@ import test from "node:test"; import assert from "node:assert/strict"; import { encode } from "@msgpack/msgpack"; import { z } from "zod"; -import { defineDocumentType } from "cultcache-ts"; +import { defineDocumentType } from "@gamecult/cultcache-ts"; import { CultNetDocumentRegistry, CultNetPeer, diff --git a/packages/cultnet-ts/package.json b/packages/cultnet-ts/package.json index df129a42..5f87eccc 100644 --- a/packages/cultnet-ts/package.json +++ b/packages/cultnet-ts/package.json @@ -53,7 +53,7 @@ "dependencies": { "@msgpack/msgpack": "^3.1.3", "ajv": "^8.17.1", - "cultcache-ts": "^0.13.5" + "@gamecult/cultcache-ts": "^0.13.5" }, "devDependencies": { "@types/node": "^24.0.0", diff --git a/packages/cultnet-ts/src/json-schema-contract.ts b/packages/cultnet-ts/src/json-schema-contract.ts index b97a6762..4d8fb85d 100644 --- a/packages/cultnet-ts/src/json-schema-contract.ts +++ b/packages/cultnet-ts/src/json-schema-contract.ts @@ -1,5 +1,5 @@ import Ajv2020, { type ErrorObject, type ValidateFunction } from "ajv/dist/2020"; -import type { CultCacheSchema } from "cultcache-ts"; +import type { CultCacheSchema } from "@gamecult/cultcache-ts"; export interface JsonSchemaContract extends CultCacheSchema { readonly schemaId: string; diff --git a/packages/cultnet-ts/src/replication.ts b/packages/cultnet-ts/src/replication.ts index d5706bea..77dab70f 100644 --- a/packages/cultnet-ts/src/replication.ts +++ b/packages/cultnet-ts/src/replication.ts @@ -6,7 +6,7 @@ import type { CultCacheDocumentFormatter, CultCacheDocumentValue, CultCacheEnvelope, -} from "cultcache-ts"; +} from "@gamecult/cultcache-ts"; import { type CultNetDocumentDeleteMessage, diff --git a/packages/cultnet-ts/test/cultnet.test.ts b/packages/cultnet-ts/test/cultnet.test.ts index 7ffbafb9..f0c3c3c3 100644 --- a/packages/cultnet-ts/test/cultnet.test.ts +++ b/packages/cultnet-ts/test/cultnet.test.ts @@ -12,7 +12,7 @@ import { CultCache, SingleFileMessagePackBackingStore, defineDocumentType, -} from "cultcache-ts"; +} from "@gamecult/cultcache-ts"; import { CultNetClientSecurityOptions, diff --git a/packages/cultnet-ts/test/interop/cultnet-interop-peer.ts b/packages/cultnet-ts/test/interop/cultnet-interop-peer.ts index 0af43301..57b7fa37 100644 --- a/packages/cultnet-ts/test/interop/cultnet-interop-peer.ts +++ b/packages/cultnet-ts/test/interop/cultnet-interop-peer.ts @@ -6,7 +6,7 @@ import process from "node:process"; import { setTimeout as delay } from "node:timers/promises"; import { decode, encode } from "@msgpack/msgpack"; -import { CultCache, SingleFileMessagePackBackingStore, defineDocumentType, type AnyCultCacheDocumentDefinition } from "cultcache-ts"; +import { CultCache, SingleFileMessagePackBackingStore, defineDocumentType, type AnyCultCacheDocumentDefinition } from "@gamecult/cultcache-ts"; import { CultNetDocumentRegistry, CultNetPeer, From 77313ed48cdc219313fc5594c872b4f1ac9eaac3 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Fri, 4 Sep 2026 16:32:10 +0200 Subject: [PATCH 143/283] Stop the interop harness leaking peers and hanging after it passes The suite finished its work in about 60 seconds and then never exited. Four runs were left alive for hours, holding 11 node and 2 dotnet peers, and a stranded peer holding cultnet_interop_peer.exe is what made two unrelated cargo builds fail with LNK1104. In CI this is a job that burns its whole timeout on green tests. Two real defects, found by asking the stuck process what it was waiting on rather than by guessing. process.getActiveResourcesInfo reported four UDPWraps and two PipeWraps still held after the last test. The four UDP sockets: eight tests bind a server socket with bindUdpSocket and close only the transport wrapper in their finally, never the socket itself. Four leaked per run, matching the four Python lanes that fail on a machine without msgpack -- the wrapper is built inside the try, so when the peer's readiness rejects it never exists to be closed, and the raw socket is orphaned. Now closed through a guarded helper that tolerates a transport having adopted it. The teardown registration: t.after was registered after every `await ready`, so a peer whose readiness rejected skipped the registration entirely and stranded every peer already spawned. Moved ahead of the spawns at all four sites. With those fixed the suite still does not drain on its own, so test:interop now passes --test-force-exit. That is safe only because cleanup demonstrably completes first: a forced run now leaves zero peers behind, where before it left nine. Forcing the exit without the fixes above would have guaranteed orphans rather than prevented them. Verified: 65 seconds, exit 1, the expected 15 pass and 12 fail, no surviving processes. The 12 failures are the Python lanes, which cannot run on this machine and are unrelated. Co-Authored-By: Claude Opus 5 --- packages/cultnet-ts/package.json | 2 +- .../test/interop/cultnet-interop.test.ts | 62 ++++++++++++++----- 2 files changed, 47 insertions(+), 17 deletions(-) diff --git a/packages/cultnet-ts/package.json b/packages/cultnet-ts/package.json index 5f87eccc..f94f0bfa 100644 --- a/packages/cultnet-ts/package.json +++ b/packages/cultnet-ts/package.json @@ -26,7 +26,7 @@ "prepack": "node tools/generate-swarm-contracts.mjs && node ../../node_modules/typescript/bin/tsc -p tsconfig.json", "typecheck": "node tools/generate-swarm-contracts.mjs && node ../../node_modules/typescript/bin/tsc -p tsconfig.json --pretty false", "test": "node tools/generate-swarm-contracts.mjs && node ../../node_modules/typescript/bin/tsc -p tsconfig.json && node ../../node_modules/typescript/bin/tsc -p tsconfig.test.json && node --test dist-test/test/*.test.js", - "test:interop": "node tools/generate-swarm-contracts.mjs && node ../../node_modules/typescript/bin/tsc -p tsconfig.json && node ../../node_modules/typescript/bin/tsc -p tsconfig.test.json && node --test dist-test/test/interop/*.test.js" + "test:interop": "node tools/generate-swarm-contracts.mjs && node ../../node_modules/typescript/bin/tsc -p tsconfig.json && node ../../node_modules/typescript/bin/tsc -p tsconfig.test.json && node --test --test-force-exit dist-test/test/interop/*.test.js" }, "keywords": [ "messagepack", diff --git a/packages/cultnet-ts/test/interop/cultnet-interop.test.ts b/packages/cultnet-ts/test/interop/cultnet-interop.test.ts index bec86942..4353e132 100644 --- a/packages/cultnet-ts/test/interop/cultnet-interop.test.ts +++ b/packages/cultnet-ts/test/interop/cultnet-interop.test.ts @@ -414,6 +414,12 @@ test("CultNet TS/Rust/C#/Python peers discover each other and exchange raw state const advertiseHost = findAdvertiseHost(); const servers: RunningServeProcess[] = []; + // Registered before anything is spawned. A peer whose readiness rejects + // would otherwise skip this and strand every peer already running. + t.after(async () => { + await Promise.all(servers.map(stopProcess)); + }); + logInteropPhase("schema-v0", "start rust peer"); servers.push(await spawnServeProcess("rust", { command: rustBinaryPath, @@ -498,10 +504,6 @@ test("CultNet TS/Rust/C#/Python peers discover each other and exchange raw state })); await servers[servers.length - 1].ready; - t.after(async () => { - await Promise.all(servers.map(stopProcess)); - }); - logInteropPhase("schema-v0", "typescript dials rust"); const tsDial = await runJsonCommand("ts-dial", process.execPath, [ tsPeerScript, @@ -989,6 +991,12 @@ test("CultNet TypeScript and Rust full interop peers exchange schema-v0 over RUD const discoveryPort = await getFreePort(); const advertiseHost = findAdvertiseHost(); const servers: RunningServeProcess[] = []; + // Registered before anything is spawned. A peer whose readiness rejects + // would otherwise skip this and strand every peer already running. + t.after(async () => { + await Promise.all(servers.map(stopProcess)); + }); + servers.push(await spawnServeProcess("rust-rudp", { command: rustBinaryPath, args: [ @@ -1030,10 +1038,6 @@ test("CultNet TypeScript and Rust full interop peers exchange schema-v0 over RUD })); await servers[servers.length - 1].ready; - t.after(async () => { - await Promise.all(servers.map(stopProcess)); - }); - logInteropPhase("ts-rust-full-rudp", "typescript dials rust over rudp"); const tsRudpDial = await runJsonCommand("ts-rust-rudp-dial", process.execPath, [ tsPeerScript, @@ -1139,6 +1143,7 @@ test("CultNet Python and TypeScript exchange schema frames when Python dials a T assert.equal(exitCode, 0, pythonClient.stderr.join("")); } finally { server.close(); + closeUdpSocket(serverSocket); if (pythonClient.child.exitCode === null && !pythonClient.child.killed) { pythonClient.child.kill("SIGTERM"); await once(pythonClient.child, "exit").catch(() => undefined); @@ -1246,6 +1251,7 @@ test("CultNet Python and TypeScript exchange schema-v0 MessagePack messages over assert.equal(exitCode, 0, pythonClient.stderr.join("")); } finally { server.close(); + closeUdpSocket(serverSocket); if (pythonClient.child.exitCode === null && !pythonClient.child.killed) { pythonClient.child.kill("SIGTERM"); await once(pythonClient.child, "exit").catch(() => undefined); @@ -1322,6 +1328,7 @@ test("CultNet Rust and TypeScript exchange schema frames when Rust dials a TypeS assert.equal(exitCode, 0, rustClient.stderr.join("")); } finally { server.close(); + closeUdpSocket(serverSocket); if (rustClient.child.exitCode === null && !rustClient.child.killed) { rustClient.child.kill("SIGTERM"); await once(rustClient.child, "exit").catch(() => undefined); @@ -1431,6 +1438,7 @@ test("CultNet Rust and TypeScript exchange schema-v0 MessagePack messages over R assert.equal(exitCode, 0, rustClient.stderr.join("")); } finally { server.close(); + closeUdpSocket(serverSocket); if (rustClient.child.exitCode === null && !rustClient.child.killed) { rustClient.child.kill("SIGTERM"); await once(rustClient.child, "exit").catch(() => undefined); @@ -1507,6 +1515,7 @@ test("CultNet C# and TypeScript exchange schema frames when C# dials a TypeScrip assert.equal(exitCode, 0, csharpClient.stderr.join("")); } finally { server.close(); + closeUdpSocket(serverSocket); if (csharpClient.child.exitCode === null && !csharpClient.child.killed) { csharpClient.child.kill("SIGTERM"); await once(csharpClient.child, "exit").catch(() => undefined); @@ -1616,6 +1625,7 @@ test("CultNet C# and TypeScript exchange schema-v0 MessagePack messages over RUD assert.equal(exitCode, 0, csharpClient.stderr.join("")); } finally { server.close(); + closeUdpSocket(serverSocket); if (csharpClient.child.exitCode === null && !csharpClient.child.killed) { csharpClient.child.kill("SIGTERM"); await once(csharpClient.child, "exit").catch(() => undefined); @@ -1692,6 +1702,7 @@ test("CultNet Kotlin and TypeScript exchange schema frames when Kotlin dials a T assert.equal(exitCode, 0, kotlinClient.stderr.join("")); } finally { server.close(); + closeUdpSocket(serverSocket); if (kotlinClient.child.exitCode === null && !kotlinClient.child.killed) { kotlinClient.child.kill("SIGTERM"); await once(kotlinClient.child, "exit").catch(() => undefined); @@ -1801,6 +1812,7 @@ test("CultNet Kotlin and TypeScript exchange schema-v0 MessagePack messages over assert.equal(exitCode, 0, kotlinClient.stderr.join("")); } finally { server.close(); + closeUdpSocket(serverSocket); if (kotlinClient.child.exitCode === null && !kotlinClient.child.killed) { kotlinClient.child.kill("SIGTERM"); await once(kotlinClient.child, "exit").catch(() => undefined); @@ -1823,6 +1835,12 @@ test("CultNet TypeScript and C# full interop peers exchange schema-v0 over RUDP" const discoveryPort = await getFreePort(); const advertiseHost = findAdvertiseHost(); const servers: RunningServeProcess[] = []; + // Registered before anything is spawned. A peer whose readiness rejects + // would otherwise skip this and strand every peer already running. + t.after(async () => { + await Promise.all(servers.map(stopProcess)); + }); + servers.push(await spawnServeProcess("csharp-rudp", { command: dotnetCommand, args: [ @@ -1865,10 +1883,6 @@ test("CultNet TypeScript and C# full interop peers exchange schema-v0 over RUDP" })); await servers[servers.length - 1].ready; - t.after(async () => { - await Promise.all(servers.map(stopProcess)); - }); - logInteropPhase("ts-csharp-full-rudp", "typescript dials csharp over rudp"); const tsRudpDial = await runJsonCommand("ts-csharp-rudp-dial", process.execPath, [ tsPeerScript, @@ -1923,6 +1937,12 @@ test("CultNet TypeScript and Kotlin full interop peers exchange schema-v0 over R const discoveryPort = await getFreePort(); const advertiseHost = findAdvertiseHost(); const servers: RunningServeProcess[] = []; + // Registered before anything is spawned. A peer whose readiness rejects + // would otherwise skip this and strand every peer already running. + t.after(async () => { + await Promise.all(servers.map(stopProcess)); + }); + servers.push(await spawnServeProcess("kotlin-rudp", { command: kotlinJavaCommand, args: [ @@ -1966,10 +1986,6 @@ test("CultNet TypeScript and Kotlin full interop peers exchange schema-v0 over R })); await servers[servers.length - 1].ready; - t.after(async () => { - await Promise.all(servers.map(stopProcess)); - }); - logInteropPhase("ts-kotlin-full-rudp", "typescript dials kotlin over rudp"); const tsRudpDial = await runJsonCommand("ts-kotlin-rudp-dial", process.execPath, [ tsPeerScript, @@ -3160,6 +3176,20 @@ function spawnRustRudpMessageClient(remotePort: number): Omit { const socket = dgram.createSocket("udp4"); await new Promise((resolveBind, rejectBind) => { From ae0ac0d3c92ccaee1a7eee2bbe033740c9ea2e55 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sat, 5 Sep 2026 17:26:44 +0200 Subject: [PATCH 144/283] Reconcile cultmesh-rs: adopt Odin's lineage, keep CultLib's additions CultLib's packages/cultmesh-rs and Odin's vendor/cultmesh-rs had diverged independently -- 87 shared symbols, 6 only here, 9 only there. Neither was simply ahead of the other, so this is a merge rather than a fast-forward. Odin's copy is the base because it is the deployed code, running in production via Idunn, and because it carries a deliberate semantic upgrade: connection_id was replaced by a per-request message_id correlation with validation requiring raw callers to supply one. That brings in the RUDP document server (647 lines) and its tests (553), which the original migration into CultLib left behind. Layered back in from CultLib's lineage: soa(), get_all_with_keys(), create_rudp_document_message(), and the plural batch publisher. The batch function was rewritten off the removed connection_id onto the connect helper. Both publish paths survive deliberately. They are different jobs, not rival implementations: the singular path polls one receipt for application-level acknowledgement and can report Invalidated, while the batch path sends and then flushes at the transport level. That is also why the census framed the 30s-versus-300ms flush_timeout as a value conflict and was wrong -- one field name, two mechanisms. The distinction is now documented at the call site. Surviving connection_id references are the RUDP protocol's own connection epoch and are unrelated to the removed options field. cargo test: 16 passed, 0 failed -- 10 lib, 6 document-server integration. Co-Authored-By: Claude Opus 5 --- packages/cultmesh-rs/src/lib.rs | 568 ++++++++++----- .../cultmesh-rs/src/rudp_document_server.rs | 647 ++++++++++++++++++ .../cultmesh-rs/tests/rudp_document_server.rs | 554 +++++++++++++++ 3 files changed, 1602 insertions(+), 167 deletions(-) create mode 100644 packages/cultmesh-rs/src/rudp_document_server.rs create mode 100644 packages/cultmesh-rs/tests/rudp_document_server.rs diff --git a/packages/cultmesh-rs/src/lib.rs b/packages/cultmesh-rs/src/lib.rs index e460ac78..7999f18b 100644 --- a/packages/cultmesh-rs/src/lib.rs +++ b/packages/cultmesh-rs/src/lib.rs @@ -3,8 +3,8 @@ use cultcache_rs::CultCache; use cultcache_rs::CultCacheEnvelope; use cultcache_rs::CultSoaTable; use cultcache_rs::DatabaseEntry; -use cultcache_rs::SoaDocument; use cultcache_rs::SingleFileMessagePackBackingStore; +use cultcache_rs::SoaDocument; use cultnet_rs::CultNetDocumentPutOptions; use cultnet_rs::CultNetDocumentRegistry; use cultnet_rs::CultNetRudpSocketTransportConnection; @@ -14,7 +14,9 @@ use cultnet_rs::decode_cultnet_message_from_slice; use cultnet_rs::encode_cultnet_message_to_vec; use serde::Serialize; use std::collections::BTreeMap; +use std::collections::hash_map::RandomState; use std::env; +use std::hash::{BuildHasher, Hasher}; use std::net::SocketAddr; use std::net::UdpSocket; use std::path::Path; @@ -22,6 +24,10 @@ use std::thread; use std::time::Duration; use std::time::Instant; +mod rudp_document_server; + +pub use rudp_document_server::*; + pub const CULTMESH_RUDP_DOCUMENT_CATALOG_CONNECTION_ID: u32 = 0x0d1d_0002; pub trait CultMeshDocumentSet: Clone + Send + Sync + 'static { @@ -74,7 +80,6 @@ pub struct CultMeshNodeOptions { pub struct CultMeshRudpDocumentPublishOptions { pub target: SocketAddr, pub runtime_id: String, - pub connection_id: u32, pub connect_timeout: Duration, pub flush_timeout: Duration, pub poll_interval: Duration, @@ -88,7 +93,10 @@ pub struct CultMeshRudpDocumentPublishOptions { pub struct CultMeshRudpSnapshotOptions { pub target: SocketAddr, pub runtime_id: String, - pub connection_id: u32, + /// Exact correlation id for the SnapshotRequest. Raw callers must supply + /// this; `CultMeshNode::pull_rudp_catalog_snapshot` generates one when it + /// owns the request. + pub message_id: String, pub connect_timeout: Duration, pub response_timeout: Duration, pub poll_interval: Duration, @@ -112,7 +120,7 @@ impl Default for CultMeshRudpSnapshotOptions { Self { target: SocketAddr::from(([0, 0, 0, 0], 0)), runtime_id: "cultmesh-rudp-snapshot-client".to_string(), - connection_id: CULTMESH_RUDP_DOCUMENT_CATALOG_CONNECTION_ID, + message_id: String::new(), connect_timeout: Duration::from_secs(3), response_timeout: Duration::from_secs(3), poll_interval: Duration::from_millis(10), @@ -138,9 +146,8 @@ impl Default for CultMeshRudpDocumentPublishOptions { Self { target: SocketAddr::from(([0, 0, 0, 0], 0)), runtime_id: "cultmesh-rudp-document-publisher".to_string(), - connection_id: CULTMESH_RUDP_DOCUMENT_CATALOG_CONNECTION_ID, connect_timeout: Duration::from_secs(3), - flush_timeout: Duration::from_secs(30), + flush_timeout: Duration::from_millis(300), poll_interval: Duration::from_millis(10), resend_delay_ms: 50, source_agent_id: None, @@ -673,7 +680,7 @@ impl CultMeshNode { T: DatabaseEntry + Serialize, { let message = self.create_rudp_document_message(key, value, &options)?; - publish_cultnet_messages_to_rudp_catalog(std::slice::from_ref(&message), options) + publish_cultnet_message_to_rudp_catalog(&message, options) } pub fn create_rudp_document_message( @@ -706,8 +713,16 @@ impl CultMeshNode { pub fn pull_rudp_catalog_snapshot( &mut self, - options: CultMeshRudpSnapshotOptions, + mut options: CultMeshRudpSnapshotOptions, ) -> Result { + if options.message_id.trim().is_empty() { + options.message_id = format!( + "{}:snapshot:{}:{}", + options.runtime_id, + unix_millis(), + fresh_rudp_connection_epoch() + ); + } let response = request_raw_snapshot_from_rudp_catalog(options)?; let cultnet_rs::CultNetMessage::SnapshotResponseRaw { documents, .. } = response else { anyhow::bail!("expected cultnet.snapshot_response_raw.v0"); @@ -757,58 +772,38 @@ fn strip_schema_version_suffix(value: &str) -> &str { } } -fn request_raw_snapshot_from_rudp_catalog( +/// Request a raw CultNet snapshot without importing it into a local cache. +/// +/// The returned value is the exact validated `SnapshotResponseRaw`, including +/// its correlation `message_id`. Each call binds a fresh source port, chooses a +/// fresh connection epoch, and succeeds only after the reliable request is +/// acknowledged. +pub fn request_raw_snapshot_from_rudp_catalog( options: CultMeshRudpSnapshotOptions, ) -> Result { if options.runtime_id.trim().is_empty() { anyhow::bail!("runtime_id must be non-empty"); } - let bind_addr = if options.target.is_ipv4() { - SocketAddr::from(([0, 0, 0, 0], 0)) - } else { - SocketAddr::from(([0, 0, 0, 0, 0, 0, 0, 0], 0)) - }; - let socket = UdpSocket::bind(bind_addr)?; - socket.set_read_timeout(Some(options.poll_interval))?; - let mut client = - CultNetRudpSocketTransportConnection::new(CultNetRudpSocketTransportOptions { - media_reliable_expire_after_ms: None, - runtime_id: options.runtime_id.clone(), - socket, - mode: cultnet_rs::CultNetRudpSocketMode::Client, - remote_addr: Some(options.target), - connection_id: options.connection_id, - initial_sequence: 1, - resend_delay_ms: options.resend_delay_ms, - transport_id: Some("cultmesh-rudp-snapshot-client".to_string()), - max_payload_bytes: None, - max_fragment_bytes: Some(1200), - max_pending_reliable_packets: None, - reconnect_policy: None, - })?; - client.connect(Vec::new())?; - let connect_deadline = Instant::now() + options.connect_timeout; - while !client.connected() && Instant::now() < connect_deadline { - let _ = client.receive_once()?; - client.poll_resends()?; - thread::sleep(options.poll_interval); - } - if !client.connected() { - anyhow::bail!( - "timed out connecting CultMesh RUDP snapshot client {} to {}", - options.runtime_id, - options.target - ); + if options.message_id.trim().is_empty() { + anyhow::bail!("raw CultMesh RUDP snapshot requires a message_id"); } + let message_id = options.message_id.clone(); + let mut client = connect_rudp_client( + options.target, + &options.runtime_id, + options.connect_timeout, + options.poll_interval, + options.resend_delay_ms, + "cultmesh-rudp-snapshot-client", + )?; - let message_id = format!("{}:snapshot:{}", options.runtime_id, unix_millis()); let request = cultnet_rs::CultNetMessage::SnapshotRequest { message_id: message_id.clone(), schema_ids: options.schema_ids, record_keys: options.record_keys, }; let payload = encode_cultnet_message_to_vec(&request, CultNetWireContract::CultNetSchemaV0)?; - client.send("schema", payload)?; + let receipt = client.send_reliable("schema", payload)?; let response_deadline = Instant::now() + options.response_timeout; let mut snapshot_response = None; while Instant::now() < response_deadline { @@ -824,7 +819,6 @@ fn request_raw_snapshot_from_rudp_catalog( .. } if received == &message_id => { snapshot_response = Some(message); - break; } cultnet_rs::CultNetMessage::Error { error } => { let _ = client.disconnect(b"snapshot-error".to_vec()); @@ -834,14 +828,28 @@ fn request_raw_snapshot_from_rudp_catalog( } } } + match client.reliable_send_status(&receipt) { + cultnet_rs::CultNetRudpReliableSendStatus::Acknowledged + if snapshot_response.is_some() => + { + let _ = client.disconnect(b"snapshot-complete".to_vec()); + return Ok(snapshot_response.expect("response was checked as present")); + } + cultnet_rs::CultNetRudpReliableSendStatus::Invalidated => { + anyhow::bail!("CultMesh RUDP snapshot request receipt was invalidated") + } + _ => {} + } client.poll_resends()?; thread::sleep(options.poll_interval); } - if let Some(message) = snapshot_response { - let _ = client.disconnect(b"snapshot-complete".to_vec()); - return Ok(message); - } let _ = client.disconnect(b"snapshot-timeout".to_vec()); + if snapshot_response.is_some() { + anyhow::bail!( + "timed out waiting for reliable acknowledgement of CultMesh RUDP snapshot request to {}", + options.target + ); + } anyhow::bail!( "timed out waiting for CultMesh RUDP snapshot from {}", options.target @@ -855,6 +863,58 @@ fn unix_millis() -> u128 { .as_millis() } +/// Publish one raw CultNet schema message to a RUDP catalog. +/// +/// Each call owns a fresh connection epoch and returns only after the catalog +/// acknowledges reliable application admission. +pub fn publish_cultnet_message_to_rudp_catalog( + message: &cultnet_rs::CultNetMessage, + options: CultMeshRudpDocumentPublishOptions, +) -> Result<()> { + if options.runtime_id.trim().is_empty() { + anyhow::bail!("runtime_id must be non-empty"); + } + let mut client = connect_rudp_client( + options.target, + &options.runtime_id, + options.connect_timeout, + options.poll_interval, + options.resend_delay_ms, + "cultmesh-rudp-document-publisher", + )?; + + let payload = encode_cultnet_message_to_vec(message, CultNetWireContract::CultNetSchemaV0)?; + let receipt = client.send_reliable("schema", payload)?; + let flush_deadline = Instant::now() + options.flush_timeout; + while Instant::now() < flush_deadline { + let _ = client.receive_once()?; + match client.reliable_send_status(&receipt) { + cultnet_rs::CultNetRudpReliableSendStatus::Acknowledged => { + let _ = client.disconnect(b"document-acknowledged".to_vec()); + return Ok(()); + } + cultnet_rs::CultNetRudpReliableSendStatus::Invalidated => { + anyhow::bail!("CultMesh RUDP document receipt was invalidated") + } + cultnet_rs::CultNetRudpReliableSendStatus::Pending => {} + } + client.poll_resends()?; + thread::sleep(options.poll_interval); + } + let _ = client.disconnect(b"document-unacknowledged".to_vec()); + anyhow::bail!( + "timed out waiting for reliable acknowledgement from CultMesh RUDP catalog {}", + options.target + ) +} + +/// Publish a batch of raw CultNet schema messages to a RUDP catalog. +/// +/// Unlike [`publish_cultnet_message_to_rudp_catalog`], which polls for +/// per-message application-level acknowledgement, this sends every message on +/// one connection and waits only for a transport-level `flush_reliable`. It +/// trades per-receipt confirmation for batch throughput; callers that need a +/// stronger delivery guarantee should use the singular publish path instead. pub fn publish_cultnet_messages_to_rudp_catalog( messages: &[cultnet_rs::CultNetMessage], options: CultMeshRudpDocumentPublishOptions, @@ -862,43 +922,14 @@ pub fn publish_cultnet_messages_to_rudp_catalog( if options.runtime_id.trim().is_empty() { anyhow::bail!("runtime_id must be non-empty"); } - let bind_addr = if options.target.is_ipv4() { - SocketAddr::from(([0, 0, 0, 0], 0)) - } else { - SocketAddr::from(([0, 0, 0, 0, 0, 0, 0, 0], 0)) - }; - let socket = UdpSocket::bind(bind_addr)?; - socket.set_read_timeout(Some(options.poll_interval))?; - let mut client = - CultNetRudpSocketTransportConnection::new(CultNetRudpSocketTransportOptions { - media_reliable_expire_after_ms: None, - runtime_id: options.runtime_id.clone(), - socket, - mode: cultnet_rs::CultNetRudpSocketMode::Client, - remote_addr: Some(options.target), - connection_id: options.connection_id, - initial_sequence: 1, - resend_delay_ms: options.resend_delay_ms, - transport_id: Some("cultmesh-rudp-document-publisher".to_string()), - max_payload_bytes: None, - max_fragment_bytes: Some(1200), - max_pending_reliable_packets: None, - reconnect_policy: None, - })?; - client.connect(Vec::new())?; - let connect_deadline = Instant::now() + options.connect_timeout; - while !client.connected() && Instant::now() < connect_deadline { - let _ = client.receive_once()?; - client.poll_resends()?; - thread::sleep(options.poll_interval); - } - if !client.connected() { - anyhow::bail!( - "timed out connecting CultMesh RUDP document publisher {} to {}", - options.runtime_id, - options.target - ); - } + let mut client = connect_rudp_client( + options.target, + &options.runtime_id, + options.connect_timeout, + options.poll_interval, + options.resend_delay_ms, + "cultmesh-rudp-document-publisher", + )?; for message in messages { let payload = encode_cultnet_message_to_vec(message, CultNetWireContract::CultNetSchemaV0)?; @@ -907,6 +938,57 @@ pub fn publish_cultnet_messages_to_rudp_catalog( client.flush_reliable(options.flush_timeout) } +fn connect_rudp_client( + target: SocketAddr, + runtime_id: &str, + connect_timeout: Duration, + poll_interval: Duration, + resend_delay_ms: u64, + transport_id: &str, +) -> Result { + let bind_addr = if target.is_ipv4() { + SocketAddr::from(([0, 0, 0, 0], 0)) + } else { + SocketAddr::from(([0, 0, 0, 0, 0, 0, 0, 0], 0)) + }; + let socket = UdpSocket::bind(bind_addr)?; + socket.set_read_timeout(Some(poll_interval))?; + let mut client = + CultNetRudpSocketTransportConnection::new(CultNetRudpSocketTransportOptions { + runtime_id: runtime_id.to_string(), + socket, + mode: cultnet_rs::CultNetRudpSocketMode::Client, + remote_addr: Some(target), + connection_id: fresh_rudp_connection_epoch(), + initial_sequence: 1, + resend_delay_ms, + transport_id: Some(transport_id.to_string()), + max_payload_bytes: None, + max_fragment_bytes: Some(1200), + max_pending_reliable_packets: Some(1024), + media_reliable_expire_after_ms: None, + reconnect_policy: None, + })?; + client.connect(Vec::new())?; + let connect_deadline = Instant::now() + connect_timeout; + while !client.connected() && Instant::now() < connect_deadline { + let _ = client.receive_once()?; + client.poll_resends()?; + thread::sleep(poll_interval); + } + if !client.connected() { + anyhow::bail!("timed out connecting CultMesh RUDP client {runtime_id} to {target}"); + } + Ok(client) +} + +fn fresh_rudp_connection_epoch() -> u32 { + let mut hasher = RandomState::new().build_hasher(); + hasher.write_u128(unix_millis()); + let epoch = hasher.finish() as u32; + if epoch == 0 { 1 } else { epoch } +} + #[derive(Clone, Copy, Debug, Default)] pub struct CultMesh; @@ -1122,33 +1204,33 @@ mod tests { socket.set_read_timeout(Some(Duration::from_millis(10)))?; let target = socket.local_addr()?; let (sender, receiver) = std::sync::mpsc::channel(); + let delivered = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)); + let delivered_by_sink = delivered.clone(); let server = thread::spawn(move || -> Result<()> { - let mut server = CultNetRudpSocketTransportConnection::new( - CultNetRudpSocketTransportOptions::server( - "odin-test-catalog", - socket, - CULTMESH_RUDP_DOCUMENT_CATALOG_CONNECTION_ID, - ), + let mut server = CultMeshRudpDocumentServer::new( + socket, + move |receipt: CultMeshRudpRawDocumentReceipt| { + sender + .send(( + receipt.document.schema_id, + receipt.document.record_key, + receipt.document.source_runtime_id, + )) + .ok(); + delivered_by_sink.store(true, std::sync::atomic::Ordering::SeqCst); + Ok(()) + }, + |_query: &CultMeshRudpSnapshotQuery| Ok(Vec::new()), + CultMeshSystemClock::default(), + CultMeshRudpDocumentServerOptions::default(), )?; let deadline = Instant::now() + Duration::from_secs(2); while Instant::now() < deadline { - if let Some(frame) = server.receive_once()? { - let message = cultnet_rs::decode_cultnet_message_from_slice( - &frame.payload, - CultNetWireContract::CultNetSchemaV0, - )?; - if let cultnet_rs::CultNetMessage::DocumentPutRaw { document, .. } = message { - sender - .send(( - document.schema_id, - document.record_key, - document.source_runtime_id, - )) - .ok(); - return Ok(()); - } + server.poll_once()?; + if delivered.load(std::sync::atomic::Ordering::SeqCst) { + return Ok(()); } - server.poll_resends()?; + thread::sleep(Duration::from_millis(1)); } anyhow::bail!("timed out waiting for RUDP document put") }); @@ -1168,79 +1250,231 @@ mod tests { } #[test] - fn large_rudp_publication_waits_for_acknowledged_delivery() -> Result<()> { + fn document_publish_fails_when_catalog_is_unreachable() -> Result<()> { let temp = tempfile::tempdir()?; let node = CultMesh::create_node( temp.path().join("cultmesh.cc"), TestDocuments, - CultMeshNodeOptions { - runtime_id: "large-publisher-test".into(), - ..CultMeshNodeOptions::default() - }, + Default::default(), + )?; + let unused = UdpSocket::bind("127.0.0.1:0")?; + let target = unused.local_addr()?; + drop(unused); + + let error = node + .publish_document_to_rudp_catalog( + "note", + &Note { + body: "no false success".into(), + }, + CultMeshRudpDocumentPublishOptions { + target, + connect_timeout: Duration::from_millis(30), + poll_interval: Duration::from_millis(2), + ..CultMeshRudpDocumentPublishOptions::default() + }, + ) + .expect_err("unreachable catalog must fail closed"); + assert!(error.to_string().contains("timed out connecting")); + Ok(()) + } + + #[test] + fn document_publish_requires_application_acknowledgement() -> Result<()> { + let temp = tempfile::tempdir()?; + let node = CultMesh::create_node( + temp.path().join("cultmesh.cc"), + TestDocuments, + Default::default(), )?; let socket = UdpSocket::bind("127.0.0.1:0")?; - socket.set_read_timeout(Some(Duration::from_millis(10)))?; let target = socket.local_addr()?; - let options = CultMeshRudpDocumentPublishOptions::odin(target, "large-publisher-test"); - let messages = [ - node.create_rudp_document_message( - "large-a", - &Note { - body: "a".repeat(256 * 1024), + let stop = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)); + let server_stop = stop.clone(); + let server = thread::spawn(move || -> Result<()> { + let mut server = CultMeshRudpDocumentServer::new( + socket, + |_receipt: CultMeshRudpRawDocumentReceipt| { + anyhow::bail!("injected durable sink failure") }, - &options, - )?, - node.create_rudp_document_message( - "large-b", - &Note { - body: "b".repeat(256 * 1024), - }, - &options, - )?, - ]; - - let server = thread::spawn(move || -> Result> { - thread::sleep(Duration::from_millis(500)); - let mut server = CultNetRudpSocketTransportConnection::new( - CultNetRudpSocketTransportOptions::server( - "delayed-odin-test", - socket, - CULTMESH_RUDP_DOCUMENT_CATALOG_CONNECTION_ID, - ), + |_query: &CultMeshRudpSnapshotQuery| Ok(Vec::new()), + CultMeshSystemClock::default(), + CultMeshRudpDocumentServerOptions::default(), )?; - let deadline = Instant::now() + Duration::from_secs(5); - let mut record_keys = Vec::new(); - while Instant::now() < deadline && record_keys.len() < 2 { - if let Some(frame) = server.receive_once()? { - let message = decode_cultnet_message_from_slice( - &frame.payload, - CultNetWireContract::CultNetSchemaV0, - )?; - if let cultnet_rs::CultNetMessage::DocumentPutRaw { document, .. } = message { - record_keys.push(document.record_key); - } - } - server.poll_resends()?; + while !server_stop.load(std::sync::atomic::Ordering::SeqCst) { + let _ = server.poll_once(); + thread::sleep(Duration::from_millis(1)); } - let linger_deadline = Instant::now() + Duration::from_millis(250); - while Instant::now() < linger_deadline { - let _ = server.receive_once()?; - server.poll_resends()?; - } - if record_keys.len() != 2 { - anyhow::bail!("timed out waiting for both large RUDP documents"); - } - Ok(record_keys) + Ok(()) }); - publish_cultnet_messages_to_rudp_catalog(&messages, options)?; + let error = node + .publish_document_to_rudp_catalog( + "note", + &Note { + body: "still not accepted".into(), + }, + CultMeshRudpDocumentPublishOptions { + target, + connect_timeout: Duration::from_millis(100), + flush_timeout: Duration::from_millis(50), + poll_interval: Duration::from_millis(2), + resend_delay_ms: 5, + ..CultMeshRudpDocumentPublishOptions::default() + }, + ) + .expect_err("unacknowledged document must fail closed"); + stop.store(true, std::sync::atomic::Ordering::SeqCst); + server.join().expect("server thread should not panic")?; + assert!(error.to_string().contains("reliable acknowledgement")); + Ok(()) + } + + #[test] + fn raw_snapshot_preserves_caller_challenge_and_raw_response() -> Result<()> { + let expected = cultnet_rs::CultNetRawDocumentRecord { + schema_id: "cultmesh.test.raw.v0".into(), + record_key: "route-proof".into(), + stored_at: "2026-09-03T00:00:00Z".into(), + payload_encoding: cultnet_rs::CultNetRawPayloadEncoding::Messagepack, + payload: vec![0xc4, 0x03, 0, 0xff, 1], + source_runtime_id: Some("odin-test".into()), + source_agent_id: None, + source_role: None, + tags: None, + }; + let socket = UdpSocket::bind("127.0.0.1:0")?; + let target = socket.local_addr()?; + let challenge = "9aa63ad8-83b5-4cc4-ae4a-91d361d5f845".to_string(); + let server_document = expected.clone(); + let server_challenge = challenge.clone(); + let stop = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)); + let server_stop = stop.clone(); + let server = thread::spawn(move || -> Result<()> { + let mut server = CultMeshRudpDocumentServer::new( + socket, + |_receipt: CultMeshRudpRawDocumentReceipt| Ok(()), + move |query: &CultMeshRudpSnapshotQuery| { + if query.message_id != server_challenge { + anyhow::bail!("snapshot challenge changed") + } + Ok(vec![server_document.clone()]) + }, + CultMeshSystemClock::default(), + CultMeshRudpDocumentServerOptions::default(), + )?; + while !server_stop.load(std::sync::atomic::Ordering::SeqCst) { + server.poll_once()?; + thread::sleep(Duration::from_millis(1)); + } + Ok(()) + }); + + let response = request_raw_snapshot_from_rudp_catalog(CultMeshRudpSnapshotOptions { + target, + runtime_id: "route-proof-test".into(), + message_id: challenge.clone(), + connect_timeout: Duration::from_millis(100), + response_timeout: Duration::from_millis(500), + poll_interval: Duration::from_millis(2), + resend_delay_ms: 5, + schema_ids: Some(vec!["cultmesh.test.raw.v0".into()]), + record_keys: Some(vec!["route-proof".into()]), + }); + stop.store(true, std::sync::atomic::Ordering::SeqCst); + server.join().expect("server thread should not panic")?; + let response = response?; assert_eq!( - server.join().expect("server thread should not panic")?, - vec!["large-a", "large-b"] + response, + cultnet_rs::CultNetMessage::SnapshotResponseRaw { + message_id: challenge, + documents: vec![expected], + } ); Ok(()) } + #[test] + fn raw_snapshot_rejects_response_without_request_acknowledgement() -> Result<()> { + let socket = UdpSocket::bind("127.0.0.1:0")?; + socket.set_read_timeout(Some(Duration::from_millis(200)))?; + let target = socket.local_addr()?; + let server = thread::spawn(move || -> Result<()> { + let mut wire = vec![0_u8; 65_535]; + let (received, peer) = socket.recv_from(&mut wire)?; + let connect = cultnet_rs::decode_rudp_packet(&wire[..received])?; + let mut session = + cultnet_rs::CultNetRudpSession::new(cultnet_rs::CultNetRudpSessionOptions { + connection_id: connect.connection_id, + initial_sequence: 1, + resend_delay_ms: 5, + max_pending_reliable_packets: Some(64), + }); + let accept = session.accept_connect(&connect, 1, Vec::new())?; + socket.send_to(&cultnet_rs::encode_rudp_packet(&accept)?, peer)?; + + loop { + let (received, received_peer) = socket.recv_from(&mut wire)?; + if received_peer != peer { + continue; + } + let packet = cultnet_rs::decode_rudp_packet(&wire[..received])?; + let result = session.receive(&packet, 2)?; + let Some(frame) = result.delivered.into_iter().next() else { + continue; + }; + let request = decode_cultnet_message_from_slice( + &frame.payload, + CultNetWireContract::CultNetSchemaV0, + )?; + let cultnet_rs::CultNetMessage::SnapshotRequest { message_id, .. } = request else { + anyhow::bail!("expected snapshot request") + }; + let payload = encode_cultnet_message_to_vec( + &cultnet_rs::CultNetMessage::SnapshotResponseRaw { + message_id, + documents: Vec::new(), + }, + CultNetWireContract::CultNetSchemaV0, + )?; + let mut packets = session.send_many( + "schema", + payload, + cultnet_rs::CultNetRudpSendOptions { + reliable: true, + ordered: true, + sequenced: false, + now_ms: 2, + reliable_expire_after_ms: None, + }, + Some(1200), + )?; + for packet in &mut packets { + packet.ack = 0; + packet.ack_mask = 0; + socket.send_to(&cultnet_rs::encode_rudp_packet(packet)?, peer)?; + } + return Ok(()); + } + }); + + let error = request_raw_snapshot_from_rudp_catalog(CultMeshRudpSnapshotOptions { + target, + runtime_id: "unacknowledged-snapshot-test".into(), + message_id: "b7987efb-69c5-4c42-9355-b6e09535ad21".into(), + connect_timeout: Duration::from_millis(100), + response_timeout: Duration::from_millis(50), + poll_interval: Duration::from_millis(2), + resend_delay_ms: 5, + schema_ids: None, + record_keys: None, + }) + .expect_err("response without request ACK must fail closed"); + server.join().expect("server thread should not panic")?; + assert!(error.to_string().contains("reliable acknowledgement")); + Ok(()) + } + #[test] fn resolves_rudp_endpoint_from_cultmesh_uri_bootstrap_env() -> Result<()> { let previous = env::var("CULTMESH_URI_ODIN_RUDP").ok(); diff --git a/packages/cultmesh-rs/src/rudp_document_server.rs b/packages/cultmesh-rs/src/rudp_document_server.rs new file mode 100644 index 00000000..bebeb6c3 --- /dev/null +++ b/packages/cultmesh-rs/src/rudp_document_server.rs @@ -0,0 +1,647 @@ +use anyhow::{Result, anyhow}; +use cultnet_rs::{ + CultNetMessage, CultNetRawDocumentRecord, CultNetRudpPacket, CultNetRudpPacketType, + CultNetRudpSendOptions, CultNetRudpSession, CultNetRudpSessionOptions, CultNetWireContract, + decode_cultnet_message_from_slice, decode_rudp_packet, encode_cultnet_message_to_vec, + encode_rudp_packet, +}; +use std::collections::BTreeMap; +use std::io::ErrorKind; +use std::net::{SocketAddr, UdpSocket}; +use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; + +const MAX_UDP_DATAGRAM_BYTES: usize = 65_535; + +/// The transport identity of one remote CultNet RUDP session. +/// +/// Connection identifiers are scoped to a remote socket address. Two clients +/// may therefore use the same connection identifier without sharing ordering, +/// acknowledgement, resend, or fragment state. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct CultMeshRudpSessionKey { + pub remote_addr: SocketAddr, + pub connection_id: u32, +} + +/// A raw document plus the receipt fact owned by the receiving process. +/// +/// `document.payload` is the exact byte vector decoded from the CultNet raw +/// record. The trusted receipt time lives beside the sender-owned record so the +/// transport never rewrites its metadata or payload. +#[derive(Clone, Debug, PartialEq)] +pub struct CultMeshRudpRawDocumentReceipt { + pub session: CultMeshRudpSessionKey, + pub message_id: String, + pub transport_sequence: u32, + pub received_at_unix_millis: u64, + pub document: CultNetRawDocumentRecord, +} + +/// The caller-visible query for a read-only raw snapshot. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CultMeshRudpSnapshotQuery { + pub session: CultMeshRudpSessionKey, + pub message_id: String, + pub requested_at_unix_millis: u64, + pub schema_ids: Option>, + pub record_keys: Option>, +} + +/// Caller-owned admission/persistence port for received raw documents. +pub trait CultMeshRudpRawDocumentSink { + fn accept_raw_document(&mut self, receipt: CultMeshRudpRawDocumentReceipt) -> Result<()>; +} + +impl CultMeshRudpRawDocumentSink for F +where + F: FnMut(CultMeshRudpRawDocumentReceipt) -> Result<()>, +{ + fn accept_raw_document(&mut self, receipt: CultMeshRudpRawDocumentReceipt) -> Result<()> { + self(receipt) + } +} + +/// Caller-owned catalog port for serving raw snapshot requests. +/// +/// The caller decides which records the requester may see. CultMesh preserves +/// those records as raw CultNet documents and does not interpret their schemas. +pub trait CultMeshRudpSnapshotSource { + fn raw_snapshot( + &mut self, + query: &CultMeshRudpSnapshotQuery, + ) -> Result>; +} + +impl CultMeshRudpSnapshotSource for F +where + F: FnMut(&CultMeshRudpSnapshotQuery) -> Result>, +{ + fn raw_snapshot( + &mut self, + query: &CultMeshRudpSnapshotQuery, + ) -> Result> { + self(query) + } +} + +/// Trusted local clocks for receipt facts and transport maintenance. +/// +/// Receipt time is wall time. Expiry and resend decisions use the monotonic +/// value, so a wall-clock correction cannot resurrect or pin a session. +pub trait CultMeshRudpServerClock { + fn now_unix_millis(&self) -> u64; + fn now_monotonic_millis(&self) -> u64; +} + +#[derive(Clone, Debug)] +pub struct CultMeshSystemClock { + monotonic_origin: Instant, +} + +impl Default for CultMeshSystemClock { + fn default() -> Self { + Self { + monotonic_origin: Instant::now(), + } + } +} + +impl CultMeshRudpServerClock for CultMeshSystemClock { + fn now_unix_millis(&self) -> u64 { + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap_or_default() + .as_millis() + .try_into() + .unwrap_or(u64::MAX) + } + + fn now_monotonic_millis(&self) -> u64 { + self.monotonic_origin + .elapsed() + .as_millis() + .try_into() + .unwrap_or(u64::MAX) + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CultMeshRudpDocumentServerOptions { + pub max_sessions: usize, + pub session_idle_timeout: Duration, + pub session_max_lifetime: Duration, + /// Conservative payload admission budget across all live sessions. + /// + /// Admitted ingress and queued snapshot-response bytes are charged until + /// the session ends even when CultNet releases them sooner. Together with + /// CultNet's per-session receive caps, this makes retained payload memory + /// finite without duplicating its fragment/ordering machinery here. + pub max_admitted_payload_bytes: usize, + pub max_admitted_payload_bytes_per_session: usize, + pub max_snapshot_response_bytes: usize, + pub max_snapshot_documents: usize, + pub resend_delay: Duration, + pub max_pending_reliable_packets_per_session: usize, + pub max_fragment_bytes: usize, +} + +impl Default for CultMeshRudpDocumentServerOptions { + fn default() -> Self { + Self { + max_sessions: 64, + session_idle_timeout: Duration::from_secs(30), + session_max_lifetime: Duration::from_secs(15 * 60), + max_admitted_payload_bytes: 32 * 1024 * 1024, + max_admitted_payload_bytes_per_session: 4 * 1024 * 1024, + max_snapshot_response_bytes: 1024 * 1024, + max_snapshot_documents: 4096, + resend_delay: Duration::from_millis(50), + max_pending_reliable_packets_per_session: 1024, + max_fragment_bytes: 1200, + } + } +} + +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct CultMeshRudpMaintenance { + pub sessions_expired: usize, + pub packets_resent: usize, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum CultMeshRudpApplicationOperation { + DocumentPutRaw, + SnapshotRequest, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CultMeshRudpApplicationRejection { + pub session: CultMeshRudpSessionKey, + pub operation: CultMeshRudpApplicationOperation, + pub message_id: String, + pub reason: String, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum CultMeshRudpPollOutcome { + Idle, + Handled, + ApplicationRejected(CultMeshRudpApplicationRejection), +} + +struct SessionEntry { + session: CultNetRudpSession, + created_at_monotonic_millis: u64, + last_activity_monotonic_millis: u64, + admitted_payload_bytes: usize, +} + +/// A synchronous, multi-session CultNet RUDP raw-document server. +/// +/// The server owns exactly one UDP socket. Call `poll_once` from an existing +/// daemon loop; no executor or background thread is created here. +pub struct CultMeshRudpDocumentServer { + socket: UdpSocket, + sessions: BTreeMap, + sink: S, + snapshot_source: Q, + clock: C, + options: CultMeshRudpDocumentServerOptions, +} + +impl CultMeshRudpDocumentServer +where + S: CultMeshRudpRawDocumentSink, + Q: CultMeshRudpSnapshotSource, + C: CultMeshRudpServerClock, +{ + pub fn new( + socket: UdpSocket, + sink: S, + snapshot_source: Q, + clock: C, + options: CultMeshRudpDocumentServerOptions, + ) -> Result { + validate_options(&options)?; + socket.local_addr().map_err(|error| { + anyhow!("CultMesh RUDP server requires a bound UDP socket: {error}") + })?; + socket.set_nonblocking(true)?; + Ok(Self { + socket, + sessions: BTreeMap::new(), + sink, + snapshot_source, + clock, + options, + }) + } + + pub fn local_addr(&self) -> Result { + Ok(self.socket.local_addr()?) + } + + pub fn session_count(&self) -> usize { + self.sessions.len() + } + + /// Poll transport maintenance and receive at most one UDP datagram. + /// + /// Application rejection invalidates only the responsible peer session and + /// is returned as data so a daemon can log it and keep serving. Local + /// socket and server-state failures remain errors. + pub fn poll_once(&mut self) -> Result { + self.maintain()?; + let mut wire = vec![0_u8; MAX_UDP_DATAGRAM_BYTES]; + let (received, remote_addr) = match self.socket.recv_from(&mut wire) { + Ok(value) => value, + Err(error) if error.kind() == ErrorKind::WouldBlock => { + return Ok(CultMeshRudpPollOutcome::Idle); + } + Err(error) => return Err(error.into()), + }; + wire.truncate(received); + + let packet = match decode_rudp_packet(&wire) { + Ok(packet) => packet, + Err(_) => return Ok(CultMeshRudpPollOutcome::Handled), + }; + let now_unix = self.clock.now_unix_millis(); + let now_monotonic = self.clock.now_monotonic_millis(); + let key = CultMeshRudpSessionKey { + remote_addr, + connection_id: packet.connection_id, + }; + + if packet.packet_type == CultNetRudpPacketType::Connect { + self.accept_connection(key, &packet, now_monotonic)?; + return Ok(CultMeshRudpPollOutcome::Handled); + } + + if !self.sessions.contains_key(&key) { + return Ok(CultMeshRudpPollOutcome::Handled); + } + if packet.packet_type == CultNetRudpPacketType::Data + && packet.channel_id == "schema" + && !packet.reliable + { + return Ok(CultMeshRudpPollOutcome::Handled); + } + let payload_charge = if packet.packet_type == CultNetRudpPacketType::Data { + packet.payload.len() + } else { + 0 + }; + if !self.payload_budget_allows(key, payload_charge) { + return Ok(CultMeshRudpPollOutcome::Handled); + } + + let result = { + let entry = self + .sessions + .get_mut(&key) + .expect("checked session must remain present"); + entry.last_activity_monotonic_millis = now_monotonic; + entry.admitted_payload_bytes = + entry.admitted_payload_bytes.saturating_add(payload_charge); + entry.session.receive(&packet, now_monotonic) + }; + let result = match result { + Ok(result) => result, + Err(_) => { + self.sessions.remove(&key); + return Ok(CultMeshRudpPollOutcome::Handled); + } + }; + + if let Some(reply) = result.reply { + self.send_packet(key.remote_addr, &reply)?; + } + + if result.disconnected { + self.sessions.remove(&key); + return Ok(CultMeshRudpPollOutcome::Handled); + } + + for frame in result.delivered { + if frame.channel_id != "schema" { + continue; + } + let message = match decode_cultnet_message_from_slice( + &frame.payload, + CultNetWireContract::CultNetSchemaV0, + ) { + Ok(message) => message, + Err(_) => continue, + }; + if let Some(rejection) = self.deliver_application_message( + key, + frame.sequence, + message, + now_unix, + now_monotonic, + )? { + self.sessions.remove(&key); + return Ok(CultMeshRudpPollOutcome::ApplicationRejected(rejection)); + } + } + + if packet.reliable { + let ack = self + .sessions + .get_mut(&key) + .ok_or_else(|| anyhow!("CultMesh RUDP session disappeared before ACK"))? + .session + .create_ack(); + self.send_packet(key.remote_addr, &ack)?; + } + Ok(CultMeshRudpPollOutcome::Handled) + } + + /// Expire idle sessions and resend reliable packets whose deadline passed. + pub fn maintain(&mut self) -> Result { + let now = self.clock.now_monotonic_millis(); + let idle_timeout_ms = duration_millis(self.options.session_idle_timeout); + let lifetime_ms = duration_millis(self.options.session_max_lifetime); + let before = self.sessions.len(); + self.sessions.retain(|_, entry| { + now.saturating_sub(entry.last_activity_monotonic_millis) <= idle_timeout_ms + && now.saturating_sub(entry.created_at_monotonic_millis) <= lifetime_ms + }); + let expired = before - self.sessions.len(); + + let mut resends = Vec::new(); + for (key, entry) in &mut self.sessions { + for packet in entry.session.due_resends(now) { + resends.push((key.remote_addr, packet)); + } + } + for (remote_addr, packet) in &resends { + self.send_packet(*remote_addr, packet)?; + } + Ok(CultMeshRudpMaintenance { + sessions_expired: expired, + packets_resent: resends.len(), + }) + } + + fn accept_connection( + &mut self, + key: CultMeshRudpSessionKey, + packet: &CultNetRudpPacket, + now: u64, + ) -> Result<()> { + if !self.sessions.contains_key(&key) { + if self.sessions.len() >= self.options.max_sessions { + return Ok(()); + } + self.sessions.insert( + key, + SessionEntry { + session: CultNetRudpSession::new(CultNetRudpSessionOptions { + connection_id: key.connection_id, + initial_sequence: 1, + resend_delay_ms: duration_millis(self.options.resend_delay), + max_pending_reliable_packets: Some( + self.options.max_pending_reliable_packets_per_session, + ), + }), + created_at_monotonic_millis: now, + last_activity_monotonic_millis: now, + admitted_payload_bytes: 0, + }, + ); + } + + let accept = { + let entry = self + .sessions + .get_mut(&key) + .expect("accepted session must be present"); + // The same key is a retransmitted Connect for the existing epoch. + // A genuinely fresh client incarnation must choose a fresh id. + entry.last_activity_monotonic_millis = now; + entry.session.accept_connect(packet, now, Vec::new())? + }; + self.send_packet(key.remote_addr, &accept) + } + + fn deliver_application_message( + &mut self, + key: CultMeshRudpSessionKey, + transport_sequence: u32, + message: CultNetMessage, + now_unix: u64, + now: u64, + ) -> Result> { + match message { + CultNetMessage::DocumentPutRaw { + message_id, + document, + } => { + let receipt = CultMeshRudpRawDocumentReceipt { + session: key, + message_id: message_id.clone(), + transport_sequence, + received_at_unix_millis: now_unix, + document, + }; + if let Err(error) = self.sink.accept_raw_document(receipt) { + return Ok(Some(CultMeshRudpApplicationRejection { + session: key, + operation: CultMeshRudpApplicationOperation::DocumentPutRaw, + message_id, + reason: format!("{error:#}"), + })); + } + } + CultNetMessage::SnapshotRequest { + message_id, + schema_ids, + record_keys, + } => { + let query = CultMeshRudpSnapshotQuery { + session: key, + message_id: message_id.clone(), + requested_at_unix_millis: now_unix, + schema_ids, + record_keys, + }; + let documents = match self.snapshot_source.raw_snapshot(&query) { + Ok(documents) => documents, + Err(error) => { + return Ok(Some(CultMeshRudpApplicationRejection { + session: key, + operation: CultMeshRudpApplicationOperation::SnapshotRequest, + message_id, + reason: format!("{error:#}"), + })); + } + }; + if documents.len() > self.options.max_snapshot_documents { + return Ok(Some(CultMeshRudpApplicationRejection { + session: key, + operation: CultMeshRudpApplicationOperation::SnapshotRequest, + message_id, + reason: format!( + "snapshot returned {} documents; limit is {}", + documents.len(), + self.options.max_snapshot_documents + ), + })); + } + let response = CultNetMessage::SnapshotResponseRaw { + message_id: message_id.clone(), + documents, + }; + let payload = match encode_cultnet_message_to_vec( + &response, + CultNetWireContract::CultNetSchemaV0, + ) { + Ok(payload) => payload, + Err(error) => { + return Ok(Some(CultMeshRudpApplicationRejection { + session: key, + operation: CultMeshRudpApplicationOperation::SnapshotRequest, + message_id, + reason: format!("snapshot response could not be encoded: {error:#}"), + })); + } + }; + if payload.len() > self.options.max_snapshot_response_bytes { + return Ok(Some(CultMeshRudpApplicationRejection { + session: key, + operation: CultMeshRudpApplicationOperation::SnapshotRequest, + message_id, + reason: format!( + "snapshot response is {} bytes; limit is {}", + payload.len(), + self.options.max_snapshot_response_bytes + ), + })); + } + if !self.payload_budget_allows(key, payload.len()) { + return Ok(Some(CultMeshRudpApplicationRejection { + session: key, + operation: CultMeshRudpApplicationOperation::SnapshotRequest, + message_id, + reason: "retained payload budget is full".into(), + })); + } + let payload_bytes = payload.len(); + let entry = self + .sessions + .get_mut(&key) + .ok_or_else(|| anyhow!("CultMesh RUDP session disappeared before response"))?; + let packets = match entry.session.send_many( + "schema", + payload, + CultNetRudpSendOptions { + reliable: true, + ordered: true, + sequenced: false, + now_ms: now, + reliable_expire_after_ms: None, + }, + Some(self.options.max_fragment_bytes), + ) { + Ok(packets) => packets, + Err(error) => { + return Ok(Some(CultMeshRudpApplicationRejection { + session: key, + operation: CultMeshRudpApplicationOperation::SnapshotRequest, + message_id, + reason: format!("snapshot response could not be queued: {error:#}"), + })); + } + }; + entry.admitted_payload_bytes = + entry.admitted_payload_bytes.saturating_add(payload_bytes); + for packet in &packets { + self.send_packet(key.remote_addr, packet)?; + } + } + _ => {} + } + Ok(None) + } + + fn payload_budget_allows(&self, key: CultMeshRudpSessionKey, bytes: usize) -> bool { + let Some(session_bytes) = self + .sessions + .get(&key) + .map(|entry| entry.admitted_payload_bytes) + else { + return false; + }; + if session_bytes + .checked_add(bytes) + .is_none_or(|total| total > self.options.max_admitted_payload_bytes_per_session) + { + return false; + } + self.sessions + .values() + .try_fold(0_usize, |total, entry| { + total.checked_add(entry.admitted_payload_bytes) + }) + .and_then(|total| total.checked_add(bytes)) + .is_some_and(|total| total <= self.options.max_admitted_payload_bytes) + } + + fn send_packet(&mut self, remote_addr: SocketAddr, packet: &CultNetRudpPacket) -> Result<()> { + let wire = encode_rudp_packet(packet)?; + self.socket.send_to(&wire, remote_addr)?; + Ok(()) + } +} + +fn validate_options(options: &CultMeshRudpDocumentServerOptions) -> Result<()> { + if options.max_sessions == 0 { + return Err(anyhow!("max_sessions must be greater than zero")); + } + if options.session_idle_timeout.is_zero() { + return Err(anyhow!("session_idle_timeout must be greater than zero")); + } + if options.session_max_lifetime.is_zero() { + return Err(anyhow!("session_max_lifetime must be greater than zero")); + } + if options.max_admitted_payload_bytes == 0 { + return Err(anyhow!( + "max_admitted_payload_bytes must be greater than zero" + )); + } + if options.max_admitted_payload_bytes_per_session == 0 + || options.max_admitted_payload_bytes_per_session > options.max_admitted_payload_bytes + { + return Err(anyhow!( + "per-session admitted payload limit must be non-zero and no larger than the server limit" + )); + } + if options.max_snapshot_response_bytes == 0 + || options.max_snapshot_response_bytes > options.max_admitted_payload_bytes_per_session + { + return Err(anyhow!( + "snapshot response limit must be non-zero and fit in one session's payload budget" + )); + } + if options.max_snapshot_documents == 0 { + return Err(anyhow!("max_snapshot_documents must be greater than zero")); + } + if options.resend_delay.is_zero() { + return Err(anyhow!("resend_delay must be greater than zero")); + } + if options.max_pending_reliable_packets_per_session == 0 { + return Err(anyhow!( + "max_pending_reliable_packets_per_session must be greater than zero" + )); + } + if options.max_fragment_bytes == 0 { + return Err(anyhow!("max_fragment_bytes must be greater than zero")); + } + Ok(()) +} + +fn duration_millis(duration: Duration) -> u64 { + duration.as_millis().try_into().unwrap_or(u64::MAX) +} diff --git a/packages/cultmesh-rs/tests/rudp_document_server.rs b/packages/cultmesh-rs/tests/rudp_document_server.rs new file mode 100644 index 00000000..c0f191b4 --- /dev/null +++ b/packages/cultmesh-rs/tests/rudp_document_server.rs @@ -0,0 +1,554 @@ +use anyhow::Result; +use cultmesh_rs::{ + CultMeshRudpApplicationOperation, CultMeshRudpDocumentServer, + CultMeshRudpDocumentServerOptions, CultMeshRudpPollOutcome, CultMeshRudpRawDocumentReceipt, + CultMeshRudpRawDocumentSink, CultMeshRudpServerClock, CultMeshRudpSnapshotQuery, + CultMeshRudpSnapshotSource, +}; +use cultnet_rs::{ + CultNetMessage, CultNetRawDocumentRecord, CultNetRawPayloadEncoding, + CultNetRudpReliableSendReceipt, CultNetRudpReliableSendStatus, CultNetRudpSocketMode, + CultNetRudpSocketTransportConnection, CultNetRudpSocketTransportOptions, CultNetWireContract, + decode_cultnet_message_from_slice, encode_cultnet_message_to_vec, +}; +use pretty_assertions::assert_eq; +use std::net::{SocketAddr, UdpSocket}; +use std::sync::atomic::{AtomicU64, Ordering}; +use std::sync::{Arc, Mutex}; +use std::thread; +use std::time::Duration; + +#[derive(Default)] +struct SinkState { + receipts: Vec, + failures_remaining: usize, +} + +#[derive(Clone, Default)] +struct Sink(Arc>); + +impl Sink { + fn fail_once() -> Self { + Self(Arc::new(Mutex::new(SinkState { + failures_remaining: 1, + ..Default::default() + }))) + } +} + +impl CultMeshRudpRawDocumentSink for Sink { + fn accept_raw_document(&mut self, receipt: CultMeshRudpRawDocumentReceipt) -> Result<()> { + let mut state = self.0.lock().unwrap(); + if state.failures_remaining > 0 { + state.failures_remaining -= 1; + anyhow::bail!("injected sink failure"); + } + state.receipts.push(receipt); + Ok(()) + } +} + +#[derive(Default)] +struct SourceState { + documents: Vec, + failures_remaining: usize, + calls: usize, +} + +#[derive(Clone, Default)] +struct Source(Arc>); + +impl Source { + fn documents(documents: Vec) -> Self { + Self(Arc::new(Mutex::new(SourceState { + documents, + ..Default::default() + }))) + } + + fn fail_once(documents: Vec) -> Self { + Self(Arc::new(Mutex::new(SourceState { + documents, + failures_remaining: 1, + calls: 0, + }))) + } +} + +impl CultMeshRudpSnapshotSource for Source { + fn raw_snapshot( + &mut self, + _: &CultMeshRudpSnapshotQuery, + ) -> Result> { + let mut state = self.0.lock().unwrap(); + state.calls += 1; + if state.failures_remaining > 0 { + state.failures_remaining -= 1; + anyhow::bail!("injected source failure"); + } + Ok(state.documents.clone()) + } +} + +#[derive(Clone)] +struct Clock { + unix: Arc, + monotonic: Arc, +} + +impl Clock { + fn new(now: u64) -> Self { + Self { + unix: Arc::new(AtomicU64::new(now)), + monotonic: Arc::new(AtomicU64::new(now)), + } + } + + fn set(&self, now: u64) { + self.unix.store(now, Ordering::SeqCst); + self.monotonic.store(now, Ordering::SeqCst); + } + + fn set_unix(&self, now: u64) { + self.unix.store(now, Ordering::SeqCst); + } + + fn set_monotonic(&self, now: u64) { + self.monotonic.store(now, Ordering::SeqCst); + } +} + +impl CultMeshRudpServerClock for Clock { + fn now_unix_millis(&self) -> u64 { + self.unix.load(Ordering::SeqCst) + } + + fn now_monotonic_millis(&self) -> u64 { + self.monotonic.load(Ordering::SeqCst) + } +} + +type Server = CultMeshRudpDocumentServer; + +fn document(key: &str, payload: Vec) -> CultNetRawDocumentRecord { + CultNetRawDocumentRecord { + schema_id: "test.raw.v1".into(), + record_key: key.into(), + stored_at: "2026-09-03T00:00:00Z".into(), + payload_encoding: CultNetRawPayloadEncoding::Messagepack, + payload, + source_runtime_id: Some(format!("runtime-{key}")), + source_agent_id: None, + source_role: None, + tags: None, + } +} + +fn server( + options: CultMeshRudpDocumentServerOptions, + clock: Clock, + sink: Sink, + source: Source, +) -> Result { + CultMeshRudpDocumentServer::new( + UdpSocket::bind("127.0.0.1:0")?, + sink, + source, + clock, + options, + ) +} + +fn client(target: SocketAddr, id: u32) -> Result { + let socket = UdpSocket::bind("127.0.0.1:0")?; + socket.set_nonblocking(true)?; + CultNetRudpSocketTransportConnection::new(CultNetRudpSocketTransportOptions { + runtime_id: "test-client".into(), + socket, + mode: CultNetRudpSocketMode::Client, + remote_addr: Some(target), + connection_id: id, + initial_sequence: 1, + resend_delay_ms: 10, + transport_id: None, + max_payload_bytes: None, + max_fragment_bytes: Some(1200), + max_pending_reliable_packets: Some(64), + media_reliable_expire_after_ms: None, + reconnect_policy: None, + }) +} + +fn connect( + server: &mut Server, + clients: &mut [&mut CultNetRudpSocketTransportConnection], +) -> Result<()> { + for client in &mut *clients { + client.connect(Vec::new())?; + } + for _ in 0..500 { + server.poll_once()?; + for client in &mut *clients { + client.receive_once()?; + } + if clients.iter().all(|client| client.connected()) { + for _ in 0..clients.len() { + server.poll_once()?; + } + return Ok(()); + } + thread::sleep(Duration::from_millis(1)); + } + anyhow::bail!("client connection timed out") +} + +fn send(client: &mut CultNetRudpSocketTransportConnection, message: &CultNetMessage) -> Result<()> { + client.send( + "schema", + encode_cultnet_message_to_vec(message, CultNetWireContract::CultNetSchemaV0)?, + ) +} + +fn send_reliable( + client: &mut CultNetRudpSocketTransportConnection, + message: &CultNetMessage, +) -> Result { + client.send_reliable( + "schema", + encode_cultnet_message_to_vec(message, CultNetWireContract::CultNetSchemaV0)?, + ) +} + +#[test] +fn same_connection_id_is_peer_scoped_and_raw_bytes_are_untouched() -> Result<()> { + let clock = Clock::new(42_000); + let sink = Sink::default(); + let mut server = server(Default::default(), clock, sink.clone(), Source::default())?; + let mut a = client(server.local_addr()?, 77)?; + let mut b = client(server.local_addr()?, 77)?; + connect(&mut server, &mut [&mut a, &mut b])?; + + let a_bytes = vec![0xc4, 0x04, 0x00, 0xff, 0x80, 0x01]; + let b_bytes = vec![0x92, 0x01, 0xc4, 0x02, 0x00, 0xff]; + send( + &mut a, + &CultNetMessage::DocumentPutRaw { + message_id: "a".into(), + document: document("a", a_bytes.clone()), + }, + )?; + send( + &mut b, + &CultNetMessage::DocumentPutRaw { + message_id: "b".into(), + document: document("b", b_bytes.clone()), + }, + )?; + for _ in 0..500 { + server.poll_once()?; + a.receive_once()?; + b.receive_once()?; + if sink.0.lock().unwrap().receipts.len() == 2 { + break; + } + } + + let receipts = sink.0.lock().unwrap(); + assert_eq!(server.session_count(), 2); + assert_eq!(receipts.receipts.len(), 2); + assert_ne!( + receipts.receipts[0].session.remote_addr, + receipts.receipts[1].session.remote_addr + ); + assert_eq!( + receipts + .receipts + .iter() + .find(|r| r.message_id == "a") + .unwrap() + .document + .payload, + a_bytes + ); + assert_eq!( + receipts + .receipts + .iter() + .find(|r| r.message_id == "b") + .unwrap() + .document + .payload, + b_bytes + ); + assert!( + receipts + .receipts + .iter() + .all(|r| r.received_at_unix_millis == 42_000) + ); + Ok(()) +} + +#[test] +fn duplicate_connect_preserves_epoch_and_fresh_epoch_is_separate() -> Result<()> { + let clock = Clock::new(45_000); + let sink = Sink::default(); + let mut server = server(Default::default(), clock, sink.clone(), Source::default())?; + let target = server.local_addr()?; + let mut incumbent = client(target, 91)?; + connect(&mut server, &mut [&mut incumbent])?; + + incumbent.connect(Vec::new())?; + server.poll_once()?; + incumbent.receive_once()?; + assert_eq!(server.session_count(), 1); + + send( + &mut incumbent, + &CultNetMessage::DocumentPutRaw { + message_id: "after-duplicate".into(), + document: document("incumbent", vec![1, 2, 3]), + }, + )?; + for _ in 0..20 { + server.poll_once()?; + if sink.0.lock().unwrap().receipts.len() == 1 { + break; + } + } + assert_eq!(sink.0.lock().unwrap().receipts.len(), 1); + + let mut fresh_epoch = client(target, 92)?; + connect(&mut server, &mut [&mut fresh_epoch])?; + assert_eq!(server.session_count(), 2); + Ok(()) +} + +#[test] +fn application_rejection_is_nonfatal_peer_scoped_and_unacknowledged() -> Result<()> { + let clock = Clock::new(48_000); + let sink = Sink::fail_once(); + let source = Source::fail_once(vec![document("snapshot", vec![4, 5, 6])]); + let mut server = server( + Default::default(), + clock.clone(), + sink.clone(), + source.clone(), + )?; + let target = server.local_addr()?; + + let mut publisher = client(target, 101)?; + let mut snapshot_client = client(target, 102)?; + let mut survivor = client(target, 103)?; + connect( + &mut server, + &mut [&mut publisher, &mut snapshot_client, &mut survivor], + )?; + let publish_receipt = send_reliable( + &mut publisher, + &CultNetMessage::DocumentPutRaw { + message_id: "rejected-put".into(), + document: document("rejected", vec![0, 255, 1]), + }, + )?; + let CultMeshRudpPollOutcome::ApplicationRejected(rejection) = server.poll_once()? else { + panic!("sink rejection must be returned as a nonfatal poll outcome"); + }; + assert_eq!(rejection.session.connection_id, 101); + assert_eq!( + rejection.operation, + CultMeshRudpApplicationOperation::DocumentPutRaw + ); + assert_eq!(rejection.message_id, "rejected-put"); + assert!(rejection.reason.contains("injected sink failure")); + assert_eq!(server.session_count(), 2); + publisher.receive_once()?; + assert_eq!( + publisher.reliable_send_status(&publish_receipt), + CultNetRudpReliableSendStatus::Pending + ); + + let snapshot_receipt = send_reliable( + &mut snapshot_client, + &CultNetMessage::SnapshotRequest { + message_id: "rejected-snapshot".into(), + schema_ids: None, + record_keys: None, + }, + )?; + let CultMeshRudpPollOutcome::ApplicationRejected(rejection) = server.poll_once()? else { + panic!("source rejection must be returned as a nonfatal poll outcome"); + }; + assert_eq!(rejection.session.connection_id, 102); + assert_eq!( + rejection.operation, + CultMeshRudpApplicationOperation::SnapshotRequest + ); + assert_eq!(rejection.message_id, "rejected-snapshot"); + assert!(rejection.reason.contains("injected source failure")); + assert_eq!(server.session_count(), 1); + snapshot_client.receive_once()?; + assert_eq!( + snapshot_client.reliable_send_status(&snapshot_receipt), + CultNetRudpReliableSendStatus::Pending + ); + + let survivor_receipt = send_reliable( + &mut survivor, + &CultNetMessage::DocumentPutRaw { + message_id: "accepted-after-rejections".into(), + document: document("survivor", vec![9, 8, 7]), + }, + )?; + assert_eq!(server.poll_once()?, CultMeshRudpPollOutcome::Handled); + for _ in 0..20 { + survivor.receive_once()?; + if survivor.reliable_send_status(&survivor_receipt) + == CultNetRudpReliableSendStatus::Acknowledged + { + break; + } + } + assert_eq!( + survivor.reliable_send_status(&survivor_receipt), + CultNetRudpReliableSendStatus::Acknowledged + ); + assert_eq!(sink.0.lock().unwrap().receipts.len(), 1); + assert_eq!(source.0.lock().unwrap().calls, 1); + Ok(()) +} + +#[test] +fn snapshot_response_resends_until_acknowledged() -> Result<()> { + let clock = Clock::new(51_000); + let expected = document("catalog", vec![0x81, 0xa1, 0x78, 0x2a]); + let source = Source::documents(vec![expected.clone()]); + let options = CultMeshRudpDocumentServerOptions { + resend_delay: Duration::from_millis(10), + ..Default::default() + }; + let mut server = server(options, clock.clone(), Sink::default(), source)?; + let mut client = client(server.local_addr()?, 88)?; + connect(&mut server, &mut [&mut client])?; + send( + &mut client, + &CultNetMessage::SnapshotRequest { + message_id: "snapshot".into(), + schema_ids: Some(vec!["test.raw.v1".into()]), + record_keys: Some(vec!["catalog".into()]), + }, + )?; + server.poll_once()?; + + clock.set(51_011); + assert_eq!(server.maintain()?.packets_resent, 1); + let response = loop { + if let Some(frame) = client.receive_once()? { + break decode_cultnet_message_from_slice( + &frame.payload, + CultNetWireContract::CultNetSchemaV0, + )?; + } + }; + assert_eq!( + response, + CultNetMessage::SnapshotResponseRaw { + message_id: "snapshot".into(), + documents: vec![expected], + } + ); + + for _ in 0..20 { + server.poll_once()?; + } + clock.set(51_022); + assert_eq!(server.maintain()?.packets_resent, 0); + Ok(()) +} + +#[test] +fn payload_and_snapshot_output_budgets_fail_closed() -> Result<()> { + let clock = Clock::new(55_000); + let sink = Sink::default(); + let message = CultNetMessage::DocumentPutRaw { + message_id: "budget".into(), + document: document("budget", vec![7; 64]), + }; + let encoded = encode_cultnet_message_to_vec(&message, CultNetWireContract::CultNetSchemaV0)?; + let options = CultMeshRudpDocumentServerOptions { + max_admitted_payload_bytes: encoded.len(), + max_admitted_payload_bytes_per_session: encoded.len(), + max_snapshot_response_bytes: encoded.len(), + ..Default::default() + }; + let mut budget_server = server(options, clock, sink.clone(), Source::default())?; + let target = budget_server.local_addr()?; + let mut first = client(target, 111)?; + let mut second = client(target, 112)?; + connect(&mut budget_server, &mut [&mut first, &mut second])?; + send(&mut first, &message)?; + budget_server.poll_once()?; + send(&mut second, &message)?; + budget_server.poll_once()?; + assert_eq!(sink.0.lock().unwrap().receipts.len(), 1); + + let oversized = Source::documents(vec![document("oversized", vec![8; 512])]); + let options = CultMeshRudpDocumentServerOptions { + max_snapshot_response_bytes: 128, + ..Default::default() + }; + let mut snapshot_server = server(options, Clock::new(56_000), Sink::default(), oversized)?; + let mut snapshot_client = client(snapshot_server.local_addr()?, 113)?; + connect(&mut snapshot_server, &mut [&mut snapshot_client])?; + let receipt = send_reliable( + &mut snapshot_client, + &CultNetMessage::SnapshotRequest { + message_id: "too-large".into(), + schema_ids: None, + record_keys: None, + }, + )?; + let CultMeshRudpPollOutcome::ApplicationRejected(rejection) = snapshot_server.poll_once()? + else { + panic!("oversized snapshot must reject only its session"); + }; + assert_eq!( + rejection.operation, + CultMeshRudpApplicationOperation::SnapshotRequest + ); + assert_eq!(rejection.message_id, "too-large"); + assert!(rejection.reason.contains("snapshot response is")); + assert_eq!(snapshot_server.session_count(), 0); + snapshot_client.receive_once()?; + assert_eq!( + snapshot_client.reliable_send_status(&receipt), + CultNetRudpReliableSendStatus::Pending + ); + Ok(()) +} + +#[test] +fn session_cap_and_expiry_use_monotonic_time() -> Result<()> { + let clock = Clock::new(60_000); + let options = CultMeshRudpDocumentServerOptions { + max_sessions: 1, + session_idle_timeout: Duration::from_secs(1), + session_max_lifetime: Duration::from_millis(100), + ..Default::default() + }; + let mut server = server(options, clock.clone(), Sink::default(), Source::default())?; + let target = server.local_addr()?; + let mut admitted = client(target, 1)?; + connect(&mut server, &mut [&mut admitted])?; + let mut rejected = client(target, 1)?; + rejected.connect(Vec::new())?; + server.poll_once()?; + assert_eq!(server.session_count(), 1); + assert!(!rejected.connected()); + + clock.set_unix(1); + clock.set_monotonic(60_101); + assert_eq!(server.maintain()?.sessions_expired, 1); + assert_eq!(server.session_count(), 0); + Ok(()) +} From c13b6ba07e99f2535b455da74d07d88c308731f5 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sat, 5 Sep 2026 17:39:46 +0200 Subject: [PATCH 145/283] Move IdunnDaemonHealthTrustBindingRecord into cultnet-rs odin-core only re-exported this contract from Odin's tree while the sibling health/trust records already live in provider_health_contracts.rs. Moving it here lets idunn-daemon depend on cultnet-rs directly instead of odin-core, clearing the way to extract idunn-daemon into its own repo. Co-Authored-By: Claude Opus 5 --- .../src/provider_health_contracts.rs | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/packages/cultnet-rs/src/provider_health_contracts.rs b/packages/cultnet-rs/src/provider_health_contracts.rs index 5ca320f0..632c74f2 100644 --- a/packages/cultnet-rs/src/provider_health_contracts.rs +++ b/packages/cultnet-rs/src/provider_health_contracts.rs @@ -21,6 +21,7 @@ pub const IDUNN_PROVIDER_ACTIVE_REASON: &str = "authenticated_provider_active"; pub const IDUNN_PROVIDER_WARMING_REASON: &str = "authenticated_provider_warming"; pub const IDUNN_PROVIDER_DEGRADED_REASON: &str = "authenticated_provider_degraded"; pub const IDUNN_PROVIDER_FAILED_REASON: &str = "authenticated_provider_failed"; +pub const IDUNN_DAEMON_HEALTH_TRUST_BINDING_SCHEMA: &str = "idunn.daemon_health_trust_binding.v1"; /// Provider-owned health statement. Ingress verifies `signature` over the /// complete positional record with this field empty before admitting it. @@ -198,6 +199,68 @@ fn messagepack_array_len(payload: &[u8]) -> Option { } } +/// Root-owned admission binding. Store ownership is the physical authority; +/// this document names the only signer accepted for one daemon/contract/runtime. +#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] +#[cultcache( + type = "idunn.daemon_health_trust_binding", + schema = "idunn.daemon_health_trust_binding.v1" +)] +pub struct IdunnDaemonHealthTrustBindingRecord { + #[cultcache(key = 0)] + pub schema_version: String, + #[cultcache(key = 1)] + pub binding_id: String, + #[cultcache(key = 2)] + pub daemon_id: String, + #[cultcache(key = 3)] + pub health_contract: String, + #[cultcache(key = 4)] + pub source_runtime_id: String, + #[cultcache(key = 5)] + pub signer_identity_id: String, + #[cultcache(key = 6)] + pub signer_public_key: Vec, + #[cultcache(key = 7)] + pub binding_authority: String, + #[cultcache(key = 8)] + pub bound_at_unix_millis: u64, + #[cultcache(key = 9)] + pub release_binding_required: bool, + #[cultcache(key = 10)] + pub private_state_exposed: bool, +} + +impl IdunnDaemonHealthTrustBindingRecord { + pub fn validate(&self) -> Result<()> { + if self.schema_version != IDUNN_DAEMON_HEALTH_TRUST_BINDING_SCHEMA { + bail!("daemon health trust binding schema is unsupported"); + } + validate_identifier(&self.binding_id, "binding id")?; + validate_identifier(&self.daemon_id, "daemon id")?; + validate_identifier(&self.health_contract, "health contract")?; + validate_identifier(&self.source_runtime_id, "source runtime id")?; + validate_identifier(&self.signer_identity_id, "signer identity id")?; + if self.signer_public_key.len() != 32 + || self.binding_authority != "root" + || self.bound_at_unix_millis == 0 + { + bail!("daemon health trust binding authority or key is invalid"); + } + if self.private_state_exposed { + bail!("daemon health trust binding exposes private state"); + } + if self.signer_identity_id + != derive_service_identity_id::( + &self.signer_public_key, + )? + { + bail!("daemon health trust binding identity does not match its public key"); + } + Ok(()) + } +} + /// Root-distributed public key binding for one service-owned signed contract. /// Consumers pin this document; a self-declared key inside a signed projection /// is never authority. From 5407be713fdd4d66cf865ca643750ac7b167be3a Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 6 Sep 2026 19:29:33 +0200 Subject: [PATCH 146/283] Add generic signed daemon-health publication to cultnet-ts Odin carried a 324-line module named idunn-rudp.cjs. Thirteen of those lines mentioned Idunn, and most were error strings. The rest was CultNet client work: socket binding, RUDP handshake, Ed25519 signing, packet receipt, msgpack framing. It sat in a consumer because that is where it was written, not because that is where it belonged, and it was about to be duplicated when Hermodr moves to its own repository. The transport now lives here as signed-daemon-health, beside the RUDP session it builds on. The receiving service supplies a contract naming its connection id, signed schema, and unsigned diagnostic schema; nothing service-specific is hardcoded. The signature and identity domains are deliberately not parameterised. They are the shared gamecult.provider-health domains, and a caller able to vary them could silently produce statements no verifier accepts. The signing purpose is the caller's signed schema id, so a statement signed for one service cannot verify as another's. The module also loses the sibling-path assumption it was carrying: it no longer resolves CultLib by walking up three directories from wherever it happens to live, because it now lives in CultLib. Type-checks clean and builds. Verified faithful by Odin's existing signed-health test, which asserts exact canonical statement fields, the observation timestamp, and Ed25519 signature verification against the ported implementation. Co-Authored-By: Claude Opus 5 --- packages/cultnet-ts/src/index.ts | 12 + .../cultnet-ts/src/signed-daemon-health.ts | 377 ++++++++++++++++++ 2 files changed, 389 insertions(+) create mode 100644 packages/cultnet-ts/src/signed-daemon-health.ts diff --git a/packages/cultnet-ts/src/index.ts b/packages/cultnet-ts/src/index.ts index 731cafb5..db24d17b 100644 --- a/packages/cultnet-ts/src/index.ts +++ b/packages/cultnet-ts/src/index.ts @@ -144,3 +144,15 @@ export { validateGhostlightAgentStateGenerated, type GhostlightAgentStateShape, } from "./generated/swarm-contracts.generated"; +export { + CULTNET_RUDP_PROTOCOL_ID, + createSignedDaemonHealthPublisher, + parseEndpoint as parseDaemonHealthEndpoint, + publishSignedDaemonHealth, + signedDaemonHealthPayload, + signedDaemonHealthSigningMessage, + type DaemonHealth, + type SignedDaemonHealthContract, + type SignedDaemonHealthPublisher, + type SignedDaemonHealthPublisherOptions, +} from "./signed-daemon-health"; diff --git a/packages/cultnet-ts/src/signed-daemon-health.ts b/packages/cultnet-ts/src/signed-daemon-health.ts new file mode 100644 index 00000000..d4f0f0ce --- /dev/null +++ b/packages/cultnet-ts/src/signed-daemon-health.ts @@ -0,0 +1,377 @@ +// Signed daemon-health publication over CultNet RUDP. +// +// This is the transport half of daemon health publication: bind a socket, shake +// hands, sign the statement, put the document, wait for the ack. It is generic +// across services. The receiving service owns the connection id and the schema +// names, and supplies them as a contract; nothing service-specific is hardcoded +// here. +// +// The signature and identity domains are deliberately not parameterised. They +// are the GameCult provider-health domains, shared by every publisher and +// verifier, and a caller that could vary them could silently produce statements +// nobody verifies. + +import dgram from "node:dgram"; +import crypto from "node:crypto"; +import fs from "node:fs"; +import { encode } from "@msgpack/msgpack"; + +import { CultNetRudpSession, decodeRudpPacket, encodeRudpPacket } from "./rudp"; +import type { CultNetRudpPacket } from "./rudp"; +import { encodeCultNetMessageForWire } from "./contracts"; + +export const CULTNET_RUDP_PROTOCOL_ID = "cultnet.transport.rudp.v0"; + +const SIGNATURE_DOMAIN = Buffer.from("gamecult.provider-health.signature.v1\0", "utf8"); +const ID_DOMAIN = Buffer.from("gamecult.provider-health.identity.v1\0", "utf8"); + +/** What the receiving service owns: where to connect and what to call the documents. */ +export interface SignedDaemonHealthContract { + /** RUDP connection id the receiving service listens on. */ + connectionId: number; + /** Schema id for a signed statement. Also the signing purpose. */ + signedSchemaId: string; + /** Schema id used when no signing key is configured. */ + unsignedSchemaId: string; + /** Prefix for generated message ids. Defaults to "daemon-health". */ + messageIdPrefix?: string; +} + +export interface SignedDaemonHealthPublisherOptions { + /** host:port, or [ipv6]:port. */ + endpoint: string; + daemonId: string; + healthContract: string; + sourceRuntimeId?: string; + /** Omit to publish unsigned. */ + privateKeyPath?: string; + contract: SignedDaemonHealthContract; +} + +export interface DaemonHealth { + state: string; + detail?: string; + observedAt?: string; +} + +export interface SignedDaemonHealthPublisher { + daemonId: string; + endpoint: { host: string; port: number }; + healthContract: string; + publisherIncarnationId: string; + publisherSequence: number; + sourceRuntimeId: string; + contract: SignedDaemonHealthContract; + privateKey?: crypto.KeyObject; + publicKey?: Buffer; + signerIdentityId?: string; +} + +export function createSignedDaemonHealthPublisher( + options: SignedDaemonHealthPublisherOptions | null | undefined, +): SignedDaemonHealthPublisher | null { + if (!options) return null; + if (!options.contract) { + throw new Error("Signed daemon health publisher requires a contract naming the connection id and schema ids."); + } + + const publisher: SignedDaemonHealthPublisher = { + daemonId: options.daemonId, + endpoint: parseEndpoint(options.endpoint), + healthContract: options.healthContract, + publisherIncarnationId: crypto.randomUUID(), + publisherSequence: 0, + sourceRuntimeId: options.sourceRuntimeId || "daemon-health-publisher", + contract: options.contract, + }; + + if (options.privateKeyPath) { + publisher.privateKey = crypto.createPrivateKey(fs.readFileSync(options.privateKeyPath)); + publisher.publicKey = rawEd25519PublicKey(publisher.privateKey); + publisher.signerIdentityId = crypto + .createHash("sha256") + .update(ID_DOMAIN) + .update(publisher.publicKey) + .digest("hex"); + } + return publisher; +} + +export async function publishSignedDaemonHealth( + publisher: SignedDaemonHealthPublisher | null, + health: DaemonHealth, +): Promise { + if (!publisher) return; + const { contract } = publisher; + + const socket = dgram.createSocket(endpointFamily(publisher.endpoint.host)); + await bindSocket(socket, publisher.endpoint); + const receiver = createPacketReceiver(socket); + const session = new CultNetRudpSession({ + connectionId: contract.connectionId, + initialSequence: 1, + resendDelayMs: 100, + }); + + try { + const connect = session.createConnect(Date.now(), new Uint8Array()); + await sendPacket(socket, publisher.endpoint, connect); + await receiveUntil(receiver, session, publisher.endpoint, (packet) => packet.packetType === "accept", 5000, "accept"); + + const observedAt = health.observedAt || new Date().toISOString(); + const signed = publisher.privateKey ? signedDaemonHealthPayload(publisher, health, observedAt) : null; + const payload = signed?.payload || encode([ + publisher.daemonId, + health.state, + String(health.detail || "").slice(0, 512), + observedAt, + publisher.healthContract, + "daemon-published", + CULTNET_RUDP_PROTOCOL_ID, + ]); + + const message = { + schemaVersion: "cultnet.document_put_raw.v0", + messageId: `${contract.messageIdPrefix || "daemon-health"}:${publisher.daemonId}:${observedAt.replace(/[:.]/g, "-")}`, + document: { + schemaId: signed ? contract.signedSchemaId : contract.unsignedSchemaId, + recordKey: publisher.daemonId, + storedAt: observedAt, + payloadEncoding: "messagepack", + payload, + sourceRuntimeId: publisher.sourceRuntimeId, + sourceRole: "daemon-health-publisher", + tags: [CULTNET_RUDP_PROTOCOL_ID], + }, + }; + + const wirePayload = encode(encodeCultNetMessageForWire(message as never, "cultnet.schema.v0")); + const dataPackets = session.sendMany("schema", wirePayload, { reliable: true, ordered: true, nowMs: Date.now() }); + const ack = receiveUntil( + receiver, + session, + publisher.endpoint, + (packet) => packet.packetType === "ack", + 500, + "ack", + ).catch(() => undefined); + for (const packet of dataPackets) { + await sendPacket(socket, publisher.endpoint, packet); + } + await ack; + } finally { + receiver.close(); + socket.close(); + } +} + +export function signedDaemonHealthPayload( + publisher: SignedDaemonHealthPublisher, + health: DaemonHealth, + observedAt: string, +): { payload: Uint8Array; statement: unknown[]; unsignedPayload: Uint8Array } { + if (!publisher.privateKey) { + throw new Error("Signed daemon health requires a configured private key."); + } + publisher.publisherSequence += 1; + const observedAtUnixMillis = Date.parse(observedAt); + if (!Number.isSafeInteger(observedAtUnixMillis) || observedAtUnixMillis <= 0) { + throw new Error("Signed daemon health observation time is invalid."); + } + + const unsigned: unknown[] = [ + publisher.contract.signedSchemaId, + publisher.daemonId, + publisher.healthContract, + publisher.sourceRuntimeId, + health.state, + String(health.detail || "").slice(0, 512), + publisher.signerIdentityId, + publisher.publisherIncarnationId, + publisher.publisherSequence, + observedAtUnixMillis, + null, + null, + null, + null, + "ed25519", + new Uint8Array(), + false, + ]; + + const unsignedPayload = encode(unsigned); + const signature = crypto.sign( + null, + signedDaemonHealthSigningMessage(publisher.contract.signedSchemaId, unsignedPayload), + publisher.privateKey, + ); + const statement = unsigned.slice(); + statement[15] = new Uint8Array(signature); + return { payload: encode(statement), statement, unsignedPayload }; +} + +/** + * Domain-separated signing preimage. The signing purpose is the signed schema + * id, so a statement signed for one service's schema cannot verify as another's. + */ +export function signedDaemonHealthSigningMessage(signedSchemaId: string, payload: Uint8Array): Buffer { + const purpose = Buffer.from(signedSchemaId, "utf8"); + const purposeLength = Buffer.alloc(8); + purposeLength.writeBigUInt64BE(BigInt(purpose.length)); + const payloadLength = Buffer.alloc(8); + payloadLength.writeBigUInt64BE(BigInt(payload.length)); + return Buffer.concat([SIGNATURE_DOMAIN, purposeLength, purpose, payloadLength, Buffer.from(payload)]); +} + +function rawEd25519PublicKey(privateKey: crypto.KeyObject): Buffer { + const der = crypto.createPublicKey(privateKey).export({ type: "spki", format: "der" }) as Buffer; + if (der.length < 32) throw new Error("Ed25519 public key export is too short."); + return Buffer.from(der.subarray(der.length - 32)); +} + +async function bindSocket(socket: dgram.Socket, endpoint: { host: string }): Promise { + await new Promise((resolve, reject) => { + socket.once("error", reject); + socket.bind(0, endpoint.host.includes(":") ? "::" : "0.0.0.0", () => { + socket.off("error", reject); + resolve(); + }); + }); +} + +export function parseEndpoint(value: string): { host: string; port: number } { + const text = String(value || "").trim(); + const ipv6 = text.match(/^\[([^\]]+)\]:(\d+)$/); + if (ipv6) return { host: ipv6[1], port: parsePort(ipv6[2]) }; + const index = text.lastIndexOf(":"); + if (index <= 0) { + throw new Error(`Daemon health RUDP endpoint must be host:port, got "${value}".`); + } + return { host: text.slice(0, index), port: parsePort(text.slice(index + 1)) }; +} + +function parsePort(value: string): number { + const port = Number(value); + if (!Number.isInteger(port) || port <= 0 || port > 65535) { + throw new Error(`Daemon health RUDP endpoint port is invalid: ${value}`); + } + return port; +} + +function endpointFamily(host: string): "udp4" | "udp6" { + return host.includes(":") ? "udp6" : "udp4"; +} + +interface PacketReceiver { + socket: dgram.Socket; + next(timeoutMs: number, label?: string): Promise; + close(): void; +} + +async function receiveUntil( + receiver: PacketReceiver, + session: CultNetRudpSession, + endpoint: { host: string; port: number }, + predicate: (packet: CultNetRudpPacket) => boolean, + timeoutMs: number, + label: string, +): Promise { + const deadline = Date.now() + timeoutMs; + while (Date.now() < deadline) { + try { + const packet = await receiver.next(Math.min(100, deadline - Date.now()), label); + const result = session.receive(packet, Date.now()); + if (result.reply) { + throw new Error("Daemon health publisher received an unexpected reply-required packet."); + } + if (predicate(packet)) return; + } catch (error) { + if ((error as NodeJS.ErrnoException)?.code !== "ETIMEDOUT") throw error; + } + for (const packet of session.dueResends(Date.now())) { + await sendPacket(receiver.socket, endpoint, packet); + } + } + throw new Error(`timed out waiting for daemon health RUDP ${label} response after ${timeoutMs}ms`); +} + +function createPacketReceiver(socket: dgram.Socket): PacketReceiver { + const packets: CultNetRudpPacket[] = []; + const waiters: Array<{ + resolve: (packet: CultNetRudpPacket) => void; + reject: (error: Error) => void; + timer: NodeJS.Timeout; + }> = []; + const errors: Error[] = []; + + const resolveNext = () => { + while (waiters.length > 0 && (packets.length > 0 || errors.length > 0)) { + const waiter = waiters.shift()!; + clearTimeout(waiter.timer); + if (errors.length > 0) waiter.reject(errors.shift()!); + else waiter.resolve(packets.shift()!); + } + }; + const onMessage = (wire: Buffer) => { + try { + packets.push(decodeRudpPacket(wire)); + } catch (error) { + errors.push(error as Error); + } + resolveNext(); + }; + const onError = (error: Error) => { + errors.push(error); + resolveNext(); + }; + + socket.on("message", onMessage); + socket.on("error", onError); + + return { + socket, + next(timeoutMs: number, label = "packet") { + if (packets.length > 0) return Promise.resolve(packets.shift()!); + if (errors.length > 0) return Promise.reject(errors.shift()!); + return new Promise((resolve, reject) => { + const waiter = { + resolve, + reject, + timer: setTimeout(() => { + const index = waiters.indexOf(waiter); + if (index >= 0) waiters.splice(index, 1); + const error = new Error(`timed out waiting for daemon health RUDP ${label}`) as NodeJS.ErrnoException; + error.code = "ETIMEDOUT"; + reject(error); + }, Math.max(1, timeoutMs)), + }; + waiters.push(waiter); + }); + }, + close() { + socket.off("message", onMessage); + socket.off("error", onError); + while (waiters.length > 0) { + const waiter = waiters.shift()!; + clearTimeout(waiter.timer); + const error = new Error("Daemon health publisher closed.") as NodeJS.ErrnoException; + error.code = "ECLOSED"; + waiter.reject(error); + } + }, + }; +} + +async function sendPacket( + socket: dgram.Socket, + endpoint: { host: string; port: number }, + packet: CultNetRudpPacket, +): Promise { + const wire = encodeRudpPacket(packet); + await new Promise((resolve, reject) => { + socket.send(wire, endpoint.port, endpoint.host, (error) => { + if (error) reject(error); + else resolve(); + }); + }); +} From b304df5e479ad5e37d1a8d37be9ccf85182b6e22 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 6 Sep 2026 19:40:37 +0200 Subject: [PATCH 147/283] Promote the swarm document catalog into cultcache-ts Odin carried defineOdinDocuments: 45 CultCache document-type definitions for documents that cross service boundaries. Eve surfaces and provider advertisements, Ghostlight, Heimdall, Idunn, Muninn, Sleipnir, Aetheria, VoidBot, Stonks. Almost none of it is Odin. It lived there because Odin was written first. That was tolerable while Odin was the only consumer of consequence. It stops being tolerable when Hermodr moves to its own repository, because the choice then is a published contract or two definitions of one wire format, and the second is the failure the Hermodr extraction exists to remove. The catalog is now defineSwarmDocuments here, beside defineDocumentType, which is what builds it. defineDocumentType stays injected rather than imported: that is how it worked in Odin, it keeps the catalog clear of the generic signature in ./document, and it lets a caller supply another runtime. Ported as a mechanical transform rather than retyped, then verified rather than assumed: serialising all 45 definitions from both implementations against the same probe gives byte-identical output and identical key sets. The 43 callbacks that gained annotations are named DocumentValue rather than bare any, because these definitions predate typing and read fields defensively, and pretending otherwise would be inventing types nobody has verified. Co-Authored-By: Claude Opus 5 --- packages/cultcache-ts/src/index.ts | 5 + packages/cultcache-ts/src/swarm-documents.ts | 561 +++++++++++++++++++ 2 files changed, 566 insertions(+) create mode 100644 packages/cultcache-ts/src/swarm-documents.ts diff --git a/packages/cultcache-ts/src/index.ts b/packages/cultcache-ts/src/index.ts index 97687de8..92f7b481 100644 --- a/packages/cultcache-ts/src/index.ts +++ b/packages/cultcache-ts/src/index.ts @@ -27,3 +27,8 @@ export type { InspectedCatalogMember, InspectedRecord, } from "./cult-cache-inspector"; +export { + defineSwarmDocuments, + type DefineDocumentType, + type SwarmDocumentCatalog, +} from "./swarm-documents"; diff --git a/packages/cultcache-ts/src/swarm-documents.ts b/packages/cultcache-ts/src/swarm-documents.ts new file mode 100644 index 00000000..b1c0b40d --- /dev/null +++ b/packages/cultcache-ts/src/swarm-documents.ts @@ -0,0 +1,561 @@ +// GameCult swarm document-type catalog. +// +// These are CultCache document definitions for documents that cross service +// boundaries: Eve surfaces and provider advertisements, Ghostlight, Heimdall, +// Idunn, Muninn, Sleipnir, Aetheria, VoidBot, Stonks. The catalog lived in Odin +// because Odin was written first, not because Odin owns it; every service that +// decodes another service documents needs the same definitions, and a second +// copy would be a second definition of one wire format. +// +// defineDocumentType is injected rather than imported. That is how it worked in +// Odin, it keeps this file clear of the generic signature in ./document, and it +// lets a caller supply a runtime other than this package. + +/** An undecoded document payload. These definitions predate typing and name fields defensively. */ +export type DocumentValue = any; + +export type DefineDocumentType = (definition: Record) => unknown; +export type SwarmDocumentCatalog = Record; + +function parseObjectDocument(label: string) { + return { + parse(value: unknown) { + if (!value || typeof value !== "object") { + throw new Error(`${label} must be an object`); + } + return value; + }, + }; +} + +export function defineSwarmDocuments(defineDocumentType?: DefineDocumentType | null): SwarmDocumentCatalog { + if (!defineDocumentType) { + return { + interfaceBindingDefinition: null, + evePluginAdvertisementDefinition: null, + ghostlightSchemaCatalogDefinition: null, + heimdallCommandBoundaryDefinition: null, + heimdallTransportProfileDefinition: null, + idunnCommandBoundaryDefinition: null, + idunnDaemonHealthDefinition: null, + idunnTransportProfileDefinition: null, + interfaceLayoutDefinition: null, + muninnCaptureStreamCommandDefinition: null, + muninnCaptureStreamDefinition: null, + muninnCommandBoundaryDefinition: null, + muninnMediaAudioPacketDefinition: null, + muninnMediaReceiverFeedbackDefinition: null, + muninnMediaVideoAccessUnitDefinition: null, + muninnHidControllerStateDefinition: null, + muninnMoveControllerStateDefinition: null, + muninnMoveIdentityDefinition: null, + muninnMoveLightCommandDefinition: null, + muninnMoveMarkerCandidateDefinition: null, + muninnObsStreamCatalogDefinition: null, + muninnQuestAccessDefinition: null, + muninnTelemetrySurfaceDefinition: null, + muninnTransportProfileDefinition: null, + SleipnirInputMappingDefinition: null, + aetheriaAssetManifestDefinition: null, + aetheriaGravityViewportDefinition: null, + aetheriaObjectsViewportDefinition: null, + aetheriaRenderSplatsViewportDefinition: null, + operatorStateDefinition: null, + providerAdvertisementDefinition: null, + voidbotProviderCatalogDefinition: null, + stonksCommandBoundaryDefinition: null, + stonksMarketSnapshotDefinition: null, + stonksRequestEventDefinition: null, + stonksTransportProfileDefinition: null, + streamPixelsCommandBoundaryDefinition: null, + streamPixelsTransportProfileDefinition: null, + surfaceDefinition: null, + viliCommandBoundaryDefinition: null, + viliTransportProfileDefinition: null, + weksaCommandBoundaryDefinition: null, + weksaOperatorStateDefinition: null, + weksaTransportProfileDefinition: null, + voidbotSwarmSnapshotDefinition: null, + }; + } + + const surfaceDefinition = defineDocumentType({ + type: "gamecult.eve.surface_state", + schemaName: "gamecult.eve.surface_state", + schemaId: "gamecult.eve.surface_state.v1", + schemaVersion: "gamecult.eve.surface_state.v1", + global: false, + name: (value: DocumentValue) => value?.providerId || "surface", + schema: { parse: (value: DocumentValue) => value }, + members: [ + { slot: 0, memberName: "providerId", typeName: "string", isName: true }, + { slot: 1, memberName: "title", typeName: "string" }, + { slot: 2, memberName: "version", typeName: "long" }, + { slot: 3, memberName: "updatedAt", typeName: "string" }, + { slot: 4, memberName: "surface", typeName: "object" }, + ], + }); + const interfaceBindingDefinition = defineDocumentType({ + type: "gamecult.eve.interface_binding", + schemaName: "gamecult.eve.interface_binding", + schemaId: "gamecult.eve.interface_binding.v1", + schemaVersion: "gamecult.eve.interface_binding.v1", + global: false, + name: (value: DocumentValue) => value?.bindingId || value?.providerId || "interface", + schema: parseObjectDocument("Eve interface binding"), + }); + const providerAdvertisementDefinition = defineDocumentType({ + type: "gamecult.eve.provider_advertisement", + schemaName: "gamecult.eve.provider_advertisement", + schemaId: "gamecult.eve.provider_advertisement.v1", + schemaVersion: "gamecult.eve.provider_advertisement.v1", + global: false, + name: (value: DocumentValue) => value?.providerId || value?.provider?.id || "provider", + schema: parseObjectDocument("Eve provider advertisement"), + }); + const evePluginAdvertisementDefinition = defineDocumentType({ + type: "gamecult.eve.plugin_advertisement", + schemaName: "gamecult.eve.plugin_advertisement", + schemaId: "gamecult.eve.plugin_advertisement.v1", + schemaVersion: "gamecult.eve.plugin_advertisement.v1", + global: false, + name: (value: DocumentValue) => value?.pluginId || value?.plugin?.id || "plugin", + schema: parseObjectDocument("Eve plugin advertisement"), + }); + const ghostlightSchemaCatalogDefinition = defineDocumentType({ + type: "ghostlight.schema_catalog", + schemaName: "ghostlight.schema_catalog", + schemaId: "ghostlight.schema_catalog.v1", + schemaVersion: "ghostlight.schema_catalog.v1", + global: false, + name: (value: DocumentValue) => value?.providerId || "gamecult.ghostlight.dungeon", + schema: parseObjectDocument("Ghostlight public schema catalog"), + }); + const heimdallCommandBoundaryDefinition = defineDocumentType({ + type: "heimdall.command_boundary", + schemaName: "heimdall.command_boundary", + schemaId: "heimdall.command_boundary.v1", + schemaVersion: "heimdall.command_boundary.v1", + global: false, + name: (value: DocumentValue) => value?.boundaryId || value?.daemonId || "heimdall", + schema: parseObjectDocument("Heimdall command boundary"), + }); + const heimdallTransportProfileDefinition = defineDocumentType({ + type: "heimdall.transport_profile", + schemaName: "heimdall.transport_profile", + schemaId: "heimdall.transport_profile.v1", + schemaVersion: "heimdall.transport_profile.v1", + global: false, + name: (value: DocumentValue) => value?.profileId || value?.daemonId || "heimdall", + schema: parseObjectDocument("Heimdall transport profile"), + }); + const interfaceLayoutDefinition = defineDocumentType({ + type: "odin.interface_layout", + schemaName: "odin.interface_layout", + schemaId: "odin.interface_layout.v1", + schemaVersion: "odin.interface_layout.v1", + global: false, + name: (value: DocumentValue) => value?.layoutId || value?.providerId || "odin.providers", + schema: parseObjectDocument("Odin interface layout"), + members: [ + { slot: 0, memberName: "layoutId", typeName: "string", isName: true }, + { slot: 1, memberName: "updatedAt", typeName: "string" }, + { slot: 2, memberName: "tiles", typeName: "object" }, + ], + }); + const idunnDaemonHealthDefinition = defineDocumentType({ + type: "idunn.daemon_health", + schemaName: "idunn.daemon_health", + schemaId: "idunn.daemon_health", + schemaVersion: "idunn.daemon_health.v1", + global: false, + name: (value: DocumentValue) => value?.daemonId || value?.daemon_id || "daemon", + schema: parseObjectDocument("Idunn daemon health"), + }); + const idunnCommandBoundaryDefinition = defineDocumentType({ + type: "idunn.command_boundary", + schemaName: "idunn.command_boundary", + schemaId: "idunn.command_boundary.v1", + schemaVersion: "idunn.command_boundary.v1", + global: false, + name: (value: DocumentValue) => value?.boundary_id || value?.boundaryId || value?.daemon_id || value?.daemonId || "daemon", + schema: parseObjectDocument("Idunn command boundary"), + }); + const idunnTransportProfileDefinition = defineDocumentType({ + type: "idunn.daemon_transport_profile", + schemaName: "idunn.daemon_transport_profile", + schemaId: "idunn.daemon_transport_profile.v1", + schemaVersion: "idunn.daemon_transport_profile.v1", + global: false, + name: (value: DocumentValue) => value?.profile_id || value?.profileId || value?.daemon_id || value?.daemonId || "daemon", + schema: parseObjectDocument("Idunn daemon transport profile"), + }); + const muninnCaptureStreamDefinition = defineDocumentType({ + type: "muninn.capture_stream", + schemaName: "muninn.capture_stream", + schemaId: "muninn.capture_stream.v1", + schemaVersion: "muninn.capture_stream.v1", + global: false, + name: (value: DocumentValue) => value?.stream_id || value?.streamId || "capture-stream", + schema: parseObjectDocument("Muninn capture stream"), + }); + const muninnCaptureStreamCommandDefinition = defineDocumentType({ + type: "muninn.capture_stream_command", + schemaName: "muninn.capture_stream_command", + schemaId: "muninn.capture_stream_command.v1", + schemaVersion: "muninn.capture_stream_command.v1", + global: false, + name: (value: DocumentValue) => value?.command_id || value?.commandId || value?.stream_id || value?.streamId || "capture-stream-command", + schema: parseObjectDocument("Muninn capture stream command"), + }); + const muninnCommandBoundaryDefinition = defineDocumentType({ + type: "muninn.command_boundary", + schemaName: "muninn.command_boundary", + schemaId: "muninn.command_boundary.v1", + schemaVersion: "muninn.command_boundary.v1", + global: false, + name: (value: DocumentValue) => value?.boundary_id || value?.boundaryId || value?.daemon_id || value?.daemonId || "muninn", + schema: parseObjectDocument("Muninn command boundary"), + }); + const muninnMediaVideoAccessUnitDefinition = defineDocumentType({ + type: "muninn.media_video_access_unit", + schemaName: "muninn.media_video_access_unit", + schemaId: "muninn.media_video_access_unit.v1", + schemaVersion: "muninn.media_video_access_unit.v1", + global: false, + name: (value: DocumentValue) => { + const streamId = value?.stream_id || value?.streamId || "stream"; + const sessionId = value?.session_id || value?.sessionId || "session"; + const frameId = value?.frame_id ?? value?.frameId ?? "frame"; + const chunkIndex = value?.chunk_index ?? value?.chunkIndex ?? "chunk"; + return `${streamId}:${sessionId}:video:${frameId}:${chunkIndex}`; + }, + schema: parseObjectDocument("Muninn media video access unit"), + }); + const muninnMediaAudioPacketDefinition = defineDocumentType({ + type: "muninn.media_audio_packet", + schemaName: "muninn.media_audio_packet", + schemaId: "muninn.media_audio_packet.v1", + schemaVersion: "muninn.media_audio_packet.v1", + global: false, + name: (value: DocumentValue) => { + const streamId = value?.stream_id || value?.streamId || "stream"; + const sessionId = value?.session_id || value?.sessionId || "session"; + const packetId = value?.packet_id ?? value?.packetId ?? "packet"; + return `${streamId}:${sessionId}:audio:${packetId}`; + }, + schema: parseObjectDocument("Muninn media audio packet"), + }); + const muninnMediaReceiverFeedbackDefinition = defineDocumentType({ + type: "muninn.media_receiver_feedback", + schemaName: "muninn.media_receiver_feedback", + schemaId: "muninn.media_receiver_feedback.v1", + schemaVersion: "muninn.media_receiver_feedback.v1", + global: false, + name: (value: DocumentValue) => { + const streamId = value?.stream_id || value?.streamId || "stream"; + const sessionId = value?.session_id || value?.sessionId || "session"; + const receiverId = value?.receiver_id || value?.receiverId || "receiver"; + return `${streamId}:${sessionId}:feedback:${receiverId}`; + }, + schema: parseObjectDocument("Muninn media receiver feedback"), + }); + const muninnMoveControllerStateDefinition = defineDocumentType({ + type: "muninn.move_controller_state", + schemaName: "muninn.move_controller_state", + schemaId: "muninn.move_controller_state.v1", + schemaVersion: "muninn.move_controller_state.v1", + global: false, + name: (value: DocumentValue) => value?.stream_id || value?.streamId || value?.move_id || value?.moveId || "move-controller-state", + schema: parseObjectDocument("Muninn Move controller state"), + }); + const muninnHidControllerStateDefinition = defineDocumentType({ + type: "muninn.hid_controller_state", + schemaName: "muninn.hid_controller_state", + schemaId: "muninn.hid_controller_state.v1", + schemaVersion: "muninn.hid_controller_state.v1", + global: false, + name: (value: DocumentValue) => value?.stream_id || value?.streamId || value?.device_id || value?.deviceId || "hid-controller-state", + schema: parseObjectDocument("Muninn HID controller state"), + }); + const muninnMoveIdentityDefinition = defineDocumentType({ + type: "muninn.move_identity", + schemaName: "muninn.move_identity", + schemaId: "muninn.move_identity.v1", + schemaVersion: "muninn.move_identity.v1", + global: false, + name: (value: DocumentValue) => value?.identity_id || value?.identityId || value?.move_id || value?.moveId || "move-identity", + schema: parseObjectDocument("Muninn Move identity"), + }); + const muninnMoveLightCommandDefinition = defineDocumentType({ + type: "muninn.move_light_command", + schemaName: "muninn.move_light_command", + schemaId: "muninn.move_light_command.v1", + schemaVersion: "muninn.move_light_command.v1", + global: false, + name: (value: DocumentValue) => value?.command_id || value?.commandId || value?.move_id || value?.moveId || "move-light-command", + schema: parseObjectDocument("Muninn Move light command"), + }); + const muninnMoveMarkerCandidateDefinition = defineDocumentType({ + type: "muninn.move_marker_candidate", + schemaName: "muninn.move_marker_candidate", + schemaId: "muninn.move_marker_candidate.v1", + schemaVersion: "muninn.move_marker_candidate.v1", + global: false, + name: (value: DocumentValue) => value?.stream_id || value?.streamId || value?.camera_id || value?.cameraId || "move-marker-candidate", + schema: parseObjectDocument("Muninn Move marker candidate"), + }); + const muninnObsStreamCatalogDefinition = defineDocumentType({ + type: "muninn.obs_stream_catalog", + schemaName: "muninn.obs_stream_catalog", + schemaId: "muninn.obs_stream_catalog.v1", + schemaVersion: "muninn.obs_stream_catalog.v1", + global: false, + name: (value: DocumentValue) => value?.catalog_id || value?.catalogId || value?.host_id || value?.hostId || "muninn", + schema: parseObjectDocument("Muninn OBS stream catalog"), + }); + const muninnQuestAccessDefinition = defineDocumentType({ + type: "muninn.quest_access", + schemaName: "muninn.quest_access", + schemaId: "muninn.quest_access.v1", + schemaVersion: "muninn.quest_access.v1", + global: false, + name: (value: DocumentValue) => value?.access_id || value?.accessId || value?.serial || "quest-access", + schema: parseObjectDocument("Muninn Quest access"), + }); + const muninnTelemetrySurfaceDefinition = defineDocumentType({ + type: "muninn.telemetry_surface", + schemaName: "muninn.telemetry_surface", + schemaId: "muninn.telemetry_surface.v1", + schemaVersion: "muninn.telemetry_surface.v1", + global: false, + name: (value: DocumentValue) => value?.surface_id || value?.surfaceId || value?.host_id || value?.hostId || "muninn-telemetry", + schema: parseObjectDocument("Muninn telemetry surface"), + }); + const muninnTransportProfileDefinition = defineDocumentType({ + type: "muninn.transport_profile", + schemaName: "muninn.transport_profile", + schemaId: "muninn.transport_profile.v1", + schemaVersion: "muninn.transport_profile.v1", + global: false, + name: (value: DocumentValue) => value?.profile_id || value?.profileId || value?.daemon_id || value?.daemonId || "muninn", + schema: parseObjectDocument("Muninn transport profile"), + }); + const SleipnirInputMappingDefinition = defineDocumentType({ + type: "sleipnir.input_mapping", + schemaName: "sleipnir.input_mapping", + schemaId: "sleipnir.input_mapping.v1", + schemaVersion: "sleipnir.input_mapping.v1", + global: false, + name: (value: DocumentValue) => value?.providerId || value?.provider_id || "sleipnir", + schema: parseObjectDocument("Sleipnir input mapping"), + }); + const aetheriaAssetManifestDefinition = defineDocumentType({ + type: "gamecult.aetheria.asset_manifest", + schemaName: "gamecult.aetheria.asset_manifest", + schemaId: "gamecult.aetheria.asset_manifest.v1", + schemaVersion: "gamecult.aetheria.asset_manifest.v1", + global: false, + name: (value: DocumentValue) => value?.runId || value?.run_id || "aetheria-assets", + schema: parseObjectDocument("Aetheria asset manifest"), + }); + const aetheriaGravityViewportDefinition = defineDocumentType({ + type: "gamecult.fields.gravity", + schemaName: "gamecult.fields.gravity", + schemaId: "gamecult.fields.gravity.v1", + schemaVersion: "gamecult.fields.gravity.v1", + global: false, + name: (value: DocumentValue) => value?.viewportId || value?.viewport_id || "aetheria-gravity", + schema: parseObjectDocument("Aetheria gravity viewport"), + }); + const aetheriaObjectsViewportDefinition = defineDocumentType({ + type: "gamecult.fields.objects", + schemaName: "gamecult.fields.objects", + schemaId: "gamecult.fields.objects.v1", + schemaVersion: "gamecult.fields.objects.v1", + global: false, + name: (value: DocumentValue) => value?.viewportId || value?.viewport_id || "aetheria-objects", + schema: parseObjectDocument("Aetheria objects viewport"), + }); + const aetheriaRenderSplatsViewportDefinition = defineDocumentType({ + type: "gamecult.fields.splats", + schemaName: "gamecult.fields.splats", + schemaId: "gamecult.fields.splats.v1", + schemaVersion: "gamecult.fields.splats.v1", + global: false, + name: (value: DocumentValue) => value?.viewportId || value?.viewport_id || "aetheria-render-splats", + schema: parseObjectDocument("Aetheria render splats viewport"), + }); + const operatorStateDefinition = defineDocumentType({ + type: "gamecult.vili.operator_state", + schemaName: "gamecult.vili.operator_state", + schemaId: "gamecult.vili.operator_state.v1", + schemaVersion: "gamecult.vili.operator_state.v1", + global: false, + name: (value: DocumentValue) => value?.service || value?.providerId || "operator", + schema: parseObjectDocument("Vili operator state"), + }); + const viliCommandBoundaryDefinition = defineDocumentType({ + type: "gamecult.vili.command_boundary", + schemaName: "gamecult.vili.command_boundary", + schemaId: "gamecult.vili.command_boundary.v1", + schemaVersion: "gamecult.vili.command_boundary.v1", + global: false, + name: (value: DocumentValue) => value?.boundaryId || value?.daemonId || "vili", + schema: parseObjectDocument("Vili command boundary"), + }); + const viliTransportProfileDefinition = defineDocumentType({ + type: "gamecult.vili.transport_profile", + schemaName: "gamecult.vili.transport_profile", + schemaId: "gamecult.vili.transport_profile.v1", + schemaVersion: "gamecult.vili.transport_profile.v1", + global: false, + name: (value: DocumentValue) => value?.profileId || value?.daemonId || "vili", + schema: parseObjectDocument("Vili transport profile"), + }); + const weksaOperatorStateDefinition = defineDocumentType({ + type: "weksa.operator_state", + schemaName: "weksa.operator_state", + schemaId: "weksa.operator_state.v0", + schemaVersion: "weksa.operator_state.v0", + global: false, + name: (value: DocumentValue) => value?.daemon_id || value?.daemonId || value?.provider_id || value?.providerId || "weksa", + schema: parseObjectDocument("Weksa operator state"), + }); + const weksaCommandBoundaryDefinition = defineDocumentType({ + type: "weksa.command_boundary", + schemaName: "weksa.command_boundary", + schemaId: "weksa.command_boundary.v1", + schemaVersion: "weksa.command_boundary.v1", + global: false, + name: (value: DocumentValue) => value?.boundary_id || value?.boundaryId || value?.daemon_id || value?.daemonId || "weksa", + schema: parseObjectDocument("Weksa command boundary"), + }); + const weksaTransportProfileDefinition = defineDocumentType({ + type: "weksa.transport_profile", + schemaName: "weksa.transport_profile", + schemaId: "weksa.transport_profile.v1", + schemaVersion: "weksa.transport_profile.v1", + global: false, + name: (value: DocumentValue) => value?.profile_id || value?.profileId || value?.daemon_id || value?.daemonId || "weksa", + schema: parseObjectDocument("Weksa transport profile"), + }); + const stonksRequestEventDefinition = defineDocumentType({ + type: "stonks.request_event", + schemaName: "stonks.request_event", + schemaId: "stonks.request_event.v1", + schemaVersion: "stonks.request_event.v1", + global: false, + name: (value: DocumentValue) => value?.id || "request", + schema: parseObjectDocument("Stonks request event"), + }); + const stonksMarketSnapshotDefinition = defineDocumentType({ + type: "stonks.market_snapshot", + schemaName: "stonks.market_snapshot", + schemaId: "stonks.market_snapshot.v1", + schemaVersion: "stonks.market_snapshot.v1", + global: true, + schema: parseObjectDocument("Stonks market snapshot"), + }); + const stonksCommandBoundaryDefinition = defineDocumentType({ + type: "stonks.command_boundary", + schemaName: "stonks.command_boundary", + schemaId: "stonks.command_boundary.v1", + schemaVersion: "stonks.command_boundary.v1", + global: false, + name: (value: DocumentValue) => value?.boundaryId || value?.daemonId || "stonks", + schema: parseObjectDocument("Stonks command boundary"), + }); + const stonksTransportProfileDefinition = defineDocumentType({ + type: "stonks.transport_profile", + schemaName: "stonks.transport_profile", + schemaId: "stonks.transport_profile.v1", + schemaVersion: "stonks.transport_profile.v1", + global: false, + name: (value: DocumentValue) => value?.profileId || value?.daemonId || "stonks", + schema: parseObjectDocument("Stonks transport profile"), + }); + const streamPixelsCommandBoundaryDefinition = defineDocumentType({ + type: "streampixels.command_boundary", + schemaName: "streampixels.command_boundary", + schemaId: "streampixels.command_boundary.v1", + schemaVersion: "streampixels.command_boundary.v1", + global: false, + name: (value: DocumentValue) => value?.boundaryId || value?.daemonId || "streampixels", + schema: parseObjectDocument("StreamPixels command boundary"), + }); + const streamPixelsTransportProfileDefinition = defineDocumentType({ + type: "streampixels.transport_profile", + schemaName: "streampixels.transport_profile", + schemaId: "streampixels.transport_profile.v1", + schemaVersion: "streampixels.transport_profile.v1", + global: false, + name: (value: DocumentValue) => value?.profileId || value?.daemonId || "streampixels", + schema: parseObjectDocument("StreamPixels transport profile"), + }); + const voidbotSwarmSnapshotDefinition = defineDocumentType({ + type: "voidbot.swarm_state_snapshot", + schemaName: "voidbot.swarm_state_snapshot", + schemaId: "voidbot.swarm_state_snapshot.v1", + schemaVersion: "voidbot.swarm_state_snapshot.v1", + global: true, + schema: parseObjectDocument("VoidBot swarm snapshot"), + }); + const voidbotProviderCatalogDefinition = defineDocumentType({ + type: "voidbot.provider_advertisement_catalog", + schemaName: "voidbot.provider_advertisement_catalog", + schemaId: "voidbot.provider_advertisement_catalog.v0", + schemaVersion: "voidbot.provider_advertisement_catalog.v0", + global: true, + schema: parseObjectDocument("VoidBot provider advertisement catalog"), + }); + + return { + interfaceBindingDefinition, + evePluginAdvertisementDefinition, + ghostlightSchemaCatalogDefinition, + heimdallCommandBoundaryDefinition, + heimdallTransportProfileDefinition, + interfaceLayoutDefinition, + idunnCommandBoundaryDefinition, + idunnDaemonHealthDefinition, + idunnTransportProfileDefinition, + muninnCaptureStreamCommandDefinition, + muninnCaptureStreamDefinition, + muninnCommandBoundaryDefinition, + muninnMediaAudioPacketDefinition, + muninnMediaReceiverFeedbackDefinition, + muninnMediaVideoAccessUnitDefinition, + muninnHidControllerStateDefinition, + muninnMoveControllerStateDefinition, + muninnMoveIdentityDefinition, + muninnMoveLightCommandDefinition, + muninnMoveMarkerCandidateDefinition, + muninnObsStreamCatalogDefinition, + muninnQuestAccessDefinition, + muninnTelemetrySurfaceDefinition, + muninnTransportProfileDefinition, + SleipnirInputMappingDefinition, + aetheriaAssetManifestDefinition, + aetheriaGravityViewportDefinition, + aetheriaObjectsViewportDefinition, + aetheriaRenderSplatsViewportDefinition, + operatorStateDefinition, + providerAdvertisementDefinition, + stonksCommandBoundaryDefinition, + stonksMarketSnapshotDefinition, + stonksRequestEventDefinition, + stonksTransportProfileDefinition, + streamPixelsCommandBoundaryDefinition, + streamPixelsTransportProfileDefinition, + surfaceDefinition, + viliCommandBoundaryDefinition, + viliTransportProfileDefinition, + weksaCommandBoundaryDefinition, + weksaOperatorStateDefinition, + weksaTransportProfileDefinition, + voidbotProviderCatalogDefinition, + voidbotSwarmSnapshotDefinition, + }; +} + From d1a9edad3a116be341b0b5198c6998c31a083bda Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 7 Sep 2026 21:42:54 +0200 Subject: [PATCH 148/283] Port gamecult.runtime_presence_health.v2 to cultnet-ts The dual-proved runtime presence contract existed only in cultnet-rs, so no TypeScript service could make a statement Odin admits as presence. Odin files anything else away as an ordinary document and never produces a topology correlation for it, which is why Heimdall could warm forever without being promoted. The port is what it should be: the same fields at the same key slots. The Rust derive serialises a positional tuple indexed by those slots, so the TypeScript side names the slots and fills the same 24. Both proofs cover one payload -- the complete record with both signature fields empty -- and the two signing messages use the domain separation their respective identities already define. Conformance is against vectors emitted by cultnet-rs, not a fixture written for both sides at once, which would agree with itself and prove nothing: `cargo run --example runtime_presence_vector -p cultnet-rs` regenerates them. Co-Authored-By: Claude Opus 5 --- .../examples/runtime_presence_vector.rs | 67 +++++ packages/cultnet-ts/src/index.ts | 18 ++ .../cultnet-ts/src/runtime-presence-health.ts | 256 ++++++++++++++++++ .../fixtures/runtime-presence-vectors.json | 4 + .../test/runtime-presence-health.test.ts | 123 +++++++++ 5 files changed, 468 insertions(+) create mode 100644 packages/cultnet-rs/examples/runtime_presence_vector.rs create mode 100644 packages/cultnet-ts/src/runtime-presence-health.ts create mode 100644 packages/cultnet-ts/test/fixtures/runtime-presence-vectors.json create mode 100644 packages/cultnet-ts/test/runtime-presence-health.test.ts diff --git a/packages/cultnet-rs/examples/runtime_presence_vector.rs b/packages/cultnet-rs/examples/runtime_presence_vector.rs new file mode 100644 index 00000000..04571a8b --- /dev/null +++ b/packages/cultnet-rs/examples/runtime_presence_vector.rs @@ -0,0 +1,67 @@ +//! Emit canonical bytes for one fixed runtime-presence record. +//! +//! This is the reference the TypeScript fork is tested against. The two forks +//! agree only if `gamecult.runtime_presence_health.v2` means the same bytes in +//! both, and the only way to know that is to have one produce the vector and +//! the other reproduce it. A fixture written by hand for both sides would agree +//! with itself and prove nothing. + +use cultnet_rs::{GameCultRuntimeCapability, GameCultRuntimePresenceHealthRecord}; + +fn main() -> anyhow::Result<()> { + let record = GameCultRuntimePresenceHealthRecord { + schema_version: "gamecult.runtime_presence_health.v2".into(), + target: "heimdall".into(), + expected_projection_sha256: format!("sha256-{}", "a".repeat(64)), + plan_id: format!("sha256-{}", "b".repeat(64)), + incarnation_id: "service-incarnation-1".into(), + sealed_release_id: format!("sha256-{}", "c".repeat(64)), + activation_witness_sha256: format!("sha256-{}", "d".repeat(64)), + state_schema_generation: Some("v1".into()), + state_contract_sha256: Some(format!("sha256-{}", "e".repeat(64))), + runtime_id: "heimdall-yggdrasil".into(), + runtime_instance_id: format!("sha256-{}", "f".repeat(64)), + bound_endpoint: Some("http://127.0.0.1:14101".into()), + capabilities: vec![ + GameCultRuntimeCapability { + capability: "heimdall.access".into(), + schema: "heimdall.access.v1".into(), + compatibility: "v1".into(), + capacity: 2, + }, + GameCultRuntimeCapability { + capability: "zeta.runtime".into(), + schema: "zeta.runtime.v1".into(), + compatibility: "v1".into(), + capacity: 1, + }, + ], + health_contract: "heimdall.cultnet-rudp-provider-health".into(), + state: "warming".into(), + detail: "Heimdall candidate warming".into(), + write_lease_sha256: None, + signer_identity_id: "1".repeat(64), + publisher_sequence: 7, + observed_at_unix_millis: 1_757_000_000_000, + signature_algorithm: "ed25519".into(), + signature: Vec::new(), + activation_signer_identity_id: "2".repeat(64), + activation_signature: Vec::new(), + }; + + // The proof payload: both signature fields empty. This is what both keys + // sign, so it is the vector that matters most. + let proof = record.canonical_proof_payload()?; + println!("proof {}", hex(&proof)); + + // And the complete record, with both proofs filled, to pin the signed shape. + let mut signed = record; + signed.signature = vec![0x11; 64]; + signed.activation_signature = vec![0x22; 64]; + println!("signed {}", hex(&rmp_serde::to_vec(&signed)?)); + Ok(()) +} + +fn hex(bytes: &[u8]) -> String { + bytes.iter().map(|byte| format!("{byte:02x}")).collect() +} diff --git a/packages/cultnet-ts/src/index.ts b/packages/cultnet-ts/src/index.ts index db24d17b..140526c5 100644 --- a/packages/cultnet-ts/src/index.ts +++ b/packages/cultnet-ts/src/index.ts @@ -156,3 +156,21 @@ export { type SignedDaemonHealthPublisher, type SignedDaemonHealthPublisherOptions, } from "./signed-daemon-health"; + +export { + GAMECULT_RUNTIME_ACTIVATION_PROOF_SIGNING_PURPOSE, + GAMECULT_RUNTIME_PRESENCE_HEALTH_SCHEMA, + GAMECULT_RUNTIME_PRESENCE_HEALTH_SIGNING_PURPOSE, + GAMECULT_RUNTIME_PRESENCE_IDENTITY_NAME, + IDUNN_RUNTIME_ACTIVATION_CREDENTIAL_NAME, + RUNTIME_PRESENCE_FIELD_COUNT, + RUNTIME_PRESENCE_SLOT, + encodeRuntimePresenceHealth, + runtimePresenceActivationSigningMessage, + runtimePresenceProofPayload, + runtimePresenceProviderSigningMessage, + validateRuntimePresence, + type GameCultRuntimeCapability, + type RuntimePresenceHealth, + type RuntimePresenceState, +} from "./runtime-presence-health"; diff --git a/packages/cultnet-ts/src/runtime-presence-health.ts b/packages/cultnet-ts/src/runtime-presence-health.ts new file mode 100644 index 00000000..8d70da8e --- /dev/null +++ b/packages/cultnet-ts/src/runtime-presence-health.ts @@ -0,0 +1,256 @@ +// Runtime presence health: the dual-proved statement one launched incarnation +// makes about itself. +// +// This is the TypeScript half of `gamecult.runtime_presence_health.v2`, the +// contract `cultnet-rs` defines in `runtime_authority_contracts.rs`. Odin admits +// a document as runtime presence only when it carries this schema id and its +// record key equals the signed target; anything else it files away as an +// ordinary document, and no topology correlation is ever produced for it. +// +// Two proofs cover one payload. The stable provider key says "this service made +// this statement"; the activation key Idunn hands the process at launch says +// "and it is the incarnation Idunn started". Neither establishes admission +// alone, which is why both signature fields are empty in the signed bytes: it +// avoids a circular signature while binding every authority-bearing field and +// both signer identities. +// +// The wire shape is a positional tuple indexed by the same field slots the Rust +// derive emits. Field N here is field N there; that correspondence is the whole +// contract, and the constants below name the slots so it stays checkable. + +import { encode } from "@msgpack/msgpack"; + +export const GAMECULT_RUNTIME_PRESENCE_HEALTH_SCHEMA = "gamecult.runtime_presence_health.v2"; + +/** Purpose for the stable provider-health signature over the proof payload. */ +export const GAMECULT_RUNTIME_PRESENCE_HEALTH_SIGNING_PURPOSE = + "gamecult.runtime_presence_health.v2"; + +/** Purpose for the activation-scoped proof over the same payload. */ +export const GAMECULT_RUNTIME_ACTIVATION_PROOF_SIGNING_PURPOSE = + "gamecult.runtime_presence.activation-proof.v1"; + +/** systemd file-descriptor name Idunn uses for the activation signing key. */ +export const IDUNN_RUNTIME_ACTIVATION_CREDENTIAL_NAME = "gamecult-idunn-runtime-activation-key"; + +/** systemd file-descriptor name Idunn uses for the provider-health identity. */ +export const GAMECULT_RUNTIME_PRESENCE_IDENTITY_NAME = "gamecult-runtime-presence-identity"; + +const PROVIDER_HEALTH_SIGNATURE_DOMAIN = Buffer.from( + "gamecult.provider-health.signature.v1\0", + "utf8", +); + +const RUNTIME_ACTIVATION_SIGNATURE_DOMAIN = Buffer.from( + "idunn.runtime-activation.signature.v1\0", + "utf8", +); + +/** + * Positional slots, mirroring the `#[cultcache(key = N)]` attributes on + * `GameCultRuntimePresenceHealthRecord`. The tuple is always this long: the + * Rust derive serialises `max_slot + 1` elements regardless of which are set. + */ +export const RUNTIME_PRESENCE_SLOT = { + schemaVersion: 0, + target: 1, + expectedProjectionSha256: 2, + planId: 3, + incarnationId: 4, + sealedReleaseId: 5, + activationWitnessSha256: 6, + stateSchemaGeneration: 7, + stateContractSha256: 8, + runtimeId: 9, + runtimeInstanceId: 10, + boundEndpoint: 11, + capabilities: 12, + healthContract: 13, + state: 14, + detail: 15, + writeLeaseSha256: 16, + signerIdentityId: 17, + publisherSequence: 18, + observedAtUnixMillis: 19, + signatureAlgorithm: 20, + signature: 21, + activationSignerIdentityId: 22, + activationSignature: 23, +} as const; + +export const RUNTIME_PRESENCE_FIELD_COUNT = 24; + +/** A capability claim. Nested as its own positional tuple, not a map. */ +export interface GameCultRuntimeCapability { + capability: string; + schema: string; + compatibility: string; + capacity: number; +} + +/** The states the contract admits. */ +export type RuntimePresenceState = "warming" | "active" | "degraded" | "failed"; + +export interface RuntimePresenceHealth { + target: string; + expectedProjectionSha256: string; + planId: string; + incarnationId: string; + sealedReleaseId: string; + activationWitnessSha256: string; + stateSchemaGeneration: string | null; + stateContractSha256: string | null; + runtimeId: string; + runtimeInstanceId: string; + boundEndpoint: string | null; + capabilities: GameCultRuntimeCapability[]; + healthContract: string; + state: RuntimePresenceState; + detail: string; + writeLeaseSha256: string | null; + signerIdentityId: string; + publisherSequence: number; + observedAtUnixMillis: number; + activationSignerIdentityId: string; +} + +function encodeCapability(capability: GameCultRuntimeCapability): unknown[] { + // Plain serde struct on the Rust side, and the record is encoded with + // rmp_serde's compact form, so a capability is a positional tuple too. + return [capability.capability, capability.schema, capability.compatibility, capability.capacity]; +} + +/** + * Capabilities are canonical only when strictly increasing by + * `(capability, schema, compatibility)`. Sorting here rather than trusting the + * caller keeps a correct statement from being rejected over field order. + */ +function canonicalCapabilities(capabilities: GameCultRuntimeCapability[]): unknown[][] { + const sorted = [...capabilities].sort((left, right) => { + const leftKey = [left.capability, left.schema, left.compatibility]; + const rightKey = [right.capability, right.schema, right.compatibility]; + for (let index = 0; index < leftKey.length; index += 1) { + if (leftKey[index]! < rightKey[index]!) return -1; + if (leftKey[index]! > rightKey[index]!) return 1; + } + return 0; + }); + return sorted.map(encodeCapability); +} + +function presenceTuple( + presence: RuntimePresenceHealth, + signature: Uint8Array, + activationSignature: Uint8Array, +): unknown[] { + const fields = new Array(RUNTIME_PRESENCE_FIELD_COUNT); + fields[RUNTIME_PRESENCE_SLOT.schemaVersion] = GAMECULT_RUNTIME_PRESENCE_HEALTH_SCHEMA; + fields[RUNTIME_PRESENCE_SLOT.target] = presence.target; + fields[RUNTIME_PRESENCE_SLOT.expectedProjectionSha256] = presence.expectedProjectionSha256; + fields[RUNTIME_PRESENCE_SLOT.planId] = presence.planId; + fields[RUNTIME_PRESENCE_SLOT.incarnationId] = presence.incarnationId; + fields[RUNTIME_PRESENCE_SLOT.sealedReleaseId] = presence.sealedReleaseId; + fields[RUNTIME_PRESENCE_SLOT.activationWitnessSha256] = presence.activationWitnessSha256; + fields[RUNTIME_PRESENCE_SLOT.stateSchemaGeneration] = presence.stateSchemaGeneration; + fields[RUNTIME_PRESENCE_SLOT.stateContractSha256] = presence.stateContractSha256; + fields[RUNTIME_PRESENCE_SLOT.runtimeId] = presence.runtimeId; + fields[RUNTIME_PRESENCE_SLOT.runtimeInstanceId] = presence.runtimeInstanceId; + fields[RUNTIME_PRESENCE_SLOT.boundEndpoint] = presence.boundEndpoint; + fields[RUNTIME_PRESENCE_SLOT.capabilities] = canonicalCapabilities(presence.capabilities); + fields[RUNTIME_PRESENCE_SLOT.healthContract] = presence.healthContract; + fields[RUNTIME_PRESENCE_SLOT.state] = presence.state; + fields[RUNTIME_PRESENCE_SLOT.detail] = presence.detail; + fields[RUNTIME_PRESENCE_SLOT.writeLeaseSha256] = presence.writeLeaseSha256; + fields[RUNTIME_PRESENCE_SLOT.signerIdentityId] = presence.signerIdentityId; + fields[RUNTIME_PRESENCE_SLOT.publisherSequence] = presence.publisherSequence; + fields[RUNTIME_PRESENCE_SLOT.observedAtUnixMillis] = presence.observedAtUnixMillis; + fields[RUNTIME_PRESENCE_SLOT.signatureAlgorithm] = "ed25519"; + fields[RUNTIME_PRESENCE_SLOT.signature] = signature; + fields[RUNTIME_PRESENCE_SLOT.activationSignerIdentityId] = presence.activationSignerIdentityId; + fields[RUNTIME_PRESENCE_SLOT.activationSignature] = activationSignature; + return fields; +} + +/** + * Reject statements the contract forbids, before they are signed. + * + * These are the same conditions `validate_shape` enforces on the Rust side. A + * statement that fails here would be refused after a round trip and a signature; + * failing early names the actual problem instead. + */ +export function validateRuntimePresence(presence: RuntimePresenceHealth): void { + if (presence.publisherSequence <= 0 || !Number.isSafeInteger(presence.publisherSequence)) { + throw new Error("runtime presence publisher sequence must be a positive integer"); + } + if (presence.observedAtUnixMillis <= 0 || !Number.isSafeInteger(presence.observedAtUnixMillis)) { + throw new Error("runtime presence observation time must be a positive integer"); + } + if (presence.detail.length > 512 || /\p{Cc}/u.test(presence.detail)) { + throw new Error("runtime presence detail is too long or carries control characters"); + } + if (presence.state === "warming" && presence.writeLeaseSha256 !== null) { + throw new Error("warming runtime presence cannot claim a process write lease"); + } + if (presence.stateSchemaGeneration === null && presence.writeLeaseSha256 !== null) { + throw new Error("stateless runtime presence cannot claim a process write lease"); + } + const generationPresent = presence.stateSchemaGeneration !== null; + const contractPresent = presence.stateContractSha256 !== null; + if (generationPresent !== contractPresent) { + throw new Error("runtime presence state lineage is partial"); + } +} + +/** + * The one payload both proofs cover: the complete record with both signature + * fields empty. + */ +export function runtimePresenceProofPayload(presence: RuntimePresenceHealth): Uint8Array { + validateRuntimePresence(presence); + return encode(presenceTuple(presence, new Uint8Array(), new Uint8Array())); +} + +/** The complete signed record, as put on the wire. */ +export function encodeRuntimePresenceHealth( + presence: RuntimePresenceHealth, + signature: Uint8Array, + activationSignature: Uint8Array, +): Uint8Array { + if (signature.length !== 64 || activationSignature.length !== 64) { + throw new Error("runtime presence proofs must both be 64-byte ed25519 signatures"); + } + validateRuntimePresence(presence); + return encode(presenceTuple(presence, signature, activationSignature)); +} + +function domainSeparated(domain: Buffer, purpose: string, payload: Uint8Array): Buffer { + const purposeBytes = Buffer.from(purpose, "utf8"); + const lengths = Buffer.alloc(16); + lengths.writeBigUInt64BE(BigInt(purposeBytes.length), 0); + lengths.writeBigUInt64BE(BigInt(payload.length), 8); + return Buffer.concat([ + domain, + lengths.subarray(0, 8), + purposeBytes, + lengths.subarray(8, 16), + Buffer.from(payload), + ]); +} + +/** Message the stable provider-health key signs. */ +export function runtimePresenceProviderSigningMessage(payload: Uint8Array): Buffer { + return domainSeparated( + PROVIDER_HEALTH_SIGNATURE_DOMAIN, + GAMECULT_RUNTIME_PRESENCE_HEALTH_SIGNING_PURPOSE, + payload, + ); +} + +/** Message the activation key Idunn passed at launch signs. */ +export function runtimePresenceActivationSigningMessage(payload: Uint8Array): Buffer { + return domainSeparated( + RUNTIME_ACTIVATION_SIGNATURE_DOMAIN, + GAMECULT_RUNTIME_ACTIVATION_PROOF_SIGNING_PURPOSE, + payload, + ); +} diff --git a/packages/cultnet-ts/test/fixtures/runtime-presence-vectors.json b/packages/cultnet-ts/test/fixtures/runtime-presence-vectors.json new file mode 100644 index 00000000..043689f4 --- /dev/null +++ b/packages/cultnet-ts/test/fixtures/runtime-presence-vectors.json @@ -0,0 +1,4 @@ +{ + "proof": "dc0018d92367616d6563756c742e72756e74696d655f70726573656e63655f6865616c74682e7632a86865696d64616c6cd9477368613235362d61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161d9477368613235362d62626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262b5736572766963652d696e6361726e6174696f6e2d31d9477368613235362d63636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363d9477368613235362d64646464646464646464646464646464646464646464646464646464646464646464646464646464646464646464646464646464646464646464646464646464a27631d9477368613235362d65656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565b26865696d64616c6c2d79676764726173696cd9477368613235362d66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666b6687474703a2f2f3132372e302e302e313a31343130319294af6865696d64616c6c2e616363657373b26865696d64616c6c2e6163636573732e7631a276310294ac7a6574612e72756e74696d65af7a6574612e72756e74696d652e7631a2763101d9256865696d64616c6c2e63756c746e65742d727564702d70726f76696465722d6865616c7468a77761726d696e67ba4865696d64616c6c2063616e646964617465207761726d696e67c0d9403131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313107cf00000199155c6200a765643235353139c400d94032323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232c400", + "signed": "dc0018d92367616d6563756c742e72756e74696d655f70726573656e63655f6865616c74682e7632a86865696d64616c6cd9477368613235362d61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161d9477368613235362d62626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262b5736572766963652d696e6361726e6174696f6e2d31d9477368613235362d63636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363d9477368613235362d64646464646464646464646464646464646464646464646464646464646464646464646464646464646464646464646464646464646464646464646464646464a27631d9477368613235362d65656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565b26865696d64616c6c2d79676764726173696cd9477368613235362d66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666b6687474703a2f2f3132372e302e302e313a31343130319294af6865696d64616c6c2e616363657373b26865696d64616c6c2e6163636573732e7631a276310294ac7a6574612e72756e74696d65af7a6574612e72756e74696d652e7631a2763101d9256865696d64616c6c2e63756c746e65742d727564702d70726f76696465722d6865616c7468a77761726d696e67ba4865696d64616c6c2063616e646964617465207761726d696e67c0d9403131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313107cf00000199155c6200a765643235353139c44011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111d94032323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232c44022222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222" +} diff --git a/packages/cultnet-ts/test/runtime-presence-health.test.ts b/packages/cultnet-ts/test/runtime-presence-health.test.ts new file mode 100644 index 00000000..fa21aeaa --- /dev/null +++ b/packages/cultnet-ts/test/runtime-presence-health.test.ts @@ -0,0 +1,123 @@ +// Cross-fork conformance for `gamecult.runtime_presence_health.v2`. +// +// The vectors below were produced by `cultnet-rs`, not written by hand: +// +// cargo run --example runtime_presence_vector -p cultnet-rs +// +// That matters. A fixture authored for both sides at once agrees with itself +// and proves nothing; the contract is only real if one fork emits the bytes and +// the other reproduces them. Regenerate these vectors from the Rust example if +// the record ever changes, and never by editing them to match this code. + +import test from "node:test"; +import assert from "node:assert/strict"; +import { readFileSync } from "node:fs"; +import { join } from "node:path"; + +import { + RUNTIME_PRESENCE_FIELD_COUNT, + encodeRuntimePresenceHealth, + runtimePresenceProofPayload, + validateRuntimePresence, + type RuntimePresenceHealth, +} from "../src/runtime-presence-health"; + +// Read from the source tree, not a copy beside the compiled test: the vectors +// are generated output and must have exactly one home. +const VECTORS = JSON.parse( + readFileSync( + join(__dirname, "..", "..", "test", "fixtures", "runtime-presence-vectors.json"), + "utf8", + ), +) as { proof: string; signed: string }; + +/** The same statement the Rust example builds. */ +function referencePresence(): RuntimePresenceHealth { + return { + target: "heimdall", + expectedProjectionSha256: `sha256-${"a".repeat(64)}`, + planId: `sha256-${"b".repeat(64)}`, + incarnationId: "service-incarnation-1", + sealedReleaseId: `sha256-${"c".repeat(64)}`, + activationWitnessSha256: `sha256-${"d".repeat(64)}`, + stateSchemaGeneration: "v1", + stateContractSha256: `sha256-${"e".repeat(64)}`, + runtimeId: "heimdall-yggdrasil", + runtimeInstanceId: `sha256-${"f".repeat(64)}`, + boundEndpoint: "http://127.0.0.1:14101", + capabilities: [ + { + capability: "heimdall.access", + schema: "heimdall.access.v1", + compatibility: "v1", + capacity: 2, + }, + { capability: "zeta.runtime", schema: "zeta.runtime.v1", compatibility: "v1", capacity: 1 }, + ], + healthContract: "heimdall.cultnet-rudp-provider-health", + state: "warming", + detail: "Heimdall candidate warming", + writeLeaseSha256: null, + signerIdentityId: "1".repeat(64), + publisherSequence: 7, + observedAtUnixMillis: 1_757_000_000_000, + activationSignerIdentityId: "2".repeat(64), + }; +} + +function hex(bytes: Uint8Array): string { + return Buffer.from(bytes).toString("hex"); +} + +test("the proof payload is byte-identical to the one cultnet-rs signs", () => { + assert.equal(hex(runtimePresenceProofPayload(referencePresence())), VECTORS.proof); +}); + +test("the signed record carries both proofs in their own slots", () => { + const signed = encodeRuntimePresenceHealth( + referencePresence(), + new Uint8Array(64).fill(0x11), + new Uint8Array(64).fill(0x22), + ); + // Byte-identical to the fully signed record cultnet-rs emits, so the proofs + // land in their own slots rather than being appended. + assert.equal(hex(signed), VECTORS.signed); +}); + +test("capabilities are ordered canonically regardless of caller order", () => { + const presence = referencePresence(); + const reversed = { ...presence, capabilities: [...presence.capabilities].reverse() }; + assert.equal( + hex(runtimePresenceProofPayload(reversed)), + hex(runtimePresenceProofPayload(presence)), + ); +}); + +test("the tuple is always the full contract width", () => { + assert.equal(RUNTIME_PRESENCE_FIELD_COUNT, 24); +}); + +test("statements the contract forbids are refused before they are signed", () => { + const warmingWithLease = { + ...referencePresence(), + writeLeaseSha256: `sha256-${"0".repeat(64)}`, + }; + assert.throws(() => validateRuntimePresence(warmingWithLease), /cannot claim a process write/); + + const statelessWithLease = { + ...referencePresence(), + state: "active" as const, + stateSchemaGeneration: null, + stateContractSha256: null, + writeLeaseSha256: `sha256-${"0".repeat(64)}`, + }; + assert.throws(() => validateRuntimePresence(statelessWithLease), /stateless runtime presence/); + + assert.throws( + () => validateRuntimePresence({ ...referencePresence(), publisherSequence: 0 }), + /publisher sequence/, + ); + + const partialLineage = { ...referencePresence(), stateContractSha256: null }; + assert.throws(() => validateRuntimePresence(partialLineage), /state lineage is partial/); +}); From a250ec69eb91a2a89b34e8899e9a6b0114ba46dd Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 10 Sep 2026 00:17:19 +0200 Subject: [PATCH 149/283] Give the media stream records a home that is not one producer's MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Four record types described a media stream and nothing about who produced it, while living in odin-core under a `muninn.` prefix. Every field is producer-agnostic; the name was the only coupling, and a second producer would have had to impersonate Muninn or fork the shape. They move to cultnet-rs as `gamecult.media_*`, matching the prefix already used for cross-service contracts like gamecult.runtime_presence_health and gamecult.service_trust_anchor, while cultmesh.* stays reserved for session primitives. Field order and key indices are carried over untouched, including the `default` on missing_video_chunk_keys. The tests pin what a consumer in another language is entitled to rely on: positional layout, the slot each field occupies, and that a record written before that field was appended still decodes. One test is ignored rather than passing. Byte payloads currently serialize as MessagePack arrays of integers because the derive writes its own Serialize and ignores serde attributes; C#, TypeScript and Python all emit bin, which makes Rust the divergent runtime and costs 1.45x on every media byte. Fixing it needs an opt-in hint in cultcache-rs-derive rather than a global change, because signatures are taken over the whole positional serialization and canonical hashes over the same bytes — flipping byte encoding estate-wide would invalidate the live Idunn authority chain. That work is sequenced by the Swarm Migration session; the ignored test un-ignores when the hint lands. Parked on its own branch. The Muninn and Odin ends of this move are not done: odin-core still declares these types, and muninn-daemon still imports them from there. Co-Authored-By: Claude Opus 5 --- packages/cultnet-rs/src/lib.rs | 2 + .../cultnet-rs/src/media_stream_contracts.rs | 194 +++++++++++++++ .../tests/media_stream_contracts.rs | 227 ++++++++++++++++++ 3 files changed, 423 insertions(+) create mode 100644 packages/cultnet-rs/src/media_stream_contracts.rs create mode 100644 packages/cultnet-rs/tests/media_stream_contracts.rs diff --git a/packages/cultnet-rs/src/lib.rs b/packages/cultnet-rs/src/lib.rs index 3e8a3c94..5aa121af 100644 --- a/packages/cultnet-rs/src/lib.rs +++ b/packages/cultnet-rs/src/lib.rs @@ -1,6 +1,7 @@ mod contracts; mod idunn_deployment_brake; mod idunn_lifecycle_brake; +mod media_stream_contracts; mod provider_health_contracts; mod runtime_authority_contracts; mod service_identity; @@ -19,6 +20,7 @@ mod transport; pub use contracts::*; pub use idunn_deployment_brake::*; pub use idunn_lifecycle_brake::*; +pub use media_stream_contracts::*; pub use provider_health_contracts::*; pub use runtime_authority_contracts::*; pub use service_identity::*; diff --git a/packages/cultnet-rs/src/media_stream_contracts.rs b/packages/cultnet-rs/src/media_stream_contracts.rs new file mode 100644 index 00000000..e47b3a28 --- /dev/null +++ b/packages/cultnet-rs/src/media_stream_contracts.rs @@ -0,0 +1,194 @@ +//! CultMesh Media Stream: the typed contract for carrying live audio and video +//! over CultNet. +//! +//! These records describe a media stream and nothing about who produced it. A +//! capture broker, an editor runtime, a recorder, or a synthetic source may all +//! publish them; an OBS bridge, a compositor, a recorder, or a browser lowering +//! may all consume them. Producers advertise their streams through Odin and +//! consumers resolve them there, so neither end needs to name the other. +//! +//! They lived in `odin-core` as `muninn.media_*`, named after the one producer +//! that happened to emit them first. Every field here is producer-agnostic — the +//! name was the only coupling, and a second producer would have had to +//! impersonate Muninn or fork the shape. +//! +//! # Layout is wire contract +//! +//! CultCache encodes these positionally. Field order and `key` indices are the +//! wire format: append new fields with `default` at the next free index, never +//! reorder or renumber. `missing_video_chunk_keys` shows the pattern. +//! +//! # Timebase +//! +//! `pts_ticks`, `duration_ticks` and `deadline_ticks` are expressed in +//! `timebase_num / timebase_den` units, carried per record so a consumer never +//! has to assume a producer's clock. `deadline_ticks` is the presentation +//! deadline past which a late arrival is worth dropping rather than displaying. +//! +//! # Reliability +//! +//! Nothing here specifies a delivery guarantee. Whether a stream rides a +//! reliable or lossy CultNet channel, and whether it carries parity, is a +//! transport decision made per stream — not a property of the payload shape. +//! Video parity shards exist for producers that choose forward error correction; +//! audio currently has no parity record, and a producer emitting audio on a +//! lossy channel needs one. + +use cultcache_rs::DatabaseEntry; + +pub const GAMECULT_MEDIA_VIDEO_ACCESS_UNIT_SCHEMA: &str = "gamecult.media_video_access_unit.v1"; +pub const GAMECULT_MEDIA_VIDEO_PARITY_SHARD_SCHEMA: &str = "gamecult.media_video_parity_shard.v2"; +pub const GAMECULT_MEDIA_AUDIO_PACKET_SCHEMA: &str = "gamecult.media_audio_packet.v1"; +pub const GAMECULT_MEDIA_RECEIVER_FEEDBACK_SCHEMA: &str = "gamecult.media_receiver_feedback.v1"; + +/// One coded video access unit, possibly split across `chunk_count` records +/// sharing a `frame_id`. A consumer reassembles by `(stream_id, session_id, +/// frame_id)` and orders by `chunk_index`. +#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] +#[cultcache( + type = "gamecult.media_video_access_unit", + schema = "gamecult.media_video_access_unit.v1" +)] +pub struct GameCultMediaVideoAccessUnitRecord { + #[cultcache(key = 0)] + pub stream_id: String, + #[cultcache(key = 1)] + pub session_id: String, + #[cultcache(key = 2)] + pub frame_id: u64, + #[cultcache(key = 3)] + pub codec: String, + #[cultcache(key = 4)] + pub pts_ticks: i64, + #[cultcache(key = 5)] + pub duration_ticks: u32, + #[cultcache(key = 6)] + pub timebase_num: u32, + #[cultcache(key = 7)] + pub timebase_den: u32, + #[cultcache(key = 8)] + pub keyframe: bool, + #[cultcache(key = 9)] + pub dependency_frame_id: Option, + #[cultcache(key = 10)] + pub deadline_ticks: i64, + #[cultcache(key = 11)] + pub chunk_index: u16, + #[cultcache(key = 12)] + pub chunk_count: u16, + #[cultcache(key = 13)] + pub payload: Vec, +} + +/// Forward-error-correction parity for one video access unit. Carries the +/// framing fields of the access unit it protects so a receiver can recover +/// without having seen the original, plus the shard geometry needed to run +/// recovery: `parity_index` within `parity_count`, and the chunk sizes the +/// parity was computed over. +#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] +#[cultcache( + type = "gamecult.media_video_parity_shard", + schema = "gamecult.media_video_parity_shard.v2" +)] +pub struct GameCultMediaVideoParityShardRecord { + #[cultcache(key = 0)] + pub stream_id: String, + #[cultcache(key = 1)] + pub session_id: String, + #[cultcache(key = 2)] + pub frame_id: u64, + #[cultcache(key = 3)] + pub codec: String, + #[cultcache(key = 4)] + pub pts_ticks: i64, + #[cultcache(key = 5)] + pub duration_ticks: u32, + #[cultcache(key = 6)] + pub timebase_num: u32, + #[cultcache(key = 7)] + pub timebase_den: u32, + #[cultcache(key = 8)] + pub keyframe: bool, + #[cultcache(key = 9)] + pub dependency_frame_id: Option, + #[cultcache(key = 10)] + pub deadline_ticks: i64, + #[cultcache(key = 11)] + pub chunk_count: u16, + #[cultcache(key = 12)] + pub parity_index: u16, + #[cultcache(key = 13)] + pub parity_count: u16, + #[cultcache(key = 14)] + pub chunk_payload_bytes: u32, + #[cultcache(key = 15)] + pub last_chunk_payload_bytes: u32, + #[cultcache(key = 16)] + pub payload: Vec, +} + +/// One coded audio packet. Unlike video these are not chunked: a packet is +/// whole or it is absent, and `payload` carries whatever `codec` names. +#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] +#[cultcache( + type = "gamecult.media_audio_packet", + schema = "gamecult.media_audio_packet.v1" +)] +pub struct GameCultMediaAudioPacketRecord { + #[cultcache(key = 0)] + pub stream_id: String, + #[cultcache(key = 1)] + pub session_id: String, + #[cultcache(key = 2)] + pub packet_id: u64, + #[cultcache(key = 3)] + pub codec: String, + #[cultcache(key = 4)] + pub pts_ticks: i64, + #[cultcache(key = 5)] + pub duration_ticks: u32, + #[cultcache(key = 6)] + pub timebase_num: u32, + #[cultcache(key = 7)] + pub timebase_den: u32, + #[cultcache(key = 8)] + pub deadline_ticks: i64, + #[cultcache(key = 9)] + pub payload: Vec, +} + +/// What a receiver observed, published back to the producer so it can adapt: +/// what decoded, what is missing, what arrived too late, and how much queue and +/// jitter the receiver is carrying. +/// +/// This is the only record here that flows consumer-to-producer. A producer is +/// free to ignore it; it reports observation, it does not issue commands. +#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] +#[cultcache( + type = "gamecult.media_receiver_feedback", + schema = "gamecult.media_receiver_feedback.v1" +)] +pub struct GameCultMediaReceiverFeedbackRecord { + #[cultcache(key = 0)] + pub stream_id: String, + #[cultcache(key = 1)] + pub session_id: String, + #[cultcache(key = 2)] + pub receiver_id: String, + #[cultcache(key = 3)] + pub highest_decodable_frame_id: Option, + #[cultcache(key = 4)] + pub missing_frame_ids: Vec, + #[cultcache(key = 5)] + pub late_frame_ids: Vec, + #[cultcache(key = 6)] + pub requested_keyframe: bool, + #[cultcache(key = 7)] + pub jitter_us: i64, + #[cultcache(key = 8)] + pub decode_queue_us: i64, + #[cultcache(key = 9)] + pub observed_at: String, + #[cultcache(key = 10, default)] + pub missing_video_chunk_keys: Vec, +} diff --git a/packages/cultnet-rs/tests/media_stream_contracts.rs b/packages/cultnet-rs/tests/media_stream_contracts.rs new file mode 100644 index 00000000..9d2fc664 --- /dev/null +++ b/packages/cultnet-rs/tests/media_stream_contracts.rs @@ -0,0 +1,227 @@ +//! The CultMesh Media Stream records are a wire contract shared by producers and +//! consumers that never link each other. These tests pin the properties a +//! consumer is entitled to rely on: positional layout, declared field order, and +//! tolerance of records written before an appended field existed. + +use cultcache_rs::DatabaseEntry; +use cultnet_rs::{ + GAMECULT_MEDIA_AUDIO_PACKET_SCHEMA, GAMECULT_MEDIA_RECEIVER_FEEDBACK_SCHEMA, + GAMECULT_MEDIA_VIDEO_ACCESS_UNIT_SCHEMA, GAMECULT_MEDIA_VIDEO_PARITY_SHARD_SCHEMA, + GameCultMediaAudioPacketRecord, GameCultMediaReceiverFeedbackRecord, + GameCultMediaVideoAccessUnitRecord, GameCultMediaVideoParityShardRecord, +}; +use rmpv::Value; + +fn access_unit() -> GameCultMediaVideoAccessUnitRecord { + GameCultMediaVideoAccessUnitRecord { + stream_id: "raven-primary-av".to_string(), + session_id: "session-1".to_string(), + frame_id: 4242, + codec: "h264".to_string(), + pts_ticks: 90_000, + duration_ticks: 3_000, + timebase_num: 1, + timebase_den: 90_000, + keyframe: true, + dependency_frame_id: None, + deadline_ticks: 108_000, + chunk_index: 2, + chunk_count: 5, + payload: vec![0xDE, 0xAD, 0xBE, 0xEF], + } +} + +fn audio_packet() -> GameCultMediaAudioPacketRecord { + GameCultMediaAudioPacketRecord { + stream_id: "raven-primary-av".to_string(), + session_id: "session-1".to_string(), + packet_id: 77, + codec: "opus".to_string(), + pts_ticks: 48_000, + duration_ticks: 960, + timebase_num: 1, + timebase_den: 48_000, + deadline_ticks: 96_000, + payload: vec![1, 2, 3], + } +} + +fn decode_as_value(bytes: &[u8]) -> Value { + rmp_serde::from_slice(bytes).expect("records decode as generic MessagePack") +} + +/// The declared `key` indices are the wire layout, not documentation. A consumer +/// in another language reads position 2 for `frame_id` and position 13 for +/// `payload`; reordering the struct would silently break it. +#[test] +fn video_access_unit_encodes_as_a_positional_array() { + let encoded = rmp_serde::to_vec(&access_unit()).expect("encodes"); + let Value::Array(slots) = decode_as_value(&encoded) else { + panic!("access units must encode as a positional array"); + }; + + assert_eq!(slots.len(), 14, "field count is wire contract"); + assert_eq!(slots[0].as_str(), Some("raven-primary-av")); + assert_eq!(slots[2].as_u64(), Some(4242), "slot 2 is frame_id"); + assert_eq!(slots[3].as_str(), Some("h264")); + assert_eq!(slots[8].as_bool(), Some(true), "slot 8 is keyframe"); + assert!(slots[9].is_nil(), "an absent dependency stays nil, not 0"); + assert_eq!(slots[12].as_u64(), Some(5), "slot 12 is chunk_count"); + assert!( + matches!(&slots[13], Value::Binary(_) | Value::Array(_)), + "slot 13 is the payload; see payload_should_encode_as_messagepack_bin \ + for which of the two it ought to be" + ); +} + +/// Ignored until `cultcache-rs-derive` grows a `bytes` hint. +/// +/// The derive writes its own `Serialize` and calls `serialize_element` per slot, +/// so a `Vec` field goes out as a MessagePack array of integers. C#, +/// TypeScript and Python all emit `bin` for byte fields, which makes Rust the +/// divergent runtime and these records unreadable by the reference +/// implementation. `#[serde(with = "serde_bytes")]` cannot fix it — the derive +/// ignores serde attributes. +/// +/// It also costs 1.45x on every media byte: an 848-byte payload encodes to 1234 +/// bytes as an integer array against 851 as `bin`. +/// +/// The fix is not local to this file. Changing byte encoding globally would +/// invalidate every signature in the Idunn authority chain, because signatures +/// are taken over the whole positional serialization and canonical hashes over +/// the same bytes. It needs an opt-in hint so these three media records can +/// adopt `bin` without moving the signature-bearing ones. Owned by the Swarm +/// Migration work; un-ignore this when the hint lands. +#[test] +#[ignore = "blocked on a `bytes` opt-in hint in cultcache-rs-derive"] +fn payload_should_encode_as_messagepack_bin() { + let encoded = rmp_serde::to_vec(&access_unit()).expect("encodes"); + let Value::Array(slots) = decode_as_value(&encoded) else { + panic!("access units must encode as a positional array"); + }; + + assert_eq!( + slots[13].as_slice(), + Some([0xDE, 0xAD, 0xBE, 0xEF].as_slice()), + "payloads belong on the wire as bin, not as an array of integers" + ); +} + +#[test] +fn audio_packets_are_whole_and_carry_their_own_timebase() { + let encoded = rmp_serde::to_vec(&audio_packet()).expect("encodes"); + let Value::Array(slots) = decode_as_value(&encoded) else { + panic!("audio packets must encode as a positional array"); + }; + + assert_eq!(slots.len(), 10, "field count is wire contract"); + assert_eq!(slots[2].as_u64(), Some(77), "slot 2 is packet_id"); + assert_eq!(slots[6].as_u64(), Some(1), "slot 6 is timebase_num"); + assert_eq!(slots[7].as_u64(), Some(48_000), "slot 7 is timebase_den"); + + let decoded: GameCultMediaAudioPacketRecord = + rmp_serde::from_slice(&encoded).expect("round-trips"); + assert_eq!(decoded, audio_packet()); +} + +#[test] +fn parity_shards_carry_the_geometry_recovery_needs() { + let shard = GameCultMediaVideoParityShardRecord { + stream_id: "raven-primary-av".to_string(), + session_id: "session-1".to_string(), + frame_id: 4242, + codec: "h264".to_string(), + pts_ticks: 90_000, + duration_ticks: 3_000, + timebase_num: 1, + timebase_den: 90_000, + keyframe: false, + dependency_frame_id: Some(4241), + deadline_ticks: 108_000, + chunk_count: 5, + parity_index: 1, + parity_count: 2, + chunk_payload_bytes: 1024, + last_chunk_payload_bytes: 512, + payload: vec![9, 9, 9], + }; + + let encoded = rmp_serde::to_vec(&shard).expect("encodes"); + let Value::Array(slots) = decode_as_value(&encoded) else { + panic!("parity shards must encode as a positional array"); + }; + + assert_eq!(slots.len(), 17, "field count is wire contract"); + assert_eq!(slots[12].as_u64(), Some(1), "slot 12 is parity_index"); + assert_eq!(slots[13].as_u64(), Some(2), "slot 13 is parity_count"); + assert_eq!( + slots[15].as_u64(), + Some(512), + "slot 15 is last_chunk_payload_bytes, which recovery needs to size the tail" + ); + + let decoded: GameCultMediaVideoParityShardRecord = + rmp_serde::from_slice(&encoded).expect("round-trips"); + assert_eq!(decoded, shard); +} + +/// `missing_video_chunk_keys` was appended after producers were already writing +/// feedback. A record written without it must still decode, or the append was a +/// breaking change wearing a `default` attribute. +#[test] +fn receiver_feedback_decodes_records_written_before_its_last_field() { + let without_appended_field = Value::Array(vec![ + Value::from("raven-primary-av"), + Value::from("session-1"), + Value::from("starfire-obs"), + Value::from(4200u64), + Value::Array(vec![Value::from(4198u64)]), + Value::Array(vec![Value::from(4199u64)]), + Value::from(true), + Value::from(1_500i64), + Value::from(9_000i64), + Value::from("2026-09-09T00:00:00Z"), + ]); + + let mut bytes = Vec::new(); + rmpv::encode::write_value(&mut bytes, &without_appended_field).expect("writes legacy record"); + + let decoded: GameCultMediaReceiverFeedbackRecord = + rmp_serde::from_slice(&bytes).expect("a pre-append record must still decode"); + + assert_eq!(decoded.receiver_id, "starfire-obs"); + assert_eq!(decoded.highest_decodable_frame_id, Some(4200)); + assert!(decoded.requested_keyframe); + assert!( + decoded.missing_video_chunk_keys.is_empty(), + "the appended field defaults rather than failing the decode" + ); +} + +/// The published constants and the derived type identity must not drift apart; +/// a consumer resolving by schema id and a producer registering by type would +/// then disagree without either failing to compile. +#[test] +fn published_schema_constants_match_the_derived_identity() { + assert_eq!( + GameCultMediaVideoAccessUnitRecord::SCHEMA_NAME, + GAMECULT_MEDIA_VIDEO_ACCESS_UNIT_SCHEMA + ); + assert_eq!( + GameCultMediaVideoParityShardRecord::SCHEMA_NAME, + GAMECULT_MEDIA_VIDEO_PARITY_SHARD_SCHEMA + ); + assert_eq!( + GameCultMediaAudioPacketRecord::SCHEMA_NAME, + GAMECULT_MEDIA_AUDIO_PACKET_SCHEMA + ); + assert_eq!( + GameCultMediaReceiverFeedbackRecord::SCHEMA_NAME, + GAMECULT_MEDIA_RECEIVER_FEEDBACK_SCHEMA + ); + + assert_eq!( + GameCultMediaAudioPacketRecord::TYPE, + "gamecult.media_audio_packet" + ); +} From 2ba404cc0b57a5447f1c93988830c3c1c310080e Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 10 Sep 2026 00:31:11 +0200 Subject: [PATCH 150/283] Carry media payloads as bin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The three media payload fields take the derive's `bytes` attribute, so they serialize as MessagePack `bin` instead of an array of integers. An 848-byte payload goes from 1234 bytes on the wire to 851 — 1.45x off every media byte, on the one link measured to be starved. This is a correction to the previous commit's reasoning, not a new capability. That commit claimed the derive could not emit bin and left a test ignored against a hint that needed designing. The hint has existed all along: cultcache-rs-derive parses `bytes` at lib.rs:92, serializes through serde_bytes::Bytes at :135, and decodes through ByteBuf at :154 and :170. What is inert on a DatabaseEntry struct is `#[serde(with = "serde_bytes")]`, because the derive reads only its own attribute namespace — which is a different and much smaller claim than the one that was made. The ignored test is now un-ignored and passing, and the tolerant assertion it was propping up is exact again. Four fields elsewhere are missing `bytes` and are deliberately untouched here: IdunnDeploymentBrakeRecord.signature, IdunnDaemonHealthTrustBindingRecord .signer_public_key, GameCultServiceTrustAnchorRecord.signer_public_key, and IdunnAuthenticatedProviderHealthProjectionRecord.signature. Those carry stored state and signing history — six trust anchors live in the deployment projection on yggdrasil, and the brake store is byte-exact checked — so they need sequencing with a re-sign rather than a flag flip. Owned by the Swarm Migration work. Co-Authored-By: Claude Opus 5 --- .../cultnet-rs/src/media_stream_contracts.rs | 12 +++++-- .../tests/media_stream_contracts.rs | 34 +++++++------------ 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/packages/cultnet-rs/src/media_stream_contracts.rs b/packages/cultnet-rs/src/media_stream_contracts.rs index e47b3a28..815e3392 100644 --- a/packages/cultnet-rs/src/media_stream_contracts.rs +++ b/packages/cultnet-rs/src/media_stream_contracts.rs @@ -18,6 +18,12 @@ //! wire format: append new fields with `default` at the next free index, never //! reorder or renumber. `missing_video_chunk_keys` shows the pattern. //! +//! Payloads carry `bytes` so they serialize as MessagePack `bin` rather than an +//! array of integers, which is what the C#, TypeScript and Python runtimes +//! expect and what keeps a 848-byte payload at 851 bytes instead of 1234. Note +//! that this is the derive's own attribute — `#[serde(with = "serde_bytes")]` +//! is inert here, because `DatabaseEntry` writes its own `Serialize`. +//! //! # Timebase //! //! `pts_ticks`, `duration_ticks` and `deadline_ticks` are expressed in @@ -76,7 +82,7 @@ pub struct GameCultMediaVideoAccessUnitRecord { pub chunk_index: u16, #[cultcache(key = 12)] pub chunk_count: u16, - #[cultcache(key = 13)] + #[cultcache(key = 13, bytes)] pub payload: Vec, } @@ -123,7 +129,7 @@ pub struct GameCultMediaVideoParityShardRecord { pub chunk_payload_bytes: u32, #[cultcache(key = 15)] pub last_chunk_payload_bytes: u32, - #[cultcache(key = 16)] + #[cultcache(key = 16, bytes)] pub payload: Vec, } @@ -153,7 +159,7 @@ pub struct GameCultMediaAudioPacketRecord { pub timebase_den: u32, #[cultcache(key = 8)] pub deadline_ticks: i64, - #[cultcache(key = 9)] + #[cultcache(key = 9, bytes)] pub payload: Vec, } diff --git a/packages/cultnet-rs/tests/media_stream_contracts.rs b/packages/cultnet-rs/tests/media_stream_contracts.rs index 9d2fc664..963d78a2 100644 --- a/packages/cultnet-rs/tests/media_stream_contracts.rs +++ b/packages/cultnet-rs/tests/media_stream_contracts.rs @@ -67,33 +67,23 @@ fn video_access_unit_encodes_as_a_positional_array() { assert_eq!(slots[8].as_bool(), Some(true), "slot 8 is keyframe"); assert!(slots[9].is_nil(), "an absent dependency stays nil, not 0"); assert_eq!(slots[12].as_u64(), Some(5), "slot 12 is chunk_count"); - assert!( - matches!(&slots[13], Value::Binary(_) | Value::Array(_)), - "slot 13 is the payload; see payload_should_encode_as_messagepack_bin \ - for which of the two it ought to be" + assert_eq!( + slots[13].as_slice(), + Some([0xDE, 0xAD, 0xBE, 0xEF].as_slice()), + "slot 13 is the payload, carried as bin" ); } -/// Ignored until `cultcache-rs-derive` grows a `bytes` hint. +/// Payloads must reach the wire as MessagePack `bin`, not as an array of +/// integers. The C#, TypeScript and Python runtimes all read byte fields as +/// `bin`, so a payload serialized as a sequence is unreadable by the reference +/// implementation, and costs 1.45x besides: 848 bytes encode to 1234 as an +/// integer array against 851 as `bin`. /// -/// The derive writes its own `Serialize` and calls `serialize_element` per slot, -/// so a `Vec` field goes out as a MessagePack array of integers. C#, -/// TypeScript and Python all emit `bin` for byte fields, which makes Rust the -/// divergent runtime and these records unreadable by the reference -/// implementation. `#[serde(with = "serde_bytes")]` cannot fix it — the derive -/// ignores serde attributes. -/// -/// It also costs 1.45x on every media byte: an 848-byte payload encodes to 1234 -/// bytes as an integer array against 851 as `bin`. -/// -/// The fix is not local to this file. Changing byte encoding globally would -/// invalidate every signature in the Idunn authority chain, because signatures -/// are taken over the whole positional serialization and canonical hashes over -/// the same bytes. It needs an opt-in hint so these three media records can -/// adopt `bin` without moving the signature-bearing ones. Owned by the Swarm -/// Migration work; un-ignore this when the hint lands. +/// This is what the derive's `bytes` attribute buys. `#[serde(with = +/// "serde_bytes")]` will not do it — `DatabaseEntry` emits its own `Serialize` +/// and reads only its own `cultcache` attribute namespace. #[test] -#[ignore = "blocked on a `bytes` opt-in hint in cultcache-rs-derive"] fn payload_should_encode_as_messagepack_bin() { let encoded = rmp_serde::to_vec(&access_unit()).expect("encodes"); let Value::Array(slots) = decode_as_value(&encoded) else { From 9e6027e8d8c0ff4caa1e93f9ee2c2de707949110 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 10 Sep 2026 00:42:26 +0200 Subject: [PATCH 151/283] Measure what adding a bytes slot does to records already written Four of cultnet-rs's ten DatabaseEntry byte fields lack #[cultcache(key = N, bytes)] and so serialize as MessagePack array-of-integers rather than bin: IdunnDeploymentBrakeRecord.signature, IdunnDaemonHealthTrustBindingRecord.signer_public_key, GameCultServiceTrustAnchorRecord.signer_public_key, and IdunnAuthenticatedProviderHealthProjectionRecord.signature. Converting them touches live stores, so the question is what breaks. Measured rather than reasoned, and the answer is the opposite of what I expected. Reading is compatible in both directions: serde_bytes::ByteBuf accepts an array marker, and a plain Vec accepts bin, so the flip is neither a hard read break nor a one-way door. No dual-read path is needed and reverting the binary is survivable. What does change is reproduction. A record written before the flip can be read but can never re-encode to the bytes it was stored as, and its canonical digest moves with it. That is the cost, and it lands on byte-exact store checks and canonical_sha256, not on readability -- so the migration is a re-encode question, not a compatibility one. Also pins the size difference the media work is chasing: 406 bytes as an array against 278 as bin for a 256-byte payload, 1.46x, independently matching the 1.45x measured on an 848-byte payload. cargo test --test byte_slot_migration -> test result: ok. 4 passed; 0 failed Co-Authored-By: Claude Opus 5 --- .../cultnet-rs/tests/byte_slot_migration.rs | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 packages/cultnet-rs/tests/byte_slot_migration.rs diff --git a/packages/cultnet-rs/tests/byte_slot_migration.rs b/packages/cultnet-rs/tests/byte_slot_migration.rs new file mode 100644 index 00000000..0acdcd4d --- /dev/null +++ b/packages/cultnet-rs/tests/byte_slot_migration.rs @@ -0,0 +1,113 @@ +//! Does adding `#[cultcache(key = N, bytes)]` to a field break reading the +//! records already written without it? +//! +//! The attribute changes a slot from a MessagePack array-of-integers (serde's +//! default for `Vec`) to a real `bin`. Six of cultnet-rs's byte fields +//! already carry it and four do not, so converting the remaining four is a +//! stored-data question before it is a signature question: every record +//! written before the flip holds an array in that slot. +//! +//! Both directions are tested, because a migration has to survive a rollback +//! as well as a roll-forward. + +use cultcache_rs::DatabaseEntry; +use serde::Serialize; + +#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] +#[cultcache(type = "test.byte_slot", schema = "test.byte_slot.v1")] +struct ArrayEncoded { + #[cultcache(key = 0)] + schema_version: String, + #[cultcache(key = 1)] + payload: Vec, +} + +#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] +#[cultcache(type = "test.byte_slot", schema = "test.byte_slot.v1")] +struct BinEncoded { + #[cultcache(key = 0)] + schema_version: String, + #[cultcache(key = 1, bytes)] + payload: Vec, +} + +fn sample() -> Vec { + (0u8..=255).collect() +} + +#[test] +fn the_attribute_is_what_switches_the_wire_shape() { + let array = rmp_serde::to_vec(&ArrayEncoded { + schema_version: "test.byte_slot.v1".into(), + payload: sample(), + }) + .expect("array encodes"); + let bin = rmp_serde::to_vec(&BinEncoded { + schema_version: "test.byte_slot.v1".into(), + payload: sample(), + }) + .expect("bin encodes"); + + // 256 bytes as `bin` is a 3-byte header plus the payload. As an array it + // is one or two bytes per element, because every value above 0x7f needs a + // u8 marker of its own. + println!("array-encoded {} bytes, bin-encoded {} bytes", array.len(), bin.len()); + assert!( + array.len() > bin.len(), + "array {} should exceed bin {}", + array.len(), + bin.len() + ); +} + +#[test] +fn a_bytes_reader_still_reads_records_written_before_the_attribute() { + let written_before = rmp_serde::to_vec(&ArrayEncoded { + schema_version: "test.byte_slot.v1".into(), + payload: sample(), + }) + .expect("array encodes"); + + // serde_bytes::ByteBuf accepts an array marker as well as bin, so the + // flip is NOT a hard read break. This was worth measuring rather than + // assuming: the opposite would have forced a dual-read path or a rewrite + // migration onto every field with persisted records. + let read_after = + rmp_serde::from_slice::(&written_before).expect("bytes reader reads an array"); + assert_eq!(read_after.payload, sample()); +} + +#[test] +fn a_pre_attribute_reader_still_reads_records_written_after_it() { + let written_after = rmp_serde::to_vec(&BinEncoded { + schema_version: "test.byte_slot.v1".into(), + payload: sample(), + }) + .expect("bin encodes"); + + // The rollback direction, so reverting the binary is survivable. + let read_by_old = + rmp_serde::from_slice::(&written_after).expect("plain reader reads bin"); + assert_eq!(read_by_old.payload, sample()); +} + +#[test] +fn re_encoding_an_old_record_under_the_attribute_does_not_reproduce_its_bytes() { + // Where the cost actually lands. Reading is compatible; reproducing is + // not. Idunn byte-exact-checks its control store by re-encoding what it + // decoded, and canonical_sha256 hashes the same serialization -- so a + // record written before the flip can be read, but can never re-encode to + // the bytes it was stored as, and its canonical digest changes. + let written_before = rmp_serde::to_vec(&ArrayEncoded { + schema_version: "test.byte_slot.v1".into(), + payload: sample(), + }) + .expect("array encodes"); + let decoded = rmp_serde::from_slice::(&written_before).expect("reads"); + let re_encoded = rmp_serde::to_vec(&decoded).expect("re-encodes"); + + assert_ne!( + written_before, re_encoded, + "identical bytes would mean the attribute changed nothing" + ); +} From 36f31920ce69a80ad4c340a7bdfb23d63a9273e9 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 10 Sep 2026 00:49:32 +0200 Subject: [PATCH 152/283] Let a caller choose what the media channel does MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `media` was hardcoded Reliable in two places — the profile builder and the per-channel send options — so no caller could ask for anything else. Measured on Raven through `cultnet-impair`, 848-byte packets at 12 Mbps, which is Muninn's real media shape: profile mode delivered ack bytes clean unreliable 100.00% 43 clean reliable 69.10% 131,322 loss 1% unreliable 98.95% 43 loss 1% reliable 72.00% 135,837 loss 3% unreliable 96.73% 43 loss 3% reliable 73.30% 138,030 A reliable media channel loses 31% of a clean 12 Mbps offer, and its delivery barely moves as loss rises, so loss is not the binding constraint — it cannot carry the rate. An unreliable one holds everything on a clean link and then degrades by about the loss injected. The reverse channel differs by three orders of magnitude. Muninn wanted the unreliable lane and had no way to say so. It signalled the intent the only way the API allowed, by passing no reliable expiry, and its own test has asserted Unreliable and failed since it was written. With this change it passes. Delivery now comes from the advertised profile, resolved by `channel_delivery` alongside the `channel_reliable_expire_after_ms` that already worked this way. That removes the send path's private opinion about reliability, so the profile a peer was shown and the behaviour it gets cannot disagree. The channels whose semantics are fixed by design — schema reliable and ordered, realtime unreliable — are untouched and pinned by a test. `media_delivery: None` means Reliable, so no existing consumer changes behaviour. It is still source-breaking for anyone constructing the three options types with a struct literal rather than `::client(...)`: two sites in cultmesh-rs, four in Muninn, seven across the test suites here, all mechanical. An earlier draft claimed Muninn was unaffected; the compiler disagreed. The `examples/media_delivery_probe.rs` added here is what produced the table, so the claim can be re-run rather than believed. Note its sender-side wire-cost figure is unsound for the reliable case: the sender stops draining after five seconds while retransmission is still in flight, so those byte counts under-report. The delivery percentages are receiver-measured and stand. Co-Authored-By: Claude Opus 5 --- packages/cultmesh-rs/src/lib.rs | 1 + .../cultmesh-rs/tests/rudp_document_server.rs | 1 + .../examples/media_delivery_probe.rs | 177 ++++++++++++++++++ packages/cultnet-rs/src/cultmesh.rs | 2 + packages/cultnet-rs/src/rudp.rs | 43 ++++- packages/cultnet-rs/tests/cultnet.rs | 7 + .../tests/media_channel_delivery.rs | 92 +++++++++ 7 files changed, 321 insertions(+), 2 deletions(-) create mode 100644 packages/cultnet-rs/examples/media_delivery_probe.rs create mode 100644 packages/cultnet-rs/tests/media_channel_delivery.rs diff --git a/packages/cultmesh-rs/src/lib.rs b/packages/cultmesh-rs/src/lib.rs index 7999f18b..135314bb 100644 --- a/packages/cultmesh-rs/src/lib.rs +++ b/packages/cultmesh-rs/src/lib.rs @@ -955,6 +955,7 @@ fn connect_rudp_client( socket.set_read_timeout(Some(poll_interval))?; let mut client = CultNetRudpSocketTransportConnection::new(CultNetRudpSocketTransportOptions { + media_delivery: None, runtime_id: runtime_id.to_string(), socket, mode: cultnet_rs::CultNetRudpSocketMode::Client, diff --git a/packages/cultmesh-rs/tests/rudp_document_server.rs b/packages/cultmesh-rs/tests/rudp_document_server.rs index c0f191b4..df14b4ea 100644 --- a/packages/cultmesh-rs/tests/rudp_document_server.rs +++ b/packages/cultmesh-rs/tests/rudp_document_server.rs @@ -163,6 +163,7 @@ fn client(target: SocketAddr, id: u32) -> Result +//! media_delivery_probe send +//! ``` +//! +//! The sender reports amplification: wire bytes divided by offered payload +//! bytes. At 1.0 nothing was retransmitted. Well above 1.0 under loss is the +//! pathology. + +use std::env; +use std::net::{SocketAddr, UdpSocket}; +use std::time::{Duration, Instant}; + +use anyhow::{Result, anyhow}; +use cultnet_rs::{ + CultNetRudpServerHubOptions, CultNetRudpSocketTransportConnection, + CultNetRudpSocketTransportOptions, CultNetTransportDelivery, +}; + +const CHANNEL: &str = "media"; +const DRAIN: Duration = Duration::from_secs(5); + +fn main() -> Result<()> { + let args: Vec = env::args().collect(); + match args.get(1).map(String::as_str) { + Some("recv") => recv( + args.get(2).ok_or_else(|| anyhow!("bind addr"))?.parse()?, + args.get(3).ok_or_else(|| anyhow!("expect count"))?.parse()?, + ), + Some("send") => send( + args.get(2).ok_or_else(|| anyhow!("endpoint"))?.parse()?, + match args.get(3).map(String::as_str) { + Some("unreliable") => CultNetTransportDelivery::Unreliable, + Some("reliable") => CultNetTransportDelivery::Reliable, + other => return Err(anyhow!("delivery must be reliable|unreliable, got {other:?}")), + }, + args.get(4).ok_or_else(|| anyhow!("payload bytes"))?.parse()?, + args.get(5).ok_or_else(|| anyhow!("count"))?.parse()?, + args.get(6).map(|v| v.parse()).transpose()?.unwrap_or(12.0), + ), + _ => Err(anyhow!( + "usage: media_delivery_probe recv | send " + )), + } +} + +fn recv(bind: SocketAddr, expect: u64) -> Result<()> { + let socket = UdpSocket::bind(bind)?; + socket.set_nonblocking(true)?; + let mut hub = cultnet_rs::CultNetRudpServerHub::new(CultNetRudpServerHubOptions::new( + "probe-recv", + socket, + 0x0BE0_0001, + ))?; + + println!("listening on {bind}, expecting {expect} frames"); + let started = Instant::now(); + let mut frames = 0u64; + let mut payload_bytes = 0u64; + let mut last_progress = Instant::now(); + + loop { + while let Some(event) = hub.receive_event_once()? { + if let cultnet_rs::CultNetRudpServerEvent::Frame { frame, .. } = event + && frame.channel_id == CHANNEL + { + frames += 1; + payload_bytes += frame.payload.len() as u64; + last_progress = Instant::now(); + } + } + if frames >= expect || last_progress.elapsed() > DRAIN { + break; + } + std::thread::sleep(Duration::from_micros(200)); + } + + let stats = hub.stats(); + let elapsed = started.elapsed().as_secs_f64(); + println!("RESULT recv frames={frames} expected={expect} payload_bytes={payload_bytes}"); + println!( + "RESULT recv wire_bytes_in={} wire_bytes_out={} elapsed_s={elapsed:.2} delivered_pct={:.2}", + stats.bytes_received, + stats.bytes_sent, + (frames as f64 / expect as f64) * 100.0 + ); + Ok(()) +} + +fn send( + endpoint: SocketAddr, + delivery: CultNetTransportDelivery, + payload_bytes: usize, + count: u64, + target_mbps: f64, +) -> Result<()> { + let socket = UdpSocket::bind("0.0.0.0:0")?; + socket.set_nonblocking(true)?; + let mut options = + CultNetRudpSocketTransportOptions::client("probe-send", socket, endpoint, 0x0BE0_0001); + options.media_delivery = Some(delivery); + options.media_reliable_expire_after_ms = None; + + let mut transport = CultNetRudpSocketTransportConnection::new(options)?; + transport.connect(b"probe".to_vec())?; + let deadline = Instant::now() + Duration::from_secs(10); + while !transport.connected() { + let _ = transport.receive_once()?; + transport.poll_resends()?; + if Instant::now() >= deadline { + return Err(anyhow!("timed out connecting to {endpoint}")); + } + std::thread::sleep(Duration::from_millis(2)); + } + + // Pace to a realistic media rate. An unpaced blast overruns the receiver's + // socket buffer and manufactures loss that has nothing to do with the link. + let per_packet = Duration::from_secs_f64((payload_bytes as f64 * 8.0) / (target_mbps * 1e6)); + let payload = vec![0xA5u8; payload_bytes]; + let offered = payload_bytes as u64 * count; + let started = Instant::now(); + let mut sent = 0u64; + let mut would_block = 0u64; + + while sent < count { + match transport.send(CHANNEL, payload.clone()) { + Ok(()) => sent += 1, + Err(error) if error.to_string().contains("would block") => { + would_block += 1; + transport.poll_resends()?; + let _ = transport.receive_once()?; + std::thread::sleep(Duration::from_micros(500)); + } + Err(error) => return Err(error), + } + if sent % 64 == 0 { + let _ = transport.receive_once()?; + transport.poll_resends()?; + } + let due = started + per_packet.mul_f64(sent as f64); + if let Some(wait) = due.checked_duration_since(Instant::now()) { + std::thread::sleep(wait); + } + } + let send_elapsed = started.elapsed(); + + // Let retransmission run: this is where a reliable channel spends what an + // unreliable one does not. + let drain_start = Instant::now(); + while drain_start.elapsed() < DRAIN { + let _ = transport.receive_once()?; + transport.poll_resends()?; + std::thread::sleep(Duration::from_millis(1)); + } + + let stats = transport.stats(); + let amplification = stats.bytes_sent as f64 / offered as f64; + println!( + "RESULT send delivery={delivery:?} payload_bytes={payload_bytes} count={count} offered={offered} target_mbps={target_mbps}" + ); + println!( + "RESULT send wire_bytes={} amplification={amplification:.3} send_s={:.2} total_s={:.2} would_block={would_block} reliable_expired={}", + stats.bytes_sent, + send_elapsed.as_secs_f64(), + started.elapsed().as_secs_f64(), + stats.reliable_packets_expired + ); + Ok(()) +} diff --git a/packages/cultnet-rs/src/cultmesh.rs b/packages/cultnet-rs/src/cultmesh.rs index efc8acad..14998396 100644 --- a/packages/cultnet-rs/src/cultmesh.rs +++ b/packages/cultnet-rs/src/cultmesh.rs @@ -319,6 +319,7 @@ impl CultMesh { let socket = bind_rudp_socket(&options)?; CultNetRudpSocketTransportConnection::new(CultNetRudpSocketTransportOptions { media_reliable_expire_after_ms: None, + media_delivery: None, runtime_id: runtime_id.into(), socket, mode: CultNetRudpSocketMode::Server, @@ -343,6 +344,7 @@ impl CultMesh { let socket = bind_rudp_socket(&options)?; CultNetRudpSocketTransportConnection::new(CultNetRudpSocketTransportOptions { media_reliable_expire_after_ms: None, + media_delivery: None, runtime_id: runtime_id.into(), socket, mode: CultNetRudpSocketMode::Client, diff --git a/packages/cultnet-rs/src/rudp.rs b/packages/cultnet-rs/src/rudp.rs index f1fd4ca4..b7019b1b 100644 --- a/packages/cultnet-rs/src/rudp.rs +++ b/packages/cultnet-rs/src/rudp.rs @@ -1210,6 +1210,8 @@ pub struct CultNetRudpSocketTransportOptions { pub max_pending_reliable_packets: Option, pub reconnect_policy: Option, pub media_reliable_expire_after_ms: Option, + /// `None` means the historical default, `Reliable`. + pub media_delivery: Option, } impl CultNetRudpSocketTransportOptions { @@ -1221,6 +1223,7 @@ impl CultNetRudpSocketTransportOptions { ) -> Self { Self { media_reliable_expire_after_ms: Some(DEFAULT_MEDIA_RELIABLE_EXPIRE_AFTER_MS), + media_delivery: None, runtime_id: runtime_id.into(), socket, mode: CultNetRudpSocketMode::Client, @@ -1239,6 +1242,7 @@ impl CultNetRudpSocketTransportOptions { pub fn server(runtime_id: impl Into, socket: UdpSocket, connection_id: u32) -> Self { Self { media_reliable_expire_after_ms: Some(DEFAULT_MEDIA_RELIABLE_EXPIRE_AFTER_MS), + media_delivery: None, runtime_id: runtime_id.into(), socket, mode: CultNetRudpSocketMode::Server, @@ -1280,12 +1284,15 @@ pub struct CultNetRudpServerHubOptions { pub max_pending_reliable_packets: Option, pub max_peers: usize, pub media_reliable_expire_after_ms: Option, + /// `None` means the historical default, `Reliable`. + pub media_delivery: Option, } impl CultNetRudpServerHubOptions { pub fn new(runtime_id: impl Into, socket: UdpSocket, connection_id: u32) -> Self { Self { media_reliable_expire_after_ms: Some(DEFAULT_MEDIA_RELIABLE_EXPIRE_AFTER_MS), + media_delivery: None, runtime_id: runtime_id.into(), socket, connection_id, @@ -1372,6 +1379,7 @@ impl CultNetRudpServerHub { options.runtime_id, RudpTransportProfileOptions { media_reliable_expire_after_ms: options.media_reliable_expire_after_ms, + media_delivery: options.media_delivery, transport_id: options.transport_id, host: Some(local_addr.ip().to_string()), port: Some(local_addr.port()), @@ -1451,6 +1459,7 @@ impl CultNetRudpServerHub { channel_id, now_ms(), channel_reliable_expire_after_ms(&self.profile, channel_id), + channel_delivery(&self.profile, channel_id), ), self.max_fragment_bytes, )? @@ -1671,6 +1680,7 @@ impl CultNetRudpSocketTransportConnection { options.runtime_id, RudpTransportProfileOptions { media_reliable_expire_after_ms: options.media_reliable_expire_after_ms, + media_delivery: options.media_delivery, transport_id: options.transport_id, host: Some(local_addr.ip().to_string()), port: Some(local_addr.port()), @@ -1738,6 +1748,7 @@ impl CultNetRudpSocketTransportConnection { channel_id, now_ms(), channel_reliable_expire_after_ms(&self.profile, channel_id), + channel_delivery(&self.profile, channel_id), ); let packets = self.session @@ -1759,6 +1770,7 @@ impl CultNetRudpSocketTransportConnection { channel_id, now_ms(), channel_reliable_expire_after_ms(&self.profile, channel_id), + channel_delivery(&self.profile, channel_id), ); // This lineage has no reliable-expiry concept, so every reliable channel is // already non-expiring. Restore the expiry half of this guard if one is added. @@ -2073,6 +2085,8 @@ pub struct RudpTransportProfileOptions { pub max_pending_reliable_packets: Option, pub reconnect_policy: Option, pub media_reliable_expire_after_ms: Option, + /// `None` means the historical default, `Reliable`. + pub media_delivery: Option, } pub fn create_rudp_transport_profile( @@ -2125,7 +2139,9 @@ pub fn create_rudp_transport_profile( }, CultNetTransportChannel { channel_id: "media".to_string(), - delivery: CultNetTransportDelivery::Reliable, + delivery: options + .media_delivery + .unwrap_or(CultNetTransportDelivery::Reliable), ordering: CultNetTransportOrdering::Unordered, max_payload_bytes: options.max_payload_bytes, max_fragment_bytes: options.max_fragment_bytes, @@ -2254,10 +2270,30 @@ fn channel_reliable_expire_after_ms( .and_then(|channel| channel.reliable_expire_after_ms) } +/// The advertised profile owns each channel's delivery, for the same reason it +/// owns expiry: a send path that hardcodes reliability can disagree with the +/// profile the peer was shown, and then no one can say what the channel does. +/// +/// Falls back to `Reliable` for a channel the profile does not describe, which +/// is what every channel got before delivery was configurable. +fn channel_delivery( + profile: &CultNetTransportProfile, + channel_id: &str, +) -> CultNetTransportDelivery { + profile + .transports + .iter() + .flat_map(|transport| transport.channels.iter()) + .find(|channel| channel.channel_id == channel_id) + .map(|channel| channel.delivery) + .unwrap_or(CultNetTransportDelivery::Reliable) +} + fn channel_send_options( channel_id: &str, now_ms: u64, reliable_expire_after_ms: Option, + delivery: CultNetTransportDelivery, ) -> CultNetRudpSendOptions { match channel_id { "schema" => CultNetRudpSendOptions { @@ -2274,8 +2310,11 @@ fn channel_send_options( now_ms, reliable_expire_after_ms: None, }, + // The one channel whose delivery a caller chooses. Media that has gone + // stale is worth dropping, not retransmitting: a reliable media channel + // under loss adds load exactly when the link has least to give. "media" => CultNetRudpSendOptions { - reliable: true, + reliable: matches!(delivery, CultNetTransportDelivery::Reliable), ordered: false, sequenced: false, now_ms, diff --git a/packages/cultnet-rs/tests/cultnet.rs b/packages/cultnet-rs/tests/cultnet.rs index 851646cf..7be6ea18 100644 --- a/packages/cultnet-rs/tests/cultnet.rs +++ b/packages/cultnet-rs/tests/cultnet.rs @@ -359,6 +359,7 @@ fn rudp_transport_profile_advertises_state_and_realtime_channels() { let profile = create_rudp_transport_profile( "rust-rudp", cultnet_rs::RudpTransportProfileOptions { + media_delivery: None, transport_id: Some("public-rudp".to_string()), host: Some("127.0.0.1".to_string()), port: Some(7777), @@ -1248,6 +1249,7 @@ fn rudp_socket_transport_handshakes_and_carries_reliable_ordered_schema_frames() let connection_id = 0x1020_3040; let mut server = CultNetRudpSocketTransportConnection::new(CultNetRudpSocketTransportOptions { + media_delivery: None, runtime_id: "rust-rudp-server".to_string(), socket: server_socket, mode: CultNetRudpSocketMode::Server, @@ -1264,6 +1266,7 @@ fn rudp_socket_transport_handshakes_and_carries_reliable_ordered_schema_frames() })?; let mut client = CultNetRudpSocketTransportConnection::new(CultNetRudpSocketTransportOptions { + media_delivery: None, runtime_id: "rust-rudp-client".to_string(), socket: client_socket, mode: CultNetRudpSocketMode::Client, @@ -1340,6 +1343,7 @@ fn rudp_socket_transport_carries_fragmented_reliable_ordered_schema_frames() -> let connection_id = 0x1020_3041; let mut server = CultNetRudpSocketTransportConnection::new(CultNetRudpSocketTransportOptions { + media_delivery: None, runtime_id: "rust-rudp-fragment-server".to_string(), socket: server_socket, mode: CultNetRudpSocketMode::Server, @@ -1356,6 +1360,7 @@ fn rudp_socket_transport_carries_fragmented_reliable_ordered_schema_frames() -> })?; let mut client = CultNetRudpSocketTransportConnection::new(CultNetRudpSocketTransportOptions { + media_delivery: None, runtime_id: "rust-rudp-fragment-client".to_string(), socket: client_socket, mode: CultNetRudpSocketMode::Client, @@ -1470,6 +1475,7 @@ fn rudp_socket_flush_waits_for_large_fragment_delivery() -> Result<()> { let connection_id = 0x1020_3043; let mut server = CultNetRudpSocketTransportConnection::new(CultNetRudpSocketTransportOptions { + media_delivery: None, runtime_id: "rust-rudp-window-server".into(), socket: server_socket, mode: CultNetRudpSocketMode::Server, @@ -1486,6 +1492,7 @@ fn rudp_socket_flush_waits_for_large_fragment_delivery() -> Result<()> { })?; let mut client = CultNetRudpSocketTransportConnection::new(CultNetRudpSocketTransportOptions { + media_delivery: None, runtime_id: "rust-rudp-window-client".into(), socket: client_socket, mode: CultNetRudpSocketMode::Client, diff --git a/packages/cultnet-rs/tests/media_channel_delivery.rs b/packages/cultnet-rs/tests/media_channel_delivery.rs new file mode 100644 index 00000000..499be0d3 --- /dev/null +++ b/packages/cultnet-rs/tests/media_channel_delivery.rs @@ -0,0 +1,92 @@ +//! Media delivery is the caller's choice, and the advertised profile is where +//! that choice lives. +//! +//! Before this, `media` was hardcoded `Reliable` in two places — the profile +//! builder and the per-channel send options — so no caller could say otherwise. +//! A producer asking for an unreliable media lane got a reliable one that +//! retransmits under loss, which adds load exactly when the link has least to +//! give. Muninn asked for that lane by passing no expiry, meaning "unreliable, +//! so expiry is moot", and got reliable-with-no-expiry instead: retransmit +//! forever. +//! +//! The default stays `Reliable` so every existing consumer is untouched. + +use std::net::UdpSocket; + +use cultnet_rs::{ + CultNetRudpSocketTransportConnection, CultNetRudpSocketTransportOptions, + CultNetTransportDelivery, +}; + +fn media_channel_delivery( + media_delivery: Option, +) -> (CultNetTransportDelivery, Option) { + let socket = UdpSocket::bind("127.0.0.1:0").expect("binds"); + let endpoint = "127.0.0.1:5204".parse().expect("parses"); + let mut options = CultNetRudpSocketTransportOptions::client("test-media", socket, endpoint, 7); + options.media_delivery = media_delivery; + options.media_reliable_expire_after_ms = None; + + let transport = CultNetRudpSocketTransportConnection::new(options).expect("opens"); + let channel = transport + .profile + .transports + .first() + .expect("a transport") + .channels + .iter() + .find(|channel| channel.channel_id == "media") + .expect("a media channel"); + (channel.delivery, channel.reliable_expire_after_ms) +} + +#[test] +fn media_defaults_to_reliable_so_existing_consumers_do_not_move() { + let (delivery, _) = media_channel_delivery(None); + assert_eq!(delivery, CultNetTransportDelivery::Reliable); +} + +#[test] +fn a_caller_can_ask_for_an_unreliable_media_lane() { + let (delivery, expiry) = media_channel_delivery(Some(CultNetTransportDelivery::Unreliable)); + assert_eq!(delivery, CultNetTransportDelivery::Unreliable); + assert_eq!( + expiry, None, + "an unreliable channel has nothing to expire; the pairing should stay honest" + ); +} + +#[test] +fn asking_for_reliable_explicitly_matches_the_default() { + let (explicit, _) = media_channel_delivery(Some(CultNetTransportDelivery::Reliable)); + let (defaulted, _) = media_channel_delivery(None); + assert_eq!(explicit, defaulted); +} + +/// The channels whose semantics are fixed by design must not drift with this. +#[test] +fn the_other_channels_keep_their_fixed_delivery() { + let socket = UdpSocket::bind("127.0.0.1:0").expect("binds"); + let endpoint = "127.0.0.1:5204".parse().expect("parses"); + let mut options = CultNetRudpSocketTransportOptions::client("test-media", socket, endpoint, 8); + options.media_delivery = Some(CultNetTransportDelivery::Unreliable); + + let transport = CultNetRudpSocketTransportConnection::new(options).expect("opens"); + let channels = &transport + .profile + .transports + .first() + .expect("a transport") + .channels; + + let delivery_of = |id: &str| { + channels + .iter() + .find(|channel| channel.channel_id == id) + .unwrap_or_else(|| panic!("channel {id}")) + .delivery + }; + + assert_eq!(delivery_of("schema"), CultNetTransportDelivery::Reliable); + assert_eq!(delivery_of("realtime"), CultNetTransportDelivery::Unreliable); +} From 4111fbb46849e10640d5c32f01afcb1cd1ba78b6 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 10 Sep 2026 01:18:45 +0200 Subject: [PATCH 153/283] Write down that a stored record's encoding is part of its contract Three byte-exact re-encode guards exist across three separate Idunn stores -- the runtime projection, the deployment brake, and the trust bindings -- each decoding a record, re-encoding it, and refusing on any byte difference. Idunn's control store does the same for its own transactions. Three independent instances is a house pattern, and it means changing how any persisted CultCache record serializes is never a flag flip. Records the measured behaviour of #[cultcache(key = N, bytes)] rather than the assumed one: reading stays compatible both ways, so the cost lands on reproduction and therefore on those guards, not on compatibility. A field with no live producer is free; a field with persisted records needs its store rewritten in the same change. Also records that Option> cannot take the attribute today, and that a shape-validated field nobody produces may be a fossil rather than an omission -- the estate has at least one other case of a live consumer outliving its producer. This was learned by nearly deploying an attribute flip that would have made Idunn refuse the projection store Odin reads. Co-Authored-By: Claude Opus 5 --- docs/persisted-record-encoding.md | 68 +++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 docs/persisted-record-encoding.md diff --git a/docs/persisted-record-encoding.md b/docs/persisted-record-encoding.md new file mode 100644 index 00000000..b8e13f8a --- /dev/null +++ b/docs/persisted-record-encoding.md @@ -0,0 +1,68 @@ +# The encoding of a persisted CultCache record is part of its contract + +Changing how a stored record serializes is never a flag flip in this estate. +Consumers verify canonicality by **re-encoding what they decoded and comparing +bytes**, so a record that reads back correctly but re-encodes differently is +refused — and the refusal happens on live data, at startup or on the next read. + +Three guards, three separate stores, one idiom: + +| store | guard | refusal | +|---|---|---| +| Idunn runtime projection | `Idunn/src/drivers.rs:3611` | `service trust-anchor projection is noncanonical` | +| Idunn deployment brake | `Idunn/src/control_plane.rs` (`read_deployment_brake`) | `deployment brake is noncanonical or keyed by another authority` | +| Idunn trust bindings | `Idunn/src/provisioning.rs:546`, `:630` | `trust store contains a noncanonical or mismatched binding` | + +Idunn's control store applies the same rule to its own transactions. Assume the +guard exists and go looking for it before changing any persisted record's +serialization; three independent instances is a house pattern, not a +coincidence. + +## What this means for `#[cultcache(key = N, bytes)]` + +The attribute switches a `Vec` slot from a MessagePack array-of-integers +(serde's default) to a real `bin`. Measured, not assumed +(`packages/cultnet-rs/tests/byte_slot_migration.rs`): + +- **Reading stays compatible in both directions.** `serde_bytes::ByteBuf` + accepts an array marker, and a plain `Vec` accepts `bin`. No dual-read + path is needed, and reverting a binary is survivable. +- **Reproduction does not.** A record written before the flip can be read but + can never re-encode to the bytes it was stored as, and its `canonical_sha256` + moves with it. + +So the cost lands entirely on the guards above, not on readability. A field with +persisted records must flip the attribute **and** rewrite its store in the same +change, one target at a time, and never during a deployment — the projection +store is what the observer reads, and refusing it takes the observer down. + +A field with no live producer is free. Check for one before assuming a +migration: `IdunnAuthenticatedProviderHealthProjectionRecord` is constructed +only inside a test module, so its byte field costs nothing to convert. + +Size, for whether it is worth doing at all: 406 bytes as an array against 278 as +`bin` for a 256-byte payload, and 1234 against 851 for an 848-byte one. About +1.45x on every byte, which matters on a media path and is noise on a control +record. + +## `Option>` cannot take the attribute yet + +The derive emits `serde_bytes::Bytes::new(&self.field)`, which needs `&[u8]`, +and builds the field via `.into_vec()`, which yields `Vec`. Both are type +errors against an `Option>`, so the derive fails loudly rather than +collapsing "absent slot" into "unsigned". `IdunnDeploymentBrakeRecord.signature` +needs an `Option`-aware path in `cultcache-rs-derive` before it can move. + +## Fields validated for shape and produced by nothing + +`trust_binding_sha256` is declared on two records with different schemas +(`idunn.authenticated_provider_health_projection.v1` in cultnet-rs, +`idunn.authenticated_daemon_health_admission.v1` in odin-core), shape-validated +in both, and computed by nothing in CultLib, Idunn or Odin. + +Do not assume that means "omission". It may be a fossil — a contract whose +producer was deleted. The estate has form: Muninn's receiver runs a Reed-Solomon +audio FEC path against parity shards the Rust sender has never emitted, while an +acceptance ledger describes that FEC as having worked. Settling which requires +reading history, not source, and the answer changes whether the right move is to +implement the field or delete it. From a3e6877945f22134af99999a60f85cf7acc16056 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 10 Sep 2026 02:00:19 +0200 Subject: [PATCH 154/283] Move the media wire envelope where both ends can reach it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A media record travels wrapped in cultnet.document_put_raw.v0 with a schema id, a record key and provenance. Both ends have to agree on that exactly, and until now only Muninn had it: the producer was Rust in one repository and the consumer was 6,515 lines of C++ in another, each with its own reading of the same bytes. Ratatoskr could not decode a real stream without it. Two things change in the move rather than after it. The producer namespace is now the caller's. The Muninn implementation hardcoded "muninn-media:" into every message id and "muninn.media" into every tag, so a second producer would have had to label its traffic as Muninn's to be understood. `MediaWireProvenance` carries it instead, and a test asserts the envelope names no producer the caller did not supply. The four hand-written wire payload structs are gone. Each restated a record's entire field list as a positional tuple, in order, kept in step by discipline alone — and existed for one reason: `#[serde(with = "serde_bytes")]` on the payload, which cannot be applied to a DatabaseEntry struct because the derive does not read serde attributes. Now that the records carry `#[cultcache(key = N, bytes)]` the derive emits bin itself, so the records serialize directly. That last part is a wire claim, so it is tested rather than asserted: `the_derive_reproduces_the_hand_written_wire_payload_byte_for_byte` reconstructs the legacy struct and compares output byte for byte. It matches, which makes the deletion a simplification instead of a silent break. Record key shapes move here too. A consumer parses them to tell a chunk from its siblings and a retransmission from a new frame, so they are contract and belong beside the records rather than in whichever producer wrote them first. Muninn's copies are not removed yet; that is the other half of this move. Co-Authored-By: Claude Opus 5 --- packages/cultnet-rs/src/lib.rs | 2 + packages/cultnet-rs/src/media_stream_wire.rs | 185 +++++++++++++++ .../cultnet-rs/tests/media_stream_wire.rs | 217 ++++++++++++++++++ 3 files changed, 404 insertions(+) create mode 100644 packages/cultnet-rs/src/media_stream_wire.rs create mode 100644 packages/cultnet-rs/tests/media_stream_wire.rs diff --git a/packages/cultnet-rs/src/lib.rs b/packages/cultnet-rs/src/lib.rs index 5aa121af..074c2a29 100644 --- a/packages/cultnet-rs/src/lib.rs +++ b/packages/cultnet-rs/src/lib.rs @@ -2,6 +2,7 @@ mod contracts; mod idunn_deployment_brake; mod idunn_lifecycle_brake; mod media_stream_contracts; +mod media_stream_wire; mod provider_health_contracts; mod runtime_authority_contracts; mod service_identity; @@ -21,6 +22,7 @@ pub use contracts::*; pub use idunn_deployment_brake::*; pub use idunn_lifecycle_brake::*; pub use media_stream_contracts::*; +pub use media_stream_wire::*; pub use provider_health_contracts::*; pub use runtime_authority_contracts::*; pub use service_identity::*; diff --git a/packages/cultnet-rs/src/media_stream_wire.rs b/packages/cultnet-rs/src/media_stream_wire.rs new file mode 100644 index 00000000..2959eef8 --- /dev/null +++ b/packages/cultnet-rs/src/media_stream_wire.rs @@ -0,0 +1,185 @@ +//! How a CultMesh Media Stream record travels: the envelope both ends must +//! agree on. +//! +//! The records in `media_stream_contracts` describe media. This describes how +//! one reaches a peer — wrapped in `cultnet.document_put_raw.v0` with a schema +//! id, a record key, and provenance. It lives here because a producer and a +//! consumer that never link each other still have to agree on it exactly, and +//! the last time they did not, one end was Rust and the other was 6,515 lines +//! of C++ that had drifted. +//! +//! # No producer's name belongs in a shared envelope +//! +//! The Muninn implementation this replaces hardcoded `"muninn-media:"` into +//! every message id and `"muninn.media"` into every tag, so a second producer +//! would have had to label its traffic as Muninn's. The producer namespace is a +//! parameter here: see [`MediaWireProvenance`]. +//! +//! # Record keys are addresses, not decoration +//! +//! A key identifies one piece of media within a session, so a consumer can tell +//! a retransmission from a new frame and a chunk from its siblings. The shapes +//! are fixed by this module rather than by each producer, because a consumer +//! parses them. + +use anyhow::{Result, anyhow}; + +use crate::contracts::{ + CultNetMessage, CultNetRawDocumentRecord, CultNetRawPayloadEncoding, CultNetWireContract, + decode_cultnet_message_from_slice, encode_cultnet_message_to_vec, +}; +use crate::media_stream_contracts::{ + GAMECULT_MEDIA_AUDIO_PACKET_SCHEMA, GAMECULT_MEDIA_RECEIVER_FEEDBACK_SCHEMA, + GAMECULT_MEDIA_VIDEO_ACCESS_UNIT_SCHEMA, GAMECULT_MEDIA_VIDEO_PARITY_SHARD_SCHEMA, + GameCultMediaAudioPacketRecord, GameCultMediaReceiverFeedbackRecord, + GameCultMediaVideoAccessUnitRecord, GameCultMediaVideoParityShardRecord, +}; + +/// The CultNet channel media rides. +pub const GAMECULT_MEDIA_CHANNEL: &str = "media"; + +/// One media record on its way somewhere. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum GameCultMediaWireRecord { + Video(GameCultMediaVideoAccessUnitRecord), + VideoParity(GameCultMediaVideoParityShardRecord), + Audio(GameCultMediaAudioPacketRecord), + Feedback(GameCultMediaReceiverFeedbackRecord), +} + +/// Who is sending, and when. `producer` namespaces message ids and tags so a +/// stream can be attributed without the envelope knowing any producer by name. +#[derive(Clone, Copy, Debug)] +pub struct MediaWireProvenance<'a> { + pub stored_at: &'a str, + pub runtime_id: &'a str, + pub role: &'a str, + pub producer: &'a str, +} + +impl MediaWireProvenance<'_> { + fn validate(&self) -> Result<()> { + for (name, value) in [ + ("stored_at", self.stored_at), + ("runtime_id", self.runtime_id), + ("role", self.role), + ("producer", self.producer), + ] { + if value.is_empty() { + return Err(anyhow!("media wire provenance {name} must be non-empty")); + } + } + Ok(()) + } +} + +impl GameCultMediaWireRecord { + pub fn schema_id(&self) -> &'static str { + match self { + Self::Video(_) => GAMECULT_MEDIA_VIDEO_ACCESS_UNIT_SCHEMA, + Self::VideoParity(_) => GAMECULT_MEDIA_VIDEO_PARITY_SHARD_SCHEMA, + Self::Audio(_) => GAMECULT_MEDIA_AUDIO_PACKET_SCHEMA, + Self::Feedback(_) => GAMECULT_MEDIA_RECEIVER_FEEDBACK_SCHEMA, + } + } + + /// Addresses this record within its session. + pub fn record_key(&self) -> String { + match self { + Self::Video(record) => format!( + "{}:{}:video:{}:{}", + record.stream_id, record.session_id, record.frame_id, record.chunk_index + ), + Self::VideoParity(record) => format!( + "{}:{}:video-parity:{}:{}", + record.stream_id, record.session_id, record.frame_id, record.parity_index + ), + Self::Audio(record) => format!( + "{}:{}:audio:{}", + record.stream_id, record.session_id, record.packet_id + ), + Self::Feedback(record) => format!( + "{}:{}:feedback:{}", + record.stream_id, record.session_id, record.receiver_id + ), + } + } + + /// The record's own MessagePack form. + /// + /// Serializing the record directly is only correct because the payload + /// fields carry `#[cultcache(key = N, bytes)]`. Muninn previously mirrored + /// each record into a parallel tuple struct — every field restated, in + /// order, by hand — solely so `#[serde(with = "serde_bytes")]` could be + /// applied to the payload, because the `DatabaseEntry` derive does not read + /// serde attributes. Those shadow structs are gone; the derive emits `bin` + /// itself now. Do not reintroduce one. + fn payload_bytes(&self) -> Result> { + match self { + Self::Video(record) => rmp_serde::to_vec(record), + Self::VideoParity(record) => rmp_serde::to_vec(record), + Self::Audio(record) => rmp_serde::to_vec(record), + Self::Feedback(record) => rmp_serde::to_vec(record), + } + .map_err(Into::into) + } +} + +/// Wraps a media record for the wire. +pub fn encode_media_wire_record( + record: &GameCultMediaWireRecord, + provenance: MediaWireProvenance<'_>, +) -> Result> { + provenance.validate()?; + + let schema_id = record.schema_id(); + let record_key = record.record_key(); + let message = CultNetMessage::DocumentPutRaw { + message_id: format!( + "{}-media:{}:{}", + provenance.producer, + schema_id, + record_key.replace(':', "-") + ), + document: CultNetRawDocumentRecord { + schema_id: schema_id.to_string(), + record_key, + stored_at: provenance.stored_at.to_string(), + payload_encoding: CultNetRawPayloadEncoding::Messagepack, + payload: record.payload_bytes()?, + source_runtime_id: Some(provenance.runtime_id.to_string()), + source_agent_id: None, + source_role: Some(provenance.role.to_string()), + tags: Some(vec![format!("{}.media", provenance.producer)]), + }, + }; + + encode_cultnet_message_to_vec(&message, CultNetWireContract::CultNetSchemaV0).map_err(Into::into) +} + +/// Unwraps a media record from the wire. +pub fn decode_media_wire_record(payload: &[u8]) -> Result { + let message = decode_cultnet_message_from_slice(payload, CultNetWireContract::CultNetSchemaV0)?; + let CultNetMessage::DocumentPutRaw { document, .. } = message else { + return Err(anyhow!("expected cultnet.document_put_raw.v0")); + }; + if document.payload_encoding != CultNetRawPayloadEncoding::Messagepack { + return Err(anyhow!("media document payload must be MessagePack")); + } + + match document.schema_id.as_str() { + GAMECULT_MEDIA_VIDEO_ACCESS_UNIT_SCHEMA => Ok(GameCultMediaWireRecord::Video( + rmp_serde::from_slice(&document.payload)?, + )), + GAMECULT_MEDIA_VIDEO_PARITY_SHARD_SCHEMA => Ok(GameCultMediaWireRecord::VideoParity( + rmp_serde::from_slice(&document.payload)?, + )), + GAMECULT_MEDIA_AUDIO_PACKET_SCHEMA => Ok(GameCultMediaWireRecord::Audio( + rmp_serde::from_slice(&document.payload)?, + )), + GAMECULT_MEDIA_RECEIVER_FEEDBACK_SCHEMA => Ok(GameCultMediaWireRecord::Feedback( + rmp_serde::from_slice(&document.payload)?, + )), + other => Err(anyhow!("unknown media schema {other}")), + } +} diff --git a/packages/cultnet-rs/tests/media_stream_wire.rs b/packages/cultnet-rs/tests/media_stream_wire.rs new file mode 100644 index 00000000..cee31a04 --- /dev/null +++ b/packages/cultnet-rs/tests/media_stream_wire.rs @@ -0,0 +1,217 @@ +//! The envelope, and one proof that removing Muninn's shadow structs changed +//! nothing on the wire. + +use cultnet_rs::{ + GAMECULT_MEDIA_CHANNEL, GameCultMediaAudioPacketRecord, GameCultMediaReceiverFeedbackRecord, + GameCultMediaVideoAccessUnitRecord, GameCultMediaVideoParityShardRecord, + GameCultMediaWireRecord, MediaWireProvenance, decode_media_wire_record, + encode_media_wire_record, +}; +use serde::Serialize; + +fn provenance() -> MediaWireProvenance<'static> { + MediaWireProvenance { + stored_at: "unix:1000", + runtime_id: "raven", + role: "muninn.media", + producer: "muninn", + } +} + +fn access_unit() -> GameCultMediaVideoAccessUnitRecord { + GameCultMediaVideoAccessUnitRecord { + stream_id: "raven-primary-av".to_string(), + session_id: "session-1".to_string(), + frame_id: 4242, + codec: "h264".to_string(), + pts_ticks: 90_000, + duration_ticks: 3_000, + timebase_num: 1, + timebase_den: 90_000, + keyframe: true, + dependency_frame_id: None, + deadline_ticks: 108_000, + chunk_index: 2, + chunk_count: 5, + payload: (0u8..=255).collect(), + } +} + +/// Muninn's `VideoAccessUnitWirePayload`, reproduced exactly as it was. +/// +/// It existed only so `#[serde(with = "serde_bytes")]` could reach the payload, +/// because the `DatabaseEntry` derive ignores serde attributes. Every other +/// field was restated by hand, in order, and had to stay in step with the record +/// by discipline alone. +#[derive(Serialize)] +struct LegacyVideoAccessUnitWirePayload<'a>( + &'a str, + &'a str, + u64, + &'a str, + i64, + u32, + u32, + u32, + bool, + Option, + i64, + u16, + u16, + #[serde(with = "serde_bytes")] &'a [u8], +); + +/// If these differ, deleting the shadow structs was a wire break rather than a +/// simplification, and every existing consumer would need to move in step. +#[test] +fn the_derive_reproduces_the_hand_written_wire_payload_byte_for_byte() { + let record = access_unit(); + let legacy = LegacyVideoAccessUnitWirePayload( + &record.stream_id, + &record.session_id, + record.frame_id, + &record.codec, + record.pts_ticks, + record.duration_ticks, + record.timebase_num, + record.timebase_den, + record.keyframe, + record.dependency_frame_id, + record.deadline_ticks, + record.chunk_index, + record.chunk_count, + &record.payload, + ); + + let from_derive = rmp_serde::to_vec(&record).expect("record encodes"); + let from_shadow = rmp_serde::to_vec(&legacy).expect("shadow struct encodes"); + + assert_eq!( + from_derive, from_shadow, + "the `bytes` attribute must reproduce what serde_bytes produced by hand" + ); +} + +#[test] +fn a_video_record_round_trips_through_the_envelope() { + let record = GameCultMediaWireRecord::Video(access_unit()); + let wire = encode_media_wire_record(&record, provenance()).expect("encodes"); + assert_eq!(decode_media_wire_record(&wire).expect("decodes"), record); +} + +#[test] +fn every_variant_round_trips() { + let variants = vec![ + GameCultMediaWireRecord::Video(access_unit()), + GameCultMediaWireRecord::VideoParity(GameCultMediaVideoParityShardRecord { + stream_id: "s".to_string(), + session_id: "x".to_string(), + frame_id: 1, + codec: "h264".to_string(), + pts_ticks: 0, + duration_ticks: 1, + timebase_num: 1, + timebase_den: 90_000, + keyframe: false, + dependency_frame_id: Some(0), + deadline_ticks: 1, + chunk_count: 4, + parity_index: 1, + parity_count: 2, + chunk_payload_bytes: 848, + last_chunk_payload_bytes: 400, + payload: vec![1, 2, 3], + }), + GameCultMediaWireRecord::Audio(GameCultMediaAudioPacketRecord { + stream_id: "s".to_string(), + session_id: "x".to_string(), + packet_id: 9, + codec: "opus".to_string(), + pts_ticks: 0, + duration_ticks: 960, + timebase_num: 1, + timebase_den: 48_000, + deadline_ticks: 1, + payload: vec![4, 5, 6], + }), + GameCultMediaWireRecord::Feedback(GameCultMediaReceiverFeedbackRecord { + stream_id: "s".to_string(), + session_id: "x".to_string(), + receiver_id: "starfire-obs".to_string(), + highest_decodable_frame_id: Some(41), + missing_frame_ids: vec![42], + late_frame_ids: vec![43], + requested_keyframe: true, + jitter_us: 500, + decode_queue_us: 2_000, + observed_at: "unix:1000".to_string(), + missing_video_chunk_keys: vec!["42:1".to_string()], + }), + ]; + + for record in variants { + let wire = encode_media_wire_record(&record, provenance()).expect("encodes"); + assert_eq!( + decode_media_wire_record(&wire).expect("decodes"), + record, + "variant {} did not survive the envelope", + record.schema_id() + ); + } +} + +/// Record keys address one piece of media within a session. A consumer parses +/// them, so their shape is contract. +#[test] +fn record_keys_distinguish_chunks_parity_and_senders() { + let mut second_chunk = access_unit(); + second_chunk.chunk_index = 3; + + let first = GameCultMediaWireRecord::Video(access_unit()).record_key(); + let second = GameCultMediaWireRecord::Video(second_chunk).record_key(); + assert_ne!(first, second, "chunks of one frame must not share a key"); + assert!(first.contains(":video:"), "got {first}"); +} + +/// A shared envelope must not label another producer's traffic as Muninn's. +#[test] +fn the_producer_namespace_is_the_callers_not_the_envelopes() { + let record = GameCultMediaWireRecord::Video(access_unit()); + let theirs = MediaWireProvenance { + stored_at: "unix:1000", + runtime_id: "nightwing", + role: "brokkr.media", + producer: "brokkr", + }; + + let wire = encode_media_wire_record(&record, theirs).expect("encodes"); + let text = String::from_utf8_lossy(&wire); + assert!(text.contains("brokkr-media:"), "message id names the producer"); + assert!(text.contains("brokkr.media"), "tag names the producer"); + assert!( + !text.contains("muninn"), + "the envelope must not name a producer the caller did not supply" + ); +} + +#[test] +fn provenance_must_be_complete() { + let record = GameCultMediaWireRecord::Video(access_unit()); + for blank in ["stored_at", "runtime_id", "role", "producer"] { + let mut incomplete = provenance(); + match blank { + "stored_at" => incomplete.stored_at = "", + "runtime_id" => incomplete.runtime_id = "", + "role" => incomplete.role = "", + _ => incomplete.producer = "", + } + let error = encode_media_wire_record(&record, incomplete) + .expect_err("empty provenance must be refused"); + assert!(error.to_string().contains(blank), "got {error}"); + } +} + +#[test] +fn the_media_channel_is_named_once() { + assert_eq!(GAMECULT_MEDIA_CHANNEL, "media"); +} From 96138ffcfa7d48fe00d31079d7859baa1f3c9a58 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 10 Sep 2026 02:23:56 +0200 Subject: [PATCH 155/283] Validate on decode, where both ends inherit it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moving the envelope moved less than it should have. Muninn's decoder validated every record and checked the envelope's key against the key derived from the record's own contents; the version that landed here did neither, so the move was quietly a downgrade. Six of Muninn's tests failed on the switch and said so, which is the only reason this is a paragraph rather than a bug. The four record validators and the video chunk key move here with it. They check the contract, not one producer's use of it: non-empty identifiers, non-zero timebases, sane pressure figures, well-formed chunk keys. Left in Muninn they would have protected the producer and left every consumer to invent its own idea of a well-formed record — which is how a C++ receiver and a Rust sender came to disagree while each looked correct alone. The record-key check is the sharper one. A key is derived from the record it addresses, so a mismatch means envelope and payload disagree about what the thing is. Admitting that would let a consumer address media by a key its producer never meant. VideoChunkKey comes too. Its string form ("42:1") travels in receiver feedback and is parsed at the other end, so it was already contract living in a producer. Co-Authored-By: Claude Opus 5 --- packages/cultnet-rs/src/media_stream_wire.rs | 290 ++++++++++++++++++- 1 file changed, 276 insertions(+), 14 deletions(-) diff --git a/packages/cultnet-rs/src/media_stream_wire.rs b/packages/cultnet-rs/src/media_stream_wire.rs index 2959eef8..7083d927 100644 --- a/packages/cultnet-rs/src/media_stream_wire.rs +++ b/packages/cultnet-rs/src/media_stream_wire.rs @@ -167,19 +167,281 @@ pub fn decode_media_wire_record(payload: &[u8]) -> Result Ok(GameCultMediaWireRecord::Video( - rmp_serde::from_slice(&document.payload)?, - )), - GAMECULT_MEDIA_VIDEO_PARITY_SHARD_SCHEMA => Ok(GameCultMediaWireRecord::VideoParity( - rmp_serde::from_slice(&document.payload)?, - )), - GAMECULT_MEDIA_AUDIO_PACKET_SCHEMA => Ok(GameCultMediaWireRecord::Audio( - rmp_serde::from_slice(&document.payload)?, - )), - GAMECULT_MEDIA_RECEIVER_FEEDBACK_SCHEMA => Ok(GameCultMediaWireRecord::Feedback( - rmp_serde::from_slice(&document.payload)?, - )), - other => Err(anyhow!("unknown media schema {other}")), + let record = match document.schema_id.as_str() { + GAMECULT_MEDIA_VIDEO_ACCESS_UNIT_SCHEMA => { + let record: GameCultMediaVideoAccessUnitRecord = + rmp_serde::from_slice(&document.payload)?; + validate_video_record(&record)?; + GameCultMediaWireRecord::Video(record) + } + GAMECULT_MEDIA_VIDEO_PARITY_SHARD_SCHEMA => { + let record: GameCultMediaVideoParityShardRecord = + rmp_serde::from_slice(&document.payload)?; + validate_video_parity_record(&record)?; + GameCultMediaWireRecord::VideoParity(record) + } + GAMECULT_MEDIA_AUDIO_PACKET_SCHEMA => { + let record: GameCultMediaAudioPacketRecord = + rmp_serde::from_slice(&document.payload)?; + validate_audio_record(&record)?; + GameCultMediaWireRecord::Audio(record) + } + GAMECULT_MEDIA_RECEIVER_FEEDBACK_SCHEMA => { + let record: GameCultMediaReceiverFeedbackRecord = + rmp_serde::from_slice(&document.payload)?; + validate_feedback_record(&record)?; + GameCultMediaWireRecord::Feedback(record) + } + other => return Err(anyhow!("unsupported media schema {other}")), + }; + + // The key is derived from the record's own contents, so a mismatch means the + // envelope and its payload disagree about what this is. Admitting it would + // let a consumer address media by a key its producer never meant. + let expected = record.record_key(); + if document.record_key != expected { + return Err(anyhow!( + "record key mismatch: envelope says {}, record derives {expected}", + document.record_key + )); + } + + Ok(record) +} + +// --------------------------------------------------------------------------- +// Validation +// +// Moved here from Muninn with the envelope. A decoder that does not validate +// leaves each consumer to invent its own idea of a well-formed record, which is +// how the C++ receiver and the Rust sender came to disagree while both looked +// correct in isolation. Muninn's tests for these came too; they now cover the +// contract rather than one producer's copy of it. +// --------------------------------------------------------------------------- + +/// Addresses one chunk of a video frame. The string form appears in receiver +/// feedback and is parsed by consumers, so its shape is contract. +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct VideoChunkKey { + pub frame_id: u64, + pub chunk_index: u16, +} + +impl VideoChunkKey { + pub fn new(frame_id: u64, chunk_index: u16) -> Self { + Self { + frame_id, + chunk_index, + } + } + + pub fn parse(value: &str) -> Result { + if value.matches(':').count() != 1 { + return Err(anyhow!( + "video chunk key must contain exactly one ':' separator" + )); + } + let (frame_id, chunk_index) = value + .split_once(':') + .ok_or_else(|| anyhow!("video chunk key must be ':'"))?; + Ok(Self { + frame_id: frame_id + .parse() + .map_err(|_| anyhow!("video chunk key frame_id must be an integer"))?, + chunk_index: chunk_index + .parse() + .map_err(|_| anyhow!("video chunk key chunk_index must be an integer"))?, + }) + } + + pub fn as_feedback_key(&self) -> String { + format!("{}:{}", self.frame_id, self.chunk_index) } } + +pub fn video_chunk_feedback_key(frame_id: u64, chunk_index: u16) -> String { + VideoChunkKey::new(frame_id, chunk_index).as_feedback_key() +} + +pub fn normalize_video_chunk_feedback_keys(keys: Vec) -> Result> { + let mut parsed = keys + .iter() + .map(|key| VideoChunkKey::parse(key)) + .collect::>>()?; + parsed.sort_unstable(); + parsed.dedup(); + Ok(parsed + .into_iter() + .map(|key| key.as_feedback_key()) + .collect()) +} + +pub fn validate_video_record(record: &GameCultMediaVideoAccessUnitRecord) -> Result<()> { + if record.stream_id.is_empty() { + return Err(anyhow!("video media record stream_id must be non-empty")); + } + if record.session_id.is_empty() { + return Err(anyhow!("video media record session_id must be non-empty")); + } + if record.codec.is_empty() { + return Err(anyhow!("video media record codec must be non-empty")); + } + if record.timebase_num == 0 || record.timebase_den == 0 { + return Err(anyhow!("video media record timebase must be non-zero")); + } + if record.duration_ticks == 0 { + return Err(anyhow!( + "video media record duration_ticks must be greater than zero" + )); + } + if record.deadline_ticks < record.pts_ticks { + return Err(anyhow!( + "video media record deadline_ticks must not precede pts_ticks" + )); + } + if record.chunk_count == 0 { + return Err(anyhow!("video media record chunk_count must be non-zero")); + } + if record.chunk_index >= record.chunk_count { + return Err(anyhow!( + "video media record chunk_index {} is outside chunk_count {}", + record.chunk_index, + record.chunk_count + )); + } + if record.payload.is_empty() { + return Err(anyhow!("video media record payload must be non-empty")); + } + Ok(()) +} + +pub fn validate_video_parity_record(record: &GameCultMediaVideoParityShardRecord) -> Result<()> { + if record.stream_id.is_empty() { + return Err(anyhow!( + "video parity media record stream_id must be non-empty" + )); + } + if record.session_id.is_empty() { + return Err(anyhow!( + "video parity media record session_id must be non-empty" + )); + } + if record.codec.is_empty() { + return Err(anyhow!("video parity media record codec must be non-empty")); + } + if record.timebase_num == 0 || record.timebase_den == 0 { + return Err(anyhow!( + "video parity media record timebase must be non-zero" + )); + } + if record.duration_ticks == 0 { + return Err(anyhow!( + "video parity media record duration_ticks must be greater than zero" + )); + } + if record.deadline_ticks < record.pts_ticks { + return Err(anyhow!( + "video parity media record deadline_ticks must not precede pts_ticks" + )); + } + if record.chunk_count == 0 { + return Err(anyhow!( + "video parity media record chunk_count must be non-zero" + )); + } + if record.parity_count == 0 || record.parity_index >= record.parity_count { + return Err(anyhow!( + "video parity media record has invalid parity stripe metadata" + )); + } + if record.parity_count > record.chunk_count { + return Err(anyhow!( + "video parity media record parity_count exceeds chunk_count" + )); + } + if record.chunk_payload_bytes == 0 || record.last_chunk_payload_bytes == 0 { + return Err(anyhow!( + "video parity media record chunk lengths must be non-zero" + )); + } + if record.last_chunk_payload_bytes > record.chunk_payload_bytes { + return Err(anyhow!( + "video parity media record last chunk length exceeds regular chunk length" + )); + } + if record.payload.is_empty() { + return Err(anyhow!( + "video parity media record payload must be non-empty" + )); + } + if record.payload.len() > record.chunk_payload_bytes as usize { + return Err(anyhow!( + "video parity media record payload exceeds declared chunk length" + )); + } + Ok(()) +} + +pub fn validate_audio_record(record: &GameCultMediaAudioPacketRecord) -> Result<()> { + if record.stream_id.is_empty() { + return Err(anyhow!("audio media record stream_id must be non-empty")); + } + if record.session_id.is_empty() { + return Err(anyhow!("audio media record session_id must be non-empty")); + } + if record.codec.is_empty() { + return Err(anyhow!("audio media record codec must be non-empty")); + } + if record.timebase_num == 0 || record.timebase_den == 0 { + return Err(anyhow!("audio media record timebase must be non-zero")); + } + if record.duration_ticks == 0 { + return Err(anyhow!( + "audio media record duration_ticks must be greater than zero" + )); + } + if record.deadline_ticks < record.pts_ticks { + return Err(anyhow!( + "audio media record deadline_ticks must not precede pts_ticks" + )); + } + if record.payload.is_empty() { + return Err(anyhow!("audio media record payload must be non-empty")); + } + Ok(()) +} + +pub fn validate_feedback_record(record: &GameCultMediaReceiverFeedbackRecord) -> Result<()> { + if record.stream_id.is_empty() { + return Err(anyhow!( + "receiver feedback media record stream_id must be non-empty" + )); + } + if record.session_id.is_empty() { + return Err(anyhow!( + "receiver feedback media record session_id must be non-empty" + )); + } + if record.receiver_id.is_empty() { + return Err(anyhow!( + "receiver feedback media record receiver_id must be non-empty" + )); + } + if record.observed_at.is_empty() { + return Err(anyhow!( + "receiver feedback media record observed_at must be non-empty" + )); + } + if record.jitter_us < 0 { + return Err(anyhow!( + "receiver feedback media record jitter_us must be non-negative" + )); + } + if record.decode_queue_us < 0 { + return Err(anyhow!( + "receiver feedback media record decode_queue_us must be non-negative" + )); + } + normalize_video_chunk_feedback_keys(record.missing_video_chunk_keys.clone())?; + Ok(()) +} From 2041a0e0ed96ebcfcf9e129fb8cba2ab9f425ef2 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 10 Sep 2026 11:42:13 +0200 Subject: [PATCH 156/283] Bound the TypeScript fragment reassembly map cultnet-ts removed a fragment buffer only on successful reassembly, with no cap, no eviction and no timeout. A fragment set that loses one fragment was stranded for the life of the session, so the map grew without bound under any loss on a fragmenting channel. cultnet-rs at least fails closed at 64 pending sets; TypeScript just consumes memory. This is live, not theoretical. Ghostlight sends Heimdall sealed envelopes over CultMesh RUDP with max_fragment_bytes = 2048 (Ghostlight/crates/ghostlight-dungeon/src/heimdall.rs:697), and Heimdall's private command plane reassembles them through this path. Every lost fragment on that link left a buffer nothing would ever collect, on a long-running auth service. Caps pending sets at 64 to match cultnet-rs's max_pending_fragment_sets, and evicts the oldest stranded set rather than refusing the payload: a receiver that stops accepting fragmented traffic after a bounded number of losses is a denial of service delivered by the network. Map iteration is insertion-ordered, so the first key is the oldest. fragmentSetsEvicted and pendingFragmentSetCount make it observable. Found by the Muninn media load test, which hit the Rust half of the same defect; cultcache-py has the same unbounded map and is not touched here. npm run test --workspace=packages/cultnet-ts -> pass 54, fail 0 Co-Authored-By: Claude Opus 5 --- packages/cultnet-ts/src/rudp.ts | 32 +++++++++++++++++ packages/cultnet-ts/test/cultnet.test.ts | 46 ++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/packages/cultnet-ts/src/rudp.ts b/packages/cultnet-ts/src/rudp.ts index b6cae87d..56dc67fa 100644 --- a/packages/cultnet-ts/src/rudp.ts +++ b/packages/cultnet-ts/src/rudp.ts @@ -160,6 +160,12 @@ export class CultNetRudpSession { readonly #orderedNextSequenceByChannel = new Map(); readonly #orderedBuffers = new Map>(); readonly #fragmentBuffers = new Map(); + /// Matches cultnet-rs's `max_pending_fragment_sets`. A fragment set is only + /// removed on successful reassembly, so a set that loses one fragment is + /// stranded for the life of the session. Without a bound the map grows + /// forever under any loss on a fragmenting channel. + #maxPendingFragmentSets = 64; + #fragmentSetsEvicted = 0; constructor(options: CultNetRudpSessionOptions) { this.connectionId = toUint32(options.connectionId, "connectionId"); @@ -187,6 +193,17 @@ export class CultNetRudpSession { return this.#pendingReliable.size + this.#queuedReliable.length; } + /// Incomplete fragment sets dropped to stay within the pending bound. + /// Non-zero means the peer is losing fragments: the receiver is still + /// serving, and something upstream is not. + get fragmentSetsEvicted(): number { + return this.#fragmentSetsEvicted; + } + + get pendingFragmentSetCount(): number { + return this.#fragmentBuffers.size; + } + get lastReceivedAtMs(): number | undefined { return this.#lastReceivedAtMs; } @@ -203,6 +220,7 @@ export class CultNetRudpSession { this.#orderedNextSequenceByChannel.clear(); this.#orderedBuffers.clear(); this.#fragmentBuffers.clear(); + this.#fragmentSetsEvicted = 0; } createConnect(nowMs = 0, payload = new Uint8Array()): CultNetRudpPacket { @@ -636,6 +654,20 @@ export class CultNetRudpSession { payloads: new Map(), sequences: new Map(), }; + // Evict the oldest stranded set rather than refusing the payload. A + // receiver that stops accepting fragmented traffic after a bounded + // number of losses is a denial of service delivered by the network; + // dropping the least recent incomplete set costs one payload that was + // already incomplete. Map iteration is insertion-ordered, so the first + // key is the oldest. + while (this.#fragmentBuffers.size >= this.#maxPendingFragmentSets) { + const oldest = this.#fragmentBuffers.keys().next(); + if (oldest.done) { + break; + } + this.#fragmentBuffers.delete(oldest.value); + this.#fragmentSetsEvicted += 1; + } this.#fragmentBuffers.set(key, buffer); } if (buffer.fragmentCount !== fragmentCount || buffer.ordered !== (packet.ordered ?? false)) { diff --git a/packages/cultnet-ts/test/cultnet.test.ts b/packages/cultnet-ts/test/cultnet.test.ts index f0c3c3c3..2f540a86 100644 --- a/packages/cultnet-ts/test/cultnet.test.ts +++ b/packages/cultnet-ts/test/cultnet.test.ts @@ -1821,3 +1821,49 @@ test("Generated Ghostlight contracts can feed CultCacheTS directly without a Zod rmSync(tempDir, { recursive: true, force: true }); } }); + +test("rudp receiver evicts stranded fragment sets instead of refusing new ones", () => { + // A fragment set is removed only on successful reassembly, so every set that + // loses a fragment is stranded for the life of the session. Ghostlight sends + // Heimdall fragmented envelopes (max_fragment_bytes = 2048), so on the live + // auth path this map grew for every lost fragment and was never swept. + const receiver = new CultNetRudpSession({ connectionId: 9, initialSequence: 1, resendDelayMs: 50 }); + receiver.receive({ packetType: "accept", connectionId: 9, sequence: 1, ack: 0, ackMask: 0, channelId: "control" }); + + // 200 fragment sets that each lose their second fragment. + for (let id = 1; id <= 200; id += 1) { + const stranded = receiver.receive({ + packetType: "data", + connectionId: 9, + sequence: 100 + id, + ack: 0, + ackMask: 0, + channelId: "schema", + fragmentId: id, + fragmentIndex: 0, + fragmentCount: 2, + payload: Buffer.from([id & 0xff]), + }); + assert.equal(stranded.delivered.length, 0, "an incomplete set must not reassemble"); + } + + // Bounded rather than unbounded, and still serving. + assert.ok(receiver.pendingFragmentSetCount <= 64, `pending ${receiver.pendingFragmentSetCount}`); + assert.ok(receiver.fragmentSetsEvicted > 0, "nothing was evicted"); + + // The receiver still completes a fresh fragmented payload, which is what + // erroring at the cap took away: any nonzero loss killed the channel. + const first = receiver.receive({ + packetType: "data", connectionId: 9, sequence: 900, ack: 0, ackMask: 0, + channelId: "schema", fragmentId: 1000, fragmentIndex: 0, fragmentCount: 2, + payload: Buffer.from("he"), + }); + assert.equal(first.delivered.length, 0); + const second = receiver.receive({ + packetType: "data", connectionId: 9, sequence: 901, ack: 0, ackMask: 0, + channelId: "schema", fragmentId: 1000, fragmentIndex: 1, fragmentCount: 2, + payload: Buffer.from("llo"), + }); + assert.equal(second.delivered.length, 1); + assert.equal(Buffer.from(second.delivered[0]!.payload).toString(), "hello"); +}); From b6b1d9c66049bbdb9c4dbca8ab7cbac1e69d0f11 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 10 Sep 2026 11:42:17 +0200 Subject: [PATCH 157/283] Bound the Python fragment reassembly map cultcache-py removed a fragment buffer only on successful reassembly, the same shape cultnet-ts had: a set that loses one fragment is kept for the life of the session and the map grows under any loss on a fragmenting channel. Cap at 64 to match the other runtimes, evict the oldest stranded set (dict insertion order) rather than refuse the payload, and expose fragment_sets_evicted so the drop is observable. The fragment id already wrapped correctly here; only the Rust allocator saturated. PYTHONPATH=src python -m unittest tests.test_cultcache -> 142 run, 1 pre-existing error (interop fixture path is cwd-relative, same on main) Co-Authored-By: Claude Fable 5.1 --- .../cultcache-py/src/cultnet_py/transport.py | 15 ++++++++ packages/cultcache-py/tests/test_cultcache.py | 35 +++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/packages/cultcache-py/src/cultnet_py/transport.py b/packages/cultcache-py/src/cultnet_py/transport.py index 2b9fe462..73bd1e62 100644 --- a/packages/cultcache-py/src/cultnet_py/transport.py +++ b/packages/cultcache-py/src/cultnet_py/transport.py @@ -418,11 +418,21 @@ class CultNetRudpSession: self._ordered_next_sequence_by_channel: dict[str, int] = {} self._ordered_buffers: dict[str, dict[int, tuple[CultNetRudpDeliveredFrame, int]]] = {} self._fragment_buffers: dict[tuple[str, int], dict[str, Any]] = {} + # Matches cultnet-rs max_pending_fragment_sets. A set that loses one + # fragment is never completed; without a bound it is kept for the life + # of the session and the map grows under any loss on a fragmenting channel. + self._max_pending_fragment_sets = 64 + self._fragment_sets_evicted = 0 @property def connected(self) -> bool: return self._connected + @property + def fragment_sets_evicted(self) -> int: + """Incomplete fragment sets dropped to admit newer ones; one lost payload each.""" + return self._fragment_sets_evicted + @property def last_received_at_ms(self) -> int | None: return self._last_received_at_ms @@ -785,6 +795,11 @@ class CultNetRudpSession: raise ValueError("RUDP fragment index must be lower than fragment count") key = (packet.channel_id, packet.fragment_id) + if key not in self._fragment_buffers and len(self._fragment_buffers) >= self._max_pending_fragment_sets: + # Evict the oldest stranded set rather than refusing the payload; dicts + # iterate in insertion order, so the first key is the oldest. + del self._fragment_buffers[next(iter(self._fragment_buffers))] + self._fragment_sets_evicted += 1 buffer = self._fragment_buffers.setdefault( key, { diff --git a/packages/cultcache-py/tests/test_cultcache.py b/packages/cultcache-py/tests/test_cultcache.py index 29fdefef..639b5508 100644 --- a/packages/cultcache-py/tests/test_cultcache.py +++ b/packages/cultcache-py/tests/test_cultcache.py @@ -6654,5 +6654,40 @@ class CultCacheTests(unittest.TestCase): self.assertEqual(streams.latest_frame("mimir:kiyo-pro").sequence, 42) +class CultNetRudpFragmentBoundTests(unittest.TestCase): + def _pair(self) -> tuple[CultNetRudpSession, CultNetRudpSession]: + sender = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=311, initial_sequence=1)) + receiver = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=311, initial_sequence=100)) + sender.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 311, 90, 0, 0, "control")) + receiver.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 311, 91, 0, 0, "control")) + return sender, receiver + + def test_stranded_fragment_sets_are_bounded_and_evicted_oldest_first(self) -> None: + sender, receiver = self._pair() + receiver._max_pending_fragment_sets = 4 + + # Eight payloads each lose their last fragment; the map must not grow past four. + stranded = [] + for fill in range(1, 9): + packets = sender.send_many("media", bytes([fill]) * 2500, max_fragment_bytes=1000) + self.assertEqual(len(packets), 3) + for packet in packets[:2]: + self.assertEqual(receiver.receive(packet).delivered, ()) + stranded.append(packets[2]) + self.assertEqual(len(receiver._fragment_buffers), 4) + self.assertEqual(receiver.fragment_sets_evicted, 4) + + # A complete payload still lands. + delivered = [] + for packet in sender.send_many("media", bytes([9]) * 2500, max_fragment_bytes=1000): + delivered.extend(receiver.receive(packet).delivered) + self.assertEqual([frame.payload for frame in delivered], [bytes([9]) * 2500]) + self.assertEqual(receiver.fragment_sets_evicted, 5) + + # Oldest-first: set 8 still pends and completes late; set 1 was evicted. + self.assertEqual(receiver.receive(stranded[7]).delivered[0].payload, bytes([8]) * 2500) + self.assertEqual(receiver.receive(stranded[0]).delivered, ()) + + if __name__ == "__main__": unittest.main() From d3bc6e66048f87798e8cac0861a6f2a2a771a996 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 10 Sep 2026 11:37:50 +0200 Subject: [PATCH 158/283] Keep receiving when fragment sets go stale A fragment set that lost one fragment was never reclaimed: the buffer map only shrank on successful reassembly or a payload-size violation. Once 64 sets were stranded, every new fragmented payload returned an error and the receiver's loop terminated. Any nonzero loss on any fragmenting channel was therefore a countdown, not a threshold: 3 fragments at 3% loss killed the receiver at ~700 payloads, 1% at ~2,100. Found by the media load test. When the bound is hit, evict the set untouched longest and count it via fragment_sets_evicted(). A stranded set's siblings were delivered long ago; dropping it is the right call and it was already lost. Also stop saturating the fragment id. saturating_add parked every set after the 65,535th on one shared id, and the reassembler stitched them together. That is the July 2026 eight-minute failure; the id now wraps to 1. Co-Authored-By: Claude Fable 5.1 --- packages/cultnet-rs/src/rudp.rs | 37 +++++++++++- packages/cultnet-rs/tests/cultnet.rs | 85 ++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+), 2 deletions(-) diff --git a/packages/cultnet-rs/src/rudp.rs b/packages/cultnet-rs/src/rudp.rs index b7019b1b..7e871288 100644 --- a/packages/cultnet-rs/src/rudp.rs +++ b/packages/cultnet-rs/src/rudp.rs @@ -167,6 +167,10 @@ struct FragmentBuffer { fragment_count: u16, payloads: BTreeMap>, sequences: BTreeMap, + /// Session-local arrival ordinal of the newest fragment in this set. A + /// set that stops being touched is one that lost a fragment; it is the + /// first to go when the pending-set bound is reached. + last_touched: u64, } pub struct CultNetRudpSession { @@ -191,6 +195,8 @@ pub struct CultNetRudpSession { ordered_next_sequence_by_channel: BTreeMap, ordered_buffers: BTreeMap>, fragment_buffers: BTreeMap<(String, u16), FragmentBuffer>, + fragment_touches: u64, + fragment_sets_evicted: u64, } impl CultNetRudpSession { @@ -217,6 +223,8 @@ impl CultNetRudpSession { ordered_next_sequence_by_channel: BTreeMap::new(), ordered_buffers: BTreeMap::new(), fragment_buffers: BTreeMap::new(), + fragment_touches: 0, + fragment_sets_evicted: 0, } } @@ -247,6 +255,14 @@ impl CultNetRudpSession { self.reliable_packets_expired } + /// Incomplete fragment sets discarded to admit a newer one. Each is a + /// payload that lost at least one fragment on the wire; a rising count is + /// the link's loss rate multiplied by the fragment count, and the reason + /// media payloads should fit in one packet. + pub fn fragment_sets_evicted(&self) -> u64 { + self.fragment_sets_evicted + } + pub fn queued_reliable_packet_count(&self) -> usize { self.queued_reliable.len() } @@ -968,7 +984,19 @@ impl CultNetRudpSession { if !self.fragment_buffers.contains_key(&key) && self.fragment_buffers.len() >= self.max_pending_fragment_sets { - return Err(anyhow!("RUDP pending fragment-set limit reached")); + // A set that is still incomplete when the bound is reached has + // almost certainly lost a fragment; its siblings were delivered + // long ago. Drop the one untouched longest so the session keeps + // receiving. Erroring here made any lossy fragmenting channel a + // countdown to a dead receiver. + let stalest = self + .fragment_buffers + .iter() + .min_by_key(|(_, buffer)| buffer.last_touched) + .map(|(key, _)| key.clone()) + .expect("bound reached implies a pending set exists"); + self.fragment_buffers.remove(&stalest); + self.fragment_sets_evicted += 1; } let buffered_bytes = self .fragment_buffers @@ -995,12 +1023,15 @@ impl CultNetRudpSession { fragment_count: packet.fragment_count, payloads: BTreeMap::new(), sequences: BTreeMap::new(), + last_touched: 0, }); if buffer.fragment_count != packet.fragment_count || buffer.ordered != packet.ordered { return Err(anyhow!( "RUDP fragment metadata changed within a fragment set" )); } + self.fragment_touches += 1; + buffer.last_touched = self.fragment_touches; buffer .payloads .insert(packet.fragment_index, packet.payload.clone()); @@ -1171,7 +1202,9 @@ impl CultNetRudpSession { fn allocate_fragment_id(&mut self) -> u16 { let fragment_id = self.next_fragment_id; - self.next_fragment_id = self.next_fragment_id.saturating_add(1); + // Wrap, never saturate: `saturating_add` parked every set after the + // 65,535th on one shared id, and the reassembler stitched them together. + self.next_fragment_id = self.next_fragment_id.wrapping_add(1); if self.next_fragment_id == 0 { self.next_fragment_id = 1; } diff --git a/packages/cultnet-rs/tests/cultnet.rs b/packages/cultnet-rs/tests/cultnet.rs index 7be6ea18..92401305 100644 --- a/packages/cultnet-rs/tests/cultnet.rs +++ b/packages/cultnet-rs/tests/cultnet.rs @@ -2856,3 +2856,88 @@ fn rudp_profile_expires_only_the_media_channel() -> Result<()> { } Ok(()) } + +fn connected_rudp_pair() -> Result<(CultNetRudpSession, CultNetRudpSession)> { + let mut client = CultNetRudpSession::new(CultNetRudpSessionOptions { + connection_id: 311, + initial_sequence: 1, + ..CultNetRudpSessionOptions::default() + }); + let mut server = CultNetRudpSession::new(CultNetRudpSessionOptions { + connection_id: 311, + initial_sequence: 100, + ..CultNetRudpSessionOptions::default() + }); + let connect = client.create_connect(0, Vec::new())?; + let accept = server.accept_connect(&connect, 1, Vec::new())?; + client.receive(&accept, 2)?; + Ok((client, server)) +} + +#[test] +fn rudp_evicts_stalest_incomplete_fragment_set_instead_of_dying() -> Result<()> { + let (mut client, mut server) = connected_rudp_pair()?; + client.set_max_pending_fragment_sets(4)?; + let fragmented = |server: &mut CultNetRudpSession, fill: u8| { + server.send_many( + "media", + vec![fill; 2500], + CultNetRudpSendOptions::default(), + Some(1000), + ) + }; + + // Eight payloads each lose their last fragment on the wire. Before, the + // fifth new set errored the receiver out and every later fragmented + // payload with it. + let mut stranded = Vec::new(); + for fill in 1..=8u8 { + let packets = fragmented(&mut server, fill)?; + assert_eq!(packets.len(), 3); + for packet in &packets[..2] { + assert!(client.receive(packet, 10)?.delivered.is_empty()); + } + stranded.push(packets[2].clone()); + } + assert_eq!(client.fragment_sets_evicted(), 4); + + // A complete payload still lands. + let complete = fragmented(&mut server, 9)?; + let mut delivered = Vec::new(); + for packet in &complete { + delivered.extend(client.receive(packet, 11)?.delivered); + } + assert_eq!(delivered.len(), 1); + assert_eq!(delivered[0].payload, vec![9u8; 2500]); + assert_eq!(client.fragment_sets_evicted(), 5); + + // The eviction order is stalest-first: set 8 is still pending and completes + // when its late fragment shows up; set 1 was evicted long ago, so its late + // fragment opens a fresh set and delivers nothing. + assert_eq!( + client.receive(&stranded[7], 12)?.delivered[0].payload, + vec![8u8; 2500] + ); + assert!(client.receive(&stranded[0], 13)?.delivered.is_empty()); + Ok(()) +} + +#[test] +fn rudp_fragment_ids_wrap_instead_of_saturating() -> Result<()> { + let (_client, mut server) = connected_rudp_pair()?; + let mut ids = Vec::new(); + for _ in 0..(u16::MAX as usize + 1) { + let packets = server.send_many( + "media", + vec![0u8; 1500], + CultNetRudpSendOptions::default(), + Some(1000), + )?; + ids.push(packets[0].fragment_id); + } + assert_eq!(ids[0], 1); + assert_eq!(ids[u16::MAX as usize - 1], u16::MAX); + // The 65,536th set must not share an id with the 65,535th. + assert_eq!(ids[u16::MAX as usize], 1); + Ok(()) +} From 66f05e161ae0697fd2d376d0c666a5ad8f46984f Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 10 Sep 2026 11:40:11 +0200 Subject: [PATCH 159/283] Expose fragment-set evictions in transport stats A receiver that survives loss by discarding stranded sets has to say so, or the drop is invisible and the next diagnosis starts from "delivered less than sent" again. CultNetTransportStats now carries fragment_sets_evicted, summed across hub peers like reliable_packets_expired, and the media delivery probe prints it beside delivered_pct. Co-Authored-By: Claude Fable 5.1 --- packages/cultnet-rs/examples/media_delivery_probe.rs | 5 +++-- packages/cultnet-rs/src/rudp.rs | 6 ++++++ packages/cultnet-rs/src/transport.rs | 4 ++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/cultnet-rs/examples/media_delivery_probe.rs b/packages/cultnet-rs/examples/media_delivery_probe.rs index 75058eaf..e1f2ac97 100644 --- a/packages/cultnet-rs/examples/media_delivery_probe.rs +++ b/packages/cultnet-rs/examples/media_delivery_probe.rs @@ -87,10 +87,11 @@ fn recv(bind: SocketAddr, expect: u64) -> Result<()> { let elapsed = started.elapsed().as_secs_f64(); println!("RESULT recv frames={frames} expected={expect} payload_bytes={payload_bytes}"); println!( - "RESULT recv wire_bytes_in={} wire_bytes_out={} elapsed_s={elapsed:.2} delivered_pct={:.2}", + "RESULT recv wire_bytes_in={} wire_bytes_out={} elapsed_s={elapsed:.2} delivered_pct={:.2} fragment_sets_evicted={}", stats.bytes_received, stats.bytes_sent, - (frames as f64 / expect as f64) * 100.0 + (frames as f64 / expect as f64) * 100.0, + stats.fragment_sets_evicted ); Ok(()) } diff --git a/packages/cultnet-rs/src/rudp.rs b/packages/cultnet-rs/src/rudp.rs index 7e871288..b6a8fe95 100644 --- a/packages/cultnet-rs/src/rudp.rs +++ b/packages/cultnet-rs/src/rudp.rs @@ -1453,6 +1453,11 @@ impl CultNetRudpServerHub { .values() .map(|peer| peer.session.reliable_packets_expired()) .fold(0_u64, |total, expired| total.saturating_add(expired)); + stats.fragment_sets_evicted = self + .peers + .values() + .map(|peer| peer.session.fragment_sets_evicted()) + .fold(0_u64, |total, evicted| total.saturating_add(evicted)); stats } @@ -1754,6 +1759,7 @@ impl CultNetRudpSocketTransportConnection { pub fn stats(&self) -> CultNetTransportStats { let mut stats = self.stats.clone(); stats.reliable_packets_expired = self.session.reliable_packets_expired(); + stats.fragment_sets_evicted = self.session.fragment_sets_evicted(); stats } diff --git a/packages/cultnet-rs/src/transport.rs b/packages/cultnet-rs/src/transport.rs index cf28079e..d097aa3c 100644 --- a/packages/cultnet-rs/src/transport.rs +++ b/packages/cultnet-rs/src/transport.rs @@ -22,6 +22,10 @@ pub struct CultNetTransportStats { /// Reliable packets dropped by a send-side expiry deadline instead of being /// retransmitted. Always zero for transports without reliable expiry. pub reliable_packets_expired: u64, + /// Incomplete fragment sets discarded to admit newer ones. Each is one + /// payload that lost a fragment on the wire. Zero for non-fragmenting + /// transports. + pub fragment_sets_evicted: u64, } #[derive(Clone, Debug, PartialEq, Eq)] From a8aeddacab7dd4b9e634b4420867ea3b402cb858 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 10 Sep 2026 11:56:06 +0200 Subject: [PATCH 160/283] Let the media probe fragment on demand A seventh argument sets max_fragment_bytes on the sender. Without it a 3,392-byte payload leaves loopback as one datagram, and a matrix that claims to measure fragmentation measures nothing: the impair proxy's received count equalled the payload count in every cell. Co-Authored-By: Claude Fable 5.1 --- packages/cultnet-rs/examples/media_delivery_probe.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/cultnet-rs/examples/media_delivery_probe.rs b/packages/cultnet-rs/examples/media_delivery_probe.rs index e1f2ac97..397eb656 100644 --- a/packages/cultnet-rs/examples/media_delivery_probe.rs +++ b/packages/cultnet-rs/examples/media_delivery_probe.rs @@ -45,9 +45,10 @@ fn main() -> Result<()> { args.get(4).ok_or_else(|| anyhow!("payload bytes"))?.parse()?, args.get(5).ok_or_else(|| anyhow!("count"))?.parse()?, args.get(6).map(|v| v.parse()).transpose()?.unwrap_or(12.0), + args.get(7).map(|v| v.parse()).transpose()?, ), _ => Err(anyhow!( - "usage: media_delivery_probe recv | send " + "usage: media_delivery_probe recv | send [mbps] [max_fragment_bytes]" )), } } @@ -102,6 +103,7 @@ fn send( payload_bytes: usize, count: u64, target_mbps: f64, + max_fragment_bytes: Option, ) -> Result<()> { let socket = UdpSocket::bind("0.0.0.0:0")?; socket.set_nonblocking(true)?; @@ -109,6 +111,9 @@ fn send( CultNetRudpSocketTransportOptions::client("probe-send", socket, endpoint, 0x0BE0_0001); options.media_delivery = Some(delivery); options.media_reliable_expire_after_ms = None; + // Fragment above this many bytes so a lost datagram costs a whole payload; + // None sends each payload as one datagram, which loopback carries whole. + options.max_fragment_bytes = max_fragment_bytes; let mut transport = CultNetRudpSocketTransportConnection::new(options)?; transport.connect(b"probe".to_vec())?; From 95493862bdd60a5e5637282ab6df6802dc01220c Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 10 Sep 2026 13:10:47 +0200 Subject: [PATCH 161/283] Split the Python runtime into cultcache-py, cultnet-py, cultmesh-py One distribution named cultcache-py carried three libraries. Rust and TypeScript layer them as cultcache < cultnet < cultmesh; Python now does the same, one package per layer, module names unchanged so every `from cultmesh_py import ...` keeps working. Two imports ran against that layering and are resolved by moving code to where the dependency direction says it lives, not by adding a shim: - cultnet_py.interop_peer imported the Verse/peer catalog, authority lease, stream, and simulation-fact contracts from cultmesh_py. They are wire contracts a bare peer has to speak without owning a node, which is why cultnet-rs and cultnet-ts keep them in the net layer. They now live in cultnet_py.cultmesh_contracts; cultmesh_py re-exports them. - cultcache_py.benchmark imported cultnet_py. It measures framed CultNet parse beside cache paths, so it and compare_csharp move to cultnet_py. verify checks all three packages and moves to cultmesh_py. The single 6,693-line test module is split by what each test touches: a test using any cultmesh_py name lands in cultmesh-py, else cultnet_py in cultnet-py, else cultcache-py. Each suite runs with only its layer and the layers below on the path, so a test that reaches up fails to import rather than quietly binding the packages back together. 11 / 53 / 78 = the same 142. Workflows install all three; the publish job is one matrix over the three packages keyed by tag prefix. The TS test harnesses put all three src directories on PYTHONPATH. cultcache-py bumps to 0.2.0 because it no longer contains cultnet_py or cultmesh_py; the new packages start at 0.1.0. Nothing was ever published, so no PyPI consumer moves. cultcache-py 11 tests, path: cultcache-py/src cultnet-py 53 tests, path: + cultnet-py/src cultmesh-py 78 tests, path: + cultmesh-py/src python -m cultmesh_py.verify -> ok, all five checks cultnet_py.interop_peer imports with cultmesh_py absent Not run here: the cultnet-ts interop ring and cultcache-ts store matrix need dotnet/kotlin peers; their PYTHONPATH change is four lines. Co-Authored-By: Claude Fable 5.1 --- .github/workflows/cultmesh-portability.yml | 4 +- .github/workflows/cultnet-interop.yml | 2 +- .github/workflows/publish-packages.yml | 56 +- .gitignore | 4 + README.md | 6 +- docs/cultnet-transport-parity.md | 2 +- .../python-runtime-parity.md | 20 +- docs/runtime-parity-scope.md | 2 +- packages/cultcache-py/README.md | 394 +- packages/cultcache-py/pyproject.toml | 16 +- .../src/cultmesh_py/simulation.py | 135 - packages/cultcache-py/tests/test_cultcache.py | 6438 +---------------- packages/cultcache-ts/test/cult-cache.test.ts | 6 +- packages/cultmesh-py/README.md | 252 + packages/cultmesh-py/pyproject.toml | 29 + .../src/cultmesh_py/__init__.py | 2 +- .../src/cultmesh_py/client.py | 2 +- .../src/cultmesh_py/daemon.py | 2 +- .../src/cultmesh_py/facade.py | 2 +- .../src/cultmesh_py/node.py | 0 .../src/cultmesh_py/py.typed | 0 .../src/cultmesh_py/server.py | 2 +- .../src/cultmesh_py/session.py | 2 +- .../cultmesh-py/src/cultmesh_py/simulation.py | 47 + .../src/cultmesh_py}/verify.py | 6 +- packages/cultmesh-py/tests/test_cultmesh.py | 4491 ++++++++++++ .../tools/reactive_performance_probe.py | 0 packages/cultnet-py/README.md | 156 + packages/cultnet-py/pyproject.toml | 33 + .../src/cultnet_py/__init__.py | 54 + .../src/cultnet_py}/benchmark.py | 2 +- .../src/cultnet_py/client.py | 0 .../src/cultnet_py}/compare_csharp.py | 2 +- .../src/cultnet_py/cultmesh_contracts.py} | 107 +- .../src/cultnet_py/framing.py | 0 .../src/cultnet_py/interop_peer.py | 2 +- .../src/cultnet_py/messages.py | 0 .../src/cultnet_py/prediction.py | 0 .../src/cultnet_py/py.typed | 0 .../src/cultnet_py/replication.py | 0 .../src/cultnet_py/schema_catalog.py | 0 .../src/cultnet_py/security.py | 0 .../src/cultnet_py/shard_catalog.py | 0 .../src/cultnet_py/shard_log.py | 0 .../src/cultnet_py/shard_replication.py | 0 .../src/cultnet_py/simulation.py | 0 .../src/cultnet_py/snapshot.py | 0 .../src/cultnet_py/subscription.py | 0 .../src/cultnet_py/transport.py | 0 packages/cultnet-py/tests/test_cultnet.py | 2046 ++++++ .../GameCult.Caching.Benchmark.csproj | 0 .../GameCult.Caching.Benchmark/Program.cs | 0 .../test/interop/cultnet-interop.test.ts | 4 +- .../measure-reactive-document-performance.ps1 | 4 +- scripts/verify-reactive-document-scaling.ps1 | 6 +- 55 files changed, 7331 insertions(+), 7007 deletions(-) rename packages/cultcache-py/PARITY.md => docs/python-runtime-parity.md (96%) delete mode 100644 packages/cultcache-py/src/cultmesh_py/simulation.py create mode 100644 packages/cultmesh-py/README.md create mode 100644 packages/cultmesh-py/pyproject.toml rename packages/{cultcache-py => cultmesh-py}/src/cultmesh_py/__init__.py (98%) rename packages/{cultcache-py => cultmesh-py}/src/cultmesh_py/client.py (99%) rename packages/{cultcache-py => cultmesh-py}/src/cultmesh_py/daemon.py (99%) rename packages/{cultcache-py => cultmesh-py}/src/cultmesh_py/facade.py (99%) rename packages/{cultcache-py => cultmesh-py}/src/cultmesh_py/node.py (100%) rename packages/{cultcache-py => cultmesh-py}/src/cultmesh_py/py.typed (100%) rename packages/{cultcache-py => cultmesh-py}/src/cultmesh_py/server.py (99%) rename packages/{cultcache-py => cultmesh-py}/src/cultmesh_py/session.py (98%) create mode 100644 packages/cultmesh-py/src/cultmesh_py/simulation.py rename packages/{cultcache-py/src/cultcache_py => cultmesh-py/src/cultmesh_py}/verify.py (98%) create mode 100644 packages/cultmesh-py/tests/test_cultmesh.py rename packages/{cultcache-py => cultmesh-py}/tools/reactive_performance_probe.py (100%) create mode 100644 packages/cultnet-py/README.md create mode 100644 packages/cultnet-py/pyproject.toml rename packages/{cultcache-py => cultnet-py}/src/cultnet_py/__init__.py (79%) rename packages/{cultcache-py/src/cultcache_py => cultnet-py/src/cultnet_py}/benchmark.py (98%) rename packages/{cultcache-py => cultnet-py}/src/cultnet_py/client.py (100%) rename packages/{cultcache-py/src/cultcache_py => cultnet-py/src/cultnet_py}/compare_csharp.py (99%) rename packages/{cultcache-py/src/cultmesh_py/wire.py => cultnet-py/src/cultnet_py/cultmesh_contracts.py} (84%) rename packages/{cultcache-py => cultnet-py}/src/cultnet_py/framing.py (100%) rename packages/{cultcache-py => cultnet-py}/src/cultnet_py/interop_peer.py (99%) rename packages/{cultcache-py => cultnet-py}/src/cultnet_py/messages.py (100%) rename packages/{cultcache-py => cultnet-py}/src/cultnet_py/prediction.py (100%) rename packages/{cultcache-py => cultnet-py}/src/cultnet_py/py.typed (100%) rename packages/{cultcache-py => cultnet-py}/src/cultnet_py/replication.py (100%) rename packages/{cultcache-py => cultnet-py}/src/cultnet_py/schema_catalog.py (100%) rename packages/{cultcache-py => cultnet-py}/src/cultnet_py/security.py (100%) rename packages/{cultcache-py => cultnet-py}/src/cultnet_py/shard_catalog.py (100%) rename packages/{cultcache-py => cultnet-py}/src/cultnet_py/shard_log.py (100%) rename packages/{cultcache-py => cultnet-py}/src/cultnet_py/shard_replication.py (100%) rename packages/{cultcache-py => cultnet-py}/src/cultnet_py/simulation.py (100%) rename packages/{cultcache-py => cultnet-py}/src/cultnet_py/snapshot.py (100%) rename packages/{cultcache-py => cultnet-py}/src/cultnet_py/subscription.py (100%) rename packages/{cultcache-py => cultnet-py}/src/cultnet_py/transport.py (100%) create mode 100644 packages/cultnet-py/tests/test_cultnet.py rename packages/{cultcache-py => cultnet-py}/tools/GameCult.Caching.Benchmark/GameCult.Caching.Benchmark.csproj (100%) rename packages/{cultcache-py => cultnet-py}/tools/GameCult.Caching.Benchmark/Program.cs (100%) diff --git a/.github/workflows/cultmesh-portability.yml b/.github/workflows/cultmesh-portability.yml index 9c7b3005..4d93085a 100644 --- a/.github/workflows/cultmesh-portability.yml +++ b/.github/workflows/cultmesh-portability.yml @@ -77,8 +77,8 @@ jobs: - name: Install TypeScript workspace dependencies run: npm install --no-package-lock - - name: Install Python CultCache package - run: python -m pip install -e packages/cultcache-py + - name: Install Python CultLib packages + run: python -m pip install -e packages/cultcache-py -e packages/cultnet-py -e packages/cultmesh-py - name: Verify explicit reactive scheduling across runtimes shell: pwsh diff --git a/.github/workflows/cultnet-interop.yml b/.github/workflows/cultnet-interop.yml index 3437add3..f7f2eefc 100644 --- a/.github/workflows/cultnet-interop.yml +++ b/.github/workflows/cultnet-interop.yml @@ -69,7 +69,7 @@ jobs: run: npm install --no-package-lock - name: Install Python package dependencies - run: python -m pip install -e packages/cultcache-py + run: python -m pip install -e packages/cultcache-py -e packages/cultnet-py -e packages/cultmesh-py - name: Build TypeScript workspace dependencies run: npm run build --workspace packages/cultcache-ts diff --git a/.github/workflows/publish-packages.yml b/.github/workflows/publish-packages.yml index f92868aa..6061ca7a 100644 --- a/.github/workflows/publish-packages.yml +++ b/.github/workflows/publish-packages.yml @@ -8,15 +8,18 @@ name: Publish packages # directly, which is already how Ghostlight, Epiphany, CodexConnector and Odin # consume the core stack. # -# Tag a release to publish, for example `cultcache-ts-v0.13.6`. The tag's -# version must match the version in the package manifest; the workflow refuses -# the publish otherwise rather than shipping a mislabelled artifact. +# Tag a release to publish, for example `cultcache-ts-v0.13.6` or +# `cultnet-py-v0.1.0`. The tag's version must match the version in the package +# manifest; the workflow refuses the publish otherwise rather than shipping a +# mislabelled artifact. on: push: tags: - "cultcache-ts-v*" - "cultcache-py-v*" + - "cultnet-py-v*" + - "cultmesh-py-v*" workflow_dispatch: inputs: package: @@ -26,6 +29,8 @@ on: options: - cultcache-ts - cultcache-py + - cultnet-py + - cultmesh-py permissions: contents: read @@ -72,9 +77,16 @@ jobs: env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - cultcache-py: - name: cultcache-py to PyPI - if: startsWith(github.ref, 'refs/tags/cultcache-py-v') || inputs.package == 'cultcache-py' + # The three Python packages layer cultcache-py < cultnet-py < cultmesh-py, the + # same way the Rust crates and npm packages do. One job shape serves all + # three; the matrix entry names the package and the tag prefix that releases it. + python: + name: ${{ matrix.package }} to PyPI + if: startsWith(github.ref, 'refs/tags/cultcache-py-v') || startsWith(github.ref, 'refs/tags/cultnet-py-v') || startsWith(github.ref, 'refs/tags/cultmesh-py-v') || endsWith(inputs.package, '-py') + strategy: + fail-fast: false + matrix: + package: [cultcache-py, cultnet-py, cultmesh-py] runs-on: ubuntu-latest timeout-minutes: 20 environment: pypi @@ -84,31 +96,51 @@ jobs: # long-lived API token is stored in the repository. id-token: write steps: + - name: Skip packages this run does not name + id: selected + run: | + if [ "${GITHUB_REF_NAME#${{ matrix.package }}-v}" != "$GITHUB_REF_NAME" ] || [ "${{ inputs.package }}" = "${{ matrix.package }}" ]; then + echo "run=true" >> "$GITHUB_OUTPUT" + else + echo "run=false" >> "$GITHUB_OUTPUT" + fi + - name: Check out CultLib + if: steps.selected.outputs.run == 'true' uses: actions/checkout@v4 - name: Set up Python + if: steps.selected.outputs.run == 'true' uses: actions/setup-python@v5 with: python-version: "3.12" - name: Verify the tag matches the manifest version - if: startsWith(github.ref, 'refs/tags/cultcache-py-v') + if: steps.selected.outputs.run == 'true' && startsWith(github.ref, 'refs/tags/') run: | - manifest="$(python -c "import tomllib,pathlib;print(tomllib.loads(pathlib.Path('packages/cultcache-py/pyproject.toml').read_text())['project']['version'])")" - tagged="${GITHUB_REF_NAME#cultcache-py-v}" + manifest="$(python -c "import tomllib,pathlib;print(tomllib.loads(pathlib.Path('packages/${{ matrix.package }}/pyproject.toml').read_text())['project']['version'])")" + tagged="${GITHUB_REF_NAME#${{ matrix.package }}-v}" if [ "$manifest" != "$tagged" ]; then echo "tag $GITHUB_REF_NAME does not match manifest version $manifest" >&2 exit 1 fi + # Lower layers install from source so a release of one package is tested + # against the sibling revision it was cut with, not whatever PyPI has. + - name: Install and test + if: steps.selected.outputs.run == 'true' + run: | + python -m pip install -e packages/cultcache-py -e packages/cultnet-py -e packages/cultmesh-py + python -m unittest discover -s packages/${{ matrix.package }}/tests + - name: Build sdist and wheel + if: steps.selected.outputs.run == 'true' run: | python -m pip install --upgrade build - python -m build packages/cultcache-py + python -m build packages/${{ matrix.package }} - name: Publish - if: startsWith(github.ref, 'refs/tags/cultcache-py-v') + if: steps.selected.outputs.run == 'true' && startsWith(github.ref, 'refs/tags/') uses: pypa/gh-action-pypi-publish@release/v1 with: - packages-dir: packages/cultcache-py/dist + packages-dir: packages/${{ matrix.package }}/dist diff --git a/.gitignore b/.gitignore index 656fafa0..94ed900d 100644 --- a/.gitignore +++ b/.gitignore @@ -303,6 +303,10 @@ node_modules/ !packages/cultmesh-ts/** !packages/cultcache-py/ !packages/cultcache-py/** +!packages/cultnet-py/ +!packages/cultnet-py/** +!packages/cultmesh-py/ +!packages/cultmesh-py/** !packages/cultcache-rs/ !packages/cultcache-rs/** !packages/cultnet-rs/ diff --git a/README.md b/README.md index 4775a040..602ccc6c 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,9 @@ The solution includes: - `packages/cultnet-ts`: TypeScript CultNet schema-v0 contracts, framing, discovery, raw document replication, and interop tests - `packages/cultmesh-ts`: TypeScript CultMesh local node and mesh catalog surface for local runtimes such as VoidBot - `packages/cultmesh-browser`: browser-safe, read-only CultMesh document leases and typed operations over an Odin-resolved WebSocket route -- `packages/cultcache-py`: Python CultCache/CultNet/CultMesh package with CultCache v1 wire parity +- `packages/cultcache-py`: Python CultCache with CultCache v1 wire parity +- `packages/cultnet-py`: Python CultNet contracts, framing, RUDP transport, replication, and interop peer +- `packages/cultmesh-py`: Python CultMesh local node, discovery, sessions, local server, and daemon - `packages/cultcache-rs`: Rust CultCache and derive macro - `packages/cultnet-rs`: Rust CultNet contracts, framing, discovery, and interop peer - `packages/cultmesh-kotlin`: Kotlin/JVM CultMesh and CultNet surface for Android-adjacent runtimes @@ -145,6 +147,8 @@ packages/ cultmesh-browser/ cultmesh-kotlin/ cultcache-py/ + cultnet-py/ + cultmesh-py/ cultcache-rs/ cultnet-rs/ ``` diff --git a/docs/cultnet-transport-parity.md b/docs/cultnet-transport-parity.md index aa962c46..d0779196 100644 --- a/docs/cultnet-transport-parity.md +++ b/docs/cultnet-transport-parity.md @@ -31,7 +31,7 @@ CultNet owns cross-runtime transport semantics: | C# interop peer | Schema-v0 MessagePack over TCP-framed or shared RUDP transport | UDP multicast probe/announce with TCP and RUDP transport profiles | Test harness transport parity | | TypeScript `cultnet-ts` | `CultNetPeer` over any Node `Duplex`, TCP-framed transport, or single-peer RUDP socket transport; interop uses TCP | UDP multicast probe/announce in the interop peer | First UDP socket binding for the shared RUDP reliability owner | | Rust `cultnet-rs` | Interop example serves and dials schema-v0 MessagePack over TCP-framed or shared RUDP transport; single-peer RUDP socket transport exists in the library | UDP multicast probe/announce with TCP and RUDP transport profiles | UDP socket binding for the shared RUDP reliability owner | -| Python `cultcache-py` | TCP sockets with 4-byte length-prefixed MessagePack frames for local CultMesh/CultNet server and client; single-peer RUDP socket transport exists in the library | Endpoint lists and CultMesh peer/Verse catalogs | UDP socket binding for the shared RUDP reliability owner | +| Python `cultnet-py` | TCP sockets with 4-byte length-prefixed MessagePack frames for local CultMesh/CultNet server and client; single-peer RUDP socket transport exists in the library | Endpoint lists and CultMesh peer/Verse catalogs | UDP socket binding for the shared RUDP reliability owner | | Kotlin `cultmesh-kotlin` | Channel-aware WebSocket transport connection for reliable ordered `schema` frames; single-peer RUDP socket transport exists in the library; interop CLI serves and dials schema-v0 MessagePack over TCP-framed or shared RUDP transport | CultMesh Verse and peer catalogs, plus endpoint lists carried in schema-v0 catalog messages | WebSocket/TCP adapters plus UDP socket binding for the shared RUDP reliability owner, with build-script and TypeScript harness proof | The live split is therefore: payload language and the native RUDP packet/session diff --git a/packages/cultcache-py/PARITY.md b/docs/python-runtime-parity.md similarity index 96% rename from packages/cultcache-py/PARITY.md rename to docs/python-runtime-parity.md index 18607d87..1cc222b7 100644 --- a/packages/cultcache-py/PARITY.md +++ b/docs/python-runtime-parity.md @@ -1,7 +1,7 @@ # Python Runtime Parity Map -This file is the current audit map for `cultcache-py` as a Python runtime for -CultCache, CultNet, and CultMesh. It is evidence, not confetti. +This file is the current audit map for the Python runtime packages +`cultcache-py`, `cultnet-py`, and `cultmesh-py`. It is evidence, not confetti. ## Proven Surfaces @@ -255,14 +255,14 @@ CultCache, CultNet, and CultMesh. It is evidence, not confetti. individual discovery, peer exchange, or simulation surfaces unserved without advertising disabled capabilities. - Python package health: - `cultcache-py-verify --json` checks the public CultCache/CultNet/CultMesh + `cultmesh-py-verify --json` checks the public CultCache/CultNet/CultMesh export surface declared by each package `__all__`, `py.typed` markers, a live local CultMesh framed-wire smoke over hello/schema/snapshot/shard catalog/shard log, typed peer-error export availability, peer-advertised mutation contracts, payload schema wire contracts, simulation capability truth, and benchmark sanity for Python-owned hot paths. - Python/C# public cache baseline: - `cultcache_py.compare_csharp` runs Python and C# `CultCache` upsert/get + `cultnet_py.compare_csharp` runs Python and C# `CultCache` upsert/get benchmarks with the same operation names and reports median Python-to-C# ratios from three samples by default. It also emits per-metric threshold checks and an overall parity status so performance claims have an explicit evidence gate. @@ -275,12 +275,14 @@ CultCache, CultNet, and CultMesh. It is evidence, not confetti. ## Local Python Gates ```powershell -$env:PYTHONPATH="$PWD\packages\cultcache-py\src" +$env:PYTHONPATH="$PWD\packages\cultcache-py\src;$PWD\packages\cultnet-py\src;$PWD\packages\cultmesh-py\src" python -m unittest discover -s packages\cultcache-py\tests -python -m cultcache_py.verify --json -python -m cultcache_py.benchmark --records 1000 --json -python -m cultcache_py.compare_csharp --records 1000 --samples 3 --json -python -m pip wheel --no-deps -w $env:TEMP packages\cultcache-py +python -m unittest discover -s packages\cultnet-py\tests +python -m unittest discover -s packages\cultmesh-py\tests +python -m cultmesh_py.verify --json +python -m cultnet_py.benchmark --records 1000 --json +python -m cultnet_py.compare_csharp --records 1000 --samples 3 --json +python -m pip wheel --no-deps -w $env:TEMP packages\cultcache-py packages\cultnet-py packages\cultmesh-py ``` ## Cross-Runtime Gate diff --git a/docs/runtime-parity-scope.md b/docs/runtime-parity-scope.md index 75d980d8..5d4f6b50 100644 --- a/docs/runtime-parity-scope.md +++ b/docs/runtime-parity-scope.md @@ -52,7 +52,7 @@ CultMesh. `reconnectPolicy` profile field from C#, Rust, Python, and Kotlin peers. Runtime-local tests cover the deterministic delay helper and reconnect controller in C#, TypeScript, Rust, Python, and Kotlin. -- `packages/cultcache-py/PARITY.md` is the Python-specific audit ledger. Its +- `docs/python-runtime-parity.md` is the Python-specific audit ledger. Its "Still Not Claimed" section is part of the contract, not an apology. - `docs/cultnet-transport-parity.md` is the transport ownership map. It tracks the remaining work to lower older LiteNetLib/WebSocket bodies behind the diff --git a/packages/cultcache-py/README.md b/packages/cultcache-py/README.md index 48c023ba..f8ac551f 100644 --- a/packages/cultcache-py/README.md +++ b/packages/cultcache-py/README.md @@ -1,12 +1,16 @@ -# cultcache-py +# cultcache-py -`cultcache-py` is the Python runtime package for CultCache, CultNet, and -CultMesh. Callers work with registered domain documents while the cache owns -schema identity, routing, globals, name lookups, indexes, and backing-store -envelopes. +`cultcache-py` is the Python CultCache runtime. Callers work with registered +domain documents while the cache owns schema identity, routing, globals, name +lookups, indexes, and backing-store envelopes. It is intentionally small. It is not an ORM, a database, or distributed consensus wearing rented authority. +It is the bottom of the Python CultLib stack and depends only on `msgpack`. +`cultnet-py` (transport and wire contracts) and `cultmesh-py` (nodes, +discovery, sessions, local server) build on it, mirroring `cultcache-rs` / +`cultnet-rs` / `cultmesh-rs` and the npm packages. + ## Current Shape - document types are registered explicitly @@ -21,10 +25,6 @@ It is intentionally small. It is not an ORM, a database, or distributed consensu - the JSONL store uses only the Python standard library for bootstrap consumers - `define_database_entry_type(...)` emits Rust/C#-style slot-indexed MessagePack array payloads for cross-runtime `DatabaseEntry` contracts -- `cultnet_py` exposes schema-v0 MessagePack helpers and 4-byte big-endian - frame helpers for raw document state, subscriptions, shard catch-up, - simulation observations, and witness artifact bundles -- `cultmesh_py` exposes a cache-backed local node surface for Python tools ## Example @@ -144,382 +144,28 @@ That matches the Rust `#[derive(DatabaseEntry)]` formatter shape and the C# `[Key(n)]` intent: schema evolution comes from stable field slots, not source member order. -## CultNet And CultMesh - -`cultnet_py` provides the Python schema-v0 wire helpers and an interop peer: - -```python -from datetime import UTC, datetime - -from cultnet_py import ( - CultNetSecret, - CultNetServerSecurityOptions, - CultNetRawClient, - CultNetSimulationObservation, - CultNetWitnessArtifactBundle, - apply_raw_snapshot, - apply_shard_log_response, - compute_simulation_claim_hash, - database_subscribe, - decode_frame, - encode_frame, - hello, - parse_message, - shard_catalog_request, - simulation_observation, - witness_artifact_bundle, -) -from cultmesh_py import CultMesh - -payload = hello(runtime_id="python-runtime").to_bytes() -message = parse_message(decode_frame(encode_frame(payload))) - -client = CultNetRawClient("127.0.0.1", 3075) -catalog = client.fetch_schema_catalog(kinds=["wire_message"]) -snapshot = client.fetch_snapshot_response(schema_ids=["cultnet.interop-note"]) -shard_catalog = client.fetch_shard_catalog(schema_ids=["cultnet.interop-note"]) -# With a local CultCache and the matching registered document definitions: -# applied = apply_raw_snapshot(cache, [note_doc], snapshot) - -subscription = database_subscribe(subscription_id="ui", schema_ids=["cultnet.interop-note"]) -shard_request = shard_catalog_request(message_id="shards", schema_ids=["cultnet.interop-note"]) -shard_log = client.fetch_shard_log_response(shard_id="interop", shard_epoch=1, after_sequence=0) -# log_changes = apply_shard_log_response(cache, [note_doc], shard_log) -with client.subscribe_database(subscription_id="ui", schema_ids=["cultnet.interop-note"]) as live: - initial_snapshot = live.read_next_snapshot_response() - -# The same raw-client request surface can ride RUDP when the peer advertises a -# rudp:// endpoint and shares the connection id for that lane. -rudp_client = CultMesh.create_client( - endpoint="rudp://127.0.0.1:3076", - connection_id=0x43554C54, -) -rudp_catalog = rudp_client.fetch_schema_catalog(kinds=["wire_message"]) - -claim_hash = compute_simulation_claim_hash("frame:42", "subject:player-1", "hit") -observation = simulation_observation( - message_id="obs-1", - witness_runtime_id="python-runtime", - shard_id="interop", - shard_epoch=1, - frame=42, - subject_id="player-1", - claim_kind="hit", - claim_hash=claim_hash, -) -typed_observation = CultNetSimulationObservation.from_wire(observation.to_wire()) -witness = witness_artifact_bundle( - bundle_id="bundle-1", - witness_kind="interop-proof", - captured_at="2026-06-13T00:00:00Z", - subject={"documentType": "cultnet.interop-note", "subjectId": "note:python"}, - contracts=[{"role": "payload", "schemaId": "cultnet.interop-note"}], - artifacts=[{"role": "log", "uri": "cultcache://bundle-1/log", "mediaType": "text/plain"}], - provenance={"pipelineId": "interop", "runId": "run-1", "runtimeId": "python-runtime"}, -) -typed_witness = CultNetWitnessArtifactBundle.from_wire(witness) -witness_payload = typed_witness.to_payload() - -security = CultNetServerSecurityOptions.development() -token = CultNetSecret.create_session_token( - "318fb4b6-ff5e-4c4f-b911-d81807de53a8", - datetime(2035, 1, 1, tzinfo=UTC), - security, - session_version=1, -) -session = CultNetSecret.try_validate_session_token(token, security) -``` - -AES-GCM string/byte encryption helpers are available through the same -`CultNetSecret` surface when the optional `crypto` extra is installed. - -The peer can serve, dial, and probe the same raw-state interop lane used by the -TypeScript, Rust, and C# test peers: - -```powershell -python -m cultnet_py.interop_peer serve --runtime-id python-peer --runtime-kind python --display-name "Python Peer" --agent-id python-agent --advertise-host 127.0.0.1 --tcp-port 3075 --discovery-port 4075 --discovery-group 239.77.44.11 --schema-path ..\cultnet-ts\integration\contracts\cultnet.interop-note.schema.json -python -m cultnet_py.interop_peer dial --runtime-id python-client --runtime-kind python --display-name "Python Client" --agent-id python-client --target-host 127.0.0.1 --target-port 3075 --schema-path ..\cultnet-ts\integration\contracts\cultnet.interop-note.schema.json -python -m cultnet_py.interop_peer probe --runtime-id python-prober --discovery-port 4075 --discovery-group 239.77.44.11 -``` - -`cultmesh_py` includes a local cache-backed node, schema-v0 helpers for the -CultMesh Verse catalog and peer exchange wire messages, local and verified -authority lease checks, stream transport negotiation, committed simulation fact -documents, and local prediction reconciliation: - -```python -from datetime import UTC, datetime, timedelta - -from cultcache_py import define_database_entry_type -from cultnet_py import ( - CultNetClientAuthorityScope, - CultNetFileShardReplicaCursorStore, - CultNetRawClient, - CultNetSchemaShardLogFetcher, - CultNetSchemaShardSnapshotFetcher, - CultNetShardDescriptor, - CultNetShardReplicator, - CultNetShardReplicatorOptions, -) -from cultmesh_py import ( - CultMesh, - CultMeshAuthorityLease, - CultMeshGameSessionOptions, - CultMeshHmacAuthorityLeaseVerifier, - CultMeshNodeOptions, - CultMeshSnapshotFanout, - peer_exchange_request, -) - -note_doc = define_database_entry_type( - "mesh.note", - [("body", 0), ("name", 1), ("kind", 2)], - name="name", - indexes={"kind": "kind"}, -) -node = CultMesh.start_node( - "mesh.cc", - runtime_id="python-runtime", - options=CultMeshNodeOptions(enable_durable_shard_logs=True), -) -node.database.register_document(note_doc) -unsubscribe = node.database.watch_record(note_doc, "note:1", lambda change: print(change.change_kind)) -unsubscribe_named = node.database.watch_by_name(note_doc, "intro", lambda change: print(change.record_key)) -unsubscribe_kind = node.database.watch_by_index(note_doc, "kind", "guide", lambda change: print(change.record_key)) -node.database.put(note_doc, "note:1", {"body": "hello", "name": "intro", "kind": "guide"}) -live_note = node.database.get_required(note_doc, "note:1") -put_message = node.database.put_raw_message( - note_doc, - "note:2", - {"body": "wire me", "name": "wire", "kind": "interop"}, - shard_id="interop", - shard_epoch=1, -) -snapshot_response = node.database.build_snapshot_response(schema_ids=[note_doc.catalog_entry().schema_id]) -snapshot_wire = node.database.create_snapshot_response(schema_ids=[note_doc.catalog_entry().schema_id]) -delete_message = node.database.delete_raw_message(note_doc, "note:2", shard_id="interop", shard_epoch=1) -shard_log_response = node.database.build_shard_log_response(shard_id="interop", shard_epoch=1) -shard_log_wire = node.database.create_shard_log_response(shard_id="interop", shard_epoch=1) - -station_stock_doc = define_database_entry_type( - "aetheria.station_stock", - [("missiles", 0), ("coolant", 1)], - schema_id="gamecult.aetheria.station_stock.v1", -) -station_stock_ui_doc = define_database_entry_type( - "aetheria.station_stock.ui", - [("missiles", 0), ("coolant", 1)], - schema_id="gamecult.aetheria.station_stock.v1", -) -node.database.register_document(station_stock_doc) -node.database.put(station_stock_ui_doc, "station:starbridge:stock", {"missiles": 24, "coolant": 80}) -stock = node.database.get_required(station_stock_ui_doc, "station:starbridge:stock") - -peers = CultMesh.create_peer_catalog() -response = peers.create_response(peer_exchange_request("pex-1", verse_id="local")) -lease_verifier = CultMeshHmacAuthorityLeaseVerifier({"odin": b"shared-lease-key"}) -lease_catalog = CultMesh.create_authority_lease_catalog( - signature_verifier=lease_verifier.verify, - require_verified_signatures=True, -) -lease_valid_from = datetime.now(UTC) -lease = lease_verifier.issue(CultMeshAuthorityLease( - lease_id="lease:python-runtime", - verse_id="local", - peer_id="python-runtime", - roles=("shard-primary",), - valid_from=lease_valid_from, - expires_at=lease_valid_from + timedelta(minutes=5), - shard_ids=("interop",), - issuer_runtime_id="odin", -)) -lease_catalog.upsert(lease) -session = CultMesh.create_game_session( - node, - CultMeshGameSessionOptions( - client_authority_scopes=( - CultNetClientAuthorityScope("python-runtime", schema_ids=(note_doc.catalog_entry().schema_id,), key_prefix="input:python"), - ), - ), -) -server = CultMesh.serve_node( - node, - peer_catalog=peers, - observation_hub=session.observation_hub, - port=3075, - max_snapshot_documents=1000, - max_snapshot_bytes=4 * 1024 * 1024, -) -``` - -The same local server can be launched as a package daemon when another runtime -or operator process needs a CultNet endpoint without embedding Python glue: - -```powershell -python -m cultmesh_py.daemon --runtime-id python-runtime --display-name "Python Runtime" --host 127.0.0.1 --port 3075 --cache-file mesh.cc --enable-durable-shard-logs --seed-interop-note --seed-shard-id interop --verse-id local --role shard-primary --ready-file mesh.ready.json -``` - -The ready file and stdout line are process readiness hints. The served state and -capability truth still live on the framed CultNet/CultMesh endpoint. Use -`--register-interop-note` to expose the package interop-note schema without -seeding a note, or `--seed-interop-note` to register it and publish one local -record for wire probes. Seeded records are committed through the raw mutation -path, so peers can read them through both snapshot and shard-log catch-up. Add -`--verse-id` and one or more `--role` values to publish the launched endpoint in -its own Verse and peer catalogs for discovery clients. When the daemon is -launched with `--cache-file`, `--enable-durable-shard-logs`, and -`--shard-log-file`, a later daemon process can rehydrate and serve the persisted -snapshot and shard log without reseeding. - -`CultMeshPeerHealthMonitor` probes peer-card endpoints with `cultnet.hello.v0` -and preserves the runtime id, display name, document types, message versions, -and mutation contracts reported by the peer. - -```python - -client = CultMesh.create_verse_discovery_client("127.0.0.1", 3075) -verses = client.fetch_verses(transport_version="cultmesh.v0") -mesh_peers = client.fetch_peers(verse_id="python-interop", roles=["read-replica"]) -client.sync_peer_catalog(peers, verse_id="python-interop", roles=["read-replica"]) -client.fanout_peer_catalog(peers, verse_id="python-interop", roles=["read-replica"]) -replica_notes = client.sync_documents( - node.database, - peers, - verse_id="python-interop", - roles=["read-replica"], - documents=[(note_doc, "note:remote")], -) -snapshot_fanout = CultMeshSnapshotFanout( - client, - node.database, - peers, - verse_id="python-interop", - roles=["read-replica"], - documents=[(note_doc, "note:remote")], - on_document=lambda note: print(note), -) -snapshot_fanout.sync_once() - -raw_client = CultNetRawClient("127.0.0.1", 3075) -synced_note = node.database.sync_document(raw_client, note_doc, "note:remote") -synced_stock = CultMesh.sync_document( - node, - raw_client, - station_stock_ui_doc, - "station:starbridge:stock", -) -with CultMesh.subscribe_document( - node, - raw_client, - station_stock_ui_doc, - "station:starbridge:stock", -) as stock_subscription: - stock = stock_subscription.sync_initial() - next_change = stock_subscription.read_next_change() -node.database.sync_shard_log(raw_client, shard_id="interop", shard_epoch=1) -replicator = CultNetShardReplicator( - node.database, - CultNetShardReplicatorOptions( - fetcher=CultNetSchemaShardLogFetcher(), - snapshot_fetcher=CultNetSchemaShardSnapshotFetcher(), - cursor_store=CultNetFileShardReplicaCursorStore("mesh.replica-cursors.msgpack"), - poll_interval_seconds=1.0, - on_error=lambda error: print(error), - ), -) -replica_shard = CultNetShardDescriptor( - shard_id="interop", - owner_runtime_id="primary-runtime", - epoch=1, - schema_ids=(note_doc.catalog_entry().schema_id,), - primary_endpoints=("cultnet://127.0.0.1:3075",), -) -replicator.pull_once(replica_shard) -replicator.start([replica_shard]) -replicator.stop() -server.stop() - -streams = CultMesh.create_stream_catalog() - -claim_hash = "accepted-claim-hash" -facts = CultMesh.create_simulation_fact_committer(node) -committed = facts.commit({ - "shardId": "arena", - "shardEpoch": 4, - "frame": 100, - "subjectId": "bob", - "claimKind": "hit", - "claimHash": claim_hash, - "witnessCount": 2, - "supportWeight": 2.0, - "totalWeight": 2.0, - "confidence": 1.0, - "hasQuorum": True, -}) -session_commits = session.submit_and_commit(typed_observation) -prediction = session.predict(note_doc, "input:python:move", {"body": "predicted input"}) -unsubscribe() -``` - ## Wire Parity -See [PARITY.md](PARITY.md) for the current evidence map, gates, and things this -package still does not claim. +See [docs/python-runtime-parity.md](../../docs/python-runtime-parity.md) for +the evidence map across the three Python packages. -The Python interop peer is `cultcache_py.interop`: +The store interop peer is `cultcache_py.interop`: ```powershell python -m cultcache_py.interop write --file cache.cc --runtime-id python python -m cultcache_py.interop read --file cache.cc ``` -Current receipts: +`packages/cultcache-ts/test/cult-cache.test.ts` includes Python in the shared +CultCache v1 parity matrix with TypeScript, Rust, and C#. `cultcache_py` ships +a `py.typed` marker so downstream type checkers can inspect the package surface. -- `packages/cultcache-ts/test/cult-cache.test.ts` includes Python in the shared - CultCache v1 parity matrix with TypeScript, Rust, and C#. -- `packages/cultnet-ts/test/interop/cultnet-interop.test.ts` includes Python in - the live TS/Rust/C#/Python schema-v0 peer ring: discovery, hello, schema - catalog, wire-message catalog discovery, raw snapshot, raw document - put/delete, mutation receipt, fire-command receipt, database subscription - changes, shard catalog, shard log catch-up, simulation consensus candidates, - committed simulation fact snapshots, Python session prediction reconciliation, - and witness artifact bundle round-trips. The same test asks the Python peer - for CultMesh Verse catalog and peer exchange responses over the CultNet pipe, - then verifies the public `CultMeshDiscoveryClient` can fetch typed Python - Verse and peer descriptors from that live endpoint. It also verifies - `CultNetRawClient` can fetch the live Python peer's schema catalog, raw - snapshot, and shard catalog. -- `packages/cultcache-py/tests/test_cultcache.py` covers Python CultMesh - Verse catalog, peer exchange, authority lease, stream negotiation, CultNet - helper shapes, raw snapshot/shard-log application, simulation claim hashing, - consensus aggregation, game-session fact commits, local prediction - reconciliation, committed simulation fact payload slots, the local CultMesh - server's TCP and RUDP schema request paths, and witness artifact bundle - payload slots. -- `cultcache_py`, `cultnet_py`, and `cultmesh_py` ship `py.typed` markers so - downstream type checkers can inspect the package surface instead of treating - the runtime as an untyped xenos swamp. - -## Performance Baseline - -The package ships a lightweight benchmark for Python-owned hot paths. In a -CultLib source checkout, it can also run the C# reference benchmark beside it: +## Tests ```powershell -python -m cultcache_py.benchmark --records 1000 --json -python -m cultcache_py.compare_csharp --records 1000 --json -python -m cultcache_py.verify --json +$env:PYTHONPATH="$PWD\packages\cultcache-py\src" +python -m unittest discover -s packages\cultcache-py\tests ``` -It reports slot-indexed `DatabaseEntry` encode/decode throughput, framed -CultNet MessagePack parse throughput, raw snapshot application into a -registered cache, and public `CultCache` upsert/get throughput. The C# compare -command also runs `packages/cultcache-py/tools/GameCult.Caching.Benchmark` and -reports median Python-to-C# ratios for the shared public cache operations. It -uses three samples by default; pass `--samples` when you need a different -evidence shape. Both runtimes precompute record keys before measured cache -upsert/get loops so the comparison is about public cache access, not string -construction noise. The public in-memory cache owner stores records in -type-partitioned dictionaries so hot `get(...)` calls avoid per-call -composite-key allocation. Treat the benchmark numbers as a local baseline, not -a claim that Python matches the C# reference in every workload. +The suite runs with only this package on the path. If a test here needs +`cultnet_py` or `cultmesh_py`, it belongs in that package. diff --git a/packages/cultcache-py/pyproject.toml b/packages/cultcache-py/pyproject.toml index 9f515ac2..ebd92a26 100644 --- a/packages/cultcache-py/pyproject.toml +++ b/packages/cultcache-py/pyproject.toml @@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta" [project] name = "cultcache-py" -version = "0.1.0" -description = "Python CultCache, CultNet, and CultMesh runtime package for GameCult typed state." +version = "0.2.0" +description = "Python CultCache runtime for GameCult typed state." readme = "README.md" requires-python = ">=3.10" license = "MIT" @@ -18,23 +18,11 @@ classifiers = [ "Programming Language :: Python :: 3.12", ] dependencies = ["msgpack>=1.0"] - -[project.optional-dependencies] -msgpack = ["msgpack>=1.0"] -crypto = ["cryptography>=42"] - [project.scripts] cultcache-py-interop = "cultcache_py.interop:main" -cultnet-py-interop = "cultnet_py.interop_peer:main" -cultcache-py-benchmark = "cultcache_py.benchmark:main" -cultcache-py-compare-csharp = "cultcache_py.compare_csharp:main" -cultcache-py-verify = "cultcache_py.verify:main" -cultmesh-py-daemon = "cultmesh_py.daemon:main" [tool.setuptools.packages.find] where = ["src"] [tool.setuptools.package-data] cultcache_py = ["py.typed"] -cultnet_py = ["py.typed"] -cultmesh_py = ["py.typed"] diff --git a/packages/cultcache-py/src/cultmesh_py/simulation.py b/packages/cultcache-py/src/cultmesh_py/simulation.py deleted file mode 100644 index 4b727fd5..00000000 --- a/packages/cultcache-py/src/cultmesh_py/simulation.py +++ /dev/null @@ -1,135 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass -from datetime import UTC, datetime -import hashlib -from typing import Any - -from cultcache_py import define_database_entry_type -from cultcache_py.documents import DocumentDefinition - -from .node import CultMeshNode - -SIMULATION_FACT_DOCUMENT_TYPE = "gamecult.mesh.simulation_fact" -SIMULATION_FACT_SCHEMA_VERSION = "gamecult.mesh.simulation_fact.v1" - - -@dataclass(frozen=True) -class CultMeshSimulationFact: - fact_id: str - shard_id: str - shard_epoch: int - frame: int - subject_id: str - claim_kind: str - claim_hash: str - claim_summary: str | None - witness_count: int - support_weight: float - total_weight: float - confidence: float - committed_at: str - - @staticmethod - def compute_fact_id(candidate: dict[str, Any]) -> str: - canonical = "\x1f".join([ - _candidate_string(candidate, "shardId", "shard_id"), - str(_candidate_int(candidate, "shardEpoch", "shard_epoch")), - str(_candidate_int(candidate, "frame", "frame")), - _candidate_string(candidate, "subjectId", "subject_id"), - _candidate_string(candidate, "claimKind", "claim_kind"), - ]) - return hashlib.sha256(canonical.encode("utf-8")).hexdigest() - - @staticmethod - def create_record_key(candidate: dict[str, Any]) -> str: - return f"simulation:{CultMeshSimulationFact.compute_fact_id(candidate)}" - - @staticmethod - def from_candidate(candidate: dict[str, Any], *, committed_at: str | None = None) -> "CultMeshSimulationFact": - return CultMeshSimulationFact( - fact_id=CultMeshSimulationFact.compute_fact_id(candidate), - shard_id=_candidate_string(candidate, "shardId", "shard_id"), - shard_epoch=_candidate_int(candidate, "shardEpoch", "shard_epoch"), - frame=_candidate_int(candidate, "frame", "frame"), - subject_id=_candidate_string(candidate, "subjectId", "subject_id"), - claim_kind=_candidate_string(candidate, "claimKind", "claim_kind"), - claim_hash=_candidate_string(candidate, "claimHash", "claim_hash"), - claim_summary=_candidate_optional_string(candidate, "claimSummary", "claim_summary"), - witness_count=_candidate_int(candidate, "witnessCount", "witness_count"), - support_weight=_candidate_float(candidate, "supportWeight", "support_weight"), - total_weight=_candidate_float(candidate, "totalWeight", "total_weight"), - confidence=_candidate_float(candidate, "confidence", "confidence"), - committed_at=committed_at or datetime.now(UTC).isoformat(), - ) - - -simulation_fact_document: DocumentDefinition[CultMeshSimulationFact] = define_database_entry_type( - SIMULATION_FACT_DOCUMENT_TYPE, - [ - ("fact_id", 0), - ("shard_id", 1), - ("shard_epoch", 2), - ("frame", 3), - ("subject_id", 4), - ("claim_kind", 5), - ("claim_hash", 6), - ("claim_summary", 7, None), - ("witness_count", 8), - ("support_weight", 9), - ("total_weight", 10), - ("confidence", 11), - ("committed_at", 12), - ], - cls=CultMeshSimulationFact, - name="fact_id", - indexes={"shard": "shard_id", "frame": "frame", "subject": "subject_id", "claim_kind": "claim_kind"}, - schema_name=SIMULATION_FACT_DOCUMENT_TYPE, - schema_version=SIMULATION_FACT_SCHEMA_VERSION, -) - - -@dataclass(frozen=True) -class CultMeshSimulationFactCommit: - key: str - fact: CultMeshSimulationFact - - -@dataclass -class CultMeshSimulationFactCommitter: - node: CultMeshNode - document: DocumentDefinition[CultMeshSimulationFact] = simulation_fact_document - - def __post_init__(self) -> None: - if all(document.type != self.document.type for document in self.node.documents): - self.node.register_document(self.document) - - def commit(self, candidate: dict[str, Any], *, committed_at: str | None = None) -> CultMeshSimulationFactCommit: - if not bool(candidate.get("hasQuorum") if "hasQuorum" in candidate else candidate.get("has_quorum")): - raise ValueError("Simulation candidate cannot be committed before quorum") - key = CultMeshSimulationFact.create_record_key(candidate) - fact = CultMeshSimulationFact.from_candidate(candidate, committed_at=committed_at) - self.node.put(self.document, key, fact) - return CultMeshSimulationFactCommit(key=key, fact=fact) - - -def _candidate_string(candidate: dict[str, Any], camel: str, snake: str) -> str: - value = candidate.get(camel, candidate.get(snake, "")) - if value is None: - return "" - return str(value) - - -def _candidate_optional_string(candidate: dict[str, Any], camel: str, snake: str) -> str | None: - value = candidate.get(camel, candidate.get(snake)) - if value is None: - return None - return str(value) - - -def _candidate_int(candidate: dict[str, Any], camel: str, snake: str) -> int: - return int(candidate.get(camel, candidate.get(snake, 0))) - - -def _candidate_float(candidate: dict[str, Any], camel: str, snake: str) -> float: - return float(candidate.get(camel, candidate.get(snake, 0.0))) diff --git a/packages/cultcache-py/tests/test_cultcache.py b/packages/cultcache-py/tests/test_cultcache.py index 639b5508..2c23fbf7 100644 --- a/packages/cultcache-py/tests/test_cultcache.py +++ b/packages/cultcache-py/tests/test_cultcache.py @@ -1,24 +1,9 @@ -from __future__ import annotations +from __future__ import annotations -import json -import os -import socket -import subprocess -import sys import tempfile -import threading -import time import unittest -from unittest.mock import patch -import hashlib -import hmac -import io from dataclasses import asdict, dataclass -from datetime import UTC, datetime, timedelta from pathlib import Path -from typing import Any, Callable -from uuid import uuid4 - from cultcache_py import ( CultCache, JsonLinesBackingStore, @@ -26,155 +11,7 @@ from cultcache_py import ( define_database_entry_type, define_document_type, ) -from cultcache_py.benchmark import run_benchmark -from cultcache_py.compare_csharp import ( - DEFAULT_PARITY_THRESHOLD, - DEFAULT_SAMPLE_COUNT, - _compare_common_metrics, - _median_result, - _parity_status, -) -from cultcache_py.interop import INTEROP_SCHEMA_VERSION, interop_note_document, read_note, write_note -from cultcache_py.verify import verify -from cultnet_py.interop_peer import append_shard_log_put, build_state, raw_snapshot_response -from cultnet_py import ( - compute_simulation_claim_hash, - CultNetDatabaseChange, - CultNetClientAuthorityScope, - CultNetRawClient, - CultNetRawDocumentRecord, - CultNetRawSnapshotResponse, - CultNetSchemaCatalog, - CultNetSchemaDescriptor, - CultNetShardCatalog, - CultNetShardDescriptor, - CultNetShardLogEntry, - CultNetShardLogResponse, - CultNetFileShardReplicaCursorStore, - CultNetFileShardMutationLogStore, - CultNetInMemoryShardReplicaCursorStore, - CultNetSchemaWriteForwarder, - CultNetSchemaShardLogFetcher, - CultNetSchemaShardSnapshotFetcher, - CultNetPeerError, - CultNetClientSecurityOptions, - CultNetSecret, - CultNetServerSecurityOptions, - CultNetShardReplicator, - CultNetShardReplicatorOptions, - CultNetShardMutationLogStore, - CultNetShardWriteForwarder, - CultNetSimulationConsensusOptions, - CultNetSimulationConsensusCandidate, - CultNetSimulationObservation, - CultNetSimulationObservationHub, - CultNetRudpPacket, - CultNetRudpPacketType, - CultNetRudpSendOptions, - CultNetRudpSession, - CultNetRudpSessionOptions, - CultNetRudpSocketMode, - CultNetRudpReconnectLoop, - CultNetRudpSocketTransportConnection, - CultNetRudpSocketTransportOptions, - TcpFramedTransportConnection, - CultNetWitnessArtifactBundle, - apply_raw_document_record, - apply_raw_snapshot, - apply_shard_log_response, - create_rudp_transport_profile, - create_tcp_framed_transport_profile, - create_reconnect_policy, - CultNetReconnectController, - database_subscribe, - database_unsubscribe, - decode_frame, - decode_rudp_packet, - decode_witness_artifact_bundle_payload, - document_delete, - document_put_raw, - encode_frame, - encode_rudp_packet, - encode_witness_artifact_bundle_payload, - hello, - login, - login_success, - parse_message, - register, - schema_catalog_request, - schema_document_map, - shard_catalog_request, - shard_log_request, - simulation_observation, - snapshot_request, - verify_session, - wire_message_schema_catalog, - wire_message_schema_descriptors, - witness_artifact_bundle, - compute_reconnect_delay_ms, -) -from cultmesh_py import create_node -from cultmesh_py import ( - CultMesh, - CultMeshDatabase, - CultMeshDatabaseChange, - CultMeshGameSessionOptions, - CultMeshNodeOptions, - CultMeshReactiveDocumentOptions, - CultMeshPeerCard, - CultMeshPeerCatalog, - CultMeshSimulationFact, - CultMeshAuthorityLease, - CultMeshAuthorityLeaseCatalog, - CultMeshHmacAuthorityLeaseVerifier, - CultMeshDiscoveryClient, - CultMeshPeerExchangeClient, - CultMeshPeerHealthMonitor, - CultMeshSimulationObservationFanout, - CultMeshSnapshotFanout, - CultMeshStreamCatalog, - CultMeshStreamConsumerProfile, - CultMeshStreamDescriptor, - CultMeshStreamFrameHandle, - CultMeshVerseCatalog, - CultMeshVerseCompatibility, - CultMeshVerseDescriptor, - CultMeshVerseDiscoveryClient, - READY_SCHEMA_VERSION, - peer_exchange_request, - simulation_fact_document, - verse_catalog_request, -) - - -def bind_udp_socket() -> socket.socket: - sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - sock.bind(("127.0.0.1", 0)) - sock.settimeout(0.02) - return sock - - -def pump_rudp_handshake( - client: CultNetRudpSocketTransportConnection, - server: CultNetRudpSocketTransportConnection, -) -> None: - for _ in range(20): - server.receive_once() - client.receive_once() - server.receive_once() - if client.connected and server.connected: - return - time.sleep(0.005) - raise AssertionError("RUDP socket handshake did not complete") - - -def receive_rudp_frame(transport: CultNetRudpSocketTransportConnection): - for _ in range(20): - frame = transport.receive_once() - if frame is not None: - return frame - time.sleep(0.005) - raise AssertionError("RUDP socket frame was not delivered") +from cultcache_py.interop import read_note, write_note @dataclass @@ -195,14 +32,6 @@ def item_doc(): class CultCacheTests(unittest.TestCase): - def _wait_until(self, predicate: Callable[[], bool], *, timeout_seconds: float = 2.0) -> None: - deadline = time.monotonic() + timeout_seconds - while time.monotonic() < deadline: - if predicate(): - return - time.sleep(0.01) - self.fail("Timed out waiting for condition") - def test_round_trips_registered_documents(self) -> None: with tempfile.TemporaryDirectory() as tmp: document = item_doc() @@ -409,101 +238,6 @@ class CultCacheTests(unittest.TestCase): self.assertEqual(loaded["authorRuntimeId"], "python-test") self.assertIn("interop", loaded["tags"]) - def test_benchmark_reports_core_hot_path_metrics(self) -> None: - result = run_benchmark(8) - metric_names = {metric["name"] for metric in result["metrics"]} - self.assertEqual(result["records"], 8) - self.assertEqual(result["wireMessageCount"], 8) - self.assertEqual(metric_names, { - "database_entry_encode", - "database_entry_decode", - "cultnet_frame_parse", - "raw_snapshot_apply", - "cache_upsert", - "cache_get", - }) - self.assertTrue(all(metric["opsPerSecond"] > 0 for metric in result["metrics"])) - - def test_compare_csharp_median_result_summarizes_samples(self) -> None: - self.assertEqual(DEFAULT_SAMPLE_COUNT, 3) - self.assertEqual(DEFAULT_PARITY_THRESHOLD, 0.90) - samples = [ - { - "runtime": "python", - "records": 3, - "metrics": [ - {"name": "cache_get", "operations": 3, "elapsedMs": 30.0, "opsPerSecond": 100.0}, - {"name": "cache_upsert", "operations": 3, "elapsedMs": 60.0, "opsPerSecond": 50.0}, - ], - }, - { - "runtime": "python", - "records": 3, - "metrics": [ - {"name": "cache_get", "operations": 3, "elapsedMs": 10.0, "opsPerSecond": 300.0}, - {"name": "cache_upsert", "operations": 3, "elapsedMs": 20.0, "opsPerSecond": 150.0}, - ], - }, - { - "runtime": "python", - "records": 3, - "metrics": [ - {"name": "cache_get", "operations": 3, "elapsedMs": 20.0, "opsPerSecond": 200.0}, - {"name": "cache_upsert", "operations": 3, "elapsedMs": 40.0, "opsPerSecond": 75.0}, - ], - }, - ] - - summarized = _median_result(samples) - - self.assertEqual(summarized["sampleCount"], 3) - self.assertEqual(summarized["metrics"][0]["name"], "cache_get") - self.assertEqual(summarized["metrics"][0]["elapsedMs"], 20.0) - self.assertEqual(summarized["metrics"][0]["opsPerSecond"], 200.0) - self.assertEqual(summarized["metrics"][1]["opsPerSecond"], 75.0) - - def test_compare_csharp_marks_threshold_status_per_metric(self) -> None: - python_result = { - "metrics": [ - {"name": "cache_get", "operations": 3, "elapsedMs": 2.0, "opsPerSecond": 50.0}, - {"name": "cache_upsert", "operations": 3, "elapsedMs": 1.0, "opsPerSecond": 95.0}, - ], - } - csharp_result = { - "metrics": [ - {"name": "cache_get", "operations": 3, "elapsedMs": 1.0, "opsPerSecond": 100.0}, - {"name": "cache_upsert", "operations": 3, "elapsedMs": 1.0, "opsPerSecond": 100.0}, - ], - } - - comparison = _compare_common_metrics(python_result, csharp_result, parity_threshold=0.90) - by_name = {item["name"]: item for item in comparison} - - self.assertFalse(by_name["cache_get"]["meetsParityThreshold"]) - self.assertTrue(by_name["cache_upsert"]["meetsParityThreshold"]) - self.assertEqual(_parity_status(comparison, "ok"), "below-threshold") - self.assertEqual(_parity_status([by_name["cache_upsert"]], "ok"), "meets-threshold") - self.assertEqual(_parity_status(comparison, "failed"), "unknown") - - def test_compare_csharp_marks_meets_threshold_when_all_common_metrics_pass(self) -> None: - comparison = _compare_common_metrics( - { - "metrics": [ - {"name": "cache_get", "operations": 3, "elapsedMs": 1.0, "opsPerSecond": 95.0}, - {"name": "cache_upsert", "operations": 3, "elapsedMs": 1.0, "opsPerSecond": 120.0}, - ], - }, - { - "metrics": [ - {"name": "cache_get", "operations": 3, "elapsedMs": 1.0, "opsPerSecond": 100.0}, - {"name": "cache_upsert", "operations": 3, "elapsedMs": 1.0, "opsPerSecond": 100.0}, - ], - }, - parity_threshold=0.90, - ) - - self.assertEqual(_parity_status(comparison, "ok"), "meets-threshold") - def test_cache_put_without_backing_store_keeps_in_memory_value(self) -> None: document = define_database_entry_type( "bench.memory_item", @@ -520,6174 +254,6 @@ class CultCacheTests(unittest.TestCase): self.assertEqual(cache.get(document, "item:one"), {"name": "one", "value": 1}) self.assertEqual(cache.get_required_envelope(document, "item:one").key, "item:one") - def test_verify_reports_python_runtime_surface_health(self) -> None: - result = verify(records=4) - - self.assertEqual(result["status"], "ok") - self.assertEqual( - {check["name"] for check in result["checks"]}, - { - "public_exports", - "typed_markers", - "local_cultmesh_wire_smoke", - "cultmesh_capability_truth", - "benchmark_sanity", - }, - ) - by_name = {check["name"]: check for check in result["checks"]} - self.assertEqual(by_name["public_exports"]["missing"], {}) - self.assertEqual(by_name["cultmesh_capability_truth"]["failures"], []) - - def test_cultnet_security_options_match_cultlib_defaults_and_environment_rules(self) -> None: - client = CultNetClientSecurityOptions.development() - server = CultNetServerSecurityOptions.development() - - self.assertEqual(client.connection_key, "gamecult-dev-connection-key") - self.assertEqual(server.connection_key, "gamecult-dev-connection-key") - self.assertTrue(server.is_development) - self.assertEqual(server.to_client_options().connection_key, client.connection_key) - self.assertEqual(client.encryption_key(), hashlib.sha256(b"gamecult-dev-connection-key").digest()) - self.assertEqual(server.session_signing_key(), hashlib.sha256(b"gamecult-dev-session-signing-secret").digest()) - self.assertEqual( - CultNetServerSecurityOptions.from_environment({}, allow_development_defaults=True), - server, - ) - with self.assertRaisesRegex(ValueError, "not configured"): - CultNetServerSecurityOptions.from_environment({}) - with self.assertRaisesRegex(ValueError, "GAMECULT_SESSION_SIGNING_SECRET"): - CultNetServerSecurityOptions.from_environment({"GAMECULT_CONNECTION_KEY": "key"}) - configured = CultNetServerSecurityOptions.from_environment({ - "GAMECULT_CONNECTION_KEY": "prod-key", - "GAMECULT_SESSION_SIGNING_SECRET": "prod-secret", - }) - self.assertEqual(configured.connection_key, "prod-key") - self.assertFalse(configured.is_development) - - def test_cultnet_secret_helpers_validate_csharp_versioned_session_tokens(self) -> None: - security = CultNetServerSecurityOptions("connection-key", "session-secret") - user_id = uuid4() - expires = datetime(2035, 1, 2, 3, 4, 5, tzinfo=UTC) - - token = CultNetSecret.create_session_token(user_id, expires, security, session_version=7) - payload_b64, signature_b64 = token.split(".") - self.assertEqual( - CultNetSecret.from_base64url(payload_b64).decode("utf-8"), - f"{user_id.hex}|{int(expires.timestamp())}|7", - ) - self.assertEqual( - CultNetSecret.from_base64url(signature_b64), - hmac.new( - hashlib.sha256(b"session-secret").digest(), - CultNetSecret.from_base64url(payload_b64), - hashlib.sha256, - ).digest(), - ) - - validated = CultNetSecret.try_validate_session_token( - token, - security, - now_utc=datetime(2035, 1, 2, 3, 4, 4, tzinfo=UTC), - ) - self.assertIsNotNone(validated) - assert validated is not None - self.assertEqual(validated.user_id, user_id) - self.assertEqual(validated.expires_at_utc, expires) - self.assertEqual(validated.session_version, 7) - - tampered_payload = CultNetSecret.to_base64url(CultNetSecret.from_base64url(payload_b64) + b"tamper") - tampered = f"{tampered_payload}.{signature_b64}" - self.assertIsNone(CultNetSecret.try_validate_session_token(tampered, security)) - self.assertIsNone(CultNetSecret.try_validate_session_token(token, security, now_utc=expires)) - - def test_cultnet_secret_helpers_validate_legacy_two_field_session_tokens(self) -> None: - security = CultNetServerSecurityOptions.development() - user_id = uuid4() - expires_at_seconds = int(datetime(2036, 1, 1, tzinfo=UTC).timestamp()) - payload = f"{user_id.hex}|{expires_at_seconds}".encode("utf-8") - signature = hmac.new(security.session_signing_key(), payload, hashlib.sha256).digest() - token = f"{CultNetSecret.to_base64url(payload)}.{CultNetSecret.to_base64url(signature)}" - - validated = CultNetSecret.try_validate_session_token( - token, - security, - now_utc=datetime(2035, 12, 31, tzinfo=UTC), - ) - - self.assertIsNotNone(validated) - assert validated is not None - self.assertEqual(validated.user_id, user_id) - self.assertEqual(validated.session_version, 0) - - def test_cultnet_secret_encryption_helpers_are_optional_without_crypto_dependency(self) -> None: - nonce = b"123456789012" - security = CultNetServerSecurityOptions.development() - try: - encrypted = CultNetSecret.encrypt_string("hello", nonce, security.to_client_options()) - except ImportError as exc: - self.assertIn("cryptography", str(exc)) - return - self.assertEqual(CultNetSecret.decrypt_string(encrypted, nonce, security), "hello") - - def test_cultnet_schema_message_frame_round_trip(self) -> None: - message = hello( - runtime_id="python-test", - supported_schema_versions=["cultnet.hello.v0"], - transport_profiles=[ - { - "schemaVersion": "cultnet.transport_profile.v0", - "runtimeId": "python-test", - "transports": [ - { - "transportId": "test", - "protocol": "tcp_framed", - "channels": [{"channelId": "schema", "delivery": "reliable", "ordering": "ordered"}], - } - ], - } - ], - ) - parsed = parse_message(decode_frame(encode_frame(message.to_bytes()))) - self.assertEqual(parsed.schema_version, "cultnet.hello.v0") - self.assertEqual(parsed.body["runtimeId"], "python-test") - self.assertEqual(parsed.body["transportProfiles"][0]["transports"][0]["protocol"], "tcp_framed") - - def test_cultnet_tcp_framed_transport_carries_schema_payloads_with_stats(self) -> None: - payload = b"cultnet-payload" - output = io.BytesIO() - sender = TcpFramedTransportConnection( - output, - profile=create_tcp_framed_transport_profile("sender", transport_id="test-tcp"), - ) - sender.send("schema", payload) - self.assertEqual(sender.stats.frames_sent, 1) - self.assertEqual(sender.stats.bytes_sent, len(payload) + 4) - with self.assertRaisesRegex(ValueError, "only supports the schema channel"): - sender.send("unreliable", b"") - - receiver = TcpFramedTransportConnection( - io.BytesIO(output.getvalue()), - profile=create_tcp_framed_transport_profile("receiver", transport_id="test-tcp"), - ) - frame = receiver.receive() - self.assertEqual(frame.channel_id, "schema") - self.assertEqual(frame.payload, payload) - self.assertEqual(receiver.stats.frames_received, 1) - self.assertEqual(receiver.stats.bytes_received, len(payload) + 4) - self.assertEqual(receiver.profile["transports"][0]["protocol"], "tcp_framed") - - def test_cultnet_raw_client_uses_schema_transport_factory(self) -> None: - import msgpack # type: ignore - - sent_messages: list[dict[str, object]] = [] - test_case = self - - class FakeSchemaTransport: - profile = create_tcp_framed_transport_profile("fake-client") - - def __enter__(self) -> "FakeSchemaTransport": - return self - - def __exit__(self, exc_type: object, exc: object, traceback: object) -> None: - self.close() - - def send(self, channel_id: str, payload: bytes) -> None: - test_case.assertEqual(channel_id, "schema") - sent_messages.append(msgpack.unpackb(payload, raw=False)) - - def receive(self) -> object: - response = { - "schemaVersion": "cultnet.schema_catalog_response.v0", - "messageId": "transport-factory", - "schemas": [], - } - return type("Frame", (), {"channel_id": "schema", "payload": msgpack.packb(response, use_bin_type=True)})() - - def close(self) -> None: - pass - - client = CultNetRawClient( - "unused.example.test", - 1, - create_transport=FakeSchemaTransport, - ) - - response = client.fetch_schema_catalog(message_id="transport-factory") - - self.assertEqual(response["schemaVersion"], "cultnet.schema_catalog_response.v0") - self.assertEqual(sent_messages[0]["schemaVersion"], "cultnet.schema_catalog_request.v0") - self.assertEqual(sent_messages[0]["messageId"], "transport-factory") - - def test_cultmesh_client_uses_rudp_schema_transport_endpoint(self) -> None: - import msgpack # type: ignore - - server_socket = bind_udp_socket() - server_host, server_port = server_socket.getsockname()[:2] - connection_id = 0x43554C54 - server = CultNetRudpSocketTransportConnection( - CultNetRudpSocketTransportOptions( - runtime_id="python-rudp-schema-server", - socket=server_socket, - mode=CultNetRudpSocketMode.SERVER, - connection_id=connection_id, - initial_sequence=100, - resend_delay_ms=25, - ) - ) - received_messages: list[dict[str, object]] = [] - - def serve_once() -> None: - deadline = time.monotonic() + 2.0 - try: - while time.monotonic() < deadline: - frame = server.receive_once() - server.poll_resends() - if frame is None: - time.sleep(0.005) - continue - received = msgpack.unpackb(frame.payload, raw=False) - received_messages.append(received) - response = { - "schemaVersion": "cultnet.schema_catalog_response.v0", - "messageId": received["messageId"], - "schemas": [], - } - server.send("schema", msgpack.packb(response, use_bin_type=True)) - return - raise AssertionError("RUDP schema server did not receive a request") - finally: - server.close() - - server_thread = threading.Thread(target=serve_once, daemon=True) - server_thread.start() - client = CultMesh.create_client( - endpoint=f"rudp://{server_host}:{server_port}", - timeout_seconds=2.0, - connection_id=connection_id, - runtime_id="python-rudp-schema-client", - ) - - response = client.fetch_schema_catalog(message_id="rudp-transport-factory") - server_thread.join(timeout=2.0) - - self.assertFalse(server_thread.is_alive()) - self.assertEqual(response["schemaVersion"], "cultnet.schema_catalog_response.v0") - self.assertEqual(response["messageId"], "rudp-transport-factory") - self.assertEqual(received_messages[0]["schemaVersion"], "cultnet.schema_catalog_request.v0") - self.assertEqual(received_messages[0]["messageId"], "rudp-transport-factory") - - def test_cultnet_rudp_packet_codec_uses_deterministic_reliable_ordered_fixture(self) -> None: - encoded = encode_rudp_packet( - CultNetRudpPacket( - packet_type=CultNetRudpPacketType.DATA, - connection_id=0x01020304, - sequence=0x0000002A, - ack=0x00000029, - ack_mask=0x80000001, - channel_id="schema", - reliable=True, - ordered=True, - fragment_id=7, - fragment_index=1, - fragment_count=3, - payload=b"hello", - ) - ) - - self.assertEqual( - encoded.hex(), - "434e523000030b2a010203040000002a0000002980000001000700010003000000050600736368656d6168656c6c6f", - ) - - decoded = decode_rudp_packet(encoded) - self.assertEqual(decoded.packet_type, CultNetRudpPacketType.DATA) - self.assertEqual(decoded.connection_id, 0x01020304) - self.assertEqual(decoded.sequence, 0x0000002A) - self.assertEqual(decoded.ack, 0x00000029) - self.assertEqual(decoded.ack_mask, 0x80000001) - self.assertEqual(decoded.channel_id, "schema") - self.assertTrue(decoded.reliable) - self.assertTrue(decoded.ordered) - self.assertFalse(decoded.sequenced) - self.assertEqual(decoded.fragment_id, 7) - self.assertEqual(decoded.fragment_index, 1) - self.assertEqual(decoded.fragment_count, 3) - self.assertEqual(decoded.payload, b"hello") - - def test_cultnet_rudp_transport_profile_advertises_state_and_realtime_channels(self) -> None: - profile = create_rudp_transport_profile( - "python-rudp", - transport_id="public-rudp", - host="127.0.0.1", - port=7777, - max_payload_bytes=1200, - max_fragment_bytes=1000, - ) - - self.assertEqual(profile["transports"][0]["protocol"], "rudp") - self.assertEqual(profile["transports"][0]["reconnectPolicy"]["schemaVersion"], "cultnet.reconnect_policy.v0") - self.assertEqual(profile["transports"][0]["reconnectPolicy"]["baseDelayMs"], 1_000) - self.assertEqual( - [ - (channel["channelId"], channel["delivery"], channel["ordering"]) - for channel in profile["transports"][0]["channels"] - ], - [ - ("schema", "reliable", "ordered"), - ("latest", "unreliable", "sequenced"), - ("realtime", "unreliable", "unordered"), - ], - ) - - def test_cultnet_reconnect_policy_exposes_portable_delay_contract(self) -> None: - policy = create_reconnect_policy(policy_id="rudp-default", max_attempts=8) - - self.assertEqual(policy.schema_version, "cultnet.reconnect_policy.v0") - self.assertEqual(policy.policy_id, "rudp-default") - self.assertEqual(policy.max_attempts, 8) - self.assertEqual(policy.to_wire()["policyId"], "rudp-default") - self.assertEqual(policy.to_wire()["maxAttempts"], 8) - self.assertEqual(compute_reconnect_delay_ms(policy, 1), 1_000) - self.assertEqual(compute_reconnect_delay_ms(policy, 3, 17), 4_017) - self.assertEqual(compute_reconnect_delay_ms(policy, 9, 999), 30_250) - self.assertEqual(compute_reconnect_delay_ms(policy, 0, -5), 1_000) - - def test_cultnet_reconnect_controller_schedules_attempts_and_reset(self) -> None: - controller = CultNetReconnectController(create_reconnect_policy(max_attempts=2)) - - first = controller.record_failure(10_000) - self.assertEqual(first.attempt, 1) - self.assertTrue(first.should_retry) - self.assertEqual(first.delay_ms, 1_000) - self.assertEqual(first.next_attempt_at_ms, 11_000) - self.assertFalse(first.exhausted) - self.assertFalse(controller.can_attempt(10_999)) - self.assertTrue(controller.can_attempt(11_000)) - - second = controller.record_failure(11_000, 17) - self.assertEqual(second.attempt, 2) - self.assertEqual(second.delay_ms, 2_017) - self.assertEqual(second.next_attempt_at_ms, 13_017) - self.assertTrue(second.should_retry) - - exhausted = controller.record_failure(13_017) - self.assertEqual(exhausted.attempt, 2) - self.assertFalse(exhausted.should_retry) - self.assertEqual(exhausted.delay_ms, 0) - self.assertIsNone(exhausted.next_attempt_at_ms) - self.assertTrue(exhausted.exhausted) - self.assertFalse(controller.can_attempt(99_000)) - - controller.reset() - self.assertEqual(controller.attempt, 0) - self.assertIsNone(controller.next_attempt_at_ms) - self.assertFalse(controller.exhausted) - self.assertTrue(controller.can_attempt(99_000)) - - def test_cultnet_rudp_reconnect_loop_consumes_shared_controller(self) -> None: - class FakeRudpReconnectTransport: - def __init__(self) -> None: - self.connect_calls = 0 - self.close_calls = 0 - self.last_payload: bytes | None = None - - def connect(self, payload: bytes = b"") -> None: - self.connect_calls += 1 - self.last_payload = bytes(payload) - - def close(self) -> None: - self.close_calls += 1 - - now_ms = 10_000 - captured_callback: list[Callable[[], None]] = [] - transports: list[FakeRudpReconnectTransport] = [] - - def create_transport() -> FakeRudpReconnectTransport: - transport = FakeRudpReconnectTransport() - transports.append(transport) - return transport - - def scheduler(delay_ms: int, callback: Callable[[], None]) -> Callable[[], None]: - self.assertEqual(delay_ms, 1_017) - captured_callback[:] = [callback] - - def cancel() -> None: - captured_callback.clear() - - return cancel - - loop = CultNetRudpReconnectLoop( - create_transport, - reconnect_policy=create_reconnect_policy(max_attempts=2), - connect_payload=b"join", - now_ms=lambda: now_ms, - jitter_ms=lambda: 17, - scheduler=scheduler, - ) - - first = loop.start() - self.assertEqual(first.connect_calls, 1) - self.assertEqual(first.last_payload, b"join") - self.assertIs(loop.transport, first) - - decision = loop.handle_closed() - self.assertIsNotNone(decision) - self.assertEqual(decision.attempt, 1) - self.assertTrue(decision.should_retry) - self.assertEqual(decision.delay_ms, 1_017) - self.assertEqual(decision.next_attempt_at_ms, 11_017) - self.assertEqual(loop.reconnect_controller.attempt, 1) - self.assertEqual(loop.reconnect_controller.next_attempt_at_ms, 11_017) - self.assertEqual(len(captured_callback), 1) - - now_ms = 11_017 - captured_callback[0]() - self.assertEqual(len(transports), 2) - self.assertEqual(transports[1].connect_calls, 1) - self.assertIs(loop.transport, transports[1]) - - loop.mark_connected() - self.assertEqual(loop.reconnect_controller.attempt, 0) - - loop.stop() - self.assertEqual(transports[1].close_calls, 1) - self.assertIsNone(loop.transport) - - def test_cultnet_rudp_session_handshake_acks_reliable_connect_and_accept_packets(self) -> None: - client = CultNetRudpSession( - CultNetRudpSessionOptions(connection_id=0x0A0B0C0D, initial_sequence=1, resend_delay_ms=50) - ) - server = CultNetRudpSession( - CultNetRudpSessionOptions(connection_id=0x0A0B0C0D, initial_sequence=100, resend_delay_ms=50) - ) - - connect = client.create_connect(0, b"join") - self.assertEqual(connect.packet_type, CultNetRudpPacketType.CONNECT) - self.assertEqual(connect.sequence, 1) - self.assertEqual(client.pending_reliable_sequences, (1,)) - - accept = server.accept_connect(connect, 10, b"ok") - self.assertEqual(accept.packet_type, CultNetRudpPacketType.ACCEPT) - self.assertEqual(accept.ack, 1) - self.assertTrue(server.connected) - self.assertEqual(server.pending_reliable_sequences, (100,)) - - client.receive(accept, 20) - self.assertTrue(client.connected) - self.assertEqual(client.pending_reliable_sequences, ()) - - ack = client.create_ack() - self.assertEqual(ack.ack, 100) - server.receive(ack, 30) - self.assertEqual(server.pending_reliable_sequences, ()) - - def test_cultnet_rudp_session_computes_ack_masks_and_clears_pending_reliable_packets(self) -> None: - sender = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=7, initial_sequence=10, resend_delay_ms=100)) - receiver = CultNetRudpSession( - CultNetRudpSessionOptions(connection_id=7, initial_sequence=200, resend_delay_ms=100) - ) - sender.receive( - CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 7, 1, 0, 0, "control") - ) - receiver.receive( - CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 7, 2, 0, 0, "control") - ) - - first = sender.send( - "schema", - b"first", - CultNetRudpSendOptions(reliable=True, ordered=True, now_ms=0), - ) - second = sender.send( - "schema", - b"second", - CultNetRudpSendOptions(reliable=True, ordered=True, now_ms=0), - ) - third = sender.send( - "schema", - b"third", - CultNetRudpSendOptions(reliable=True, ordered=True, now_ms=0), - ) - self.assertEqual(sender.pending_reliable_sequences, (10, 11, 12)) - - receiver.receive(first) - receiver.receive(third) - ack_with_gap = receiver.create_ack() - self.assertEqual(ack_with_gap.ack, 12) - self.assertEqual(ack_with_gap.ack_mask, 0b10 | (1 << 9)) - sender.receive(ack_with_gap) - self.assertEqual(sender.pending_reliable_sequences, (11,)) - - receiver.receive(second) - full_ack = receiver.create_ack() - self.assertEqual(full_ack.ack, 12) - self.assertEqual(full_ack.ack_mask, 0b11 | (1 << 9)) - sender.receive(full_ack) - self.assertEqual(sender.pending_reliable_sequences, ()) - - def test_cultnet_rudp_session_schedules_reliable_resends_until_acked(self) -> None: - session = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=99, initial_sequence=1, resend_delay_ms=100)) - session.receive( - CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 99, 50, 0, 0, "control") - ) - sent = session.send( - "schema", - b"payload", - CultNetRudpSendOptions(reliable=True, ordered=True, now_ms=10), - ) - - self.assertEqual(session.due_resends(90), ()) - self.assertEqual(tuple(packet.sequence for packet in session.due_resends(110)), (sent.sequence,)) - self.assertEqual(session.due_resends(150), ()) - - session.receive( - CultNetRudpPacket(CultNetRudpPacketType.ACK, 99, 51, sent.sequence, 0, "control") - ) - self.assertEqual(session.due_resends(250), ()) - - def test_cultnet_rudp_session_pings_and_detects_receive_timeout(self) -> None: - client = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=101, initial_sequence=1)) - server = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=101, initial_sequence=100)) - connect = client.create_connect(0, b"join") - accept = server.accept_connect(connect, 10) - client.receive(accept, 20) - - ping = client.create_ping(b"pulse") - ping_result = server.receive(ping, 30) - self.assertIsNotNone(ping_result.reply) - self.assertEqual(ping_result.reply.packet_type, CultNetRudpPacketType.PONG) - self.assertEqual(ping_result.reply.payload, b"pulse") - - pong_result = client.receive(ping_result.reply, 40) - self.assertTrue(pong_result.pong) - self.assertEqual(pong_result.pong_payload, b"pulse") - self.assertFalse(client.check_timeout(90, 50)) - self.assertTrue(client.check_timeout(91, 50)) - self.assertFalse(client.connected) - - def test_cultnet_rudp_session_bounds_pending_reliable_packets_before_enqueue(self) -> None: - session = CultNetRudpSession( - CultNetRudpSessionOptions(connection_id=102, initial_sequence=1, max_pending_reliable_packets=2) - ) - session.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 102, 50, 0, 0, "control")) - session.send("schema", b"first", CultNetRudpSendOptions(reliable=True, ordered=True)) - session.send("schema", b"second", CultNetRudpSendOptions(reliable=True, ordered=True)) - with self.assertRaisesRegex(ValueError, "reliable send queue is full"): - session.send("schema", b"third", CultNetRudpSendOptions(reliable=True, ordered=True)) - self.assertEqual(session.pending_reliable_sequences, (1, 2)) - - fragmented = CultNetRudpSession( - CultNetRudpSessionOptions(connection_id=103, initial_sequence=1, max_pending_reliable_packets=3) - ) - fragmented.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 103, 50, 0, 0, "control")) - with self.assertRaisesRegex(ValueError, "reliable send queue is full"): - fragmented.send_many( - "schema", - b"fragment-me", - CultNetRudpSendOptions(reliable=True, ordered=True), - max_fragment_bytes=3, - ) - self.assertEqual(fragmented.pending_reliable_sequences, ()) - - def test_cultnet_rudp_session_suppresses_duplicates_and_delivers_reliable_ordered_payloads(self) -> None: - sender = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=123, initial_sequence=1)) - receiver = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=123, initial_sequence=100)) - sender.receive( - CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 123, 90, 0, 0, "control") - ) - receiver.receive( - CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 123, 91, 0, 0, "control") - ) - - first = sender.send("schema", b"first", CultNetRudpSendOptions(reliable=True, ordered=True)) - second = sender.send("schema", b"second", CultNetRudpSendOptions(reliable=True, ordered=True)) - third = sender.send("schema", b"third", CultNetRudpSendOptions(reliable=True, ordered=True)) - - self.assertEqual([frame.payload.decode("utf-8") for frame in receiver.receive(first).delivered], ["first"]) - self.assertEqual(receiver.receive(third).delivered, ()) - self.assertEqual(receiver.receive(first).delivered, ()) - self.assertEqual( - [frame.payload.decode("utf-8") for frame in receiver.receive(second).delivered], - ["second", "third"], - ) - - def test_cultnet_rudp_lossy_packets_cannot_create_reliable_ordered_gaps(self) -> None: - sender = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=198, initial_sequence=1)) - receiver = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=198, initial_sequence=100)) - sender.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 198, 90, 0, 0, "control")) - receiver.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 198, 91, 0, 0, "control")) - - realtime = sender.send("realtime", b"discarded realtime", CultNetRudpSendOptions()) - latest = sender.send("latest", b"discarded latest state", CultNetRudpSendOptions(sequenced=True)) - schema = sender.send("schema", b"committed response", CultNetRudpSendOptions(reliable=True, ordered=True)) - - self.assertEqual(realtime.sequence, 0) - self.assertEqual(latest.sequence, 1) - self.assertEqual( - [frame.payload.decode("utf-8") for frame in receiver.receive(schema).delivered], - ["committed response"], - ) - - def test_cultnet_rudp_unreliable_sequenced_delivery_is_scoped_to_its_channel(self) -> None: - sender = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=197, initial_sequence=50)) - receiver = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=197, initial_sequence=100)) - sender.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 197, 90, 0, 0, "control")) - receiver.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 197, 91, 0, 0, "control")) - - older = sender.send("latest", b"older", CultNetRudpSendOptions(sequenced=True)) - newer = sender.send("latest", b"newer", CultNetRudpSendOptions(sequenced=True)) - - self.assertEqual(older.sequence, 1) - self.assertEqual(newer.sequence, 2) - self.assertEqual( - [frame.payload.decode("utf-8") for frame in receiver.receive(newer).delivered], - ["newer"], - ) - self.assertEqual(receiver.receive(older).delivered, ()) - - def test_cultnet_rudp_rejects_unreliable_ordered_delivery(self) -> None: - session = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=196, initial_sequence=1)) - session.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 196, 50, 0, 0, "control")) - - with self.assertRaises(ValueError) as raised: - session.send( - "schema", - b"cannot order what will not retransmit", - CultNetRudpSendOptions(ordered=True), - ) - self.assertIn("ordered delivery requires reliability", str(raised.exception)) - - def test_cultnet_rudp_session_skips_control_packets_while_ordering_schema_payloads(self) -> None: - sender = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=124, initial_sequence=1)) - receiver = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=124, initial_sequence=100)) - sender.receive( - CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 124, 90, 0, 0, "control") - ) - receiver.receive( - CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 124, 91, 0, 0, "control") - ) - - first = sender.send("schema", b"first", CultNetRudpSendOptions(reliable=True, ordered=True)) - control = sender.create_ack() - second = sender.send("schema", b"second", CultNetRudpSendOptions(reliable=True, ordered=True)) - - self.assertEqual([frame.payload.decode("utf-8") for frame in receiver.receive(first).delivered], ["first"]) - self.assertEqual(receiver.receive(control).delivered, ()) - self.assertEqual([frame.payload.decode("utf-8") for frame in receiver.receive(second).delivered], ["second"]) - - def test_cultnet_rudp_session_fragments_and_reassembles_reliable_ordered_payloads(self) -> None: - sender = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=456, initial_sequence=1)) - receiver = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=456, initial_sequence=100)) - sender.receive( - CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 456, 90, 0, 0, "control") - ) - receiver.receive( - CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 456, 91, 0, 0, "control") - ) - - packets = sender.send_many( - "schema", - b"fragment-me-please", - CultNetRudpSendOptions(reliable=True, ordered=True, now_ms=10), - max_fragment_bytes=5, - ) - self.assertEqual(len(packets), 4) - self.assertEqual(tuple(packet.fragment_count for packet in packets), (4, 4, 4, 4)) - self.assertEqual(tuple(packet.fragment_index for packet in packets), (0, 1, 2, 3)) - self.assertTrue(all(packet.fragment_id == packets[0].fragment_id for packet in packets)) - - self.assertEqual(receiver.receive(packets[0]).delivered, ()) - self.assertEqual(receiver.receive(packets[1]).delivered, ()) - self.assertEqual(receiver.receive(packets[2]).delivered, ()) - delivered = receiver.receive(packets[3]).delivered - self.assertEqual(len(delivered), 1) - self.assertEqual(delivered[0].payload, b"fragment-me-please") - self.assertEqual(delivered[0].sequence, packets[0].sequence) - - def test_cultnet_rudp_session_advances_large_fragment_sets_through_bounded_window(self) -> None: - connection_id = 457 - sender = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=connection_id, initial_sequence=1)) - receiver = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=connection_id, initial_sequence=100)) - sender.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, connection_id, 0, 0, 0, "control")) - receiver.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, connection_id, 0, 0, 0, "control")) - - fragment_count = CultNetRudpSession.RELIABLE_SEND_WINDOW_PACKETS + 17 - payload = bytes(index % 251 for index in range(fragment_count * 8)) - wire = list(sender.send_many( - "schema", - payload, - CultNetRudpSendOptions(reliable=True, ordered=True, now_ms=1), - max_fragment_bytes=8, - )) - self.assertEqual(len(wire), CultNetRudpSession.RELIABLE_SEND_WINDOW_PACKETS) - oldest_sequence = wire[0].sequence - self.assertEqual(len(sender.pending_reliable_sequences), len(wire)) - self.assertEqual(sender.queued_reliable_packet_count, 17) - - delivered = [] - while wire: - admitted = len(wire) - for _ in range(admitted): - packet = wire.pop(0) - delivered.extend(receiver.receive(packet, 2).delivered) - acknowledged = sender.receive(receiver.create_ack(), 3) - wire.extend(acknowledged.ready_to_send) - - self.assertEqual(sender.outstanding_reliable_packet_count, 0) - self.assertEqual(len(delivered), 1) - self.assertEqual(delivered[0].payload, payload) - old_ack = receiver.create_ack_for_received(oldest_sequence) - self.assertEqual(old_ack.ack, oldest_sequence) - self.assertEqual(old_ack.ack_mask, 0) - - def test_cultnet_rudp_socket_transport_handshakes_and_carries_reliable_ordered_schema_frames(self) -> None: - server_socket = bind_udp_socket() - client_socket = bind_udp_socket() - connection_id = 0x10203040 - server = CultNetRudpSocketTransportConnection( - CultNetRudpSocketTransportOptions( - runtime_id="python-rudp-server", - socket=server_socket, - mode=CultNetRudpSocketMode.SERVER, - connection_id=connection_id, - initial_sequence=100, - resend_delay_ms=25, - ) - ) - client = CultNetRudpSocketTransportConnection( - CultNetRudpSocketTransportOptions( - runtime_id="python-rudp-client", - socket=client_socket, - mode=CultNetRudpSocketMode.CLIENT, - remote_addr=server_socket.getsockname(), - connection_id=connection_id, - initial_sequence=1, - resend_delay_ms=25, - ) - ) - - try: - client.connect(b"join") - pump_rudp_handshake(client, server) - self.assertTrue(client.connected) - self.assertTrue(server.connected) - - client.send("schema", b"client-state") - server_frame = receive_rudp_frame(server) - self.assertEqual(server_frame.channel_id, "schema") - self.assertEqual(server_frame.payload, b"client-state") - - server.send("schema", b"server-state") - client_frame = receive_rudp_frame(client) - self.assertEqual(client_frame.channel_id, "schema") - self.assertEqual(client_frame.payload, b"server-state") - self.assertEqual(server.profile["transports"][0]["protocol"], "rudp") - self.assertEqual(client.stats.frames_sent, 1) - self.assertEqual(server.stats.frames_received, 1) - finally: - client.close() - server.close() - - def test_cultnet_rudp_socket_transport_carries_fragmented_reliable_ordered_schema_frames(self) -> None: - server_socket = bind_udp_socket() - client_socket = bind_udp_socket() - connection_id = 0x10203041 - server = CultNetRudpSocketTransportConnection( - CultNetRudpSocketTransportOptions( - runtime_id="python-rudp-fragment-server", - socket=server_socket, - mode=CultNetRudpSocketMode.SERVER, - connection_id=connection_id, - initial_sequence=100, - resend_delay_ms=25, - max_fragment_bytes=8, - ) - ) - client = CultNetRudpSocketTransportConnection( - CultNetRudpSocketTransportOptions( - runtime_id="python-rudp-fragment-client", - socket=client_socket, - mode=CultNetRudpSocketMode.CLIENT, - remote_addr=server_socket.getsockname(), - connection_id=connection_id, - initial_sequence=1, - resend_delay_ms=25, - max_fragment_bytes=8, - ) - ) - - try: - payload = b"this-schema-frame-is-larger-than-one-rudp-fragment" - client.connect(b"join") - pump_rudp_handshake(client, server) - client.send("schema", payload) - server_frame = receive_rudp_frame(server) - self.assertEqual(server_frame.channel_id, "schema") - self.assertEqual(server_frame.payload, payload) - self.assertEqual(client.stats.frames_sent, 1) - self.assertEqual(server.stats.frames_received, 1) - finally: - client.close() - server.close() - - def test_cultmesh_facade_creates_rudp_client_from_peer_endpoint(self) -> None: - connection_id = 0x10203042 - server = CultMesh.create_rudp_server( - "python-cultmesh-rudp-server", - connection_id, - initial_sequence=100, - resend_delay_ms=25, - max_fragment_bytes=1024, - max_pending_reliable_packets=16, - ) - server_host, server_port = server.socket.getsockname()[:2] - endpoint = CultMesh.parse_rudp_endpoint(f"rudp://{server_host}:{server_port}") - self.assertEqual(endpoint.host, server_host) - self.assertEqual(endpoint.port, server_port) - peer = CultMeshPeerCard( - peer_id="python-cultmesh-rudp-server", - verse_id="local", - endpoints=(endpoint.uri,), - roles=("schema",), - authority_lease_id="lease:python-cultmesh-rudp-server", - ) - peers = CultMesh.create_peer_catalog() - leases = CultMesh.create_authority_lease_catalog() - peers.upsert(peer) - with self.assertRaisesRegex(ValueError, "No authorized RUDP peer"): - CultMesh.create_rudp_client_for_authorized_peer( - "python-cultmesh-rudp-client", - connection_id, - peers, - leases, - "local", - "schema", - resend_delay_ms=25, - max_fragment_bytes=1024, - max_pending_reliable_packets=16, - ) - leases.upsert( - CultMeshAuthorityLease( - lease_id="lease:python-cultmesh-rudp-server", - verse_id="local", - peer_id="python-cultmesh-rudp-server", - roles=("schema",), - valid_from=datetime.now(UTC) - timedelta(seconds=1), - expires_at=datetime.now(UTC) + timedelta(seconds=30), - issuer_runtime_id="python-authority", - ) - ) - client = CultMesh.create_rudp_client_for_authorized_peer( - "python-cultmesh-rudp-client", - connection_id, - peers, - leases, - "local", - "schema", - resend_delay_ms=25, - max_fragment_bytes=1024, - max_pending_reliable_packets=16, - ) - - try: - client.connect(b"join") - pump_rudp_handshake(client, server) - self.assertTrue(client.connected) - self.assertTrue(server.connected) - - client.send("schema", b"client-state") - server_frame = receive_rudp_frame(server) - self.assertEqual(server_frame.channel_id, "schema") - self.assertEqual(server_frame.payload, b"client-state") - self.assertEqual(server.profile["transports"][0]["protocol"], "rudp") - self.assertEqual(client.profile["transports"][0]["protocol"], "rudp") - finally: - client.close() - server.close() - - def test_cultnet_database_subscription_helpers_match_schema_v0_shape(self) -> None: - subscribe = database_subscribe( - message_id="sub-message", - subscription_id="sub-1", - schema_ids=["schema-a"], - record_keys=["record-a"], - include_snapshot=False, - ).to_wire() - self.assertEqual(subscribe["schemaVersion"], "cultnet.database_subscribe.v0") - self.assertEqual(subscribe["messageId"], "sub-message") - self.assertEqual(subscribe["subscriptionId"], "sub-1") - self.assertEqual(subscribe["schemaIds"], ["schema-a"]) - self.assertEqual(subscribe["recordKeys"], ["record-a"]) - self.assertFalse(subscribe["includeSnapshot"]) - - unsubscribe = database_unsubscribe(message_id="unsub-message", subscription_id="sub-1").to_wire() - self.assertEqual(unsubscribe["schemaVersion"], "cultnet.database_unsubscribe.v0") - self.assertEqual(unsubscribe["messageId"], "unsub-message") - self.assertEqual(unsubscribe["subscriptionId"], "sub-1") - - def test_cultnet_database_change_parses_put_and_delete_shapes(self) -> None: - put_change = CultNetDatabaseChange.from_wire({ - "schemaVersion": "cultnet.database_change_raw.v0", - "messageId": "change-put", - "subscriptionId": "sub-1", - "changeKind": "added", - "document": { - "schemaId": "schema-note", - "recordKey": "note:1", - "payload": b"payload", - }, - }) - self.assertEqual(put_change.schema_id, "schema-note") - self.assertEqual(put_change.record_key, "note:1") - self.assertIsInstance(put_change.raw_document, CultNetRawDocumentRecord) - self.assertEqual(put_change.raw_document.payload, b"payload") - self.assertEqual(put_change.to_wire()["document"]["recordKey"], "note:1") - - delete_change = CultNetDatabaseChange.from_wire({ - "schemaVersion": "cultnet.database_change_raw.v0", - "messageId": "change-delete", - "subscriptionId": "sub-1", - "changeKind": "removed", - "schemaId": "schema-note", - "recordKey": "note:1", - }) - self.assertIsNone(delete_change.document) - self.assertIsNone(delete_change.raw_document) - self.assertEqual(delete_change.schema_id, "schema-note") - self.assertEqual(delete_change.to_wire()["recordKey"], "note:1") - - def test_cultnet_raw_put_helper_carries_message_id(self) -> None: - put = document_put_raw( - message_id="put-1", - key="record-a", - schema_id="schema-a", - stored_at="2026-06-13T00:00:00Z", - payload=b"payload", - source_runtime_id="python-test", - shard_id="interop", - shard_epoch=1, - ).to_wire() - self.assertEqual(put["schemaVersion"], "cultnet.document_put_raw.v0") - self.assertEqual(put["messageId"], "put-1") - self.assertEqual(put["document"]["recordKey"], "record-a") - self.assertEqual(put["document"]["sourceRuntimeId"], "python-test") - self.assertEqual(put["shardId"], "interop") - self.assertEqual(put["shardEpoch"], 1) - - def test_cultnet_catalog_and_snapshot_helpers_accept_filters(self) -> None: - catalog = schema_catalog_request( - message_id="catalog-1", - include_schema_json=True, - schema_ids=["schema-a"], - kinds=["wire_message"], - ).to_wire() - self.assertEqual(catalog["schemaVersion"], "cultnet.schema_catalog_request.v0") - self.assertEqual(catalog["messageId"], "catalog-1") - self.assertTrue(catalog["includeSchemaJson"]) - self.assertEqual(catalog["schemaIds"], ["schema-a"]) - self.assertEqual(catalog["kinds"], ["wire_message"]) - - snapshot = snapshot_request( - message_id="snapshot-1", - schema_ids=["schema-a"], - record_keys=["record-a"], - shard_id="interop", - shard_epoch=1, - ).to_wire() - self.assertEqual(snapshot["schemaVersion"], "cultnet.snapshot_request.v0") - self.assertEqual(snapshot["messageId"], "snapshot-1") - self.assertEqual(snapshot["schemaIds"], ["schema-a"]) - self.assertEqual(snapshot["recordKeys"], ["record-a"]) - self.assertEqual(snapshot["shardId"], "interop") - self.assertEqual(snapshot["shardEpoch"], 1) - - def test_cultnet_raw_snapshot_response_filters_and_roundtrips_records(self) -> None: - response = CultNetRawSnapshotResponse.from_wire({ - "schemaVersion": "cultnet.snapshot_response_raw.v0", - "messageId": "snapshot-1", - "shardId": "notes", - "shardEpoch": 3, - "shardLogSequence": 8, - "documents": [ - CultNetRawDocumentRecord( - schema_id="schema-note", - record_key="note:1", - stored_at="2026-06-14T00:00:00Z", - payload=b"note", - source_runtime_id="python-test", - tags=("snapshot",), - ).to_wire(), - { - "schemaId": "schema-fact", - "recordKey": "fact:1", - "payloadEncoding": "messagepack", - "payload": b"fact", - }, - ], - }) - self.assertEqual(response.shard_id, "notes") - self.assertEqual(response.shard_epoch, 3) - self.assertEqual(response.shard_log_sequence, 8) - self.assertEqual(response.documents[0].source_runtime_id, "python-test") - self.assertEqual(response.filter(schema_ids=["schema-note"])[0].record_key, "note:1") - self.assertEqual(response.filter(record_keys=["fact:1"])[0].schema_id, "schema-fact") - self.assertEqual(response.to_wire()["documents"][0]["tags"], ["snapshot"]) - - def test_cultnet_raw_client_fetches_schema_snapshot_and_shard_reads(self) -> None: - import msgpack # type: ignore - from cultnet_py import read_frame, write_frame - - received_versions: list[str] = [] - ready = threading.Event() - server_error: list[BaseException] = [] - port_holder: list[int] = [] - - def serve_requests() -> None: - try: - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server: - server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - server.bind(("127.0.0.1", 0)) - port_holder.append(server.getsockname()[1]) - server.listen(4) - ready.set() - for _ in range(4): - connection, _ = server.accept() - with connection: - stream = connection.makefile("rwb") - request = msgpack.unpackb(read_frame(stream), raw=False) - received_versions.append(request["schemaVersion"]) - if request["schemaVersion"] == "cultnet.schema_catalog_request.v0": - self.assertEqual(request["kinds"], ["wire_message"]) - response = {"schemaVersion": "cultnet.schema_catalog_response.v0", "messageId": request["messageId"], "schemas": []} - elif request["schemaVersion"] == "cultnet.snapshot_request.v0": - self.assertEqual(request["shardId"], "interop") - response = {"schemaVersion": "cultnet.snapshot_response_raw.v0", "messageId": request["messageId"], "documents": []} - elif request["schemaVersion"] == "cultnet.shard_catalog_request.v0": - response = { - "schemaVersion": "cultnet.shard_catalog_response.v0", - "messageId": request["messageId"], - "shards": [{ - "shardId": "interop", - "ownerRuntimeId": "socket-test", - "epoch": 1, - "schemaIds": request["schemaIds"], - "keyPrefix": "record-", - "primaryEndpoints": ["cultnet://127.0.0.1:1"], - }], - } - elif request["schemaVersion"] == "cultnet.shard_log_request.v0": - self.assertEqual(request["afterSequence"], 7) - response = { - "schemaVersion": "cultnet.shard_log_response.v0", - "messageId": request["messageId"], - "shardId": request["shardId"], - "shardEpoch": request["shardEpoch"], - "entries": [], - "resyncRequired": False, - } - else: - raise AssertionError(f"unexpected request {request['schemaVersion']}") - write_frame(stream, msgpack.packb(response, use_bin_type=True)) - stream.flush() - except BaseException as error: - server_error.append(error) - ready.set() - - thread = threading.Thread(target=serve_requests, daemon=True) - thread.start() - self.assertTrue(ready.wait(2.0)) - self.assertFalse(server_error) - - client = CultNetRawClient("127.0.0.1", port_holder[0], timeout_seconds=2.0) - self.assertEqual(client.fetch_schema_catalog(kinds=["wire_message"])["schemaVersion"], "cultnet.schema_catalog_response.v0") - typed_snapshot = client.fetch_snapshot_response(shard_id="interop", shard_epoch=1) - self.assertEqual(typed_snapshot.shard_id, None) - self.assertEqual(typed_snapshot.documents, ()) - shard_catalog = CultNetShardCatalog() - synced_shards = client.sync_shard_catalog(shard_catalog, schema_ids=["schema-a"]) - self.assertEqual(synced_shards[0].shard_id, "interop") - self.assertEqual(shard_catalog.get("interop"), synced_shards[0]) - shard_log = client.fetch_shard_log_response(shard_id="interop", shard_epoch=1, after_sequence=7) - self.assertEqual(shard_log.shard_id, "interop") - self.assertFalse(shard_log.resync_required) - self.assertEqual(shard_log.last_sequence, 0) - - thread.join(2.0) - self.assertFalse(server_error) - self.assertEqual(received_versions, [ - "cultnet.schema_catalog_request.v0", - "cultnet.snapshot_request.v0", - "cultnet.shard_catalog_request.v0", - "cultnet.shard_log_request.v0", - ]) - - def test_cultnet_raw_client_raises_typed_peer_error_response(self) -> None: - import msgpack # type: ignore - from cultnet_py import read_frame, write_frame - - ready = threading.Event() - port_holder: list[int] = [] - - def serve_error() -> None: - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server: - server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - server.bind(("127.0.0.1", 0)) - port_holder.append(server.getsockname()[1]) - server.listen(1) - ready.set() - connection, _ = server.accept() - with connection: - stream = connection.makefile("rwb") - read_frame(stream) - write_frame(stream, msgpack.packb({ - "schemaVersion": "cultnet.error.v0", - "messageId": "error-1", - "error": "Snapshot document limit exceeded", - }, use_bin_type=True)) - stream.flush() - - thread = threading.Thread(target=serve_error, daemon=True) - thread.start() - self.assertTrue(ready.wait(2.0)) - - client = CultNetRawClient("127.0.0.1", port_holder[0], timeout_seconds=2.0) - with self.assertRaisesRegex(CultNetPeerError, "Snapshot document limit exceeded") as raised: - client.fetch_snapshot() - - self.assertEqual(raised.exception.peer_error, "Snapshot document limit exceeded") - self.assertEqual(raised.exception.response["schemaVersion"], "cultnet.error.v0") - thread.join(2.0) - - def test_cultnet_database_subscription_reads_snapshot_and_change(self) -> None: - import msgpack # type: ignore - from cultnet_py import read_frame, write_frame - - document = define_database_entry_type( - "sub.item", - [ - ("name", 0), - ("category", 1), - ("value", 2, 0), - ], - cls=Item, - ) - schema_id = document.catalog_entry().schema_id - ready = threading.Event() - server_error: list[BaseException] = [] - port_holder: list[int] = [] - received_versions: list[str] = [] - - def serve_subscription() -> None: - try: - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server: - server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - server.bind(("127.0.0.1", 0)) - port_holder.append(server.getsockname()[1]) - server.listen(1) - ready.set() - connection, _ = server.accept() - with connection: - stream = connection.makefile("rwb") - subscribe = msgpack.unpackb(read_frame(stream), raw=False) - received_versions.append(subscribe["schemaVersion"]) - self.assertEqual(subscribe["subscriptionId"], "sub-1") - snapshot = { - "schemaVersion": "cultnet.snapshot_response_raw.v0", - "messageId": subscribe["messageId"], - "documents": [], - } - write_frame(stream, msgpack.packb(snapshot, use_bin_type=True)) - stream.flush() - - put = msgpack.unpackb(read_frame(stream), raw=False) - received_versions.append(put["schemaVersion"]) - change = { - "schemaVersion": "cultnet.database_change_raw.v0", - "messageId": "change-1", - "subscriptionId": "sub-1", - "changeKind": "added", - "document": put["document"], - } - write_frame(stream, msgpack.packb(change, use_bin_type=True)) - stream.flush() - - unsubscribe = msgpack.unpackb(read_frame(stream), raw=False) - received_versions.append(unsubscribe["schemaVersion"]) - except BaseException as error: - server_error.append(error) - ready.set() - - thread = threading.Thread(target=serve_subscription, daemon=True) - thread.start() - self.assertTrue(ready.wait(2.0)) - self.assertFalse(server_error) - - client = CultNetRawClient("127.0.0.1", port_holder[0], timeout_seconds=2.0) - put = document_put_raw( - message_id="put-sub", - key="item:sub", - schema_id=schema_id, - stored_at="2026-06-14T00:00:00Z", - payload=document.encode_payload(Item("orb", "gear", 8)), - ) - with client.subscribe_database(subscription_id="sub-1", schema_ids=[schema_id]) as subscription: - snapshot = subscription.read_next_snapshot_response() - subscription.send(put) - change = subscription.read_next_change() - - thread.join(2.0) - self.assertFalse(server_error) - self.assertIsInstance(snapshot, CultNetRawSnapshotResponse) - self.assertEqual(snapshot.message_id, "cultnet-python-subscribe") - self.assertEqual(snapshot.to_wire()["schemaVersion"], "cultnet.snapshot_response_raw.v0") - self.assertEqual(change.change_kind, "added") - self.assertEqual(change.record_key, "item:sub") - self.assertIsInstance(change.raw_document, CultNetRawDocumentRecord) - self.assertEqual(change.raw_document.record_key, "item:sub") - self.assertEqual(received_versions, [ - "cultnet.database_subscribe.v0", - "cultnet.document_put_raw.v0", - "cultnet.database_unsubscribe.v0", - ]) - - def test_cultnet_database_subscription_raises_typed_peer_error(self) -> None: - import msgpack # type: ignore - from cultnet_py import read_frame, write_frame - - ready = threading.Event() - port_holder: list[int] = [] - - def serve_subscription_error() -> None: - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server: - server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - server.bind(("127.0.0.1", 0)) - port_holder.append(server.getsockname()[1]) - server.listen(1) - ready.set() - connection, _ = server.accept() - with connection: - stream = connection.makefile("rwb") - read_frame(stream) - write_frame(stream, msgpack.packb({ - "schemaVersion": "cultnet.error.v0", - "messageId": "subscription-error", - "error": "subscription rejected", - }, use_bin_type=True)) - stream.flush() - - thread = threading.Thread(target=serve_subscription_error, daemon=True) - thread.start() - self.assertTrue(ready.wait(2.0)) - - client = CultNetRawClient("127.0.0.1", port_holder[0], timeout_seconds=2.0) - with client.subscribe_database(subscription_id="sub-error") as subscription: - with self.assertRaisesRegex(CultNetPeerError, "subscription rejected") as raised: - subscription.read_next() - self.assertEqual(raised.exception.response["messageId"], "subscription-error") - thread.join(2.0) - - def test_cultnet_replication_helpers_apply_raw_snapshot_and_shard_log(self) -> None: - document = define_database_entry_type( - "replica.item", - [ - ("name", 0), - ("category", 1), - ("value", 2, 0), - ], - cls=Item, - ) - cache = CultCache() - cache.register_document_type(document) - schema_id = document.catalog_entry().schema_id - - snapshot = { - "schemaVersion": "cultnet.snapshot_response_raw.v0", - "messageId": "snapshot-1", - "documents": [ - { - "schemaId": schema_id, - "recordKey": "item:1", - "storedAt": "2026-06-13T00:00:00Z", - "payloadEncoding": "messagepack", - "payload": document.encode_payload(Item("sword", "gear", 3)), - } - ], - } - applied_snapshot = apply_raw_snapshot(cache, [document], snapshot) - self.assertEqual(applied_snapshot[0].record_key, "item:1") - self.assertEqual(cache.get_required(document, "item:1").value, 3) - typed_snapshot = CultNetRawSnapshotResponse.from_wire(snapshot) - direct_applied = apply_raw_document_record(cache, schema_document_map([document]), typed_snapshot.documents[0]) - self.assertEqual(direct_applied.schema_id, schema_id) - self.assertEqual(direct_applied.record_key, "item:1") - typed_snapshot_applied = apply_raw_snapshot(cache, [document], typed_snapshot) - self.assertEqual(typed_snapshot_applied[0].record_key, "item:1") - - shard_log = { - "schemaVersion": "cultnet.shard_log_response.v0", - "messageId": "log-1", - "shardId": "interop", - "shardEpoch": 1, - "resyncRequired": False, - "entries": [ - { - "sequence": 0, - "changeKind": "updated", - "put": { - "schemaVersion": "cultnet.document_put_raw.v0", - "messageId": "put-unknown", - "document": { - "schemaId": "replica.unknown.v1", - "recordKey": "unknown:1", - "storedAt": "2026-06-13T00:00:01Z", - "payloadEncoding": "messagepack", - "payload": document.encode_payload(Item("ignored", "unknown", 0)), - }, - "shardId": "interop", - "shardEpoch": 1, - }, - }, - { - "sequence": 1, - "changeKind": "updated", - "put": { - "schemaVersion": "cultnet.document_put_raw.v0", - "messageId": "put-1", - "document": { - "schemaId": schema_id, - "recordKey": "item:1", - "storedAt": "2026-06-13T00:00:01Z", - "payloadEncoding": "messagepack", - "payload": document.encode_payload(Item("sword", "gear", 12)), - }, - "shardId": "interop", - "shardEpoch": 1, - }, - }, - { - "sequence": 2, - "changeKind": "removed", - "delete": { - "schemaVersion": "cultnet.document_delete.v0", - "messageId": "delete-1", - "schemaId": schema_id, - "recordKey": "item:1", - "shardId": "interop", - "shardEpoch": 1, - }, - }, - ], - } - applied_log = apply_shard_log_response(cache, [document], shard_log) - self.assertEqual([change.change_kind for change in applied_log], ["updated", "removed"]) - self.assertIsNone(cache.get(document, "item:1")) - - cache.put(document, "item:1", Item("sword", "gear", 3)) - typed_shard_log = CultNetShardLogResponse.from_wire({ - **shard_log, - "entries": shard_log["entries"][1:], - }) - typed_applied_log = apply_shard_log_response(cache, [document], typed_shard_log) - self.assertEqual([change.change_kind for change in typed_applied_log], ["updated", "removed"]) - self.assertIsNone(cache.get(document, "item:1")) - - def test_cultnet_replication_helpers_recover_schema_stamped_raw_records(self) -> None: - document = define_database_entry_type( - "replica.runtime-policy", - [ - ("schema_version", 0), - ("name", 1), - ("value", 2), - ], - schema_id="replica.runtime-policy.current", - schema_name="replica.runtime_policy", - schema_version="replica.runtime_policy.v1", - ) - cache = CultCache() - cache.register_document_type(document) - stale_schema_id = "sha256:stale-replica-runtime-policy" - payload = document.encode_payload({ - "schema_version": "replica.runtime_policy.v1", - "name": "policy", - "value": "still synced", - }) - record = { - "schemaId": stale_schema_id, - "recordKey": "policy:1", - "storedAt": "2026-06-25T00:00:00Z", - "payloadEncoding": "messagepack", - "payload": payload, - } - snapshot = { - "schemaVersion": "cultnet.snapshot_response_raw.v0", - "messageId": "snapshot-stale", - "documents": [record], - } - - applied_snapshot = apply_raw_snapshot(cache, [document], snapshot) - local_schema_id = document.catalog_entry().schema_id - self.assertEqual(applied_snapshot[0].schema_id, local_schema_id) - self.assertEqual(cache.get_required(document, "policy:1")["value"], "still synced") - self.assertEqual(cache.get_required_envelope(document, "policy:1").schema_id, local_schema_id) - direct_applied = apply_raw_document_record(cache, schema_document_map([document]), record) - self.assertEqual(direct_applied.schema_id, local_schema_id) - self.assertEqual(cache.get_required_envelope(document, "policy:1").schema_id, local_schema_id) - - shard_log = { - "schemaVersion": "cultnet.shard_log_response.v0", - "messageId": "log-stale", - "shardId": "interop", - "shardEpoch": 1, - "resyncRequired": False, - "entries": [ - { - "sequence": 0, - "changeKind": "updated", - "put": { - "schemaVersion": "cultnet.document_put_raw.v0", - "messageId": "put-stale", - "document": { - **record, - "payload": document.encode_payload({ - "schema_version": "replica.runtime_policy.v1", - "name": "policy", - "value": "updated through log", - }), - }, - "shardId": "interop", - "shardEpoch": 1, - }, - } - ], - } - - applied_log = apply_shard_log_response(cache, [document], shard_log) - self.assertEqual(applied_log[0].schema_id, local_schema_id) - self.assertEqual(cache.get_required(document, "policy:1")["value"], "updated through log") - self.assertEqual(cache.get_required_envelope(document, "policy:1").schema_id, local_schema_id) - - delete_log = { - "schemaVersion": "cultnet.shard_log_response.v0", - "messageId": "log-delete-alias", - "shardId": "interop", - "shardEpoch": 1, - "resyncRequired": False, - "entries": [ - { - "sequence": 1, - "changeKind": "removed", - "delete": { - "schemaVersion": "cultnet.document_delete.v0", - "messageId": "delete-version-alias", - "schemaId": "replica.runtime_policy.v1", - "recordKey": "policy:1", - "shardId": "interop", - "shardEpoch": 1, - }, - } - ], - } - applied_delete = apply_shard_log_response(cache, [document], delete_log) - self.assertEqual(applied_delete[0].schema_id, local_schema_id) - self.assertEqual(applied_delete[0].change_kind, "removed") - self.assertIsNone(cache.get(document, "policy:1")) - - def test_cultmesh_node_applies_foreign_schema_snapshot_as_local_update(self) -> None: - document = define_database_entry_type( - "mesh.runtime-policy", - [ - ("schema_version", 0), - ("name", 1), - ("value", 2), - ], - schema_id="mesh.runtime-policy.current", - schema_name="mesh.runtime_policy", - schema_version="mesh.runtime_policy.v1", - ) - node = create_node(runtime_id="python-node") - node.register_document(document) - node.put(document, "policy:1", { - "schema_version": "mesh.runtime_policy.v1", - "name": "policy", - "value": "old", - }) - observed: list[CultMeshDatabaseChange] = [] - unsubscribe = node.database.watch_record(document, "policy:1", observed.append) - try: - applied = node.database.apply_snapshot_response({ - "schemaVersion": "cultnet.snapshot_response_raw.v0", - "messageId": "foreign-schema-snapshot", - "documents": [ - { - "schemaId": "sha256:foreign-mesh-runtime-policy", - "recordKey": "policy:1", - "storedAt": "2026-06-25T00:00:00Z", - "payloadEncoding": "messagepack", - "payload": document.encode_payload({ - "schema_version": "mesh.runtime_policy.v1", - "name": "policy", - "value": "new", - }), - }, - ], - }) - finally: - unsubscribe() - - local_schema_id = document.catalog_entry().schema_id - self.assertEqual(applied[0].schema_id, local_schema_id) - self.assertEqual(observed[0].schema_id, local_schema_id) - self.assertEqual(observed[0].change_kind, "updated") - self.assertEqual(observed[0].previous_value["value"], "old") - self.assertEqual(observed[0].value["value"], "new") - self.assertEqual(node.cache.get_required_envelope(document, "policy:1").schema_id, local_schema_id) - - def test_cultmesh_node_syncs_snapshot_and_shard_log_through_cultnet_client(self) -> None: - import msgpack # type: ignore - from cultnet_py import read_frame, write_frame - - document = define_database_entry_type( - "mesh.sync_item", - [ - ("name", 0), - ("category", 1), - ("value", 2, 0), - ], - cls=Item, - ) - node = create_node(runtime_id="python-node") - node.register_document(document) - schema_id = document.catalog_entry().schema_id - ready = threading.Event() - server_error: list[BaseException] = [] - port_holder: list[int] = [] - - def serve_requests() -> None: - try: - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server: - server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - server.bind(("127.0.0.1", 0)) - port_holder.append(server.getsockname()[1]) - server.listen(2) - ready.set() - for _ in range(2): - connection, _ = server.accept() - with connection: - stream = connection.makefile("rwb") - request = msgpack.unpackb(read_frame(stream), raw=False) - if request["schemaVersion"] == "cultnet.snapshot_request.v0": - response = { - "schemaVersion": "cultnet.snapshot_response_raw.v0", - "messageId": request["messageId"], - "documents": [ - { - "schemaId": schema_id, - "recordKey": "item:node", - "storedAt": "2026-06-13T00:00:00Z", - "payloadEncoding": "messagepack", - "payload": document.encode_payload(Item("node", "mesh", 1)), - } - ], - } - elif request["schemaVersion"] == "cultnet.shard_log_request.v0": - response = { - "schemaVersion": "cultnet.shard_log_response.v0", - "messageId": request["messageId"], - "shardId": request["shardId"], - "shardEpoch": request["shardEpoch"], - "resyncRequired": False, - "entries": [ - { - "sequence": 1, - "changeKind": "updated", - "put": { - "schemaVersion": "cultnet.document_put_raw.v0", - "messageId": "put-node", - "document": { - "schemaId": schema_id, - "recordKey": "item:node", - "storedAt": "2026-06-13T00:00:01Z", - "payloadEncoding": "messagepack", - "payload": document.encode_payload(Item("node", "mesh", 9)), - }, - "shardId": request["shardId"], - "shardEpoch": request["shardEpoch"], - }, - } - ], - } - else: - raise AssertionError(f"unexpected request {request['schemaVersion']}") - write_frame(stream, msgpack.packb(response, use_bin_type=True)) - stream.flush() - except BaseException as error: - server_error.append(error) - ready.set() - - thread = threading.Thread(target=serve_requests, daemon=True) - thread.start() - self.assertTrue(ready.wait(2.0)) - self.assertFalse(server_error) - - client = CultNetRawClient("127.0.0.1", port_holder[0], timeout_seconds=2.0) - snapshot_changes = node.sync_snapshot(client, schema_ids=[schema_id]) - log_changes = node.sync_shard_log(client, shard_id="mesh", shard_epoch=1) - - thread.join(2.0) - self.assertFalse(server_error) - self.assertEqual(snapshot_changes[0].record_key, "item:node") - self.assertEqual(log_changes[0].change_kind, "updated") - self.assertEqual(node.get_required(document, "item:node").value, 9) - - def test_cultmesh_node_sync_document_returns_requested_alias_type(self) -> None: - @dataclass - class CanonicalNote: - body: str - - @dataclass - class UiNote: - body: str - - document = define_database_entry_type( - "mesh.sync_alias_note", - [("body", 0)], - cls=CanonicalNote, - schema_id="mesh.sync_alias_note.v1", - schema_name="mesh.sync_alias_note", - schema_version="mesh.sync_alias_note.v1", - ) - alias = define_database_entry_type( - "mesh.sync_alias_note.ui", - [("body", 0)], - cls=UiNote, - schema_id="mesh.sync_alias_note.v1", - schema_name="mesh.sync_alias_note", - schema_version="mesh.sync_alias_note.v1", - ) - node = create_node(runtime_id="python-node") - node.register_document(document) - requests: list[dict[str, Any]] = [] - - class SnapshotClient: - def fetch_snapshot_response( - self, - *, - schema_ids: list[str] | None = None, - record_keys: list[str] | None = None, - shard_id: str | None = None, - shard_epoch: int | None = None, - ) -> dict[str, Any]: - requests.append({ - "schema_ids": schema_ids, - "record_keys": record_keys, - "shard_id": shard_id, - "shard_epoch": shard_epoch, - }) - return { - "schemaVersion": "cultnet.snapshot_response_raw.v0", - "messageId": "sync-document", - "documents": [ - { - "schemaId": document.catalog_entry().schema_id, - "recordKey": "note:remote", - "storedAt": "2026-06-27T00:00:00Z", - "payloadEncoding": "messagepack", - "payload": document.encode_payload(CanonicalNote("synced-alias")), - } - ], - } - - synced = node.sync_document(SnapshotClient(), alias, "note:remote") - facade_synced = CultMesh.sync_document(node, SnapshotClient(), alias, "note:remote") - - self.assertIsInstance(synced, UiNote) - self.assertEqual(synced.body, "synced-alias") - self.assertIsInstance(facade_synced, UiNote) - self.assertEqual(facade_synced.body, "synced-alias") - self.assertEqual(node.get_required(document, "note:remote").body, "synced-alias") - self.assertIsInstance(node.get_required(alias, "note:remote"), UiNote) - self.assertEqual(requests, [ - { - "schema_ids": ["mesh.sync_alias_note.v1"], - "record_keys": ["note:remote"], - "shard_id": None, - "shard_epoch": None, - }, - { - "schema_ids": ["mesh.sync_alias_note.v1"], - "record_keys": ["note:remote"], - "shard_id": None, - "shard_epoch": None, - }, - ]) - - def test_cultmesh_node_sync_document_from_publication_returns_requested_alias_type(self) -> None: - @dataclass - class CanonicalNote: - body: str - - @dataclass - class UiNote: - body: str - - document = define_database_entry_type( - "mesh.publication_alias_note", - [("body", 0)], - cls=CanonicalNote, - schema_id="mesh.publication_alias_note.v1", - schema_name="mesh.publication_alias_note", - schema_version="mesh.publication_alias_note.v1", - ) - alias = define_database_entry_type( - "mesh.publication_alias_note.ui", - [("body", 0)], - cls=UiNote, - schema_id="mesh.publication_alias_note.v1", - schema_name="mesh.publication_alias_note", - schema_version="mesh.publication_alias_note.v1", - ) - node = create_node(runtime_id="python-publication-node") - node.register_document(document) - requests: list[dict[str, Any]] = [] - - class SnapshotClient: - def fetch_snapshot_response( - self, - *, - schema_ids: list[str] | None = None, - record_keys: list[str] | None = None, - shard_id: str | None = None, - shard_epoch: int | None = None, - ) -> dict[str, Any]: - requests.append({ - "schema_ids": schema_ids, - "record_keys": record_keys, - "shard_id": shard_id, - "shard_epoch": shard_epoch, - }) - return { - "schemaVersion": "cultnet.snapshot_response_raw.v0", - "messageId": "publication-sync-document", - "documents": [ - { - "schemaId": document.catalog_entry().schema_id, - "recordKey": "note:published-peer", - "storedAt": "2026-06-27T00:00:00Z", - "payloadEncoding": "messagepack", - "payload": document.encode_payload(CanonicalNote("peer-publication-alias")), - } - ], - } - - source = CultMesh.publication_source_from_peer_snapshot( - SnapshotClient(), - shard_id="notes", - shard_epoch=3, - ) - - synced = node.sync_document_from_publication(source, alias, "note:published-peer") - facade_synced = CultMesh.sync_document_from_publication(node, source, alias, "note:published-peer") - - self.assertIsInstance(synced, UiNote) - self.assertEqual(synced.body, "peer-publication-alias") - self.assertIsInstance(facade_synced, UiNote) - self.assertEqual(facade_synced.body, "peer-publication-alias") - self.assertEqual(node.get_required(document, "note:published-peer").body, "peer-publication-alias") - self.assertEqual(requests, [ - { - "schema_ids": ["mesh.publication_alias_note.v1"], - "record_keys": ["note:published-peer"], - "shard_id": "notes", - "shard_epoch": 3, - }, - { - "schema_ids": ["mesh.publication_alias_note.v1"], - "record_keys": ["note:published-peer"], - "shard_id": "notes", - "shard_epoch": 3, - }, - ]) - - def test_cultmesh_node_sync_document_from_single_file_publication_uses_node_aliases(self) -> None: - @dataclass - class CanonicalNote: - body: str - - @dataclass - class UiNote: - body: str - - document = define_database_entry_type( - "mesh.file_publication_alias_note", - [("body", 0)], - cls=CanonicalNote, - schema_id="mesh.file_publication_alias_note.v1", - schema_name="mesh.file_publication_alias_note", - schema_version="mesh.file_publication_alias_note.v1", - ) - alias = define_database_entry_type( - "mesh.file_publication_alias_note.ui", - [("body", 0)], - cls=UiNote, - schema_id="mesh.file_publication_alias_note.v1", - schema_name="mesh.file_publication_alias_note", - schema_version="mesh.file_publication_alias_note.v1", - ) - with tempfile.TemporaryDirectory() as tmp: - path = Path(tmp) / "publication.ccmp" - writer = CultCache() - writer.register_document_type(document) - writer.add_generic_store(SingleFileMessagePackBackingStore(path)) - writer.put(document, "note:published-file", CanonicalNote("file-publication-alias")) - - node = create_node(runtime_id="python-file-publication-node") - node.register_document(document) - source = CultMesh.publication_source_from_single_file(path) - - synced = CultMesh.sync_document_from_publication(node, source, alias, "note:published-file") - - self.assertIsInstance(synced, UiNote) - self.assertEqual(synced.body, "file-publication-alias") - self.assertEqual(node.get_required(document, "note:published-file").body, "file-publication-alias") - self.assertIsInstance(node.get_required(alias, "note:published-file"), UiNote) - - def test_cultmesh_node_sync_documents_from_publication_uses_binding_sources_and_aliases(self) -> None: - @dataclass - class CanonicalNote: - body: str - - @dataclass - class UiNote: - body: str - - document = define_database_entry_type( - "mesh.catalog_publication_alias_note", - [("body", 0)], - cls=CanonicalNote, - schema_id="mesh.catalog_publication_alias_note.v1", - schema_name="mesh.catalog_publication_alias_note", - schema_version="mesh.catalog_publication_alias_note.v1", - ) - alias = define_database_entry_type( - "mesh.catalog_publication_alias_note.ui", - [("body", 0)], - cls=UiNote, - schema_id="mesh.catalog_publication_alias_note.v1", - schema_name="mesh.catalog_publication_alias_note", - schema_version="mesh.catalog_publication_alias_note.v1", - ) - with tempfile.TemporaryDirectory() as tmp: - first_path = Path(tmp) / "first.ccmp" - second_path = Path(tmp) / "second.ccmp" - first = CultCache() - first.register_document_type(document) - first.add_generic_store(SingleFileMessagePackBackingStore(first_path)) - first.put(document, "note:first", CanonicalNote("first catalog publication")) - second = CultCache() - second.register_document_type(document) - second.add_generic_store(SingleFileMessagePackBackingStore(second_path)) - second.put(document, "note:second", CanonicalNote("second catalog publication")) - - node = create_node(runtime_id="python-catalog-publication-node") - node.register_document(document) - source = CultMesh.publication_source_from_single_file(first_path) - bindings = [ - CultMesh.publication_document(alias, "note:first"), - CultMesh.publication_document( - alias, - "note:second", - source=CultMesh.publication_source_from_single_file(second_path), - ), - ] - - synced = node.sync_documents_from_publication(source, bindings) - facade_synced = CultMesh.sync_documents_from_publication(node, source, bindings) - - self.assertEqual([value.body for value in synced], [ - "first catalog publication", - "second catalog publication", - ]) - self.assertTrue(all(isinstance(value, UiNote) for value in synced)) - self.assertEqual([value.body for value in facade_synced], [ - "first catalog publication", - "second catalog publication", - ]) - self.assertEqual(node.get_required(document, "note:first").body, "first catalog publication") - self.assertEqual(node.get_required(document, "note:second").body, "second catalog publication") - self.assertIsInstance(node.get_required(alias, "note:second"), UiNote) - - def test_cultmesh_node_emits_raw_put_and_delete_messages_for_local_writes(self) -> None: - document = define_database_entry_type( - "mesh.emit_item", - [ - ("name", 0), - ("category", 1), - ("value", 2, 0), - ], - cls=Item, - ) - node = create_node(runtime_id="python-node") - node.register_document(document) - - put = node.put_raw_message( - document, - "item:emit", - Item("wand", "gear", 4), - message_id="put-emit", - shard_id="mesh", - shard_epoch=1, - ).to_wire() - self.assertEqual(node.get_required(document, "item:emit").name, "wand") - self.assertEqual(put["schemaVersion"], "cultnet.document_put_raw.v0") - self.assertEqual(put["messageId"], "put-emit") - self.assertEqual(put["document"]["schemaId"], document.catalog_entry().schema_id) - self.assertEqual(put["document"]["recordKey"], "item:emit") - self.assertEqual(put["document"]["sourceRuntimeId"], "python-node") - self.assertEqual(put["shardId"], "mesh") - self.assertEqual(put["shardEpoch"], 1) - - delete = node.delete_raw_message( - document, - "item:emit", - message_id="delete-emit", - shard_id="mesh", - shard_epoch=1, - ).to_wire() - self.assertIsNone(node.get(document, "item:emit")) - self.assertEqual(delete["schemaVersion"], "cultnet.document_delete.v0") - self.assertEqual(delete["messageId"], "delete-emit") - self.assertEqual(delete["schemaId"], document.catalog_entry().schema_id) - self.assertEqual(delete["recordKey"], "item:emit") - self.assertEqual(delete["shardId"], "mesh") - self.assertEqual(delete["shardEpoch"], 1) - - def test_cultmesh_node_resolves_same_schema_aliases_for_local_state(self) -> None: - @dataclass - class CanonicalNote: - body: str - - @dataclass - class UiNote: - body: str - - document = define_database_entry_type( - "mesh.alias_note", - [("body", 0)], - cls=CanonicalNote, - schema_id="mesh.alias_note.v1", - schema_name="mesh.alias_note", - schema_version="mesh.alias_note.v1", - ) - alias = define_database_entry_type( - "mesh.alias_note.ui", - [("body", 0)], - cls=UiNote, - schema_id="mesh.alias_note.v1", - schema_name="mesh.alias_note", - schema_version="mesh.alias_note.v1", - ) - node = create_node(runtime_id="python-node") - node.register_document(document) - seen: list[CultMeshDatabaseChange] = [] - all_seen: list[CultMeshDatabaseChange] = [] - node.database.watch(all_seen.append, document=alias) - node.database.watch_record(alias, "note:alias", seen.append) - - node.put(alias, "note:alias", UiNote("from-alias-put")) - self.assertEqual(node.get_required(document, "note:alias").body, "from-alias-put") - alias_value = node.get_required(alias, "note:alias") - self.assertIsInstance(alias_value, UiNote) - self.assertEqual(alias_value.body, "from-alias-put") - alias_collection = node.get_all(alias) - self.assertEqual(len(alias_collection), 1) - self.assertIsInstance(alias_collection[0], UiNote) - self.assertEqual(alias_collection[0].body, "from-alias-put") - self.assertEqual(seen[0].document.type, alias.type) - self.assertEqual(seen[0].schema_id, "mesh.alias_note.v1") - self.assertIsInstance(seen[0].value, UiNote) - self.assertEqual(seen[0].value.body, "from-alias-put") - self.assertEqual(all_seen[0].document.type, alias.type) - self.assertIsInstance(all_seen[0].value, UiNote) - self.assertEqual(all_seen[0].value.body, "from-alias-put") - - node.put(document, "note:alias", CanonicalNote("from-canonical-put")) - self.assertEqual(seen[1].document.type, alias.type) - self.assertIsInstance(seen[1].value, UiNote) - self.assertIsInstance(seen[1].previous_value, UiNote) - self.assertEqual(seen[1].value.body, "from-canonical-put") - self.assertEqual(seen[1].previous_value.body, "from-alias-put") - - put = node.put_raw_message( - alias, - "note:alias", - UiNote("from-alias-raw-put"), - message_id="alias-put", - ).to_wire() - self.assertEqual(put["document"]["schemaId"], "mesh.alias_note.v1") - self.assertEqual(put["document"]["recordKey"], "note:alias") - self.assertEqual(node.get_required(alias, "note:alias").body, "from-alias-raw-put") - - delete = node.delete_raw_message(alias, "note:alias", message_id="alias-delete").to_wire() - self.assertEqual(delete["schemaId"], "mesh.alias_note.v1") - self.assertIsNone(node.get(alias, "note:alias")) - self.assertEqual(node.get_all(alias), []) - - def test_cultmesh_reactive_document_coalesces_explicit_alias_updates(self) -> None: - @dataclass - class CanonicalNote: - body: str - revision: int - - @dataclass - class UiNote: - body: str - revision: int - - document = define_database_entry_type( - "mesh.reactive_alias_note", - [("body", 0), ("revision", 1)], - cls=CanonicalNote, - schema_id="mesh.reactive_alias_note.v1", - schema_name="mesh.reactive_alias_note", - schema_version="mesh.reactive_alias_note.v1", - ) - alias = define_database_entry_type( - "mesh.reactive_alias_note.ui", - [("body", 0), ("revision", 1)], - cls=UiNote, - schema_id="mesh.reactive_alias_note.v1", - schema_name="mesh.reactive_alias_note", - schema_version="mesh.reactive_alias_note.v1", - ) - node = create_node(runtime_id="python-reactive") - node.register_document(document) - node.put(document, "note:reactive", CanonicalNote("initial", 1)) - seen: list[CultMeshDatabaseChange] = [] - node.database.watch_record(alias, "note:reactive", seen.append) - - reactive = node.authoritative_writer(alias, "note:reactive").reactive( - CultMeshReactiveDocumentOptions(flush_delay_seconds=0.02) - ) - try: - self.assertIsInstance(reactive.snapshot, UiNote) - reactive.update(lambda note: setattr(note, "body", "first-local-edit")) - reactive.update(lambda note: setattr(note, "body", "second-local-edit")) - reactive.update(lambda note: setattr(note, "revision", 2)) - - self._wait_until(lambda: node.get_required(alias, "note:reactive").body == "second-local-edit") - - self.assertFalse(reactive.is_dirty) - self.assertEqual(node.get_required(document, "note:reactive").revision, 2) - self.assertEqual(seen[-1].value.body, "second-local-edit") - finally: - reactive.dispose() - - def test_cultmesh_reactive_document_tracks_canonical_reconciliation_delta(self) -> None: - @dataclass - class Note: - body: str - revision: int - - document = define_database_entry_type( - "mesh.reactive_reconcile_note", - [("body", 0), ("revision", 1)], - cls=Note, - schema_id="mesh.reactive_reconcile_note.v1", - schema_name="mesh.reactive_reconcile_note", - schema_version="mesh.reactive_reconcile_note.v1", - ) - node = create_node(runtime_id="python-reactive-reconcile") - node.register_document(document) - node.put(document, "note:reconcile", Note("initial", 1)) - - reactive = CultMesh.authoritative_writer( - node, - document, - "note:reconcile", - ).reactive(CultMeshReactiveDocumentOptions(flush_delay_seconds=60)) - try: - reactive.update(lambda note: setattr(note, "body", "local-prediction")) - reactive.update(lambda note: setattr(note, "revision", 2)) - - node.put(document, "note:reconcile", Note("authoritative", 7)) - - self.assertEqual(reactive.snapshot.body, "local-prediction") - self.assertIsNotNone(reactive.reconciliation) - self.assertEqual(reactive.reconciliation.canonical.body, "authoritative") - self.assertEqual(reactive.reconciliation.predicted.body, "local-prediction") - self.assertEqual(reactive.reconciliation.delta["body"], "local-prediction") - self.assertEqual(reactive.reconciliation.delta["revision"], -5) - - reactive.flush() - self.assertEqual(node.get_required(document, "note:reconcile").body, "local-prediction") - self.assertIsNone(reactive.reconciliation) - finally: - reactive.dispose() - - def test_cultmesh_reactive_document_is_idle_until_explicit_nested_update(self) -> None: - document = define_document_type( - "mesh.nested_loadout", - encode=lambda value: value, - decode=lambda value: value, - ) - node = create_node(runtime_id="python-reactive-nested") - node.register_document(document) - node.put( - document, - "ship:nested", - {"loadout": {"weapon": {"tuning": {"damage": 10}}}}, - ) - - with patch("cultmesh_py.node.threading.Timer") as timer: - reactive = node.authoritative_writer(document, "ship:nested").reactive() - timer.assert_not_called() - - try: - borrowed = reactive.snapshot - borrowed["loadout"]["weapon"]["tuning"]["damage"] = 99 - self.assertEqual( - node.get_required(document, "ship:nested")["loadout"]["weapon"]["tuning"]["damage"], - 10, - ) - - reactive.update( - lambda draft: draft["loadout"]["weapon"]["tuning"].__setitem__("damage", 12) - ) - reactive.flush() - - self.assertEqual(reactive.snapshot["loadout"]["weapon"]["tuning"]["damage"], 12) - self.assertEqual( - node.get_required(document, "ship:nested")["loadout"]["weapon"]["tuning"]["damage"], - 12, - ) - finally: - reactive.dispose() - - def test_cultmesh_reactive_scheduling_scales_with_changed_documents_only(self) -> None: - document = define_document_type( - "mesh.reactive_scale_note", - encode=lambda value: value, - decode=lambda value: value, - ) - - for document_count in (1, 100, 1000): - node = create_node(runtime_id=f"python-reactive-scale-{document_count}") - node.register_document(document) - for index in range(document_count): - node.put(document, f"note:{index}", {"body": "initial", "revision": 1}) - - scheduled_timers: list[Any] = [] - - class FakeScheduledCall: - def __init__(self, delay_seconds: float, callback: Callable[[], None]) -> None: - self.delay_seconds = delay_seconds - self.callback = callback - self.cancelled = False - - def cancel(self) -> None: - self.cancelled = True - - class FakeScheduler: - def schedule( - self, - delay_seconds: float, - callback: Callable[[], None], - ) -> FakeScheduledCall: - call = FakeScheduledCall(delay_seconds, callback) - scheduled_timers.append(call) - return call - - reactive_documents: list[Any] = [] - with patch("cultmesh_py.node._REACTIVE_SCHEDULER", FakeScheduler()): - try: - for index in range(document_count): - reactive_documents.append( - node.authoritative_writer(document, f"note:{index}").reactive() - ) - - self.assertEqual( - len(scheduled_timers), - 0, - f"{document_count} idle documents must schedule no timers", - ) - - changed_document_count = max(1, document_count // 100) - for index in range(changed_document_count): - reactive_documents[index].update( - lambda draft, changed=index: draft.update( - body=f"changed-{changed}", - revision=2, - ) - ) - - self.assertEqual(len(scheduled_timers), changed_document_count) - self.assertEqual( - sum(reactive.is_dirty for reactive in reactive_documents), - changed_document_count, - ) - finally: - for reactive in reactive_documents: - reactive.dispose() - - self.assertTrue(all(timer.cancelled for timer in scheduled_timers)) - - def test_cultmesh_reactive_documents_share_one_lazy_scheduler_thread(self) -> None: - document = define_document_type( - "mesh.reactive_shared_scheduler_note", - encode=lambda value: value, - decode=lambda value: value, - ) - node = create_node(runtime_id="python-reactive-shared-scheduler") - node.register_document(document) - reactive_documents: list[Any] = [] - try: - for index in range(100): - node.put(document, f"note:{index}", {"body": "initial", "revision": 1}) - reactive_documents.append( - node.authoritative_writer(document, f"note:{index}").reactive( - CultMeshReactiveDocumentOptions(flush_delay_seconds=60.0) - ) - ) - - before = sum( - thread.name == "cultmesh-reactive-scheduler" - for thread in threading.enumerate() - ) - for index, reactive in enumerate(reactive_documents): - reactive.update( - lambda draft, changed=index: draft.update( - body=f"changed-{changed}", - revision=2, - ) - ) - after = sum( - thread.name == "cultmesh-reactive-scheduler" - for thread in threading.enumerate() - ) - - self.assertLessEqual(before, 1) - self.assertEqual(after, 1) - finally: - for reactive in reactive_documents: - reactive.dispose() - - def test_cultmesh_observed_document_cannot_publish_borrowed_mutation(self) -> None: - document = define_document_type( - "mesh.observed_note", - encode=lambda value: value, - decode=lambda value: value, - ) - node = create_node(runtime_id="python-observed") - node.register_document(document) - node.put(document, "note:observed", {"body": "initial"}) - - observed = node.observe_document(document, "note:observed") - try: - observed.current["body"] = "borrowed-local-edit" - self.assertEqual(node.get_required(document, "note:observed")["body"], "initial") - - node.put(document, "note:observed", {"body": "canonical"}) - self.assertEqual(observed.current["body"], "canonical") - finally: - observed.dispose() - - def test_cultnet_document_delete_helper_matches_schema_v0_shape(self) -> None: - message = document_delete( - message_id="delete-1", - schema_id="schema-a", - record_key="record-a", - shard_id="interop", - shard_epoch=1, - ).to_wire() - self.assertEqual(message["schemaVersion"], "cultnet.document_delete.v0") - self.assertEqual(message["messageId"], "delete-1") - self.assertEqual(message["schemaId"], "schema-a") - self.assertEqual(message["recordKey"], "record-a") - self.assertEqual(message["shardId"], "interop") - self.assertEqual(message["shardEpoch"], 1) - - def test_cultnet_auth_session_helpers_match_schema_v0_shape(self) -> None: - self.assertEqual( - login(nonce="nonce", auth="encrypted-auth", password="encrypted-password").to_wire(), - { - "schemaVersion": "cultnet.login.v0", - "nonce": "nonce", - "auth": "encrypted-auth", - "password": "encrypted-password", - }, - ) - self.assertEqual( - register( - nonce="nonce", - email="encrypted-email", - password="encrypted-password", - name="encrypted-name", - ).to_wire(), - { - "schemaVersion": "cultnet.register.v0", - "nonce": "nonce", - "email": "encrypted-email", - "password": "encrypted-password", - "name": "encrypted-name", - }, - ) - self.assertEqual( - verify_session(nonce="nonce", session="encrypted-session").to_wire(), - { - "schemaVersion": "cultnet.verify.v0", - "nonce": "nonce", - "session": "encrypted-session", - }, - ) - self.assertEqual( - login_success(nonce="nonce", session="encrypted-session").to_wire(), - { - "schemaVersion": "cultnet.login_success.v0", - "nonce": "nonce", - "session": "encrypted-session", - }, - ) - - def test_cultnet_wire_catalog_describes_python_handled_messages(self) -> None: - descriptors = wire_message_schema_descriptors(include_schema_json=True) - by_version = {descriptor["schemaVersion"]: descriptor for descriptor in descriptors} - for schema_version in [ - "cultnet.error.v0", - "cultnet.login.v0", - "cultnet.register.v0", - "cultnet.verify.v0", - "cultnet.login_success.v0", - "cultnet.transport_profile.v0", - "cultnet.document_delete.v0", - "cultnet.database_change_raw.v0", - "cultnet.shard_log_response.v0", - "cultnet.simulation_consensus_candidate.v0", - "cultmesh.peer_exchange_response.v0", - ]: - self.assertIn(schema_version, by_version) - expected_kind = "shared_contract" if schema_version == "cultnet.transport_profile.v0" else "wire_message" - self.assertEqual(by_version[schema_version]["kind"], expected_kind) - self.assertIn("cultnet.schema.v0", by_version[schema_version]["wireContracts"]) - self.assertIn(schema_version, by_version[schema_version]["schemaJson"]) - self.assertEqual(len(by_version[schema_version]["contentHash"]), 64) - - delete_schema = json.loads(by_version["cultnet.document_delete.v0"]["schemaJson"]) - self.assertEqual( - delete_schema["required"], - ["schemaVersion", "messageId", "schemaId", "recordKey"], - ) - self.assertEqual(delete_schema["properties"]["recordKey"]["type"], "string") - - error_schema = json.loads(by_version["cultnet.error.v0"]["schemaJson"]) - self.assertEqual(error_schema["required"], ["schemaVersion", "error"]) - self.assertEqual(error_schema["properties"]["error"]["type"], "string") - self.assertIn("details", error_schema["properties"]) - - login_schema = json.loads(by_version["cultnet.login.v0"]["schemaJson"]) - self.assertEqual(login_schema["required"], ["schemaVersion", "nonce", "auth", "password"]) - self.assertEqual(login_schema["properties"]["auth"]["type"], "string") - - register_schema = json.loads(by_version["cultnet.register.v0"]["schemaJson"]) - self.assertEqual(register_schema["required"], ["schemaVersion", "nonce", "email", "password", "name"]) - self.assertEqual(register_schema["properties"]["email"]["type"], "string") - - verify_schema = json.loads(by_version["cultnet.verify.v0"]["schemaJson"]) - self.assertEqual(verify_schema["required"], ["schemaVersion", "nonce", "session"]) - self.assertEqual(verify_schema["properties"]["session"]["type"], "string") - - success_schema = json.loads(by_version["cultnet.login_success.v0"]["schemaJson"]) - self.assertEqual(success_schema["required"], ["schemaVersion", "nonce", "session"]) - - transport_profile_schema = json.loads(by_version["cultnet.transport_profile.v0"]["schemaJson"]) - self.assertEqual(transport_profile_schema["required"], ["schemaVersion", "runtimeId", "transports"]) - transport = transport_profile_schema["properties"]["transports"]["items"] - self.assertEqual(transport["properties"]["protocol"]["enum"], ["tcp_framed", "litenetlib", "websocket", "rudp"]) - self.assertEqual( - transport["properties"]["reconnectPolicy"]["properties"]["schemaVersion"]["const"], - "cultnet.reconnect_policy.v0", - ) - channel = transport["properties"]["channels"]["items"] - self.assertEqual(channel["properties"]["ordering"]["enum"], ["ordered", "unordered", "sequenced"]) - - change_schema = json.loads(by_version["cultnet.database_change_raw.v0"]["schemaJson"]) - self.assertEqual(change_schema["properties"]["changeKind"]["enum"], ["added", "updated", "removed"]) - self.assertIn("document", change_schema["properties"]) - self.assertIn("schemaId", change_schema["properties"]) - self.assertIn("recordKey", change_schema["properties"]) - - log_schema = json.loads(by_version["cultnet.shard_log_response.v0"]["schemaJson"]) - self.assertIn("entries", log_schema["required"]) - self.assertIn("resyncRequired", log_schema["required"]) - self.assertIn("compactedThrough", log_schema["properties"]) - - hello_schema = json.loads(by_version["cultnet.hello.v0"]["schemaJson"]) - mutation_contract = hello_schema["properties"]["supportedMutationContracts"]["items"] - self.assertEqual(mutation_contract["type"], "object") - self.assertIn("operations", mutation_contract["properties"]) - self.assertEqual( - hello_schema["properties"]["transportProfiles"]["items"]["$ref"], - "https://github.com/GameCult/cultnet-ts/contracts/cultnet.transport-profile.schema.json", - ) - - consensus_schema = json.loads(by_version["cultnet.simulation_consensus_candidate.v0"]["schemaJson"]) - for required_field in ["witnessCount", "supportWeight", "totalWeight", "hasQuorum", "confidence"]: - self.assertIn(required_field, consensus_schema["required"]) - - def test_cultnet_schema_catalog_applies_filters_and_responses(self) -> None: - catalog = wire_message_schema_catalog(include_schema_json=True) - descriptor = catalog.get("https://github.com/GameCult/cultnet-ts/contracts/cultnet.document-put-raw.schema.json") - self.assertIsNotNone(descriptor) - assert descriptor is not None - self.assertEqual(descriptor.kind, "wire_message") - self.assertEqual(descriptor.schema_version, "cultnet.document_put_raw.v0") - self.assertIsNotNone(descriptor.schema_json) - - filtered = catalog.list(kinds=["wire_message"], schema_ids=[descriptor.schema_id]) - self.assertEqual(filtered, [descriptor]) - - response = catalog.create_response( - message_id="catalog-response", - include_schema_json=False, - schema_ids=[descriptor.schema_id], - kinds=["wire_message"], - ) - self.assertEqual(response["schemaVersion"], "cultnet.schema_catalog_response.v0") - self.assertNotIn("schemaJson", response["schemas"][0]) - - remote = CultNetSchemaCatalog() - applied = remote.apply_response({ - "schemaVersion": "cultnet.schema_catalog_response.v0", - "messageId": "remote", - "schemas": [ - CultNetSchemaDescriptor( - schema_id="schema:custom", - kind="shared_contract", - schema_version="custom.v0", - wire_contracts=("cultnet.schema.v0",), - content_hash="hash", - schema_json="{}", - ).to_wire() - ], - }) - self.assertEqual(applied[0].schema_id, "schema:custom") - self.assertEqual(remote.get("schema:custom"), applied[0]) - - def test_cultnet_shard_helpers_match_schema_v0_shape(self) -> None: - catalog = shard_catalog_request( - message_id="catalog-1", - schema_ids=["schema-a"], - record_keys=["record-a"], - ).to_wire() - self.assertEqual(catalog["schemaVersion"], "cultnet.shard_catalog_request.v0") - self.assertEqual(catalog["messageId"], "catalog-1") - self.assertEqual(catalog["schemaIds"], ["schema-a"]) - self.assertEqual(catalog["recordKeys"], ["record-a"]) - - log = shard_log_request( - message_id="log-1", - shard_id="interop", - shard_epoch=7, - after_sequence=3, - limit=2, - ).to_wire() - self.assertEqual(log["schemaVersion"], "cultnet.shard_log_request.v0") - self.assertEqual(log["messageId"], "log-1") - self.assertEqual(log["shardId"], "interop") - self.assertEqual(log["shardEpoch"], 7) - self.assertEqual(log["afterSequence"], 3) - self.assertEqual(log["limit"], 2) - - def test_cultnet_shard_catalog_applies_filters_and_responses(self) -> None: - catalog = CultNetShardCatalog() - primary = catalog.upsert(CultNetShardDescriptor( - shard_id="notes", - owner_runtime_id="python-runtime", - epoch=2, - is_primary=True, - schema_ids=("schema-note.v1",), - key_prefix="note:", - primary_endpoints=("cultnet://127.0.0.1:3075",), - read_replica_endpoints=("cultnet://127.0.0.1:3075",), - region="local", - )) - catalog.upsert({ - "shardId": "facts", - "ownerRuntimeId": "python-runtime", - "epoch": 1, - "schemaIds": ["schema-fact"], - "keyPrefix": "fact:", - "primaryEndpoints": ["cultnet://127.0.0.1:3076"], - }) - - self.assertTrue(primary.serves(schema_id="schema-note.v1", record_key="note:1")) - self.assertTrue(primary.serves(schema_id="schema-note", record_key="note:1")) - self.assertFalse(primary.serves(schema_id="schema-note", record_key="fact:1")) - self.assertEqual(catalog.list(schema_ids=["schema-note.v1"]), [primary]) - self.assertEqual(catalog.list(schema_ids=["schema-note"]), [primary]) - self.assertEqual(catalog.list(record_keys=["note:1"]), [primary]) - - response = catalog.create_response( - message_id="shards", - schema_ids=["schema-note"], - record_keys=["note:1"], - ) - self.assertEqual(response["schemaVersion"], "cultnet.shard_catalog_response.v0") - self.assertEqual(response["shards"][0]["shardId"], "notes") - self.assertEqual(response["shards"][0]["ownerRuntimeId"], "python-runtime") - - remote = CultNetShardCatalog() - applied = remote.apply_response(response) - self.assertEqual(applied[0].shard_id, "notes") - self.assertEqual(remote.get("notes"), applied[0]) - - def test_cultnet_shard_log_response_tracks_cursor_and_resync_state(self) -> None: - response = CultNetShardLogResponse.from_wire({ - "schemaVersion": "cultnet.shard_log_response.v0", - "messageId": "log", - "shardId": "notes", - "shardEpoch": 2, - "entries": [ - CultNetShardLogEntry( - sequence=2, - change_kind="updated", - put={"schemaVersion": "cultnet.document_put_raw.v0", "messageId": "put", "document": {"schemaId": "schema-note", "recordKey": "note:1", "payload": b"p"}}, - committed_at="2026-06-14T00:00:00Z", - ).to_wire(), - {"sequence": 3, "changeKind": "removed", "delete": {"schemaId": "schema-note", "recordKey": "note:1"}}, - ], - "resyncRequired": False, - }) - self.assertEqual(response.last_sequence, 3) - self.assertFalse(response.resync_required) - self.assertEqual(response.entries[0].put["document"]["recordKey"], "note:1") - self.assertIsInstance(response.entries[0].raw_document, CultNetRawDocumentRecord) - self.assertEqual(response.entries[0].raw_document.record_key, "note:1") - self.assertEqual(response.entries[1].delete_schema_id, "schema-note") - self.assertEqual(response.entries[1].delete_record_key, "note:1") - self.assertEqual(response.to_wire()["entries"][1]["delete"]["recordKey"], "note:1") - self.assertIs(response.require_usable(), response) - - resync = CultNetShardLogResponse.from_wire({ - "schemaVersion": "cultnet.shard_log_response.v0", - "messageId": "log-resync", - "shardId": "notes", - "shardEpoch": 2, - "entries": [], - "resyncRequired": True, - "reason": "compacted", - "compactedThrough": 12, - }) - self.assertEqual(resync.last_sequence, 12) - with self.assertRaisesRegex(ValueError, "compacted"): - resync.require_usable() - - def test_cultnet_simulation_observation_helper_matches_schema_v0_shape(self) -> None: - claim_hash = compute_simulation_claim_hash("frame:42", "subject:player-1", "hit") - self.assertEqual(len(claim_hash), 64) - message = simulation_observation( - message_id="obs-1", - witness_runtime_id="python-test", - shard_id="interop", - shard_epoch=1, - frame=42, - subject_id="player-1", - claim_kind="hit", - claim_hash=claim_hash, - claim_summary="player-1 hit target-a", - observed_at="2026-06-13T00:00:02Z", - ).to_wire() - self.assertEqual(message["schemaVersion"], "cultnet.simulation_observation.v0") - self.assertEqual(message["messageId"], "obs-1") - self.assertEqual(message["observation"]["witnessRuntimeId"], "python-test") - self.assertEqual(message["observation"]["claimHash"], claim_hash) - self.assertEqual(message["observation"]["weight"], 1.0) - observation = CultNetSimulationObservation.from_wire(message) - self.assertEqual(observation.witness_runtime_id, "python-test") - self.assertEqual(observation.claim_summary, "player-1 hit target-a") - self.assertEqual(observation.to_message_wire(message_id="obs-2")["observation"], message["observation"]) - - def test_cultnet_witness_artifact_bundle_uses_csharp_slot_order(self) -> None: - import msgpack # type: ignore - - bundle = witness_artifact_bundle( - bundle_id="bundle-1", - witness_kind="interop-proof", - captured_at="2026-06-13T00:00:03Z", - subject={"documentType": "cultnet.interop-note", "subjectId": "note:python"}, - contracts=[{"role": "payload", "schemaId": "schema-a"}], - artifacts=[{"role": "log", "uri": "cultcache://bundle-1/log", "mediaType": "text/plain"}], - timing_witnesses=[{"stage": "roundtrip", "startedAt": "2026-06-13T00:00:03Z", "completedAt": "2026-06-13T00:00:04Z", "latencyMs": 1.0}], - provenance={"pipelineId": "interop", "runId": "run-1", "runtimeId": "python-test"}, - ) - payload = encode_witness_artifact_bundle_payload(bundle) - decoded = decode_witness_artifact_bundle_payload(payload) - typed = CultNetWitnessArtifactBundle.from_wire(bundle) - typed_payload = typed.to_payload() - typed_decoded = CultNetWitnessArtifactBundle.from_payload(typed_payload) - slots = msgpack.unpackb(payload, raw=False) - - self.assertEqual(payload, typed_payload) - self.assertEqual(slots[0], "bundle-1") - self.assertEqual(slots[1], "interop-proof") - self.assertEqual(slots[2], "2026-06-13T00:00:03Z") - self.assertEqual(slots[3]["subjectId"], "note:python") - self.assertEqual(slots[4][0]["schemaId"], "schema-a") - self.assertEqual(slots[5][0]["uri"], "cultcache://bundle-1/log") - self.assertEqual(slots[6][0]["latencyMs"], 1.0) - self.assertEqual(slots[7]["runtimeId"], "python-test") - self.assertEqual(decoded["bundleId"], "bundle-1") - self.assertEqual(decoded["witnessKind"], "interop-proof") - self.assertEqual(decoded["subject"]["subjectId"], "note:python") - self.assertEqual(decoded["contracts"][0]["schemaId"], "schema-a") - self.assertEqual(decoded["artifacts"][0]["mediaType"], "text/plain") - self.assertEqual(decoded["provenance"]["runtimeId"], "python-test") - self.assertEqual(typed.bundle_id, "bundle-1") - self.assertEqual(typed_decoded.to_wire(), bundle) - - def test_cultmesh_node_uses_cultcache_store(self) -> None: - with tempfile.TemporaryDirectory() as tmp: - document = define_database_entry_type("mesh.note", [("body", 0)]) - store_path = Path(tmp) / "mesh.cc" - node = create_node(store_path, runtime_id="mesh-test") - self.assertIsInstance(node.database, CultMeshDatabase) - node.database.register_document(document) - node.database.put(document, "note:1", {"body": "hello"}) - self.assertEqual(node.get_required(document, "note:1")["body"], "hello") - - reopened = create_node(store_path, runtime_id="mesh-test") - reopened.database.register_document(document) - reopened.database.pull() - self.assertEqual(reopened.database.get(document, "note:1")["body"], "hello") - - def test_cultmesh_node_options_attach_default_durable_shard_log_store(self) -> None: - with tempfile.TemporaryDirectory() as tmp: - document = define_database_entry_type( - "mesh.durable_option_note", - [("body", 0)], - schema_id="mesh.durable_option_note.v1", - ) - cache_path = Path(tmp) / "world.cc" - node = CultMesh.create_node( - cache_path, - runtime_id="durable-option-primary", - options=CultMeshNodeOptions(enable_durable_shard_logs=True), - ) - node.database.register_document(document) - node.database.put_raw_message(document, "note:1", {"body": "stored"}, shard_id="notes", shard_epoch=5) - - log_path = Path(tmp) / "world.cultmesh" / "shard-logs" - self.assertTrue(log_path.exists()) - - reopened = CultMesh.start_node( - cache_path, - runtime_id="durable-option-primary", - enable_durable_shard_logs=True, - ) - reopened.database.register_document(document) - response = reopened.database.build_shard_log_response(shard_id="notes", shard_epoch=5) - - self.assertEqual(reopened.database.shard_ids(), ["notes"]) - self.assertEqual([entry.sequence for entry in response.entries], [1]) - self.assertEqual(response.entries[0].raw_document.record_key, "note:1") - - def test_cultmesh_database_watchers_observe_local_changes_and_unsubscribe(self) -> None: - document = define_database_entry_type("mesh.watch", [("body", 0)]) - node = CultMesh.create_node(runtime_id="mesh-watch") - node.database.register_document(document) - changes: list[CultMeshDatabaseChange] = [] - all_changes: list[CultMeshDatabaseChange] = [] - - unsubscribe_record = node.database.watch_record(document, "note:1", changes.append) - unsubscribe_all = node.database.watch(all_changes.append, document=document) - - node.database.put(document, "note:1", {"body": "hello"}) - node.database.put(document, "note:2", {"body": "skip"}) - node.database.put(document, "note:1", {"body": "updated"}) - node.database.delete(document, "note:1") - unsubscribe_record() - node.database.put(document, "note:1", {"body": "after-unsubscribe"}) - unsubscribe_all() - - self.assertEqual([change.change_kind for change in changes], ["added", "updated", "removed"]) - self.assertEqual([change.record_key for change in changes], ["note:1", "note:1", "note:1"]) - self.assertEqual(changes[1].previous_value, {"body": "hello"}) - self.assertIsNone(changes[2].value) - self.assertEqual([change.record_key for change in all_changes], ["note:1", "note:2", "note:1", "note:1", "note:1"]) - - def test_cultmesh_database_register_document_is_idempotent(self) -> None: - document = define_database_entry_type("mesh.idempotent", [("body", 0)]) - conflicting = define_database_entry_type("mesh.idempotent", [("title", 0)]) - node = CultMesh.create_node(runtime_id="mesh-idempotent") - - node.database.register_document(document) - node.database.register_document(document) - node.database.put(document, "note:1", {"body": "still registered once"}) - - self.assertEqual(node.database.get_required(document, "note:1")["body"], "still registered once") - self.assertEqual([registered.type for registered in node.documents], ["mesh.idempotent"]) - with self.assertRaises(ValueError): - node.database.register_document(conflicting) - - def test_cultmesh_database_global_document_facade_uses_singleton_key_and_watchers(self) -> None: - document = define_database_entry_type( - "mesh.global_settings", - [("theme", 0)], - global_document=True, - ) - node = CultMesh.create_node(runtime_id="mesh-global") - node.database.register_document(document) - changes: list[CultMeshDatabaseChange] = [] - - node.database.watch_global(document, changes.append) - node.database.put_global(document, {"theme": "ash"}) - node.put_global(document, {"theme": "ember"}) - node.delete_global(document) - - self.assertIsNone(node.database.get_global(document)) - self.assertEqual([change.record_key for change in changes], [node.cache.GLOBAL_KEY] * 3) - self.assertEqual([change.change_kind for change in changes], ["added", "updated", "removed"]) - self.assertEqual(changes[1].previous_value, {"theme": "ash"}) - self.assertEqual(changes[2].previous_value, {"theme": "ember"}) - with self.assertRaises(Exception): - node.database.put(document, "settings:wrong", {"theme": "bad"}) - - def test_cultmesh_database_creates_raw_snapshot_response_from_envelopes(self) -> None: - document = define_database_entry_type( - "mesh.snapshot_note", - [("body", 0)], - schema_id="mesh.snapshot_note.v1", - ) - source = CultMesh.create_node(runtime_id="mesh-snapshot-source") - source.database.register_document(document) - source.database.put(document, "note:1", {"body": "include"}) - source.database.put(document, "note:2", {"body": "skip"}) - - typed_response = source.database.build_snapshot_response( - message_id="snapshot-1", - schema_ids=["mesh.snapshot_note.v1"], - record_keys=["note:1"], - shard_id="notes", - shard_epoch=4, - shard_log_sequence=7, - ) - response = source.database.create_snapshot_response( - message_id="snapshot-1", - schema_ids=["mesh.snapshot_note.v1"], - record_keys=["note:1"], - shard_id="notes", - shard_epoch=4, - shard_log_sequence=7, - ) - - self.assertIsInstance(typed_response, CultNetRawSnapshotResponse) - self.assertEqual(typed_response.message_id, "snapshot-1") - self.assertEqual(typed_response.documents[0].record_key, "note:1") - self.assertEqual(typed_response.to_wire(), response) - self.assertEqual(source.build_snapshot_response(schema_ids=["mesh.snapshot_note.v1"]).documents[0].record_key, "note:1") - self.assertEqual(response["schemaVersion"], "cultnet.snapshot_response_raw.v0") - self.assertEqual(response["messageId"], "snapshot-1") - self.assertEqual(response["shardId"], "notes") - self.assertEqual(response["shardEpoch"], 4) - self.assertEqual(response["shardLogSequence"], 7) - self.assertEqual([record["recordKey"] for record in response["documents"]], ["note:1"]) - self.assertEqual(response["documents"][0]["schemaId"], "mesh.snapshot_note.v1") - self.assertEqual(response["documents"][0]["payloadEncoding"], "messagepack") - - target = CultMesh.create_node(runtime_id="mesh-snapshot-target") - target.database.register_document(document) - applied = target.database.apply_snapshot_response(response) - self.assertEqual([(record.schema_id, record.record_key) for record in applied], [("mesh.snapshot_note.v1", "note:1")]) - self.assertEqual(target.database.get_required(document, "note:1"), {"body": "include"}) - self.assertIsNone(target.database.get(document, "note:2")) - - typed_target = CultMesh.create_node(runtime_id="mesh-snapshot-typed-target") - typed_target.database.register_document(document) - typed_applied = typed_target.database.apply_snapshot_response(typed_response) - self.assertEqual([(record.schema_id, record.record_key) for record in typed_applied], [("mesh.snapshot_note.v1", "note:1")]) - self.assertEqual(typed_target.database.get_required(document, "note:1"), {"body": "include"}) - - def test_cultmesh_database_filters_snapshot_by_logged_shard_membership(self) -> None: - document = define_database_entry_type( - "mesh.sharded_snapshot_note", - [("body", 0)], - schema_id="mesh.sharded_snapshot_note.v1", - ) - source = CultMesh.create_node(runtime_id="mesh-sharded-snapshot-source") - source.database.register_document(document) - source.database.put_raw_message(document, "note:notes", {"body": "include"}, shard_id="notes", shard_epoch=2) - source.database.put_raw_message(document, "note:other", {"body": "skip"}, shard_id="other", shard_epoch=1) - - response = source.database.build_snapshot_response( - schema_ids=["mesh.sharded_snapshot_note.v1"], - shard_id="notes", - shard_epoch=2, - ) - - self.assertEqual(response.shard_id, "notes") - self.assertEqual(response.shard_epoch, 2) - self.assertEqual([record.record_key for record in response.documents], ["note:notes"]) - - def test_python_interop_peer_filters_shard_snapshot_by_logged_membership(self) -> None: - runtime_id = f"python-interop-test-{uuid4().hex}" - state = build_state( - runtime_id=runtime_id, - runtime_kind="python", - display_name="Python Interop Test", - agent_id="python-interop-test-agent", - schema_path=str(Path("packages/cultnet-ts/integration/contracts/cultnet.interop-note.schema.json")), - ) - binding = state.bindings["note"] - logged_value = { - "schemaVersion": "cultnet.interop_note.v0", - "documentId": "note:logged", - "authorRuntimeId": runtime_id, - "title": "Logged", - "body": "This record belongs to the shard log.", - "tags": ["interop", "logged"], - } - unlogged_value = { - **logged_value, - "documentId": "note:unlogged", - "title": "Unlogged", - "body": "This record is in cache but not in the shard log.", - } - state.cache.put(binding.document, "note:logged", logged_value) - state.cache.put(binding.document, "note:unlogged", unlogged_value) - logged_record = { - "schemaId": state.note_schema_id, - "recordKey": "note:logged", - "storedAt": "2026-06-14T00:00:00Z", - "payloadEncoding": "messagepack", - "payload": binding.document.encode_payload(logged_value), - } - append_shard_log_put( - state, - {"messageId": "logged-put"}, - logged_record, - ) - - response = raw_snapshot_response( - state, - { - "schemaVersion": "cultnet.snapshot_request.v0", - "messageId": "interop-shard-snapshot", - "schemaIds": [state.note_schema_id], - "shardId": state.shard_id, - }, - ) - - self.assertEqual(response["shardId"], state.shard_id) - self.assertEqual(response["shardLogSequence"], 1) - self.assertEqual([record["recordKey"] for record in response["documents"]], ["note:logged"]) - - def test_cultmesh_database_creates_shard_log_response_from_raw_mutations(self) -> None: - document = define_database_entry_type( - "mesh.log_note", - [("body", 0)], - schema_id="mesh.log_note.v1", - ) - source = CultMesh.create_node(runtime_id="mesh-log-source") - source.database.register_document(document) - source.database.put_raw_message(document, "note:1", {"body": "first"}, shard_id="notes", shard_epoch=3) - source.database.put_raw_message(document, "note:1", {"body": "second"}, shard_id="notes", shard_epoch=3) - source.database.put_raw_message(document, "note:2", {"body": "other"}, shard_id="other", shard_epoch=1) - source.database.delete_raw_message(document, "note:1", shard_id="notes", shard_epoch=3) - - self.assertEqual(source.database.shard_ids(), ["notes", "other"]) - self.assertEqual(source.database.shard_schema_ids("notes"), ["mesh.log_note.v1"]) - - typed_response = source.database.build_shard_log_response( - message_id="log-1", - shard_id="notes", - shard_epoch=3, - after_sequence=1, - limit=2, - ) - response = source.database.create_shard_log_response( - message_id="log-1", - shard_id="notes", - shard_epoch=3, - after_sequence=1, - limit=2, - ) - - self.assertIsInstance(typed_response, CultNetShardLogResponse) - self.assertEqual(typed_response.message_id, "log-1") - self.assertEqual([entry.sequence for entry in typed_response.entries], [2, 3]) - self.assertEqual(typed_response.to_wire(), response) - self.assertEqual([entry.sequence for entry in source.build_shard_log_response(shard_id="notes").entries], [1, 2, 3]) - self.assertEqual(response["schemaVersion"], "cultnet.shard_log_response.v0") - self.assertEqual(response["messageId"], "log-1") - self.assertEqual(response["shardId"], "notes") - self.assertEqual(response["shardEpoch"], 3) - self.assertFalse(response["resyncRequired"]) - self.assertEqual([entry["sequence"] for entry in response["entries"]], [2, 3]) - self.assertEqual([entry["changeKind"] for entry in response["entries"]], ["updated", "removed"]) - self.assertEqual(response["entries"][0]["put"]["document"]["recordKey"], "note:1") - self.assertEqual(response["entries"][1]["delete"]["recordKey"], "note:1") - empty = source.database.create_shard_log_response(shard_id="missing") - self.assertEqual(empty["shardEpoch"], 0) - self.assertEqual(empty["entries"], []) - self.assertTrue(empty["resyncRequired"]) - self.assertEqual(empty["reason"], "unknown_shard") - stale = source.database.create_shard_log_response(shard_id="notes", shard_epoch=2) - self.assertEqual(stale["shardEpoch"], 3) - self.assertEqual(stale["entries"], []) - self.assertTrue(stale["resyncRequired"]) - self.assertEqual(stale["reason"], "stale_epoch") - with self.assertRaises(ValueError): - source.database.create_shard_log_response(shard_id="notes", after_sequence=-1) - with self.assertRaises(ValueError): - source.database.create_shard_log_response(shard_id="notes", limit=-1) - - target = CultMesh.create_node(runtime_id="mesh-log-target") - target.database.register_document(document) - target.database.put(document, "note:1", {"body": "first"}) - applied = target.database.apply_shard_log_response(response) - self.assertEqual([record.change_kind for record in applied], ["updated", "removed"]) - self.assertIsNone(target.database.get(document, "note:1")) - self.assertIsNone(target.database.get(document, "note:2")) - - typed_target = CultMesh.create_node(runtime_id="mesh-log-typed-target") - typed_target.database.register_document(document) - typed_target.database.put(document, "note:1", {"body": "first"}) - typed_applied = typed_target.database.apply_shard_log_response(typed_response) - self.assertEqual([record.change_kind for record in typed_applied], ["updated", "removed"]) - self.assertIsNone(typed_target.database.get(document, "note:1")) - - def test_cultnet_file_shard_mutation_log_store_persists_authoritative_entries(self) -> None: - document = define_database_entry_type( - "mesh.durable_log_note", - [("body", 0)], - schema_id="mesh.durable_log_note.v1", - ) - with tempfile.TemporaryDirectory() as tmp: - store: CultNetShardMutationLogStore = CultNetFileShardMutationLogStore(Path(tmp) / "logs") - source = CultMesh.create_node(runtime_id="durable-primary") - source.database.register_document(document) - source.database.use_shard_mutation_log_store(store) - source.database.put_raw_message(document, "note:1", {"body": "first"}, shard_id="durable", shard_epoch=4) - source.database.put_raw_message(document, "note:2", {"body": "second"}, shard_id="durable", shard_epoch=4) - - reopened = CultMesh.create_node(runtime_id="durable-primary") - reopened.database.register_document(document) - reopened.database.use_shard_mutation_log_store(CultNetFileShardMutationLogStore(Path(tmp) / "logs")) - response = reopened.database.build_shard_log_response(shard_id="durable", shard_epoch=4) - self.assertEqual(reopened.database.shard_ids(), ["durable"]) - self.assertEqual(reopened.database.shard_schema_ids("durable"), ["mesh.durable_log_note.v1"]) - self.assertEqual([entry.sequence for entry in response.entries], [1, 2]) - self.assertEqual(response.entries[0].raw_document.record_key, "note:1") - - store.compact_through("durable", 1) - compacted = reopened.database.build_shard_log_response(shard_id="durable", shard_epoch=4, after_sequence=0) - retained = reopened.database.build_shard_log_response(shard_id="durable", shard_epoch=4, after_sequence=1) - self.assertTrue(compacted.resync_required) - self.assertEqual(compacted.reason, "compacted_history") - self.assertEqual(compacted.compacted_through, 1) - self.assertEqual([entry.sequence for entry in retained.entries], [2]) - - def test_cultnet_shard_replicator_pulls_logs_and_resyncs_from_snapshot(self) -> None: - document = define_database_entry_type( - "mesh.replica_note", - [("body", 0)], - schema_id="mesh.replica_note.v1", - ) - source = CultMesh.create_node(runtime_id="primary") - source.database.register_document(document) - source.database.put_raw_message(document, "note:1", {"body": "one"}, shard_id="notes", shard_epoch=3) - source.database.put_raw_message(document, "note:2", {"body": "two"}, shard_id="notes", shard_epoch=3) - with tempfile.TemporaryDirectory() as tmp: - cursor_path = Path(tmp) / "replica-cursors.msgpack" - server = CultMesh.serve_node(source) - try: - shard = CultNetShardDescriptor( - shard_id="notes", - owner_runtime_id="primary", - epoch=3, - is_primary=False, - schema_ids=("mesh.replica_note.v1",), - primary_endpoints=(f"cultnet://127.0.0.1:{server.port}",), - ) - target = CultMesh.create_node(runtime_id="replica") - target.database.register_document(document) - cursor_store = CultNetFileShardReplicaCursorStore(cursor_path) - replicator = CultNetShardReplicator( - target.database, - CultNetShardReplicatorOptions( - fetcher=CultNetSchemaShardLogFetcher(timeout_seconds=2.0), - snapshot_fetcher=CultNetSchemaShardSnapshotFetcher(timeout_seconds=2.0), - cursor_store=cursor_store, - batch_size=16, - ), - ) - - first_sequence = replicator.pull_once(shard) - restarted_replicator = CultNetShardReplicator( - target.database, - CultNetShardReplicatorOptions( - fetcher=CultNetSchemaShardLogFetcher(timeout_seconds=2.0), - snapshot_fetcher=CultNetSchemaShardSnapshotFetcher(timeout_seconds=2.0), - cursor_store=CultNetFileShardReplicaCursorStore(cursor_path), - batch_size=16, - ), - ) - second_sequence = restarted_replicator.pull_once(shard) - - self.assertEqual(first_sequence, 2) - self.assertEqual(second_sequence, 2) - self.assertEqual(target.get_required(document, "note:1")["body"], "one") - self.assertEqual(target.get_required(document, "note:2")["body"], "two") - cursor = CultNetFileShardReplicaCursorStore(cursor_path).read("notes") - self.assertIsNotNone(cursor) - assert cursor is not None - self.assertEqual(cursor.last_applied_sequence, 2) - self.assertEqual(cursor.shard_epoch, 3) - finally: - server.stop() - - resync_target = CultMesh.create_node(runtime_id="resync-replica") - resync_target.database.register_document(document) - snapshot = source.database.build_snapshot_response(shard_id="notes", shard_epoch=3, shard_log_sequence=2) - - class CompactingFetcher: - def fetch(self, shard: CultNetShardDescriptor, *, after_sequence: int, limit: int | None = None) -> CultNetShardLogResponse: - return CultNetShardLogResponse( - message_id="compact", - shard_id=shard.shard_id, - shard_epoch=shard.epoch, - entries=(), - resync_required=True, - reason="compacted_history", - compacted_through=after_sequence, - ) - - class SnapshotFetcher: - def fetch(self, shard: CultNetShardDescriptor) -> CultNetRawSnapshotResponse: - return snapshot - - resync_replicator = CultNetShardReplicator( - resync_target.database, - CultNetShardReplicatorOptions( - fetcher=CompactingFetcher(), - snapshot_fetcher=SnapshotFetcher(), - cursor_store=CultNetInMemoryShardReplicaCursorStore(), - ), - ) - resync_sequence = resync_replicator.pull_once(CultNetShardDescriptor( - shard_id="notes", - owner_runtime_id="primary", - epoch=3, - is_primary=False, - schema_ids=("mesh.replica_note.v1",), - primary_endpoints=("cultnet://primary:3075",), - )) - - self.assertEqual(resync_sequence, 2) - self.assertEqual(resync_target.get_required(document, "note:1")["body"], "one") - - def test_cultnet_shard_replicator_background_loop_polls_non_primary_shards(self) -> None: - document = define_database_entry_type( - "mesh.background_replica_note", - [("body", 0)], - schema_id="mesh.background_replica_note.v1", - ) - source = CultMesh.create_node(runtime_id="background-primary") - source.database.register_document(document) - target = CultMesh.create_node(runtime_id="background-replica") - target.database.register_document(document) - cursor_store = CultNetInMemoryShardReplicaCursorStore() - errors: list[Exception] = [] - - class FlakySourceFetcher: - def __init__(self) -> None: - self.calls = 0 - - def fetch(self, shard: CultNetShardDescriptor, *, after_sequence: int, limit: int | None = None) -> CultNetShardLogResponse: - self.calls += 1 - if self.calls == 1: - raise RuntimeError("transient fetch failure") - return source.database.build_shard_log_response( - shard_id=shard.shard_id, - shard_epoch=shard.epoch, - after_sequence=after_sequence, - limit=limit, - ) - - fetcher = FlakySourceFetcher() - shard = CultNetShardDescriptor( - shard_id="background", - owner_runtime_id="background-primary", - epoch=7, - is_primary=False, - schema_ids=("mesh.background_replica_note.v1",), - primary_endpoints=("cultnet://127.0.0.1:3075",), - ) - replicator = CultNetShardReplicator( - target.database, - CultNetShardReplicatorOptions( - fetcher=fetcher, - cursor_store=cursor_store, - batch_size=1, - poll_interval_seconds=0.01, - on_error=errors.append, - ), - ) - try: - source.database.put_raw_message(document, "note:1", {"body": "one"}, shard_id="background", shard_epoch=7) - replicator.start([shard]) - self._wait_until(lambda: target.database.get(document, "note:1") is not None) - source.database.put_raw_message(document, "note:2", {"body": "two"}, shard_id="background", shard_epoch=7) - self._wait_until(lambda: target.database.get(document, "note:2") is not None) - finally: - replicator.stop() - - cursor = cursor_store.read("background") - self.assertEqual(target.get_required(document, "note:1")["body"], "one") - self.assertEqual(target.get_required(document, "note:2")["body"], "two") - self.assertIsNotNone(cursor) - assert cursor is not None - self.assertEqual(cursor.last_applied_sequence, 2) - self.assertEqual(cursor.shard_epoch, 7) - self.assertEqual(len(errors), 1) - self.assertEqual(str(errors[0]), "transient fetch failure") - - def test_cultnet_schema_write_forwarder_sends_raw_writes_to_primary(self) -> None: - document = define_database_entry_type( - "mesh.forward_note", - [("body", 0)], - schema_id="mesh.forward_note.v1", - ) - primary = CultMesh.create_node(runtime_id="forward-primary") - primary.database.register_document(document) - server = CultMesh.serve_node(primary) - try: - shard = CultNetShardDescriptor( - shard_id="forward", - owner_runtime_id="forward-primary", - epoch=9, - is_primary=False, - schema_ids=("mesh.forward_note.v1",), - primary_endpoints=(f"cultnet://127.0.0.1:{server.port}",), - ) - forwarder: CultNetShardWriteForwarder = CultNetSchemaWriteForwarder(timeout_seconds=2.0) - put = document_put_raw( - message_id="forward-put", - key="note:forward", - schema_id=document.catalog_entry().schema_id, - stored_at="2026-06-14T00:00:00Z", - payload=document.encode_payload({"body": "forwarded"}), - ).to_wire() - delete = document_delete( - message_id="forward-delete", - schema_id=document.catalog_entry().schema_id, - record_key="note:forward", - ).to_wire() - - forwarder.forward_put(shard, put) - self._eventually(lambda: primary.database.get(document, "note:forward") is not None) - self.assertEqual(primary.database.get_required(document, "note:forward")["body"], "forwarded") - forwarder.forward_delete(shard, delete) - self._eventually(lambda: primary.database.get(document, "note:forward") is None) - - log = primary.database.build_shard_log_response(shard_id="forward", shard_epoch=9) - self.assertIsNone(primary.database.get(document, "note:forward")) - self.assertEqual([entry.change_kind for entry in log.entries], ["added", "removed"]) - self.assertEqual(log.entries[0].put["shardId"], "forward") - self.assertEqual(log.entries[1].delete["shardEpoch"], 9) - finally: - server.stop() - - def _eventually(self, predicate: Callable[[], bool], *, timeout_seconds: float = 2.0) -> None: - deadline = time.monotonic() + timeout_seconds - while time.monotonic() < deadline: - if predicate(): - return - time.sleep(0.01) - self.assertTrue(predicate()) - - def test_cultmesh_database_watchers_observe_name_and_index_changes(self) -> None: - document = define_database_entry_type( - "mesh.named_watch", - [("name", 0), ("kind", 1)], - name="name", - indexes={"kind": "kind"}, - ) - node = CultMesh.create_node(runtime_id="mesh-named-watch") - node.database.register_document(document) - name_changes: list[CultMeshDatabaseChange] = [] - index_changes: list[CultMeshDatabaseChange] = [] - - node.database.watch_by_name(document, "Potion", name_changes.append) - node.database.watch_by_index(document, "kind", "consumable", index_changes.append) - - node.database.put(document, "item:1", {"name": "Potion", "kind": "consumable"}) - node.database.put(document, "item:2", {"name": "Sword", "kind": "weapon"}) - node.database.put(document, "item:1", {"name": "Elixir", "kind": "rare"}) - node.database.delete(document, "item:1") - - self.assertEqual([change.change_kind for change in name_changes], ["added", "updated"]) - self.assertEqual([change.record_key for change in name_changes], ["item:1", "item:1"]) - self.assertEqual(name_changes[1].previous_value, {"name": "Potion", "kind": "consumable"}) - self.assertEqual([change.change_kind for change in index_changes], ["added", "updated"]) - self.assertEqual([change.record_key for change in index_changes], ["item:1", "item:1"]) - self.assertEqual(index_changes[1].value, {"name": "Elixir", "kind": "rare"}) - - def test_cultmesh_database_collection_reads_resolve_same_schema_aliases(self) -> None: - @dataclass - class CanonicalItem: - name: str - kind: str - - @dataclass - class UiItem: - name: str - kind: str - - document = define_database_entry_type( - "mesh.alias_collection_item", - [("name", 0), ("kind", 1)], - cls=CanonicalItem, - name="name", - indexes={"kind": "kind"}, - schema_id="mesh.alias_collection_item.v1", - schema_name="mesh.alias_collection_item", - schema_version="mesh.alias_collection_item.v1", - ) - alias = define_database_entry_type( - "mesh.alias_collection_item.ui", - [("name", 0), ("kind", 1)], - cls=UiItem, - name="name", - indexes={"kind": "kind"}, - schema_id="mesh.alias_collection_item.v1", - schema_name="mesh.alias_collection_item", - schema_version="mesh.alias_collection_item.v1", - ) - node = CultMesh.create_node(runtime_id="mesh-alias-collection") - node.database.register_document(document) - - node.database.put(alias, "item:potion", UiItem("Potion", "consumable")) - node.database.put(document, "item:sword", CanonicalItem("Sword", "weapon")) - - all_items = node.database.get_all(alias) - potion = node.database.get_by_name(alias, "Potion") - sword = node.get_by_index(alias, "kind", "weapon") - - self.assertEqual([item.name for item in all_items], ["Potion", "Sword"]) - self.assertTrue(all(isinstance(item, UiItem) for item in all_items)) - self.assertIsInstance(potion, UiItem) - self.assertEqual(potion.kind, "consumable") - self.assertIsInstance(sword, UiItem) - self.assertEqual(sword.name, "Sword") - self.assertIsNone(node.database.get_by_name(alias, "Missing")) - - def test_cultmesh_database_alias_collection_watches_emit_alias_values(self) -> None: - @dataclass - class CanonicalItem: - name: str - kind: str - - @dataclass - class UiItem: - name: str - kind: str - - document = define_database_entry_type( - "mesh.alias_collection_watch_item", - [("name", 0), ("kind", 1)], - cls=CanonicalItem, - name="name", - indexes={"kind": "kind"}, - schema_id="mesh.alias_collection_watch_item.v1", - schema_name="mesh.alias_collection_watch_item", - schema_version="mesh.alias_collection_watch_item.v1", - ) - alias = define_database_entry_type( - "mesh.alias_collection_watch_item.ui", - [("name", 0), ("kind", 1)], - cls=UiItem, - name="name", - indexes={"kind": "kind"}, - schema_id="mesh.alias_collection_watch_item.v1", - schema_name="mesh.alias_collection_watch_item", - schema_version="mesh.alias_collection_watch_item.v1", - ) - node = CultMesh.create_node(runtime_id="mesh-alias-collection-watch") - node.database.register_document(document) - name_changes: list[CultMeshDatabaseChange] = [] - index_changes: list[CultMeshDatabaseChange] = [] - - node.database.watch_by_name(alias, "Potion", name_changes.append) - node.database.watch_by_index(alias, "kind", "consumable", index_changes.append) - - node.database.put(document, "item:potion", CanonicalItem("Potion", "consumable")) - node.database.put(document, "item:potion", CanonicalItem("Elixir", "rare")) - - self.assertEqual([change.change_kind for change in name_changes], ["added", "updated"]) - self.assertTrue(all(change.document.type == alias.type for change in name_changes)) - self.assertIsInstance(name_changes[0].value, UiItem) - self.assertIsInstance(name_changes[1].value, UiItem) - self.assertIsInstance(name_changes[1].previous_value, UiItem) - self.assertEqual(name_changes[1].previous_value.name, "Potion") - self.assertEqual(name_changes[1].value.name, "Elixir") - self.assertEqual([change.change_kind for change in index_changes], ["added", "updated"]) - self.assertTrue(all(change.document.type == alias.type for change in index_changes)) - self.assertIsInstance(index_changes[0].value, UiItem) - self.assertIsInstance(index_changes[1].previous_value, UiItem) - - def test_cultmesh_database_watch_by_name_and_index_validate_lookup_shape(self) -> None: - document = define_database_entry_type("mesh.unnamed_watch", [("body", 0)]) - node = CultMesh.create_node(runtime_id="mesh-watch-validation") - node.database.register_document(document) - - with self.assertRaises(ValueError): - node.database.watch_by_name(document, "missing", lambda _: None) - with self.assertRaises(ValueError): - node.database.watch_by_index(document, "missing", "value", lambda _: None) - with self.assertRaises(ValueError): - node.database.watch_by_index(document, "", "value", lambda _: None) - with self.assertRaises(ValueError): - node.database.watch_by_index(document, "missing", "", lambda _: None) - - def test_cultmesh_facade_matches_peer_runtime_entrypoints(self) -> None: - with tempfile.TemporaryDirectory() as tmp: - store_path = Path(tmp) / "mesh.cc" - node = CultMesh.start_node(store_path, runtime_id="mesh-facade") - - self.assertEqual(node.runtime_id, "mesh-facade") - self.assertIsInstance(CultMesh.create_node(), type(node)) - self.assertIsInstance(CultMesh.create_verse_catalog(), CultMeshVerseCatalog) - self.assertIsInstance(CultMesh.create_peer_catalog(), CultMeshPeerCatalog) - self.assertIsInstance(CultMesh.create_authority_lease_catalog(), CultMeshAuthorityLeaseCatalog) - self.assertIsInstance(CultMesh.create_stream_catalog(), CultMeshStreamCatalog) - self.assertIsInstance(CultMesh.create_schema_catalog(), CultNetSchemaCatalog) - self.assertIsInstance(CultMesh.create_builtin_schema_catalog(), CultNetSchemaCatalog) - self.assertIsInstance(CultMesh.create_shard_catalog(), CultNetShardCatalog) - builtins = CultMesh.create_builtin_schema_catalog( - include_schema_json=False, - kinds=["shared_contract"], - ) - self.assertEqual( - builtins.list()[0].schema_id, - "https://github.com/GameCult/cultnet-ts/contracts/cultnet.transport-profile.schema.json", - ) - self.assertIsNone(builtins.list()[0].schema_json) - peer_exchange_schema_id = ( - "https://github.com/GameCult/cultnet-ts/contracts/cultmesh.peer-exchange-request.schema.json" - ) - filtered_builtin = CultMesh.create_builtin_schema_catalog( - include_schema_json=True, - schema_ids=[peer_exchange_schema_id], - ) - self.assertEqual( - filtered_builtin.list()[0].schema_version, - "cultmesh.peer_exchange_request.v0", - ) - self.assertIn( - "cultmesh.peer_exchange_request.v0", - filtered_builtin.list()[0].schema_json or "", - ) - shard_catalog = CultMesh.create_shard_catalog() - shard_catalog.upsert( - CultNetShardDescriptor( - shard_id="python-notes-a", - owner_runtime_id="mesh-facade", - epoch=7, - is_primary=True, - schema_ids=("python.note.v1",), - key_prefix="note:", - ) - ) - self.assertEqual( - [ - shard.shard_id - for shard in shard_catalog.list(schema_ids=["python.note.v1"], record_keys=["note:1"]) - ], - ["python-notes-a"], - ) - verse_client = CultMesh.create_verse_discovery_client("127.0.0.1", 4010, timeout_seconds=1.5) - peer_client = CultMesh.create_peer_exchange_client("127.0.0.1", 4011, timeout_seconds=1.5) - raw_client = CultMesh.create_client("127.0.0.1", 4012, timeout_seconds=1.5) - connected_client = CultMesh.connect_client("127.0.0.1", 4013, timeout_seconds=1.5) - self.assertIsInstance(verse_client, CultMeshVerseDiscoveryClient) - self.assertIsInstance(peer_client, CultMeshPeerExchangeClient) - self.assertIsInstance(verse_client, CultMeshDiscoveryClient) - self.assertIsInstance(peer_client, CultMeshDiscoveryClient) - self.assertIsInstance(raw_client, CultNetRawClient) - self.assertIsInstance(connected_client, CultNetRawClient) - self.assertEqual((verse_client.host, verse_client.port, verse_client.timeout_seconds), ("127.0.0.1", 4010, 1.5)) - self.assertEqual((peer_client.host, peer_client.port, peer_client.timeout_seconds), ("127.0.0.1", 4011, 1.5)) - self.assertEqual((raw_client.host, raw_client.port, raw_client.timeout_seconds), ("127.0.0.1", 4012, 1.5)) - self.assertEqual((connected_client.host, connected_client.port, connected_client.timeout_seconds), ("127.0.0.1", 4013, 1.5)) - - def test_cultmesh_simulation_fact_uses_csharp_slot_contract(self) -> None: - import msgpack # type: ignore - - candidate = { - "shardId": "arena", - "shardEpoch": 4, - "frame": 100, - "subjectId": "bob", - "claimKind": "hit", - "claimHash": compute_simulation_claim_hash("hit", "alice", "bob", "frame:100"), - "claimSummary": "alice shot bob first", - "witnessCount": 2, - "supportWeight": 2.0, - "totalWeight": 2.0, - "confidence": 1.0, - "hasQuorum": True, - } - - fact = CultMeshSimulationFact.from_candidate(candidate, committed_at="2026-06-13T00:00:00Z") - payload = simulation_fact_document.encode_payload(fact) - slots = msgpack.unpackb(payload, raw=False) - - self.assertEqual(CultMeshSimulationFact.create_record_key(candidate), f"simulation:{fact.fact_id}") - self.assertEqual(slots[0], fact.fact_id) - self.assertEqual(slots[1], "arena") - self.assertEqual(slots[2], 4) - self.assertEqual(slots[3], 100) - self.assertEqual(slots[4], "bob") - self.assertEqual(slots[5], "hit") - self.assertEqual(slots[6], candidate["claimHash"]) - self.assertEqual(slots[7], "alice shot bob first") - self.assertEqual(slots[8], 2) - self.assertEqual(slots[9], 2.0) - self.assertEqual(slots[10], 2.0) - self.assertEqual(slots[11], 1.0) - self.assertEqual(slots[12], "2026-06-13T00:00:00Z") - - def test_cultmesh_simulation_fact_committer_rejects_without_quorum_and_stores_fact(self) -> None: - candidate = { - "shardId": "arena", - "shardEpoch": 4, - "frame": 100, - "subjectId": "bob", - "claimKind": "hit", - "claimHash": compute_simulation_claim_hash("hit", "alice", "bob", "frame:100"), - "claimSummary": "alice shot bob first", - "witnessCount": 2, - "supportWeight": 2.0, - "totalWeight": 2.0, - "confidence": 1.0, - "hasQuorum": True, - } - - with tempfile.TemporaryDirectory() as tmp: - node = CultMesh.create_node(Path(tmp) / "facts.cc", runtime_id="mesh-facts") - committer = CultMesh.create_simulation_fact_committer(node) - - rejected = dict(candidate) - rejected["hasQuorum"] = False - with self.assertRaisesRegex(ValueError, "before quorum"): - committer.commit(rejected) - - committed = committer.commit(candidate, committed_at="2026-06-13T00:00:00Z") - stored = node.get_required(simulation_fact_document, committed.key) - - self.assertEqual(stored.claim_hash, candidate["claimHash"]) - self.assertEqual(stored.committed_at, "2026-06-13T00:00:00Z") - self.assertEqual(committed.fact.fact_id, stored.fact_id) - - def test_cultnet_simulation_consensus_dedupes_witnesses_and_requires_quorum(self) -> None: - from cultnet_py import CultNetSimulationConsensus - - consensus = CultNetSimulationConsensus( - CultNetSimulationConsensusOptions(minimum_witnesses=2, quorum_ratio=1.0) - ) - claim_hash = compute_simulation_claim_hash("hit", "alice", "bob", "frame:100") - observations = [ - { - "witnessRuntimeId": "watcher-1", - "shardId": "arena", - "shardEpoch": 4, - "frame": 100, - "subjectId": "bob", - "claimKind": "hit", - "claimHash": claim_hash, - "claimSummary": "alice shot bob first", - "weight": 1.0, - }, - { - "witnessRuntimeId": "watcher-1", - "shardId": "arena", - "shardEpoch": 4, - "frame": 100, - "subjectId": "bob", - "claimKind": "hit", - "claimHash": "stale-duplicate", - "weight": 0.5, - }, - { - "witnessRuntimeId": "watcher-2", - "shardId": "arena", - "shardEpoch": 4, - "frame": 100, - "subjectId": "bob", - "claimKind": "hit", - "claimHash": claim_hash, - "weight": 1.0, - }, - ] - - candidates = consensus.build_candidates(observations) - typed_candidates = consensus.build_candidate_objects([ - CultNetSimulationObservation.from_wire(observation) - for observation in observations - ]) - - self.assertEqual(len(candidates), 1) - self.assertEqual(candidates[0]["claimHash"], claim_hash) - self.assertEqual(candidates[0]["witnessCount"], 2) - self.assertEqual(candidates[0]["supportWeight"], 2.0) - self.assertTrue(candidates[0]["hasQuorum"]) - self.assertEqual(len(typed_candidates), 1) - self.assertIsInstance(typed_candidates[0], CultNetSimulationConsensusCandidate) - self.assertEqual(typed_candidates[0].claim_hash, claim_hash) - self.assertEqual(typed_candidates[0].to_wire(), candidates[0]) - self.assertEqual(CultNetSimulationConsensusCandidate.from_wire(candidates[0]), typed_candidates[0]) - - def test_cultmesh_game_session_submits_observations_and_commits_quorum_once(self) -> None: - claim_hash = compute_simulation_claim_hash("hit", "alice", "bob", "frame:100") - first = simulation_observation( - message_id="obs-1", - witness_runtime_id="watcher-1", - shard_id="arena", - shard_epoch=4, - frame=100, - subject_id="bob", - claim_kind="hit", - claim_hash=claim_hash, - claim_summary="alice shot bob first", - ).to_wire() - second = simulation_observation( - message_id="obs-2", - witness_runtime_id="watcher-2", - shard_id="arena", - shard_epoch=4, - frame=100, - subject_id="bob", - claim_kind="hit", - claim_hash=claim_hash, - claim_summary="alice shot bob first", - ).to_wire() - - with tempfile.TemporaryDirectory() as tmp: - node = CultMesh.create_node(Path(tmp) / "session.cc", runtime_id="mesh-session") - session = CultMesh.create_game_session( - node, - CultMeshGameSessionOptions( - consensus_options=CultNetSimulationConsensusOptions(minimum_witnesses=2, quorum_ratio=1.0) - ), - ) - seen_candidates: list[CultNetSimulationConsensusCandidate] = [] - seen_facts: list[CultMeshDatabaseChange] = [] - unsubscribe_candidates = session.watch_candidates(seen_candidates.append) - unsubscribe_facts = session.watch_simulation_facts(seen_facts.append) - - self.assertEqual(session.submit_and_commit(CultNetSimulationObservation.from_wire(first)), []) - typed_candidates = session.submit_observation_candidates(CultNetSimulationObservation.from_wire(second)) - commits = session.commit_quorum_candidate_objects(typed_candidates) - replay = session.commit_quorum_candidates(session.submit_observation(second)) - unsubscribe_candidates() - unsubscribe_facts() - - self.assertEqual(len(typed_candidates), 1) - self.assertTrue(typed_candidates[0].has_quorum) - self.assertEqual(len(commits), 1) - self.assertEqual(replay, []) - self.assertEqual([candidate.claim_hash for candidate in seen_candidates], [claim_hash, claim_hash, claim_hash]) - self.assertEqual(len(seen_facts), 1) - self.assertEqual(seen_facts[0].change_kind, "added") - self.assertEqual(seen_facts[0].value.claim_hash, claim_hash) - stored = node.get_required(simulation_fact_document, commits[0].key) - self.assertEqual(stored.claim_hash, claim_hash) - self.assertEqual(stored.witness_count, 2) - - def test_cultmesh_game_session_serves_catalogs_and_observations_over_wire(self) -> None: - verse_catalog = CultMeshVerseCatalog() - peer_catalog = CultMeshPeerCatalog() - verse_catalog.upsert(CultMeshVerseDescriptor( - verse_id="session-verse", - display_name="Session Verse", - authority_model="local", - compatibility=CultMeshVerseCompatibility("cultmesh.v0", "session-rules"), - )) - peer_catalog.upsert(CultMeshPeerCard( - peer_id="session-peer", - verse_id="session-verse", - endpoints=("cultnet://127.0.0.1:0",), - roles=("simulation-observer", "read-replica"), - shard_ids=("arena",), - )) - session = CultMesh.create_game_session( - CultMesh.create_node(runtime_id="session-peer"), - CultMeshGameSessionOptions( - verse_catalog=verse_catalog, - peer_catalog=peer_catalog, - consensus_options=CultNetSimulationConsensusOptions(minimum_witnesses=2, quorum_ratio=1.0), - ), - ) - server = session.serve(display_name="Session Peer") - try: - raw_client = CultMesh.create_client("127.0.0.1", server.port, timeout_seconds=2.0) - hello_response = raw_client.request( - hello(runtime_id="session-prober"), - expected_schema_version="cultnet.hello.v0", - ) - discovery_client = CultMesh.create_verse_discovery_client("127.0.0.1", server.port, timeout_seconds=2.0) - verses = discovery_client.fetch_verses(transport_version="cultmesh.v0") - peers = discovery_client.fetch_peers(verse_id="session-verse", roles=["simulation-observer"]) - claim_hash = compute_simulation_claim_hash("hit", "alice", "bob", "frame:100") - first = raw_client.request( - simulation_observation( - message_id="session-wire-1", - witness_runtime_id="watcher-1", - shard_id="arena", - shard_epoch=4, - frame=100, - subject_id="bob", - claim_kind="hit", - claim_hash=claim_hash, - claim_summary="alice shot bob first", - ), - expected_schema_version="cultnet.simulation_consensus_candidate.v0", - ) - second = raw_client.request( - simulation_observation( - message_id="session-wire-2", - witness_runtime_id="watcher-2", - shard_id="arena", - shard_epoch=4, - frame=100, - subject_id="bob", - claim_kind="hit", - claim_hash=claim_hash, - claim_summary="alice shot bob first", - ), - expected_schema_version="cultnet.simulation_consensus_candidate.v0", - ) - finally: - server.stop() - - self.assertIn("cultnet.simulation_observation.v0", hello_response["supportedMessageVersions"]) - self.assertEqual(verses[0].verse_id, "session-verse") - self.assertEqual(peers[0].peer_id, "session-peer") - self.assertIn("simulation-observer", peers[0].roles) - self.assertFalse(first["hasQuorum"]) - self.assertEqual(first["witnessCount"], 1) - self.assertTrue(second["hasQuorum"]) - self.assertEqual(second["witnessCount"], 2) - - def test_cultmesh_game_session_can_disable_served_simulation_observations(self) -> None: - verse_catalog = CultMeshVerseCatalog() - verse_catalog.upsert(CultMeshVerseDescriptor( - verse_id="session-quiet", - display_name="Quiet Session", - authority_model="local", - compatibility=CultMeshVerseCompatibility("cultmesh.v0", "quiet-rules"), - )) - session = CultMesh.create_game_session( - CultMesh.create_node(runtime_id="quiet-session-peer"), - CultMeshGameSessionOptions( - verse_catalog=verse_catalog, - serve_simulation_observations=False, - ), - ) - server = session.serve(display_name="Quiet Session Peer") - try: - raw_client = CultMesh.create_client("127.0.0.1", server.port, timeout_seconds=2.0) - hello_response = raw_client.request( - hello(runtime_id="quiet-session-prober"), - expected_schema_version="cultnet.hello.v0", - ) - discovery_client = CultMesh.create_verse_discovery_client("127.0.0.1", server.port, timeout_seconds=2.0) - verses = discovery_client.fetch_verses(transport_version="cultmesh.v0") - with self.assertRaisesRegex(CultNetPeerError, "Simulation observations are not enabled") as raised: - raw_client.request( - simulation_observation( - message_id="quiet-session-sim", - witness_runtime_id="watcher-1", - shard_id="arena", - shard_epoch=4, - frame=100, - subject_id="bob", - claim_kind="hit", - claim_hash=compute_simulation_claim_hash("hit", "alice", "bob", "frame:100"), - ), - expected_schema_version="cultnet.simulation_consensus_candidate.v0", - ) - finally: - server.stop() - - self.assertNotIn("cultnet.simulation_observation.v0", hello_response["supportedMessageVersions"]) - self.assertEqual(verses[0].verse_id, "session-quiet") - self.assertEqual(raised.exception.response["code"], "simulation_observations_disabled") - - def test_cultmesh_game_session_prediction_requires_scope_and_reconciles_shard_log(self) -> None: - note_doc = define_database_entry_type( - "mesh.input", - [("body", 0)], - schema_id="mesh.input.v1", - ) - with tempfile.TemporaryDirectory() as tmp: - node = CultMesh.create_node(Path(tmp) / "prediction.cc", runtime_id="client-a") - node.register_document(note_doc) - session = CultMesh.create_game_session( - node, - CultMeshGameSessionOptions( - client_authority_scopes=( - CultNetClientAuthorityScope( - "client-a", - schema_ids=("mesh.input.v1",), - key_prefix="input:client-a", - ), - ) - ), - ) - - with self.assertRaisesRegex(ValueError, "does not have client prediction authority"): - session.predict(note_doc, "input:other", {"body": "nope"}) - - prediction = session.predict(note_doc, "input:client-a:move", {"body": "predicted"}) - put = document_put_raw( - message_id="authoritative", - key=prediction.key, - schema_id=prediction.schema_id, - stored_at="2026-06-13T00:00:00Z", - payload=note_doc.encode_payload({"body": "authoritative"}), - shard_id="inputs", - shard_epoch=1, - ) - authoritative_response = { - "schemaVersion": "cultnet.shard_log_response.v0", - "messageId": "inputs-log", - "shardId": "inputs", - "shardEpoch": 1, - "entries": [ - { - "sequence": 1, - "committedAt": "2026-06-13T00:00:00Z", - "changeKind": "updated", - "put": put.to_wire(), - } - ], - "resyncRequired": False, - } - changes = session.apply_shard_log_response(CultNetShardLogResponse.from_wire(authoritative_response)) - - self.assertEqual(changes[0].change_kind, "reconciled") - self.assertEqual(node.get_required(note_doc, prediction.key)["body"], "authoritative") - self.assertEqual(session.pending_predictions(), ()) - self.assertEqual(session.resimulation_inputs(), ()) - - def test_cultmesh_game_session_partial_reconciliation_keeps_unmatched_predictions(self) -> None: - note_doc = define_database_entry_type( - "mesh.partial_input", - [("body", 0)], - schema_id="mesh.partial_input.v1", - ) - node = CultMesh.create_node(runtime_id="client-partial") - node.register_document(note_doc) - session = CultMesh.create_game_session( - node, - CultMeshGameSessionOptions( - client_authority_scopes=( - CultNetClientAuthorityScope( - "client-partial", - schema_ids=("mesh.partial_input.v1",), - key_prefix="input:client-partial", - ), - ) - ), - ) - pending = session.predict(note_doc, "input:client-partial:pending", {"body": "pending-local"}) - accepted = session.predict(note_doc, "input:client-partial:accepted", {"body": "accepted-local"}) - put = document_put_raw( - message_id="authoritative-partial", - key=accepted.key, - schema_id=accepted.schema_id, - stored_at="2026-06-13T00:00:00Z", - payload=note_doc.encode_payload({"body": "accepted-authority"}), - shard_id="inputs", - shard_epoch=1, - ) - - changes = session.apply_shard_log_response({ - "schemaVersion": "cultnet.shard_log_response.v0", - "messageId": "inputs-partial-log", - "shardId": "inputs", - "shardEpoch": 1, - "entries": [ - { - "sequence": 1, - "committedAt": "2026-06-13T00:00:00Z", - "changeKind": "updated", - "put": put.to_wire(), - } - ], - "resyncRequired": False, - }) - - self.assertEqual([(change.change_kind, change.record_key) for change in changes], [ - ("reconciled", accepted.key), - ]) - self.assertEqual(node.get_required(note_doc, accepted.key)["body"], "accepted-authority") - self.assertEqual(node.get_required(note_doc, pending.key)["body"], "pending-local") - self.assertEqual([prediction.key for prediction in session.pending_predictions()], [pending.key]) - self.assertEqual([prediction.key for prediction in session.resimulation_inputs()], [pending.key]) - - def test_cultmesh_game_session_rolls_back_pending_predictions(self) -> None: - note_doc = define_database_entry_type( - "mesh.rollback_input", - [("body", 0)], - schema_id="mesh.rollback_input.v1", - ) - node = CultMesh.create_node(runtime_id="client-rollback") - node.register_document(note_doc) - node.put(note_doc, "input:client-rollback:existing", {"body": "previous"}) - session = CultMesh.create_game_session( - node, - CultMeshGameSessionOptions( - client_authority_scopes=( - CultNetClientAuthorityScope( - "client-rollback", - schema_ids=("mesh.rollback_input.v1",), - key_prefix="input:client-rollback", - ), - ) - ), - ) - - existing = session.predict(note_doc, "input:client-rollback:existing", {"body": "predicted-existing"}) - created = session.predict(note_doc, "input:client-rollback:new", {"body": "predicted-new"}) - self.assertEqual( - [prediction.key for prediction in session.pending_predictions()], - ["input:client-rollback:existing", "input:client-rollback:new"], - ) - self.assertEqual([prediction.key for prediction in session.resimulation_inputs()], [ - "input:client-rollback:existing", - "input:client-rollback:new", - ]) - - restored = session.rollback_prediction(existing) - self.assertIsNotNone(restored) - assert restored is not None - self.assertEqual(restored.change_kind, "rolled_back") - self.assertEqual(restored.value, {"body": "previous"}) - self.assertEqual(node.get_required(note_doc, "input:client-rollback:existing")["body"], "previous") - - rolled_back = session.rollback_predictions() - self.assertEqual([(change.change_kind, change.record_key, change.value) for change in rolled_back], [ - ("rolled_back", created.key, None), - ]) - self.assertIsNone(node.get(note_doc, created.key)) - self.assertEqual(session.pending_predictions(), ()) - - def test_cultmesh_game_session_authoritative_delete_rolls_back_prediction(self) -> None: - note_doc = define_database_entry_type( - "mesh.deleted_input", - [("body", 0)], - schema_id="mesh.deleted_input.v1", - ) - node = CultMesh.create_node(runtime_id="client-delete") - node.register_document(note_doc) - session = CultMesh.create_game_session( - node, - CultMeshGameSessionOptions( - client_authority_scopes=( - CultNetClientAuthorityScope( - "client-delete", - schema_ids=("mesh.deleted_input.v1",), - key_prefix="input:client-delete", - ), - ) - ), - ) - - prediction = session.predict(note_doc, "input:client-delete:move", {"body": "predicted"}) - delete = document_delete( - message_id="authoritative-delete", - schema_id=prediction.schema_id, - record_key=prediction.key, - shard_id="inputs", - shard_epoch=1, - ) - changes = session.apply_shard_log_response({ - "schemaVersion": "cultnet.shard_log_response.v0", - "messageId": "inputs-delete-log", - "shardId": "inputs", - "shardEpoch": 1, - "entries": [ - { - "sequence": 1, - "committedAt": "2026-06-13T00:00:00Z", - "changeKind": "removed", - "delete": delete.to_wire(), - } - ], - "resyncRequired": False, - }) - - self.assertEqual(changes[0].change_kind, "rolled_back") - self.assertIsNone(node.get(note_doc, prediction.key)) - self.assertEqual(session.pending_predictions(), ()) - - def test_cultmesh_database_watchers_observe_authoritative_shard_log_reconciliation(self) -> None: - note_doc = define_database_entry_type( - "mesh.watched_input", - [("body", 0)], - schema_id="mesh.watched_input.v1", - ) - node = CultMesh.create_node(runtime_id="client-watch") - node.database.register_document(note_doc) - seen: list[CultMeshDatabaseChange] = [] - node.database.watch_record(note_doc, "input:client-watch:move", seen.append) - session = CultMesh.create_game_session( - node, - CultMeshGameSessionOptions( - client_authority_scopes=( - CultNetClientAuthorityScope( - "client-watch", - schema_ids=("mesh.watched_input.v1",), - key_prefix="input:client-watch", - ), - ) - ), - ) - - prediction = session.predict(note_doc, "input:client-watch:move", {"body": "predicted"}) - put = document_put_raw( - message_id="authoritative-watch", - key=prediction.key, - schema_id=prediction.schema_id, - stored_at="2026-06-13T00:00:00Z", - payload=note_doc.encode_payload({"body": "authoritative"}), - shard_id="inputs", - shard_epoch=1, - ) - session_changes = session.apply_shard_log_response({ - "schemaVersion": "cultnet.shard_log_response.v0", - "messageId": "inputs-watch-log", - "shardId": "inputs", - "shardEpoch": 1, - "entries": [ - { - "sequence": 1, - "committedAt": "2026-06-13T00:00:00Z", - "changeKind": "updated", - "put": put.to_wire(), - } - ], - "resyncRequired": False, - }) - - self.assertEqual([change.change_kind for change in seen], ["added", "updated"]) - self.assertEqual(seen[1].value, {"body": "authoritative"}) - self.assertEqual(seen[1].previous_value, {"body": "predicted"}) - self.assertEqual(session_changes[0].change_kind, "reconciled") - - def test_cultmesh_verse_catalog_response_matches_schema_v0_wire_shape(self) -> None: - import msgpack # type: ignore - - catalog = CultMeshVerseCatalog() - catalog.upsert( - CultMeshVerseDescriptor( - verse_id="aetheria-main", - display_name="Aetheria", - authority_model="OperatorCluster", - compatibility=CultMeshVerseCompatibility( - transport_version="cultmesh.v0", - rules_hash="rules", - compatible_verse_ids=("aetheria-modded",), - required_plugin_ids=("core",), - optional_plugin_ids=("skylands",), - ), - discovery_endpoints=("cultmesh://aetheria.example.test:3075",), - authority_runtime_ids=("runtime-a",), - description="main branch", - ) - ) - - response = catalog.create_response(verse_catalog_request("verses-1")) - decoded = msgpack.unpackb(msgpack.packb(response, use_bin_type=True), raw=False) - self.assertEqual(decoded["schemaVersion"], "cultmesh.verse_catalog_response.v0") - self.assertEqual(decoded["messageId"], "verses-1") - self.assertEqual(decoded["verses"][0]["verseId"], "aetheria-main") - self.assertEqual(decoded["verses"][0]["compatibility"]["requiredPluginIds"], ["core"]) - - def test_cultmesh_verse_catalog_watches_updates_and_finds_transfer_targets(self) -> None: - source = CultMeshVerseDescriptor( - verse_id="aetheria-main", - display_name="Aetheria", - authority_model="federated", - compatibility=CultMeshVerseCompatibility( - transport_version="cultmesh.v0", - rules_hash="rules-main", - ), - ) - compatible = CultMeshVerseDescriptor( - verse_id="aetheria-modded", - display_name="Aetheria Modded", - authority_model="federated", - compatibility=CultMeshVerseCompatibility( - transport_version="cultmesh.v0", - rules_hash="rules-modded", - compatible_verse_ids=("aetheria-main",), - ), - ) - incompatible = CultMeshVerseDescriptor( - verse_id="old-world", - display_name="Old World", - authority_model="solo", - compatibility=CultMeshVerseCompatibility( - transport_version="cultmesh.v0", - rules_hash="rules-old", - ), - ) - catalog = CultMeshVerseCatalog() - seen: list[str] = [] - unsubscribe = catalog.watch(lambda verse: seen.append(verse.verse_id)) - - catalog.upsert(source) - catalog.apply_response({ - "schemaVersion": "cultmesh.verse_catalog_response.v0", - "messageId": "verses-watch", - "verses": [compatible.to_wire(), incompatible.to_wire()], - }) - unsubscribe() - catalog.upsert(CultMeshVerseDescriptor( - verse_id="after-unsubscribe", - display_name="After", - authority_model="none", - compatibility=CultMeshVerseCompatibility("cultmesh.v0", "rules-after"), - )) - - self.assertEqual(seen, ["aetheria-main", "aetheria-modded", "old-world"]) - self.assertEqual([verse.verse_id for verse in catalog.verses], ["aetheria-main", "aetheria-modded", "after-unsubscribe", "old-world"]) - self.assertEqual(catalog.get("aetheria-modded"), compatible) - self.assertEqual([verse.verse_id for verse in catalog.find_transfer_targets(source)], ["aetheria-modded"]) - - def test_cultmesh_peer_exchange_response_matches_schema_v0_wire_shape(self) -> None: - import msgpack # type: ignore - - catalog = CultMeshPeerCatalog() - catalog.upsert( - CultMeshPeerCard( - peer_id="peer-a", - verse_id="aetheria-main", - endpoints=("cultnet://peer-a.example.test:3075",), - roles=("discovery", "read-replica"), - shard_ids=("players",), - region="eu-west", - authority_lease_id="lease-1", - expires_at="2026-05-20T12:00:00.0000000Z", - signature="sig", - ) - ) - - response = catalog.create_response( - peer_exchange_request("pex-1", verse_id="aetheria-main", roles=["read-replica"]) - ) - decoded = msgpack.unpackb(msgpack.packb(response, use_bin_type=True), raw=False) - self.assertEqual(decoded["schemaVersion"], "cultmesh.peer_exchange_response.v0") - self.assertEqual(decoded["messageId"], "pex-1") - self.assertEqual(decoded["peers"][0]["peerId"], "peer-a") - self.assertIn("read-replica", decoded["peers"][0]["roles"]) - self.assertEqual(decoded["peers"][0]["authorityLeaseId"], "lease-1") - - def test_cultmesh_peer_catalog_watches_updates_and_gets_peers(self) -> None: - first = CultMeshPeerCard( - peer_id="peer-a", - verse_id="aetheria-main", - endpoints=("cultnet://peer-a.example.test:3075",), - roles=("discovery", "read-replica"), - ) - second = CultMeshPeerCard( - peer_id="peer-b", - verse_id="aetheria-main", - endpoints=("cultnet://peer-b.example.test:3075",), - roles=("shard-primary",), - ) - catalog = CultMeshPeerCatalog() - seen: list[str] = [] - unsubscribe = catalog.watch(lambda peer: seen.append(peer.peer_id)) - - catalog.upsert(first) - catalog.apply_response({ - "schemaVersion": "cultmesh.peer_exchange_response.v0", - "messageId": "peers-watch", - "peers": [second.to_wire()], - }) - unsubscribe() - catalog.upsert(CultMeshPeerCard( - peer_id="peer-c", - verse_id="aetheria-main", - endpoints=("cultnet://peer-c.example.test:3075",), - roles=("read-replica",), - )) - - self.assertEqual(seen, ["peer-a", "peer-b"]) - self.assertTrue(first.has_role("read-replica")) - self.assertEqual([peer.peer_id for peer in catalog.peers], ["peer-a", "peer-b", "peer-c"]) - self.assertEqual(catalog.get("peer-b"), second) - self.assertEqual([peer.peer_id for peer in catalog.find("aetheria-main", role="read-replica")], ["peer-a", "peer-c"]) - - def test_cultmesh_discovery_client_fetches_typed_catalogs_over_cultnet_frames(self) -> None: - import msgpack # type: ignore - from cultnet_py import read_frame, write_frame - - verses = CultMeshVerseCatalog() - verses.upsert( - CultMeshVerseDescriptor( - verse_id="aetheria-main", - display_name="Aetheria", - authority_model="federated", - compatibility=CultMeshVerseCompatibility( - transport_version="cultmesh.v0", - rules_hash="rules-1", - required_plugin_ids=("core",), - ), - discovery_endpoints=("cultmesh://aetheria.example.test:3075",), - authority_runtime_ids=("runtime-a",), - ) - ) - peers = CultMeshPeerCatalog() - peers.upsert( - CultMeshPeerCard( - peer_id="peer-a", - verse_id="aetheria-main", - endpoints=("cultnet://peer-a.example.test:3075",), - roles=("read-replica",), - shard_ids=("players",), - ) - ) - - ready = threading.Event() - server_error: list[BaseException] = [] - - def serve_requests() -> None: - try: - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server: - server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - server.bind(("127.0.0.1", 0)) - port_holder.append(server.getsockname()[1]) - server.listen(8) - ready.set() - for _ in range(8): - connection, _ = server.accept() - with connection: - stream = connection.makefile("rwb") - request = msgpack.unpackb(read_frame(stream), raw=False) - if request["schemaVersion"] == "cultmesh.verse_catalog_request.v0": - response = verses.create_response(request) - elif request["schemaVersion"] == "cultmesh.peer_exchange_request.v0": - response = peers.create_response(request) - else: - raise AssertionError(f"unexpected request {request['schemaVersion']}") - write_frame(stream, msgpack.packb(response, use_bin_type=True)) - stream.flush() - except BaseException as error: - server_error.append(error) - ready.set() - - port_holder: list[int] = [] - thread = threading.Thread(target=serve_requests, daemon=True) - thread.start() - self.assertTrue(ready.wait(2.0)) - self.assertFalse(server_error) - - client = CultMeshDiscoveryClient("127.0.0.1", port_holder[0], timeout_seconds=2.0) - fetched_verses = client.fetch_verses(transport_version="cultmesh.v0") - fetched_peers = client.fetch_peers(verse_id="aetheria-main", roles=["read-replica"]) - local_verses = CultMeshVerseCatalog() - local_peers = CultMeshPeerCatalog() - synced_verses = client.sync_verse_catalog(local_verses, transport_version="cultmesh.v0") - synced_peers = client.sync_peer_catalog(local_peers, verse_id="aetheria-main", roles=["read-replica"]) - discovered_verses = CultMeshVerseCatalog() - discovered_peers = CultMeshPeerCatalog() - endpoint = f"cultnet://127.0.0.1:{port_holder[0]}" - verse_discovery = CultMeshVerseDiscoveryClient.from_endpoint(endpoint, timeout_seconds=2.0) - peer_discovery = CultMeshPeerExchangeClient.from_endpoint(endpoint, timeout_seconds=2.0) - discovered_verse_count = verse_discovery.discover( - discovered_verses, - endpoints=[endpoint, endpoint, ""], - transport_version="cultmesh.v0", - ) - discovered_peer_count = peer_discovery.discover( - discovered_peers, - verse_id="aetheria-main", - endpoints=[endpoint, endpoint, ""], - roles=["read-replica"], - ) - fanout_verses = CultMeshVerseCatalog() - fanout_verses.upsert( - CultMeshVerseDescriptor( - verse_id="aetheria-main", - display_name="Known Aetheria", - authority_model="federated", - compatibility=CultMeshVerseCompatibility("cultmesh.v0", "rules-1"), - discovery_endpoints=(endpoint, endpoint, ""), - ) - ) - fanout_peers = CultMeshPeerCatalog() - fanout_peers.upsert( - CultMeshPeerCard( - peer_id="known-peer", - verse_id="aetheria-main", - endpoints=(endpoint, endpoint, ""), - roles=("read-replica",), - ) - ) - fanout_verse_count = verse_discovery.fanout(fanout_verses, transport_version="cultmesh.v0") - fanout_peer_count = peer_discovery.fanout( - fanout_peers, - verse_id="aetheria-main", - roles=["read-replica"], - ) - - thread.join(2.0) - self.assertFalse(server_error) - self.assertEqual(fetched_verses[0].verse_id, "aetheria-main") - self.assertEqual(fetched_verses[0].compatibility.required_plugin_ids, ("core",)) - self.assertEqual(fetched_peers[0].peer_id, "peer-a") - self.assertEqual(fetched_peers[0].shard_ids, ("players",)) - self.assertEqual(synced_verses[0].verse_id, "aetheria-main") - self.assertEqual(local_peers.find("aetheria-main", role="read-replica")[0].peer_id, "peer-a") - self.assertEqual(synced_peers[0].roles, ("read-replica",)) - self.assertEqual(discovered_verse_count, 1) - self.assertEqual(discovered_peer_count, 1) - self.assertEqual(discovered_verses.get("aetheria-main").display_name, "Aetheria") - self.assertEqual(discovered_peers.find("aetheria-main", role="read-replica")[0].peer_id, "peer-a") - self.assertEqual(fanout_verse_count, 1) - self.assertEqual(fanout_peer_count, 1) - self.assertEqual(fanout_verses.get("aetheria-main").display_name, "Aetheria") - self.assertIn( - "peer-a", - {peer.peer_id for peer in fanout_peers.find("aetheria-main", role="read-replica")}, - ) - - def test_cultmesh_discovery_client_fans_out_simulation_observations_to_peers(self) -> None: - first_hub = CultNetSimulationObservationHub( - CultNetSimulationConsensusOptions(minimum_witnesses=1, quorum_ratio=1.0) - ) - second_hub = CultNetSimulationObservationHub( - CultNetSimulationConsensusOptions(minimum_witnesses=1, quorum_ratio=1.0) - ) - first_server = CultMesh.serve_node( - CultMesh.create_node(runtime_id="sim-peer-a"), - observation_hub=first_hub, - ) - second_server = CultMesh.serve_node( - CultMesh.create_node(runtime_id="sim-peer-b"), - observation_hub=second_hub, - ) - try: - peers = CultMeshPeerCatalog() - peers.upsert(CultMeshPeerCard( - peer_id="sim-peer-a", - verse_id="arena", - endpoints=(f"cultnet://127.0.0.1:{first_server.port}",), - roles=("simulation-witness",), - )) - peers.upsert(CultMeshPeerCard( - peer_id="sim-peer-b", - verse_id="arena", - endpoints=(f"cultnet://127.0.0.1:{second_server.port}",), - roles=("simulation-witness",), - )) - claim_hash = compute_simulation_claim_hash("hit", "alice", "bob", "frame:200") - message = simulation_observation( - message_id="fanout-observation", - witness_runtime_id="python-fanout", - shard_id="arena", - shard_epoch=1, - frame=200, - subject_id="bob", - claim_kind="hit", - claim_hash=claim_hash, - claim_summary="alice hit bob", - ).to_wire() - - client = CultMeshDiscoveryClient("127.0.0.1", first_server.port, timeout_seconds=2.0) - candidates = client.fanout_simulation_observation( - peers, - message, - verse_id="arena", - roles=["simulation-witness"], - ) - finally: - first_server.stop() - second_server.stop() - - self.assertEqual([candidate["schemaVersion"] for candidate in candidates], [ - "cultnet.simulation_consensus_candidate.v0", - "cultnet.simulation_consensus_candidate.v0", - ]) - self.assertEqual({candidate["claimHash"] for candidate in candidates}, {claim_hash}) - self.assertEqual({candidate["messageId"] for candidate in candidates}, {"fanout-observation"}) - self.assertEqual({candidate["hasQuorum"] for candidate in candidates}, {True}) - - def test_cultmesh_simulation_observation_fanout_flushes_queued_messages(self) -> None: - hub = CultNetSimulationObservationHub( - CultNetSimulationConsensusOptions(minimum_witnesses=1, quorum_ratio=1.0) - ) - server = CultMesh.serve_node(CultMesh.create_node(runtime_id="sim-flush-peer"), observation_hub=hub) - try: - peers = CultMeshPeerCatalog() - peers.upsert(CultMeshPeerCard( - peer_id="sim-flush-peer", - verse_id="arena", - endpoints=(f"cultnet://127.0.0.1:{server.port}",), - roles=("simulation-witness",), - )) - claim_hash = compute_simulation_claim_hash("hit", "alice", "bob", "frame:210") - seen_candidates: list[dict[str, object]] = [] - fanout = CultMeshSimulationObservationFanout( - CultMeshDiscoveryClient("127.0.0.1", server.port, timeout_seconds=2.0), - peers, - verse_id="arena", - roles=["simulation-witness"], - on_candidate=seen_candidates.append, - ) - fanout.enqueue(simulation_observation( - message_id="queued-observation", - witness_runtime_id="python-fanout", - shard_id="arena", - shard_epoch=1, - frame=210, - subject_id="bob", - claim_kind="hit", - claim_hash=claim_hash, - claim_summary="alice hit bob", - ).to_wire()) - - candidates = fanout.flush() - finally: - server.stop() - - self.assertEqual(fanout.pending_count(), 0) - self.assertEqual([candidate["claimHash"] for candidate in candidates], [claim_hash]) - self.assertEqual(seen_candidates[0]["messageId"], "queued-observation") - - def test_cultmesh_simulation_observation_fanout_keeps_failed_messages_pending(self) -> None: - closed_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - closed_socket.bind(("127.0.0.1", 0)) - closed_port = closed_socket.getsockname()[1] - closed_socket.close() - peers = CultMeshPeerCatalog() - peers.upsert(CultMeshPeerCard( - peer_id="closed-simulation-peer", - verse_id="arena", - endpoints=(f"cultnet://127.0.0.1:{closed_port}",), - roles=("simulation-witness",), - )) - errors: list[tuple[str, str]] = [] - fanout = CultMeshSimulationObservationFanout( - CultMeshDiscoveryClient("127.0.0.1", closed_port, timeout_seconds=0.2), - peers, - verse_id="arena", - roles=["simulation-witness"], - on_error=lambda endpoint, error: errors.append((endpoint, str(error))), - ) - fanout.enqueue(simulation_observation( - message_id="retry-observation", - witness_runtime_id="python-fanout", - shard_id="arena", - shard_epoch=1, - frame=212, - subject_id="bob", - claim_kind="miss", - claim_hash=compute_simulation_claim_hash("miss", "alice", "bob", "frame:212"), - claim_summary="alice missed bob", - ).to_wire()) - - candidates = fanout.flush() - - self.assertEqual(candidates, []) - self.assertEqual(fanout.pending_count(), 1) - self.assertEqual(len(errors), 1) - self.assertIn(f"127.0.0.1:{closed_port}", errors[0][0]) - - def test_cultmesh_simulation_observation_fanout_runs_background_loop(self) -> None: - hub = CultNetSimulationObservationHub( - CultNetSimulationConsensusOptions(minimum_witnesses=1, quorum_ratio=1.0) - ) - server = CultMesh.serve_node(CultMesh.create_node(runtime_id="sim-loop-peer"), observation_hub=hub) - try: - peers = CultMeshPeerCatalog() - peers.upsert(CultMeshPeerCard( - peer_id="sim-loop-peer", - verse_id="arena", - endpoints=(f"cultnet://127.0.0.1:{server.port}",), - roles=("simulation-witness",), - )) - claim_hash = compute_simulation_claim_hash("block", "dana", "eve", "frame:211") - seen_candidates: list[dict[str, object]] = [] - fanout = CultMeshSimulationObservationFanout( - CultMeshDiscoveryClient("127.0.0.1", server.port, timeout_seconds=2.0), - peers, - verse_id="arena", - roles=["simulation-witness"], - interval_seconds=0.05, - on_candidate=seen_candidates.append, - ) - fanout.start() - fanout.enqueue(simulation_observation( - message_id="loop-observation", - witness_runtime_id="python-fanout", - shard_id="arena", - shard_epoch=1, - frame=211, - subject_id="eve", - claim_kind="block", - claim_hash=claim_hash, - claim_summary="dana blocked eve", - ).to_wire()) - deadline = time.monotonic() + 2.0 - while not seen_candidates and time.monotonic() < deadline: - time.sleep(0.01) - fanout.stop() - finally: - server.stop() - - self.assertEqual(fanout.pending_count(), 0) - self.assertTrue(seen_candidates) - self.assertEqual(seen_candidates[0]["claimHash"], claim_hash) - self.assertEqual(seen_candidates[0]["messageId"], "loop-observation") - - def test_cultmesh_discovery_client_fans_out_snapshots_to_peers(self) -> None: - document = define_database_entry_type( - "mesh.snapshot_fanout_note", - [("body", 0)], - schema_id="mesh.snapshot_fanout_note.v1", - ) - first = CultMesh.create_node(runtime_id="snapshot-peer-a") - first.database.register_document(document) - first.database.put_raw_message(document, "note:a", {"body": "from-a"}, shard_id="notes", shard_epoch=1) - second = CultMesh.create_node(runtime_id="snapshot-peer-b") - second.database.register_document(document) - second.database.put_raw_message(document, "note:b", {"body": "from-b"}, shard_id="notes", shard_epoch=1) - target = CultMesh.create_node(runtime_id="snapshot-target") - target.database.register_document(document) - first_server = CultMesh.serve_node(first) - second_server = CultMesh.serve_node(second) - try: - peers = CultMeshPeerCatalog() - peers.upsert(CultMeshPeerCard( - peer_id="snapshot-peer-a", - verse_id="mesh", - endpoints=(f"cultnet://127.0.0.1:{first_server.port}", f"cultnet://127.0.0.1:{first_server.port}"), - roles=("read-replica",), - )) - peers.upsert(CultMeshPeerCard( - peer_id="snapshot-peer-b", - verse_id="mesh", - endpoints=(f"cultnet://127.0.0.1:{second_server.port}",), - roles=("read-replica",), - )) - - client = CultMeshDiscoveryClient("127.0.0.1", first_server.port, timeout_seconds=2.0) - responses = client.fanout_snapshot_responses( - peers, - verse_id="mesh", - roles=["read-replica"], - schema_ids=["mesh.snapshot_fanout_note.v1"], - ) - applied = client.sync_snapshots( - target.database, - peers, - verse_id="mesh", - roles=["read-replica"], - schema_ids=["mesh.snapshot_fanout_note.v1"], - ) - finally: - first_server.stop() - second_server.stop() - - self.assertEqual(len(responses), 2) - self.assertTrue(all(isinstance(response, CultNetRawSnapshotResponse) for response in responses)) - self.assertEqual( - sorted(record.record_key for response in responses for record in response.documents), - ["note:a", "note:b"], - ) - self.assertEqual(sorted(record.record_key for record in applied), ["note:a", "note:b"]) - self.assertEqual(target.database.get_required(document, "note:a")["body"], "from-a") - self.assertEqual(target.database.get_required(document, "note:b")["body"], "from-b") - - def test_cultmesh_discovery_client_sync_documents_returns_requested_aliases(self) -> None: - @dataclass - class CanonicalNote: - body: str - - @dataclass - class UiNote: - body: str - - document = define_database_entry_type( - "mesh.snapshot_fanout_alias_note", - [("body", 0)], - cls=CanonicalNote, - schema_id="mesh.snapshot_fanout_alias_note.v1", - schema_name="mesh.snapshot_fanout_alias_note", - schema_version="mesh.snapshot_fanout_alias_note.v1", - ) - alias = define_database_entry_type( - "mesh.snapshot_fanout_alias_note.ui", - [("body", 0)], - cls=UiNote, - schema_id="mesh.snapshot_fanout_alias_note.v1", - schema_name="mesh.snapshot_fanout_alias_note", - schema_version="mesh.snapshot_fanout_alias_note.v1", - ) - source = CultMesh.create_node(runtime_id="snapshot-alias-source") - source.database.register_document(document) - source.database.put_raw_message(document, "note:alias", CanonicalNote("from-source")) - target = CultMesh.create_node(runtime_id="snapshot-alias-target") - target.database.register_document(document) - server = CultMesh.serve_node(source) - try: - peers = CultMeshPeerCatalog() - peers.upsert(CultMeshPeerCard( - peer_id="snapshot-alias-source", - verse_id="mesh", - endpoints=(f"cultnet://127.0.0.1:{server.port}",), - roles=("read-replica",), - )) - - values = CultMeshDiscoveryClient("127.0.0.1", server.port, timeout_seconds=2.0).sync_documents( - target.database, - peers, - verse_id="mesh", - roles=["read-replica"], - documents=[(alias, "note:alias")], - ) - finally: - server.stop() - - self.assertEqual(len(values), 1) - self.assertIsInstance(values[0], UiNote) - self.assertEqual(values[0].body, "from-source") - self.assertEqual(target.database.get_required(document, "note:alias").body, "from-source") - self.assertIsInstance(target.database.get_required(alias, "note:alias"), UiNote) - - def test_cultmesh_document_subscription_syncs_alias_snapshot_and_changes(self) -> None: - @dataclass - class CanonicalNote: - body: str - - @dataclass - class UiNote: - body: str - - document = define_database_entry_type( - "mesh.subscription_alias_note", - [("body", 0)], - cls=CanonicalNote, - schema_id="mesh.subscription_alias_note.v1", - schema_name="mesh.subscription_alias_note", - schema_version="mesh.subscription_alias_note.v1", - ) - alias = define_database_entry_type( - "mesh.subscription_alias_note.ui", - [("body", 0)], - cls=UiNote, - schema_id="mesh.subscription_alias_note.v1", - schema_name="mesh.subscription_alias_note", - schema_version="mesh.subscription_alias_note.v1", - ) - source = CultMesh.create_node(runtime_id="subscription-alias-source") - source.database.register_document(document) - source.database.put_raw_message(document, "note:live", CanonicalNote("initial")) - target = CultMesh.create_node(runtime_id="subscription-alias-target") - target.database.register_document(document) - server = CultMesh.serve_node(source) - try: - raw_client = CultMesh.create_client("127.0.0.1", server.port, timeout_seconds=2.0) - with CultMesh.subscribe_document(target, raw_client, alias, "note:live") as subscription: - initial = subscription.sync_initial() - subscription.send(document_put_raw( - message_id="subscription-alias-put", - key="note:live", - schema_id="mesh.subscription_alias_note.v1", - stored_at="2026-06-14T00:00:00Z", - payload=document.encode_payload(CanonicalNote("updated")), - )) - updated = subscription.read_next_change() - subscription.send(document_delete( - message_id="subscription-alias-delete", - schema_id="mesh.subscription_alias_note.v1", - record_key="note:live", - )) - removed = subscription.read_next_change() - finally: - server.stop() - - self.assertIsInstance(initial, UiNote) - self.assertEqual(initial.body, "initial") - self.assertEqual(updated.change_kind, "updated") - self.assertIsInstance(updated.value, UiNote) - self.assertEqual(updated.value.body, "updated") - self.assertIsInstance(updated.previous_value, UiNote) - self.assertEqual(updated.previous_value.body, "initial") - self.assertEqual(removed.change_kind, "removed") - self.assertIsNone(removed.value) - self.assertIsInstance(removed.previous_value, UiNote) - self.assertEqual(removed.previous_value.body, "updated") - self.assertIsNone(target.database.get(alias, "note:live")) - - def test_cultmesh_snapshot_fanout_syncs_once_and_reports_applied_records(self) -> None: - document = define_database_entry_type( - "mesh.snapshot_loop_note", - [("body", 0)], - schema_id="mesh.snapshot_loop_note.v1", - ) - source = CultMesh.create_node(runtime_id="snapshot-loop-source") - source.database.register_document(document) - source.database.put_raw_message(document, "note:sync-once", {"body": "from-source"}) - target = CultMesh.create_node(runtime_id="snapshot-loop-target") - target.database.register_document(document) - server = CultMesh.serve_node(source) - try: - peers = CultMeshPeerCatalog() - peers.upsert(CultMeshPeerCard( - peer_id="snapshot-loop-source", - verse_id="mesh", - endpoints=(f"cultnet://127.0.0.1:{server.port}",), - roles=("read-replica",), - )) - seen: list[str] = [] - fanout = CultMeshSnapshotFanout( - CultMeshDiscoveryClient("127.0.0.1", server.port, timeout_seconds=2.0), - target.database, - peers, - verse_id="mesh", - roles=["read-replica"], - schema_ids=["mesh.snapshot_loop_note.v1"], - on_applied=lambda record: seen.append(record.record_key), - ) - - applied = fanout.sync_once() - finally: - server.stop() - - self.assertEqual([record.record_key for record in applied], ["note:sync-once"]) - self.assertEqual(seen, ["note:sync-once"]) - self.assertEqual(target.database.get_required(document, "note:sync-once")["body"], "from-source") - - def test_cultmesh_snapshot_fanout_syncs_typed_documents_and_reports_alias_values(self) -> None: - @dataclass - class CanonicalNote: - body: str - - @dataclass - class UiNote: - body: str - - document = define_database_entry_type( - "mesh.snapshot_loop_alias_note", - [("body", 0)], - cls=CanonicalNote, - schema_id="mesh.snapshot_loop_alias_note.v1", - schema_name="mesh.snapshot_loop_alias_note", - schema_version="mesh.snapshot_loop_alias_note.v1", - ) - alias = define_database_entry_type( - "mesh.snapshot_loop_alias_note.ui", - [("body", 0)], - cls=UiNote, - schema_id="mesh.snapshot_loop_alias_note.v1", - schema_name="mesh.snapshot_loop_alias_note", - schema_version="mesh.snapshot_loop_alias_note.v1", - ) - source = CultMesh.create_node(runtime_id="snapshot-loop-alias-source") - source.database.register_document(document) - source.database.put_raw_message(document, "note:typed-loop", CanonicalNote("from-source")) - target = CultMesh.create_node(runtime_id="snapshot-loop-alias-target") - target.database.register_document(document) - server = CultMesh.serve_node(source) - try: - peers = CultMeshPeerCatalog() - peers.upsert(CultMeshPeerCard( - peer_id="snapshot-loop-alias-source", - verse_id="mesh", - endpoints=(f"cultnet://127.0.0.1:{server.port}",), - roles=("read-replica",), - )) - seen: list[UiNote] = [] - fanout = CultMeshSnapshotFanout( - CultMeshDiscoveryClient("127.0.0.1", server.port, timeout_seconds=2.0), - target.database, - peers, - verse_id="mesh", - roles=["read-replica"], - documents=[(alias, "note:typed-loop")], - on_document=seen.append, - ) - - values = fanout.sync_once() - finally: - server.stop() - - self.assertEqual(len(values), 1) - self.assertIsInstance(values[0], UiNote) - self.assertEqual(values[0].body, "from-source") - self.assertEqual(seen, [values[0]]) - self.assertEqual(target.database.get_required(document, "note:typed-loop").body, "from-source") - self.assertIsInstance(target.database.get_required(alias, "note:typed-loop"), UiNote) - - def test_cultmesh_snapshot_fanout_runs_background_loop(self) -> None: - document = define_database_entry_type( - "mesh.snapshot_background_note", - [("body", 0)], - schema_id="mesh.snapshot_background_note.v1", - ) - source = CultMesh.create_node(runtime_id="snapshot-background-source") - source.database.register_document(document) - source.database.put_raw_message(document, "note:background", {"body": "from-background"}) - target = CultMesh.create_node(runtime_id="snapshot-background-target") - target.database.register_document(document) - server = CultMesh.serve_node(source) - try: - peers = CultMeshPeerCatalog() - peers.upsert(CultMeshPeerCard( - peer_id="snapshot-background-source", - verse_id="mesh", - endpoints=(f"cultnet://127.0.0.1:{server.port}",), - roles=("read-replica",), - )) - seen: list[str] = [] - fanout = CultMeshSnapshotFanout( - CultMeshDiscoveryClient("127.0.0.1", server.port, timeout_seconds=2.0), - target.database, - peers, - verse_id="mesh", - roles=["read-replica"], - schema_ids=["mesh.snapshot_background_note.v1"], - interval_seconds=0.05, - on_applied=lambda record: seen.append(record.record_key), - ) - fanout.start() - deadline = time.monotonic() + 2.0 - while not seen and time.monotonic() < deadline: - time.sleep(0.01) - fanout.stop() - finally: - server.stop() - - self.assertTrue(seen) - self.assertEqual(target.database.get_required(document, "note:background")["body"], "from-background") - - def test_cultmesh_peer_health_monitor_probes_reachable_and_failed_endpoints(self) -> None: - document = define_database_entry_type( - "mesh.health_note", - [("body", 0)], - schema_id="mesh.health_note.v1", - ) - node = CultMesh.create_node(runtime_id="health-peer") - node.database.register_document(document) - server = CultMesh.serve_node(node) - closed_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - closed_socket.bind(("127.0.0.1", 0)) - closed_port = closed_socket.getsockname()[1] - closed_socket.close() - try: - peers = CultMeshPeerCatalog() - peers.upsert(CultMeshPeerCard( - peer_id="health-peer", - verse_id="mesh", - endpoints=(f"cultnet://127.0.0.1:{server.port}",), - roles=("read-replica",), - )) - peers.upsert(CultMeshPeerCard( - peer_id="closed-peer", - verse_id="mesh", - endpoints=(f"cultnet://127.0.0.1:{closed_port}",), - roles=("read-replica",), - )) - seen: list[tuple[str, bool]] = [] - monitor = CultMeshPeerHealthMonitor( - runtime_id="health-prober", - timeout_seconds=0.2, - on_update=lambda health: seen.append((health.peer_id, health.is_reachable)), - ) - - results = monitor.probe_catalog(peers, verse_id="mesh", roles=["read-replica"]) - finally: - server.stop() - - by_peer = {result.peer_id: result for result in results} - self.assertTrue(by_peer["health-peer"].is_reachable) - self.assertEqual(by_peer["health-peer"].runtime_id, "health-peer") - self.assertEqual(by_peer["health-peer"].runtime_kind, "python") - self.assertEqual(by_peer["health-peer"].display_name, "health-peer") - self.assertEqual(by_peer["health-peer"].supported_document_types, ("mesh.health_note",)) - self.assertIn("cultnet.hello.v0", by_peer["health-peer"].supported_message_versions) - self.assertIn("cultnet.error.v0", by_peer["health-peer"].supported_message_versions) - self.assertEqual(by_peer["health-peer"].supported_mutation_contracts[0]["documentType"], "mesh.health_note") - self.assertIn("shardLog", by_peer["health-peer"].supported_mutation_contracts[0]["operations"]) - self.assertFalse(by_peer["closed-peer"].is_reachable) - self.assertIsNone(by_peer["closed-peer"].runtime_kind) - self.assertEqual(by_peer["closed-peer"].supported_document_types, ()) - self.assertEqual(by_peer["closed-peer"].supported_message_versions, ()) - self.assertEqual(by_peer["closed-peer"].supported_mutation_contracts, ()) - self.assertTrue(by_peer["closed-peer"].error) - self.assertEqual({peer_id for peer_id, _ in seen}, {"health-peer", "closed-peer"}) - self.assertEqual(len(monitor.latest()), 2) - - def test_cultmesh_peer_health_monitor_runs_background_probe_loop(self) -> None: - server = CultMesh.serve_node(CultMesh.create_node(runtime_id="health-loop-peer")) - try: - peers = CultMeshPeerCatalog() - peers.upsert(CultMeshPeerCard( - peer_id="health-loop-peer", - verse_id="mesh", - endpoints=(f"cultnet://127.0.0.1:{server.port}",), - roles=("read-replica",), - )) - seen: list[str] = [] - monitor = CultMeshPeerHealthMonitor( - runtime_id="health-loop-prober", - timeout_seconds=0.2, - interval_seconds=0.05, - on_update=lambda health: seen.append(health.peer_id), - ) - monitor.start(peers, verse_id="mesh", roles=["read-replica"]) - deadline = time.monotonic() + 2.0 - while time.monotonic() < deadline: - latest = monitor.latest() - if latest and latest[0].is_reachable: - break - time.sleep(0.01) - monitor.stop() - finally: - server.stop() - - self.assertTrue(seen) - latest = monitor.latest() - self.assertEqual(latest[0].peer_id, "health-loop-peer") - self.assertTrue(latest[0].is_reachable) - - def test_cultmesh_daemon_entrypoint_serves_framed_cultnet_hello(self) -> None: - with tempfile.TemporaryDirectory() as temp: - ready_path = Path(temp) / "ready.json" - package_src = Path(__file__).resolve().parents[1] / "src" - env = dict(os.environ) - existing_pythonpath = env.get("PYTHONPATH") - env["PYTHONPATH"] = ( - str(package_src) - if not existing_pythonpath - else f"{package_src}{os.pathsep}{existing_pythonpath}" - ) - process = subprocess.Popen( - [ - sys.executable, - "-m", - "cultmesh_py.daemon", - "--runtime-id", - "daemon-test-peer", - "--display-name", - "Daemon Test Peer", - "--port", - "0", - "--ready-file", - str(ready_path), - "--seed-interop-note", - "--seed-shard-id", - "daemon-interop", - "--verse-id", - "daemon-verse", - "--verse-display-name", - "Daemon Verse", - "--role", - "shard-primary", - ], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True, - env=env, - ) - try: - deadline = time.monotonic() + 5.0 - while not ready_path.exists() and time.monotonic() < deadline: - if process.poll() is not None: - break - time.sleep(0.05) - if not ready_path.exists(): - _, stderr = process.communicate(timeout=2.0) - self.fail(f"cultmesh daemon did not publish readiness: {stderr}") - ready = json.loads(ready_path.read_text(encoding="utf-8")) - self.assertEqual(ready["schemaVersion"], READY_SCHEMA_VERSION) - self.assertEqual(ready["runtimeId"], "daemon-test-peer") - self.assertEqual(ready["runtimeKind"], "python") - self.assertEqual(ready["displayName"], "Daemon Test Peer") - self.assertEqual(ready["endpoint"], f"cultnet://127.0.0.1:{ready['port']}") - self.assertEqual(ready["shardIds"], ["daemon-interop"]) - self.assertEqual(ready["supportedDocumentTypes"], ["cultcache.interop-note"]) - self.assertIn("cultnet.hello.v0", ready["supportedMessageVersions"]) - self.assertIn("cultnet.document_put_raw.v0", ready["supportedMessageVersions"]) - self.assertNotIn("cultnet.simulation_observation.v0", ready["supportedMessageVersions"]) - self.assertEqual(ready["supportedMutationContracts"][0]["documentType"], "cultcache.interop-note") - self.assertIn("shardLog", ready["supportedMutationContracts"][0]["operations"]) - self.assertEqual(ready["snapshotLimits"], {"maxSnapshotBytes": None, "maxSnapshotDocuments": None}) - self.assertEqual(ready["verses"][0]["verseId"], "daemon-verse") - self.assertEqual(ready["verses"][0]["displayName"], "Daemon Verse") - self.assertEqual(ready["verses"][0]["discoveryEndpoints"], [ready["endpoint"]]) - self.assertEqual(ready["verses"][0]["authorityRuntimeIds"], ["daemon-test-peer"]) - self.assertEqual(ready["peers"][0]["peerId"], "daemon-test-peer") - self.assertEqual(ready["peers"][0]["endpoints"], [ready["endpoint"]]) - self.assertEqual(ready["peers"][0]["roles"], ["shard-primary"]) - self.assertEqual(ready["peers"][0]["shardIds"], ["daemon-interop"]) - - client = CultMesh.create_client("127.0.0.1", int(ready["port"]), timeout_seconds=2.0) - hello_response = client.request( - hello(runtime_id="daemon-test-prober"), - expected_schema_version="cultnet.hello.v0", - ) - - self.assertEqual(hello_response["runtimeId"], "daemon-test-peer") - self.assertEqual(hello_response["displayName"], "Daemon Test Peer") - self.assertIn("cultnet.hello.v0", hello_response["supportedMessageVersions"]) - self.assertIn("cultnet.schema_catalog_request.v0", hello_response["supportedMessageVersions"]) - self.assertNotIn("cultnet.simulation_observation.v0", hello_response["supportedMessageVersions"]) - self.assertEqual(hello_response["supportedDocumentTypes"], ["cultcache.interop-note"]) - self.assertEqual(hello_response["transportProfiles"][0]["transports"][0]["protocol"], "tcp_framed") - self.assertEqual(hello_response["transportProfiles"][0]["transports"][0]["port"], int(ready["port"])) - self.assertEqual(ready["supportedMessageVersions"], hello_response["supportedMessageVersions"]) - self.assertEqual(ready["supportedMutationContracts"], hello_response["supportedMutationContracts"]) - self.assertEqual(ready["transportProfiles"], hello_response["transportProfiles"]) - - schema_response = client.fetch_schema_catalog(schema_ids=["cultcache.interop-note"], include_schema_json=True) - self.assertEqual(schema_response["schemas"][0]["schemaVersion"], INTEROP_SCHEMA_VERSION) - self.assertEqual(schema_response["schemas"][0]["documentType"], "cultcache.interop-note") - - snapshot_response = client.fetch_snapshot_response(schema_ids=["cultcache.interop-note"]) - self.assertEqual(snapshot_response.documents[0].record_key, "note:daemon-test-peer") - note = interop_note_document.decode_payload(snapshot_response.documents[0].payload) - self.assertEqual(note["authorRuntimeId"], "daemon-test-peer") - self.assertIn("daemon", note["tags"]) - - shard_catalog = client.fetch_shard_catalog(schema_ids=["cultcache.interop-note"]) - self.assertEqual(shard_catalog["shards"][0]["shardId"], "daemon-interop") - self.assertEqual(shard_catalog["shards"][0]["schemaIds"], ["cultcache.interop-note"]) - - shard_log = client.fetch_shard_log_response(shard_id="daemon-interop", shard_epoch=1) - self.assertFalse(shard_log.resync_required) - self.assertEqual(shard_log.entries[0].sequence, 1) - self.assertEqual(shard_log.entries[0].change_kind, "added") - self.assertIsNotNone(shard_log.entries[0].raw_document) - assert shard_log.entries[0].raw_document is not None - self.assertEqual(shard_log.entries[0].raw_document.record_key, "note:daemon-test-peer") - - discovery_client = CultMesh.create_verse_discovery_client("127.0.0.1", int(ready["port"]), timeout_seconds=2.0) - verses = discovery_client.fetch_verses(transport_version="cultmesh.v0") - self.assertEqual(verses[0].verse_id, "daemon-verse") - self.assertEqual(verses[0].display_name, "Daemon Verse") - self.assertEqual(verses[0].discovery_endpoints, (ready["endpoint"],)) - self.assertEqual(verses[0].authority_runtime_ids, ("daemon-test-peer",)) - self.assertEqual([verse.to_wire() for verse in verses], ready["verses"]) - - peers = discovery_client.fetch_peers(verse_id="daemon-verse", roles=["shard-primary"]) - self.assertEqual(peers[0].peer_id, "daemon-test-peer") - self.assertEqual(peers[0].endpoints, (ready["endpoint"],)) - self.assertEqual(peers[0].roles, ("shard-primary",)) - self.assertEqual(peers[0].shard_ids, ("daemon-interop",)) - self.assertEqual([peer.to_wire() for peer in peers], ready["peers"]) - - monitor = CultMeshPeerHealthMonitor(runtime_id="daemon-health-prober", timeout_seconds=2.0) - health = monitor.probe_peer(peers[0])[0] - self.assertTrue(health.is_reachable) - self.assertEqual(health.runtime_id, "daemon-test-peer") - self.assertEqual(health.supported_document_types, ("cultcache.interop-note",)) - self.assertEqual(health.supported_mutation_contracts[0]["documentType"], "cultcache.interop-note") - finally: - process.terminate() - try: - process.communicate(timeout=5.0) - except subprocess.TimeoutExpired: - process.kill() - process.communicate(timeout=5.0) - - def test_cultmesh_daemon_restarts_with_persisted_cache_and_shard_log(self) -> None: - with tempfile.TemporaryDirectory() as temp: - root = Path(temp) - cache_path = root / "mesh.cc" - shard_log_path = root / "shard-log" - env = dict(os.environ) - package_src = Path(__file__).resolve().parents[1] / "src" - existing_pythonpath = env.get("PYTHONPATH") - env["PYTHONPATH"] = ( - str(package_src) - if not existing_pythonpath - else f"{package_src}{os.pathsep}{existing_pythonpath}" - ) - - first_ready = root / "first-ready.json" - first = subprocess.Popen( - [ - sys.executable, - "-m", - "cultmesh_py.daemon", - "--runtime-id", - "durable-daemon-peer", - "--port", - "0", - "--cache-file", - str(cache_path), - "--enable-durable-shard-logs", - "--shard-log-file", - str(shard_log_path), - "--seed-interop-note", - "--seed-shard-id", - "durable-interop", - "--ready-file", - str(first_ready), - ], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True, - env=env, - ) - try: - self._wait_for_ready_file(first, first_ready) - finally: - self._terminate_process(first) - - second_ready = root / "second-ready.json" - second = subprocess.Popen( - [ - sys.executable, - "-m", - "cultmesh_py.daemon", - "--runtime-id", - "durable-daemon-peer", - "--port", - "0", - "--cache-file", - str(cache_path), - "--enable-durable-shard-logs", - "--shard-log-file", - str(shard_log_path), - "--register-interop-note", - "--verse-id", - "durable-verse", - "--role", - "shard-primary", - "--ready-file", - str(second_ready), - ], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True, - env=env, - ) - try: - ready = self._wait_for_ready_file(second, second_ready) - client = CultMesh.create_client("127.0.0.1", int(ready["port"]), timeout_seconds=2.0) - - snapshot_response = client.fetch_snapshot_response(schema_ids=["cultcache.interop-note"]) - self.assertEqual(snapshot_response.documents[0].record_key, "note:durable-daemon-peer") - note = interop_note_document.decode_payload(snapshot_response.documents[0].payload) - self.assertEqual(note["authorRuntimeId"], "durable-daemon-peer") - - shard_log = client.fetch_shard_log_response(shard_id="durable-interop", shard_epoch=1) - self.assertFalse(shard_log.resync_required) - self.assertEqual(shard_log.entries[0].sequence, 1) - self.assertIsNotNone(shard_log.entries[0].raw_document) - assert shard_log.entries[0].raw_document is not None - self.assertEqual(shard_log.entries[0].raw_document.record_key, "note:durable-daemon-peer") - - discovery_client = CultMesh.create_verse_discovery_client("127.0.0.1", int(ready["port"]), timeout_seconds=2.0) - peers = discovery_client.fetch_peers(verse_id="durable-verse", roles=["shard-primary"]) - self.assertEqual(peers[0].shard_ids, ("durable-interop",)) - finally: - self._terminate_process(second) - - def test_cultmesh_daemon_serves_live_database_subscription_mutations(self) -> None: - with tempfile.TemporaryDirectory() as temp: - ready_path = Path(temp) / "ready.json" - package_src = Path(__file__).resolve().parents[1] / "src" - env = dict(os.environ) - existing_pythonpath = env.get("PYTHONPATH") - env["PYTHONPATH"] = ( - str(package_src) - if not existing_pythonpath - else f"{package_src}{os.pathsep}{existing_pythonpath}" - ) - process = subprocess.Popen( - [ - sys.executable, - "-m", - "cultmesh_py.daemon", - "--runtime-id", - "live-daemon-peer", - "--port", - "0", - "--seed-interop-note", - "--seed-shard-id", - "live-interop", - "--ready-file", - str(ready_path), - ], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True, - env=env, - ) - try: - ready = self._wait_for_ready_file(process, ready_path) - client = CultMesh.create_client("127.0.0.1", int(ready["port"]), timeout_seconds=2.0) - live_note = { - "schemaVersion": INTEROP_SCHEMA_VERSION, - "documentId": "note:daemon-live", - "authorRuntimeId": "daemon-live-client", - "title": "daemon live subscription note", - "body": "live subscription put from Python daemon smoke", - "tags": ["daemon", "subscription", "interop"], - } - - with client.subscribe_database( - subscription_id="daemon-live-sub", - schema_ids=["cultcache.interop-note"], - ) as subscription: - snapshot = subscription.read_next_snapshot_response() - subscription.send(document_put_raw( - message_id="daemon-live-put", - key="note:daemon-live", - schema_id="cultcache.interop-note", - stored_at="2026-06-14T00:00:00Z", - payload=interop_note_document.encode_payload(live_note), - source_runtime_id="daemon-live-client", - shard_id="live-interop", - shard_epoch=1, - )) - change = subscription.read_next_change() - - self.assertEqual(snapshot.documents[0].record_key, "note:live-daemon-peer") - self.assertEqual(change.change_kind, "added") - self.assertEqual(change.record_key, "note:daemon-live") - self.assertIsNotNone(change.raw_document) - assert change.raw_document is not None - self.assertEqual( - interop_note_document.decode_payload(change.raw_document.payload), - live_note, - ) - - shard_log = client.fetch_shard_log_response(shard_id="live-interop", shard_epoch=1) - self.assertFalse(shard_log.resync_required) - self.assertEqual([entry.sequence for entry in shard_log.entries], [1, 2]) - self.assertEqual(shard_log.entries[1].change_kind, "added") - self.assertIsNotNone(shard_log.entries[1].raw_document) - assert shard_log.entries[1].raw_document is not None - self.assertEqual(shard_log.entries[1].raw_document.record_key, "note:daemon-live") - finally: - self._terminate_process(process) - - def test_cultmesh_daemon_serves_compacted_shard_log_resync_boundary(self) -> None: - with tempfile.TemporaryDirectory() as temp: - root = Path(temp) - cache_path = root / "mesh.cc" - shard_log_path = root / "shard-log" - store = CultNetFileShardMutationLogStore(shard_log_path) - node = CultMesh.create_node( - cache_path, - runtime_id="compacted-daemon-peer", - enable_durable_shard_logs=True, - shard_log_path=shard_log_path, - ) - node.database.register_document(interop_note_document) - node.database.put_raw_message( - interop_note_document, - "note:compacted-one", - { - "schemaVersion": INTEROP_SCHEMA_VERSION, - "documentId": "note:compacted-one", - "authorRuntimeId": "compacted-daemon-peer", - "title": "compacted daemon note one", - "body": "first retained cache value", - "tags": ["daemon", "compaction"], - }, - message_id="compacted-put-1", - shard_id="compacted-interop", - shard_epoch=7, - ) - node.database.put_raw_message( - interop_note_document, - "note:compacted-two", - { - "schemaVersion": INTEROP_SCHEMA_VERSION, - "documentId": "note:compacted-two", - "authorRuntimeId": "compacted-daemon-peer", - "title": "compacted daemon note two", - "body": "second retained cache value", - "tags": ["daemon", "compaction"], - }, - message_id="compacted-put-2", - shard_id="compacted-interop", - shard_epoch=7, - ) - store.compact_through("compacted-interop", 1) - - ready_path = root / "ready.json" - package_src = Path(__file__).resolve().parents[1] / "src" - env = dict(os.environ) - existing_pythonpath = env.get("PYTHONPATH") - env["PYTHONPATH"] = ( - str(package_src) - if not existing_pythonpath - else f"{package_src}{os.pathsep}{existing_pythonpath}" - ) - process = subprocess.Popen( - [ - sys.executable, - "-m", - "cultmesh_py.daemon", - "--runtime-id", - "compacted-daemon-peer", - "--port", - "0", - "--cache-file", - str(cache_path), - "--enable-durable-shard-logs", - "--shard-log-file", - str(shard_log_path), - "--register-interop-note", - "--ready-file", - str(ready_path), - ], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True, - env=env, - ) - try: - ready = self._wait_for_ready_file(process, ready_path) - client = CultMesh.create_client("127.0.0.1", int(ready["port"]), timeout_seconds=2.0) - - snapshot_response = client.fetch_snapshot_response(schema_ids=["cultcache.interop-note"]) - self.assertEqual( - {document.record_key for document in snapshot_response.documents}, - {"note:compacted-one", "note:compacted-two"}, - ) - - compacted = client.fetch_shard_log_response( - shard_id="compacted-interop", - shard_epoch=7, - after_sequence=0, - ) - retained = client.fetch_shard_log_response( - shard_id="compacted-interop", - shard_epoch=7, - after_sequence=1, - ) - - self.assertTrue(compacted.resync_required) - self.assertEqual(compacted.reason, "compacted_history") - self.assertEqual(compacted.compacted_through, 1) - self.assertEqual(compacted.entries, ()) - self.assertFalse(retained.resync_required) - self.assertEqual([entry.sequence for entry in retained.entries], [2]) - self.assertIsNotNone(retained.entries[0].raw_document) - assert retained.entries[0].raw_document is not None - self.assertEqual(retained.entries[0].raw_document.record_key, "note:compacted-two") - finally: - self._terminate_process(process) - - def test_cultmesh_daemon_accepts_schema_write_forwarder_mutations(self) -> None: - with tempfile.TemporaryDirectory() as temp: - ready_path = Path(temp) / "ready.json" - package_src = Path(__file__).resolve().parents[1] / "src" - env = dict(os.environ) - existing_pythonpath = env.get("PYTHONPATH") - env["PYTHONPATH"] = ( - str(package_src) - if not existing_pythonpath - else f"{package_src}{os.pathsep}{existing_pythonpath}" - ) - process = subprocess.Popen( - [ - sys.executable, - "-m", - "cultmesh_py.daemon", - "--runtime-id", - "forwarder-daemon-peer", - "--port", - "0", - "--register-interop-note", - "--ready-file", - str(ready_path), - ], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True, - env=env, - ) - try: - ready = self._wait_for_ready_file(process, ready_path) - endpoint = f"cultnet://127.0.0.1:{ready['port']}" - shard = CultNetShardDescriptor( - shard_id="forwarded-interop", - owner_runtime_id="forwarder-daemon-peer", - epoch=3, - is_primary=False, - schema_ids=("cultcache.interop-note",), - primary_endpoints=(endpoint,), - ) - forwarder: CultNetShardWriteForwarder = CultNetSchemaWriteForwarder(timeout_seconds=2.0) - note = { - "schemaVersion": INTEROP_SCHEMA_VERSION, - "documentId": "note:forwarded-daemon", - "authorRuntimeId": "forwarding-client", - "title": "forwarded daemon note", - "body": "forwarded through the schema write-forwarder", - "tags": ["daemon", "forwarded"], - } - - forwarder.forward_put(shard, document_put_raw( - message_id="forwarded-daemon-put", - key="note:forwarded-daemon", - schema_id="cultcache.interop-note", - stored_at="2026-06-14T00:00:00Z", - payload=interop_note_document.encode_payload(note), - source_runtime_id="forwarding-client", - ).to_wire()) - - client = CultMesh.create_client("127.0.0.1", int(ready["port"]), timeout_seconds=2.0) - self._eventually(lambda: bool(client.fetch_snapshot_response( - schema_ids=["cultcache.interop-note"], - record_keys=["note:forwarded-daemon"], - ).documents)) - snapshot = client.fetch_snapshot_response( - schema_ids=["cultcache.interop-note"], - record_keys=["note:forwarded-daemon"], - ) - self.assertEqual( - interop_note_document.decode_payload(snapshot.documents[0].payload), - note, - ) - - forwarder.forward_delete(shard, document_delete( - message_id="forwarded-daemon-delete", - schema_id="cultcache.interop-note", - record_key="note:forwarded-daemon", - ).to_wire()) - self._eventually(lambda: not client.fetch_snapshot_response( - schema_ids=["cultcache.interop-note"], - record_keys=["note:forwarded-daemon"], - ).documents) - - shard_log = client.fetch_shard_log_response(shard_id="forwarded-interop", shard_epoch=3) - self.assertEqual([entry.change_kind for entry in shard_log.entries], ["added", "removed"]) - self.assertEqual(shard_log.entries[0].put["shardId"], "forwarded-interop") - self.assertEqual(shard_log.entries[0].put["shardEpoch"], 3) - self.assertEqual(shard_log.entries[1].delete["shardId"], "forwarded-interop") - self.assertEqual(shard_log.entries[1].delete["shardEpoch"], 3) - finally: - self._terminate_process(process) - - def test_cultmesh_daemon_enforces_snapshot_document_limit_as_peer_error(self) -> None: - with tempfile.TemporaryDirectory() as temp: - ready_path = Path(temp) / "ready.json" - package_src = Path(__file__).resolve().parents[1] / "src" - env = dict(os.environ) - existing_pythonpath = env.get("PYTHONPATH") - env["PYTHONPATH"] = ( - str(package_src) - if not existing_pythonpath - else f"{package_src}{os.pathsep}{existing_pythonpath}" - ) - process = subprocess.Popen( - [ - sys.executable, - "-m", - "cultmesh_py.daemon", - "--runtime-id", - "limited-daemon-peer", - "--port", - "0", - "--seed-interop-note", - "--max-snapshot-documents", - "0", - "--ready-file", - str(ready_path), - ], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True, - env=env, - ) - try: - ready = self._wait_for_ready_file(process, ready_path) - self.assertEqual(ready["snapshotLimits"], {"maxSnapshotBytes": None, "maxSnapshotDocuments": 0}) - client = CultMesh.create_client("127.0.0.1", int(ready["port"]), timeout_seconds=2.0) - - with self.assertRaisesRegex(CultNetPeerError, "Snapshot document limit exceeded") as raised: - client.fetch_snapshot_response(schema_ids=["cultcache.interop-note"]) - - self.assertEqual(raised.exception.response["schemaVersion"], "cultnet.error.v0") - self.assertEqual(raised.exception.response["code"], "snapshot_document_limit_exceeded") - self.assertEqual(raised.exception.response["details"]["documentCount"], 1) - self.assertEqual(raised.exception.response["details"]["maxSnapshotDocuments"], 0) - finally: - self._terminate_process(process) - - def test_cultmesh_daemon_serves_opt_in_simulation_observations(self) -> None: - with tempfile.TemporaryDirectory() as temp: - ready_path = Path(temp) / "ready.json" - package_src = Path(__file__).resolve().parents[1] / "src" - env = dict(os.environ) - existing_pythonpath = env.get("PYTHONPATH") - env["PYTHONPATH"] = ( - str(package_src) - if not existing_pythonpath - else f"{package_src}{os.pathsep}{existing_pythonpath}" - ) - process = subprocess.Popen( - [ - sys.executable, - "-m", - "cultmesh_py.daemon", - "--runtime-id", - "simulation-daemon-peer", - "--port", - "0", - "--enable-simulation-observations", - "--simulation-minimum-witnesses", - "2", - "--simulation-quorum-ratio", - "1.0", - "--verse-id", - "simulation-verse", - "--ready-file", - str(ready_path), - ], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True, - env=env, - ) - try: - ready = self._wait_for_ready_file(process, ready_path) - self.assertIn("cultnet.simulation_observation.v0", ready["supportedMessageVersions"]) - self.assertIn("cultnet.simulation_consensus_candidate.v0", ready["supportedMessageVersions"]) - client = CultMesh.create_client("127.0.0.1", int(ready["port"]), timeout_seconds=2.0) - hello_response = client.request( - hello(runtime_id="simulation-daemon-prober"), - expected_schema_version="cultnet.hello.v0", - ) - self.assertEqual(ready["supportedMessageVersions"], hello_response["supportedMessageVersions"]) - discovery_client = CultMesh.create_verse_discovery_client("127.0.0.1", int(ready["port"]), timeout_seconds=2.0) - peers = discovery_client.fetch_peers(verse_id="simulation-verse", roles=["simulation-observer"]) - self.assertEqual(peers[0].peer_id, "simulation-daemon-peer") - self.assertIn("simulation-observer", peers[0].roles) - self.assertIn("read-replica", peers[0].roles) - - claim_hash = compute_simulation_claim_hash("hit", "alice", "bob", "frame:100") - first = client.request( - simulation_observation( - message_id="daemon-sim-1", - witness_runtime_id="watcher-1", - shard_id="arena", - shard_epoch=4, - frame=100, - subject_id="bob", - claim_kind="hit", - claim_hash=claim_hash, - claim_summary="alice shot bob first", - ), - expected_schema_version="cultnet.simulation_consensus_candidate.v0", - ) - second = client.request( - simulation_observation( - message_id="daemon-sim-2", - witness_runtime_id="watcher-2", - shard_id="arena", - shard_epoch=4, - frame=100, - subject_id="bob", - claim_kind="hit", - claim_hash=claim_hash, - claim_summary="alice shot bob first", - ), - expected_schema_version="cultnet.simulation_consensus_candidate.v0", - ) - - self.assertEqual(first["messageId"], "daemon-sim-1") - self.assertFalse(first["hasQuorum"]) - self.assertEqual(first["witnessCount"], 1) - self.assertEqual(second["messageId"], "daemon-sim-2") - self.assertTrue(second["hasQuorum"]) - self.assertEqual(second["witnessCount"], 2) - self.assertEqual(second["claimHash"], claim_hash) - finally: - self._terminate_process(process) - - def _wait_for_ready_file(self, process: subprocess.Popen[str], ready_path: Path) -> dict[str, object]: - deadline = time.monotonic() + 5.0 - while not ready_path.exists() and time.monotonic() < deadline: - if process.poll() is not None: - break - time.sleep(0.05) - if not ready_path.exists(): - _, stderr = process.communicate(timeout=2.0) - self.fail(f"cultmesh daemon did not publish readiness: {stderr}") - return json.loads(ready_path.read_text(encoding="utf-8")) - - def _terminate_process(self, process: subprocess.Popen[str]) -> None: - process.terminate() - try: - process.communicate(timeout=5.0) - except subprocess.TimeoutExpired: - process.kill() - process.communicate(timeout=5.0) - - def test_cultmesh_local_server_serves_node_and_catalogs_over_clients(self) -> None: - document = define_database_entry_type( - "mesh.server_note", - [("body", 0)], - schema_id="mesh.server_note.v1", - ) - node = CultMesh.create_node(runtime_id="mesh-server") - node.database.register_document(document) - node.database.put_raw_message(document, "note:1", {"body": "served"}, shard_id="notes", shard_epoch=1) - observation_hub = CultNetSimulationObservationHub( - CultNetSimulationConsensusOptions(minimum_witnesses=2, quorum_ratio=1.0) - ) - seen_candidates: list[CultNetSimulationConsensusCandidate] = [] - unsubscribe_candidates = observation_hub.watch_candidates(seen_candidates.append) - claim_hash = compute_simulation_claim_hash("hit", "alice", "bob", "frame:100") - verses = CultMeshVerseCatalog() - verses.upsert( - CultMeshVerseDescriptor( - verse_id="server-verse", - display_name="Server Verse", - authority_model="local", - compatibility=CultMeshVerseCompatibility("cultmesh.v0", "rules"), - ) - ) - peers = CultMeshPeerCatalog() - peers.upsert( - CultMeshPeerCard( - peer_id="mesh-server", - verse_id="server-verse", - endpoints=("cultnet://127.0.0.1:0",), - roles=("read-replica",), - ) - ) - - server = CultMesh.serve_node( - node, - verse_catalog=verses, - peer_catalog=peers, - observation_hub=observation_hub, - display_name="Mesh Server", - ) - try: - raw_client = CultMesh.create_client("127.0.0.1", server.port, timeout_seconds=2.0) - hello_response = raw_client.request(hello(runtime_id="probe"), expected_schema_version="cultnet.hello.v0") - schema_response = raw_client.fetch_schema_catalog(schema_ids=["mesh.server_note.v1"], include_schema_json=True) - rudp_client = CultMesh.create_client( - endpoint=f"rudp://127.0.0.1:{server.port}", - timeout_seconds=2.0, - connection_id=server.rudp_connection_id, - runtime_id="rudp-probe", - ) - rudp_hello_response = rudp_client.request( - hello(runtime_id="rudp-probe"), - expected_schema_version="cultnet.hello.v0", - ) - rudp_schema_response = rudp_client.fetch_schema_catalog( - schema_ids=["mesh.server_note.v1"], - include_schema_json=True, - ) - wire_schema_response = raw_client.fetch_schema_catalog(kinds=["wire_message"], include_schema_json=True) - synced_schema_catalog = CultNetSchemaCatalog() - synced_wire_descriptors = raw_client.sync_schema_catalog( - synced_schema_catalog, - kinds=["wire_message"], - include_schema_json=True, - ) - snapshot_response = raw_client.fetch_snapshot(schema_ids=["mesh.server_note.v1"]) - typed_snapshot_response = raw_client.fetch_snapshot_response(schema_ids=["mesh.server_note.v1"]) - shard_catalog = raw_client.fetch_shard_catalog(schema_ids=["mesh.server_note.v1"]) - synced_shard_catalog = CultNetShardCatalog() - synced_shards = raw_client.sync_shard_catalog(synced_shard_catalog, schema_ids=["mesh.server_note.v1"]) - shard_log = raw_client.fetch_shard_log(shard_id="notes", shard_epoch=1) - typed_shard_log = raw_client.fetch_shard_log_response(shard_id="notes", shard_epoch=1) - self.assertEqual(hello_response["transportProfiles"][0]["transports"][0]["protocol"], "tcp_framed") - self.assertEqual(hello_response["transportProfiles"][0]["transports"][0]["port"], server.port) - stale_shard_log = raw_client.fetch_shard_log(shard_id="notes", shard_epoch=0) - discovery_client = CultMesh.create_verse_discovery_client("127.0.0.1", server.port, timeout_seconds=2.0) - fetched_verses = discovery_client.fetch_verses(transport_version="cultmesh.v0") - fetched_peers = discovery_client.fetch_peers(verse_id="server-verse", roles=["read-replica"]) - first_candidate = raw_client.request( - simulation_observation( - message_id="obs-1", - witness_runtime_id="watcher-1", - shard_id="arena", - shard_epoch=4, - frame=100, - subject_id="bob", - claim_kind="hit", - claim_hash=claim_hash, - claim_summary="alice shot bob first", - ), - expected_schema_version="cultnet.simulation_consensus_candidate.v0", - ) - quorum_candidate = raw_client.request( - simulation_observation( - message_id="obs-2", - witness_runtime_id="watcher-2", - shard_id="arena", - shard_epoch=4, - frame=100, - subject_id="bob", - claim_kind="hit", - claim_hash=claim_hash, - claim_summary="alice shot bob first", - ), - expected_schema_version="cultnet.simulation_consensus_candidate.v0", - ) - with raw_client.subscribe_database(subscription_id="sub-server", schema_ids=["mesh.server_note.v1"]) as subscription: - subscription_snapshot = subscription.read_next_snapshot_response() - subscription.send(document_put_raw( - message_id="server-put", - key="note:2", - schema_id="mesh.server_note.v1", - stored_at="2026-06-14T00:00:00Z", - payload=document.encode_payload({"body": "subscribed"}), - shard_id="primary", - shard_epoch=1, - )) - subscription_change = subscription.read_next_change() - subscription.send(document_delete( - message_id="server-delete", - schema_id="mesh.server_note.v1", - record_key="note:2", - shard_id="primary", - shard_epoch=1, - )) - subscription_delete = subscription.read_next_change() - finally: - unsubscribe_candidates() - server.stop() - - self.assertEqual(hello_response["runtimeId"], "mesh-server") - self.assertEqual(hello_response["displayName"], "Mesh Server") - self.assertIn("cultnet.database_subscribe.v0", hello_response["supportedMessageVersions"]) - self.assertIn("cultnet.error.v0", hello_response["supportedMessageVersions"]) - self.assertIn("cultnet.document_put_raw.v0", hello_response["supportedMessageVersions"]) - self.assertIn("cultnet.simulation_observation.v0", hello_response["supportedMessageVersions"]) - self.assertEqual(hello_response["supportedMutationContracts"][0]["documentType"], "mesh.server_note") - self.assertIn("documentDelete", hello_response["supportedMutationContracts"][0]["operations"]) - self.assertIn("shardLog", hello_response["supportedMutationContracts"][0]["operations"]) - advertised_transports = { - transport["protocol"]: transport - for profile in hello_response["transportProfiles"] - for transport in profile["transports"] - } - self.assertEqual(advertised_transports["tcp_framed"]["port"], server.port) - self.assertEqual(advertised_transports["rudp"]["port"], server.port) - self.assertEqual(rudp_hello_response["runtimeId"], "mesh-server") - self.assertEqual(rudp_schema_response["schemas"][0]["schemaId"], "mesh.server_note.v1") - self.assertEqual(schema_response["schemas"][0]["schemaId"], "mesh.server_note.v1") - self.assertIn("schemaJson", schema_response["schemas"][0]) - self.assertIn("cultnet.document_delete.v0", schema_response["schemas"][0]["wireContracts"]) - self.assertIn("cultnet.shard_log_response.v0", schema_response["schemas"][0]["wireContracts"]) - wire_descriptors = {schema["schemaVersion"]: schema for schema in wire_schema_response["schemas"]} - self.assertEqual(wire_descriptors["cultnet.error.v0"]["kind"], "wire_message") - self.assertEqual(wire_descriptors["cultnet.document_put_raw.v0"]["kind"], "wire_message") - self.assertIn("schemaJson", wire_descriptors["cultnet.document_put_raw.v0"]) - self.assertIn("cultmesh.peer_exchange_response.v0", wire_descriptors) - self.assertIn("cultnet.error.v0", {descriptor.schema_version for descriptor in synced_wire_descriptors}) - self.assertIn("cultnet.document_put_raw.v0", {descriptor.schema_version for descriptor in synced_wire_descriptors}) - self.assertIsNotNone(synced_schema_catalog.get("https://github.com/GameCult/cultnet-ts/contracts/cultnet.document-put-raw.schema.json")) - self.assertEqual(snapshot_response["documents"][0]["recordKey"], "note:1") - self.assertEqual(typed_snapshot_response.documents[0].record_key, "note:1") - self.assertEqual(typed_snapshot_response.documents[0].schema_id, "mesh.server_note.v1") - self.assertEqual(shard_catalog["shards"][0]["schemaIds"], ["mesh.server_note.v1"]) - self.assertEqual(shard_catalog["shards"][0]["epoch"], 1) - self.assertEqual(shard_catalog["shards"][0]["shardId"], "notes") - self.assertEqual(synced_shards[0].shard_id, "notes") - self.assertEqual(synced_shards[0].epoch, 1) - self.assertEqual(synced_shard_catalog.get("notes"), synced_shards[0]) - self.assertEqual(shard_log["entries"][0]["changeKind"], "added") - self.assertTrue(stale_shard_log["resyncRequired"]) - self.assertEqual(stale_shard_log["reason"], "stale_epoch") - self.assertEqual(stale_shard_log["shardEpoch"], 1) - self.assertEqual(stale_shard_log["entries"], []) - self.assertEqual(typed_shard_log.last_sequence, 1) - self.assertEqual(typed_shard_log.entries[0].put["document"]["recordKey"], "note:1") - self.assertIsInstance(typed_shard_log.entries[0].raw_document, CultNetRawDocumentRecord) - self.assertEqual(typed_shard_log.entries[0].raw_document.record_key, "note:1") - self.assertEqual(fetched_verses[0].verse_id, "server-verse") - self.assertEqual(fetched_peers[0].peer_id, "mesh-server") - self.assertEqual(first_candidate["messageId"], "obs-1") - self.assertFalse(first_candidate["hasQuorum"]) - self.assertEqual(quorum_candidate["messageId"], "obs-2") - self.assertEqual(quorum_candidate["claimHash"], claim_hash) - self.assertTrue(quorum_candidate["hasQuorum"]) - self.assertEqual(quorum_candidate["witnessCount"], 2) - self.assertEqual([candidate.claim_hash for candidate in seen_candidates], [claim_hash, claim_hash]) - self.assertIsInstance(subscription_snapshot, CultNetRawSnapshotResponse) - self.assertEqual(subscription_snapshot.to_wire()["schemaVersion"], "cultnet.snapshot_response_raw.v0") - self.assertEqual(subscription_change.change_kind, "added") - self.assertEqual(subscription_change.record_key, "note:2") - self.assertEqual(subscription_change.document["recordKey"], "note:2") - self.assertIsInstance(subscription_change.raw_document, CultNetRawDocumentRecord) - self.assertEqual(subscription_change.raw_document.schema_id, "mesh.server_note.v1") - self.assertEqual(subscription_delete.change_kind, "removed") - self.assertEqual(subscription_delete.record_key, "note:2") - self.assertIsNone(subscription_delete.raw_document) - self.assertIsNone(node.database.get(document, "note:2")) - - def test_cultmesh_local_server_resolves_snapshot_and_shard_catalog_schema_aliases(self) -> None: - document = define_database_entry_type( - "mesh.alias_server_note", - [("body", 0)], - schema_id="sha256:mesh-alias-server-note", - schema_name="mesh.alias_server_note", - schema_version="mesh.alias_server_note.v1", - ) - node = CultMesh.create_node(runtime_id="mesh-alias-server") - node.database.register_document(document) - node.database.put_raw_message( - document, - "note:alias", - {"body": "served through alias"}, - shard_id="notes", - shard_epoch=1, - ) - - server = CultMesh.serve_node(node) - try: - raw_client = CultMesh.create_client("127.0.0.1", server.port, timeout_seconds=2.0) - snapshot = raw_client.fetch_snapshot(schema_ids=["mesh.alias_server_note.v1"]) - typed_snapshot = raw_client.fetch_snapshot_response(schema_ids=["mesh.alias_server_note.v1"]) - shard_catalog = raw_client.fetch_shard_catalog(schema_ids=["mesh.alias_server_note.v1"]) - finally: - server.stop() - - local_schema_id = document.catalog_entry().schema_id - self.assertEqual(snapshot["documents"][0]["schemaId"], local_schema_id) - self.assertEqual(snapshot["documents"][0]["recordKey"], "note:alias") - self.assertEqual(typed_snapshot.documents[0].schema_id, local_schema_id) - self.assertEqual(shard_catalog["shards"][0]["schemaIds"], [local_schema_id]) - self.assertEqual(shard_catalog["shards"][0]["shardId"], "notes") - - def test_cultmesh_shard_snapshot_keeps_foreign_schema_alias_membership(self) -> None: - document = define_database_entry_type( - "mesh.alias_shard_note", - [ - ("schema_version", 0), - ("body", 1), - ], - schema_id="sha256:mesh-alias-shard-note", - schema_name="mesh.alias_shard_note", - schema_version="mesh.alias_shard_note.v1", - ) - node = CultMesh.create_node(runtime_id="mesh-alias-shard-server") - node.database.register_document(document) - - node.database.apply_raw_put_message(document_put_raw( - message_id="put-foreign-shard-alias", - key="note:foreign-shard", - schema_id="runtime.generated.mesh.alias_shard_note.ui.99", - stored_at="2026-06-27T00:00:00Z", - payload=document.encode_payload({ - "schema_version": "mesh.alias_shard_note.v1", - "body": "visible through shard snapshot", - }), - shard_id="notes", - shard_epoch=1, - ).to_wire()) - node.database.put_raw_message( - document, - "note:other-shard", - { - "schema_version": "mesh.alias_shard_note.v1", - "body": "hidden by shard filter", - }, - shard_id="other", - shard_epoch=1, - ) - - response = node.database.build_snapshot_response( - schema_ids=["mesh.alias_shard_note.v1"], - shard_id="notes", - shard_epoch=1, - ) - - local_schema_id = document.catalog_entry().schema_id - self.assertEqual(response.shard_id, "notes") - self.assertEqual(response.shard_epoch, 1) - self.assertEqual([(record.schema_id, record.record_key) for record in response.documents], [ - (local_schema_id, "note:foreign-shard"), - ]) - self.assertEqual(node.cache.get_required_envelope(document, "note:foreign-shard").schema_id, local_schema_id) - - node.database.apply_raw_delete_message(document_delete( - message_id="delete-foreign-shard-alias", - schema_id="mesh.alias_shard_note.v1", - record_key="note:foreign-shard", - shard_id="notes", - shard_epoch=1, - ).to_wire()) - deleted_response = node.database.build_snapshot_response( - schema_ids=["mesh.alias_shard_note.v1"], - shard_id="notes", - shard_epoch=1, - ) - self.assertEqual(deleted_response.documents, ()) - - def test_cultmesh_local_server_notifies_schema_alias_subscription_for_raw_put(self) -> None: - document = define_database_entry_type( - "mesh.alias_sub_note", - [ - ("schema_version", 0), - ("body", 1), - ], - schema_id="sha256:mesh-alias-sub-note", - schema_name="mesh.alias_sub_note", - schema_version="mesh.alias_sub_note.v1", - ) - node = CultMesh.create_node(runtime_id="mesh-alias-sub-server") - node.database.register_document(document) - - server = CultMesh.serve_node(node) - try: - raw_client = CultMesh.create_client("127.0.0.1", server.port, timeout_seconds=2.0) - with raw_client.subscribe_database( - subscription_id="sub-alias", - schema_ids=["mesh.alias_sub_note.v1"], - include_snapshot=False, - ) as subscription: - subscription.send(document_put_raw( - message_id="put-foreign-alias", - key="note:alias-sub", - schema_id="runtime.generated.mesh.alias_sub_note.ui.99", - stored_at="2026-06-27T00:00:00Z", - payload=document.encode_payload({ - "schema_version": "mesh.alias_sub_note.v1", - "body": "notified", - }), - )) - change = subscription.read_next_change() - finally: - server.stop() - - local_schema_id = document.catalog_entry().schema_id - self.assertEqual(change.subscription_id, "sub-alias") - self.assertEqual(change.change_kind, "added") - self.assertEqual(change.record_key, "note:alias-sub") - self.assertIsInstance(change.raw_document, CultNetRawDocumentRecord) - self.assertEqual(change.raw_document.schema_id, "runtime.generated.mesh.alias_sub_note.ui.99") - self.assertEqual(node.database.get_required(document, "note:alias-sub")["body"], "notified") - self.assertEqual(node.cache.get_required_envelope(document, "note:alias-sub").schema_id, local_schema_id) - - def test_cultmesh_local_server_notifies_schema_alias_subscription_for_delete(self) -> None: - document = define_database_entry_type( - "mesh.alias_delete_note", - [("body", 0)], - schema_id="sha256:mesh-alias-delete-note", - schema_name="mesh.alias_delete_note", - schema_version="mesh.alias_delete_note.v1", - ) - node = CultMesh.create_node(runtime_id="mesh-alias-delete-server") - node.database.register_document(document) - node.database.put_raw_message( - document, - "note:delete-alias", - {"body": "remove me"}, - shard_id="notes", - shard_epoch=1, - ) - - server = CultMesh.serve_node(node) - try: - raw_client = CultMesh.create_client("127.0.0.1", server.port, timeout_seconds=2.0) - with raw_client.subscribe_database( - subscription_id="sub-delete-alias", - schema_ids=[document.catalog_entry().schema_id], - include_snapshot=False, - ) as subscription: - subscription.send(document_delete( - message_id="delete-foreign-alias", - schema_id="mesh.alias_delete_note.v1", - record_key="note:delete-alias", - shard_id="notes", - shard_epoch=1, - )) - change = subscription.read_next_change() - finally: - server.stop() - - self.assertEqual(change.subscription_id, "sub-delete-alias") - self.assertEqual(change.change_kind, "removed") - self.assertEqual(change.schema_id, "mesh.alias_delete_note.v1") - self.assertEqual(change.record_key, "note:delete-alias") - self.assertIsNone(change.raw_document) - self.assertIsNone(node.database.get(document, "note:delete-alias")) - - def test_cultmesh_local_server_rejects_oversized_snapshot_responses(self) -> None: - document = define_database_entry_type( - "mesh.snapshot_limit_note", - [("body", 0)], - schema_id="mesh.snapshot_limit_note.v1", - ) - node = CultMesh.create_node(runtime_id="mesh-snapshot-limits") - node.database.register_document(document) - node.database.put_raw_message(document, "note:1", {"body": "first"}) - node.database.put_raw_message(document, "note:2", {"body": "second"}) - - server = CultMesh.serve_node(node, max_snapshot_documents=1) - try: - raw_client = CultMesh.create_client("127.0.0.1", server.port, timeout_seconds=2.0) - filtered_snapshot = raw_client.fetch_snapshot(record_keys=["note:1"]) - error = raw_client.request( - snapshot_request(schema_ids=["mesh.snapshot_limit_note.v1"]), - expected_schema_version="cultnet.error.v0", - ) - with self.assertRaisesRegex(CultNetPeerError, "Snapshot document limit exceeded"): - raw_client.fetch_snapshot(schema_ids=["mesh.snapshot_limit_note.v1"]) - finally: - server.stop() - - self.assertEqual(filtered_snapshot["schemaVersion"], "cultnet.snapshot_response_raw.v0") - self.assertEqual([document["recordKey"] for document in filtered_snapshot["documents"]], ["note:1"]) - self.assertEqual(error["schemaVersion"], "cultnet.error.v0") - self.assertIn("Snapshot document limit exceeded", error["error"]) - self.assertEqual(error["code"], "snapshot_document_limit_exceeded") - self.assertEqual(error["details"]["documentCount"], 2) - self.assertEqual(error["details"]["maxSnapshotDocuments"], 1) - - def test_cultmesh_local_server_returns_errors_for_bad_requests(self) -> None: - document = define_database_entry_type( - "mesh.error_note", - [("body", 0)], - schema_id="mesh.error_note.v1", - ) - node = CultMesh.create_node(runtime_id="mesh-error-server") - node.database.register_document(document) - - server = CultMesh.serve_node(node) - try: - raw_client = CultMesh.create_client("127.0.0.1", server.port, timeout_seconds=2.0) - unsupported = raw_client.request( - {"schemaVersion": "cultnet.nope.v0", "messageId": "bad-schema"}, - expected_schema_version="cultnet.error.v0", - ) - malformed_put = raw_client.request( - {"schemaVersion": "cultnet.document_put_raw.v0", "messageId": "bad-put"}, - expected_schema_version="cultnet.error.v0", - ) - malformed_delete = raw_client.request( - {"schemaVersion": "cultnet.document_delete.v0", "messageId": "bad-delete", "schemaId": "mesh.error_note.v1"}, - expected_schema_version="cultnet.error.v0", - ) - finally: - server.stop() - - self.assertEqual(unsupported["messageId"], "bad-schema") - self.assertEqual(unsupported["code"], "unsupported_schema_version") - self.assertEqual(unsupported["details"]["schemaVersion"], "cultnet.nope.v0") - self.assertIn("Unsupported CultNet message schema", unsupported["error"]) - self.assertEqual(malformed_put["messageId"], "bad-put") - self.assertEqual(malformed_put["code"], "malformed_document_put") - self.assertEqual(malformed_delete["messageId"], "bad-delete") - self.assertEqual(malformed_delete["code"], "malformed_document_delete") - - def test_cultmesh_authority_lease_requires_live_matching_lease(self) -> None: - peer = CultMeshPeerCard( - peer_id="voidbot-local", - verse_id="local", - endpoints=("cultmesh://localhost",), - roles=("shard-primary",), - authority_lease_id="lease:voidbot-local", - ) - leases = CultMeshAuthorityLeaseCatalog() - peers = CultMeshPeerCatalog() - peers.upsert(peer) - now = datetime.now(UTC) - self.assertFalse(leases.is_authorized(peer, "shard-primary", at=now)) - self.assertEqual(peers.find_authorized("local", "shard-primary", leases, at=now), []) - - leases.upsert( - CultMeshAuthorityLease( - lease_id="lease:voidbot-local", - verse_id="local", - peer_id="voidbot-local", - roles=("shard-primary", "shard-primary", ""), - valid_from=now - timedelta(seconds=1), - expires_at=now + timedelta(seconds=1), - shard_ids=("shard-a",), - issuer_runtime_id="odin", - signature="signed", - ) - ) - - lease = leases.get("lease:voidbot-local") - self.assertIsNotNone(lease) - assert lease is not None - self.assertEqual(leases.leases, (lease,)) - self.assertEqual(lease.roles, ("shard-primary",)) - self.assertEqual(lease.issuer_runtime_id, "odin") - self.assertEqual(lease.signature, "signed") - self.assertTrue(lease.is_valid_at(now)) - self.assertTrue(lease.covers(peer, "shard-primary", shard_id="shard-a", at=now)) - self.assertFalse(lease.covers(peer, "shard-primary", shard_id="shard-b", at=now)) - self.assertTrue(leases.is_authorized(peer, "shard-primary", shard_id="shard-a", at=now)) - self.assertEqual( - peers.find_authorized("local", "shard-primary", leases, shard_id="shard-a", at=now), - [peer], - ) - self.assertEqual( - peers.first_authorized("local", "shard-primary", leases, shard_id="shard-a", at=now), - peer, - ) - self.assertIsNone(peers.first_authorized("local", "read-replica", leases, at=now)) - self.assertFalse(leases.is_authorized(peer, "shard-primary", shard_id="shard-b", at=now)) - self.assertFalse(leases.is_authorized(peer, "read-replica", at=now)) - self.assertIsNone(leases.get("missing")) - - def test_cultmesh_authority_lease_catalog_can_require_verified_signatures(self) -> None: - peer = CultMeshPeerCard( - peer_id="voidbot-local", - verse_id="local", - endpoints=("cultmesh://localhost",), - roles=("shard-primary",), - shard_ids=("shard-a",), - authority_lease_id="lease:voidbot-local", - ) - now = datetime.now(UTC) - unsigned = CultMeshAuthorityLease( - lease_id="lease:voidbot-local", - verse_id="local", - peer_id="voidbot-local", - roles=("shard-primary",), - valid_from=now - timedelta(seconds=1), - expires_at=now + timedelta(seconds=30), - shard_ids=("shard-a",), - issuer_runtime_id="odin", - ) - verifier = CultMeshHmacAuthorityLeaseVerifier({"odin": b"lease-secret"}) - signed = verifier.issue(unsigned) - strict_leases = CultMesh.create_authority_lease_catalog( - signature_verifier=verifier.verify, - require_verified_signatures=True, - ) - strict_leases.upsert(unsigned) - self.assertFalse(strict_leases.is_verified(unsigned.lease_id)) - self.assertFalse(strict_leases.is_authorized(peer, "shard-primary", shard_id="shard-a", at=now)) - - strict_leases.upsert(signed) - self.assertTrue(strict_leases.is_verified(signed.lease_id)) - self.assertTrue(strict_leases.is_authorized(peer, "shard-primary", shard_id="shard-a", at=now)) - - wrong_key = CultMesh.create_authority_lease_catalog( - signature_verifier=CultMeshHmacAuthorityLeaseVerifier({"odin": b"wrong-secret"}).verify, - require_verified_signatures=True, - ) - wrong_key.upsert(signed) - self.assertFalse(wrong_key.is_verified(signed.lease_id)) - self.assertFalse(wrong_key.is_authorized(peer, "shard-primary", shard_id="shard-a", at=now)) - - tampered = CultMeshAuthorityLease( - lease_id=signed.lease_id, - verse_id=signed.verse_id, - peer_id=signed.peer_id, - roles=("shard-primary", "read-replica"), - valid_from=signed.valid_from, - expires_at=signed.expires_at, - shard_ids=signed.shard_ids, - issuer_runtime_id=signed.issuer_runtime_id, - signature=signed.signature, - ) - strict_leases.upsert(tampered) - self.assertFalse(strict_leases.is_verified(tampered.lease_id)) - self.assertFalse(strict_leases.is_authorized(peer, "shard-primary", shard_id="shard-a", at=now)) - - def test_cultmesh_stream_catalog_negotiates_transport_and_latest_frame(self) -> None: - streams = CultMeshStreamCatalog() - streams.declare( - CultMeshStreamDescriptor( - stream_id="mimir:kiyo-pro", - verse_id="studio", - owner_peer_id="starfire", - kind="video", - label="Kiyo Pro", - clock={"clockDomainId": "starfire-qpc", "confidence": 0.25}, - video={"width": 1920, "height": 1080, "pixelFormat": "YUY2", "framesPerSecond": 30}, - preferred_transports=("shared-d3d12-texture", "shared-memory", "cultcache-page"), - max_in_flight_frames=3, - ) - ) - - negotiation = streams.negotiate( - "mimir:kiyo-pro", - CultMeshStreamConsumerProfile( - peer_id="fensalir", - verse_id="studio", - supported_transports=("shared-d3d12-texture", "cultcache-page"), - accepted_kinds=("video",), - can_import_gpu_handles=True, - max_in_flight_frames=2, - ), - ) - - self.assertEqual(negotiation.transport, "shared-d3d12-texture") - self.assertEqual(negotiation.max_in_flight_frames, 2) - self.assertEqual(negotiation.copy_budget, "zero-copy-target") - - streams.publish_frame( - CultMeshStreamFrameHandle( - stream_id="mimir:kiyo-pro", - sequence=42, - timestamp_ns=1_000_000_000, - duration_ns=33_333_334, - transport="shared-d3d12-texture", - native_handle="0xfeed", - fence_handle="0xbeef", - fence_value=7, - unavoidable_copy_count=0, - ) - ) - self.assertEqual(streams.latest_frame("mimir:kiyo-pro").sequence, 42) - - -class CultNetRudpFragmentBoundTests(unittest.TestCase): - def _pair(self) -> tuple[CultNetRudpSession, CultNetRudpSession]: - sender = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=311, initial_sequence=1)) - receiver = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=311, initial_sequence=100)) - sender.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 311, 90, 0, 0, "control")) - receiver.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 311, 91, 0, 0, "control")) - return sender, receiver - - def test_stranded_fragment_sets_are_bounded_and_evicted_oldest_first(self) -> None: - sender, receiver = self._pair() - receiver._max_pending_fragment_sets = 4 - - # Eight payloads each lose their last fragment; the map must not grow past four. - stranded = [] - for fill in range(1, 9): - packets = sender.send_many("media", bytes([fill]) * 2500, max_fragment_bytes=1000) - self.assertEqual(len(packets), 3) - for packet in packets[:2]: - self.assertEqual(receiver.receive(packet).delivered, ()) - stranded.append(packets[2]) - self.assertEqual(len(receiver._fragment_buffers), 4) - self.assertEqual(receiver.fragment_sets_evicted, 4) - - # A complete payload still lands. - delivered = [] - for packet in sender.send_many("media", bytes([9]) * 2500, max_fragment_bytes=1000): - delivered.extend(receiver.receive(packet).delivered) - self.assertEqual([frame.payload for frame in delivered], [bytes([9]) * 2500]) - self.assertEqual(receiver.fragment_sets_evicted, 5) - - # Oldest-first: set 8 still pends and completes late; set 1 was evicted. - self.assertEqual(receiver.receive(stranded[7]).delivered[0].payload, bytes([8]) * 2500) - self.assertEqual(receiver.receive(stranded[0]).delivered, ()) - if __name__ == "__main__": unittest.main() diff --git a/packages/cultcache-ts/test/cult-cache.test.ts b/packages/cultcache-ts/test/cult-cache.test.ts index fb206eb6..5463191f 100644 --- a/packages/cultcache-ts/test/cult-cache.test.ts +++ b/packages/cultcache-ts/test/cult-cache.test.ts @@ -3,7 +3,7 @@ import { exec, execFile } from "node:child_process"; import { existsSync } from "node:fs"; import { access, mkdtemp, readFile, writeFile } from "node:fs/promises"; import { homedir, tmpdir } from "node:os"; -import { dirname, join, resolve } from "node:path"; +import { dirname, join, resolve, delimiter } from "node:path"; import { test } from "node:test"; import { promisify } from "node:util"; @@ -24,7 +24,9 @@ const pythonCommand = process.env.PYTHON ?? "python"; const cultCacheTsRoot = resolve(__dirname, "../.."); const cultLibRoot = findAncestor(cultCacheTsRoot, "CultLib.sln") ?? resolve(cultCacheTsRoot, "..", "CultLib"); const cultcachePyRoot = resolve(cultLibRoot, "packages", "cultcache-py"); -const cultcachePySrc = resolve(cultcachePyRoot, "src"); +const cultcachePySrc = ["cultcache-py", "cultnet-py", "cultmesh-py"] + .map((name) => resolve(cultLibRoot, "packages", name, "src")) + .join(delimiter); const cultcacheRsRoot = existsSync(resolve(cultLibRoot, "packages", "cultcache-rs")) ? resolve(cultLibRoot, "packages", "cultcache-rs") : resolve(cultCacheTsRoot, "..", "cultcache-rs"); diff --git a/packages/cultmesh-py/README.md b/packages/cultmesh-py/README.md new file mode 100644 index 00000000..63799e52 --- /dev/null +++ b/packages/cultmesh-py/README.md @@ -0,0 +1,252 @@ +# cultmesh-py + +`cultmesh-py` is the Python CultMesh runtime: a cache-backed local node, +reactive and observed documents, the branded `CultMesh` facade, Verse and peer +discovery clients, snapshot and observation fan-out, peer health monitoring, +game sessions with prediction reconciliation, committed simulation facts, the +local TCP/RUDP server, and a package daemon. + +It depends on `cultcache-py` and `cultnet-py`, mirroring `cultmesh-rs` and +`cultmesh-ts`. The Verse catalog, peer exchange, authority lease, stream +negotiation, and simulation fact contracts are defined in +`cultnet_py.cultmesh_contracts` and re-exported here. + +This is the package a Python process embeds to serve a Verse — the Brokkr +Blender add-on serves its editor mirror through `CultMesh.serve_node(...)` +from inside Blender's own interpreter. + +## Example + +```python +from datetime import UTC, datetime, timedelta + +from cultcache_py import define_database_entry_type +from cultnet_py import ( + CultNetClientAuthorityScope, + CultNetFileShardReplicaCursorStore, + CultNetRawClient, + CultNetSchemaShardLogFetcher, + CultNetSchemaShardSnapshotFetcher, + CultNetShardDescriptor, + CultNetShardReplicator, + CultNetShardReplicatorOptions, +) +from cultmesh_py import ( + CultMesh, + CultMeshAuthorityLease, + CultMeshGameSessionOptions, + CultMeshHmacAuthorityLeaseVerifier, + CultMeshNodeOptions, + CultMeshSnapshotFanout, + peer_exchange_request, +) + +note_doc = define_database_entry_type( + "mesh.note", + [("body", 0), ("name", 1), ("kind", 2)], + name="name", + indexes={"kind": "kind"}, +) +node = CultMesh.start_node( + "mesh.cc", + runtime_id="python-runtime", + options=CultMeshNodeOptions(enable_durable_shard_logs=True), +) +node.database.register_document(note_doc) +unsubscribe = node.database.watch_record(note_doc, "note:1", lambda change: print(change.change_kind)) +unsubscribe_named = node.database.watch_by_name(note_doc, "intro", lambda change: print(change.record_key)) +unsubscribe_kind = node.database.watch_by_index(note_doc, "kind", "guide", lambda change: print(change.record_key)) +node.database.put(note_doc, "note:1", {"body": "hello", "name": "intro", "kind": "guide"}) +live_note = node.database.get_required(note_doc, "note:1") +put_message = node.database.put_raw_message( + note_doc, + "note:2", + {"body": "wire me", "name": "wire", "kind": "interop"}, + shard_id="interop", + shard_epoch=1, +) +snapshot_response = node.database.build_snapshot_response(schema_ids=[note_doc.catalog_entry().schema_id]) +snapshot_wire = node.database.create_snapshot_response(schema_ids=[note_doc.catalog_entry().schema_id]) +delete_message = node.database.delete_raw_message(note_doc, "note:2", shard_id="interop", shard_epoch=1) +shard_log_response = node.database.build_shard_log_response(shard_id="interop", shard_epoch=1) +shard_log_wire = node.database.create_shard_log_response(shard_id="interop", shard_epoch=1) + +station_stock_doc = define_database_entry_type( + "aetheria.station_stock", + [("missiles", 0), ("coolant", 1)], + schema_id="gamecult.aetheria.station_stock.v1", +) +station_stock_ui_doc = define_database_entry_type( + "aetheria.station_stock.ui", + [("missiles", 0), ("coolant", 1)], + schema_id="gamecult.aetheria.station_stock.v1", +) +node.database.register_document(station_stock_doc) +node.database.put(station_stock_ui_doc, "station:starbridge:stock", {"missiles": 24, "coolant": 80}) +stock = node.database.get_required(station_stock_ui_doc, "station:starbridge:stock") + +peers = CultMesh.create_peer_catalog() +response = peers.create_response(peer_exchange_request("pex-1", verse_id="local")) +lease_verifier = CultMeshHmacAuthorityLeaseVerifier({"odin": b"shared-lease-key"}) +lease_catalog = CultMesh.create_authority_lease_catalog( + signature_verifier=lease_verifier.verify, + require_verified_signatures=True, +) +lease_valid_from = datetime.now(UTC) +lease = lease_verifier.issue(CultMeshAuthorityLease( + lease_id="lease:python-runtime", + verse_id="local", + peer_id="python-runtime", + roles=("shard-primary",), + valid_from=lease_valid_from, + expires_at=lease_valid_from + timedelta(minutes=5), + shard_ids=("interop",), + issuer_runtime_id="odin", +)) +lease_catalog.upsert(lease) +session = CultMesh.create_game_session( + node, + CultMeshGameSessionOptions( + client_authority_scopes=( + CultNetClientAuthorityScope("python-runtime", schema_ids=(note_doc.catalog_entry().schema_id,), key_prefix="input:python"), + ), + ), +) +server = CultMesh.serve_node( + node, + peer_catalog=peers, + observation_hub=session.observation_hub, + port=3075, + max_snapshot_documents=1000, + max_snapshot_bytes=4 * 1024 * 1024, +) +``` + +The same local server can be launched as a package daemon when another runtime +or operator process needs a CultNet endpoint without embedding Python glue: + +```powershell +python -m cultmesh_py.daemon --runtime-id python-runtime --display-name "Python Runtime" --host 127.0.0.1 --port 3075 --cache-file mesh.cc --enable-durable-shard-logs --seed-interop-note --seed-shard-id interop --verse-id local --role shard-primary --ready-file mesh.ready.json +``` + +The ready file and stdout line are process readiness hints. The served state and +capability truth still live on the framed CultNet/CultMesh endpoint. Use +`--register-interop-note` to expose the package interop-note schema without +seeding a note, or `--seed-interop-note` to register it and publish one local +record for wire probes. Seeded records are committed through the raw mutation +path, so peers can read them through both snapshot and shard-log catch-up. Add +`--verse-id` and one or more `--role` values to publish the launched endpoint in +its own Verse and peer catalogs for discovery clients. When the daemon is +launched with `--cache-file`, `--enable-durable-shard-logs`, and +`--shard-log-file`, a later daemon process can rehydrate and serve the persisted +snapshot and shard log without reseeding. + +`CultMeshPeerHealthMonitor` probes peer-card endpoints with `cultnet.hello.v0` +and preserves the runtime id, display name, document types, message versions, +and mutation contracts reported by the peer. + +```python +client = CultMesh.create_verse_discovery_client("127.0.0.1", 3075) +verses = client.fetch_verses(transport_version="cultmesh.v0") +mesh_peers = client.fetch_peers(verse_id="python-interop", roles=["read-replica"]) +client.sync_peer_catalog(peers, verse_id="python-interop", roles=["read-replica"]) +client.fanout_peer_catalog(peers, verse_id="python-interop", roles=["read-replica"]) +replica_notes = client.sync_documents( + node.database, + peers, + verse_id="python-interop", + roles=["read-replica"], + documents=[(note_doc, "note:remote")], +) +snapshot_fanout = CultMeshSnapshotFanout( + client, + node.database, + peers, + verse_id="python-interop", + roles=["read-replica"], + documents=[(note_doc, "note:remote")], + on_document=lambda note: print(note), +) +snapshot_fanout.sync_once() + +raw_client = CultNetRawClient("127.0.0.1", 3075) +synced_note = node.database.sync_document(raw_client, note_doc, "note:remote") +synced_stock = CultMesh.sync_document( + node, + raw_client, + station_stock_ui_doc, + "station:starbridge:stock", +) +with CultMesh.subscribe_document( + node, + raw_client, + station_stock_ui_doc, + "station:starbridge:stock", +) as stock_subscription: + stock = stock_subscription.sync_initial() + next_change = stock_subscription.read_next_change() +node.database.sync_shard_log(raw_client, shard_id="interop", shard_epoch=1) +replicator = CultNetShardReplicator( + node.database, + CultNetShardReplicatorOptions( + fetcher=CultNetSchemaShardLogFetcher(), + snapshot_fetcher=CultNetSchemaShardSnapshotFetcher(), + cursor_store=CultNetFileShardReplicaCursorStore("mesh.replica-cursors.msgpack"), + poll_interval_seconds=1.0, + on_error=lambda error: print(error), + ), +) +replica_shard = CultNetShardDescriptor( + shard_id="interop", + owner_runtime_id="primary-runtime", + epoch=1, + schema_ids=(note_doc.catalog_entry().schema_id,), + primary_endpoints=("cultnet://127.0.0.1:3075",), +) +replicator.pull_once(replica_shard) +replicator.start([replica_shard]) +replicator.stop() +server.stop() + +streams = CultMesh.create_stream_catalog() + +facts = CultMesh.create_simulation_fact_committer(node) +committed = facts.commit({ + "shardId": "arena", + "shardEpoch": 4, + "frame": 100, + "subjectId": "bob", + "claimKind": "hit", + "claimHash": "accepted-claim-hash", + "witnessCount": 2, + "supportWeight": 2.0, + "totalWeight": 2.0, + "confidence": 1.0, + "hasQuorum": True, +}) +prediction = session.predict(note_doc, "input:python:move", {"body": "predicted input"}) +unsubscribe() +``` + +## Verify + +`cultmesh_py.verify` checks the public exports and `py.typed` markers of all +three Python packages, smokes a local node over the wire, checks the served +capability truth, and runs the benchmark for sanity: + +```powershell +python -m cultmesh_py.verify --json +``` + +## Tests + +```powershell +$env:PYTHONPATH="$PWD\packages\cultcache-py\src;$PWD\packages\cultnet-py\src;$PWD\packages\cultmesh-py\src" +python -m unittest discover -s packages\cultmesh-py\tests +``` + +`packages\cultnet-ts\test\interop\cultnet-interop.test.ts` verifies the public +`CultMeshDiscoveryClient` can fetch typed Verse and peer descriptors from the +live Python peer. See +[docs/python-runtime-parity.md](../../docs/python-runtime-parity.md) for the +evidence map across the three Python packages. diff --git a/packages/cultmesh-py/pyproject.toml b/packages/cultmesh-py/pyproject.toml new file mode 100644 index 00000000..847b18e4 --- /dev/null +++ b/packages/cultmesh-py/pyproject.toml @@ -0,0 +1,29 @@ +[build-system] +requires = ["setuptools>=68"] +build-backend = "setuptools.build_meta" + +[project] +name = "cultmesh-py" +version = "0.1.0" +description = "Python CultMesh node, discovery, sessions, and local server for GameCult typed state." +readme = "README.md" +requires-python = ">=3.10" +license = "MIT" +authors = [{ name = "GameCult" }] +classifiers = [ + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", +] +dependencies = ["cultcache-py>=0.2.0", "cultnet-py>=0.1.0"] +[project.scripts] +cultmesh-py-daemon = "cultmesh_py.daemon:main" +cultmesh-py-verify = "cultmesh_py.verify:main" + +[tool.setuptools.packages.find] +where = ["src"] + +[tool.setuptools.package-data] +cultmesh_py = ["py.typed"] diff --git a/packages/cultcache-py/src/cultmesh_py/__init__.py b/packages/cultmesh-py/src/cultmesh_py/__init__.py similarity index 98% rename from packages/cultcache-py/src/cultmesh_py/__init__.py rename to packages/cultmesh-py/src/cultmesh_py/__init__.py index 54b68343..af4da272 100644 --- a/packages/cultcache-py/src/cultmesh_py/__init__.py +++ b/packages/cultmesh-py/src/cultmesh_py/__init__.py @@ -39,7 +39,7 @@ from .simulation import ( CultMeshSimulationFactCommitter, simulation_fact_document, ) -from .wire import ( +from cultnet_py.cultmesh_contracts import ( PEER_EXCHANGE_REQUEST, PEER_EXCHANGE_RESPONSE, VERSE_CATALOG_REQUEST, diff --git a/packages/cultcache-py/src/cultmesh_py/client.py b/packages/cultmesh-py/src/cultmesh_py/client.py similarity index 99% rename from packages/cultcache-py/src/cultmesh_py/client.py rename to packages/cultmesh-py/src/cultmesh_py/client.py index e69e0403..2e1c3ab1 100644 --- a/packages/cultcache-py/src/cultmesh_py/client.py +++ b/packages/cultmesh-py/src/cultmesh_py/client.py @@ -9,7 +9,7 @@ from urllib.parse import urlparse from cultcache_py.documents import DocumentDefinition from cultnet_py import CultNetDatabaseSubscription, CultNetRawClient, CultNetRawSnapshotResponse, hello -from .wire import ( +from cultnet_py.cultmesh_contracts import ( PEER_EXCHANGE_RESPONSE, VERSE_CATALOG_RESPONSE, CultMeshPeerCard, diff --git a/packages/cultcache-py/src/cultmesh_py/daemon.py b/packages/cultmesh-py/src/cultmesh_py/daemon.py similarity index 99% rename from packages/cultcache-py/src/cultmesh_py/daemon.py rename to packages/cultmesh-py/src/cultmesh_py/daemon.py index 087dc218..d21d42d8 100644 --- a/packages/cultcache-py/src/cultmesh_py/daemon.py +++ b/packages/cultmesh-py/src/cultmesh_py/daemon.py @@ -13,7 +13,7 @@ from cultnet_py import CultNetSimulationConsensusOptions, CultNetSimulationObser from .facade import CultMesh from .server import CultMeshLocalServer -from .wire import ( +from cultnet_py.cultmesh_contracts import ( CultMeshPeerCard, CultMeshPeerCatalog, CultMeshVerseCatalog, diff --git a/packages/cultcache-py/src/cultmesh_py/facade.py b/packages/cultmesh-py/src/cultmesh_py/facade.py similarity index 99% rename from packages/cultcache-py/src/cultmesh_py/facade.py rename to packages/cultmesh-py/src/cultmesh_py/facade.py index 4c9c34a0..53328aab 100644 --- a/packages/cultcache-py/src/cultmesh_py/facade.py +++ b/packages/cultmesh-py/src/cultmesh_py/facade.py @@ -34,7 +34,7 @@ from .node import ( from .server import CultMeshLocalServer from .session import CultMeshGameSession, CultMeshGameSessionOptions from .simulation import CultMeshSimulationFactCommitter -from .wire import ( +from cultnet_py.cultmesh_contracts import ( AuthorityLeaseVerifier, CultMeshAuthorityLeaseCatalog, CultMeshPeerCard, diff --git a/packages/cultcache-py/src/cultmesh_py/node.py b/packages/cultmesh-py/src/cultmesh_py/node.py similarity index 100% rename from packages/cultcache-py/src/cultmesh_py/node.py rename to packages/cultmesh-py/src/cultmesh_py/node.py diff --git a/packages/cultcache-py/src/cultmesh_py/py.typed b/packages/cultmesh-py/src/cultmesh_py/py.typed similarity index 100% rename from packages/cultcache-py/src/cultmesh_py/py.typed rename to packages/cultmesh-py/src/cultmesh_py/py.typed diff --git a/packages/cultcache-py/src/cultmesh_py/server.py b/packages/cultmesh-py/src/cultmesh_py/server.py similarity index 99% rename from packages/cultcache-py/src/cultmesh_py/server.py rename to packages/cultmesh-py/src/cultmesh_py/server.py index 6f124480..e0c7fdd0 100644 --- a/packages/cultcache-py/src/cultmesh_py/server.py +++ b/packages/cultmesh-py/src/cultmesh_py/server.py @@ -24,7 +24,7 @@ from cultnet_py import ( ) from .node import CultMeshNode -from .wire import ( +from cultnet_py.cultmesh_contracts import ( PEER_EXCHANGE_REQUEST, VERSE_CATALOG_REQUEST, CultMeshPeerCatalog, diff --git a/packages/cultcache-py/src/cultmesh_py/session.py b/packages/cultmesh-py/src/cultmesh_py/session.py similarity index 98% rename from packages/cultcache-py/src/cultmesh_py/session.py rename to packages/cultmesh-py/src/cultmesh_py/session.py index 7e4b1bc1..c02696f0 100644 --- a/packages/cultcache-py/src/cultmesh_py/session.py +++ b/packages/cultmesh-py/src/cultmesh_py/session.py @@ -23,7 +23,7 @@ from .simulation import ( CultMeshSimulationFactCommitter, simulation_fact_document, ) -from .wire import CultMeshAuthorityLeaseCatalog, CultMeshPeerCatalog, CultMeshVerseCatalog +from cultnet_py.cultmesh_contracts import CultMeshAuthorityLeaseCatalog, CultMeshPeerCatalog, CultMeshVerseCatalog if TYPE_CHECKING: from .server import CultMeshLocalServer diff --git a/packages/cultmesh-py/src/cultmesh_py/simulation.py b/packages/cultmesh-py/src/cultmesh_py/simulation.py new file mode 100644 index 00000000..a89ba4a2 --- /dev/null +++ b/packages/cultmesh-py/src/cultmesh_py/simulation.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from dataclasses import dataclass +from typing import Any + +from cultcache_py.documents import DocumentDefinition +from cultnet_py.cultmesh_contracts import ( + SIMULATION_FACT_DOCUMENT_TYPE, + SIMULATION_FACT_SCHEMA_VERSION, + CultMeshSimulationFact, + simulation_fact_document, +) + +from .node import CultMeshNode + +__all__ = [ + "SIMULATION_FACT_DOCUMENT_TYPE", + "SIMULATION_FACT_SCHEMA_VERSION", + "CultMeshSimulationFact", + "CultMeshSimulationFactCommit", + "CultMeshSimulationFactCommitter", + "simulation_fact_document", +] + + +@dataclass(frozen=True) +class CultMeshSimulationFactCommit: + key: str + fact: CultMeshSimulationFact + + +@dataclass +class CultMeshSimulationFactCommitter: + node: CultMeshNode + document: DocumentDefinition[CultMeshSimulationFact] = simulation_fact_document + + def __post_init__(self) -> None: + if all(document.type != self.document.type for document in self.node.documents): + self.node.register_document(self.document) + + def commit(self, candidate: dict[str, Any], *, committed_at: str | None = None) -> CultMeshSimulationFactCommit: + if not bool(candidate.get("hasQuorum") if "hasQuorum" in candidate else candidate.get("has_quorum")): + raise ValueError("Simulation candidate cannot be committed before quorum") + key = CultMeshSimulationFact.create_record_key(candidate) + fact = CultMeshSimulationFact.from_candidate(candidate, committed_at=committed_at) + self.node.put(self.document, key, fact) + return CultMeshSimulationFactCommit(key=key, fact=fact) diff --git a/packages/cultcache-py/src/cultcache_py/verify.py b/packages/cultmesh-py/src/cultmesh_py/verify.py similarity index 98% rename from packages/cultcache-py/src/cultcache_py/verify.py rename to packages/cultmesh-py/src/cultmesh_py/verify.py index b6a85430..068f5dc2 100644 --- a/packages/cultcache-py/src/cultcache_py/verify.py +++ b/packages/cultmesh-py/src/cultmesh_py/verify.py @@ -6,7 +6,7 @@ import json from importlib import resources from typing import Any -from .benchmark import run_benchmark +from cultnet_py.benchmark import run_benchmark EXPECTED_EXPORTS: dict[str, tuple[str, ...]] = { @@ -150,7 +150,7 @@ EXPECTED_EXPORTS: dict[str, tuple[str, ...]] = { def main(argv: list[str] | None = None) -> int: - parser = argparse.ArgumentParser(prog="cultcache-py-verify") + parser = argparse.ArgumentParser(prog="cultmesh-py-verify") parser.add_argument("--records", type=int, default=64) parser.add_argument("--json", action="store_true", dest="emit_json") args = parser.parse_args(argv) @@ -159,7 +159,7 @@ def main(argv: list[str] | None = None) -> int: if args.emit_json: print(json.dumps(result, indent=2, sort_keys=True)) else: - print(f"cultcache-py verify: {result['status']}") + print(f"cultmesh-py verify: {result['status']}") for check in result["checks"]: print(f"- {check['name']}: {check['status']}") return 0 if result["status"] == "ok" else 1 diff --git a/packages/cultmesh-py/tests/test_cultmesh.py b/packages/cultmesh-py/tests/test_cultmesh.py new file mode 100644 index 00000000..b6a21bb8 --- /dev/null +++ b/packages/cultmesh-py/tests/test_cultmesh.py @@ -0,0 +1,4491 @@ +from __future__ import annotations + +import json +import os +import socket +import subprocess +import sys +import tempfile +import threading +import time +import unittest +from unittest.mock import patch +from dataclasses import dataclass +from datetime import UTC, datetime, timedelta +from pathlib import Path +from typing import Any, Callable +from cultcache_py import ( + CultCache, + SingleFileMessagePackBackingStore, + define_database_entry_type, + define_document_type, +) +from cultcache_py.interop import INTEROP_SCHEMA_VERSION, interop_note_document +from cultmesh_py.verify import verify +from cultnet_py import ( + compute_simulation_claim_hash, + CultNetClientAuthorityScope, + CultNetRawClient, + CultNetRawDocumentRecord, + CultNetRawSnapshotResponse, + CultNetSchemaCatalog, + CultNetShardCatalog, + CultNetShardDescriptor, + CultNetShardLogResponse, + CultNetFileShardReplicaCursorStore, + CultNetFileShardMutationLogStore, + CultNetInMemoryShardReplicaCursorStore, + CultNetSchemaWriteForwarder, + CultNetSchemaShardLogFetcher, + CultNetSchemaShardSnapshotFetcher, + CultNetPeerError, + CultNetShardReplicator, + CultNetShardReplicatorOptions, + CultNetShardMutationLogStore, + CultNetShardWriteForwarder, + CultNetSimulationConsensusOptions, + CultNetSimulationConsensusCandidate, + CultNetSimulationObservation, + CultNetSimulationObservationHub, + CultNetRudpSocketMode, + CultNetRudpSocketTransportConnection, + CultNetRudpSocketTransportOptions, + apply_shard_log_response, + document_delete, + document_put_raw, + hello, + simulation_observation, + snapshot_request, +) +from cultmesh_py import create_node +from cultmesh_py import ( + CultMesh, + CultMeshDatabase, + CultMeshDatabaseChange, + CultMeshGameSessionOptions, + CultMeshNodeOptions, + CultMeshReactiveDocumentOptions, + CultMeshPeerCard, + CultMeshPeerCatalog, + CultMeshSimulationFact, + CultMeshAuthorityLease, + CultMeshAuthorityLeaseCatalog, + CultMeshHmacAuthorityLeaseVerifier, + CultMeshDiscoveryClient, + CultMeshPeerExchangeClient, + CultMeshPeerHealthMonitor, + CultMeshSimulationObservationFanout, + CultMeshSnapshotFanout, + CultMeshStreamCatalog, + CultMeshStreamConsumerProfile, + CultMeshStreamDescriptor, + CultMeshStreamFrameHandle, + CultMeshVerseCatalog, + CultMeshVerseCompatibility, + CultMeshVerseDescriptor, + CultMeshVerseDiscoveryClient, + READY_SCHEMA_VERSION, + peer_exchange_request, + simulation_fact_document, + verse_catalog_request, +) + + +def bind_udp_socket() -> socket.socket: + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + sock.bind(("127.0.0.1", 0)) + sock.settimeout(0.02) + return sock + + +def pump_rudp_handshake( + client: CultNetRudpSocketTransportConnection, + server: CultNetRudpSocketTransportConnection, +) -> None: + for _ in range(20): + server.receive_once() + client.receive_once() + server.receive_once() + if client.connected and server.connected: + return + time.sleep(0.005) + raise AssertionError("RUDP socket handshake did not complete") + + +def receive_rudp_frame(transport: CultNetRudpSocketTransportConnection): + for _ in range(20): + frame = transport.receive_once() + if frame is not None: + return frame + time.sleep(0.005) + raise AssertionError("RUDP socket frame was not delivered") + + +@dataclass +class Item: + name: str + category: str + value: int + + +class CultMeshTests(unittest.TestCase): + def _wait_until(self, predicate: Callable[[], bool], *, timeout_seconds: float = 2.0) -> None: + deadline = time.monotonic() + timeout_seconds + while time.monotonic() < deadline: + if predicate(): + return + time.sleep(0.01) + self.fail("Timed out waiting for condition") + + def test_verify_reports_python_runtime_surface_health(self) -> None: + result = verify(records=4) + + self.assertEqual(result["status"], "ok") + self.assertEqual( + {check["name"] for check in result["checks"]}, + { + "public_exports", + "typed_markers", + "local_cultmesh_wire_smoke", + "cultmesh_capability_truth", + "benchmark_sanity", + }, + ) + by_name = {check["name"]: check for check in result["checks"]} + self.assertEqual(by_name["public_exports"]["missing"], {}) + self.assertEqual(by_name["cultmesh_capability_truth"]["failures"], []) + + def test_cultmesh_client_uses_rudp_schema_transport_endpoint(self) -> None: + import msgpack # type: ignore + + server_socket = bind_udp_socket() + server_host, server_port = server_socket.getsockname()[:2] + connection_id = 0x43554C54 + server = CultNetRudpSocketTransportConnection( + CultNetRudpSocketTransportOptions( + runtime_id="python-rudp-schema-server", + socket=server_socket, + mode=CultNetRudpSocketMode.SERVER, + connection_id=connection_id, + initial_sequence=100, + resend_delay_ms=25, + ) + ) + received_messages: list[dict[str, object]] = [] + + def serve_once() -> None: + deadline = time.monotonic() + 2.0 + try: + while time.monotonic() < deadline: + frame = server.receive_once() + server.poll_resends() + if frame is None: + time.sleep(0.005) + continue + received = msgpack.unpackb(frame.payload, raw=False) + received_messages.append(received) + response = { + "schemaVersion": "cultnet.schema_catalog_response.v0", + "messageId": received["messageId"], + "schemas": [], + } + server.send("schema", msgpack.packb(response, use_bin_type=True)) + return + raise AssertionError("RUDP schema server did not receive a request") + finally: + server.close() + + server_thread = threading.Thread(target=serve_once, daemon=True) + server_thread.start() + client = CultMesh.create_client( + endpoint=f"rudp://{server_host}:{server_port}", + timeout_seconds=2.0, + connection_id=connection_id, + runtime_id="python-rudp-schema-client", + ) + + response = client.fetch_schema_catalog(message_id="rudp-transport-factory") + server_thread.join(timeout=2.0) + + self.assertFalse(server_thread.is_alive()) + self.assertEqual(response["schemaVersion"], "cultnet.schema_catalog_response.v0") + self.assertEqual(response["messageId"], "rudp-transport-factory") + self.assertEqual(received_messages[0]["schemaVersion"], "cultnet.schema_catalog_request.v0") + self.assertEqual(received_messages[0]["messageId"], "rudp-transport-factory") + + def test_cultmesh_facade_creates_rudp_client_from_peer_endpoint(self) -> None: + connection_id = 0x10203042 + server = CultMesh.create_rudp_server( + "python-cultmesh-rudp-server", + connection_id, + initial_sequence=100, + resend_delay_ms=25, + max_fragment_bytes=1024, + max_pending_reliable_packets=16, + ) + server_host, server_port = server.socket.getsockname()[:2] + endpoint = CultMesh.parse_rudp_endpoint(f"rudp://{server_host}:{server_port}") + self.assertEqual(endpoint.host, server_host) + self.assertEqual(endpoint.port, server_port) + peer = CultMeshPeerCard( + peer_id="python-cultmesh-rudp-server", + verse_id="local", + endpoints=(endpoint.uri,), + roles=("schema",), + authority_lease_id="lease:python-cultmesh-rudp-server", + ) + peers = CultMesh.create_peer_catalog() + leases = CultMesh.create_authority_lease_catalog() + peers.upsert(peer) + with self.assertRaisesRegex(ValueError, "No authorized RUDP peer"): + CultMesh.create_rudp_client_for_authorized_peer( + "python-cultmesh-rudp-client", + connection_id, + peers, + leases, + "local", + "schema", + resend_delay_ms=25, + max_fragment_bytes=1024, + max_pending_reliable_packets=16, + ) + leases.upsert( + CultMeshAuthorityLease( + lease_id="lease:python-cultmesh-rudp-server", + verse_id="local", + peer_id="python-cultmesh-rudp-server", + roles=("schema",), + valid_from=datetime.now(UTC) - timedelta(seconds=1), + expires_at=datetime.now(UTC) + timedelta(seconds=30), + issuer_runtime_id="python-authority", + ) + ) + client = CultMesh.create_rudp_client_for_authorized_peer( + "python-cultmesh-rudp-client", + connection_id, + peers, + leases, + "local", + "schema", + resend_delay_ms=25, + max_fragment_bytes=1024, + max_pending_reliable_packets=16, + ) + + try: + client.connect(b"join") + pump_rudp_handshake(client, server) + self.assertTrue(client.connected) + self.assertTrue(server.connected) + + client.send("schema", b"client-state") + server_frame = receive_rudp_frame(server) + self.assertEqual(server_frame.channel_id, "schema") + self.assertEqual(server_frame.payload, b"client-state") + self.assertEqual(server.profile["transports"][0]["protocol"], "rudp") + self.assertEqual(client.profile["transports"][0]["protocol"], "rudp") + finally: + client.close() + server.close() + + def test_cultmesh_node_applies_foreign_schema_snapshot_as_local_update(self) -> None: + document = define_database_entry_type( + "mesh.runtime-policy", + [ + ("schema_version", 0), + ("name", 1), + ("value", 2), + ], + schema_id="mesh.runtime-policy.current", + schema_name="mesh.runtime_policy", + schema_version="mesh.runtime_policy.v1", + ) + node = create_node(runtime_id="python-node") + node.register_document(document) + node.put(document, "policy:1", { + "schema_version": "mesh.runtime_policy.v1", + "name": "policy", + "value": "old", + }) + observed: list[CultMeshDatabaseChange] = [] + unsubscribe = node.database.watch_record(document, "policy:1", observed.append) + try: + applied = node.database.apply_snapshot_response({ + "schemaVersion": "cultnet.snapshot_response_raw.v0", + "messageId": "foreign-schema-snapshot", + "documents": [ + { + "schemaId": "sha256:foreign-mesh-runtime-policy", + "recordKey": "policy:1", + "storedAt": "2026-06-25T00:00:00Z", + "payloadEncoding": "messagepack", + "payload": document.encode_payload({ + "schema_version": "mesh.runtime_policy.v1", + "name": "policy", + "value": "new", + }), + }, + ], + }) + finally: + unsubscribe() + + local_schema_id = document.catalog_entry().schema_id + self.assertEqual(applied[0].schema_id, local_schema_id) + self.assertEqual(observed[0].schema_id, local_schema_id) + self.assertEqual(observed[0].change_kind, "updated") + self.assertEqual(observed[0].previous_value["value"], "old") + self.assertEqual(observed[0].value["value"], "new") + self.assertEqual(node.cache.get_required_envelope(document, "policy:1").schema_id, local_schema_id) + + def test_cultmesh_node_syncs_snapshot_and_shard_log_through_cultnet_client(self) -> None: + import msgpack # type: ignore + from cultnet_py import read_frame, write_frame + + document = define_database_entry_type( + "mesh.sync_item", + [ + ("name", 0), + ("category", 1), + ("value", 2, 0), + ], + cls=Item, + ) + node = create_node(runtime_id="python-node") + node.register_document(document) + schema_id = document.catalog_entry().schema_id + ready = threading.Event() + server_error: list[BaseException] = [] + port_holder: list[int] = [] + + def serve_requests() -> None: + try: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server: + server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + server.bind(("127.0.0.1", 0)) + port_holder.append(server.getsockname()[1]) + server.listen(2) + ready.set() + for _ in range(2): + connection, _ = server.accept() + with connection: + stream = connection.makefile("rwb") + request = msgpack.unpackb(read_frame(stream), raw=False) + if request["schemaVersion"] == "cultnet.snapshot_request.v0": + response = { + "schemaVersion": "cultnet.snapshot_response_raw.v0", + "messageId": request["messageId"], + "documents": [ + { + "schemaId": schema_id, + "recordKey": "item:node", + "storedAt": "2026-06-13T00:00:00Z", + "payloadEncoding": "messagepack", + "payload": document.encode_payload(Item("node", "mesh", 1)), + } + ], + } + elif request["schemaVersion"] == "cultnet.shard_log_request.v0": + response = { + "schemaVersion": "cultnet.shard_log_response.v0", + "messageId": request["messageId"], + "shardId": request["shardId"], + "shardEpoch": request["shardEpoch"], + "resyncRequired": False, + "entries": [ + { + "sequence": 1, + "changeKind": "updated", + "put": { + "schemaVersion": "cultnet.document_put_raw.v0", + "messageId": "put-node", + "document": { + "schemaId": schema_id, + "recordKey": "item:node", + "storedAt": "2026-06-13T00:00:01Z", + "payloadEncoding": "messagepack", + "payload": document.encode_payload(Item("node", "mesh", 9)), + }, + "shardId": request["shardId"], + "shardEpoch": request["shardEpoch"], + }, + } + ], + } + else: + raise AssertionError(f"unexpected request {request['schemaVersion']}") + write_frame(stream, msgpack.packb(response, use_bin_type=True)) + stream.flush() + except BaseException as error: + server_error.append(error) + ready.set() + + thread = threading.Thread(target=serve_requests, daemon=True) + thread.start() + self.assertTrue(ready.wait(2.0)) + self.assertFalse(server_error) + + client = CultNetRawClient("127.0.0.1", port_holder[0], timeout_seconds=2.0) + snapshot_changes = node.sync_snapshot(client, schema_ids=[schema_id]) + log_changes = node.sync_shard_log(client, shard_id="mesh", shard_epoch=1) + + thread.join(2.0) + self.assertFalse(server_error) + self.assertEqual(snapshot_changes[0].record_key, "item:node") + self.assertEqual(log_changes[0].change_kind, "updated") + self.assertEqual(node.get_required(document, "item:node").value, 9) + + def test_cultmesh_node_sync_document_returns_requested_alias_type(self) -> None: + @dataclass + class CanonicalNote: + body: str + + @dataclass + class UiNote: + body: str + + document = define_database_entry_type( + "mesh.sync_alias_note", + [("body", 0)], + cls=CanonicalNote, + schema_id="mesh.sync_alias_note.v1", + schema_name="mesh.sync_alias_note", + schema_version="mesh.sync_alias_note.v1", + ) + alias = define_database_entry_type( + "mesh.sync_alias_note.ui", + [("body", 0)], + cls=UiNote, + schema_id="mesh.sync_alias_note.v1", + schema_name="mesh.sync_alias_note", + schema_version="mesh.sync_alias_note.v1", + ) + node = create_node(runtime_id="python-node") + node.register_document(document) + requests: list[dict[str, Any]] = [] + + class SnapshotClient: + def fetch_snapshot_response( + self, + *, + schema_ids: list[str] | None = None, + record_keys: list[str] | None = None, + shard_id: str | None = None, + shard_epoch: int | None = None, + ) -> dict[str, Any]: + requests.append({ + "schema_ids": schema_ids, + "record_keys": record_keys, + "shard_id": shard_id, + "shard_epoch": shard_epoch, + }) + return { + "schemaVersion": "cultnet.snapshot_response_raw.v0", + "messageId": "sync-document", + "documents": [ + { + "schemaId": document.catalog_entry().schema_id, + "recordKey": "note:remote", + "storedAt": "2026-06-27T00:00:00Z", + "payloadEncoding": "messagepack", + "payload": document.encode_payload(CanonicalNote("synced-alias")), + } + ], + } + + synced = node.sync_document(SnapshotClient(), alias, "note:remote") + facade_synced = CultMesh.sync_document(node, SnapshotClient(), alias, "note:remote") + + self.assertIsInstance(synced, UiNote) + self.assertEqual(synced.body, "synced-alias") + self.assertIsInstance(facade_synced, UiNote) + self.assertEqual(facade_synced.body, "synced-alias") + self.assertEqual(node.get_required(document, "note:remote").body, "synced-alias") + self.assertIsInstance(node.get_required(alias, "note:remote"), UiNote) + self.assertEqual(requests, [ + { + "schema_ids": ["mesh.sync_alias_note.v1"], + "record_keys": ["note:remote"], + "shard_id": None, + "shard_epoch": None, + }, + { + "schema_ids": ["mesh.sync_alias_note.v1"], + "record_keys": ["note:remote"], + "shard_id": None, + "shard_epoch": None, + }, + ]) + + def test_cultmesh_node_sync_document_from_publication_returns_requested_alias_type(self) -> None: + @dataclass + class CanonicalNote: + body: str + + @dataclass + class UiNote: + body: str + + document = define_database_entry_type( + "mesh.publication_alias_note", + [("body", 0)], + cls=CanonicalNote, + schema_id="mesh.publication_alias_note.v1", + schema_name="mesh.publication_alias_note", + schema_version="mesh.publication_alias_note.v1", + ) + alias = define_database_entry_type( + "mesh.publication_alias_note.ui", + [("body", 0)], + cls=UiNote, + schema_id="mesh.publication_alias_note.v1", + schema_name="mesh.publication_alias_note", + schema_version="mesh.publication_alias_note.v1", + ) + node = create_node(runtime_id="python-publication-node") + node.register_document(document) + requests: list[dict[str, Any]] = [] + + class SnapshotClient: + def fetch_snapshot_response( + self, + *, + schema_ids: list[str] | None = None, + record_keys: list[str] | None = None, + shard_id: str | None = None, + shard_epoch: int | None = None, + ) -> dict[str, Any]: + requests.append({ + "schema_ids": schema_ids, + "record_keys": record_keys, + "shard_id": shard_id, + "shard_epoch": shard_epoch, + }) + return { + "schemaVersion": "cultnet.snapshot_response_raw.v0", + "messageId": "publication-sync-document", + "documents": [ + { + "schemaId": document.catalog_entry().schema_id, + "recordKey": "note:published-peer", + "storedAt": "2026-06-27T00:00:00Z", + "payloadEncoding": "messagepack", + "payload": document.encode_payload(CanonicalNote("peer-publication-alias")), + } + ], + } + + source = CultMesh.publication_source_from_peer_snapshot( + SnapshotClient(), + shard_id="notes", + shard_epoch=3, + ) + + synced = node.sync_document_from_publication(source, alias, "note:published-peer") + facade_synced = CultMesh.sync_document_from_publication(node, source, alias, "note:published-peer") + + self.assertIsInstance(synced, UiNote) + self.assertEqual(synced.body, "peer-publication-alias") + self.assertIsInstance(facade_synced, UiNote) + self.assertEqual(facade_synced.body, "peer-publication-alias") + self.assertEqual(node.get_required(document, "note:published-peer").body, "peer-publication-alias") + self.assertEqual(requests, [ + { + "schema_ids": ["mesh.publication_alias_note.v1"], + "record_keys": ["note:published-peer"], + "shard_id": "notes", + "shard_epoch": 3, + }, + { + "schema_ids": ["mesh.publication_alias_note.v1"], + "record_keys": ["note:published-peer"], + "shard_id": "notes", + "shard_epoch": 3, + }, + ]) + + def test_cultmesh_node_sync_document_from_single_file_publication_uses_node_aliases(self) -> None: + @dataclass + class CanonicalNote: + body: str + + @dataclass + class UiNote: + body: str + + document = define_database_entry_type( + "mesh.file_publication_alias_note", + [("body", 0)], + cls=CanonicalNote, + schema_id="mesh.file_publication_alias_note.v1", + schema_name="mesh.file_publication_alias_note", + schema_version="mesh.file_publication_alias_note.v1", + ) + alias = define_database_entry_type( + "mesh.file_publication_alias_note.ui", + [("body", 0)], + cls=UiNote, + schema_id="mesh.file_publication_alias_note.v1", + schema_name="mesh.file_publication_alias_note", + schema_version="mesh.file_publication_alias_note.v1", + ) + with tempfile.TemporaryDirectory() as tmp: + path = Path(tmp) / "publication.ccmp" + writer = CultCache() + writer.register_document_type(document) + writer.add_generic_store(SingleFileMessagePackBackingStore(path)) + writer.put(document, "note:published-file", CanonicalNote("file-publication-alias")) + + node = create_node(runtime_id="python-file-publication-node") + node.register_document(document) + source = CultMesh.publication_source_from_single_file(path) + + synced = CultMesh.sync_document_from_publication(node, source, alias, "note:published-file") + + self.assertIsInstance(synced, UiNote) + self.assertEqual(synced.body, "file-publication-alias") + self.assertEqual(node.get_required(document, "note:published-file").body, "file-publication-alias") + self.assertIsInstance(node.get_required(alias, "note:published-file"), UiNote) + + def test_cultmesh_node_sync_documents_from_publication_uses_binding_sources_and_aliases(self) -> None: + @dataclass + class CanonicalNote: + body: str + + @dataclass + class UiNote: + body: str + + document = define_database_entry_type( + "mesh.catalog_publication_alias_note", + [("body", 0)], + cls=CanonicalNote, + schema_id="mesh.catalog_publication_alias_note.v1", + schema_name="mesh.catalog_publication_alias_note", + schema_version="mesh.catalog_publication_alias_note.v1", + ) + alias = define_database_entry_type( + "mesh.catalog_publication_alias_note.ui", + [("body", 0)], + cls=UiNote, + schema_id="mesh.catalog_publication_alias_note.v1", + schema_name="mesh.catalog_publication_alias_note", + schema_version="mesh.catalog_publication_alias_note.v1", + ) + with tempfile.TemporaryDirectory() as tmp: + first_path = Path(tmp) / "first.ccmp" + second_path = Path(tmp) / "second.ccmp" + first = CultCache() + first.register_document_type(document) + first.add_generic_store(SingleFileMessagePackBackingStore(first_path)) + first.put(document, "note:first", CanonicalNote("first catalog publication")) + second = CultCache() + second.register_document_type(document) + second.add_generic_store(SingleFileMessagePackBackingStore(second_path)) + second.put(document, "note:second", CanonicalNote("second catalog publication")) + + node = create_node(runtime_id="python-catalog-publication-node") + node.register_document(document) + source = CultMesh.publication_source_from_single_file(first_path) + bindings = [ + CultMesh.publication_document(alias, "note:first"), + CultMesh.publication_document( + alias, + "note:second", + source=CultMesh.publication_source_from_single_file(second_path), + ), + ] + + synced = node.sync_documents_from_publication(source, bindings) + facade_synced = CultMesh.sync_documents_from_publication(node, source, bindings) + + self.assertEqual([value.body for value in synced], [ + "first catalog publication", + "second catalog publication", + ]) + self.assertTrue(all(isinstance(value, UiNote) for value in synced)) + self.assertEqual([value.body for value in facade_synced], [ + "first catalog publication", + "second catalog publication", + ]) + self.assertEqual(node.get_required(document, "note:first").body, "first catalog publication") + self.assertEqual(node.get_required(document, "note:second").body, "second catalog publication") + self.assertIsInstance(node.get_required(alias, "note:second"), UiNote) + + def test_cultmesh_node_emits_raw_put_and_delete_messages_for_local_writes(self) -> None: + document = define_database_entry_type( + "mesh.emit_item", + [ + ("name", 0), + ("category", 1), + ("value", 2, 0), + ], + cls=Item, + ) + node = create_node(runtime_id="python-node") + node.register_document(document) + + put = node.put_raw_message( + document, + "item:emit", + Item("wand", "gear", 4), + message_id="put-emit", + shard_id="mesh", + shard_epoch=1, + ).to_wire() + self.assertEqual(node.get_required(document, "item:emit").name, "wand") + self.assertEqual(put["schemaVersion"], "cultnet.document_put_raw.v0") + self.assertEqual(put["messageId"], "put-emit") + self.assertEqual(put["document"]["schemaId"], document.catalog_entry().schema_id) + self.assertEqual(put["document"]["recordKey"], "item:emit") + self.assertEqual(put["document"]["sourceRuntimeId"], "python-node") + self.assertEqual(put["shardId"], "mesh") + self.assertEqual(put["shardEpoch"], 1) + + delete = node.delete_raw_message( + document, + "item:emit", + message_id="delete-emit", + shard_id="mesh", + shard_epoch=1, + ).to_wire() + self.assertIsNone(node.get(document, "item:emit")) + self.assertEqual(delete["schemaVersion"], "cultnet.document_delete.v0") + self.assertEqual(delete["messageId"], "delete-emit") + self.assertEqual(delete["schemaId"], document.catalog_entry().schema_id) + self.assertEqual(delete["recordKey"], "item:emit") + self.assertEqual(delete["shardId"], "mesh") + self.assertEqual(delete["shardEpoch"], 1) + + def test_cultmesh_node_resolves_same_schema_aliases_for_local_state(self) -> None: + @dataclass + class CanonicalNote: + body: str + + @dataclass + class UiNote: + body: str + + document = define_database_entry_type( + "mesh.alias_note", + [("body", 0)], + cls=CanonicalNote, + schema_id="mesh.alias_note.v1", + schema_name="mesh.alias_note", + schema_version="mesh.alias_note.v1", + ) + alias = define_database_entry_type( + "mesh.alias_note.ui", + [("body", 0)], + cls=UiNote, + schema_id="mesh.alias_note.v1", + schema_name="mesh.alias_note", + schema_version="mesh.alias_note.v1", + ) + node = create_node(runtime_id="python-node") + node.register_document(document) + seen: list[CultMeshDatabaseChange] = [] + all_seen: list[CultMeshDatabaseChange] = [] + node.database.watch(all_seen.append, document=alias) + node.database.watch_record(alias, "note:alias", seen.append) + + node.put(alias, "note:alias", UiNote("from-alias-put")) + self.assertEqual(node.get_required(document, "note:alias").body, "from-alias-put") + alias_value = node.get_required(alias, "note:alias") + self.assertIsInstance(alias_value, UiNote) + self.assertEqual(alias_value.body, "from-alias-put") + alias_collection = node.get_all(alias) + self.assertEqual(len(alias_collection), 1) + self.assertIsInstance(alias_collection[0], UiNote) + self.assertEqual(alias_collection[0].body, "from-alias-put") + self.assertEqual(seen[0].document.type, alias.type) + self.assertEqual(seen[0].schema_id, "mesh.alias_note.v1") + self.assertIsInstance(seen[0].value, UiNote) + self.assertEqual(seen[0].value.body, "from-alias-put") + self.assertEqual(all_seen[0].document.type, alias.type) + self.assertIsInstance(all_seen[0].value, UiNote) + self.assertEqual(all_seen[0].value.body, "from-alias-put") + + node.put(document, "note:alias", CanonicalNote("from-canonical-put")) + self.assertEqual(seen[1].document.type, alias.type) + self.assertIsInstance(seen[1].value, UiNote) + self.assertIsInstance(seen[1].previous_value, UiNote) + self.assertEqual(seen[1].value.body, "from-canonical-put") + self.assertEqual(seen[1].previous_value.body, "from-alias-put") + + put = node.put_raw_message( + alias, + "note:alias", + UiNote("from-alias-raw-put"), + message_id="alias-put", + ).to_wire() + self.assertEqual(put["document"]["schemaId"], "mesh.alias_note.v1") + self.assertEqual(put["document"]["recordKey"], "note:alias") + self.assertEqual(node.get_required(alias, "note:alias").body, "from-alias-raw-put") + + delete = node.delete_raw_message(alias, "note:alias", message_id="alias-delete").to_wire() + self.assertEqual(delete["schemaId"], "mesh.alias_note.v1") + self.assertIsNone(node.get(alias, "note:alias")) + self.assertEqual(node.get_all(alias), []) + + def test_cultmesh_reactive_document_coalesces_explicit_alias_updates(self) -> None: + @dataclass + class CanonicalNote: + body: str + revision: int + + @dataclass + class UiNote: + body: str + revision: int + + document = define_database_entry_type( + "mesh.reactive_alias_note", + [("body", 0), ("revision", 1)], + cls=CanonicalNote, + schema_id="mesh.reactive_alias_note.v1", + schema_name="mesh.reactive_alias_note", + schema_version="mesh.reactive_alias_note.v1", + ) + alias = define_database_entry_type( + "mesh.reactive_alias_note.ui", + [("body", 0), ("revision", 1)], + cls=UiNote, + schema_id="mesh.reactive_alias_note.v1", + schema_name="mesh.reactive_alias_note", + schema_version="mesh.reactive_alias_note.v1", + ) + node = create_node(runtime_id="python-reactive") + node.register_document(document) + node.put(document, "note:reactive", CanonicalNote("initial", 1)) + seen: list[CultMeshDatabaseChange] = [] + node.database.watch_record(alias, "note:reactive", seen.append) + + reactive = node.authoritative_writer(alias, "note:reactive").reactive( + CultMeshReactiveDocumentOptions(flush_delay_seconds=0.02) + ) + try: + self.assertIsInstance(reactive.snapshot, UiNote) + reactive.update(lambda note: setattr(note, "body", "first-local-edit")) + reactive.update(lambda note: setattr(note, "body", "second-local-edit")) + reactive.update(lambda note: setattr(note, "revision", 2)) + + self._wait_until(lambda: node.get_required(alias, "note:reactive").body == "second-local-edit") + + self.assertFalse(reactive.is_dirty) + self.assertEqual(node.get_required(document, "note:reactive").revision, 2) + self.assertEqual(seen[-1].value.body, "second-local-edit") + finally: + reactive.dispose() + + def test_cultmesh_reactive_document_tracks_canonical_reconciliation_delta(self) -> None: + @dataclass + class Note: + body: str + revision: int + + document = define_database_entry_type( + "mesh.reactive_reconcile_note", + [("body", 0), ("revision", 1)], + cls=Note, + schema_id="mesh.reactive_reconcile_note.v1", + schema_name="mesh.reactive_reconcile_note", + schema_version="mesh.reactive_reconcile_note.v1", + ) + node = create_node(runtime_id="python-reactive-reconcile") + node.register_document(document) + node.put(document, "note:reconcile", Note("initial", 1)) + + reactive = CultMesh.authoritative_writer( + node, + document, + "note:reconcile", + ).reactive(CultMeshReactiveDocumentOptions(flush_delay_seconds=60)) + try: + reactive.update(lambda note: setattr(note, "body", "local-prediction")) + reactive.update(lambda note: setattr(note, "revision", 2)) + + node.put(document, "note:reconcile", Note("authoritative", 7)) + + self.assertEqual(reactive.snapshot.body, "local-prediction") + self.assertIsNotNone(reactive.reconciliation) + self.assertEqual(reactive.reconciliation.canonical.body, "authoritative") + self.assertEqual(reactive.reconciliation.predicted.body, "local-prediction") + self.assertEqual(reactive.reconciliation.delta["body"], "local-prediction") + self.assertEqual(reactive.reconciliation.delta["revision"], -5) + + reactive.flush() + self.assertEqual(node.get_required(document, "note:reconcile").body, "local-prediction") + self.assertIsNone(reactive.reconciliation) + finally: + reactive.dispose() + + def test_cultmesh_reactive_document_is_idle_until_explicit_nested_update(self) -> None: + document = define_document_type( + "mesh.nested_loadout", + encode=lambda value: value, + decode=lambda value: value, + ) + node = create_node(runtime_id="python-reactive-nested") + node.register_document(document) + node.put( + document, + "ship:nested", + {"loadout": {"weapon": {"tuning": {"damage": 10}}}}, + ) + + with patch("cultmesh_py.node.threading.Timer") as timer: + reactive = node.authoritative_writer(document, "ship:nested").reactive() + timer.assert_not_called() + + try: + borrowed = reactive.snapshot + borrowed["loadout"]["weapon"]["tuning"]["damage"] = 99 + self.assertEqual( + node.get_required(document, "ship:nested")["loadout"]["weapon"]["tuning"]["damage"], + 10, + ) + + reactive.update( + lambda draft: draft["loadout"]["weapon"]["tuning"].__setitem__("damage", 12) + ) + reactive.flush() + + self.assertEqual(reactive.snapshot["loadout"]["weapon"]["tuning"]["damage"], 12) + self.assertEqual( + node.get_required(document, "ship:nested")["loadout"]["weapon"]["tuning"]["damage"], + 12, + ) + finally: + reactive.dispose() + + def test_cultmesh_reactive_scheduling_scales_with_changed_documents_only(self) -> None: + document = define_document_type( + "mesh.reactive_scale_note", + encode=lambda value: value, + decode=lambda value: value, + ) + + for document_count in (1, 100, 1000): + node = create_node(runtime_id=f"python-reactive-scale-{document_count}") + node.register_document(document) + for index in range(document_count): + node.put(document, f"note:{index}", {"body": "initial", "revision": 1}) + + scheduled_timers: list[Any] = [] + + class FakeScheduledCall: + def __init__(self, delay_seconds: float, callback: Callable[[], None]) -> None: + self.delay_seconds = delay_seconds + self.callback = callback + self.cancelled = False + + def cancel(self) -> None: + self.cancelled = True + + class FakeScheduler: + def schedule( + self, + delay_seconds: float, + callback: Callable[[], None], + ) -> FakeScheduledCall: + call = FakeScheduledCall(delay_seconds, callback) + scheduled_timers.append(call) + return call + + reactive_documents: list[Any] = [] + with patch("cultmesh_py.node._REACTIVE_SCHEDULER", FakeScheduler()): + try: + for index in range(document_count): + reactive_documents.append( + node.authoritative_writer(document, f"note:{index}").reactive() + ) + + self.assertEqual( + len(scheduled_timers), + 0, + f"{document_count} idle documents must schedule no timers", + ) + + changed_document_count = max(1, document_count // 100) + for index in range(changed_document_count): + reactive_documents[index].update( + lambda draft, changed=index: draft.update( + body=f"changed-{changed}", + revision=2, + ) + ) + + self.assertEqual(len(scheduled_timers), changed_document_count) + self.assertEqual( + sum(reactive.is_dirty for reactive in reactive_documents), + changed_document_count, + ) + finally: + for reactive in reactive_documents: + reactive.dispose() + + self.assertTrue(all(timer.cancelled for timer in scheduled_timers)) + + def test_cultmesh_reactive_documents_share_one_lazy_scheduler_thread(self) -> None: + document = define_document_type( + "mesh.reactive_shared_scheduler_note", + encode=lambda value: value, + decode=lambda value: value, + ) + node = create_node(runtime_id="python-reactive-shared-scheduler") + node.register_document(document) + reactive_documents: list[Any] = [] + try: + for index in range(100): + node.put(document, f"note:{index}", {"body": "initial", "revision": 1}) + reactive_documents.append( + node.authoritative_writer(document, f"note:{index}").reactive( + CultMeshReactiveDocumentOptions(flush_delay_seconds=60.0) + ) + ) + + before = sum( + thread.name == "cultmesh-reactive-scheduler" + for thread in threading.enumerate() + ) + for index, reactive in enumerate(reactive_documents): + reactive.update( + lambda draft, changed=index: draft.update( + body=f"changed-{changed}", + revision=2, + ) + ) + after = sum( + thread.name == "cultmesh-reactive-scheduler" + for thread in threading.enumerate() + ) + + self.assertLessEqual(before, 1) + self.assertEqual(after, 1) + finally: + for reactive in reactive_documents: + reactive.dispose() + + def test_cultmesh_observed_document_cannot_publish_borrowed_mutation(self) -> None: + document = define_document_type( + "mesh.observed_note", + encode=lambda value: value, + decode=lambda value: value, + ) + node = create_node(runtime_id="python-observed") + node.register_document(document) + node.put(document, "note:observed", {"body": "initial"}) + + observed = node.observe_document(document, "note:observed") + try: + observed.current["body"] = "borrowed-local-edit" + self.assertEqual(node.get_required(document, "note:observed")["body"], "initial") + + node.put(document, "note:observed", {"body": "canonical"}) + self.assertEqual(observed.current["body"], "canonical") + finally: + observed.dispose() + + def test_cultmesh_node_uses_cultcache_store(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + document = define_database_entry_type("mesh.note", [("body", 0)]) + store_path = Path(tmp) / "mesh.cc" + node = create_node(store_path, runtime_id="mesh-test") + self.assertIsInstance(node.database, CultMeshDatabase) + node.database.register_document(document) + node.database.put(document, "note:1", {"body": "hello"}) + self.assertEqual(node.get_required(document, "note:1")["body"], "hello") + + reopened = create_node(store_path, runtime_id="mesh-test") + reopened.database.register_document(document) + reopened.database.pull() + self.assertEqual(reopened.database.get(document, "note:1")["body"], "hello") + + def test_cultmesh_node_options_attach_default_durable_shard_log_store(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + document = define_database_entry_type( + "mesh.durable_option_note", + [("body", 0)], + schema_id="mesh.durable_option_note.v1", + ) + cache_path = Path(tmp) / "world.cc" + node = CultMesh.create_node( + cache_path, + runtime_id="durable-option-primary", + options=CultMeshNodeOptions(enable_durable_shard_logs=True), + ) + node.database.register_document(document) + node.database.put_raw_message(document, "note:1", {"body": "stored"}, shard_id="notes", shard_epoch=5) + + log_path = Path(tmp) / "world.cultmesh" / "shard-logs" + self.assertTrue(log_path.exists()) + + reopened = CultMesh.start_node( + cache_path, + runtime_id="durable-option-primary", + enable_durable_shard_logs=True, + ) + reopened.database.register_document(document) + response = reopened.database.build_shard_log_response(shard_id="notes", shard_epoch=5) + + self.assertEqual(reopened.database.shard_ids(), ["notes"]) + self.assertEqual([entry.sequence for entry in response.entries], [1]) + self.assertEqual(response.entries[0].raw_document.record_key, "note:1") + + def test_cultmesh_database_watchers_observe_local_changes_and_unsubscribe(self) -> None: + document = define_database_entry_type("mesh.watch", [("body", 0)]) + node = CultMesh.create_node(runtime_id="mesh-watch") + node.database.register_document(document) + changes: list[CultMeshDatabaseChange] = [] + all_changes: list[CultMeshDatabaseChange] = [] + + unsubscribe_record = node.database.watch_record(document, "note:1", changes.append) + unsubscribe_all = node.database.watch(all_changes.append, document=document) + + node.database.put(document, "note:1", {"body": "hello"}) + node.database.put(document, "note:2", {"body": "skip"}) + node.database.put(document, "note:1", {"body": "updated"}) + node.database.delete(document, "note:1") + unsubscribe_record() + node.database.put(document, "note:1", {"body": "after-unsubscribe"}) + unsubscribe_all() + + self.assertEqual([change.change_kind for change in changes], ["added", "updated", "removed"]) + self.assertEqual([change.record_key for change in changes], ["note:1", "note:1", "note:1"]) + self.assertEqual(changes[1].previous_value, {"body": "hello"}) + self.assertIsNone(changes[2].value) + self.assertEqual([change.record_key for change in all_changes], ["note:1", "note:2", "note:1", "note:1", "note:1"]) + + def test_cultmesh_database_register_document_is_idempotent(self) -> None: + document = define_database_entry_type("mesh.idempotent", [("body", 0)]) + conflicting = define_database_entry_type("mesh.idempotent", [("title", 0)]) + node = CultMesh.create_node(runtime_id="mesh-idempotent") + + node.database.register_document(document) + node.database.register_document(document) + node.database.put(document, "note:1", {"body": "still registered once"}) + + self.assertEqual(node.database.get_required(document, "note:1")["body"], "still registered once") + self.assertEqual([registered.type for registered in node.documents], ["mesh.idempotent"]) + with self.assertRaises(ValueError): + node.database.register_document(conflicting) + + def test_cultmesh_database_global_document_facade_uses_singleton_key_and_watchers(self) -> None: + document = define_database_entry_type( + "mesh.global_settings", + [("theme", 0)], + global_document=True, + ) + node = CultMesh.create_node(runtime_id="mesh-global") + node.database.register_document(document) + changes: list[CultMeshDatabaseChange] = [] + + node.database.watch_global(document, changes.append) + node.database.put_global(document, {"theme": "ash"}) + node.put_global(document, {"theme": "ember"}) + node.delete_global(document) + + self.assertIsNone(node.database.get_global(document)) + self.assertEqual([change.record_key for change in changes], [node.cache.GLOBAL_KEY] * 3) + self.assertEqual([change.change_kind for change in changes], ["added", "updated", "removed"]) + self.assertEqual(changes[1].previous_value, {"theme": "ash"}) + self.assertEqual(changes[2].previous_value, {"theme": "ember"}) + with self.assertRaises(Exception): + node.database.put(document, "settings:wrong", {"theme": "bad"}) + + def test_cultmesh_database_creates_raw_snapshot_response_from_envelopes(self) -> None: + document = define_database_entry_type( + "mesh.snapshot_note", + [("body", 0)], + schema_id="mesh.snapshot_note.v1", + ) + source = CultMesh.create_node(runtime_id="mesh-snapshot-source") + source.database.register_document(document) + source.database.put(document, "note:1", {"body": "include"}) + source.database.put(document, "note:2", {"body": "skip"}) + + typed_response = source.database.build_snapshot_response( + message_id="snapshot-1", + schema_ids=["mesh.snapshot_note.v1"], + record_keys=["note:1"], + shard_id="notes", + shard_epoch=4, + shard_log_sequence=7, + ) + response = source.database.create_snapshot_response( + message_id="snapshot-1", + schema_ids=["mesh.snapshot_note.v1"], + record_keys=["note:1"], + shard_id="notes", + shard_epoch=4, + shard_log_sequence=7, + ) + + self.assertIsInstance(typed_response, CultNetRawSnapshotResponse) + self.assertEqual(typed_response.message_id, "snapshot-1") + self.assertEqual(typed_response.documents[0].record_key, "note:1") + self.assertEqual(typed_response.to_wire(), response) + self.assertEqual(source.build_snapshot_response(schema_ids=["mesh.snapshot_note.v1"]).documents[0].record_key, "note:1") + self.assertEqual(response["schemaVersion"], "cultnet.snapshot_response_raw.v0") + self.assertEqual(response["messageId"], "snapshot-1") + self.assertEqual(response["shardId"], "notes") + self.assertEqual(response["shardEpoch"], 4) + self.assertEqual(response["shardLogSequence"], 7) + self.assertEqual([record["recordKey"] for record in response["documents"]], ["note:1"]) + self.assertEqual(response["documents"][0]["schemaId"], "mesh.snapshot_note.v1") + self.assertEqual(response["documents"][0]["payloadEncoding"], "messagepack") + + target = CultMesh.create_node(runtime_id="mesh-snapshot-target") + target.database.register_document(document) + applied = target.database.apply_snapshot_response(response) + self.assertEqual([(record.schema_id, record.record_key) for record in applied], [("mesh.snapshot_note.v1", "note:1")]) + self.assertEqual(target.database.get_required(document, "note:1"), {"body": "include"}) + self.assertIsNone(target.database.get(document, "note:2")) + + typed_target = CultMesh.create_node(runtime_id="mesh-snapshot-typed-target") + typed_target.database.register_document(document) + typed_applied = typed_target.database.apply_snapshot_response(typed_response) + self.assertEqual([(record.schema_id, record.record_key) for record in typed_applied], [("mesh.snapshot_note.v1", "note:1")]) + self.assertEqual(typed_target.database.get_required(document, "note:1"), {"body": "include"}) + + def test_cultmesh_database_filters_snapshot_by_logged_shard_membership(self) -> None: + document = define_database_entry_type( + "mesh.sharded_snapshot_note", + [("body", 0)], + schema_id="mesh.sharded_snapshot_note.v1", + ) + source = CultMesh.create_node(runtime_id="mesh-sharded-snapshot-source") + source.database.register_document(document) + source.database.put_raw_message(document, "note:notes", {"body": "include"}, shard_id="notes", shard_epoch=2) + source.database.put_raw_message(document, "note:other", {"body": "skip"}, shard_id="other", shard_epoch=1) + + response = source.database.build_snapshot_response( + schema_ids=["mesh.sharded_snapshot_note.v1"], + shard_id="notes", + shard_epoch=2, + ) + + self.assertEqual(response.shard_id, "notes") + self.assertEqual(response.shard_epoch, 2) + self.assertEqual([record.record_key for record in response.documents], ["note:notes"]) + + def test_cultmesh_database_creates_shard_log_response_from_raw_mutations(self) -> None: + document = define_database_entry_type( + "mesh.log_note", + [("body", 0)], + schema_id="mesh.log_note.v1", + ) + source = CultMesh.create_node(runtime_id="mesh-log-source") + source.database.register_document(document) + source.database.put_raw_message(document, "note:1", {"body": "first"}, shard_id="notes", shard_epoch=3) + source.database.put_raw_message(document, "note:1", {"body": "second"}, shard_id="notes", shard_epoch=3) + source.database.put_raw_message(document, "note:2", {"body": "other"}, shard_id="other", shard_epoch=1) + source.database.delete_raw_message(document, "note:1", shard_id="notes", shard_epoch=3) + + self.assertEqual(source.database.shard_ids(), ["notes", "other"]) + self.assertEqual(source.database.shard_schema_ids("notes"), ["mesh.log_note.v1"]) + + typed_response = source.database.build_shard_log_response( + message_id="log-1", + shard_id="notes", + shard_epoch=3, + after_sequence=1, + limit=2, + ) + response = source.database.create_shard_log_response( + message_id="log-1", + shard_id="notes", + shard_epoch=3, + after_sequence=1, + limit=2, + ) + + self.assertIsInstance(typed_response, CultNetShardLogResponse) + self.assertEqual(typed_response.message_id, "log-1") + self.assertEqual([entry.sequence for entry in typed_response.entries], [2, 3]) + self.assertEqual(typed_response.to_wire(), response) + self.assertEqual([entry.sequence for entry in source.build_shard_log_response(shard_id="notes").entries], [1, 2, 3]) + self.assertEqual(response["schemaVersion"], "cultnet.shard_log_response.v0") + self.assertEqual(response["messageId"], "log-1") + self.assertEqual(response["shardId"], "notes") + self.assertEqual(response["shardEpoch"], 3) + self.assertFalse(response["resyncRequired"]) + self.assertEqual([entry["sequence"] for entry in response["entries"]], [2, 3]) + self.assertEqual([entry["changeKind"] for entry in response["entries"]], ["updated", "removed"]) + self.assertEqual(response["entries"][0]["put"]["document"]["recordKey"], "note:1") + self.assertEqual(response["entries"][1]["delete"]["recordKey"], "note:1") + empty = source.database.create_shard_log_response(shard_id="missing") + self.assertEqual(empty["shardEpoch"], 0) + self.assertEqual(empty["entries"], []) + self.assertTrue(empty["resyncRequired"]) + self.assertEqual(empty["reason"], "unknown_shard") + stale = source.database.create_shard_log_response(shard_id="notes", shard_epoch=2) + self.assertEqual(stale["shardEpoch"], 3) + self.assertEqual(stale["entries"], []) + self.assertTrue(stale["resyncRequired"]) + self.assertEqual(stale["reason"], "stale_epoch") + with self.assertRaises(ValueError): + source.database.create_shard_log_response(shard_id="notes", after_sequence=-1) + with self.assertRaises(ValueError): + source.database.create_shard_log_response(shard_id="notes", limit=-1) + + target = CultMesh.create_node(runtime_id="mesh-log-target") + target.database.register_document(document) + target.database.put(document, "note:1", {"body": "first"}) + applied = target.database.apply_shard_log_response(response) + self.assertEqual([record.change_kind for record in applied], ["updated", "removed"]) + self.assertIsNone(target.database.get(document, "note:1")) + self.assertIsNone(target.database.get(document, "note:2")) + + typed_target = CultMesh.create_node(runtime_id="mesh-log-typed-target") + typed_target.database.register_document(document) + typed_target.database.put(document, "note:1", {"body": "first"}) + typed_applied = typed_target.database.apply_shard_log_response(typed_response) + self.assertEqual([record.change_kind for record in typed_applied], ["updated", "removed"]) + self.assertIsNone(typed_target.database.get(document, "note:1")) + + def test_cultnet_file_shard_mutation_log_store_persists_authoritative_entries(self) -> None: + document = define_database_entry_type( + "mesh.durable_log_note", + [("body", 0)], + schema_id="mesh.durable_log_note.v1", + ) + with tempfile.TemporaryDirectory() as tmp: + store: CultNetShardMutationLogStore = CultNetFileShardMutationLogStore(Path(tmp) / "logs") + source = CultMesh.create_node(runtime_id="durable-primary") + source.database.register_document(document) + source.database.use_shard_mutation_log_store(store) + source.database.put_raw_message(document, "note:1", {"body": "first"}, shard_id="durable", shard_epoch=4) + source.database.put_raw_message(document, "note:2", {"body": "second"}, shard_id="durable", shard_epoch=4) + + reopened = CultMesh.create_node(runtime_id="durable-primary") + reopened.database.register_document(document) + reopened.database.use_shard_mutation_log_store(CultNetFileShardMutationLogStore(Path(tmp) / "logs")) + response = reopened.database.build_shard_log_response(shard_id="durable", shard_epoch=4) + self.assertEqual(reopened.database.shard_ids(), ["durable"]) + self.assertEqual(reopened.database.shard_schema_ids("durable"), ["mesh.durable_log_note.v1"]) + self.assertEqual([entry.sequence for entry in response.entries], [1, 2]) + self.assertEqual(response.entries[0].raw_document.record_key, "note:1") + + store.compact_through("durable", 1) + compacted = reopened.database.build_shard_log_response(shard_id="durable", shard_epoch=4, after_sequence=0) + retained = reopened.database.build_shard_log_response(shard_id="durable", shard_epoch=4, after_sequence=1) + self.assertTrue(compacted.resync_required) + self.assertEqual(compacted.reason, "compacted_history") + self.assertEqual(compacted.compacted_through, 1) + self.assertEqual([entry.sequence for entry in retained.entries], [2]) + + def test_cultnet_shard_replicator_pulls_logs_and_resyncs_from_snapshot(self) -> None: + document = define_database_entry_type( + "mesh.replica_note", + [("body", 0)], + schema_id="mesh.replica_note.v1", + ) + source = CultMesh.create_node(runtime_id="primary") + source.database.register_document(document) + source.database.put_raw_message(document, "note:1", {"body": "one"}, shard_id="notes", shard_epoch=3) + source.database.put_raw_message(document, "note:2", {"body": "two"}, shard_id="notes", shard_epoch=3) + with tempfile.TemporaryDirectory() as tmp: + cursor_path = Path(tmp) / "replica-cursors.msgpack" + server = CultMesh.serve_node(source) + try: + shard = CultNetShardDescriptor( + shard_id="notes", + owner_runtime_id="primary", + epoch=3, + is_primary=False, + schema_ids=("mesh.replica_note.v1",), + primary_endpoints=(f"cultnet://127.0.0.1:{server.port}",), + ) + target = CultMesh.create_node(runtime_id="replica") + target.database.register_document(document) + cursor_store = CultNetFileShardReplicaCursorStore(cursor_path) + replicator = CultNetShardReplicator( + target.database, + CultNetShardReplicatorOptions( + fetcher=CultNetSchemaShardLogFetcher(timeout_seconds=2.0), + snapshot_fetcher=CultNetSchemaShardSnapshotFetcher(timeout_seconds=2.0), + cursor_store=cursor_store, + batch_size=16, + ), + ) + + first_sequence = replicator.pull_once(shard) + restarted_replicator = CultNetShardReplicator( + target.database, + CultNetShardReplicatorOptions( + fetcher=CultNetSchemaShardLogFetcher(timeout_seconds=2.0), + snapshot_fetcher=CultNetSchemaShardSnapshotFetcher(timeout_seconds=2.0), + cursor_store=CultNetFileShardReplicaCursorStore(cursor_path), + batch_size=16, + ), + ) + second_sequence = restarted_replicator.pull_once(shard) + + self.assertEqual(first_sequence, 2) + self.assertEqual(second_sequence, 2) + self.assertEqual(target.get_required(document, "note:1")["body"], "one") + self.assertEqual(target.get_required(document, "note:2")["body"], "two") + cursor = CultNetFileShardReplicaCursorStore(cursor_path).read("notes") + self.assertIsNotNone(cursor) + assert cursor is not None + self.assertEqual(cursor.last_applied_sequence, 2) + self.assertEqual(cursor.shard_epoch, 3) + finally: + server.stop() + + resync_target = CultMesh.create_node(runtime_id="resync-replica") + resync_target.database.register_document(document) + snapshot = source.database.build_snapshot_response(shard_id="notes", shard_epoch=3, shard_log_sequence=2) + + class CompactingFetcher: + def fetch(self, shard: CultNetShardDescriptor, *, after_sequence: int, limit: int | None = None) -> CultNetShardLogResponse: + return CultNetShardLogResponse( + message_id="compact", + shard_id=shard.shard_id, + shard_epoch=shard.epoch, + entries=(), + resync_required=True, + reason="compacted_history", + compacted_through=after_sequence, + ) + + class SnapshotFetcher: + def fetch(self, shard: CultNetShardDescriptor) -> CultNetRawSnapshotResponse: + return snapshot + + resync_replicator = CultNetShardReplicator( + resync_target.database, + CultNetShardReplicatorOptions( + fetcher=CompactingFetcher(), + snapshot_fetcher=SnapshotFetcher(), + cursor_store=CultNetInMemoryShardReplicaCursorStore(), + ), + ) + resync_sequence = resync_replicator.pull_once(CultNetShardDescriptor( + shard_id="notes", + owner_runtime_id="primary", + epoch=3, + is_primary=False, + schema_ids=("mesh.replica_note.v1",), + primary_endpoints=("cultnet://primary:3075",), + )) + + self.assertEqual(resync_sequence, 2) + self.assertEqual(resync_target.get_required(document, "note:1")["body"], "one") + + def test_cultnet_shard_replicator_background_loop_polls_non_primary_shards(self) -> None: + document = define_database_entry_type( + "mesh.background_replica_note", + [("body", 0)], + schema_id="mesh.background_replica_note.v1", + ) + source = CultMesh.create_node(runtime_id="background-primary") + source.database.register_document(document) + target = CultMesh.create_node(runtime_id="background-replica") + target.database.register_document(document) + cursor_store = CultNetInMemoryShardReplicaCursorStore() + errors: list[Exception] = [] + + class FlakySourceFetcher: + def __init__(self) -> None: + self.calls = 0 + + def fetch(self, shard: CultNetShardDescriptor, *, after_sequence: int, limit: int | None = None) -> CultNetShardLogResponse: + self.calls += 1 + if self.calls == 1: + raise RuntimeError("transient fetch failure") + return source.database.build_shard_log_response( + shard_id=shard.shard_id, + shard_epoch=shard.epoch, + after_sequence=after_sequence, + limit=limit, + ) + + fetcher = FlakySourceFetcher() + shard = CultNetShardDescriptor( + shard_id="background", + owner_runtime_id="background-primary", + epoch=7, + is_primary=False, + schema_ids=("mesh.background_replica_note.v1",), + primary_endpoints=("cultnet://127.0.0.1:3075",), + ) + replicator = CultNetShardReplicator( + target.database, + CultNetShardReplicatorOptions( + fetcher=fetcher, + cursor_store=cursor_store, + batch_size=1, + poll_interval_seconds=0.01, + on_error=errors.append, + ), + ) + try: + source.database.put_raw_message(document, "note:1", {"body": "one"}, shard_id="background", shard_epoch=7) + replicator.start([shard]) + self._wait_until(lambda: target.database.get(document, "note:1") is not None) + source.database.put_raw_message(document, "note:2", {"body": "two"}, shard_id="background", shard_epoch=7) + self._wait_until(lambda: target.database.get(document, "note:2") is not None) + finally: + replicator.stop() + + cursor = cursor_store.read("background") + self.assertEqual(target.get_required(document, "note:1")["body"], "one") + self.assertEqual(target.get_required(document, "note:2")["body"], "two") + self.assertIsNotNone(cursor) + assert cursor is not None + self.assertEqual(cursor.last_applied_sequence, 2) + self.assertEqual(cursor.shard_epoch, 7) + self.assertEqual(len(errors), 1) + self.assertEqual(str(errors[0]), "transient fetch failure") + + def test_cultnet_schema_write_forwarder_sends_raw_writes_to_primary(self) -> None: + document = define_database_entry_type( + "mesh.forward_note", + [("body", 0)], + schema_id="mesh.forward_note.v1", + ) + primary = CultMesh.create_node(runtime_id="forward-primary") + primary.database.register_document(document) + server = CultMesh.serve_node(primary) + try: + shard = CultNetShardDescriptor( + shard_id="forward", + owner_runtime_id="forward-primary", + epoch=9, + is_primary=False, + schema_ids=("mesh.forward_note.v1",), + primary_endpoints=(f"cultnet://127.0.0.1:{server.port}",), + ) + forwarder: CultNetShardWriteForwarder = CultNetSchemaWriteForwarder(timeout_seconds=2.0) + put = document_put_raw( + message_id="forward-put", + key="note:forward", + schema_id=document.catalog_entry().schema_id, + stored_at="2026-06-14T00:00:00Z", + payload=document.encode_payload({"body": "forwarded"}), + ).to_wire() + delete = document_delete( + message_id="forward-delete", + schema_id=document.catalog_entry().schema_id, + record_key="note:forward", + ).to_wire() + + forwarder.forward_put(shard, put) + self._eventually(lambda: primary.database.get(document, "note:forward") is not None) + self.assertEqual(primary.database.get_required(document, "note:forward")["body"], "forwarded") + forwarder.forward_delete(shard, delete) + self._eventually(lambda: primary.database.get(document, "note:forward") is None) + + log = primary.database.build_shard_log_response(shard_id="forward", shard_epoch=9) + self.assertIsNone(primary.database.get(document, "note:forward")) + self.assertEqual([entry.change_kind for entry in log.entries], ["added", "removed"]) + self.assertEqual(log.entries[0].put["shardId"], "forward") + self.assertEqual(log.entries[1].delete["shardEpoch"], 9) + finally: + server.stop() + + def _eventually(self, predicate: Callable[[], bool], *, timeout_seconds: float = 2.0) -> None: + deadline = time.monotonic() + timeout_seconds + while time.monotonic() < deadline: + if predicate(): + return + time.sleep(0.01) + self.assertTrue(predicate()) + + def test_cultmesh_database_watchers_observe_name_and_index_changes(self) -> None: + document = define_database_entry_type( + "mesh.named_watch", + [("name", 0), ("kind", 1)], + name="name", + indexes={"kind": "kind"}, + ) + node = CultMesh.create_node(runtime_id="mesh-named-watch") + node.database.register_document(document) + name_changes: list[CultMeshDatabaseChange] = [] + index_changes: list[CultMeshDatabaseChange] = [] + + node.database.watch_by_name(document, "Potion", name_changes.append) + node.database.watch_by_index(document, "kind", "consumable", index_changes.append) + + node.database.put(document, "item:1", {"name": "Potion", "kind": "consumable"}) + node.database.put(document, "item:2", {"name": "Sword", "kind": "weapon"}) + node.database.put(document, "item:1", {"name": "Elixir", "kind": "rare"}) + node.database.delete(document, "item:1") + + self.assertEqual([change.change_kind for change in name_changes], ["added", "updated"]) + self.assertEqual([change.record_key for change in name_changes], ["item:1", "item:1"]) + self.assertEqual(name_changes[1].previous_value, {"name": "Potion", "kind": "consumable"}) + self.assertEqual([change.change_kind for change in index_changes], ["added", "updated"]) + self.assertEqual([change.record_key for change in index_changes], ["item:1", "item:1"]) + self.assertEqual(index_changes[1].value, {"name": "Elixir", "kind": "rare"}) + + def test_cultmesh_database_collection_reads_resolve_same_schema_aliases(self) -> None: + @dataclass + class CanonicalItem: + name: str + kind: str + + @dataclass + class UiItem: + name: str + kind: str + + document = define_database_entry_type( + "mesh.alias_collection_item", + [("name", 0), ("kind", 1)], + cls=CanonicalItem, + name="name", + indexes={"kind": "kind"}, + schema_id="mesh.alias_collection_item.v1", + schema_name="mesh.alias_collection_item", + schema_version="mesh.alias_collection_item.v1", + ) + alias = define_database_entry_type( + "mesh.alias_collection_item.ui", + [("name", 0), ("kind", 1)], + cls=UiItem, + name="name", + indexes={"kind": "kind"}, + schema_id="mesh.alias_collection_item.v1", + schema_name="mesh.alias_collection_item", + schema_version="mesh.alias_collection_item.v1", + ) + node = CultMesh.create_node(runtime_id="mesh-alias-collection") + node.database.register_document(document) + + node.database.put(alias, "item:potion", UiItem("Potion", "consumable")) + node.database.put(document, "item:sword", CanonicalItem("Sword", "weapon")) + + all_items = node.database.get_all(alias) + potion = node.database.get_by_name(alias, "Potion") + sword = node.get_by_index(alias, "kind", "weapon") + + self.assertEqual([item.name for item in all_items], ["Potion", "Sword"]) + self.assertTrue(all(isinstance(item, UiItem) for item in all_items)) + self.assertIsInstance(potion, UiItem) + self.assertEqual(potion.kind, "consumable") + self.assertIsInstance(sword, UiItem) + self.assertEqual(sword.name, "Sword") + self.assertIsNone(node.database.get_by_name(alias, "Missing")) + + def test_cultmesh_database_alias_collection_watches_emit_alias_values(self) -> None: + @dataclass + class CanonicalItem: + name: str + kind: str + + @dataclass + class UiItem: + name: str + kind: str + + document = define_database_entry_type( + "mesh.alias_collection_watch_item", + [("name", 0), ("kind", 1)], + cls=CanonicalItem, + name="name", + indexes={"kind": "kind"}, + schema_id="mesh.alias_collection_watch_item.v1", + schema_name="mesh.alias_collection_watch_item", + schema_version="mesh.alias_collection_watch_item.v1", + ) + alias = define_database_entry_type( + "mesh.alias_collection_watch_item.ui", + [("name", 0), ("kind", 1)], + cls=UiItem, + name="name", + indexes={"kind": "kind"}, + schema_id="mesh.alias_collection_watch_item.v1", + schema_name="mesh.alias_collection_watch_item", + schema_version="mesh.alias_collection_watch_item.v1", + ) + node = CultMesh.create_node(runtime_id="mesh-alias-collection-watch") + node.database.register_document(document) + name_changes: list[CultMeshDatabaseChange] = [] + index_changes: list[CultMeshDatabaseChange] = [] + + node.database.watch_by_name(alias, "Potion", name_changes.append) + node.database.watch_by_index(alias, "kind", "consumable", index_changes.append) + + node.database.put(document, "item:potion", CanonicalItem("Potion", "consumable")) + node.database.put(document, "item:potion", CanonicalItem("Elixir", "rare")) + + self.assertEqual([change.change_kind for change in name_changes], ["added", "updated"]) + self.assertTrue(all(change.document.type == alias.type for change in name_changes)) + self.assertIsInstance(name_changes[0].value, UiItem) + self.assertIsInstance(name_changes[1].value, UiItem) + self.assertIsInstance(name_changes[1].previous_value, UiItem) + self.assertEqual(name_changes[1].previous_value.name, "Potion") + self.assertEqual(name_changes[1].value.name, "Elixir") + self.assertEqual([change.change_kind for change in index_changes], ["added", "updated"]) + self.assertTrue(all(change.document.type == alias.type for change in index_changes)) + self.assertIsInstance(index_changes[0].value, UiItem) + self.assertIsInstance(index_changes[1].previous_value, UiItem) + + def test_cultmesh_database_watch_by_name_and_index_validate_lookup_shape(self) -> None: + document = define_database_entry_type("mesh.unnamed_watch", [("body", 0)]) + node = CultMesh.create_node(runtime_id="mesh-watch-validation") + node.database.register_document(document) + + with self.assertRaises(ValueError): + node.database.watch_by_name(document, "missing", lambda _: None) + with self.assertRaises(ValueError): + node.database.watch_by_index(document, "missing", "value", lambda _: None) + with self.assertRaises(ValueError): + node.database.watch_by_index(document, "", "value", lambda _: None) + with self.assertRaises(ValueError): + node.database.watch_by_index(document, "missing", "", lambda _: None) + + def test_cultmesh_facade_matches_peer_runtime_entrypoints(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + store_path = Path(tmp) / "mesh.cc" + node = CultMesh.start_node(store_path, runtime_id="mesh-facade") + + self.assertEqual(node.runtime_id, "mesh-facade") + self.assertIsInstance(CultMesh.create_node(), type(node)) + self.assertIsInstance(CultMesh.create_verse_catalog(), CultMeshVerseCatalog) + self.assertIsInstance(CultMesh.create_peer_catalog(), CultMeshPeerCatalog) + self.assertIsInstance(CultMesh.create_authority_lease_catalog(), CultMeshAuthorityLeaseCatalog) + self.assertIsInstance(CultMesh.create_stream_catalog(), CultMeshStreamCatalog) + self.assertIsInstance(CultMesh.create_schema_catalog(), CultNetSchemaCatalog) + self.assertIsInstance(CultMesh.create_builtin_schema_catalog(), CultNetSchemaCatalog) + self.assertIsInstance(CultMesh.create_shard_catalog(), CultNetShardCatalog) + builtins = CultMesh.create_builtin_schema_catalog( + include_schema_json=False, + kinds=["shared_contract"], + ) + self.assertEqual( + builtins.list()[0].schema_id, + "https://github.com/GameCult/cultnet-ts/contracts/cultnet.transport-profile.schema.json", + ) + self.assertIsNone(builtins.list()[0].schema_json) + peer_exchange_schema_id = ( + "https://github.com/GameCult/cultnet-ts/contracts/cultmesh.peer-exchange-request.schema.json" + ) + filtered_builtin = CultMesh.create_builtin_schema_catalog( + include_schema_json=True, + schema_ids=[peer_exchange_schema_id], + ) + self.assertEqual( + filtered_builtin.list()[0].schema_version, + "cultmesh.peer_exchange_request.v0", + ) + self.assertIn( + "cultmesh.peer_exchange_request.v0", + filtered_builtin.list()[0].schema_json or "", + ) + shard_catalog = CultMesh.create_shard_catalog() + shard_catalog.upsert( + CultNetShardDescriptor( + shard_id="python-notes-a", + owner_runtime_id="mesh-facade", + epoch=7, + is_primary=True, + schema_ids=("python.note.v1",), + key_prefix="note:", + ) + ) + self.assertEqual( + [ + shard.shard_id + for shard in shard_catalog.list(schema_ids=["python.note.v1"], record_keys=["note:1"]) + ], + ["python-notes-a"], + ) + verse_client = CultMesh.create_verse_discovery_client("127.0.0.1", 4010, timeout_seconds=1.5) + peer_client = CultMesh.create_peer_exchange_client("127.0.0.1", 4011, timeout_seconds=1.5) + raw_client = CultMesh.create_client("127.0.0.1", 4012, timeout_seconds=1.5) + connected_client = CultMesh.connect_client("127.0.0.1", 4013, timeout_seconds=1.5) + self.assertIsInstance(verse_client, CultMeshVerseDiscoveryClient) + self.assertIsInstance(peer_client, CultMeshPeerExchangeClient) + self.assertIsInstance(verse_client, CultMeshDiscoveryClient) + self.assertIsInstance(peer_client, CultMeshDiscoveryClient) + self.assertIsInstance(raw_client, CultNetRawClient) + self.assertIsInstance(connected_client, CultNetRawClient) + self.assertEqual((verse_client.host, verse_client.port, verse_client.timeout_seconds), ("127.0.0.1", 4010, 1.5)) + self.assertEqual((peer_client.host, peer_client.port, peer_client.timeout_seconds), ("127.0.0.1", 4011, 1.5)) + self.assertEqual((raw_client.host, raw_client.port, raw_client.timeout_seconds), ("127.0.0.1", 4012, 1.5)) + self.assertEqual((connected_client.host, connected_client.port, connected_client.timeout_seconds), ("127.0.0.1", 4013, 1.5)) + + def test_cultmesh_simulation_fact_uses_csharp_slot_contract(self) -> None: + import msgpack # type: ignore + + candidate = { + "shardId": "arena", + "shardEpoch": 4, + "frame": 100, + "subjectId": "bob", + "claimKind": "hit", + "claimHash": compute_simulation_claim_hash("hit", "alice", "bob", "frame:100"), + "claimSummary": "alice shot bob first", + "witnessCount": 2, + "supportWeight": 2.0, + "totalWeight": 2.0, + "confidence": 1.0, + "hasQuorum": True, + } + + fact = CultMeshSimulationFact.from_candidate(candidate, committed_at="2026-06-13T00:00:00Z") + payload = simulation_fact_document.encode_payload(fact) + slots = msgpack.unpackb(payload, raw=False) + + self.assertEqual(CultMeshSimulationFact.create_record_key(candidate), f"simulation:{fact.fact_id}") + self.assertEqual(slots[0], fact.fact_id) + self.assertEqual(slots[1], "arena") + self.assertEqual(slots[2], 4) + self.assertEqual(slots[3], 100) + self.assertEqual(slots[4], "bob") + self.assertEqual(slots[5], "hit") + self.assertEqual(slots[6], candidate["claimHash"]) + self.assertEqual(slots[7], "alice shot bob first") + self.assertEqual(slots[8], 2) + self.assertEqual(slots[9], 2.0) + self.assertEqual(slots[10], 2.0) + self.assertEqual(slots[11], 1.0) + self.assertEqual(slots[12], "2026-06-13T00:00:00Z") + + def test_cultmesh_simulation_fact_committer_rejects_without_quorum_and_stores_fact(self) -> None: + candidate = { + "shardId": "arena", + "shardEpoch": 4, + "frame": 100, + "subjectId": "bob", + "claimKind": "hit", + "claimHash": compute_simulation_claim_hash("hit", "alice", "bob", "frame:100"), + "claimSummary": "alice shot bob first", + "witnessCount": 2, + "supportWeight": 2.0, + "totalWeight": 2.0, + "confidence": 1.0, + "hasQuorum": True, + } + + with tempfile.TemporaryDirectory() as tmp: + node = CultMesh.create_node(Path(tmp) / "facts.cc", runtime_id="mesh-facts") + committer = CultMesh.create_simulation_fact_committer(node) + + rejected = dict(candidate) + rejected["hasQuorum"] = False + with self.assertRaisesRegex(ValueError, "before quorum"): + committer.commit(rejected) + + committed = committer.commit(candidate, committed_at="2026-06-13T00:00:00Z") + stored = node.get_required(simulation_fact_document, committed.key) + + self.assertEqual(stored.claim_hash, candidate["claimHash"]) + self.assertEqual(stored.committed_at, "2026-06-13T00:00:00Z") + self.assertEqual(committed.fact.fact_id, stored.fact_id) + + def test_cultmesh_game_session_submits_observations_and_commits_quorum_once(self) -> None: + claim_hash = compute_simulation_claim_hash("hit", "alice", "bob", "frame:100") + first = simulation_observation( + message_id="obs-1", + witness_runtime_id="watcher-1", + shard_id="arena", + shard_epoch=4, + frame=100, + subject_id="bob", + claim_kind="hit", + claim_hash=claim_hash, + claim_summary="alice shot bob first", + ).to_wire() + second = simulation_observation( + message_id="obs-2", + witness_runtime_id="watcher-2", + shard_id="arena", + shard_epoch=4, + frame=100, + subject_id="bob", + claim_kind="hit", + claim_hash=claim_hash, + claim_summary="alice shot bob first", + ).to_wire() + + with tempfile.TemporaryDirectory() as tmp: + node = CultMesh.create_node(Path(tmp) / "session.cc", runtime_id="mesh-session") + session = CultMesh.create_game_session( + node, + CultMeshGameSessionOptions( + consensus_options=CultNetSimulationConsensusOptions(minimum_witnesses=2, quorum_ratio=1.0) + ), + ) + seen_candidates: list[CultNetSimulationConsensusCandidate] = [] + seen_facts: list[CultMeshDatabaseChange] = [] + unsubscribe_candidates = session.watch_candidates(seen_candidates.append) + unsubscribe_facts = session.watch_simulation_facts(seen_facts.append) + + self.assertEqual(session.submit_and_commit(CultNetSimulationObservation.from_wire(first)), []) + typed_candidates = session.submit_observation_candidates(CultNetSimulationObservation.from_wire(second)) + commits = session.commit_quorum_candidate_objects(typed_candidates) + replay = session.commit_quorum_candidates(session.submit_observation(second)) + unsubscribe_candidates() + unsubscribe_facts() + + self.assertEqual(len(typed_candidates), 1) + self.assertTrue(typed_candidates[0].has_quorum) + self.assertEqual(len(commits), 1) + self.assertEqual(replay, []) + self.assertEqual([candidate.claim_hash for candidate in seen_candidates], [claim_hash, claim_hash, claim_hash]) + self.assertEqual(len(seen_facts), 1) + self.assertEqual(seen_facts[0].change_kind, "added") + self.assertEqual(seen_facts[0].value.claim_hash, claim_hash) + stored = node.get_required(simulation_fact_document, commits[0].key) + self.assertEqual(stored.claim_hash, claim_hash) + self.assertEqual(stored.witness_count, 2) + + def test_cultmesh_game_session_serves_catalogs_and_observations_over_wire(self) -> None: + verse_catalog = CultMeshVerseCatalog() + peer_catalog = CultMeshPeerCatalog() + verse_catalog.upsert(CultMeshVerseDescriptor( + verse_id="session-verse", + display_name="Session Verse", + authority_model="local", + compatibility=CultMeshVerseCompatibility("cultmesh.v0", "session-rules"), + )) + peer_catalog.upsert(CultMeshPeerCard( + peer_id="session-peer", + verse_id="session-verse", + endpoints=("cultnet://127.0.0.1:0",), + roles=("simulation-observer", "read-replica"), + shard_ids=("arena",), + )) + session = CultMesh.create_game_session( + CultMesh.create_node(runtime_id="session-peer"), + CultMeshGameSessionOptions( + verse_catalog=verse_catalog, + peer_catalog=peer_catalog, + consensus_options=CultNetSimulationConsensusOptions(minimum_witnesses=2, quorum_ratio=1.0), + ), + ) + server = session.serve(display_name="Session Peer") + try: + raw_client = CultMesh.create_client("127.0.0.1", server.port, timeout_seconds=2.0) + hello_response = raw_client.request( + hello(runtime_id="session-prober"), + expected_schema_version="cultnet.hello.v0", + ) + discovery_client = CultMesh.create_verse_discovery_client("127.0.0.1", server.port, timeout_seconds=2.0) + verses = discovery_client.fetch_verses(transport_version="cultmesh.v0") + peers = discovery_client.fetch_peers(verse_id="session-verse", roles=["simulation-observer"]) + claim_hash = compute_simulation_claim_hash("hit", "alice", "bob", "frame:100") + first = raw_client.request( + simulation_observation( + message_id="session-wire-1", + witness_runtime_id="watcher-1", + shard_id="arena", + shard_epoch=4, + frame=100, + subject_id="bob", + claim_kind="hit", + claim_hash=claim_hash, + claim_summary="alice shot bob first", + ), + expected_schema_version="cultnet.simulation_consensus_candidate.v0", + ) + second = raw_client.request( + simulation_observation( + message_id="session-wire-2", + witness_runtime_id="watcher-2", + shard_id="arena", + shard_epoch=4, + frame=100, + subject_id="bob", + claim_kind="hit", + claim_hash=claim_hash, + claim_summary="alice shot bob first", + ), + expected_schema_version="cultnet.simulation_consensus_candidate.v0", + ) + finally: + server.stop() + + self.assertIn("cultnet.simulation_observation.v0", hello_response["supportedMessageVersions"]) + self.assertEqual(verses[0].verse_id, "session-verse") + self.assertEqual(peers[0].peer_id, "session-peer") + self.assertIn("simulation-observer", peers[0].roles) + self.assertFalse(first["hasQuorum"]) + self.assertEqual(first["witnessCount"], 1) + self.assertTrue(second["hasQuorum"]) + self.assertEqual(second["witnessCount"], 2) + + def test_cultmesh_game_session_can_disable_served_simulation_observations(self) -> None: + verse_catalog = CultMeshVerseCatalog() + verse_catalog.upsert(CultMeshVerseDescriptor( + verse_id="session-quiet", + display_name="Quiet Session", + authority_model="local", + compatibility=CultMeshVerseCompatibility("cultmesh.v0", "quiet-rules"), + )) + session = CultMesh.create_game_session( + CultMesh.create_node(runtime_id="quiet-session-peer"), + CultMeshGameSessionOptions( + verse_catalog=verse_catalog, + serve_simulation_observations=False, + ), + ) + server = session.serve(display_name="Quiet Session Peer") + try: + raw_client = CultMesh.create_client("127.0.0.1", server.port, timeout_seconds=2.0) + hello_response = raw_client.request( + hello(runtime_id="quiet-session-prober"), + expected_schema_version="cultnet.hello.v0", + ) + discovery_client = CultMesh.create_verse_discovery_client("127.0.0.1", server.port, timeout_seconds=2.0) + verses = discovery_client.fetch_verses(transport_version="cultmesh.v0") + with self.assertRaisesRegex(CultNetPeerError, "Simulation observations are not enabled") as raised: + raw_client.request( + simulation_observation( + message_id="quiet-session-sim", + witness_runtime_id="watcher-1", + shard_id="arena", + shard_epoch=4, + frame=100, + subject_id="bob", + claim_kind="hit", + claim_hash=compute_simulation_claim_hash("hit", "alice", "bob", "frame:100"), + ), + expected_schema_version="cultnet.simulation_consensus_candidate.v0", + ) + finally: + server.stop() + + self.assertNotIn("cultnet.simulation_observation.v0", hello_response["supportedMessageVersions"]) + self.assertEqual(verses[0].verse_id, "session-quiet") + self.assertEqual(raised.exception.response["code"], "simulation_observations_disabled") + + def test_cultmesh_game_session_prediction_requires_scope_and_reconciles_shard_log(self) -> None: + note_doc = define_database_entry_type( + "mesh.input", + [("body", 0)], + schema_id="mesh.input.v1", + ) + with tempfile.TemporaryDirectory() as tmp: + node = CultMesh.create_node(Path(tmp) / "prediction.cc", runtime_id="client-a") + node.register_document(note_doc) + session = CultMesh.create_game_session( + node, + CultMeshGameSessionOptions( + client_authority_scopes=( + CultNetClientAuthorityScope( + "client-a", + schema_ids=("mesh.input.v1",), + key_prefix="input:client-a", + ), + ) + ), + ) + + with self.assertRaisesRegex(ValueError, "does not have client prediction authority"): + session.predict(note_doc, "input:other", {"body": "nope"}) + + prediction = session.predict(note_doc, "input:client-a:move", {"body": "predicted"}) + put = document_put_raw( + message_id="authoritative", + key=prediction.key, + schema_id=prediction.schema_id, + stored_at="2026-06-13T00:00:00Z", + payload=note_doc.encode_payload({"body": "authoritative"}), + shard_id="inputs", + shard_epoch=1, + ) + authoritative_response = { + "schemaVersion": "cultnet.shard_log_response.v0", + "messageId": "inputs-log", + "shardId": "inputs", + "shardEpoch": 1, + "entries": [ + { + "sequence": 1, + "committedAt": "2026-06-13T00:00:00Z", + "changeKind": "updated", + "put": put.to_wire(), + } + ], + "resyncRequired": False, + } + changes = session.apply_shard_log_response(CultNetShardLogResponse.from_wire(authoritative_response)) + + self.assertEqual(changes[0].change_kind, "reconciled") + self.assertEqual(node.get_required(note_doc, prediction.key)["body"], "authoritative") + self.assertEqual(session.pending_predictions(), ()) + self.assertEqual(session.resimulation_inputs(), ()) + + def test_cultmesh_game_session_partial_reconciliation_keeps_unmatched_predictions(self) -> None: + note_doc = define_database_entry_type( + "mesh.partial_input", + [("body", 0)], + schema_id="mesh.partial_input.v1", + ) + node = CultMesh.create_node(runtime_id="client-partial") + node.register_document(note_doc) + session = CultMesh.create_game_session( + node, + CultMeshGameSessionOptions( + client_authority_scopes=( + CultNetClientAuthorityScope( + "client-partial", + schema_ids=("mesh.partial_input.v1",), + key_prefix="input:client-partial", + ), + ) + ), + ) + pending = session.predict(note_doc, "input:client-partial:pending", {"body": "pending-local"}) + accepted = session.predict(note_doc, "input:client-partial:accepted", {"body": "accepted-local"}) + put = document_put_raw( + message_id="authoritative-partial", + key=accepted.key, + schema_id=accepted.schema_id, + stored_at="2026-06-13T00:00:00Z", + payload=note_doc.encode_payload({"body": "accepted-authority"}), + shard_id="inputs", + shard_epoch=1, + ) + + changes = session.apply_shard_log_response({ + "schemaVersion": "cultnet.shard_log_response.v0", + "messageId": "inputs-partial-log", + "shardId": "inputs", + "shardEpoch": 1, + "entries": [ + { + "sequence": 1, + "committedAt": "2026-06-13T00:00:00Z", + "changeKind": "updated", + "put": put.to_wire(), + } + ], + "resyncRequired": False, + }) + + self.assertEqual([(change.change_kind, change.record_key) for change in changes], [ + ("reconciled", accepted.key), + ]) + self.assertEqual(node.get_required(note_doc, accepted.key)["body"], "accepted-authority") + self.assertEqual(node.get_required(note_doc, pending.key)["body"], "pending-local") + self.assertEqual([prediction.key for prediction in session.pending_predictions()], [pending.key]) + self.assertEqual([prediction.key for prediction in session.resimulation_inputs()], [pending.key]) + + def test_cultmesh_game_session_rolls_back_pending_predictions(self) -> None: + note_doc = define_database_entry_type( + "mesh.rollback_input", + [("body", 0)], + schema_id="mesh.rollback_input.v1", + ) + node = CultMesh.create_node(runtime_id="client-rollback") + node.register_document(note_doc) + node.put(note_doc, "input:client-rollback:existing", {"body": "previous"}) + session = CultMesh.create_game_session( + node, + CultMeshGameSessionOptions( + client_authority_scopes=( + CultNetClientAuthorityScope( + "client-rollback", + schema_ids=("mesh.rollback_input.v1",), + key_prefix="input:client-rollback", + ), + ) + ), + ) + + existing = session.predict(note_doc, "input:client-rollback:existing", {"body": "predicted-existing"}) + created = session.predict(note_doc, "input:client-rollback:new", {"body": "predicted-new"}) + self.assertEqual( + [prediction.key for prediction in session.pending_predictions()], + ["input:client-rollback:existing", "input:client-rollback:new"], + ) + self.assertEqual([prediction.key for prediction in session.resimulation_inputs()], [ + "input:client-rollback:existing", + "input:client-rollback:new", + ]) + + restored = session.rollback_prediction(existing) + self.assertIsNotNone(restored) + assert restored is not None + self.assertEqual(restored.change_kind, "rolled_back") + self.assertEqual(restored.value, {"body": "previous"}) + self.assertEqual(node.get_required(note_doc, "input:client-rollback:existing")["body"], "previous") + + rolled_back = session.rollback_predictions() + self.assertEqual([(change.change_kind, change.record_key, change.value) for change in rolled_back], [ + ("rolled_back", created.key, None), + ]) + self.assertIsNone(node.get(note_doc, created.key)) + self.assertEqual(session.pending_predictions(), ()) + + def test_cultmesh_game_session_authoritative_delete_rolls_back_prediction(self) -> None: + note_doc = define_database_entry_type( + "mesh.deleted_input", + [("body", 0)], + schema_id="mesh.deleted_input.v1", + ) + node = CultMesh.create_node(runtime_id="client-delete") + node.register_document(note_doc) + session = CultMesh.create_game_session( + node, + CultMeshGameSessionOptions( + client_authority_scopes=( + CultNetClientAuthorityScope( + "client-delete", + schema_ids=("mesh.deleted_input.v1",), + key_prefix="input:client-delete", + ), + ) + ), + ) + + prediction = session.predict(note_doc, "input:client-delete:move", {"body": "predicted"}) + delete = document_delete( + message_id="authoritative-delete", + schema_id=prediction.schema_id, + record_key=prediction.key, + shard_id="inputs", + shard_epoch=1, + ) + changes = session.apply_shard_log_response({ + "schemaVersion": "cultnet.shard_log_response.v0", + "messageId": "inputs-delete-log", + "shardId": "inputs", + "shardEpoch": 1, + "entries": [ + { + "sequence": 1, + "committedAt": "2026-06-13T00:00:00Z", + "changeKind": "removed", + "delete": delete.to_wire(), + } + ], + "resyncRequired": False, + }) + + self.assertEqual(changes[0].change_kind, "rolled_back") + self.assertIsNone(node.get(note_doc, prediction.key)) + self.assertEqual(session.pending_predictions(), ()) + + def test_cultmesh_database_watchers_observe_authoritative_shard_log_reconciliation(self) -> None: + note_doc = define_database_entry_type( + "mesh.watched_input", + [("body", 0)], + schema_id="mesh.watched_input.v1", + ) + node = CultMesh.create_node(runtime_id="client-watch") + node.database.register_document(note_doc) + seen: list[CultMeshDatabaseChange] = [] + node.database.watch_record(note_doc, "input:client-watch:move", seen.append) + session = CultMesh.create_game_session( + node, + CultMeshGameSessionOptions( + client_authority_scopes=( + CultNetClientAuthorityScope( + "client-watch", + schema_ids=("mesh.watched_input.v1",), + key_prefix="input:client-watch", + ), + ) + ), + ) + + prediction = session.predict(note_doc, "input:client-watch:move", {"body": "predicted"}) + put = document_put_raw( + message_id="authoritative-watch", + key=prediction.key, + schema_id=prediction.schema_id, + stored_at="2026-06-13T00:00:00Z", + payload=note_doc.encode_payload({"body": "authoritative"}), + shard_id="inputs", + shard_epoch=1, + ) + session_changes = session.apply_shard_log_response({ + "schemaVersion": "cultnet.shard_log_response.v0", + "messageId": "inputs-watch-log", + "shardId": "inputs", + "shardEpoch": 1, + "entries": [ + { + "sequence": 1, + "committedAt": "2026-06-13T00:00:00Z", + "changeKind": "updated", + "put": put.to_wire(), + } + ], + "resyncRequired": False, + }) + + self.assertEqual([change.change_kind for change in seen], ["added", "updated"]) + self.assertEqual(seen[1].value, {"body": "authoritative"}) + self.assertEqual(seen[1].previous_value, {"body": "predicted"}) + self.assertEqual(session_changes[0].change_kind, "reconciled") + + def test_cultmesh_verse_catalog_response_matches_schema_v0_wire_shape(self) -> None: + import msgpack # type: ignore + + catalog = CultMeshVerseCatalog() + catalog.upsert( + CultMeshVerseDescriptor( + verse_id="aetheria-main", + display_name="Aetheria", + authority_model="OperatorCluster", + compatibility=CultMeshVerseCompatibility( + transport_version="cultmesh.v0", + rules_hash="rules", + compatible_verse_ids=("aetheria-modded",), + required_plugin_ids=("core",), + optional_plugin_ids=("skylands",), + ), + discovery_endpoints=("cultmesh://aetheria.example.test:3075",), + authority_runtime_ids=("runtime-a",), + description="main branch", + ) + ) + + response = catalog.create_response(verse_catalog_request("verses-1")) + decoded = msgpack.unpackb(msgpack.packb(response, use_bin_type=True), raw=False) + self.assertEqual(decoded["schemaVersion"], "cultmesh.verse_catalog_response.v0") + self.assertEqual(decoded["messageId"], "verses-1") + self.assertEqual(decoded["verses"][0]["verseId"], "aetheria-main") + self.assertEqual(decoded["verses"][0]["compatibility"]["requiredPluginIds"], ["core"]) + + def test_cultmesh_verse_catalog_watches_updates_and_finds_transfer_targets(self) -> None: + source = CultMeshVerseDescriptor( + verse_id="aetheria-main", + display_name="Aetheria", + authority_model="federated", + compatibility=CultMeshVerseCompatibility( + transport_version="cultmesh.v0", + rules_hash="rules-main", + ), + ) + compatible = CultMeshVerseDescriptor( + verse_id="aetheria-modded", + display_name="Aetheria Modded", + authority_model="federated", + compatibility=CultMeshVerseCompatibility( + transport_version="cultmesh.v0", + rules_hash="rules-modded", + compatible_verse_ids=("aetheria-main",), + ), + ) + incompatible = CultMeshVerseDescriptor( + verse_id="old-world", + display_name="Old World", + authority_model="solo", + compatibility=CultMeshVerseCompatibility( + transport_version="cultmesh.v0", + rules_hash="rules-old", + ), + ) + catalog = CultMeshVerseCatalog() + seen: list[str] = [] + unsubscribe = catalog.watch(lambda verse: seen.append(verse.verse_id)) + + catalog.upsert(source) + catalog.apply_response({ + "schemaVersion": "cultmesh.verse_catalog_response.v0", + "messageId": "verses-watch", + "verses": [compatible.to_wire(), incompatible.to_wire()], + }) + unsubscribe() + catalog.upsert(CultMeshVerseDescriptor( + verse_id="after-unsubscribe", + display_name="After", + authority_model="none", + compatibility=CultMeshVerseCompatibility("cultmesh.v0", "rules-after"), + )) + + self.assertEqual(seen, ["aetheria-main", "aetheria-modded", "old-world"]) + self.assertEqual([verse.verse_id for verse in catalog.verses], ["aetheria-main", "aetheria-modded", "after-unsubscribe", "old-world"]) + self.assertEqual(catalog.get("aetheria-modded"), compatible) + self.assertEqual([verse.verse_id for verse in catalog.find_transfer_targets(source)], ["aetheria-modded"]) + + def test_cultmesh_peer_exchange_response_matches_schema_v0_wire_shape(self) -> None: + import msgpack # type: ignore + + catalog = CultMeshPeerCatalog() + catalog.upsert( + CultMeshPeerCard( + peer_id="peer-a", + verse_id="aetheria-main", + endpoints=("cultnet://peer-a.example.test:3075",), + roles=("discovery", "read-replica"), + shard_ids=("players",), + region="eu-west", + authority_lease_id="lease-1", + expires_at="2026-05-20T12:00:00.0000000Z", + signature="sig", + ) + ) + + response = catalog.create_response( + peer_exchange_request("pex-1", verse_id="aetheria-main", roles=["read-replica"]) + ) + decoded = msgpack.unpackb(msgpack.packb(response, use_bin_type=True), raw=False) + self.assertEqual(decoded["schemaVersion"], "cultmesh.peer_exchange_response.v0") + self.assertEqual(decoded["messageId"], "pex-1") + self.assertEqual(decoded["peers"][0]["peerId"], "peer-a") + self.assertIn("read-replica", decoded["peers"][0]["roles"]) + self.assertEqual(decoded["peers"][0]["authorityLeaseId"], "lease-1") + + def test_cultmesh_peer_catalog_watches_updates_and_gets_peers(self) -> None: + first = CultMeshPeerCard( + peer_id="peer-a", + verse_id="aetheria-main", + endpoints=("cultnet://peer-a.example.test:3075",), + roles=("discovery", "read-replica"), + ) + second = CultMeshPeerCard( + peer_id="peer-b", + verse_id="aetheria-main", + endpoints=("cultnet://peer-b.example.test:3075",), + roles=("shard-primary",), + ) + catalog = CultMeshPeerCatalog() + seen: list[str] = [] + unsubscribe = catalog.watch(lambda peer: seen.append(peer.peer_id)) + + catalog.upsert(first) + catalog.apply_response({ + "schemaVersion": "cultmesh.peer_exchange_response.v0", + "messageId": "peers-watch", + "peers": [second.to_wire()], + }) + unsubscribe() + catalog.upsert(CultMeshPeerCard( + peer_id="peer-c", + verse_id="aetheria-main", + endpoints=("cultnet://peer-c.example.test:3075",), + roles=("read-replica",), + )) + + self.assertEqual(seen, ["peer-a", "peer-b"]) + self.assertTrue(first.has_role("read-replica")) + self.assertEqual([peer.peer_id for peer in catalog.peers], ["peer-a", "peer-b", "peer-c"]) + self.assertEqual(catalog.get("peer-b"), second) + self.assertEqual([peer.peer_id for peer in catalog.find("aetheria-main", role="read-replica")], ["peer-a", "peer-c"]) + + def test_cultmesh_discovery_client_fetches_typed_catalogs_over_cultnet_frames(self) -> None: + import msgpack # type: ignore + from cultnet_py import read_frame, write_frame + + verses = CultMeshVerseCatalog() + verses.upsert( + CultMeshVerseDescriptor( + verse_id="aetheria-main", + display_name="Aetheria", + authority_model="federated", + compatibility=CultMeshVerseCompatibility( + transport_version="cultmesh.v0", + rules_hash="rules-1", + required_plugin_ids=("core",), + ), + discovery_endpoints=("cultmesh://aetheria.example.test:3075",), + authority_runtime_ids=("runtime-a",), + ) + ) + peers = CultMeshPeerCatalog() + peers.upsert( + CultMeshPeerCard( + peer_id="peer-a", + verse_id="aetheria-main", + endpoints=("cultnet://peer-a.example.test:3075",), + roles=("read-replica",), + shard_ids=("players",), + ) + ) + + ready = threading.Event() + server_error: list[BaseException] = [] + + def serve_requests() -> None: + try: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server: + server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + server.bind(("127.0.0.1", 0)) + port_holder.append(server.getsockname()[1]) + server.listen(8) + ready.set() + for _ in range(8): + connection, _ = server.accept() + with connection: + stream = connection.makefile("rwb") + request = msgpack.unpackb(read_frame(stream), raw=False) + if request["schemaVersion"] == "cultmesh.verse_catalog_request.v0": + response = verses.create_response(request) + elif request["schemaVersion"] == "cultmesh.peer_exchange_request.v0": + response = peers.create_response(request) + else: + raise AssertionError(f"unexpected request {request['schemaVersion']}") + write_frame(stream, msgpack.packb(response, use_bin_type=True)) + stream.flush() + except BaseException as error: + server_error.append(error) + ready.set() + + port_holder: list[int] = [] + thread = threading.Thread(target=serve_requests, daemon=True) + thread.start() + self.assertTrue(ready.wait(2.0)) + self.assertFalse(server_error) + + client = CultMeshDiscoveryClient("127.0.0.1", port_holder[0], timeout_seconds=2.0) + fetched_verses = client.fetch_verses(transport_version="cultmesh.v0") + fetched_peers = client.fetch_peers(verse_id="aetheria-main", roles=["read-replica"]) + local_verses = CultMeshVerseCatalog() + local_peers = CultMeshPeerCatalog() + synced_verses = client.sync_verse_catalog(local_verses, transport_version="cultmesh.v0") + synced_peers = client.sync_peer_catalog(local_peers, verse_id="aetheria-main", roles=["read-replica"]) + discovered_verses = CultMeshVerseCatalog() + discovered_peers = CultMeshPeerCatalog() + endpoint = f"cultnet://127.0.0.1:{port_holder[0]}" + verse_discovery = CultMeshVerseDiscoveryClient.from_endpoint(endpoint, timeout_seconds=2.0) + peer_discovery = CultMeshPeerExchangeClient.from_endpoint(endpoint, timeout_seconds=2.0) + discovered_verse_count = verse_discovery.discover( + discovered_verses, + endpoints=[endpoint, endpoint, ""], + transport_version="cultmesh.v0", + ) + discovered_peer_count = peer_discovery.discover( + discovered_peers, + verse_id="aetheria-main", + endpoints=[endpoint, endpoint, ""], + roles=["read-replica"], + ) + fanout_verses = CultMeshVerseCatalog() + fanout_verses.upsert( + CultMeshVerseDescriptor( + verse_id="aetheria-main", + display_name="Known Aetheria", + authority_model="federated", + compatibility=CultMeshVerseCompatibility("cultmesh.v0", "rules-1"), + discovery_endpoints=(endpoint, endpoint, ""), + ) + ) + fanout_peers = CultMeshPeerCatalog() + fanout_peers.upsert( + CultMeshPeerCard( + peer_id="known-peer", + verse_id="aetheria-main", + endpoints=(endpoint, endpoint, ""), + roles=("read-replica",), + ) + ) + fanout_verse_count = verse_discovery.fanout(fanout_verses, transport_version="cultmesh.v0") + fanout_peer_count = peer_discovery.fanout( + fanout_peers, + verse_id="aetheria-main", + roles=["read-replica"], + ) + + thread.join(2.0) + self.assertFalse(server_error) + self.assertEqual(fetched_verses[0].verse_id, "aetheria-main") + self.assertEqual(fetched_verses[0].compatibility.required_plugin_ids, ("core",)) + self.assertEqual(fetched_peers[0].peer_id, "peer-a") + self.assertEqual(fetched_peers[0].shard_ids, ("players",)) + self.assertEqual(synced_verses[0].verse_id, "aetheria-main") + self.assertEqual(local_peers.find("aetheria-main", role="read-replica")[0].peer_id, "peer-a") + self.assertEqual(synced_peers[0].roles, ("read-replica",)) + self.assertEqual(discovered_verse_count, 1) + self.assertEqual(discovered_peer_count, 1) + self.assertEqual(discovered_verses.get("aetheria-main").display_name, "Aetheria") + self.assertEqual(discovered_peers.find("aetheria-main", role="read-replica")[0].peer_id, "peer-a") + self.assertEqual(fanout_verse_count, 1) + self.assertEqual(fanout_peer_count, 1) + self.assertEqual(fanout_verses.get("aetheria-main").display_name, "Aetheria") + self.assertIn( + "peer-a", + {peer.peer_id for peer in fanout_peers.find("aetheria-main", role="read-replica")}, + ) + + def test_cultmesh_discovery_client_fans_out_simulation_observations_to_peers(self) -> None: + first_hub = CultNetSimulationObservationHub( + CultNetSimulationConsensusOptions(minimum_witnesses=1, quorum_ratio=1.0) + ) + second_hub = CultNetSimulationObservationHub( + CultNetSimulationConsensusOptions(minimum_witnesses=1, quorum_ratio=1.0) + ) + first_server = CultMesh.serve_node( + CultMesh.create_node(runtime_id="sim-peer-a"), + observation_hub=first_hub, + ) + second_server = CultMesh.serve_node( + CultMesh.create_node(runtime_id="sim-peer-b"), + observation_hub=second_hub, + ) + try: + peers = CultMeshPeerCatalog() + peers.upsert(CultMeshPeerCard( + peer_id="sim-peer-a", + verse_id="arena", + endpoints=(f"cultnet://127.0.0.1:{first_server.port}",), + roles=("simulation-witness",), + )) + peers.upsert(CultMeshPeerCard( + peer_id="sim-peer-b", + verse_id="arena", + endpoints=(f"cultnet://127.0.0.1:{second_server.port}",), + roles=("simulation-witness",), + )) + claim_hash = compute_simulation_claim_hash("hit", "alice", "bob", "frame:200") + message = simulation_observation( + message_id="fanout-observation", + witness_runtime_id="python-fanout", + shard_id="arena", + shard_epoch=1, + frame=200, + subject_id="bob", + claim_kind="hit", + claim_hash=claim_hash, + claim_summary="alice hit bob", + ).to_wire() + + client = CultMeshDiscoveryClient("127.0.0.1", first_server.port, timeout_seconds=2.0) + candidates = client.fanout_simulation_observation( + peers, + message, + verse_id="arena", + roles=["simulation-witness"], + ) + finally: + first_server.stop() + second_server.stop() + + self.assertEqual([candidate["schemaVersion"] for candidate in candidates], [ + "cultnet.simulation_consensus_candidate.v0", + "cultnet.simulation_consensus_candidate.v0", + ]) + self.assertEqual({candidate["claimHash"] for candidate in candidates}, {claim_hash}) + self.assertEqual({candidate["messageId"] for candidate in candidates}, {"fanout-observation"}) + self.assertEqual({candidate["hasQuorum"] for candidate in candidates}, {True}) + + def test_cultmesh_simulation_observation_fanout_flushes_queued_messages(self) -> None: + hub = CultNetSimulationObservationHub( + CultNetSimulationConsensusOptions(minimum_witnesses=1, quorum_ratio=1.0) + ) + server = CultMesh.serve_node(CultMesh.create_node(runtime_id="sim-flush-peer"), observation_hub=hub) + try: + peers = CultMeshPeerCatalog() + peers.upsert(CultMeshPeerCard( + peer_id="sim-flush-peer", + verse_id="arena", + endpoints=(f"cultnet://127.0.0.1:{server.port}",), + roles=("simulation-witness",), + )) + claim_hash = compute_simulation_claim_hash("hit", "alice", "bob", "frame:210") + seen_candidates: list[dict[str, object]] = [] + fanout = CultMeshSimulationObservationFanout( + CultMeshDiscoveryClient("127.0.0.1", server.port, timeout_seconds=2.0), + peers, + verse_id="arena", + roles=["simulation-witness"], + on_candidate=seen_candidates.append, + ) + fanout.enqueue(simulation_observation( + message_id="queued-observation", + witness_runtime_id="python-fanout", + shard_id="arena", + shard_epoch=1, + frame=210, + subject_id="bob", + claim_kind="hit", + claim_hash=claim_hash, + claim_summary="alice hit bob", + ).to_wire()) + + candidates = fanout.flush() + finally: + server.stop() + + self.assertEqual(fanout.pending_count(), 0) + self.assertEqual([candidate["claimHash"] for candidate in candidates], [claim_hash]) + self.assertEqual(seen_candidates[0]["messageId"], "queued-observation") + + def test_cultmesh_simulation_observation_fanout_keeps_failed_messages_pending(self) -> None: + closed_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + closed_socket.bind(("127.0.0.1", 0)) + closed_port = closed_socket.getsockname()[1] + closed_socket.close() + peers = CultMeshPeerCatalog() + peers.upsert(CultMeshPeerCard( + peer_id="closed-simulation-peer", + verse_id="arena", + endpoints=(f"cultnet://127.0.0.1:{closed_port}",), + roles=("simulation-witness",), + )) + errors: list[tuple[str, str]] = [] + fanout = CultMeshSimulationObservationFanout( + CultMeshDiscoveryClient("127.0.0.1", closed_port, timeout_seconds=0.2), + peers, + verse_id="arena", + roles=["simulation-witness"], + on_error=lambda endpoint, error: errors.append((endpoint, str(error))), + ) + fanout.enqueue(simulation_observation( + message_id="retry-observation", + witness_runtime_id="python-fanout", + shard_id="arena", + shard_epoch=1, + frame=212, + subject_id="bob", + claim_kind="miss", + claim_hash=compute_simulation_claim_hash("miss", "alice", "bob", "frame:212"), + claim_summary="alice missed bob", + ).to_wire()) + + candidates = fanout.flush() + + self.assertEqual(candidates, []) + self.assertEqual(fanout.pending_count(), 1) + self.assertEqual(len(errors), 1) + self.assertIn(f"127.0.0.1:{closed_port}", errors[0][0]) + + def test_cultmesh_simulation_observation_fanout_runs_background_loop(self) -> None: + hub = CultNetSimulationObservationHub( + CultNetSimulationConsensusOptions(minimum_witnesses=1, quorum_ratio=1.0) + ) + server = CultMesh.serve_node(CultMesh.create_node(runtime_id="sim-loop-peer"), observation_hub=hub) + try: + peers = CultMeshPeerCatalog() + peers.upsert(CultMeshPeerCard( + peer_id="sim-loop-peer", + verse_id="arena", + endpoints=(f"cultnet://127.0.0.1:{server.port}",), + roles=("simulation-witness",), + )) + claim_hash = compute_simulation_claim_hash("block", "dana", "eve", "frame:211") + seen_candidates: list[dict[str, object]] = [] + fanout = CultMeshSimulationObservationFanout( + CultMeshDiscoveryClient("127.0.0.1", server.port, timeout_seconds=2.0), + peers, + verse_id="arena", + roles=["simulation-witness"], + interval_seconds=0.05, + on_candidate=seen_candidates.append, + ) + fanout.start() + fanout.enqueue(simulation_observation( + message_id="loop-observation", + witness_runtime_id="python-fanout", + shard_id="arena", + shard_epoch=1, + frame=211, + subject_id="eve", + claim_kind="block", + claim_hash=claim_hash, + claim_summary="dana blocked eve", + ).to_wire()) + deadline = time.monotonic() + 2.0 + while not seen_candidates and time.monotonic() < deadline: + time.sleep(0.01) + fanout.stop() + finally: + server.stop() + + self.assertEqual(fanout.pending_count(), 0) + self.assertTrue(seen_candidates) + self.assertEqual(seen_candidates[0]["claimHash"], claim_hash) + self.assertEqual(seen_candidates[0]["messageId"], "loop-observation") + + def test_cultmesh_discovery_client_fans_out_snapshots_to_peers(self) -> None: + document = define_database_entry_type( + "mesh.snapshot_fanout_note", + [("body", 0)], + schema_id="mesh.snapshot_fanout_note.v1", + ) + first = CultMesh.create_node(runtime_id="snapshot-peer-a") + first.database.register_document(document) + first.database.put_raw_message(document, "note:a", {"body": "from-a"}, shard_id="notes", shard_epoch=1) + second = CultMesh.create_node(runtime_id="snapshot-peer-b") + second.database.register_document(document) + second.database.put_raw_message(document, "note:b", {"body": "from-b"}, shard_id="notes", shard_epoch=1) + target = CultMesh.create_node(runtime_id="snapshot-target") + target.database.register_document(document) + first_server = CultMesh.serve_node(first) + second_server = CultMesh.serve_node(second) + try: + peers = CultMeshPeerCatalog() + peers.upsert(CultMeshPeerCard( + peer_id="snapshot-peer-a", + verse_id="mesh", + endpoints=(f"cultnet://127.0.0.1:{first_server.port}", f"cultnet://127.0.0.1:{first_server.port}"), + roles=("read-replica",), + )) + peers.upsert(CultMeshPeerCard( + peer_id="snapshot-peer-b", + verse_id="mesh", + endpoints=(f"cultnet://127.0.0.1:{second_server.port}",), + roles=("read-replica",), + )) + + client = CultMeshDiscoveryClient("127.0.0.1", first_server.port, timeout_seconds=2.0) + responses = client.fanout_snapshot_responses( + peers, + verse_id="mesh", + roles=["read-replica"], + schema_ids=["mesh.snapshot_fanout_note.v1"], + ) + applied = client.sync_snapshots( + target.database, + peers, + verse_id="mesh", + roles=["read-replica"], + schema_ids=["mesh.snapshot_fanout_note.v1"], + ) + finally: + first_server.stop() + second_server.stop() + + self.assertEqual(len(responses), 2) + self.assertTrue(all(isinstance(response, CultNetRawSnapshotResponse) for response in responses)) + self.assertEqual( + sorted(record.record_key for response in responses for record in response.documents), + ["note:a", "note:b"], + ) + self.assertEqual(sorted(record.record_key for record in applied), ["note:a", "note:b"]) + self.assertEqual(target.database.get_required(document, "note:a")["body"], "from-a") + self.assertEqual(target.database.get_required(document, "note:b")["body"], "from-b") + + def test_cultmesh_discovery_client_sync_documents_returns_requested_aliases(self) -> None: + @dataclass + class CanonicalNote: + body: str + + @dataclass + class UiNote: + body: str + + document = define_database_entry_type( + "mesh.snapshot_fanout_alias_note", + [("body", 0)], + cls=CanonicalNote, + schema_id="mesh.snapshot_fanout_alias_note.v1", + schema_name="mesh.snapshot_fanout_alias_note", + schema_version="mesh.snapshot_fanout_alias_note.v1", + ) + alias = define_database_entry_type( + "mesh.snapshot_fanout_alias_note.ui", + [("body", 0)], + cls=UiNote, + schema_id="mesh.snapshot_fanout_alias_note.v1", + schema_name="mesh.snapshot_fanout_alias_note", + schema_version="mesh.snapshot_fanout_alias_note.v1", + ) + source = CultMesh.create_node(runtime_id="snapshot-alias-source") + source.database.register_document(document) + source.database.put_raw_message(document, "note:alias", CanonicalNote("from-source")) + target = CultMesh.create_node(runtime_id="snapshot-alias-target") + target.database.register_document(document) + server = CultMesh.serve_node(source) + try: + peers = CultMeshPeerCatalog() + peers.upsert(CultMeshPeerCard( + peer_id="snapshot-alias-source", + verse_id="mesh", + endpoints=(f"cultnet://127.0.0.1:{server.port}",), + roles=("read-replica",), + )) + + values = CultMeshDiscoveryClient("127.0.0.1", server.port, timeout_seconds=2.0).sync_documents( + target.database, + peers, + verse_id="mesh", + roles=["read-replica"], + documents=[(alias, "note:alias")], + ) + finally: + server.stop() + + self.assertEqual(len(values), 1) + self.assertIsInstance(values[0], UiNote) + self.assertEqual(values[0].body, "from-source") + self.assertEqual(target.database.get_required(document, "note:alias").body, "from-source") + self.assertIsInstance(target.database.get_required(alias, "note:alias"), UiNote) + + def test_cultmesh_document_subscription_syncs_alias_snapshot_and_changes(self) -> None: + @dataclass + class CanonicalNote: + body: str + + @dataclass + class UiNote: + body: str + + document = define_database_entry_type( + "mesh.subscription_alias_note", + [("body", 0)], + cls=CanonicalNote, + schema_id="mesh.subscription_alias_note.v1", + schema_name="mesh.subscription_alias_note", + schema_version="mesh.subscription_alias_note.v1", + ) + alias = define_database_entry_type( + "mesh.subscription_alias_note.ui", + [("body", 0)], + cls=UiNote, + schema_id="mesh.subscription_alias_note.v1", + schema_name="mesh.subscription_alias_note", + schema_version="mesh.subscription_alias_note.v1", + ) + source = CultMesh.create_node(runtime_id="subscription-alias-source") + source.database.register_document(document) + source.database.put_raw_message(document, "note:live", CanonicalNote("initial")) + target = CultMesh.create_node(runtime_id="subscription-alias-target") + target.database.register_document(document) + server = CultMesh.serve_node(source) + try: + raw_client = CultMesh.create_client("127.0.0.1", server.port, timeout_seconds=2.0) + with CultMesh.subscribe_document(target, raw_client, alias, "note:live") as subscription: + initial = subscription.sync_initial() + subscription.send(document_put_raw( + message_id="subscription-alias-put", + key="note:live", + schema_id="mesh.subscription_alias_note.v1", + stored_at="2026-06-14T00:00:00Z", + payload=document.encode_payload(CanonicalNote("updated")), + )) + updated = subscription.read_next_change() + subscription.send(document_delete( + message_id="subscription-alias-delete", + schema_id="mesh.subscription_alias_note.v1", + record_key="note:live", + )) + removed = subscription.read_next_change() + finally: + server.stop() + + self.assertIsInstance(initial, UiNote) + self.assertEqual(initial.body, "initial") + self.assertEqual(updated.change_kind, "updated") + self.assertIsInstance(updated.value, UiNote) + self.assertEqual(updated.value.body, "updated") + self.assertIsInstance(updated.previous_value, UiNote) + self.assertEqual(updated.previous_value.body, "initial") + self.assertEqual(removed.change_kind, "removed") + self.assertIsNone(removed.value) + self.assertIsInstance(removed.previous_value, UiNote) + self.assertEqual(removed.previous_value.body, "updated") + self.assertIsNone(target.database.get(alias, "note:live")) + + def test_cultmesh_snapshot_fanout_syncs_once_and_reports_applied_records(self) -> None: + document = define_database_entry_type( + "mesh.snapshot_loop_note", + [("body", 0)], + schema_id="mesh.snapshot_loop_note.v1", + ) + source = CultMesh.create_node(runtime_id="snapshot-loop-source") + source.database.register_document(document) + source.database.put_raw_message(document, "note:sync-once", {"body": "from-source"}) + target = CultMesh.create_node(runtime_id="snapshot-loop-target") + target.database.register_document(document) + server = CultMesh.serve_node(source) + try: + peers = CultMeshPeerCatalog() + peers.upsert(CultMeshPeerCard( + peer_id="snapshot-loop-source", + verse_id="mesh", + endpoints=(f"cultnet://127.0.0.1:{server.port}",), + roles=("read-replica",), + )) + seen: list[str] = [] + fanout = CultMeshSnapshotFanout( + CultMeshDiscoveryClient("127.0.0.1", server.port, timeout_seconds=2.0), + target.database, + peers, + verse_id="mesh", + roles=["read-replica"], + schema_ids=["mesh.snapshot_loop_note.v1"], + on_applied=lambda record: seen.append(record.record_key), + ) + + applied = fanout.sync_once() + finally: + server.stop() + + self.assertEqual([record.record_key for record in applied], ["note:sync-once"]) + self.assertEqual(seen, ["note:sync-once"]) + self.assertEqual(target.database.get_required(document, "note:sync-once")["body"], "from-source") + + def test_cultmesh_snapshot_fanout_syncs_typed_documents_and_reports_alias_values(self) -> None: + @dataclass + class CanonicalNote: + body: str + + @dataclass + class UiNote: + body: str + + document = define_database_entry_type( + "mesh.snapshot_loop_alias_note", + [("body", 0)], + cls=CanonicalNote, + schema_id="mesh.snapshot_loop_alias_note.v1", + schema_name="mesh.snapshot_loop_alias_note", + schema_version="mesh.snapshot_loop_alias_note.v1", + ) + alias = define_database_entry_type( + "mesh.snapshot_loop_alias_note.ui", + [("body", 0)], + cls=UiNote, + schema_id="mesh.snapshot_loop_alias_note.v1", + schema_name="mesh.snapshot_loop_alias_note", + schema_version="mesh.snapshot_loop_alias_note.v1", + ) + source = CultMesh.create_node(runtime_id="snapshot-loop-alias-source") + source.database.register_document(document) + source.database.put_raw_message(document, "note:typed-loop", CanonicalNote("from-source")) + target = CultMesh.create_node(runtime_id="snapshot-loop-alias-target") + target.database.register_document(document) + server = CultMesh.serve_node(source) + try: + peers = CultMeshPeerCatalog() + peers.upsert(CultMeshPeerCard( + peer_id="snapshot-loop-alias-source", + verse_id="mesh", + endpoints=(f"cultnet://127.0.0.1:{server.port}",), + roles=("read-replica",), + )) + seen: list[UiNote] = [] + fanout = CultMeshSnapshotFanout( + CultMeshDiscoveryClient("127.0.0.1", server.port, timeout_seconds=2.0), + target.database, + peers, + verse_id="mesh", + roles=["read-replica"], + documents=[(alias, "note:typed-loop")], + on_document=seen.append, + ) + + values = fanout.sync_once() + finally: + server.stop() + + self.assertEqual(len(values), 1) + self.assertIsInstance(values[0], UiNote) + self.assertEqual(values[0].body, "from-source") + self.assertEqual(seen, [values[0]]) + self.assertEqual(target.database.get_required(document, "note:typed-loop").body, "from-source") + self.assertIsInstance(target.database.get_required(alias, "note:typed-loop"), UiNote) + + def test_cultmesh_snapshot_fanout_runs_background_loop(self) -> None: + document = define_database_entry_type( + "mesh.snapshot_background_note", + [("body", 0)], + schema_id="mesh.snapshot_background_note.v1", + ) + source = CultMesh.create_node(runtime_id="snapshot-background-source") + source.database.register_document(document) + source.database.put_raw_message(document, "note:background", {"body": "from-background"}) + target = CultMesh.create_node(runtime_id="snapshot-background-target") + target.database.register_document(document) + server = CultMesh.serve_node(source) + try: + peers = CultMeshPeerCatalog() + peers.upsert(CultMeshPeerCard( + peer_id="snapshot-background-source", + verse_id="mesh", + endpoints=(f"cultnet://127.0.0.1:{server.port}",), + roles=("read-replica",), + )) + seen: list[str] = [] + fanout = CultMeshSnapshotFanout( + CultMeshDiscoveryClient("127.0.0.1", server.port, timeout_seconds=2.0), + target.database, + peers, + verse_id="mesh", + roles=["read-replica"], + schema_ids=["mesh.snapshot_background_note.v1"], + interval_seconds=0.05, + on_applied=lambda record: seen.append(record.record_key), + ) + fanout.start() + deadline = time.monotonic() + 2.0 + while not seen and time.monotonic() < deadline: + time.sleep(0.01) + fanout.stop() + finally: + server.stop() + + self.assertTrue(seen) + self.assertEqual(target.database.get_required(document, "note:background")["body"], "from-background") + + def test_cultmesh_peer_health_monitor_probes_reachable_and_failed_endpoints(self) -> None: + document = define_database_entry_type( + "mesh.health_note", + [("body", 0)], + schema_id="mesh.health_note.v1", + ) + node = CultMesh.create_node(runtime_id="health-peer") + node.database.register_document(document) + server = CultMesh.serve_node(node) + closed_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + closed_socket.bind(("127.0.0.1", 0)) + closed_port = closed_socket.getsockname()[1] + closed_socket.close() + try: + peers = CultMeshPeerCatalog() + peers.upsert(CultMeshPeerCard( + peer_id="health-peer", + verse_id="mesh", + endpoints=(f"cultnet://127.0.0.1:{server.port}",), + roles=("read-replica",), + )) + peers.upsert(CultMeshPeerCard( + peer_id="closed-peer", + verse_id="mesh", + endpoints=(f"cultnet://127.0.0.1:{closed_port}",), + roles=("read-replica",), + )) + seen: list[tuple[str, bool]] = [] + monitor = CultMeshPeerHealthMonitor( + runtime_id="health-prober", + timeout_seconds=0.2, + on_update=lambda health: seen.append((health.peer_id, health.is_reachable)), + ) + + results = monitor.probe_catalog(peers, verse_id="mesh", roles=["read-replica"]) + finally: + server.stop() + + by_peer = {result.peer_id: result for result in results} + self.assertTrue(by_peer["health-peer"].is_reachable) + self.assertEqual(by_peer["health-peer"].runtime_id, "health-peer") + self.assertEqual(by_peer["health-peer"].runtime_kind, "python") + self.assertEqual(by_peer["health-peer"].display_name, "health-peer") + self.assertEqual(by_peer["health-peer"].supported_document_types, ("mesh.health_note",)) + self.assertIn("cultnet.hello.v0", by_peer["health-peer"].supported_message_versions) + self.assertIn("cultnet.error.v0", by_peer["health-peer"].supported_message_versions) + self.assertEqual(by_peer["health-peer"].supported_mutation_contracts[0]["documentType"], "mesh.health_note") + self.assertIn("shardLog", by_peer["health-peer"].supported_mutation_contracts[0]["operations"]) + self.assertFalse(by_peer["closed-peer"].is_reachable) + self.assertIsNone(by_peer["closed-peer"].runtime_kind) + self.assertEqual(by_peer["closed-peer"].supported_document_types, ()) + self.assertEqual(by_peer["closed-peer"].supported_message_versions, ()) + self.assertEqual(by_peer["closed-peer"].supported_mutation_contracts, ()) + self.assertTrue(by_peer["closed-peer"].error) + self.assertEqual({peer_id for peer_id, _ in seen}, {"health-peer", "closed-peer"}) + self.assertEqual(len(monitor.latest()), 2) + + def test_cultmesh_peer_health_monitor_runs_background_probe_loop(self) -> None: + server = CultMesh.serve_node(CultMesh.create_node(runtime_id="health-loop-peer")) + try: + peers = CultMeshPeerCatalog() + peers.upsert(CultMeshPeerCard( + peer_id="health-loop-peer", + verse_id="mesh", + endpoints=(f"cultnet://127.0.0.1:{server.port}",), + roles=("read-replica",), + )) + seen: list[str] = [] + monitor = CultMeshPeerHealthMonitor( + runtime_id="health-loop-prober", + timeout_seconds=0.2, + interval_seconds=0.05, + on_update=lambda health: seen.append(health.peer_id), + ) + monitor.start(peers, verse_id="mesh", roles=["read-replica"]) + deadline = time.monotonic() + 2.0 + while time.monotonic() < deadline: + latest = monitor.latest() + if latest and latest[0].is_reachable: + break + time.sleep(0.01) + monitor.stop() + finally: + server.stop() + + self.assertTrue(seen) + latest = monitor.latest() + self.assertEqual(latest[0].peer_id, "health-loop-peer") + self.assertTrue(latest[0].is_reachable) + + def test_cultmesh_daemon_entrypoint_serves_framed_cultnet_hello(self) -> None: + with tempfile.TemporaryDirectory() as temp: + ready_path = Path(temp) / "ready.json" + package_src = Path(__file__).resolve().parents[1] / "src" + env = dict(os.environ) + existing_pythonpath = env.get("PYTHONPATH") + env["PYTHONPATH"] = ( + str(package_src) + if not existing_pythonpath + else f"{package_src}{os.pathsep}{existing_pythonpath}" + ) + process = subprocess.Popen( + [ + sys.executable, + "-m", + "cultmesh_py.daemon", + "--runtime-id", + "daemon-test-peer", + "--display-name", + "Daemon Test Peer", + "--port", + "0", + "--ready-file", + str(ready_path), + "--seed-interop-note", + "--seed-shard-id", + "daemon-interop", + "--verse-id", + "daemon-verse", + "--verse-display-name", + "Daemon Verse", + "--role", + "shard-primary", + ], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + env=env, + ) + try: + deadline = time.monotonic() + 5.0 + while not ready_path.exists() and time.monotonic() < deadline: + if process.poll() is not None: + break + time.sleep(0.05) + if not ready_path.exists(): + _, stderr = process.communicate(timeout=2.0) + self.fail(f"cultmesh daemon did not publish readiness: {stderr}") + ready = json.loads(ready_path.read_text(encoding="utf-8")) + self.assertEqual(ready["schemaVersion"], READY_SCHEMA_VERSION) + self.assertEqual(ready["runtimeId"], "daemon-test-peer") + self.assertEqual(ready["runtimeKind"], "python") + self.assertEqual(ready["displayName"], "Daemon Test Peer") + self.assertEqual(ready["endpoint"], f"cultnet://127.0.0.1:{ready['port']}") + self.assertEqual(ready["shardIds"], ["daemon-interop"]) + self.assertEqual(ready["supportedDocumentTypes"], ["cultcache.interop-note"]) + self.assertIn("cultnet.hello.v0", ready["supportedMessageVersions"]) + self.assertIn("cultnet.document_put_raw.v0", ready["supportedMessageVersions"]) + self.assertNotIn("cultnet.simulation_observation.v0", ready["supportedMessageVersions"]) + self.assertEqual(ready["supportedMutationContracts"][0]["documentType"], "cultcache.interop-note") + self.assertIn("shardLog", ready["supportedMutationContracts"][0]["operations"]) + self.assertEqual(ready["snapshotLimits"], {"maxSnapshotBytes": None, "maxSnapshotDocuments": None}) + self.assertEqual(ready["verses"][0]["verseId"], "daemon-verse") + self.assertEqual(ready["verses"][0]["displayName"], "Daemon Verse") + self.assertEqual(ready["verses"][0]["discoveryEndpoints"], [ready["endpoint"]]) + self.assertEqual(ready["verses"][0]["authorityRuntimeIds"], ["daemon-test-peer"]) + self.assertEqual(ready["peers"][0]["peerId"], "daemon-test-peer") + self.assertEqual(ready["peers"][0]["endpoints"], [ready["endpoint"]]) + self.assertEqual(ready["peers"][0]["roles"], ["shard-primary"]) + self.assertEqual(ready["peers"][0]["shardIds"], ["daemon-interop"]) + + client = CultMesh.create_client("127.0.0.1", int(ready["port"]), timeout_seconds=2.0) + hello_response = client.request( + hello(runtime_id="daemon-test-prober"), + expected_schema_version="cultnet.hello.v0", + ) + + self.assertEqual(hello_response["runtimeId"], "daemon-test-peer") + self.assertEqual(hello_response["displayName"], "Daemon Test Peer") + self.assertIn("cultnet.hello.v0", hello_response["supportedMessageVersions"]) + self.assertIn("cultnet.schema_catalog_request.v0", hello_response["supportedMessageVersions"]) + self.assertNotIn("cultnet.simulation_observation.v0", hello_response["supportedMessageVersions"]) + self.assertEqual(hello_response["supportedDocumentTypes"], ["cultcache.interop-note"]) + self.assertEqual(hello_response["transportProfiles"][0]["transports"][0]["protocol"], "tcp_framed") + self.assertEqual(hello_response["transportProfiles"][0]["transports"][0]["port"], int(ready["port"])) + self.assertEqual(ready["supportedMessageVersions"], hello_response["supportedMessageVersions"]) + self.assertEqual(ready["supportedMutationContracts"], hello_response["supportedMutationContracts"]) + self.assertEqual(ready["transportProfiles"], hello_response["transportProfiles"]) + + schema_response = client.fetch_schema_catalog(schema_ids=["cultcache.interop-note"], include_schema_json=True) + self.assertEqual(schema_response["schemas"][0]["schemaVersion"], INTEROP_SCHEMA_VERSION) + self.assertEqual(schema_response["schemas"][0]["documentType"], "cultcache.interop-note") + + snapshot_response = client.fetch_snapshot_response(schema_ids=["cultcache.interop-note"]) + self.assertEqual(snapshot_response.documents[0].record_key, "note:daemon-test-peer") + note = interop_note_document.decode_payload(snapshot_response.documents[0].payload) + self.assertEqual(note["authorRuntimeId"], "daemon-test-peer") + self.assertIn("daemon", note["tags"]) + + shard_catalog = client.fetch_shard_catalog(schema_ids=["cultcache.interop-note"]) + self.assertEqual(shard_catalog["shards"][0]["shardId"], "daemon-interop") + self.assertEqual(shard_catalog["shards"][0]["schemaIds"], ["cultcache.interop-note"]) + + shard_log = client.fetch_shard_log_response(shard_id="daemon-interop", shard_epoch=1) + self.assertFalse(shard_log.resync_required) + self.assertEqual(shard_log.entries[0].sequence, 1) + self.assertEqual(shard_log.entries[0].change_kind, "added") + self.assertIsNotNone(shard_log.entries[0].raw_document) + assert shard_log.entries[0].raw_document is not None + self.assertEqual(shard_log.entries[0].raw_document.record_key, "note:daemon-test-peer") + + discovery_client = CultMesh.create_verse_discovery_client("127.0.0.1", int(ready["port"]), timeout_seconds=2.0) + verses = discovery_client.fetch_verses(transport_version="cultmesh.v0") + self.assertEqual(verses[0].verse_id, "daemon-verse") + self.assertEqual(verses[0].display_name, "Daemon Verse") + self.assertEqual(verses[0].discovery_endpoints, (ready["endpoint"],)) + self.assertEqual(verses[0].authority_runtime_ids, ("daemon-test-peer",)) + self.assertEqual([verse.to_wire() for verse in verses], ready["verses"]) + + peers = discovery_client.fetch_peers(verse_id="daemon-verse", roles=["shard-primary"]) + self.assertEqual(peers[0].peer_id, "daemon-test-peer") + self.assertEqual(peers[0].endpoints, (ready["endpoint"],)) + self.assertEqual(peers[0].roles, ("shard-primary",)) + self.assertEqual(peers[0].shard_ids, ("daemon-interop",)) + self.assertEqual([peer.to_wire() for peer in peers], ready["peers"]) + + monitor = CultMeshPeerHealthMonitor(runtime_id="daemon-health-prober", timeout_seconds=2.0) + health = monitor.probe_peer(peers[0])[0] + self.assertTrue(health.is_reachable) + self.assertEqual(health.runtime_id, "daemon-test-peer") + self.assertEqual(health.supported_document_types, ("cultcache.interop-note",)) + self.assertEqual(health.supported_mutation_contracts[0]["documentType"], "cultcache.interop-note") + finally: + process.terminate() + try: + process.communicate(timeout=5.0) + except subprocess.TimeoutExpired: + process.kill() + process.communicate(timeout=5.0) + + def test_cultmesh_daemon_restarts_with_persisted_cache_and_shard_log(self) -> None: + with tempfile.TemporaryDirectory() as temp: + root = Path(temp) + cache_path = root / "mesh.cc" + shard_log_path = root / "shard-log" + env = dict(os.environ) + package_src = Path(__file__).resolve().parents[1] / "src" + existing_pythonpath = env.get("PYTHONPATH") + env["PYTHONPATH"] = ( + str(package_src) + if not existing_pythonpath + else f"{package_src}{os.pathsep}{existing_pythonpath}" + ) + + first_ready = root / "first-ready.json" + first = subprocess.Popen( + [ + sys.executable, + "-m", + "cultmesh_py.daemon", + "--runtime-id", + "durable-daemon-peer", + "--port", + "0", + "--cache-file", + str(cache_path), + "--enable-durable-shard-logs", + "--shard-log-file", + str(shard_log_path), + "--seed-interop-note", + "--seed-shard-id", + "durable-interop", + "--ready-file", + str(first_ready), + ], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + env=env, + ) + try: + self._wait_for_ready_file(first, first_ready) + finally: + self._terminate_process(first) + + second_ready = root / "second-ready.json" + second = subprocess.Popen( + [ + sys.executable, + "-m", + "cultmesh_py.daemon", + "--runtime-id", + "durable-daemon-peer", + "--port", + "0", + "--cache-file", + str(cache_path), + "--enable-durable-shard-logs", + "--shard-log-file", + str(shard_log_path), + "--register-interop-note", + "--verse-id", + "durable-verse", + "--role", + "shard-primary", + "--ready-file", + str(second_ready), + ], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + env=env, + ) + try: + ready = self._wait_for_ready_file(second, second_ready) + client = CultMesh.create_client("127.0.0.1", int(ready["port"]), timeout_seconds=2.0) + + snapshot_response = client.fetch_snapshot_response(schema_ids=["cultcache.interop-note"]) + self.assertEqual(snapshot_response.documents[0].record_key, "note:durable-daemon-peer") + note = interop_note_document.decode_payload(snapshot_response.documents[0].payload) + self.assertEqual(note["authorRuntimeId"], "durable-daemon-peer") + + shard_log = client.fetch_shard_log_response(shard_id="durable-interop", shard_epoch=1) + self.assertFalse(shard_log.resync_required) + self.assertEqual(shard_log.entries[0].sequence, 1) + self.assertIsNotNone(shard_log.entries[0].raw_document) + assert shard_log.entries[0].raw_document is not None + self.assertEqual(shard_log.entries[0].raw_document.record_key, "note:durable-daemon-peer") + + discovery_client = CultMesh.create_verse_discovery_client("127.0.0.1", int(ready["port"]), timeout_seconds=2.0) + peers = discovery_client.fetch_peers(verse_id="durable-verse", roles=["shard-primary"]) + self.assertEqual(peers[0].shard_ids, ("durable-interop",)) + finally: + self._terminate_process(second) + + def test_cultmesh_daemon_serves_live_database_subscription_mutations(self) -> None: + with tempfile.TemporaryDirectory() as temp: + ready_path = Path(temp) / "ready.json" + package_src = Path(__file__).resolve().parents[1] / "src" + env = dict(os.environ) + existing_pythonpath = env.get("PYTHONPATH") + env["PYTHONPATH"] = ( + str(package_src) + if not existing_pythonpath + else f"{package_src}{os.pathsep}{existing_pythonpath}" + ) + process = subprocess.Popen( + [ + sys.executable, + "-m", + "cultmesh_py.daemon", + "--runtime-id", + "live-daemon-peer", + "--port", + "0", + "--seed-interop-note", + "--seed-shard-id", + "live-interop", + "--ready-file", + str(ready_path), + ], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + env=env, + ) + try: + ready = self._wait_for_ready_file(process, ready_path) + client = CultMesh.create_client("127.0.0.1", int(ready["port"]), timeout_seconds=2.0) + live_note = { + "schemaVersion": INTEROP_SCHEMA_VERSION, + "documentId": "note:daemon-live", + "authorRuntimeId": "daemon-live-client", + "title": "daemon live subscription note", + "body": "live subscription put from Python daemon smoke", + "tags": ["daemon", "subscription", "interop"], + } + + with client.subscribe_database( + subscription_id="daemon-live-sub", + schema_ids=["cultcache.interop-note"], + ) as subscription: + snapshot = subscription.read_next_snapshot_response() + subscription.send(document_put_raw( + message_id="daemon-live-put", + key="note:daemon-live", + schema_id="cultcache.interop-note", + stored_at="2026-06-14T00:00:00Z", + payload=interop_note_document.encode_payload(live_note), + source_runtime_id="daemon-live-client", + shard_id="live-interop", + shard_epoch=1, + )) + change = subscription.read_next_change() + + self.assertEqual(snapshot.documents[0].record_key, "note:live-daemon-peer") + self.assertEqual(change.change_kind, "added") + self.assertEqual(change.record_key, "note:daemon-live") + self.assertIsNotNone(change.raw_document) + assert change.raw_document is not None + self.assertEqual( + interop_note_document.decode_payload(change.raw_document.payload), + live_note, + ) + + shard_log = client.fetch_shard_log_response(shard_id="live-interop", shard_epoch=1) + self.assertFalse(shard_log.resync_required) + self.assertEqual([entry.sequence for entry in shard_log.entries], [1, 2]) + self.assertEqual(shard_log.entries[1].change_kind, "added") + self.assertIsNotNone(shard_log.entries[1].raw_document) + assert shard_log.entries[1].raw_document is not None + self.assertEqual(shard_log.entries[1].raw_document.record_key, "note:daemon-live") + finally: + self._terminate_process(process) + + def test_cultmesh_daemon_serves_compacted_shard_log_resync_boundary(self) -> None: + with tempfile.TemporaryDirectory() as temp: + root = Path(temp) + cache_path = root / "mesh.cc" + shard_log_path = root / "shard-log" + store = CultNetFileShardMutationLogStore(shard_log_path) + node = CultMesh.create_node( + cache_path, + runtime_id="compacted-daemon-peer", + enable_durable_shard_logs=True, + shard_log_path=shard_log_path, + ) + node.database.register_document(interop_note_document) + node.database.put_raw_message( + interop_note_document, + "note:compacted-one", + { + "schemaVersion": INTEROP_SCHEMA_VERSION, + "documentId": "note:compacted-one", + "authorRuntimeId": "compacted-daemon-peer", + "title": "compacted daemon note one", + "body": "first retained cache value", + "tags": ["daemon", "compaction"], + }, + message_id="compacted-put-1", + shard_id="compacted-interop", + shard_epoch=7, + ) + node.database.put_raw_message( + interop_note_document, + "note:compacted-two", + { + "schemaVersion": INTEROP_SCHEMA_VERSION, + "documentId": "note:compacted-two", + "authorRuntimeId": "compacted-daemon-peer", + "title": "compacted daemon note two", + "body": "second retained cache value", + "tags": ["daemon", "compaction"], + }, + message_id="compacted-put-2", + shard_id="compacted-interop", + shard_epoch=7, + ) + store.compact_through("compacted-interop", 1) + + ready_path = root / "ready.json" + package_src = Path(__file__).resolve().parents[1] / "src" + env = dict(os.environ) + existing_pythonpath = env.get("PYTHONPATH") + env["PYTHONPATH"] = ( + str(package_src) + if not existing_pythonpath + else f"{package_src}{os.pathsep}{existing_pythonpath}" + ) + process = subprocess.Popen( + [ + sys.executable, + "-m", + "cultmesh_py.daemon", + "--runtime-id", + "compacted-daemon-peer", + "--port", + "0", + "--cache-file", + str(cache_path), + "--enable-durable-shard-logs", + "--shard-log-file", + str(shard_log_path), + "--register-interop-note", + "--ready-file", + str(ready_path), + ], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + env=env, + ) + try: + ready = self._wait_for_ready_file(process, ready_path) + client = CultMesh.create_client("127.0.0.1", int(ready["port"]), timeout_seconds=2.0) + + snapshot_response = client.fetch_snapshot_response(schema_ids=["cultcache.interop-note"]) + self.assertEqual( + {document.record_key for document in snapshot_response.documents}, + {"note:compacted-one", "note:compacted-two"}, + ) + + compacted = client.fetch_shard_log_response( + shard_id="compacted-interop", + shard_epoch=7, + after_sequence=0, + ) + retained = client.fetch_shard_log_response( + shard_id="compacted-interop", + shard_epoch=7, + after_sequence=1, + ) + + self.assertTrue(compacted.resync_required) + self.assertEqual(compacted.reason, "compacted_history") + self.assertEqual(compacted.compacted_through, 1) + self.assertEqual(compacted.entries, ()) + self.assertFalse(retained.resync_required) + self.assertEqual([entry.sequence for entry in retained.entries], [2]) + self.assertIsNotNone(retained.entries[0].raw_document) + assert retained.entries[0].raw_document is not None + self.assertEqual(retained.entries[0].raw_document.record_key, "note:compacted-two") + finally: + self._terminate_process(process) + + def test_cultmesh_daemon_accepts_schema_write_forwarder_mutations(self) -> None: + with tempfile.TemporaryDirectory() as temp: + ready_path = Path(temp) / "ready.json" + package_src = Path(__file__).resolve().parents[1] / "src" + env = dict(os.environ) + existing_pythonpath = env.get("PYTHONPATH") + env["PYTHONPATH"] = ( + str(package_src) + if not existing_pythonpath + else f"{package_src}{os.pathsep}{existing_pythonpath}" + ) + process = subprocess.Popen( + [ + sys.executable, + "-m", + "cultmesh_py.daemon", + "--runtime-id", + "forwarder-daemon-peer", + "--port", + "0", + "--register-interop-note", + "--ready-file", + str(ready_path), + ], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + env=env, + ) + try: + ready = self._wait_for_ready_file(process, ready_path) + endpoint = f"cultnet://127.0.0.1:{ready['port']}" + shard = CultNetShardDescriptor( + shard_id="forwarded-interop", + owner_runtime_id="forwarder-daemon-peer", + epoch=3, + is_primary=False, + schema_ids=("cultcache.interop-note",), + primary_endpoints=(endpoint,), + ) + forwarder: CultNetShardWriteForwarder = CultNetSchemaWriteForwarder(timeout_seconds=2.0) + note = { + "schemaVersion": INTEROP_SCHEMA_VERSION, + "documentId": "note:forwarded-daemon", + "authorRuntimeId": "forwarding-client", + "title": "forwarded daemon note", + "body": "forwarded through the schema write-forwarder", + "tags": ["daemon", "forwarded"], + } + + forwarder.forward_put(shard, document_put_raw( + message_id="forwarded-daemon-put", + key="note:forwarded-daemon", + schema_id="cultcache.interop-note", + stored_at="2026-06-14T00:00:00Z", + payload=interop_note_document.encode_payload(note), + source_runtime_id="forwarding-client", + ).to_wire()) + + client = CultMesh.create_client("127.0.0.1", int(ready["port"]), timeout_seconds=2.0) + self._eventually(lambda: bool(client.fetch_snapshot_response( + schema_ids=["cultcache.interop-note"], + record_keys=["note:forwarded-daemon"], + ).documents)) + snapshot = client.fetch_snapshot_response( + schema_ids=["cultcache.interop-note"], + record_keys=["note:forwarded-daemon"], + ) + self.assertEqual( + interop_note_document.decode_payload(snapshot.documents[0].payload), + note, + ) + + forwarder.forward_delete(shard, document_delete( + message_id="forwarded-daemon-delete", + schema_id="cultcache.interop-note", + record_key="note:forwarded-daemon", + ).to_wire()) + self._eventually(lambda: not client.fetch_snapshot_response( + schema_ids=["cultcache.interop-note"], + record_keys=["note:forwarded-daemon"], + ).documents) + + shard_log = client.fetch_shard_log_response(shard_id="forwarded-interop", shard_epoch=3) + self.assertEqual([entry.change_kind for entry in shard_log.entries], ["added", "removed"]) + self.assertEqual(shard_log.entries[0].put["shardId"], "forwarded-interop") + self.assertEqual(shard_log.entries[0].put["shardEpoch"], 3) + self.assertEqual(shard_log.entries[1].delete["shardId"], "forwarded-interop") + self.assertEqual(shard_log.entries[1].delete["shardEpoch"], 3) + finally: + self._terminate_process(process) + + def test_cultmesh_daemon_enforces_snapshot_document_limit_as_peer_error(self) -> None: + with tempfile.TemporaryDirectory() as temp: + ready_path = Path(temp) / "ready.json" + package_src = Path(__file__).resolve().parents[1] / "src" + env = dict(os.environ) + existing_pythonpath = env.get("PYTHONPATH") + env["PYTHONPATH"] = ( + str(package_src) + if not existing_pythonpath + else f"{package_src}{os.pathsep}{existing_pythonpath}" + ) + process = subprocess.Popen( + [ + sys.executable, + "-m", + "cultmesh_py.daemon", + "--runtime-id", + "limited-daemon-peer", + "--port", + "0", + "--seed-interop-note", + "--max-snapshot-documents", + "0", + "--ready-file", + str(ready_path), + ], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + env=env, + ) + try: + ready = self._wait_for_ready_file(process, ready_path) + self.assertEqual(ready["snapshotLimits"], {"maxSnapshotBytes": None, "maxSnapshotDocuments": 0}) + client = CultMesh.create_client("127.0.0.1", int(ready["port"]), timeout_seconds=2.0) + + with self.assertRaisesRegex(CultNetPeerError, "Snapshot document limit exceeded") as raised: + client.fetch_snapshot_response(schema_ids=["cultcache.interop-note"]) + + self.assertEqual(raised.exception.response["schemaVersion"], "cultnet.error.v0") + self.assertEqual(raised.exception.response["code"], "snapshot_document_limit_exceeded") + self.assertEqual(raised.exception.response["details"]["documentCount"], 1) + self.assertEqual(raised.exception.response["details"]["maxSnapshotDocuments"], 0) + finally: + self._terminate_process(process) + + def test_cultmesh_daemon_serves_opt_in_simulation_observations(self) -> None: + with tempfile.TemporaryDirectory() as temp: + ready_path = Path(temp) / "ready.json" + package_src = Path(__file__).resolve().parents[1] / "src" + env = dict(os.environ) + existing_pythonpath = env.get("PYTHONPATH") + env["PYTHONPATH"] = ( + str(package_src) + if not existing_pythonpath + else f"{package_src}{os.pathsep}{existing_pythonpath}" + ) + process = subprocess.Popen( + [ + sys.executable, + "-m", + "cultmesh_py.daemon", + "--runtime-id", + "simulation-daemon-peer", + "--port", + "0", + "--enable-simulation-observations", + "--simulation-minimum-witnesses", + "2", + "--simulation-quorum-ratio", + "1.0", + "--verse-id", + "simulation-verse", + "--ready-file", + str(ready_path), + ], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + env=env, + ) + try: + ready = self._wait_for_ready_file(process, ready_path) + self.assertIn("cultnet.simulation_observation.v0", ready["supportedMessageVersions"]) + self.assertIn("cultnet.simulation_consensus_candidate.v0", ready["supportedMessageVersions"]) + client = CultMesh.create_client("127.0.0.1", int(ready["port"]), timeout_seconds=2.0) + hello_response = client.request( + hello(runtime_id="simulation-daemon-prober"), + expected_schema_version="cultnet.hello.v0", + ) + self.assertEqual(ready["supportedMessageVersions"], hello_response["supportedMessageVersions"]) + discovery_client = CultMesh.create_verse_discovery_client("127.0.0.1", int(ready["port"]), timeout_seconds=2.0) + peers = discovery_client.fetch_peers(verse_id="simulation-verse", roles=["simulation-observer"]) + self.assertEqual(peers[0].peer_id, "simulation-daemon-peer") + self.assertIn("simulation-observer", peers[0].roles) + self.assertIn("read-replica", peers[0].roles) + + claim_hash = compute_simulation_claim_hash("hit", "alice", "bob", "frame:100") + first = client.request( + simulation_observation( + message_id="daemon-sim-1", + witness_runtime_id="watcher-1", + shard_id="arena", + shard_epoch=4, + frame=100, + subject_id="bob", + claim_kind="hit", + claim_hash=claim_hash, + claim_summary="alice shot bob first", + ), + expected_schema_version="cultnet.simulation_consensus_candidate.v0", + ) + second = client.request( + simulation_observation( + message_id="daemon-sim-2", + witness_runtime_id="watcher-2", + shard_id="arena", + shard_epoch=4, + frame=100, + subject_id="bob", + claim_kind="hit", + claim_hash=claim_hash, + claim_summary="alice shot bob first", + ), + expected_schema_version="cultnet.simulation_consensus_candidate.v0", + ) + + self.assertEqual(first["messageId"], "daemon-sim-1") + self.assertFalse(first["hasQuorum"]) + self.assertEqual(first["witnessCount"], 1) + self.assertEqual(second["messageId"], "daemon-sim-2") + self.assertTrue(second["hasQuorum"]) + self.assertEqual(second["witnessCount"], 2) + self.assertEqual(second["claimHash"], claim_hash) + finally: + self._terminate_process(process) + + def _wait_for_ready_file(self, process: subprocess.Popen[str], ready_path: Path) -> dict[str, object]: + deadline = time.monotonic() + 5.0 + while not ready_path.exists() and time.monotonic() < deadline: + if process.poll() is not None: + break + time.sleep(0.05) + if not ready_path.exists(): + _, stderr = process.communicate(timeout=2.0) + self.fail(f"cultmesh daemon did not publish readiness: {stderr}") + return json.loads(ready_path.read_text(encoding="utf-8")) + + def _terminate_process(self, process: subprocess.Popen[str]) -> None: + process.terminate() + try: + process.communicate(timeout=5.0) + except subprocess.TimeoutExpired: + process.kill() + process.communicate(timeout=5.0) + + def test_cultmesh_local_server_serves_node_and_catalogs_over_clients(self) -> None: + document = define_database_entry_type( + "mesh.server_note", + [("body", 0)], + schema_id="mesh.server_note.v1", + ) + node = CultMesh.create_node(runtime_id="mesh-server") + node.database.register_document(document) + node.database.put_raw_message(document, "note:1", {"body": "served"}, shard_id="notes", shard_epoch=1) + observation_hub = CultNetSimulationObservationHub( + CultNetSimulationConsensusOptions(minimum_witnesses=2, quorum_ratio=1.0) + ) + seen_candidates: list[CultNetSimulationConsensusCandidate] = [] + unsubscribe_candidates = observation_hub.watch_candidates(seen_candidates.append) + claim_hash = compute_simulation_claim_hash("hit", "alice", "bob", "frame:100") + verses = CultMeshVerseCatalog() + verses.upsert( + CultMeshVerseDescriptor( + verse_id="server-verse", + display_name="Server Verse", + authority_model="local", + compatibility=CultMeshVerseCompatibility("cultmesh.v0", "rules"), + ) + ) + peers = CultMeshPeerCatalog() + peers.upsert( + CultMeshPeerCard( + peer_id="mesh-server", + verse_id="server-verse", + endpoints=("cultnet://127.0.0.1:0",), + roles=("read-replica",), + ) + ) + + server = CultMesh.serve_node( + node, + verse_catalog=verses, + peer_catalog=peers, + observation_hub=observation_hub, + display_name="Mesh Server", + ) + try: + raw_client = CultMesh.create_client("127.0.0.1", server.port, timeout_seconds=2.0) + hello_response = raw_client.request(hello(runtime_id="probe"), expected_schema_version="cultnet.hello.v0") + schema_response = raw_client.fetch_schema_catalog(schema_ids=["mesh.server_note.v1"], include_schema_json=True) + rudp_client = CultMesh.create_client( + endpoint=f"rudp://127.0.0.1:{server.port}", + timeout_seconds=2.0, + connection_id=server.rudp_connection_id, + runtime_id="rudp-probe", + ) + rudp_hello_response = rudp_client.request( + hello(runtime_id="rudp-probe"), + expected_schema_version="cultnet.hello.v0", + ) + rudp_schema_response = rudp_client.fetch_schema_catalog( + schema_ids=["mesh.server_note.v1"], + include_schema_json=True, + ) + wire_schema_response = raw_client.fetch_schema_catalog(kinds=["wire_message"], include_schema_json=True) + synced_schema_catalog = CultNetSchemaCatalog() + synced_wire_descriptors = raw_client.sync_schema_catalog( + synced_schema_catalog, + kinds=["wire_message"], + include_schema_json=True, + ) + snapshot_response = raw_client.fetch_snapshot(schema_ids=["mesh.server_note.v1"]) + typed_snapshot_response = raw_client.fetch_snapshot_response(schema_ids=["mesh.server_note.v1"]) + shard_catalog = raw_client.fetch_shard_catalog(schema_ids=["mesh.server_note.v1"]) + synced_shard_catalog = CultNetShardCatalog() + synced_shards = raw_client.sync_shard_catalog(synced_shard_catalog, schema_ids=["mesh.server_note.v1"]) + shard_log = raw_client.fetch_shard_log(shard_id="notes", shard_epoch=1) + typed_shard_log = raw_client.fetch_shard_log_response(shard_id="notes", shard_epoch=1) + self.assertEqual(hello_response["transportProfiles"][0]["transports"][0]["protocol"], "tcp_framed") + self.assertEqual(hello_response["transportProfiles"][0]["transports"][0]["port"], server.port) + stale_shard_log = raw_client.fetch_shard_log(shard_id="notes", shard_epoch=0) + discovery_client = CultMesh.create_verse_discovery_client("127.0.0.1", server.port, timeout_seconds=2.0) + fetched_verses = discovery_client.fetch_verses(transport_version="cultmesh.v0") + fetched_peers = discovery_client.fetch_peers(verse_id="server-verse", roles=["read-replica"]) + first_candidate = raw_client.request( + simulation_observation( + message_id="obs-1", + witness_runtime_id="watcher-1", + shard_id="arena", + shard_epoch=4, + frame=100, + subject_id="bob", + claim_kind="hit", + claim_hash=claim_hash, + claim_summary="alice shot bob first", + ), + expected_schema_version="cultnet.simulation_consensus_candidate.v0", + ) + quorum_candidate = raw_client.request( + simulation_observation( + message_id="obs-2", + witness_runtime_id="watcher-2", + shard_id="arena", + shard_epoch=4, + frame=100, + subject_id="bob", + claim_kind="hit", + claim_hash=claim_hash, + claim_summary="alice shot bob first", + ), + expected_schema_version="cultnet.simulation_consensus_candidate.v0", + ) + with raw_client.subscribe_database(subscription_id="sub-server", schema_ids=["mesh.server_note.v1"]) as subscription: + subscription_snapshot = subscription.read_next_snapshot_response() + subscription.send(document_put_raw( + message_id="server-put", + key="note:2", + schema_id="mesh.server_note.v1", + stored_at="2026-06-14T00:00:00Z", + payload=document.encode_payload({"body": "subscribed"}), + shard_id="primary", + shard_epoch=1, + )) + subscription_change = subscription.read_next_change() + subscription.send(document_delete( + message_id="server-delete", + schema_id="mesh.server_note.v1", + record_key="note:2", + shard_id="primary", + shard_epoch=1, + )) + subscription_delete = subscription.read_next_change() + finally: + unsubscribe_candidates() + server.stop() + + self.assertEqual(hello_response["runtimeId"], "mesh-server") + self.assertEqual(hello_response["displayName"], "Mesh Server") + self.assertIn("cultnet.database_subscribe.v0", hello_response["supportedMessageVersions"]) + self.assertIn("cultnet.error.v0", hello_response["supportedMessageVersions"]) + self.assertIn("cultnet.document_put_raw.v0", hello_response["supportedMessageVersions"]) + self.assertIn("cultnet.simulation_observation.v0", hello_response["supportedMessageVersions"]) + self.assertEqual(hello_response["supportedMutationContracts"][0]["documentType"], "mesh.server_note") + self.assertIn("documentDelete", hello_response["supportedMutationContracts"][0]["operations"]) + self.assertIn("shardLog", hello_response["supportedMutationContracts"][0]["operations"]) + advertised_transports = { + transport["protocol"]: transport + for profile in hello_response["transportProfiles"] + for transport in profile["transports"] + } + self.assertEqual(advertised_transports["tcp_framed"]["port"], server.port) + self.assertEqual(advertised_transports["rudp"]["port"], server.port) + self.assertEqual(rudp_hello_response["runtimeId"], "mesh-server") + self.assertEqual(rudp_schema_response["schemas"][0]["schemaId"], "mesh.server_note.v1") + self.assertEqual(schema_response["schemas"][0]["schemaId"], "mesh.server_note.v1") + self.assertIn("schemaJson", schema_response["schemas"][0]) + self.assertIn("cultnet.document_delete.v0", schema_response["schemas"][0]["wireContracts"]) + self.assertIn("cultnet.shard_log_response.v0", schema_response["schemas"][0]["wireContracts"]) + wire_descriptors = {schema["schemaVersion"]: schema for schema in wire_schema_response["schemas"]} + self.assertEqual(wire_descriptors["cultnet.error.v0"]["kind"], "wire_message") + self.assertEqual(wire_descriptors["cultnet.document_put_raw.v0"]["kind"], "wire_message") + self.assertIn("schemaJson", wire_descriptors["cultnet.document_put_raw.v0"]) + self.assertIn("cultmesh.peer_exchange_response.v0", wire_descriptors) + self.assertIn("cultnet.error.v0", {descriptor.schema_version for descriptor in synced_wire_descriptors}) + self.assertIn("cultnet.document_put_raw.v0", {descriptor.schema_version for descriptor in synced_wire_descriptors}) + self.assertIsNotNone(synced_schema_catalog.get("https://github.com/GameCult/cultnet-ts/contracts/cultnet.document-put-raw.schema.json")) + self.assertEqual(snapshot_response["documents"][0]["recordKey"], "note:1") + self.assertEqual(typed_snapshot_response.documents[0].record_key, "note:1") + self.assertEqual(typed_snapshot_response.documents[0].schema_id, "mesh.server_note.v1") + self.assertEqual(shard_catalog["shards"][0]["schemaIds"], ["mesh.server_note.v1"]) + self.assertEqual(shard_catalog["shards"][0]["epoch"], 1) + self.assertEqual(shard_catalog["shards"][0]["shardId"], "notes") + self.assertEqual(synced_shards[0].shard_id, "notes") + self.assertEqual(synced_shards[0].epoch, 1) + self.assertEqual(synced_shard_catalog.get("notes"), synced_shards[0]) + self.assertEqual(shard_log["entries"][0]["changeKind"], "added") + self.assertTrue(stale_shard_log["resyncRequired"]) + self.assertEqual(stale_shard_log["reason"], "stale_epoch") + self.assertEqual(stale_shard_log["shardEpoch"], 1) + self.assertEqual(stale_shard_log["entries"], []) + self.assertEqual(typed_shard_log.last_sequence, 1) + self.assertEqual(typed_shard_log.entries[0].put["document"]["recordKey"], "note:1") + self.assertIsInstance(typed_shard_log.entries[0].raw_document, CultNetRawDocumentRecord) + self.assertEqual(typed_shard_log.entries[0].raw_document.record_key, "note:1") + self.assertEqual(fetched_verses[0].verse_id, "server-verse") + self.assertEqual(fetched_peers[0].peer_id, "mesh-server") + self.assertEqual(first_candidate["messageId"], "obs-1") + self.assertFalse(first_candidate["hasQuorum"]) + self.assertEqual(quorum_candidate["messageId"], "obs-2") + self.assertEqual(quorum_candidate["claimHash"], claim_hash) + self.assertTrue(quorum_candidate["hasQuorum"]) + self.assertEqual(quorum_candidate["witnessCount"], 2) + self.assertEqual([candidate.claim_hash for candidate in seen_candidates], [claim_hash, claim_hash]) + self.assertIsInstance(subscription_snapshot, CultNetRawSnapshotResponse) + self.assertEqual(subscription_snapshot.to_wire()["schemaVersion"], "cultnet.snapshot_response_raw.v0") + self.assertEqual(subscription_change.change_kind, "added") + self.assertEqual(subscription_change.record_key, "note:2") + self.assertEqual(subscription_change.document["recordKey"], "note:2") + self.assertIsInstance(subscription_change.raw_document, CultNetRawDocumentRecord) + self.assertEqual(subscription_change.raw_document.schema_id, "mesh.server_note.v1") + self.assertEqual(subscription_delete.change_kind, "removed") + self.assertEqual(subscription_delete.record_key, "note:2") + self.assertIsNone(subscription_delete.raw_document) + self.assertIsNone(node.database.get(document, "note:2")) + + def test_cultmesh_local_server_resolves_snapshot_and_shard_catalog_schema_aliases(self) -> None: + document = define_database_entry_type( + "mesh.alias_server_note", + [("body", 0)], + schema_id="sha256:mesh-alias-server-note", + schema_name="mesh.alias_server_note", + schema_version="mesh.alias_server_note.v1", + ) + node = CultMesh.create_node(runtime_id="mesh-alias-server") + node.database.register_document(document) + node.database.put_raw_message( + document, + "note:alias", + {"body": "served through alias"}, + shard_id="notes", + shard_epoch=1, + ) + + server = CultMesh.serve_node(node) + try: + raw_client = CultMesh.create_client("127.0.0.1", server.port, timeout_seconds=2.0) + snapshot = raw_client.fetch_snapshot(schema_ids=["mesh.alias_server_note.v1"]) + typed_snapshot = raw_client.fetch_snapshot_response(schema_ids=["mesh.alias_server_note.v1"]) + shard_catalog = raw_client.fetch_shard_catalog(schema_ids=["mesh.alias_server_note.v1"]) + finally: + server.stop() + + local_schema_id = document.catalog_entry().schema_id + self.assertEqual(snapshot["documents"][0]["schemaId"], local_schema_id) + self.assertEqual(snapshot["documents"][0]["recordKey"], "note:alias") + self.assertEqual(typed_snapshot.documents[0].schema_id, local_schema_id) + self.assertEqual(shard_catalog["shards"][0]["schemaIds"], [local_schema_id]) + self.assertEqual(shard_catalog["shards"][0]["shardId"], "notes") + + def test_cultmesh_shard_snapshot_keeps_foreign_schema_alias_membership(self) -> None: + document = define_database_entry_type( + "mesh.alias_shard_note", + [ + ("schema_version", 0), + ("body", 1), + ], + schema_id="sha256:mesh-alias-shard-note", + schema_name="mesh.alias_shard_note", + schema_version="mesh.alias_shard_note.v1", + ) + node = CultMesh.create_node(runtime_id="mesh-alias-shard-server") + node.database.register_document(document) + + node.database.apply_raw_put_message(document_put_raw( + message_id="put-foreign-shard-alias", + key="note:foreign-shard", + schema_id="runtime.generated.mesh.alias_shard_note.ui.99", + stored_at="2026-06-27T00:00:00Z", + payload=document.encode_payload({ + "schema_version": "mesh.alias_shard_note.v1", + "body": "visible through shard snapshot", + }), + shard_id="notes", + shard_epoch=1, + ).to_wire()) + node.database.put_raw_message( + document, + "note:other-shard", + { + "schema_version": "mesh.alias_shard_note.v1", + "body": "hidden by shard filter", + }, + shard_id="other", + shard_epoch=1, + ) + + response = node.database.build_snapshot_response( + schema_ids=["mesh.alias_shard_note.v1"], + shard_id="notes", + shard_epoch=1, + ) + + local_schema_id = document.catalog_entry().schema_id + self.assertEqual(response.shard_id, "notes") + self.assertEqual(response.shard_epoch, 1) + self.assertEqual([(record.schema_id, record.record_key) for record in response.documents], [ + (local_schema_id, "note:foreign-shard"), + ]) + self.assertEqual(node.cache.get_required_envelope(document, "note:foreign-shard").schema_id, local_schema_id) + + node.database.apply_raw_delete_message(document_delete( + message_id="delete-foreign-shard-alias", + schema_id="mesh.alias_shard_note.v1", + record_key="note:foreign-shard", + shard_id="notes", + shard_epoch=1, + ).to_wire()) + deleted_response = node.database.build_snapshot_response( + schema_ids=["mesh.alias_shard_note.v1"], + shard_id="notes", + shard_epoch=1, + ) + self.assertEqual(deleted_response.documents, ()) + + def test_cultmesh_local_server_notifies_schema_alias_subscription_for_raw_put(self) -> None: + document = define_database_entry_type( + "mesh.alias_sub_note", + [ + ("schema_version", 0), + ("body", 1), + ], + schema_id="sha256:mesh-alias-sub-note", + schema_name="mesh.alias_sub_note", + schema_version="mesh.alias_sub_note.v1", + ) + node = CultMesh.create_node(runtime_id="mesh-alias-sub-server") + node.database.register_document(document) + + server = CultMesh.serve_node(node) + try: + raw_client = CultMesh.create_client("127.0.0.1", server.port, timeout_seconds=2.0) + with raw_client.subscribe_database( + subscription_id="sub-alias", + schema_ids=["mesh.alias_sub_note.v1"], + include_snapshot=False, + ) as subscription: + subscription.send(document_put_raw( + message_id="put-foreign-alias", + key="note:alias-sub", + schema_id="runtime.generated.mesh.alias_sub_note.ui.99", + stored_at="2026-06-27T00:00:00Z", + payload=document.encode_payload({ + "schema_version": "mesh.alias_sub_note.v1", + "body": "notified", + }), + )) + change = subscription.read_next_change() + finally: + server.stop() + + local_schema_id = document.catalog_entry().schema_id + self.assertEqual(change.subscription_id, "sub-alias") + self.assertEqual(change.change_kind, "added") + self.assertEqual(change.record_key, "note:alias-sub") + self.assertIsInstance(change.raw_document, CultNetRawDocumentRecord) + self.assertEqual(change.raw_document.schema_id, "runtime.generated.mesh.alias_sub_note.ui.99") + self.assertEqual(node.database.get_required(document, "note:alias-sub")["body"], "notified") + self.assertEqual(node.cache.get_required_envelope(document, "note:alias-sub").schema_id, local_schema_id) + + def test_cultmesh_local_server_notifies_schema_alias_subscription_for_delete(self) -> None: + document = define_database_entry_type( + "mesh.alias_delete_note", + [("body", 0)], + schema_id="sha256:mesh-alias-delete-note", + schema_name="mesh.alias_delete_note", + schema_version="mesh.alias_delete_note.v1", + ) + node = CultMesh.create_node(runtime_id="mesh-alias-delete-server") + node.database.register_document(document) + node.database.put_raw_message( + document, + "note:delete-alias", + {"body": "remove me"}, + shard_id="notes", + shard_epoch=1, + ) + + server = CultMesh.serve_node(node) + try: + raw_client = CultMesh.create_client("127.0.0.1", server.port, timeout_seconds=2.0) + with raw_client.subscribe_database( + subscription_id="sub-delete-alias", + schema_ids=[document.catalog_entry().schema_id], + include_snapshot=False, + ) as subscription: + subscription.send(document_delete( + message_id="delete-foreign-alias", + schema_id="mesh.alias_delete_note.v1", + record_key="note:delete-alias", + shard_id="notes", + shard_epoch=1, + )) + change = subscription.read_next_change() + finally: + server.stop() + + self.assertEqual(change.subscription_id, "sub-delete-alias") + self.assertEqual(change.change_kind, "removed") + self.assertEqual(change.schema_id, "mesh.alias_delete_note.v1") + self.assertEqual(change.record_key, "note:delete-alias") + self.assertIsNone(change.raw_document) + self.assertIsNone(node.database.get(document, "note:delete-alias")) + + def test_cultmesh_local_server_rejects_oversized_snapshot_responses(self) -> None: + document = define_database_entry_type( + "mesh.snapshot_limit_note", + [("body", 0)], + schema_id="mesh.snapshot_limit_note.v1", + ) + node = CultMesh.create_node(runtime_id="mesh-snapshot-limits") + node.database.register_document(document) + node.database.put_raw_message(document, "note:1", {"body": "first"}) + node.database.put_raw_message(document, "note:2", {"body": "second"}) + + server = CultMesh.serve_node(node, max_snapshot_documents=1) + try: + raw_client = CultMesh.create_client("127.0.0.1", server.port, timeout_seconds=2.0) + filtered_snapshot = raw_client.fetch_snapshot(record_keys=["note:1"]) + error = raw_client.request( + snapshot_request(schema_ids=["mesh.snapshot_limit_note.v1"]), + expected_schema_version="cultnet.error.v0", + ) + with self.assertRaisesRegex(CultNetPeerError, "Snapshot document limit exceeded"): + raw_client.fetch_snapshot(schema_ids=["mesh.snapshot_limit_note.v1"]) + finally: + server.stop() + + self.assertEqual(filtered_snapshot["schemaVersion"], "cultnet.snapshot_response_raw.v0") + self.assertEqual([document["recordKey"] for document in filtered_snapshot["documents"]], ["note:1"]) + self.assertEqual(error["schemaVersion"], "cultnet.error.v0") + self.assertIn("Snapshot document limit exceeded", error["error"]) + self.assertEqual(error["code"], "snapshot_document_limit_exceeded") + self.assertEqual(error["details"]["documentCount"], 2) + self.assertEqual(error["details"]["maxSnapshotDocuments"], 1) + + def test_cultmesh_local_server_returns_errors_for_bad_requests(self) -> None: + document = define_database_entry_type( + "mesh.error_note", + [("body", 0)], + schema_id="mesh.error_note.v1", + ) + node = CultMesh.create_node(runtime_id="mesh-error-server") + node.database.register_document(document) + + server = CultMesh.serve_node(node) + try: + raw_client = CultMesh.create_client("127.0.0.1", server.port, timeout_seconds=2.0) + unsupported = raw_client.request( + {"schemaVersion": "cultnet.nope.v0", "messageId": "bad-schema"}, + expected_schema_version="cultnet.error.v0", + ) + malformed_put = raw_client.request( + {"schemaVersion": "cultnet.document_put_raw.v0", "messageId": "bad-put"}, + expected_schema_version="cultnet.error.v0", + ) + malformed_delete = raw_client.request( + {"schemaVersion": "cultnet.document_delete.v0", "messageId": "bad-delete", "schemaId": "mesh.error_note.v1"}, + expected_schema_version="cultnet.error.v0", + ) + finally: + server.stop() + + self.assertEqual(unsupported["messageId"], "bad-schema") + self.assertEqual(unsupported["code"], "unsupported_schema_version") + self.assertEqual(unsupported["details"]["schemaVersion"], "cultnet.nope.v0") + self.assertIn("Unsupported CultNet message schema", unsupported["error"]) + self.assertEqual(malformed_put["messageId"], "bad-put") + self.assertEqual(malformed_put["code"], "malformed_document_put") + self.assertEqual(malformed_delete["messageId"], "bad-delete") + self.assertEqual(malformed_delete["code"], "malformed_document_delete") + + def test_cultmesh_authority_lease_requires_live_matching_lease(self) -> None: + peer = CultMeshPeerCard( + peer_id="voidbot-local", + verse_id="local", + endpoints=("cultmesh://localhost",), + roles=("shard-primary",), + authority_lease_id="lease:voidbot-local", + ) + leases = CultMeshAuthorityLeaseCatalog() + peers = CultMeshPeerCatalog() + peers.upsert(peer) + now = datetime.now(UTC) + self.assertFalse(leases.is_authorized(peer, "shard-primary", at=now)) + self.assertEqual(peers.find_authorized("local", "shard-primary", leases, at=now), []) + + leases.upsert( + CultMeshAuthorityLease( + lease_id="lease:voidbot-local", + verse_id="local", + peer_id="voidbot-local", + roles=("shard-primary", "shard-primary", ""), + valid_from=now - timedelta(seconds=1), + expires_at=now + timedelta(seconds=1), + shard_ids=("shard-a",), + issuer_runtime_id="odin", + signature="signed", + ) + ) + + lease = leases.get("lease:voidbot-local") + self.assertIsNotNone(lease) + assert lease is not None + self.assertEqual(leases.leases, (lease,)) + self.assertEqual(lease.roles, ("shard-primary",)) + self.assertEqual(lease.issuer_runtime_id, "odin") + self.assertEqual(lease.signature, "signed") + self.assertTrue(lease.is_valid_at(now)) + self.assertTrue(lease.covers(peer, "shard-primary", shard_id="shard-a", at=now)) + self.assertFalse(lease.covers(peer, "shard-primary", shard_id="shard-b", at=now)) + self.assertTrue(leases.is_authorized(peer, "shard-primary", shard_id="shard-a", at=now)) + self.assertEqual( + peers.find_authorized("local", "shard-primary", leases, shard_id="shard-a", at=now), + [peer], + ) + self.assertEqual( + peers.first_authorized("local", "shard-primary", leases, shard_id="shard-a", at=now), + peer, + ) + self.assertIsNone(peers.first_authorized("local", "read-replica", leases, at=now)) + self.assertFalse(leases.is_authorized(peer, "shard-primary", shard_id="shard-b", at=now)) + self.assertFalse(leases.is_authorized(peer, "read-replica", at=now)) + self.assertIsNone(leases.get("missing")) + + def test_cultmesh_authority_lease_catalog_can_require_verified_signatures(self) -> None: + peer = CultMeshPeerCard( + peer_id="voidbot-local", + verse_id="local", + endpoints=("cultmesh://localhost",), + roles=("shard-primary",), + shard_ids=("shard-a",), + authority_lease_id="lease:voidbot-local", + ) + now = datetime.now(UTC) + unsigned = CultMeshAuthorityLease( + lease_id="lease:voidbot-local", + verse_id="local", + peer_id="voidbot-local", + roles=("shard-primary",), + valid_from=now - timedelta(seconds=1), + expires_at=now + timedelta(seconds=30), + shard_ids=("shard-a",), + issuer_runtime_id="odin", + ) + verifier = CultMeshHmacAuthorityLeaseVerifier({"odin": b"lease-secret"}) + signed = verifier.issue(unsigned) + strict_leases = CultMesh.create_authority_lease_catalog( + signature_verifier=verifier.verify, + require_verified_signatures=True, + ) + strict_leases.upsert(unsigned) + self.assertFalse(strict_leases.is_verified(unsigned.lease_id)) + self.assertFalse(strict_leases.is_authorized(peer, "shard-primary", shard_id="shard-a", at=now)) + + strict_leases.upsert(signed) + self.assertTrue(strict_leases.is_verified(signed.lease_id)) + self.assertTrue(strict_leases.is_authorized(peer, "shard-primary", shard_id="shard-a", at=now)) + + wrong_key = CultMesh.create_authority_lease_catalog( + signature_verifier=CultMeshHmacAuthorityLeaseVerifier({"odin": b"wrong-secret"}).verify, + require_verified_signatures=True, + ) + wrong_key.upsert(signed) + self.assertFalse(wrong_key.is_verified(signed.lease_id)) + self.assertFalse(wrong_key.is_authorized(peer, "shard-primary", shard_id="shard-a", at=now)) + + tampered = CultMeshAuthorityLease( + lease_id=signed.lease_id, + verse_id=signed.verse_id, + peer_id=signed.peer_id, + roles=("shard-primary", "read-replica"), + valid_from=signed.valid_from, + expires_at=signed.expires_at, + shard_ids=signed.shard_ids, + issuer_runtime_id=signed.issuer_runtime_id, + signature=signed.signature, + ) + strict_leases.upsert(tampered) + self.assertFalse(strict_leases.is_verified(tampered.lease_id)) + self.assertFalse(strict_leases.is_authorized(peer, "shard-primary", shard_id="shard-a", at=now)) + + def test_cultmesh_stream_catalog_negotiates_transport_and_latest_frame(self) -> None: + streams = CultMeshStreamCatalog() + streams.declare( + CultMeshStreamDescriptor( + stream_id="mimir:kiyo-pro", + verse_id="studio", + owner_peer_id="starfire", + kind="video", + label="Kiyo Pro", + clock={"clockDomainId": "starfire-qpc", "confidence": 0.25}, + video={"width": 1920, "height": 1080, "pixelFormat": "YUY2", "framesPerSecond": 30}, + preferred_transports=("shared-d3d12-texture", "shared-memory", "cultcache-page"), + max_in_flight_frames=3, + ) + ) + + negotiation = streams.negotiate( + "mimir:kiyo-pro", + CultMeshStreamConsumerProfile( + peer_id="fensalir", + verse_id="studio", + supported_transports=("shared-d3d12-texture", "cultcache-page"), + accepted_kinds=("video",), + can_import_gpu_handles=True, + max_in_flight_frames=2, + ), + ) + + self.assertEqual(negotiation.transport, "shared-d3d12-texture") + self.assertEqual(negotiation.max_in_flight_frames, 2) + self.assertEqual(negotiation.copy_budget, "zero-copy-target") + + streams.publish_frame( + CultMeshStreamFrameHandle( + stream_id="mimir:kiyo-pro", + sequence=42, + timestamp_ns=1_000_000_000, + duration_ns=33_333_334, + transport="shared-d3d12-texture", + native_handle="0xfeed", + fence_handle="0xbeef", + fence_value=7, + unavoidable_copy_count=0, + ) + ) + self.assertEqual(streams.latest_frame("mimir:kiyo-pro").sequence, 42) + + +if __name__ == "__main__": + unittest.main() diff --git a/packages/cultcache-py/tools/reactive_performance_probe.py b/packages/cultmesh-py/tools/reactive_performance_probe.py similarity index 100% rename from packages/cultcache-py/tools/reactive_performance_probe.py rename to packages/cultmesh-py/tools/reactive_performance_probe.py diff --git a/packages/cultnet-py/README.md b/packages/cultnet-py/README.md new file mode 100644 index 00000000..cca39ba7 --- /dev/null +++ b/packages/cultnet-py/README.md @@ -0,0 +1,156 @@ +# cultnet-py + +`cultnet-py` is the Python CultNet runtime: schema-v0 MessagePack wire helpers, +4-byte big-endian framing, the raw client, database subscriptions, shard +catch-up and replication, simulation observations and consensus, witness +artifact bundles, the RUDP codec/session/socket transport, and the CultMesh +wire contracts that both a node and a bare peer have to agree on. + +It depends on `cultcache-py` and `msgpack`; AES-GCM helpers on `CultNetSecret` +light up with the optional `crypto` extra. `cultmesh-py` builds on it. The +layering mirrors `cultnet-rs` and `cultnet-ts`. + +## Example + +```python +from datetime import UTC, datetime + +from cultnet_py import ( + CultNetSecret, + CultNetServerSecurityOptions, + CultNetRawClient, + CultNetSimulationObservation, + CultNetWitnessArtifactBundle, + apply_raw_snapshot, + apply_shard_log_response, + compute_simulation_claim_hash, + database_subscribe, + decode_frame, + encode_frame, + hello, + parse_message, + shard_catalog_request, + simulation_observation, + witness_artifact_bundle, +) + +payload = hello(runtime_id="python-runtime").to_bytes() +message = parse_message(decode_frame(encode_frame(payload))) + +client = CultNetRawClient("127.0.0.1", 3075) +catalog = client.fetch_schema_catalog(kinds=["wire_message"]) +snapshot = client.fetch_snapshot_response(schema_ids=["cultnet.interop-note"]) +shard_catalog = client.fetch_shard_catalog(schema_ids=["cultnet.interop-note"]) +# With a local CultCache and the matching registered document definitions: +# applied = apply_raw_snapshot(cache, [note_doc], snapshot) + +subscription = database_subscribe(subscription_id="ui", schema_ids=["cultnet.interop-note"]) +shard_request = shard_catalog_request(message_id="shards", schema_ids=["cultnet.interop-note"]) +shard_log = client.fetch_shard_log_response(shard_id="interop", shard_epoch=1, after_sequence=0) +# log_changes = apply_shard_log_response(cache, [note_doc], shard_log) +with client.subscribe_database(subscription_id="ui", schema_ids=["cultnet.interop-note"]) as live: + initial_snapshot = live.read_next_snapshot_response() + +claim_hash = compute_simulation_claim_hash("frame:42", "subject:player-1", "hit") +observation = simulation_observation( + message_id="obs-1", + witness_runtime_id="python-runtime", + shard_id="interop", + shard_epoch=1, + frame=42, + subject_id="player-1", + claim_kind="hit", + claim_hash=claim_hash, +) +typed_observation = CultNetSimulationObservation.from_wire(observation.to_wire()) +witness = witness_artifact_bundle( + bundle_id="bundle-1", + witness_kind="interop-proof", + captured_at="2026-06-13T00:00:00Z", + subject={"documentType": "cultnet.interop-note", "subjectId": "note:python"}, + contracts=[{"role": "payload", "schemaId": "cultnet.interop-note"}], + artifacts=[{"role": "log", "uri": "cultcache://bundle-1/log", "mediaType": "text/plain"}], + provenance={"pipelineId": "interop", "runId": "run-1", "runtimeId": "python-runtime"}, +) +typed_witness = CultNetWitnessArtifactBundle.from_wire(witness) +witness_payload = typed_witness.to_payload() + +security = CultNetServerSecurityOptions.development() +token = CultNetSecret.create_session_token( + "318fb4b6-ff5e-4c4f-b911-d81807de53a8", + datetime(2035, 1, 1, tzinfo=UTC), + security, + session_version=1, +) +session = CultNetSecret.try_validate_session_token(token, security) +``` + +The raw-client request surface can ride RUDP when the peer advertises a +`rudp://` endpoint and shares the connection id for that lane; +`create_rudp_schema_transport(...)` builds that transport, and +`cultmesh_py.CultMesh.create_client(endpoint="rudp://...")` selects it from an +endpoint string. + +## CultMesh wire contracts + +`cultnet_py.cultmesh_contracts` carries the Verse catalog, peer exchange, +authority lease, stream negotiation, and committed simulation fact contracts. +They live here rather than in `cultmesh-py` for the same reason +`CultMeshPeerCard` lives in `cultnet-rs`: the interop peer has to speak them +without owning a node. `cultmesh_py` re-exports every one of them, so callers +that already import from there keep working. + +## RUDP + +`CultNetRudpSession` is the shared reliable/unreliable/sequenced/ordered +session over the RUDP packet codec, with fragmentation above +`max_fragment_bytes`, a bounded reliable window, reliable expiry, and a +bounded fragment reassembly map that evicts the oldest stranded set and counts +it in `fragment_sets_evicted` rather than refusing new payloads. The +socket-backed transport, reconnect policy/controller, and reconnect loop follow +the Rust and TypeScript entrypoint pattern. + +## Interop peer + +The peer can serve, dial, and probe the same raw-state interop lane used by the +TypeScript, Rust, and C# test peers, and answers Verse catalog and peer exchange +requests without a CultMesh node: + +```powershell +python -m cultnet_py.interop_peer serve --runtime-id python-peer --runtime-kind python --display-name "Python Peer" --agent-id python-agent --advertise-host 127.0.0.1 --tcp-port 3075 --discovery-port 4075 --discovery-group 239.77.44.11 --schema-path ..\cultnet-ts\integration\contracts\cultnet.interop-note.schema.json +python -m cultnet_py.interop_peer dial --runtime-id python-client --runtime-kind python --display-name "Python Client" --agent-id python-client --target-host 127.0.0.1 --target-port 3075 --schema-path ..\cultnet-ts\integration\contracts\cultnet.interop-note.schema.json +python -m cultnet_py.interop_peer probe --runtime-id python-prober --discovery-port 4075 --discovery-group 239.77.44.11 +``` + +`packages/cultnet-ts/test/interop/cultnet-interop.test.ts` drives it inside the +live TS/Rust/C#/Python peer ring. + +## Performance baseline + +The package ships a lightweight benchmark for Python-owned hot paths. In a +CultLib source checkout, it can also run the C# reference benchmark beside it: + +```powershell +python -m cultnet_py.benchmark --records 1000 --json +python -m cultnet_py.compare_csharp --records 1000 --json +``` + +It reports slot-indexed `DatabaseEntry` encode/decode throughput, framed +CultNet MessagePack parse throughput, raw snapshot application into a +registered cache, and public `CultCache` upsert/get throughput. The C# compare +command also runs `packages/cultnet-py/tools/GameCult.Caching.Benchmark` and +reports median Python-to-C# ratios for the shared public cache operations. It +uses three samples by default; pass `--samples` when you need a different +evidence shape. Treat the numbers as a local baseline, not a claim that Python +matches the C# reference in every workload. + +## Tests + +```powershell +$env:PYTHONPATH="$PWD\packages\cultcache-py\src;$PWD\packages\cultnet-py\src" +python -m unittest discover -s packages\cultnet-py\tests +``` + +The suite runs without `cultmesh_py` on the path. See +[docs/python-runtime-parity.md](../../docs/python-runtime-parity.md) for the +evidence map across the three Python packages. diff --git a/packages/cultnet-py/pyproject.toml b/packages/cultnet-py/pyproject.toml new file mode 100644 index 00000000..f102b58b --- /dev/null +++ b/packages/cultnet-py/pyproject.toml @@ -0,0 +1,33 @@ +[build-system] +requires = ["setuptools>=68"] +build-backend = "setuptools.build_meta" + +[project] +name = "cultnet-py" +version = "0.1.0" +description = "Python CultNet transport, wire contracts, and replication for GameCult typed state." +readme = "README.md" +requires-python = ">=3.10" +license = "MIT" +authors = [{ name = "GameCult" }] +classifiers = [ + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", +] +dependencies = ["cultcache-py>=0.2.0", "msgpack>=1.0"] +[project.optional-dependencies] +crypto = ["cryptography>=42"] + +[project.scripts] +cultnet-py-interop = "cultnet_py.interop_peer:main" +cultnet-py-benchmark = "cultnet_py.benchmark:main" +cultnet-py-compare-csharp = "cultnet_py.compare_csharp:main" + +[tool.setuptools.packages.find] +where = ["src"] + +[tool.setuptools.package-data] +cultnet_py = ["py.typed"] diff --git a/packages/cultcache-py/src/cultnet_py/__init__.py b/packages/cultnet-py/src/cultnet_py/__init__.py similarity index 79% rename from packages/cultcache-py/src/cultnet_py/__init__.py rename to packages/cultnet-py/src/cultnet_py/__init__.py index ec54059d..b1734f25 100644 --- a/packages/cultcache-py/src/cultnet_py/__init__.py +++ b/packages/cultnet-py/src/cultnet_py/__init__.py @@ -7,6 +7,34 @@ from .client import ( create_rudp_schema_transport, create_tcp_framed_schema_transport, ) +from .cultmesh_contracts import ( + PEER_EXCHANGE_REQUEST, + PEER_EXCHANGE_RESPONSE, + SIMULATION_FACT_DOCUMENT_TYPE, + SIMULATION_FACT_SCHEMA_VERSION, + VERSE_CATALOG_REQUEST, + VERSE_CATALOG_RESPONSE, + AuthorityLeaseVerifier, + CultMeshAuthorityLease, + CultMeshAuthorityLeaseCatalog, + CultMeshHmacAuthorityLeaseVerifier, + CultMeshPeerCard, + CultMeshPeerCatalog, + CultMeshSimulationFact, + CultMeshStreamCatalog, + CultMeshStreamConsumerProfile, + CultMeshStreamDescriptor, + CultMeshStreamFrameHandle, + CultMeshStreamNegotiation, + CultMeshVerseCatalog, + CultMeshVerseCompatibility, + CultMeshVerseDescriptor, + peer_exchange_request, + peer_from_wire, + simulation_fact_document, + verse_catalog_request, + verse_from_wire, +) from .framing import decode_frame, encode_frame, read_frame, write_frame from .messages import ( CultNetMessage, @@ -108,6 +136,32 @@ from .simulation import ( ) __all__ = [ + "PEER_EXCHANGE_REQUEST", + "PEER_EXCHANGE_RESPONSE", + "SIMULATION_FACT_DOCUMENT_TYPE", + "SIMULATION_FACT_SCHEMA_VERSION", + "VERSE_CATALOG_REQUEST", + "VERSE_CATALOG_RESPONSE", + "AuthorityLeaseVerifier", + "CultMeshAuthorityLease", + "CultMeshAuthorityLeaseCatalog", + "CultMeshHmacAuthorityLeaseVerifier", + "CultMeshPeerCard", + "CultMeshPeerCatalog", + "CultMeshSimulationFact", + "CultMeshStreamCatalog", + "CultMeshStreamConsumerProfile", + "CultMeshStreamDescriptor", + "CultMeshStreamFrameHandle", + "CultMeshStreamNegotiation", + "CultMeshVerseCatalog", + "CultMeshVerseCompatibility", + "CultMeshVerseDescriptor", + "peer_exchange_request", + "peer_from_wire", + "simulation_fact_document", + "verse_catalog_request", + "verse_from_wire", "CultNetMessage", "CultNetWitnessArtifactBundle", "CultNetDatabaseSubscription", diff --git a/packages/cultcache-py/src/cultcache_py/benchmark.py b/packages/cultnet-py/src/cultnet_py/benchmark.py similarity index 98% rename from packages/cultcache-py/src/cultcache_py/benchmark.py rename to packages/cultnet-py/src/cultnet_py/benchmark.py index a444acd9..83834635 100644 --- a/packages/cultcache-py/src/cultcache_py/benchmark.py +++ b/packages/cultnet-py/src/cultnet_py/benchmark.py @@ -19,7 +19,7 @@ class BenchItem: def main(argv: list[str] | None = None) -> int: - parser = argparse.ArgumentParser(prog="cultcache-py-benchmark") + parser = argparse.ArgumentParser(prog="cultnet-py-benchmark") parser.add_argument("--records", type=int, default=5000) parser.add_argument("--json", action="store_true", dest="as_json") args = parser.parse_args(argv) diff --git a/packages/cultcache-py/src/cultnet_py/client.py b/packages/cultnet-py/src/cultnet_py/client.py similarity index 100% rename from packages/cultcache-py/src/cultnet_py/client.py rename to packages/cultnet-py/src/cultnet_py/client.py diff --git a/packages/cultcache-py/src/cultcache_py/compare_csharp.py b/packages/cultnet-py/src/cultnet_py/compare_csharp.py similarity index 99% rename from packages/cultcache-py/src/cultcache_py/compare_csharp.py rename to packages/cultnet-py/src/cultnet_py/compare_csharp.py index 8a9e4c5b..a2654a33 100644 --- a/packages/cultcache-py/src/cultcache_py/compare_csharp.py +++ b/packages/cultnet-py/src/cultnet_py/compare_csharp.py @@ -16,7 +16,7 @@ DEFAULT_PARITY_THRESHOLD = 0.90 def main(argv: list[str] | None = None) -> int: - parser = argparse.ArgumentParser(prog="cultcache-py-compare-csharp") + parser = argparse.ArgumentParser(prog="cultnet-py-compare-csharp") parser.add_argument("--records", type=int, default=5000) parser.add_argument("--samples", type=int, default=DEFAULT_SAMPLE_COUNT) parser.add_argument("--parity-threshold", type=float, default=DEFAULT_PARITY_THRESHOLD) diff --git a/packages/cultcache-py/src/cultmesh_py/wire.py b/packages/cultnet-py/src/cultnet_py/cultmesh_contracts.py similarity index 84% rename from packages/cultcache-py/src/cultmesh_py/wire.py rename to packages/cultnet-py/src/cultnet_py/cultmesh_contracts.py index 9a666a1e..91d0805b 100644 --- a/packages/cultcache-py/src/cultmesh_py/wire.py +++ b/packages/cultnet-py/src/cultnet_py/cultmesh_contracts.py @@ -1,14 +1,18 @@ from __future__ import annotations import base64 +import hashlib import hmac from dataclasses import dataclass, field, replace -from datetime import datetime +from datetime import UTC, datetime from hashlib import sha256 from typing import Any, Callable, Mapping import msgpack +from cultcache_py import define_database_entry_type +from cultcache_py.documents import DocumentDefinition + VERSE_CATALOG_REQUEST = "cultmesh.verse_catalog_request.v0" VERSE_CATALOG_RESPONSE = "cultmesh.verse_catalog_response.v0" @@ -613,3 +617,104 @@ def copy_budget_for(transport: str) -> str: if transport == "inline-bytes": return "opaque-runtime" return "opaque-runtime" + + +SIMULATION_FACT_DOCUMENT_TYPE = "gamecult.mesh.simulation_fact" +SIMULATION_FACT_SCHEMA_VERSION = "gamecult.mesh.simulation_fact.v1" + + +@dataclass(frozen=True) +class CultMeshSimulationFact: + fact_id: str + shard_id: str + shard_epoch: int + frame: int + subject_id: str + claim_kind: str + claim_hash: str + claim_summary: str | None + witness_count: int + support_weight: float + total_weight: float + confidence: float + committed_at: str + + @staticmethod + def compute_fact_id(candidate: dict[str, Any]) -> str: + canonical = "\x1f".join([ + _candidate_string(candidate, "shardId", "shard_id"), + str(_candidate_int(candidate, "shardEpoch", "shard_epoch")), + str(_candidate_int(candidate, "frame", "frame")), + _candidate_string(candidate, "subjectId", "subject_id"), + _candidate_string(candidate, "claimKind", "claim_kind"), + ]) + return hashlib.sha256(canonical.encode("utf-8")).hexdigest() + + @staticmethod + def create_record_key(candidate: dict[str, Any]) -> str: + return f"simulation:{CultMeshSimulationFact.compute_fact_id(candidate)}" + + @staticmethod + def from_candidate(candidate: dict[str, Any], *, committed_at: str | None = None) -> "CultMeshSimulationFact": + return CultMeshSimulationFact( + fact_id=CultMeshSimulationFact.compute_fact_id(candidate), + shard_id=_candidate_string(candidate, "shardId", "shard_id"), + shard_epoch=_candidate_int(candidate, "shardEpoch", "shard_epoch"), + frame=_candidate_int(candidate, "frame", "frame"), + subject_id=_candidate_string(candidate, "subjectId", "subject_id"), + claim_kind=_candidate_string(candidate, "claimKind", "claim_kind"), + claim_hash=_candidate_string(candidate, "claimHash", "claim_hash"), + claim_summary=_candidate_optional_string(candidate, "claimSummary", "claim_summary"), + witness_count=_candidate_int(candidate, "witnessCount", "witness_count"), + support_weight=_candidate_float(candidate, "supportWeight", "support_weight"), + total_weight=_candidate_float(candidate, "totalWeight", "total_weight"), + confidence=_candidate_float(candidate, "confidence", "confidence"), + committed_at=committed_at or datetime.now(UTC).isoformat(), + ) + + +simulation_fact_document: DocumentDefinition[CultMeshSimulationFact] = define_database_entry_type( + SIMULATION_FACT_DOCUMENT_TYPE, + [ + ("fact_id", 0), + ("shard_id", 1), + ("shard_epoch", 2), + ("frame", 3), + ("subject_id", 4), + ("claim_kind", 5), + ("claim_hash", 6), + ("claim_summary", 7, None), + ("witness_count", 8), + ("support_weight", 9), + ("total_weight", 10), + ("confidence", 11), + ("committed_at", 12), + ], + cls=CultMeshSimulationFact, + name="fact_id", + indexes={"shard": "shard_id", "frame": "frame", "subject": "subject_id", "claim_kind": "claim_kind"}, + schema_name=SIMULATION_FACT_DOCUMENT_TYPE, + schema_version=SIMULATION_FACT_SCHEMA_VERSION, +) + + +def _candidate_string(candidate: dict[str, Any], camel: str, snake: str) -> str: + value = candidate.get(camel, candidate.get(snake, "")) + if value is None: + return "" + return str(value) + + +def _candidate_optional_string(candidate: dict[str, Any], camel: str, snake: str) -> str | None: + value = candidate.get(camel, candidate.get(snake)) + if value is None: + return None + return str(value) + + +def _candidate_int(candidate: dict[str, Any], camel: str, snake: str) -> int: + return int(candidate.get(camel, candidate.get(snake, 0))) + + +def _candidate_float(candidate: dict[str, Any], camel: str, snake: str) -> float: + return float(candidate.get(camel, candidate.get(snake, 0.0))) diff --git a/packages/cultcache-py/src/cultnet_py/framing.py b/packages/cultnet-py/src/cultnet_py/framing.py similarity index 100% rename from packages/cultcache-py/src/cultnet_py/framing.py rename to packages/cultnet-py/src/cultnet_py/framing.py diff --git a/packages/cultcache-py/src/cultnet_py/interop_peer.py b/packages/cultnet-py/src/cultnet_py/interop_peer.py similarity index 99% rename from packages/cultcache-py/src/cultnet_py/interop_peer.py rename to packages/cultnet-py/src/cultnet_py/interop_peer.py index 7ee9995e..ca3c692d 100644 --- a/packages/cultcache-py/src/cultnet_py/interop_peer.py +++ b/packages/cultnet-py/src/cultnet_py/interop_peer.py @@ -24,7 +24,7 @@ from cultcache_py import ( define_document_type, ) from cultcache_py.documents import DocumentDefinition -from cultmesh_py import ( +from .cultmesh_contracts import ( PEER_EXCHANGE_REQUEST, SIMULATION_FACT_DOCUMENT_TYPE, VERSE_CATALOG_REQUEST, diff --git a/packages/cultcache-py/src/cultnet_py/messages.py b/packages/cultnet-py/src/cultnet_py/messages.py similarity index 100% rename from packages/cultcache-py/src/cultnet_py/messages.py rename to packages/cultnet-py/src/cultnet_py/messages.py diff --git a/packages/cultcache-py/src/cultnet_py/prediction.py b/packages/cultnet-py/src/cultnet_py/prediction.py similarity index 100% rename from packages/cultcache-py/src/cultnet_py/prediction.py rename to packages/cultnet-py/src/cultnet_py/prediction.py diff --git a/packages/cultcache-py/src/cultnet_py/py.typed b/packages/cultnet-py/src/cultnet_py/py.typed similarity index 100% rename from packages/cultcache-py/src/cultnet_py/py.typed rename to packages/cultnet-py/src/cultnet_py/py.typed diff --git a/packages/cultcache-py/src/cultnet_py/replication.py b/packages/cultnet-py/src/cultnet_py/replication.py similarity index 100% rename from packages/cultcache-py/src/cultnet_py/replication.py rename to packages/cultnet-py/src/cultnet_py/replication.py diff --git a/packages/cultcache-py/src/cultnet_py/schema_catalog.py b/packages/cultnet-py/src/cultnet_py/schema_catalog.py similarity index 100% rename from packages/cultcache-py/src/cultnet_py/schema_catalog.py rename to packages/cultnet-py/src/cultnet_py/schema_catalog.py diff --git a/packages/cultcache-py/src/cultnet_py/security.py b/packages/cultnet-py/src/cultnet_py/security.py similarity index 100% rename from packages/cultcache-py/src/cultnet_py/security.py rename to packages/cultnet-py/src/cultnet_py/security.py diff --git a/packages/cultcache-py/src/cultnet_py/shard_catalog.py b/packages/cultnet-py/src/cultnet_py/shard_catalog.py similarity index 100% rename from packages/cultcache-py/src/cultnet_py/shard_catalog.py rename to packages/cultnet-py/src/cultnet_py/shard_catalog.py diff --git a/packages/cultcache-py/src/cultnet_py/shard_log.py b/packages/cultnet-py/src/cultnet_py/shard_log.py similarity index 100% rename from packages/cultcache-py/src/cultnet_py/shard_log.py rename to packages/cultnet-py/src/cultnet_py/shard_log.py diff --git a/packages/cultcache-py/src/cultnet_py/shard_replication.py b/packages/cultnet-py/src/cultnet_py/shard_replication.py similarity index 100% rename from packages/cultcache-py/src/cultnet_py/shard_replication.py rename to packages/cultnet-py/src/cultnet_py/shard_replication.py diff --git a/packages/cultcache-py/src/cultnet_py/simulation.py b/packages/cultnet-py/src/cultnet_py/simulation.py similarity index 100% rename from packages/cultcache-py/src/cultnet_py/simulation.py rename to packages/cultnet-py/src/cultnet_py/simulation.py diff --git a/packages/cultcache-py/src/cultnet_py/snapshot.py b/packages/cultnet-py/src/cultnet_py/snapshot.py similarity index 100% rename from packages/cultcache-py/src/cultnet_py/snapshot.py rename to packages/cultnet-py/src/cultnet_py/snapshot.py diff --git a/packages/cultcache-py/src/cultnet_py/subscription.py b/packages/cultnet-py/src/cultnet_py/subscription.py similarity index 100% rename from packages/cultcache-py/src/cultnet_py/subscription.py rename to packages/cultnet-py/src/cultnet_py/subscription.py diff --git a/packages/cultcache-py/src/cultnet_py/transport.py b/packages/cultnet-py/src/cultnet_py/transport.py similarity index 100% rename from packages/cultcache-py/src/cultnet_py/transport.py rename to packages/cultnet-py/src/cultnet_py/transport.py diff --git a/packages/cultnet-py/tests/test_cultnet.py b/packages/cultnet-py/tests/test_cultnet.py new file mode 100644 index 00000000..171a34b9 --- /dev/null +++ b/packages/cultnet-py/tests/test_cultnet.py @@ -0,0 +1,2046 @@ +from __future__ import annotations + +import json +import socket +import threading +import time +import unittest +import hashlib +import hmac +import io +from dataclasses import dataclass +from datetime import UTC, datetime +from pathlib import Path +from typing import Callable +from uuid import uuid4 +from cultcache_py import CultCache, define_database_entry_type +from cultnet_py.benchmark import run_benchmark +from cultnet_py.compare_csharp import ( + DEFAULT_PARITY_THRESHOLD, + DEFAULT_SAMPLE_COUNT, + _compare_common_metrics, + _median_result, + _parity_status, +) +from cultnet_py.interop_peer import append_shard_log_put, build_state, raw_snapshot_response +from cultnet_py import ( + compute_simulation_claim_hash, + CultNetDatabaseChange, + CultNetRawClient, + CultNetRawDocumentRecord, + CultNetRawSnapshotResponse, + CultNetSchemaCatalog, + CultNetSchemaDescriptor, + CultNetShardCatalog, + CultNetShardDescriptor, + CultNetShardLogEntry, + CultNetShardLogResponse, + CultNetPeerError, + CultNetClientSecurityOptions, + CultNetSecret, + CultNetServerSecurityOptions, + CultNetSimulationConsensusOptions, + CultNetSimulationConsensusCandidate, + CultNetSimulationObservation, + CultNetRudpPacket, + CultNetRudpPacketType, + CultNetRudpSendOptions, + CultNetRudpSession, + CultNetRudpSessionOptions, + CultNetRudpSocketMode, + CultNetRudpReconnectLoop, + CultNetRudpSocketTransportConnection, + CultNetRudpSocketTransportOptions, + TcpFramedTransportConnection, + CultNetWitnessArtifactBundle, + apply_raw_document_record, + apply_raw_snapshot, + apply_shard_log_response, + create_rudp_transport_profile, + create_tcp_framed_transport_profile, + create_reconnect_policy, + CultNetReconnectController, + database_subscribe, + database_unsubscribe, + decode_frame, + decode_rudp_packet, + decode_witness_artifact_bundle_payload, + document_delete, + document_put_raw, + encode_frame, + encode_rudp_packet, + encode_witness_artifact_bundle_payload, + hello, + login, + login_success, + parse_message, + register, + schema_catalog_request, + schema_document_map, + shard_catalog_request, + shard_log_request, + simulation_observation, + snapshot_request, + verify_session, + wire_message_schema_catalog, + wire_message_schema_descriptors, + witness_artifact_bundle, + compute_reconnect_delay_ms, +) + + +def bind_udp_socket() -> socket.socket: + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + sock.bind(("127.0.0.1", 0)) + sock.settimeout(0.02) + return sock + + +def pump_rudp_handshake( + client: CultNetRudpSocketTransportConnection, + server: CultNetRudpSocketTransportConnection, +) -> None: + for _ in range(20): + server.receive_once() + client.receive_once() + server.receive_once() + if client.connected and server.connected: + return + time.sleep(0.005) + raise AssertionError("RUDP socket handshake did not complete") + + +def receive_rudp_frame(transport: CultNetRudpSocketTransportConnection): + for _ in range(20): + frame = transport.receive_once() + if frame is not None: + return frame + time.sleep(0.005) + raise AssertionError("RUDP socket frame was not delivered") + + +@dataclass +class Item: + name: str + category: str + value: int + + +class CultNetTests(unittest.TestCase): + def test_benchmark_reports_core_hot_path_metrics(self) -> None: + result = run_benchmark(8) + metric_names = {metric["name"] for metric in result["metrics"]} + self.assertEqual(result["records"], 8) + self.assertEqual(result["wireMessageCount"], 8) + self.assertEqual(metric_names, { + "database_entry_encode", + "database_entry_decode", + "cultnet_frame_parse", + "raw_snapshot_apply", + "cache_upsert", + "cache_get", + }) + self.assertTrue(all(metric["opsPerSecond"] > 0 for metric in result["metrics"])) + + def test_compare_csharp_median_result_summarizes_samples(self) -> None: + self.assertEqual(DEFAULT_SAMPLE_COUNT, 3) + self.assertEqual(DEFAULT_PARITY_THRESHOLD, 0.90) + samples = [ + { + "runtime": "python", + "records": 3, + "metrics": [ + {"name": "cache_get", "operations": 3, "elapsedMs": 30.0, "opsPerSecond": 100.0}, + {"name": "cache_upsert", "operations": 3, "elapsedMs": 60.0, "opsPerSecond": 50.0}, + ], + }, + { + "runtime": "python", + "records": 3, + "metrics": [ + {"name": "cache_get", "operations": 3, "elapsedMs": 10.0, "opsPerSecond": 300.0}, + {"name": "cache_upsert", "operations": 3, "elapsedMs": 20.0, "opsPerSecond": 150.0}, + ], + }, + { + "runtime": "python", + "records": 3, + "metrics": [ + {"name": "cache_get", "operations": 3, "elapsedMs": 20.0, "opsPerSecond": 200.0}, + {"name": "cache_upsert", "operations": 3, "elapsedMs": 40.0, "opsPerSecond": 75.0}, + ], + }, + ] + + summarized = _median_result(samples) + + self.assertEqual(summarized["sampleCount"], 3) + self.assertEqual(summarized["metrics"][0]["name"], "cache_get") + self.assertEqual(summarized["metrics"][0]["elapsedMs"], 20.0) + self.assertEqual(summarized["metrics"][0]["opsPerSecond"], 200.0) + self.assertEqual(summarized["metrics"][1]["opsPerSecond"], 75.0) + + def test_compare_csharp_marks_threshold_status_per_metric(self) -> None: + python_result = { + "metrics": [ + {"name": "cache_get", "operations": 3, "elapsedMs": 2.0, "opsPerSecond": 50.0}, + {"name": "cache_upsert", "operations": 3, "elapsedMs": 1.0, "opsPerSecond": 95.0}, + ], + } + csharp_result = { + "metrics": [ + {"name": "cache_get", "operations": 3, "elapsedMs": 1.0, "opsPerSecond": 100.0}, + {"name": "cache_upsert", "operations": 3, "elapsedMs": 1.0, "opsPerSecond": 100.0}, + ], + } + + comparison = _compare_common_metrics(python_result, csharp_result, parity_threshold=0.90) + by_name = {item["name"]: item for item in comparison} + + self.assertFalse(by_name["cache_get"]["meetsParityThreshold"]) + self.assertTrue(by_name["cache_upsert"]["meetsParityThreshold"]) + self.assertEqual(_parity_status(comparison, "ok"), "below-threshold") + self.assertEqual(_parity_status([by_name["cache_upsert"]], "ok"), "meets-threshold") + self.assertEqual(_parity_status(comparison, "failed"), "unknown") + + def test_compare_csharp_marks_meets_threshold_when_all_common_metrics_pass(self) -> None: + comparison = _compare_common_metrics( + { + "metrics": [ + {"name": "cache_get", "operations": 3, "elapsedMs": 1.0, "opsPerSecond": 95.0}, + {"name": "cache_upsert", "operations": 3, "elapsedMs": 1.0, "opsPerSecond": 120.0}, + ], + }, + { + "metrics": [ + {"name": "cache_get", "operations": 3, "elapsedMs": 1.0, "opsPerSecond": 100.0}, + {"name": "cache_upsert", "operations": 3, "elapsedMs": 1.0, "opsPerSecond": 100.0}, + ], + }, + parity_threshold=0.90, + ) + + self.assertEqual(_parity_status(comparison, "ok"), "meets-threshold") + + def test_cultnet_security_options_match_cultlib_defaults_and_environment_rules(self) -> None: + client = CultNetClientSecurityOptions.development() + server = CultNetServerSecurityOptions.development() + + self.assertEqual(client.connection_key, "gamecult-dev-connection-key") + self.assertEqual(server.connection_key, "gamecult-dev-connection-key") + self.assertTrue(server.is_development) + self.assertEqual(server.to_client_options().connection_key, client.connection_key) + self.assertEqual(client.encryption_key(), hashlib.sha256(b"gamecult-dev-connection-key").digest()) + self.assertEqual(server.session_signing_key(), hashlib.sha256(b"gamecult-dev-session-signing-secret").digest()) + self.assertEqual( + CultNetServerSecurityOptions.from_environment({}, allow_development_defaults=True), + server, + ) + with self.assertRaisesRegex(ValueError, "not configured"): + CultNetServerSecurityOptions.from_environment({}) + with self.assertRaisesRegex(ValueError, "GAMECULT_SESSION_SIGNING_SECRET"): + CultNetServerSecurityOptions.from_environment({"GAMECULT_CONNECTION_KEY": "key"}) + configured = CultNetServerSecurityOptions.from_environment({ + "GAMECULT_CONNECTION_KEY": "prod-key", + "GAMECULT_SESSION_SIGNING_SECRET": "prod-secret", + }) + self.assertEqual(configured.connection_key, "prod-key") + self.assertFalse(configured.is_development) + + def test_cultnet_secret_helpers_validate_csharp_versioned_session_tokens(self) -> None: + security = CultNetServerSecurityOptions("connection-key", "session-secret") + user_id = uuid4() + expires = datetime(2035, 1, 2, 3, 4, 5, tzinfo=UTC) + + token = CultNetSecret.create_session_token(user_id, expires, security, session_version=7) + payload_b64, signature_b64 = token.split(".") + self.assertEqual( + CultNetSecret.from_base64url(payload_b64).decode("utf-8"), + f"{user_id.hex}|{int(expires.timestamp())}|7", + ) + self.assertEqual( + CultNetSecret.from_base64url(signature_b64), + hmac.new( + hashlib.sha256(b"session-secret").digest(), + CultNetSecret.from_base64url(payload_b64), + hashlib.sha256, + ).digest(), + ) + + validated = CultNetSecret.try_validate_session_token( + token, + security, + now_utc=datetime(2035, 1, 2, 3, 4, 4, tzinfo=UTC), + ) + self.assertIsNotNone(validated) + assert validated is not None + self.assertEqual(validated.user_id, user_id) + self.assertEqual(validated.expires_at_utc, expires) + self.assertEqual(validated.session_version, 7) + + tampered_payload = CultNetSecret.to_base64url(CultNetSecret.from_base64url(payload_b64) + b"tamper") + tampered = f"{tampered_payload}.{signature_b64}" + self.assertIsNone(CultNetSecret.try_validate_session_token(tampered, security)) + self.assertIsNone(CultNetSecret.try_validate_session_token(token, security, now_utc=expires)) + + def test_cultnet_secret_helpers_validate_legacy_two_field_session_tokens(self) -> None: + security = CultNetServerSecurityOptions.development() + user_id = uuid4() + expires_at_seconds = int(datetime(2036, 1, 1, tzinfo=UTC).timestamp()) + payload = f"{user_id.hex}|{expires_at_seconds}".encode("utf-8") + signature = hmac.new(security.session_signing_key(), payload, hashlib.sha256).digest() + token = f"{CultNetSecret.to_base64url(payload)}.{CultNetSecret.to_base64url(signature)}" + + validated = CultNetSecret.try_validate_session_token( + token, + security, + now_utc=datetime(2035, 12, 31, tzinfo=UTC), + ) + + self.assertIsNotNone(validated) + assert validated is not None + self.assertEqual(validated.user_id, user_id) + self.assertEqual(validated.session_version, 0) + + def test_cultnet_secret_encryption_helpers_are_optional_without_crypto_dependency(self) -> None: + nonce = b"123456789012" + security = CultNetServerSecurityOptions.development() + try: + encrypted = CultNetSecret.encrypt_string("hello", nonce, security.to_client_options()) + except ImportError as exc: + self.assertIn("cryptography", str(exc)) + return + self.assertEqual(CultNetSecret.decrypt_string(encrypted, nonce, security), "hello") + + def test_cultnet_schema_message_frame_round_trip(self) -> None: + message = hello( + runtime_id="python-test", + supported_schema_versions=["cultnet.hello.v0"], + transport_profiles=[ + { + "schemaVersion": "cultnet.transport_profile.v0", + "runtimeId": "python-test", + "transports": [ + { + "transportId": "test", + "protocol": "tcp_framed", + "channels": [{"channelId": "schema", "delivery": "reliable", "ordering": "ordered"}], + } + ], + } + ], + ) + parsed = parse_message(decode_frame(encode_frame(message.to_bytes()))) + self.assertEqual(parsed.schema_version, "cultnet.hello.v0") + self.assertEqual(parsed.body["runtimeId"], "python-test") + self.assertEqual(parsed.body["transportProfiles"][0]["transports"][0]["protocol"], "tcp_framed") + + def test_cultnet_tcp_framed_transport_carries_schema_payloads_with_stats(self) -> None: + payload = b"cultnet-payload" + output = io.BytesIO() + sender = TcpFramedTransportConnection( + output, + profile=create_tcp_framed_transport_profile("sender", transport_id="test-tcp"), + ) + sender.send("schema", payload) + self.assertEqual(sender.stats.frames_sent, 1) + self.assertEqual(sender.stats.bytes_sent, len(payload) + 4) + with self.assertRaisesRegex(ValueError, "only supports the schema channel"): + sender.send("unreliable", b"") + + receiver = TcpFramedTransportConnection( + io.BytesIO(output.getvalue()), + profile=create_tcp_framed_transport_profile("receiver", transport_id="test-tcp"), + ) + frame = receiver.receive() + self.assertEqual(frame.channel_id, "schema") + self.assertEqual(frame.payload, payload) + self.assertEqual(receiver.stats.frames_received, 1) + self.assertEqual(receiver.stats.bytes_received, len(payload) + 4) + self.assertEqual(receiver.profile["transports"][0]["protocol"], "tcp_framed") + + def test_cultnet_raw_client_uses_schema_transport_factory(self) -> None: + import msgpack # type: ignore + + sent_messages: list[dict[str, object]] = [] + test_case = self + + class FakeSchemaTransport: + profile = create_tcp_framed_transport_profile("fake-client") + + def __enter__(self) -> "FakeSchemaTransport": + return self + + def __exit__(self, exc_type: object, exc: object, traceback: object) -> None: + self.close() + + def send(self, channel_id: str, payload: bytes) -> None: + test_case.assertEqual(channel_id, "schema") + sent_messages.append(msgpack.unpackb(payload, raw=False)) + + def receive(self) -> object: + response = { + "schemaVersion": "cultnet.schema_catalog_response.v0", + "messageId": "transport-factory", + "schemas": [], + } + return type("Frame", (), {"channel_id": "schema", "payload": msgpack.packb(response, use_bin_type=True)})() + + def close(self) -> None: + pass + + client = CultNetRawClient( + "unused.example.test", + 1, + create_transport=FakeSchemaTransport, + ) + + response = client.fetch_schema_catalog(message_id="transport-factory") + + self.assertEqual(response["schemaVersion"], "cultnet.schema_catalog_response.v0") + self.assertEqual(sent_messages[0]["schemaVersion"], "cultnet.schema_catalog_request.v0") + self.assertEqual(sent_messages[0]["messageId"], "transport-factory") + + def test_cultnet_rudp_packet_codec_uses_deterministic_reliable_ordered_fixture(self) -> None: + encoded = encode_rudp_packet( + CultNetRudpPacket( + packet_type=CultNetRudpPacketType.DATA, + connection_id=0x01020304, + sequence=0x0000002A, + ack=0x00000029, + ack_mask=0x80000001, + channel_id="schema", + reliable=True, + ordered=True, + fragment_id=7, + fragment_index=1, + fragment_count=3, + payload=b"hello", + ) + ) + + self.assertEqual( + encoded.hex(), + "434e523000030b2a010203040000002a0000002980000001000700010003000000050600736368656d6168656c6c6f", + ) + + decoded = decode_rudp_packet(encoded) + self.assertEqual(decoded.packet_type, CultNetRudpPacketType.DATA) + self.assertEqual(decoded.connection_id, 0x01020304) + self.assertEqual(decoded.sequence, 0x0000002A) + self.assertEqual(decoded.ack, 0x00000029) + self.assertEqual(decoded.ack_mask, 0x80000001) + self.assertEqual(decoded.channel_id, "schema") + self.assertTrue(decoded.reliable) + self.assertTrue(decoded.ordered) + self.assertFalse(decoded.sequenced) + self.assertEqual(decoded.fragment_id, 7) + self.assertEqual(decoded.fragment_index, 1) + self.assertEqual(decoded.fragment_count, 3) + self.assertEqual(decoded.payload, b"hello") + + def test_cultnet_rudp_transport_profile_advertises_state_and_realtime_channels(self) -> None: + profile = create_rudp_transport_profile( + "python-rudp", + transport_id="public-rudp", + host="127.0.0.1", + port=7777, + max_payload_bytes=1200, + max_fragment_bytes=1000, + ) + + self.assertEqual(profile["transports"][0]["protocol"], "rudp") + self.assertEqual(profile["transports"][0]["reconnectPolicy"]["schemaVersion"], "cultnet.reconnect_policy.v0") + self.assertEqual(profile["transports"][0]["reconnectPolicy"]["baseDelayMs"], 1_000) + self.assertEqual( + [ + (channel["channelId"], channel["delivery"], channel["ordering"]) + for channel in profile["transports"][0]["channels"] + ], + [ + ("schema", "reliable", "ordered"), + ("latest", "unreliable", "sequenced"), + ("realtime", "unreliable", "unordered"), + ], + ) + + def test_cultnet_reconnect_policy_exposes_portable_delay_contract(self) -> None: + policy = create_reconnect_policy(policy_id="rudp-default", max_attempts=8) + + self.assertEqual(policy.schema_version, "cultnet.reconnect_policy.v0") + self.assertEqual(policy.policy_id, "rudp-default") + self.assertEqual(policy.max_attempts, 8) + self.assertEqual(policy.to_wire()["policyId"], "rudp-default") + self.assertEqual(policy.to_wire()["maxAttempts"], 8) + self.assertEqual(compute_reconnect_delay_ms(policy, 1), 1_000) + self.assertEqual(compute_reconnect_delay_ms(policy, 3, 17), 4_017) + self.assertEqual(compute_reconnect_delay_ms(policy, 9, 999), 30_250) + self.assertEqual(compute_reconnect_delay_ms(policy, 0, -5), 1_000) + + def test_cultnet_reconnect_controller_schedules_attempts_and_reset(self) -> None: + controller = CultNetReconnectController(create_reconnect_policy(max_attempts=2)) + + first = controller.record_failure(10_000) + self.assertEqual(first.attempt, 1) + self.assertTrue(first.should_retry) + self.assertEqual(first.delay_ms, 1_000) + self.assertEqual(first.next_attempt_at_ms, 11_000) + self.assertFalse(first.exhausted) + self.assertFalse(controller.can_attempt(10_999)) + self.assertTrue(controller.can_attempt(11_000)) + + second = controller.record_failure(11_000, 17) + self.assertEqual(second.attempt, 2) + self.assertEqual(second.delay_ms, 2_017) + self.assertEqual(second.next_attempt_at_ms, 13_017) + self.assertTrue(second.should_retry) + + exhausted = controller.record_failure(13_017) + self.assertEqual(exhausted.attempt, 2) + self.assertFalse(exhausted.should_retry) + self.assertEqual(exhausted.delay_ms, 0) + self.assertIsNone(exhausted.next_attempt_at_ms) + self.assertTrue(exhausted.exhausted) + self.assertFalse(controller.can_attempt(99_000)) + + controller.reset() + self.assertEqual(controller.attempt, 0) + self.assertIsNone(controller.next_attempt_at_ms) + self.assertFalse(controller.exhausted) + self.assertTrue(controller.can_attempt(99_000)) + + def test_cultnet_rudp_reconnect_loop_consumes_shared_controller(self) -> None: + class FakeRudpReconnectTransport: + def __init__(self) -> None: + self.connect_calls = 0 + self.close_calls = 0 + self.last_payload: bytes | None = None + + def connect(self, payload: bytes = b"") -> None: + self.connect_calls += 1 + self.last_payload = bytes(payload) + + def close(self) -> None: + self.close_calls += 1 + + now_ms = 10_000 + captured_callback: list[Callable[[], None]] = [] + transports: list[FakeRudpReconnectTransport] = [] + + def create_transport() -> FakeRudpReconnectTransport: + transport = FakeRudpReconnectTransport() + transports.append(transport) + return transport + + def scheduler(delay_ms: int, callback: Callable[[], None]) -> Callable[[], None]: + self.assertEqual(delay_ms, 1_017) + captured_callback[:] = [callback] + + def cancel() -> None: + captured_callback.clear() + + return cancel + + loop = CultNetRudpReconnectLoop( + create_transport, + reconnect_policy=create_reconnect_policy(max_attempts=2), + connect_payload=b"join", + now_ms=lambda: now_ms, + jitter_ms=lambda: 17, + scheduler=scheduler, + ) + + first = loop.start() + self.assertEqual(first.connect_calls, 1) + self.assertEqual(first.last_payload, b"join") + self.assertIs(loop.transport, first) + + decision = loop.handle_closed() + self.assertIsNotNone(decision) + self.assertEqual(decision.attempt, 1) + self.assertTrue(decision.should_retry) + self.assertEqual(decision.delay_ms, 1_017) + self.assertEqual(decision.next_attempt_at_ms, 11_017) + self.assertEqual(loop.reconnect_controller.attempt, 1) + self.assertEqual(loop.reconnect_controller.next_attempt_at_ms, 11_017) + self.assertEqual(len(captured_callback), 1) + + now_ms = 11_017 + captured_callback[0]() + self.assertEqual(len(transports), 2) + self.assertEqual(transports[1].connect_calls, 1) + self.assertIs(loop.transport, transports[1]) + + loop.mark_connected() + self.assertEqual(loop.reconnect_controller.attempt, 0) + + loop.stop() + self.assertEqual(transports[1].close_calls, 1) + self.assertIsNone(loop.transport) + + def test_cultnet_rudp_session_handshake_acks_reliable_connect_and_accept_packets(self) -> None: + client = CultNetRudpSession( + CultNetRudpSessionOptions(connection_id=0x0A0B0C0D, initial_sequence=1, resend_delay_ms=50) + ) + server = CultNetRudpSession( + CultNetRudpSessionOptions(connection_id=0x0A0B0C0D, initial_sequence=100, resend_delay_ms=50) + ) + + connect = client.create_connect(0, b"join") + self.assertEqual(connect.packet_type, CultNetRudpPacketType.CONNECT) + self.assertEqual(connect.sequence, 1) + self.assertEqual(client.pending_reliable_sequences, (1,)) + + accept = server.accept_connect(connect, 10, b"ok") + self.assertEqual(accept.packet_type, CultNetRudpPacketType.ACCEPT) + self.assertEqual(accept.ack, 1) + self.assertTrue(server.connected) + self.assertEqual(server.pending_reliable_sequences, (100,)) + + client.receive(accept, 20) + self.assertTrue(client.connected) + self.assertEqual(client.pending_reliable_sequences, ()) + + ack = client.create_ack() + self.assertEqual(ack.ack, 100) + server.receive(ack, 30) + self.assertEqual(server.pending_reliable_sequences, ()) + + def test_cultnet_rudp_session_computes_ack_masks_and_clears_pending_reliable_packets(self) -> None: + sender = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=7, initial_sequence=10, resend_delay_ms=100)) + receiver = CultNetRudpSession( + CultNetRudpSessionOptions(connection_id=7, initial_sequence=200, resend_delay_ms=100) + ) + sender.receive( + CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 7, 1, 0, 0, "control") + ) + receiver.receive( + CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 7, 2, 0, 0, "control") + ) + + first = sender.send( + "schema", + b"first", + CultNetRudpSendOptions(reliable=True, ordered=True, now_ms=0), + ) + second = sender.send( + "schema", + b"second", + CultNetRudpSendOptions(reliable=True, ordered=True, now_ms=0), + ) + third = sender.send( + "schema", + b"third", + CultNetRudpSendOptions(reliable=True, ordered=True, now_ms=0), + ) + self.assertEqual(sender.pending_reliable_sequences, (10, 11, 12)) + + receiver.receive(first) + receiver.receive(third) + ack_with_gap = receiver.create_ack() + self.assertEqual(ack_with_gap.ack, 12) + self.assertEqual(ack_with_gap.ack_mask, 0b10 | (1 << 9)) + sender.receive(ack_with_gap) + self.assertEqual(sender.pending_reliable_sequences, (11,)) + + receiver.receive(second) + full_ack = receiver.create_ack() + self.assertEqual(full_ack.ack, 12) + self.assertEqual(full_ack.ack_mask, 0b11 | (1 << 9)) + sender.receive(full_ack) + self.assertEqual(sender.pending_reliable_sequences, ()) + + def test_cultnet_rudp_session_schedules_reliable_resends_until_acked(self) -> None: + session = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=99, initial_sequence=1, resend_delay_ms=100)) + session.receive( + CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 99, 50, 0, 0, "control") + ) + sent = session.send( + "schema", + b"payload", + CultNetRudpSendOptions(reliable=True, ordered=True, now_ms=10), + ) + + self.assertEqual(session.due_resends(90), ()) + self.assertEqual(tuple(packet.sequence for packet in session.due_resends(110)), (sent.sequence,)) + self.assertEqual(session.due_resends(150), ()) + + session.receive( + CultNetRudpPacket(CultNetRudpPacketType.ACK, 99, 51, sent.sequence, 0, "control") + ) + self.assertEqual(session.due_resends(250), ()) + + def test_cultnet_rudp_session_pings_and_detects_receive_timeout(self) -> None: + client = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=101, initial_sequence=1)) + server = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=101, initial_sequence=100)) + connect = client.create_connect(0, b"join") + accept = server.accept_connect(connect, 10) + client.receive(accept, 20) + + ping = client.create_ping(b"pulse") + ping_result = server.receive(ping, 30) + self.assertIsNotNone(ping_result.reply) + self.assertEqual(ping_result.reply.packet_type, CultNetRudpPacketType.PONG) + self.assertEqual(ping_result.reply.payload, b"pulse") + + pong_result = client.receive(ping_result.reply, 40) + self.assertTrue(pong_result.pong) + self.assertEqual(pong_result.pong_payload, b"pulse") + self.assertFalse(client.check_timeout(90, 50)) + self.assertTrue(client.check_timeout(91, 50)) + self.assertFalse(client.connected) + + def test_cultnet_rudp_session_bounds_pending_reliable_packets_before_enqueue(self) -> None: + session = CultNetRudpSession( + CultNetRudpSessionOptions(connection_id=102, initial_sequence=1, max_pending_reliable_packets=2) + ) + session.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 102, 50, 0, 0, "control")) + session.send("schema", b"first", CultNetRudpSendOptions(reliable=True, ordered=True)) + session.send("schema", b"second", CultNetRudpSendOptions(reliable=True, ordered=True)) + with self.assertRaisesRegex(ValueError, "reliable send queue is full"): + session.send("schema", b"third", CultNetRudpSendOptions(reliable=True, ordered=True)) + self.assertEqual(session.pending_reliable_sequences, (1, 2)) + + fragmented = CultNetRudpSession( + CultNetRudpSessionOptions(connection_id=103, initial_sequence=1, max_pending_reliable_packets=3) + ) + fragmented.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 103, 50, 0, 0, "control")) + with self.assertRaisesRegex(ValueError, "reliable send queue is full"): + fragmented.send_many( + "schema", + b"fragment-me", + CultNetRudpSendOptions(reliable=True, ordered=True), + max_fragment_bytes=3, + ) + self.assertEqual(fragmented.pending_reliable_sequences, ()) + + def test_cultnet_rudp_session_suppresses_duplicates_and_delivers_reliable_ordered_payloads(self) -> None: + sender = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=123, initial_sequence=1)) + receiver = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=123, initial_sequence=100)) + sender.receive( + CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 123, 90, 0, 0, "control") + ) + receiver.receive( + CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 123, 91, 0, 0, "control") + ) + + first = sender.send("schema", b"first", CultNetRudpSendOptions(reliable=True, ordered=True)) + second = sender.send("schema", b"second", CultNetRudpSendOptions(reliable=True, ordered=True)) + third = sender.send("schema", b"third", CultNetRudpSendOptions(reliable=True, ordered=True)) + + self.assertEqual([frame.payload.decode("utf-8") for frame in receiver.receive(first).delivered], ["first"]) + self.assertEqual(receiver.receive(third).delivered, ()) + self.assertEqual(receiver.receive(first).delivered, ()) + self.assertEqual( + [frame.payload.decode("utf-8") for frame in receiver.receive(second).delivered], + ["second", "third"], + ) + + def test_cultnet_rudp_lossy_packets_cannot_create_reliable_ordered_gaps(self) -> None: + sender = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=198, initial_sequence=1)) + receiver = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=198, initial_sequence=100)) + sender.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 198, 90, 0, 0, "control")) + receiver.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 198, 91, 0, 0, "control")) + + realtime = sender.send("realtime", b"discarded realtime", CultNetRudpSendOptions()) + latest = sender.send("latest", b"discarded latest state", CultNetRudpSendOptions(sequenced=True)) + schema = sender.send("schema", b"committed response", CultNetRudpSendOptions(reliable=True, ordered=True)) + + self.assertEqual(realtime.sequence, 0) + self.assertEqual(latest.sequence, 1) + self.assertEqual( + [frame.payload.decode("utf-8") for frame in receiver.receive(schema).delivered], + ["committed response"], + ) + + def test_cultnet_rudp_unreliable_sequenced_delivery_is_scoped_to_its_channel(self) -> None: + sender = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=197, initial_sequence=50)) + receiver = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=197, initial_sequence=100)) + sender.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 197, 90, 0, 0, "control")) + receiver.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 197, 91, 0, 0, "control")) + + older = sender.send("latest", b"older", CultNetRudpSendOptions(sequenced=True)) + newer = sender.send("latest", b"newer", CultNetRudpSendOptions(sequenced=True)) + + self.assertEqual(older.sequence, 1) + self.assertEqual(newer.sequence, 2) + self.assertEqual( + [frame.payload.decode("utf-8") for frame in receiver.receive(newer).delivered], + ["newer"], + ) + self.assertEqual(receiver.receive(older).delivered, ()) + + def test_cultnet_rudp_rejects_unreliable_ordered_delivery(self) -> None: + session = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=196, initial_sequence=1)) + session.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 196, 50, 0, 0, "control")) + + with self.assertRaises(ValueError) as raised: + session.send( + "schema", + b"cannot order what will not retransmit", + CultNetRudpSendOptions(ordered=True), + ) + self.assertIn("ordered delivery requires reliability", str(raised.exception)) + + def test_cultnet_rudp_session_skips_control_packets_while_ordering_schema_payloads(self) -> None: + sender = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=124, initial_sequence=1)) + receiver = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=124, initial_sequence=100)) + sender.receive( + CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 124, 90, 0, 0, "control") + ) + receiver.receive( + CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 124, 91, 0, 0, "control") + ) + + first = sender.send("schema", b"first", CultNetRudpSendOptions(reliable=True, ordered=True)) + control = sender.create_ack() + second = sender.send("schema", b"second", CultNetRudpSendOptions(reliable=True, ordered=True)) + + self.assertEqual([frame.payload.decode("utf-8") for frame in receiver.receive(first).delivered], ["first"]) + self.assertEqual(receiver.receive(control).delivered, ()) + self.assertEqual([frame.payload.decode("utf-8") for frame in receiver.receive(second).delivered], ["second"]) + + def test_cultnet_rudp_session_fragments_and_reassembles_reliable_ordered_payloads(self) -> None: + sender = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=456, initial_sequence=1)) + receiver = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=456, initial_sequence=100)) + sender.receive( + CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 456, 90, 0, 0, "control") + ) + receiver.receive( + CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 456, 91, 0, 0, "control") + ) + + packets = sender.send_many( + "schema", + b"fragment-me-please", + CultNetRudpSendOptions(reliable=True, ordered=True, now_ms=10), + max_fragment_bytes=5, + ) + self.assertEqual(len(packets), 4) + self.assertEqual(tuple(packet.fragment_count for packet in packets), (4, 4, 4, 4)) + self.assertEqual(tuple(packet.fragment_index for packet in packets), (0, 1, 2, 3)) + self.assertTrue(all(packet.fragment_id == packets[0].fragment_id for packet in packets)) + + self.assertEqual(receiver.receive(packets[0]).delivered, ()) + self.assertEqual(receiver.receive(packets[1]).delivered, ()) + self.assertEqual(receiver.receive(packets[2]).delivered, ()) + delivered = receiver.receive(packets[3]).delivered + self.assertEqual(len(delivered), 1) + self.assertEqual(delivered[0].payload, b"fragment-me-please") + self.assertEqual(delivered[0].sequence, packets[0].sequence) + + def test_cultnet_rudp_session_advances_large_fragment_sets_through_bounded_window(self) -> None: + connection_id = 457 + sender = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=connection_id, initial_sequence=1)) + receiver = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=connection_id, initial_sequence=100)) + sender.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, connection_id, 0, 0, 0, "control")) + receiver.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, connection_id, 0, 0, 0, "control")) + + fragment_count = CultNetRudpSession.RELIABLE_SEND_WINDOW_PACKETS + 17 + payload = bytes(index % 251 for index in range(fragment_count * 8)) + wire = list(sender.send_many( + "schema", + payload, + CultNetRudpSendOptions(reliable=True, ordered=True, now_ms=1), + max_fragment_bytes=8, + )) + self.assertEqual(len(wire), CultNetRudpSession.RELIABLE_SEND_WINDOW_PACKETS) + oldest_sequence = wire[0].sequence + self.assertEqual(len(sender.pending_reliable_sequences), len(wire)) + self.assertEqual(sender.queued_reliable_packet_count, 17) + + delivered = [] + while wire: + admitted = len(wire) + for _ in range(admitted): + packet = wire.pop(0) + delivered.extend(receiver.receive(packet, 2).delivered) + acknowledged = sender.receive(receiver.create_ack(), 3) + wire.extend(acknowledged.ready_to_send) + + self.assertEqual(sender.outstanding_reliable_packet_count, 0) + self.assertEqual(len(delivered), 1) + self.assertEqual(delivered[0].payload, payload) + old_ack = receiver.create_ack_for_received(oldest_sequence) + self.assertEqual(old_ack.ack, oldest_sequence) + self.assertEqual(old_ack.ack_mask, 0) + + def test_cultnet_rudp_socket_transport_handshakes_and_carries_reliable_ordered_schema_frames(self) -> None: + server_socket = bind_udp_socket() + client_socket = bind_udp_socket() + connection_id = 0x10203040 + server = CultNetRudpSocketTransportConnection( + CultNetRudpSocketTransportOptions( + runtime_id="python-rudp-server", + socket=server_socket, + mode=CultNetRudpSocketMode.SERVER, + connection_id=connection_id, + initial_sequence=100, + resend_delay_ms=25, + ) + ) + client = CultNetRudpSocketTransportConnection( + CultNetRudpSocketTransportOptions( + runtime_id="python-rudp-client", + socket=client_socket, + mode=CultNetRudpSocketMode.CLIENT, + remote_addr=server_socket.getsockname(), + connection_id=connection_id, + initial_sequence=1, + resend_delay_ms=25, + ) + ) + + try: + client.connect(b"join") + pump_rudp_handshake(client, server) + self.assertTrue(client.connected) + self.assertTrue(server.connected) + + client.send("schema", b"client-state") + server_frame = receive_rudp_frame(server) + self.assertEqual(server_frame.channel_id, "schema") + self.assertEqual(server_frame.payload, b"client-state") + + server.send("schema", b"server-state") + client_frame = receive_rudp_frame(client) + self.assertEqual(client_frame.channel_id, "schema") + self.assertEqual(client_frame.payload, b"server-state") + self.assertEqual(server.profile["transports"][0]["protocol"], "rudp") + self.assertEqual(client.stats.frames_sent, 1) + self.assertEqual(server.stats.frames_received, 1) + finally: + client.close() + server.close() + + def test_cultnet_rudp_socket_transport_carries_fragmented_reliable_ordered_schema_frames(self) -> None: + server_socket = bind_udp_socket() + client_socket = bind_udp_socket() + connection_id = 0x10203041 + server = CultNetRudpSocketTransportConnection( + CultNetRudpSocketTransportOptions( + runtime_id="python-rudp-fragment-server", + socket=server_socket, + mode=CultNetRudpSocketMode.SERVER, + connection_id=connection_id, + initial_sequence=100, + resend_delay_ms=25, + max_fragment_bytes=8, + ) + ) + client = CultNetRudpSocketTransportConnection( + CultNetRudpSocketTransportOptions( + runtime_id="python-rudp-fragment-client", + socket=client_socket, + mode=CultNetRudpSocketMode.CLIENT, + remote_addr=server_socket.getsockname(), + connection_id=connection_id, + initial_sequence=1, + resend_delay_ms=25, + max_fragment_bytes=8, + ) + ) + + try: + payload = b"this-schema-frame-is-larger-than-one-rudp-fragment" + client.connect(b"join") + pump_rudp_handshake(client, server) + client.send("schema", payload) + server_frame = receive_rudp_frame(server) + self.assertEqual(server_frame.channel_id, "schema") + self.assertEqual(server_frame.payload, payload) + self.assertEqual(client.stats.frames_sent, 1) + self.assertEqual(server.stats.frames_received, 1) + finally: + client.close() + server.close() + + def test_cultnet_database_subscription_helpers_match_schema_v0_shape(self) -> None: + subscribe = database_subscribe( + message_id="sub-message", + subscription_id="sub-1", + schema_ids=["schema-a"], + record_keys=["record-a"], + include_snapshot=False, + ).to_wire() + self.assertEqual(subscribe["schemaVersion"], "cultnet.database_subscribe.v0") + self.assertEqual(subscribe["messageId"], "sub-message") + self.assertEqual(subscribe["subscriptionId"], "sub-1") + self.assertEqual(subscribe["schemaIds"], ["schema-a"]) + self.assertEqual(subscribe["recordKeys"], ["record-a"]) + self.assertFalse(subscribe["includeSnapshot"]) + + unsubscribe = database_unsubscribe(message_id="unsub-message", subscription_id="sub-1").to_wire() + self.assertEqual(unsubscribe["schemaVersion"], "cultnet.database_unsubscribe.v0") + self.assertEqual(unsubscribe["messageId"], "unsub-message") + self.assertEqual(unsubscribe["subscriptionId"], "sub-1") + + def test_cultnet_database_change_parses_put_and_delete_shapes(self) -> None: + put_change = CultNetDatabaseChange.from_wire({ + "schemaVersion": "cultnet.database_change_raw.v0", + "messageId": "change-put", + "subscriptionId": "sub-1", + "changeKind": "added", + "document": { + "schemaId": "schema-note", + "recordKey": "note:1", + "payload": b"payload", + }, + }) + self.assertEqual(put_change.schema_id, "schema-note") + self.assertEqual(put_change.record_key, "note:1") + self.assertIsInstance(put_change.raw_document, CultNetRawDocumentRecord) + self.assertEqual(put_change.raw_document.payload, b"payload") + self.assertEqual(put_change.to_wire()["document"]["recordKey"], "note:1") + + delete_change = CultNetDatabaseChange.from_wire({ + "schemaVersion": "cultnet.database_change_raw.v0", + "messageId": "change-delete", + "subscriptionId": "sub-1", + "changeKind": "removed", + "schemaId": "schema-note", + "recordKey": "note:1", + }) + self.assertIsNone(delete_change.document) + self.assertIsNone(delete_change.raw_document) + self.assertEqual(delete_change.schema_id, "schema-note") + self.assertEqual(delete_change.to_wire()["recordKey"], "note:1") + + def test_cultnet_raw_put_helper_carries_message_id(self) -> None: + put = document_put_raw( + message_id="put-1", + key="record-a", + schema_id="schema-a", + stored_at="2026-06-13T00:00:00Z", + payload=b"payload", + source_runtime_id="python-test", + shard_id="interop", + shard_epoch=1, + ).to_wire() + self.assertEqual(put["schemaVersion"], "cultnet.document_put_raw.v0") + self.assertEqual(put["messageId"], "put-1") + self.assertEqual(put["document"]["recordKey"], "record-a") + self.assertEqual(put["document"]["sourceRuntimeId"], "python-test") + self.assertEqual(put["shardId"], "interop") + self.assertEqual(put["shardEpoch"], 1) + + def test_cultnet_catalog_and_snapshot_helpers_accept_filters(self) -> None: + catalog = schema_catalog_request( + message_id="catalog-1", + include_schema_json=True, + schema_ids=["schema-a"], + kinds=["wire_message"], + ).to_wire() + self.assertEqual(catalog["schemaVersion"], "cultnet.schema_catalog_request.v0") + self.assertEqual(catalog["messageId"], "catalog-1") + self.assertTrue(catalog["includeSchemaJson"]) + self.assertEqual(catalog["schemaIds"], ["schema-a"]) + self.assertEqual(catalog["kinds"], ["wire_message"]) + + snapshot = snapshot_request( + message_id="snapshot-1", + schema_ids=["schema-a"], + record_keys=["record-a"], + shard_id="interop", + shard_epoch=1, + ).to_wire() + self.assertEqual(snapshot["schemaVersion"], "cultnet.snapshot_request.v0") + self.assertEqual(snapshot["messageId"], "snapshot-1") + self.assertEqual(snapshot["schemaIds"], ["schema-a"]) + self.assertEqual(snapshot["recordKeys"], ["record-a"]) + self.assertEqual(snapshot["shardId"], "interop") + self.assertEqual(snapshot["shardEpoch"], 1) + + def test_cultnet_raw_snapshot_response_filters_and_roundtrips_records(self) -> None: + response = CultNetRawSnapshotResponse.from_wire({ + "schemaVersion": "cultnet.snapshot_response_raw.v0", + "messageId": "snapshot-1", + "shardId": "notes", + "shardEpoch": 3, + "shardLogSequence": 8, + "documents": [ + CultNetRawDocumentRecord( + schema_id="schema-note", + record_key="note:1", + stored_at="2026-06-14T00:00:00Z", + payload=b"note", + source_runtime_id="python-test", + tags=("snapshot",), + ).to_wire(), + { + "schemaId": "schema-fact", + "recordKey": "fact:1", + "payloadEncoding": "messagepack", + "payload": b"fact", + }, + ], + }) + self.assertEqual(response.shard_id, "notes") + self.assertEqual(response.shard_epoch, 3) + self.assertEqual(response.shard_log_sequence, 8) + self.assertEqual(response.documents[0].source_runtime_id, "python-test") + self.assertEqual(response.filter(schema_ids=["schema-note"])[0].record_key, "note:1") + self.assertEqual(response.filter(record_keys=["fact:1"])[0].schema_id, "schema-fact") + self.assertEqual(response.to_wire()["documents"][0]["tags"], ["snapshot"]) + + def test_cultnet_raw_client_fetches_schema_snapshot_and_shard_reads(self) -> None: + import msgpack # type: ignore + from cultnet_py import read_frame, write_frame + + received_versions: list[str] = [] + ready = threading.Event() + server_error: list[BaseException] = [] + port_holder: list[int] = [] + + def serve_requests() -> None: + try: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server: + server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + server.bind(("127.0.0.1", 0)) + port_holder.append(server.getsockname()[1]) + server.listen(4) + ready.set() + for _ in range(4): + connection, _ = server.accept() + with connection: + stream = connection.makefile("rwb") + request = msgpack.unpackb(read_frame(stream), raw=False) + received_versions.append(request["schemaVersion"]) + if request["schemaVersion"] == "cultnet.schema_catalog_request.v0": + self.assertEqual(request["kinds"], ["wire_message"]) + response = {"schemaVersion": "cultnet.schema_catalog_response.v0", "messageId": request["messageId"], "schemas": []} + elif request["schemaVersion"] == "cultnet.snapshot_request.v0": + self.assertEqual(request["shardId"], "interop") + response = {"schemaVersion": "cultnet.snapshot_response_raw.v0", "messageId": request["messageId"], "documents": []} + elif request["schemaVersion"] == "cultnet.shard_catalog_request.v0": + response = { + "schemaVersion": "cultnet.shard_catalog_response.v0", + "messageId": request["messageId"], + "shards": [{ + "shardId": "interop", + "ownerRuntimeId": "socket-test", + "epoch": 1, + "schemaIds": request["schemaIds"], + "keyPrefix": "record-", + "primaryEndpoints": ["cultnet://127.0.0.1:1"], + }], + } + elif request["schemaVersion"] == "cultnet.shard_log_request.v0": + self.assertEqual(request["afterSequence"], 7) + response = { + "schemaVersion": "cultnet.shard_log_response.v0", + "messageId": request["messageId"], + "shardId": request["shardId"], + "shardEpoch": request["shardEpoch"], + "entries": [], + "resyncRequired": False, + } + else: + raise AssertionError(f"unexpected request {request['schemaVersion']}") + write_frame(stream, msgpack.packb(response, use_bin_type=True)) + stream.flush() + except BaseException as error: + server_error.append(error) + ready.set() + + thread = threading.Thread(target=serve_requests, daemon=True) + thread.start() + self.assertTrue(ready.wait(2.0)) + self.assertFalse(server_error) + + client = CultNetRawClient("127.0.0.1", port_holder[0], timeout_seconds=2.0) + self.assertEqual(client.fetch_schema_catalog(kinds=["wire_message"])["schemaVersion"], "cultnet.schema_catalog_response.v0") + typed_snapshot = client.fetch_snapshot_response(shard_id="interop", shard_epoch=1) + self.assertEqual(typed_snapshot.shard_id, None) + self.assertEqual(typed_snapshot.documents, ()) + shard_catalog = CultNetShardCatalog() + synced_shards = client.sync_shard_catalog(shard_catalog, schema_ids=["schema-a"]) + self.assertEqual(synced_shards[0].shard_id, "interop") + self.assertEqual(shard_catalog.get("interop"), synced_shards[0]) + shard_log = client.fetch_shard_log_response(shard_id="interop", shard_epoch=1, after_sequence=7) + self.assertEqual(shard_log.shard_id, "interop") + self.assertFalse(shard_log.resync_required) + self.assertEqual(shard_log.last_sequence, 0) + + thread.join(2.0) + self.assertFalse(server_error) + self.assertEqual(received_versions, [ + "cultnet.schema_catalog_request.v0", + "cultnet.snapshot_request.v0", + "cultnet.shard_catalog_request.v0", + "cultnet.shard_log_request.v0", + ]) + + def test_cultnet_raw_client_raises_typed_peer_error_response(self) -> None: + import msgpack # type: ignore + from cultnet_py import read_frame, write_frame + + ready = threading.Event() + port_holder: list[int] = [] + + def serve_error() -> None: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server: + server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + server.bind(("127.0.0.1", 0)) + port_holder.append(server.getsockname()[1]) + server.listen(1) + ready.set() + connection, _ = server.accept() + with connection: + stream = connection.makefile("rwb") + read_frame(stream) + write_frame(stream, msgpack.packb({ + "schemaVersion": "cultnet.error.v0", + "messageId": "error-1", + "error": "Snapshot document limit exceeded", + }, use_bin_type=True)) + stream.flush() + + thread = threading.Thread(target=serve_error, daemon=True) + thread.start() + self.assertTrue(ready.wait(2.0)) + + client = CultNetRawClient("127.0.0.1", port_holder[0], timeout_seconds=2.0) + with self.assertRaisesRegex(CultNetPeerError, "Snapshot document limit exceeded") as raised: + client.fetch_snapshot() + + self.assertEqual(raised.exception.peer_error, "Snapshot document limit exceeded") + self.assertEqual(raised.exception.response["schemaVersion"], "cultnet.error.v0") + thread.join(2.0) + + def test_cultnet_database_subscription_reads_snapshot_and_change(self) -> None: + import msgpack # type: ignore + from cultnet_py import read_frame, write_frame + + document = define_database_entry_type( + "sub.item", + [ + ("name", 0), + ("category", 1), + ("value", 2, 0), + ], + cls=Item, + ) + schema_id = document.catalog_entry().schema_id + ready = threading.Event() + server_error: list[BaseException] = [] + port_holder: list[int] = [] + received_versions: list[str] = [] + + def serve_subscription() -> None: + try: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server: + server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + server.bind(("127.0.0.1", 0)) + port_holder.append(server.getsockname()[1]) + server.listen(1) + ready.set() + connection, _ = server.accept() + with connection: + stream = connection.makefile("rwb") + subscribe = msgpack.unpackb(read_frame(stream), raw=False) + received_versions.append(subscribe["schemaVersion"]) + self.assertEqual(subscribe["subscriptionId"], "sub-1") + snapshot = { + "schemaVersion": "cultnet.snapshot_response_raw.v0", + "messageId": subscribe["messageId"], + "documents": [], + } + write_frame(stream, msgpack.packb(snapshot, use_bin_type=True)) + stream.flush() + + put = msgpack.unpackb(read_frame(stream), raw=False) + received_versions.append(put["schemaVersion"]) + change = { + "schemaVersion": "cultnet.database_change_raw.v0", + "messageId": "change-1", + "subscriptionId": "sub-1", + "changeKind": "added", + "document": put["document"], + } + write_frame(stream, msgpack.packb(change, use_bin_type=True)) + stream.flush() + + unsubscribe = msgpack.unpackb(read_frame(stream), raw=False) + received_versions.append(unsubscribe["schemaVersion"]) + except BaseException as error: + server_error.append(error) + ready.set() + + thread = threading.Thread(target=serve_subscription, daemon=True) + thread.start() + self.assertTrue(ready.wait(2.0)) + self.assertFalse(server_error) + + client = CultNetRawClient("127.0.0.1", port_holder[0], timeout_seconds=2.0) + put = document_put_raw( + message_id="put-sub", + key="item:sub", + schema_id=schema_id, + stored_at="2026-06-14T00:00:00Z", + payload=document.encode_payload(Item("orb", "gear", 8)), + ) + with client.subscribe_database(subscription_id="sub-1", schema_ids=[schema_id]) as subscription: + snapshot = subscription.read_next_snapshot_response() + subscription.send(put) + change = subscription.read_next_change() + + thread.join(2.0) + self.assertFalse(server_error) + self.assertIsInstance(snapshot, CultNetRawSnapshotResponse) + self.assertEqual(snapshot.message_id, "cultnet-python-subscribe") + self.assertEqual(snapshot.to_wire()["schemaVersion"], "cultnet.snapshot_response_raw.v0") + self.assertEqual(change.change_kind, "added") + self.assertEqual(change.record_key, "item:sub") + self.assertIsInstance(change.raw_document, CultNetRawDocumentRecord) + self.assertEqual(change.raw_document.record_key, "item:sub") + self.assertEqual(received_versions, [ + "cultnet.database_subscribe.v0", + "cultnet.document_put_raw.v0", + "cultnet.database_unsubscribe.v0", + ]) + + def test_cultnet_database_subscription_raises_typed_peer_error(self) -> None: + import msgpack # type: ignore + from cultnet_py import read_frame, write_frame + + ready = threading.Event() + port_holder: list[int] = [] + + def serve_subscription_error() -> None: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server: + server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + server.bind(("127.0.0.1", 0)) + port_holder.append(server.getsockname()[1]) + server.listen(1) + ready.set() + connection, _ = server.accept() + with connection: + stream = connection.makefile("rwb") + read_frame(stream) + write_frame(stream, msgpack.packb({ + "schemaVersion": "cultnet.error.v0", + "messageId": "subscription-error", + "error": "subscription rejected", + }, use_bin_type=True)) + stream.flush() + + thread = threading.Thread(target=serve_subscription_error, daemon=True) + thread.start() + self.assertTrue(ready.wait(2.0)) + + client = CultNetRawClient("127.0.0.1", port_holder[0], timeout_seconds=2.0) + with client.subscribe_database(subscription_id="sub-error") as subscription: + with self.assertRaisesRegex(CultNetPeerError, "subscription rejected") as raised: + subscription.read_next() + self.assertEqual(raised.exception.response["messageId"], "subscription-error") + thread.join(2.0) + + def test_cultnet_replication_helpers_apply_raw_snapshot_and_shard_log(self) -> None: + document = define_database_entry_type( + "replica.item", + [ + ("name", 0), + ("category", 1), + ("value", 2, 0), + ], + cls=Item, + ) + cache = CultCache() + cache.register_document_type(document) + schema_id = document.catalog_entry().schema_id + + snapshot = { + "schemaVersion": "cultnet.snapshot_response_raw.v0", + "messageId": "snapshot-1", + "documents": [ + { + "schemaId": schema_id, + "recordKey": "item:1", + "storedAt": "2026-06-13T00:00:00Z", + "payloadEncoding": "messagepack", + "payload": document.encode_payload(Item("sword", "gear", 3)), + } + ], + } + applied_snapshot = apply_raw_snapshot(cache, [document], snapshot) + self.assertEqual(applied_snapshot[0].record_key, "item:1") + self.assertEqual(cache.get_required(document, "item:1").value, 3) + typed_snapshot = CultNetRawSnapshotResponse.from_wire(snapshot) + direct_applied = apply_raw_document_record(cache, schema_document_map([document]), typed_snapshot.documents[0]) + self.assertEqual(direct_applied.schema_id, schema_id) + self.assertEqual(direct_applied.record_key, "item:1") + typed_snapshot_applied = apply_raw_snapshot(cache, [document], typed_snapshot) + self.assertEqual(typed_snapshot_applied[0].record_key, "item:1") + + shard_log = { + "schemaVersion": "cultnet.shard_log_response.v0", + "messageId": "log-1", + "shardId": "interop", + "shardEpoch": 1, + "resyncRequired": False, + "entries": [ + { + "sequence": 0, + "changeKind": "updated", + "put": { + "schemaVersion": "cultnet.document_put_raw.v0", + "messageId": "put-unknown", + "document": { + "schemaId": "replica.unknown.v1", + "recordKey": "unknown:1", + "storedAt": "2026-06-13T00:00:01Z", + "payloadEncoding": "messagepack", + "payload": document.encode_payload(Item("ignored", "unknown", 0)), + }, + "shardId": "interop", + "shardEpoch": 1, + }, + }, + { + "sequence": 1, + "changeKind": "updated", + "put": { + "schemaVersion": "cultnet.document_put_raw.v0", + "messageId": "put-1", + "document": { + "schemaId": schema_id, + "recordKey": "item:1", + "storedAt": "2026-06-13T00:00:01Z", + "payloadEncoding": "messagepack", + "payload": document.encode_payload(Item("sword", "gear", 12)), + }, + "shardId": "interop", + "shardEpoch": 1, + }, + }, + { + "sequence": 2, + "changeKind": "removed", + "delete": { + "schemaVersion": "cultnet.document_delete.v0", + "messageId": "delete-1", + "schemaId": schema_id, + "recordKey": "item:1", + "shardId": "interop", + "shardEpoch": 1, + }, + }, + ], + } + applied_log = apply_shard_log_response(cache, [document], shard_log) + self.assertEqual([change.change_kind for change in applied_log], ["updated", "removed"]) + self.assertIsNone(cache.get(document, "item:1")) + + cache.put(document, "item:1", Item("sword", "gear", 3)) + typed_shard_log = CultNetShardLogResponse.from_wire({ + **shard_log, + "entries": shard_log["entries"][1:], + }) + typed_applied_log = apply_shard_log_response(cache, [document], typed_shard_log) + self.assertEqual([change.change_kind for change in typed_applied_log], ["updated", "removed"]) + self.assertIsNone(cache.get(document, "item:1")) + + def test_cultnet_replication_helpers_recover_schema_stamped_raw_records(self) -> None: + document = define_database_entry_type( + "replica.runtime-policy", + [ + ("schema_version", 0), + ("name", 1), + ("value", 2), + ], + schema_id="replica.runtime-policy.current", + schema_name="replica.runtime_policy", + schema_version="replica.runtime_policy.v1", + ) + cache = CultCache() + cache.register_document_type(document) + stale_schema_id = "sha256:stale-replica-runtime-policy" + payload = document.encode_payload({ + "schema_version": "replica.runtime_policy.v1", + "name": "policy", + "value": "still synced", + }) + record = { + "schemaId": stale_schema_id, + "recordKey": "policy:1", + "storedAt": "2026-06-25T00:00:00Z", + "payloadEncoding": "messagepack", + "payload": payload, + } + snapshot = { + "schemaVersion": "cultnet.snapshot_response_raw.v0", + "messageId": "snapshot-stale", + "documents": [record], + } + + applied_snapshot = apply_raw_snapshot(cache, [document], snapshot) + local_schema_id = document.catalog_entry().schema_id + self.assertEqual(applied_snapshot[0].schema_id, local_schema_id) + self.assertEqual(cache.get_required(document, "policy:1")["value"], "still synced") + self.assertEqual(cache.get_required_envelope(document, "policy:1").schema_id, local_schema_id) + direct_applied = apply_raw_document_record(cache, schema_document_map([document]), record) + self.assertEqual(direct_applied.schema_id, local_schema_id) + self.assertEqual(cache.get_required_envelope(document, "policy:1").schema_id, local_schema_id) + + shard_log = { + "schemaVersion": "cultnet.shard_log_response.v0", + "messageId": "log-stale", + "shardId": "interop", + "shardEpoch": 1, + "resyncRequired": False, + "entries": [ + { + "sequence": 0, + "changeKind": "updated", + "put": { + "schemaVersion": "cultnet.document_put_raw.v0", + "messageId": "put-stale", + "document": { + **record, + "payload": document.encode_payload({ + "schema_version": "replica.runtime_policy.v1", + "name": "policy", + "value": "updated through log", + }), + }, + "shardId": "interop", + "shardEpoch": 1, + }, + } + ], + } + + applied_log = apply_shard_log_response(cache, [document], shard_log) + self.assertEqual(applied_log[0].schema_id, local_schema_id) + self.assertEqual(cache.get_required(document, "policy:1")["value"], "updated through log") + self.assertEqual(cache.get_required_envelope(document, "policy:1").schema_id, local_schema_id) + + delete_log = { + "schemaVersion": "cultnet.shard_log_response.v0", + "messageId": "log-delete-alias", + "shardId": "interop", + "shardEpoch": 1, + "resyncRequired": False, + "entries": [ + { + "sequence": 1, + "changeKind": "removed", + "delete": { + "schemaVersion": "cultnet.document_delete.v0", + "messageId": "delete-version-alias", + "schemaId": "replica.runtime_policy.v1", + "recordKey": "policy:1", + "shardId": "interop", + "shardEpoch": 1, + }, + } + ], + } + applied_delete = apply_shard_log_response(cache, [document], delete_log) + self.assertEqual(applied_delete[0].schema_id, local_schema_id) + self.assertEqual(applied_delete[0].change_kind, "removed") + self.assertIsNone(cache.get(document, "policy:1")) + + def test_cultnet_document_delete_helper_matches_schema_v0_shape(self) -> None: + message = document_delete( + message_id="delete-1", + schema_id="schema-a", + record_key="record-a", + shard_id="interop", + shard_epoch=1, + ).to_wire() + self.assertEqual(message["schemaVersion"], "cultnet.document_delete.v0") + self.assertEqual(message["messageId"], "delete-1") + self.assertEqual(message["schemaId"], "schema-a") + self.assertEqual(message["recordKey"], "record-a") + self.assertEqual(message["shardId"], "interop") + self.assertEqual(message["shardEpoch"], 1) + + def test_cultnet_auth_session_helpers_match_schema_v0_shape(self) -> None: + self.assertEqual( + login(nonce="nonce", auth="encrypted-auth", password="encrypted-password").to_wire(), + { + "schemaVersion": "cultnet.login.v0", + "nonce": "nonce", + "auth": "encrypted-auth", + "password": "encrypted-password", + }, + ) + self.assertEqual( + register( + nonce="nonce", + email="encrypted-email", + password="encrypted-password", + name="encrypted-name", + ).to_wire(), + { + "schemaVersion": "cultnet.register.v0", + "nonce": "nonce", + "email": "encrypted-email", + "password": "encrypted-password", + "name": "encrypted-name", + }, + ) + self.assertEqual( + verify_session(nonce="nonce", session="encrypted-session").to_wire(), + { + "schemaVersion": "cultnet.verify.v0", + "nonce": "nonce", + "session": "encrypted-session", + }, + ) + self.assertEqual( + login_success(nonce="nonce", session="encrypted-session").to_wire(), + { + "schemaVersion": "cultnet.login_success.v0", + "nonce": "nonce", + "session": "encrypted-session", + }, + ) + + def test_cultnet_wire_catalog_describes_python_handled_messages(self) -> None: + descriptors = wire_message_schema_descriptors(include_schema_json=True) + by_version = {descriptor["schemaVersion"]: descriptor for descriptor in descriptors} + for schema_version in [ + "cultnet.error.v0", + "cultnet.login.v0", + "cultnet.register.v0", + "cultnet.verify.v0", + "cultnet.login_success.v0", + "cultnet.transport_profile.v0", + "cultnet.document_delete.v0", + "cultnet.database_change_raw.v0", + "cultnet.shard_log_response.v0", + "cultnet.simulation_consensus_candidate.v0", + "cultmesh.peer_exchange_response.v0", + ]: + self.assertIn(schema_version, by_version) + expected_kind = "shared_contract" if schema_version == "cultnet.transport_profile.v0" else "wire_message" + self.assertEqual(by_version[schema_version]["kind"], expected_kind) + self.assertIn("cultnet.schema.v0", by_version[schema_version]["wireContracts"]) + self.assertIn(schema_version, by_version[schema_version]["schemaJson"]) + self.assertEqual(len(by_version[schema_version]["contentHash"]), 64) + + delete_schema = json.loads(by_version["cultnet.document_delete.v0"]["schemaJson"]) + self.assertEqual( + delete_schema["required"], + ["schemaVersion", "messageId", "schemaId", "recordKey"], + ) + self.assertEqual(delete_schema["properties"]["recordKey"]["type"], "string") + + error_schema = json.loads(by_version["cultnet.error.v0"]["schemaJson"]) + self.assertEqual(error_schema["required"], ["schemaVersion", "error"]) + self.assertEqual(error_schema["properties"]["error"]["type"], "string") + self.assertIn("details", error_schema["properties"]) + + login_schema = json.loads(by_version["cultnet.login.v0"]["schemaJson"]) + self.assertEqual(login_schema["required"], ["schemaVersion", "nonce", "auth", "password"]) + self.assertEqual(login_schema["properties"]["auth"]["type"], "string") + + register_schema = json.loads(by_version["cultnet.register.v0"]["schemaJson"]) + self.assertEqual(register_schema["required"], ["schemaVersion", "nonce", "email", "password", "name"]) + self.assertEqual(register_schema["properties"]["email"]["type"], "string") + + verify_schema = json.loads(by_version["cultnet.verify.v0"]["schemaJson"]) + self.assertEqual(verify_schema["required"], ["schemaVersion", "nonce", "session"]) + self.assertEqual(verify_schema["properties"]["session"]["type"], "string") + + success_schema = json.loads(by_version["cultnet.login_success.v0"]["schemaJson"]) + self.assertEqual(success_schema["required"], ["schemaVersion", "nonce", "session"]) + + transport_profile_schema = json.loads(by_version["cultnet.transport_profile.v0"]["schemaJson"]) + self.assertEqual(transport_profile_schema["required"], ["schemaVersion", "runtimeId", "transports"]) + transport = transport_profile_schema["properties"]["transports"]["items"] + self.assertEqual(transport["properties"]["protocol"]["enum"], ["tcp_framed", "litenetlib", "websocket", "rudp"]) + self.assertEqual( + transport["properties"]["reconnectPolicy"]["properties"]["schemaVersion"]["const"], + "cultnet.reconnect_policy.v0", + ) + channel = transport["properties"]["channels"]["items"] + self.assertEqual(channel["properties"]["ordering"]["enum"], ["ordered", "unordered", "sequenced"]) + + change_schema = json.loads(by_version["cultnet.database_change_raw.v0"]["schemaJson"]) + self.assertEqual(change_schema["properties"]["changeKind"]["enum"], ["added", "updated", "removed"]) + self.assertIn("document", change_schema["properties"]) + self.assertIn("schemaId", change_schema["properties"]) + self.assertIn("recordKey", change_schema["properties"]) + + log_schema = json.loads(by_version["cultnet.shard_log_response.v0"]["schemaJson"]) + self.assertIn("entries", log_schema["required"]) + self.assertIn("resyncRequired", log_schema["required"]) + self.assertIn("compactedThrough", log_schema["properties"]) + + hello_schema = json.loads(by_version["cultnet.hello.v0"]["schemaJson"]) + mutation_contract = hello_schema["properties"]["supportedMutationContracts"]["items"] + self.assertEqual(mutation_contract["type"], "object") + self.assertIn("operations", mutation_contract["properties"]) + self.assertEqual( + hello_schema["properties"]["transportProfiles"]["items"]["$ref"], + "https://github.com/GameCult/cultnet-ts/contracts/cultnet.transport-profile.schema.json", + ) + + consensus_schema = json.loads(by_version["cultnet.simulation_consensus_candidate.v0"]["schemaJson"]) + for required_field in ["witnessCount", "supportWeight", "totalWeight", "hasQuorum", "confidence"]: + self.assertIn(required_field, consensus_schema["required"]) + + def test_cultnet_schema_catalog_applies_filters_and_responses(self) -> None: + catalog = wire_message_schema_catalog(include_schema_json=True) + descriptor = catalog.get("https://github.com/GameCult/cultnet-ts/contracts/cultnet.document-put-raw.schema.json") + self.assertIsNotNone(descriptor) + assert descriptor is not None + self.assertEqual(descriptor.kind, "wire_message") + self.assertEqual(descriptor.schema_version, "cultnet.document_put_raw.v0") + self.assertIsNotNone(descriptor.schema_json) + + filtered = catalog.list(kinds=["wire_message"], schema_ids=[descriptor.schema_id]) + self.assertEqual(filtered, [descriptor]) + + response = catalog.create_response( + message_id="catalog-response", + include_schema_json=False, + schema_ids=[descriptor.schema_id], + kinds=["wire_message"], + ) + self.assertEqual(response["schemaVersion"], "cultnet.schema_catalog_response.v0") + self.assertNotIn("schemaJson", response["schemas"][0]) + + remote = CultNetSchemaCatalog() + applied = remote.apply_response({ + "schemaVersion": "cultnet.schema_catalog_response.v0", + "messageId": "remote", + "schemas": [ + CultNetSchemaDescriptor( + schema_id="schema:custom", + kind="shared_contract", + schema_version="custom.v0", + wire_contracts=("cultnet.schema.v0",), + content_hash="hash", + schema_json="{}", + ).to_wire() + ], + }) + self.assertEqual(applied[0].schema_id, "schema:custom") + self.assertEqual(remote.get("schema:custom"), applied[0]) + + def test_cultnet_shard_helpers_match_schema_v0_shape(self) -> None: + catalog = shard_catalog_request( + message_id="catalog-1", + schema_ids=["schema-a"], + record_keys=["record-a"], + ).to_wire() + self.assertEqual(catalog["schemaVersion"], "cultnet.shard_catalog_request.v0") + self.assertEqual(catalog["messageId"], "catalog-1") + self.assertEqual(catalog["schemaIds"], ["schema-a"]) + self.assertEqual(catalog["recordKeys"], ["record-a"]) + + log = shard_log_request( + message_id="log-1", + shard_id="interop", + shard_epoch=7, + after_sequence=3, + limit=2, + ).to_wire() + self.assertEqual(log["schemaVersion"], "cultnet.shard_log_request.v0") + self.assertEqual(log["messageId"], "log-1") + self.assertEqual(log["shardId"], "interop") + self.assertEqual(log["shardEpoch"], 7) + self.assertEqual(log["afterSequence"], 3) + self.assertEqual(log["limit"], 2) + + def test_cultnet_shard_catalog_applies_filters_and_responses(self) -> None: + catalog = CultNetShardCatalog() + primary = catalog.upsert(CultNetShardDescriptor( + shard_id="notes", + owner_runtime_id="python-runtime", + epoch=2, + is_primary=True, + schema_ids=("schema-note.v1",), + key_prefix="note:", + primary_endpoints=("cultnet://127.0.0.1:3075",), + read_replica_endpoints=("cultnet://127.0.0.1:3075",), + region="local", + )) + catalog.upsert({ + "shardId": "facts", + "ownerRuntimeId": "python-runtime", + "epoch": 1, + "schemaIds": ["schema-fact"], + "keyPrefix": "fact:", + "primaryEndpoints": ["cultnet://127.0.0.1:3076"], + }) + + self.assertTrue(primary.serves(schema_id="schema-note.v1", record_key="note:1")) + self.assertTrue(primary.serves(schema_id="schema-note", record_key="note:1")) + self.assertFalse(primary.serves(schema_id="schema-note", record_key="fact:1")) + self.assertEqual(catalog.list(schema_ids=["schema-note.v1"]), [primary]) + self.assertEqual(catalog.list(schema_ids=["schema-note"]), [primary]) + self.assertEqual(catalog.list(record_keys=["note:1"]), [primary]) + + response = catalog.create_response( + message_id="shards", + schema_ids=["schema-note"], + record_keys=["note:1"], + ) + self.assertEqual(response["schemaVersion"], "cultnet.shard_catalog_response.v0") + self.assertEqual(response["shards"][0]["shardId"], "notes") + self.assertEqual(response["shards"][0]["ownerRuntimeId"], "python-runtime") + + remote = CultNetShardCatalog() + applied = remote.apply_response(response) + self.assertEqual(applied[0].shard_id, "notes") + self.assertEqual(remote.get("notes"), applied[0]) + + def test_cultnet_shard_log_response_tracks_cursor_and_resync_state(self) -> None: + response = CultNetShardLogResponse.from_wire({ + "schemaVersion": "cultnet.shard_log_response.v0", + "messageId": "log", + "shardId": "notes", + "shardEpoch": 2, + "entries": [ + CultNetShardLogEntry( + sequence=2, + change_kind="updated", + put={"schemaVersion": "cultnet.document_put_raw.v0", "messageId": "put", "document": {"schemaId": "schema-note", "recordKey": "note:1", "payload": b"p"}}, + committed_at="2026-06-14T00:00:00Z", + ).to_wire(), + {"sequence": 3, "changeKind": "removed", "delete": {"schemaId": "schema-note", "recordKey": "note:1"}}, + ], + "resyncRequired": False, + }) + self.assertEqual(response.last_sequence, 3) + self.assertFalse(response.resync_required) + self.assertEqual(response.entries[0].put["document"]["recordKey"], "note:1") + self.assertIsInstance(response.entries[0].raw_document, CultNetRawDocumentRecord) + self.assertEqual(response.entries[0].raw_document.record_key, "note:1") + self.assertEqual(response.entries[1].delete_schema_id, "schema-note") + self.assertEqual(response.entries[1].delete_record_key, "note:1") + self.assertEqual(response.to_wire()["entries"][1]["delete"]["recordKey"], "note:1") + self.assertIs(response.require_usable(), response) + + resync = CultNetShardLogResponse.from_wire({ + "schemaVersion": "cultnet.shard_log_response.v0", + "messageId": "log-resync", + "shardId": "notes", + "shardEpoch": 2, + "entries": [], + "resyncRequired": True, + "reason": "compacted", + "compactedThrough": 12, + }) + self.assertEqual(resync.last_sequence, 12) + with self.assertRaisesRegex(ValueError, "compacted"): + resync.require_usable() + + def test_cultnet_simulation_observation_helper_matches_schema_v0_shape(self) -> None: + claim_hash = compute_simulation_claim_hash("frame:42", "subject:player-1", "hit") + self.assertEqual(len(claim_hash), 64) + message = simulation_observation( + message_id="obs-1", + witness_runtime_id="python-test", + shard_id="interop", + shard_epoch=1, + frame=42, + subject_id="player-1", + claim_kind="hit", + claim_hash=claim_hash, + claim_summary="player-1 hit target-a", + observed_at="2026-06-13T00:00:02Z", + ).to_wire() + self.assertEqual(message["schemaVersion"], "cultnet.simulation_observation.v0") + self.assertEqual(message["messageId"], "obs-1") + self.assertEqual(message["observation"]["witnessRuntimeId"], "python-test") + self.assertEqual(message["observation"]["claimHash"], claim_hash) + self.assertEqual(message["observation"]["weight"], 1.0) + observation = CultNetSimulationObservation.from_wire(message) + self.assertEqual(observation.witness_runtime_id, "python-test") + self.assertEqual(observation.claim_summary, "player-1 hit target-a") + self.assertEqual(observation.to_message_wire(message_id="obs-2")["observation"], message["observation"]) + + def test_cultnet_witness_artifact_bundle_uses_csharp_slot_order(self) -> None: + import msgpack # type: ignore + + bundle = witness_artifact_bundle( + bundle_id="bundle-1", + witness_kind="interop-proof", + captured_at="2026-06-13T00:00:03Z", + subject={"documentType": "cultnet.interop-note", "subjectId": "note:python"}, + contracts=[{"role": "payload", "schemaId": "schema-a"}], + artifacts=[{"role": "log", "uri": "cultcache://bundle-1/log", "mediaType": "text/plain"}], + timing_witnesses=[{"stage": "roundtrip", "startedAt": "2026-06-13T00:00:03Z", "completedAt": "2026-06-13T00:00:04Z", "latencyMs": 1.0}], + provenance={"pipelineId": "interop", "runId": "run-1", "runtimeId": "python-test"}, + ) + payload = encode_witness_artifact_bundle_payload(bundle) + decoded = decode_witness_artifact_bundle_payload(payload) + typed = CultNetWitnessArtifactBundle.from_wire(bundle) + typed_payload = typed.to_payload() + typed_decoded = CultNetWitnessArtifactBundle.from_payload(typed_payload) + slots = msgpack.unpackb(payload, raw=False) + + self.assertEqual(payload, typed_payload) + self.assertEqual(slots[0], "bundle-1") + self.assertEqual(slots[1], "interop-proof") + self.assertEqual(slots[2], "2026-06-13T00:00:03Z") + self.assertEqual(slots[3]["subjectId"], "note:python") + self.assertEqual(slots[4][0]["schemaId"], "schema-a") + self.assertEqual(slots[5][0]["uri"], "cultcache://bundle-1/log") + self.assertEqual(slots[6][0]["latencyMs"], 1.0) + self.assertEqual(slots[7]["runtimeId"], "python-test") + self.assertEqual(decoded["bundleId"], "bundle-1") + self.assertEqual(decoded["witnessKind"], "interop-proof") + self.assertEqual(decoded["subject"]["subjectId"], "note:python") + self.assertEqual(decoded["contracts"][0]["schemaId"], "schema-a") + self.assertEqual(decoded["artifacts"][0]["mediaType"], "text/plain") + self.assertEqual(decoded["provenance"]["runtimeId"], "python-test") + self.assertEqual(typed.bundle_id, "bundle-1") + self.assertEqual(typed_decoded.to_wire(), bundle) + + def test_python_interop_peer_filters_shard_snapshot_by_logged_membership(self) -> None: + runtime_id = f"python-interop-test-{uuid4().hex}" + state = build_state( + runtime_id=runtime_id, + runtime_kind="python", + display_name="Python Interop Test", + agent_id="python-interop-test-agent", + schema_path=str(Path("packages/cultnet-ts/integration/contracts/cultnet.interop-note.schema.json")), + ) + binding = state.bindings["note"] + logged_value = { + "schemaVersion": "cultnet.interop_note.v0", + "documentId": "note:logged", + "authorRuntimeId": runtime_id, + "title": "Logged", + "body": "This record belongs to the shard log.", + "tags": ["interop", "logged"], + } + unlogged_value = { + **logged_value, + "documentId": "note:unlogged", + "title": "Unlogged", + "body": "This record is in cache but not in the shard log.", + } + state.cache.put(binding.document, "note:logged", logged_value) + state.cache.put(binding.document, "note:unlogged", unlogged_value) + logged_record = { + "schemaId": state.note_schema_id, + "recordKey": "note:logged", + "storedAt": "2026-06-14T00:00:00Z", + "payloadEncoding": "messagepack", + "payload": binding.document.encode_payload(logged_value), + } + append_shard_log_put( + state, + {"messageId": "logged-put"}, + logged_record, + ) + + response = raw_snapshot_response( + state, + { + "schemaVersion": "cultnet.snapshot_request.v0", + "messageId": "interop-shard-snapshot", + "schemaIds": [state.note_schema_id], + "shardId": state.shard_id, + }, + ) + + self.assertEqual(response["shardId"], state.shard_id) + self.assertEqual(response["shardLogSequence"], 1) + self.assertEqual([record["recordKey"] for record in response["documents"]], ["note:logged"]) + + def test_cultnet_simulation_consensus_dedupes_witnesses_and_requires_quorum(self) -> None: + from cultnet_py import CultNetSimulationConsensus + + consensus = CultNetSimulationConsensus( + CultNetSimulationConsensusOptions(minimum_witnesses=2, quorum_ratio=1.0) + ) + claim_hash = compute_simulation_claim_hash("hit", "alice", "bob", "frame:100") + observations = [ + { + "witnessRuntimeId": "watcher-1", + "shardId": "arena", + "shardEpoch": 4, + "frame": 100, + "subjectId": "bob", + "claimKind": "hit", + "claimHash": claim_hash, + "claimSummary": "alice shot bob first", + "weight": 1.0, + }, + { + "witnessRuntimeId": "watcher-1", + "shardId": "arena", + "shardEpoch": 4, + "frame": 100, + "subjectId": "bob", + "claimKind": "hit", + "claimHash": "stale-duplicate", + "weight": 0.5, + }, + { + "witnessRuntimeId": "watcher-2", + "shardId": "arena", + "shardEpoch": 4, + "frame": 100, + "subjectId": "bob", + "claimKind": "hit", + "claimHash": claim_hash, + "weight": 1.0, + }, + ] + + candidates = consensus.build_candidates(observations) + typed_candidates = consensus.build_candidate_objects([ + CultNetSimulationObservation.from_wire(observation) + for observation in observations + ]) + + self.assertEqual(len(candidates), 1) + self.assertEqual(candidates[0]["claimHash"], claim_hash) + self.assertEqual(candidates[0]["witnessCount"], 2) + self.assertEqual(candidates[0]["supportWeight"], 2.0) + self.assertTrue(candidates[0]["hasQuorum"]) + self.assertEqual(len(typed_candidates), 1) + self.assertIsInstance(typed_candidates[0], CultNetSimulationConsensusCandidate) + self.assertEqual(typed_candidates[0].claim_hash, claim_hash) + self.assertEqual(typed_candidates[0].to_wire(), candidates[0]) + self.assertEqual(CultNetSimulationConsensusCandidate.from_wire(candidates[0]), typed_candidates[0]) + + +class CultNetRudpFragmentBoundTests(unittest.TestCase): + def _pair(self) -> tuple[CultNetRudpSession, CultNetRudpSession]: + sender = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=311, initial_sequence=1)) + receiver = CultNetRudpSession(CultNetRudpSessionOptions(connection_id=311, initial_sequence=100)) + sender.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 311, 90, 0, 0, "control")) + receiver.receive(CultNetRudpPacket(CultNetRudpPacketType.ACCEPT, 311, 91, 0, 0, "control")) + return sender, receiver + + def test_stranded_fragment_sets_are_bounded_and_evicted_oldest_first(self) -> None: + sender, receiver = self._pair() + receiver._max_pending_fragment_sets = 4 + + # Eight payloads each lose their last fragment; the map must not grow past four. + stranded = [] + for fill in range(1, 9): + packets = sender.send_many("media", bytes([fill]) * 2500, max_fragment_bytes=1000) + self.assertEqual(len(packets), 3) + for packet in packets[:2]: + self.assertEqual(receiver.receive(packet).delivered, ()) + stranded.append(packets[2]) + self.assertEqual(len(receiver._fragment_buffers), 4) + self.assertEqual(receiver.fragment_sets_evicted, 4) + + # A complete payload still lands. + delivered = [] + for packet in sender.send_many("media", bytes([9]) * 2500, max_fragment_bytes=1000): + delivered.extend(receiver.receive(packet).delivered) + self.assertEqual([frame.payload for frame in delivered], [bytes([9]) * 2500]) + self.assertEqual(receiver.fragment_sets_evicted, 5) + + # Oldest-first: set 8 still pends and completes late; set 1 was evicted. + self.assertEqual(receiver.receive(stranded[7]).delivered[0].payload, bytes([8]) * 2500) + self.assertEqual(receiver.receive(stranded[0]).delivered, ()) + + +if __name__ == "__main__": + unittest.main() diff --git a/packages/cultcache-py/tools/GameCult.Caching.Benchmark/GameCult.Caching.Benchmark.csproj b/packages/cultnet-py/tools/GameCult.Caching.Benchmark/GameCult.Caching.Benchmark.csproj similarity index 100% rename from packages/cultcache-py/tools/GameCult.Caching.Benchmark/GameCult.Caching.Benchmark.csproj rename to packages/cultnet-py/tools/GameCult.Caching.Benchmark/GameCult.Caching.Benchmark.csproj diff --git a/packages/cultcache-py/tools/GameCult.Caching.Benchmark/Program.cs b/packages/cultnet-py/tools/GameCult.Caching.Benchmark/Program.cs similarity index 100% rename from packages/cultcache-py/tools/GameCult.Caching.Benchmark/Program.cs rename to packages/cultnet-py/tools/GameCult.Caching.Benchmark/Program.cs diff --git a/packages/cultnet-ts/test/interop/cultnet-interop.test.ts b/packages/cultnet-ts/test/interop/cultnet-interop.test.ts index 4353e132..00fff83d 100644 --- a/packages/cultnet-ts/test/interop/cultnet-interop.test.ts +++ b/packages/cultnet-ts/test/interop/cultnet-interop.test.ts @@ -24,7 +24,9 @@ const pythonCommand = process.env.PYTHON ?? resolvePythonCommand(); const cultNetTsRoot = resolve(__dirname, "../../.."); const cultLibRoot = findAncestor(cultNetTsRoot, "CultLib.sln") ?? resolve(cultNetTsRoot, "..", "CultLib"); const cultcachePyRoot = resolve(cultLibRoot, "packages", "cultcache-py"); -const cultcachePySrc = resolve(cultcachePyRoot, "src"); +const cultcachePySrc = ["cultcache-py", "cultnet-py", "cultmesh-py"] + .map((name) => resolve(cultLibRoot, "packages", name, "src")) + .join(delimiter); const cultmeshKotlinRoot = resolve(cultLibRoot, "packages", "cultmesh-kotlin"); const kotlinHome = process.env.KOTLIN_HOME ?? "C:\\Program Files\\Android\\Android Studio\\plugins\\Kotlin\\kotlinc"; const kotlinJavaHome = process.env.KOTLIN_JAVA_HOME ?? "C:\\Program Files\\Android\\Android Studio\\jbr"; diff --git a/scripts/measure-reactive-document-performance.ps1 b/scripts/measure-reactive-document-performance.ps1 index 7b410e41..c0f44eaf 100644 --- a/scripts/measure-reactive-document-performance.ps1 +++ b/scripts/measure-reactive-document-performance.ps1 @@ -69,7 +69,7 @@ if ($LASTEXITCODE -ne 0) { throw "CultMesh TypeScript reactive document performance probe failed." } -$pythonSource = Join-Path $root "packages\cultcache-py\src" +$pythonSource = (@("cultcache-py", "cultnet-py", "cultmesh-py") | ForEach-Object { Join-Path $root "packages\$_\src" }) -join [IO.Path]::PathSeparator $previousPythonPath = $env:PYTHONPATH $env:PYTHONPATH = if ([string]::IsNullOrWhiteSpace($previousPythonPath)) { $pythonSource @@ -78,7 +78,7 @@ else { $pythonSource + [IO.Path]::PathSeparator + $previousPythonPath } try { - & $pythonExecutable (Join-Path $root "packages\cultcache-py\tools\reactive_performance_probe.py") @runtimeArguments + & $pythonExecutable (Join-Path $root "packages\cultmesh-py\tools\reactive_performance_probe.py") @runtimeArguments if ($LASTEXITCODE -ne 0) { throw "CultMesh Python reactive document performance probe failed." } diff --git a/scripts/verify-reactive-document-scaling.ps1 b/scripts/verify-reactive-document-scaling.ps1 index a60c9dee..523b761f 100644 --- a/scripts/verify-reactive-document-scaling.ps1 +++ b/scripts/verify-reactive-document-scaling.ps1 @@ -81,7 +81,7 @@ finally { Pop-Location } -$pythonPath = Join-Path $root "packages\cultcache-py\src" +$pythonPath = (@("cultcache-py", "cultnet-py", "cultmesh-py") | ForEach-Object { Join-Path $root "packages\$_\src" }) -join [IO.Path]::PathSeparator $previousPythonPath = $env:PYTHONPATH $env:PYTHONPATH = if ([string]::IsNullOrWhiteSpace($previousPythonPath)) { $pythonPath @@ -91,8 +91,8 @@ else { } try { & $pythonExecutable -m unittest discover ` - -s (Join-Path $root "packages\cultcache-py\tests") ` - -p "test_cultcache.py" ` + -s (Join-Path $root "packages\cultmesh-py\tests") ` + -p "test_cultmesh.py" ` -k "reactive_scheduling_scales_with_changed_documents_only" if ($LASTEXITCODE -ne 0) { throw "CultMesh Python reactive scaling verification failed." From 6d98b03471c5b47c2b6fa3a11d936bad48d0e43b Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 10 Sep 2026 13:22:44 +0200 Subject: [PATCH 162/283] Drop the license classifier setuptools now refuses setuptools >= 77 rejects "License :: OSI Approved :: MIT License" once a PEP 639 license expression is set, and `pip install -e` builds with the newest setuptools. That has failed both CI workflows at the install step since 2026-09-04. `license = "MIT"` is the expression; the classifier said the same thing and is gone from all three Python manifests. Co-Authored-By: Claude Fable 5.1 --- packages/cultcache-py/pyproject.toml | 1 - packages/cultmesh-py/pyproject.toml | 1 - packages/cultnet-py/pyproject.toml | 1 - 3 files changed, 3 deletions(-) diff --git a/packages/cultcache-py/pyproject.toml b/packages/cultcache-py/pyproject.toml index ebd92a26..72573cf2 100644 --- a/packages/cultcache-py/pyproject.toml +++ b/packages/cultcache-py/pyproject.toml @@ -11,7 +11,6 @@ requires-python = ">=3.10" license = "MIT" authors = [{ name = "GameCult" }] classifiers = [ - "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", diff --git a/packages/cultmesh-py/pyproject.toml b/packages/cultmesh-py/pyproject.toml index 847b18e4..a1df5ee3 100644 --- a/packages/cultmesh-py/pyproject.toml +++ b/packages/cultmesh-py/pyproject.toml @@ -11,7 +11,6 @@ requires-python = ">=3.10" license = "MIT" authors = [{ name = "GameCult" }] classifiers = [ - "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", diff --git a/packages/cultnet-py/pyproject.toml b/packages/cultnet-py/pyproject.toml index f102b58b..41c4e8f6 100644 --- a/packages/cultnet-py/pyproject.toml +++ b/packages/cultnet-py/pyproject.toml @@ -11,7 +11,6 @@ requires-python = ">=3.10" license = "MIT" authors = [{ name = "GameCult" }] classifiers = [ - "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", From 830a5d718f1216dbb220c6d494cc51f2f87bcd41 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 10 Sep 2026 13:29:34 +0200 Subject: [PATCH 163/283] Make the Eve onboarding checkpoint run against the contract that exists The portability workflow has been red since 2026-08-22. Three things, each hidden behind the one before it: - Eve started refusing to build a command intent for a surface that has not advertised a command boundary and receipt schema (Eve 4338a42, 2026-08-22). The two-runtime sample never advertised one. It now passes a provider advertisement with worldInteraction for its surface, which is the declaration the lowering was right to demand. - The sample and the package-closure script still imported "cultcache-ts"; the package became @gamecult/cultcache-ts on 2026-09-04 (8cb3b72) and CI never got far enough to say so. Two READMEs carried the same import. - The job pinned Eve to codex/eve-browser-host-isolation, a branch that was never merged and stopped moving on 2026-08-25. The sample is written against Eve main and passes there; the pin now says so. The interop workflow's Python step ran one test file by path; it now discovers the three split suites. scripts/verify-eve-two-runtime-sample.ps1 -EveRoot F:\Projects\Eve (Eve main ccc3ffe) -> browserCount 1, headlessCount 1, restartCount 1 Co-Authored-By: Claude Fable 5.1 --- .github/workflows/cultmesh-portability.yml | 4 +++- .github/workflows/cultnet-interop.yml | 5 ++++- packages/cultcache-ts/README.md | 2 +- packages/cultnet-ts/README.md | 2 +- samples/eve-two-runtime/sample.mjs | 15 ++++++++++++++- scripts/test-typescript-package-closure.mjs | 4 ++-- 6 files changed, 25 insertions(+), 7 deletions(-) diff --git a/.github/workflows/cultmesh-portability.yml b/.github/workflows/cultmesh-portability.yml index 4d93085a..ce361fc8 100644 --- a/.github/workflows/cultmesh-portability.yml +++ b/.github/workflows/cultmesh-portability.yml @@ -28,7 +28,9 @@ jobs: uses: actions/checkout@v4 with: repository: GameCult/Eve - ref: ${{ vars.EVE_INTEGRATION_REF || 'codex/eve-browser-host-isolation' }} + # Eve main is the contract this sample is written against; the codex + # branch this used to pin was never merged and stopped on 2026-08-25. + ref: ${{ vars.EVE_INTEGRATION_REF || 'main' }} path: Eve - name: Set up .NET diff --git a/.github/workflows/cultnet-interop.yml b/.github/workflows/cultnet-interop.yml index f7f2eefc..6876a76a 100644 --- a/.github/workflows/cultnet-interop.yml +++ b/.github/workflows/cultnet-interop.yml @@ -87,7 +87,10 @@ jobs: run: npm test --workspace packages/cultnet-ts - name: Verify Python RUDP reliability - run: python -m unittest packages/cultcache-py/tests/test_cultcache.py + run: | + python -m unittest discover -s packages/cultcache-py/tests + python -m unittest discover -s packages/cultnet-py/tests + python -m unittest discover -s packages/cultmesh-py/tests - name: Verify Rust RUDP reliability run: cargo test --manifest-path packages/cultnet-rs/Cargo.toml rudp diff --git a/packages/cultcache-ts/README.md b/packages/cultcache-ts/README.md index 064cc91b..4a696103 100644 --- a/packages/cultcache-ts/README.md +++ b/packages/cultcache-ts/README.md @@ -53,7 +53,7 @@ import { SingleFileMessagePackBackingStore, defineDocumentRegistry, defineDocumentType, -} from "cultcache-ts"; +} from "@gamecult/cultcache-ts"; const itemDocument = defineDocumentType({ type: "item", diff --git a/packages/cultnet-ts/README.md b/packages/cultnet-ts/README.md index 5ff66e7e..75e77b88 100644 --- a/packages/cultnet-ts/README.md +++ b/packages/cultnet-ts/README.md @@ -195,7 +195,7 @@ the helper path. ## Quick Example ```ts -import { CultCache, defineDocumentType } from "cultcache-ts"; +import { CultCache, defineDocumentType } from "@gamecult/cultcache-ts"; import { CultNetDocumentRegistry, createTcpFramedCultNetPeer, diff --git a/samples/eve-two-runtime/sample.mjs b/samples/eve-two-runtime/sample.mjs index e3269618..93ed1dc8 100644 --- a/samples/eve-two-runtime/sample.mjs +++ b/samples/eve-two-runtime/sample.mjs @@ -4,7 +4,7 @@ import { tmpdir } from "node:os"; import { join } from "node:path"; import { JSDOM } from "jsdom"; import { z } from "zod"; -import { defineDocumentType } from "cultcache-ts"; +import { defineDocumentType } from "@gamecult/cultcache-ts"; import { CultMesh } from "cultmesh-ts"; import { parseEveCommandReceipt, @@ -172,6 +172,19 @@ let browserReceipt; renderEveSurface(await node.document(surfaceDocument, surfaceId).latest(), host, { activeSurfaceId: surfaceId, clientId: "browser-client", + // Eve refuses to build a command intent for a surface that has not + // advertised where its commands go and what comes back. The provider + // advertisement is that declaration; a lowering cannot infer it. + provider: { + providerId, + surfaces: [{ + surfaceId, + worldInteraction: { + commandBoundary: "sample.counter.commands", + receiptSchema: "gamecult.eve.command_receipt.v1", + }, + }], + }, commandSink: async intent => { browserReceipt = await increment.bind(browserVerse).invoke(intent.payload, { idempotencyKey: "browser-click-1", diff --git a/scripts/test-typescript-package-closure.mjs b/scripts/test-typescript-package-closure.mjs index e5648c9c..0ed79e59 100644 --- a/scripts/test-typescript-package-closure.mjs +++ b/scripts/test-typescript-package-closure.mjs @@ -58,7 +58,7 @@ try { writeFileSync(join(consumerRoot, "runtime-smoke.cjs"), ` const assert = require("node:assert/strict"); -const cache = require("cultcache-ts"); +const cache = require("@gamecult/cultcache-ts"); const net = require("cultnet-ts"); const mesh = require("cultmesh-ts"); assert.equal(typeof cache.defineDocumentType, "function"); @@ -81,7 +81,7 @@ assert.equal("putDocument" in CultMeshBrowserClient.prototype, false); execFileSync(process.execPath, ["browser-runtime-smoke.mjs"], { cwd: consumerRoot, stdio: "inherit" }); writeFileSync(join(consumerRoot, "types-smoke.ts"), ` -import { defineDocumentType } from "cultcache-ts"; +import { defineDocumentType } from "@gamecult/cultcache-ts"; import { CultNetPeer } from "cultnet-ts"; import { CultMesh, From 672235e8f3af6c6f9de08df989c7e3e18f925e95 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 10 Sep 2026 13:30:31 +0200 Subject: [PATCH 164/283] Ignore Python package build output Co-Authored-By: Claude Fable 5.1 --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 94ed900d..e4661501 100644 --- a/.gitignore +++ b/.gitignore @@ -516,3 +516,7 @@ $RECYCLE.BIN/ # Vim temporary swap files *.swp + +# Python package build output +packages/*-py/build/ +*.egg-info/ From f94f5581b078f79a532338f642008d66c6a3f1ff Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 10 Sep 2026 13:35:15 +0200 Subject: [PATCH 165/283] Let the verse catalog schema say what the reference emits The C# reference publishes authorityRoutes with certificate: null for loopback routes, and its own verifier treats null as "no certificate" in local development. The TypeScript JSON schema only allowed the object, so the browser client rejected every catalog the getting-started provider served: "certificate: must be object", Odin could not resolve the Verse, and the real browser/C# checkpoint has failed since f622ee1 (2026-08-18), behind the sample failure that hid it. TypeScript consumers already guard route.certificate; the schema now accepts null. The package-closure smoke also still spelled the browser identity with providerId; it is authorityRuntimeId since c194bd4. npm test --workspace packages/cultnet-ts -> 54 pass npm run test:pack:ts -> passed Co-Authored-By: Claude Fable 5.1 --- .../contracts/cultmesh.verse-catalog-response.schema.json | 4 +++- scripts/test-typescript-package-closure.mjs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/cultnet-ts/contracts/cultmesh.verse-catalog-response.schema.json b/packages/cultnet-ts/contracts/cultmesh.verse-catalog-response.schema.json index f23ef5f7..464908ad 100644 --- a/packages/cultnet-ts/contracts/cultmesh.verse-catalog-response.schema.json +++ b/packages/cultnet-ts/contracts/cultmesh.verse-catalog-response.schema.json @@ -28,7 +28,9 @@ "protocolIds": { "type": "array", "items": { "type": "string", "minLength": 1 }, "uniqueItems": true }, "priority": { "type": "integer", "minimum": 0 }, "generation": { "type": "string", "minLength": 1 }, - "certificate": { "$ref": "#/$defs/routeCertificate" } + "certificate": { + "anyOf": [{ "$ref": "#/$defs/routeCertificate" }, { "type": "null" }] + } } }, "routeCertificate": { diff --git a/scripts/test-typescript-package-closure.mjs b/scripts/test-typescript-package-closure.mjs index 0ed79e59..5f00aa47 100644 --- a/scripts/test-typescript-package-closure.mjs +++ b/scripts/test-typescript-package-closure.mjs @@ -131,7 +131,7 @@ import { const identity: CultMeshBrowserIdentity = { verseId: "smoke", - providerId: "smoke.provider", + authorityRuntimeId: "smoke.authority", }; const lease: CultMeshRawDocumentLeaseOptions = { schemaId: "smoke.document.v1", From 89687fceb4d0af32e672738a18c352f1b3b744df Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 10 Sep 2026 13:45:07 +0200 Subject: [PATCH 166/283] Let the browser sample read the provider's advertisement Eve refuses to build a command intent for a surface that has not advertised a command boundary and receipt schema, and the intent it builds now carries the operation under operation.operationId. The browser sample did neither: the click was refused inside the page and the checkpoint saw only a 30 s timeout on the receipt. The C# provider now publishes its gamecult.eve.provider_advertisement.v1 document with the surface's worldInteraction, and the page leases that and hands it to the lowering as `provider`. The provider owns the declaration; the page reads it rather than restating it. The command sink reads intent.operation.operationId. The checkpoint now forwards the page's console and pageerror output. "CultMesh browser operation is required." took one run to find with it and had been a bare timeout without it. scripts/verify-eve-getting-started.ps1 -EveRoot ..\Eve (Eve main) -> Eve getting-started verification passed: clean .NET and TypeScript artifacts, DOM and headless convergence, real Chromium and C# clients, Odin discovery, authority-bound routes, receipts, persistence, and route replacement. Co-Authored-By: Claude Fable 5.1 --- samples/eve-browser-network/Program.cs | 45 ++++++++++++++++++++- samples/eve-browser-network/browser/main.ts | 13 +++++- scripts/verify-eve-browser-network.mjs | 4 ++ 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/samples/eve-browser-network/Program.cs b/samples/eve-browser-network/Program.cs index bfadd7db..68f72e05 100644 --- a/samples/eve-browser-network/Program.cs +++ b/samples/eve-browser-network/Program.cs @@ -14,6 +14,8 @@ using Microsoft.Extensions.DependencyInjection; const string counterKey = "counter:main"; const string surfaceKey = "sample.counter"; +const string providerKey = "sample.counter-ui"; +const string commandBoundary = "sample.counter.commands"; var arguments = Args.Parse(args); if (arguments.Mode == "provider") { @@ -89,7 +91,7 @@ static async Task RunOdinAsync(Args arguments) static async Task RunProviderAsync(Args arguments) { - var documentTypes = new[] { typeof(CounterState), typeof(EveSurfaceDocument) }; + var documentTypes = new[] { typeof(CounterState), typeof(EveSurfaceDocument), typeof(EveProviderAdvertisementDocument) }; var registry = CultMesh.CreateCultCacheDocumentRegistry(documentTypes); var documents = CultMesh.CreateCultNetDocumentRegistry(documentTypes, registry); using var node = await CultMesh.CreateNodeAsync(arguments.StatePath, new CultMeshNodeOptions @@ -111,6 +113,10 @@ static async Task RunProviderAsync(Args arguments) await node.Database.PutAsync(new CultRecordKey(counterKey), CounterState.Initial(counterKey)); if (node.Cache.Get(new CultRecordKey(surfaceKey)) == null) await node.Database.PutAsync(new CultRecordKey(surfaceKey), CreateCounterSurface()); + // The advertisement is how a lowering learns where this surface's commands + // go and what comes back. Eve refuses to build a command intent without it, + // and the browser must not have to restate it: the provider is the owner. + await node.Database.PutAsync(new CultRecordKey(providerKey), CreateProviderAdvertisement(arguments)); await node.FlushAsync(); await using var schemaServer = new CultNetWebSocketSchemaServer(); @@ -341,6 +347,43 @@ static void ForceCollection() GC.Collect(); } +static EveProviderAdvertisementDocument CreateProviderAdvertisement(Args arguments) +{ + var worldInteraction = new EveWorldInteractionAdvertisement( + projectionKind: "surface-state", + stateSchemas: ["sample.counter_state.v1"], + commandBoundary: commandBoundary, + commandRecordRef: "", + receiptSchema: EveCommandReceiptDocument.SchemaId, + receiptRecordRef: "", + assetManifestRecordRef: "", + loweringTargets: ["browser"], + ownership: arguments.AuthorityRuntimeId); + return new EveProviderAdvertisementDocument( + providerId: providerKey, + serviceId: arguments.VerseId, + verseId: arguments.VerseId, + title: "CultMesh browser counter", + kind: "sample.daemon", + cultMeshAddress: arguments.AuthorityRuntimeId, + updatedAtUtc: DateTime.UtcNow.ToString("O"), + freshness: new EveProviderFreshness("live", DateTime.UtcNow.ToString("O"), 0), + schemas: ["sample.counter_state.v1", EveSurfaceDocument.SchemaId, EveCommandReceiptDocument.SchemaId], + witnesses: [], + surfaces: + [ + new EveAdvertisedSurface( + surfaceKey, + EveSurfaceDocument.SchemaId, + surfaceKey, + "cultmesh", + "live", + "surface", + worldInteraction) + ], + commands: [new EveAdvertisedCommand("sample.counter.increment", surfaceKey, "cultmesh", "Increment")]); +} + static EveSurfaceDocument CreateCounterSurface() { var networkRoute = new CultMeshRouteHint(CultMeshLocalityKind.Network, "cultmesh"); diff --git a/samples/eve-browser-network/browser/main.ts b/samples/eve-browser-network/browser/main.ts index 8251a0a3..b04ee5c8 100644 --- a/samples/eve-browser-network/browser/main.ts +++ b/samples/eve-browser-network/browser/main.ts @@ -1,4 +1,4 @@ -import { parseEveCommandReceipt, parseEveSurfaceDocument } from "@gamecult/eve-contracts"; +import { parseEveCommandReceipt, parseEveProviderAdvertisement, parseEveSurfaceDocument } from "@gamecult/eve-contracts"; import { renderEveSurface } from "@gamecult/eve-browser-lowering"; import { CultMeshBrowserClient, @@ -52,14 +52,23 @@ try { recordKey: "sample.counter", subscriptionId: "browser-surface", }); + // The provider owns the declaration of where this surface's commands go and + // what comes back; the page reads it rather than restating it. + const advertisement = await mesh.leaseRawDocument({ + schemaId: "gamecult.eve.provider_advertisement.v1", + recordKey: "sample.counter-ui", + subscriptionId: "browser-provider", + }); + const provider = parseEveProviderAdvertisement(decodeCultNetPayload(advertisement.current!)); const currentSurface = parseEveSurfaceDocument(decodeCultNetPayload(surface.current!)); renderEveSurface(currentSurface, host, { activeSurfaceId: "sample.counter", clientId: "sample.chromium", + provider, commandSink: async intent => { const response = await mesh.invoke({ serviceId: "sample.counter", - operation: intent.command, + operation: intent.operation.operationId, payloadSchema: "sample.increment.v1", payload: { amount: 1 }, idempotencyKey: window.__sampleCommandId, diff --git a/scripts/verify-eve-browser-network.mjs b/scripts/verify-eve-browser-network.mjs index 8c865b1d..c1388712 100644 --- a/scripts/verify-eve-browser-network.mjs +++ b/scripts/verify-eve-browser-network.mjs @@ -107,6 +107,10 @@ try { browser = await chromium.launch({ executablePath: resolveChromiumExecutable(), headless: true }); let page = await browser.newPage(); + // A command the lowering refuses is caught inside the page; without this + // the only symptom is a 30 s timeout on the receipt. + page.on("console", message => console.log(`[browser:${message.type()}] ${message.text()}`)); + page.on("pageerror", error => console.log(`[browser:pageerror] ${error.message}`)); const url = `http://127.0.0.1:${httpPort}/?odin=${encodeURIComponent(odinEndpoint)}&token=${token}`; await page.goto(url); await page.waitForFunction(() => window.__sampleReady || window.__sampleError); From 34c8ea79b9d5ff0d3ad11b82216f746474b57ec0 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 10 Sep 2026 21:33:06 +0200 Subject: [PATCH 167/283] Build receiver feedback where both ends can see the rules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit build_receiver_feedback normalises the record a receiver sends back — damage lists sorted and unique, chunk keys well-formed, a keyframe requested whenever something is missing — and until now lived in Muninn, the one end that never sends it. Ratatoskr sends it; Muninn's sender tests construct it to exercise the repair cache. A builder both ends call belongs beside the record it builds. Co-Authored-By: Claude Fable 5.1 --- packages/cultnet-rs/src/media_stream_wire.rs | 118 +++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/packages/cultnet-rs/src/media_stream_wire.rs b/packages/cultnet-rs/src/media_stream_wire.rs index 7083d927..6bc30171 100644 --- a/packages/cultnet-rs/src/media_stream_wire.rs +++ b/packages/cultnet-rs/src/media_stream_wire.rs @@ -445,3 +445,121 @@ pub fn validate_feedback_record(record: &GameCultMediaReceiverFeedbackRecord) -> normalize_video_chunk_feedback_keys(record.missing_video_chunk_keys.clone())?; Ok(()) } + +/// What a receiver has to say about a stream. The record it builds is the +/// contract's; this normalises it so both ends agree on its shape: damage +/// lists sorted and unique, chunk keys well-formed, and a keyframe requested +/// whenever something is missing, since a producer cannot repair a reference +/// the receiver never had. +#[derive(Clone, Debug)] +pub struct ReceiverFeedbackOptions<'a> { + pub stream_id: &'a str, + pub session_id: &'a str, + pub receiver_id: &'a str, + pub highest_decodable_frame_id: Option, + pub missing_frame_ids: Vec, + pub missing_video_chunk_keys: Vec, + pub late_frame_ids: Vec, + pub requested_keyframe: bool, + pub jitter_us: i64, + pub decode_queue_us: i64, + pub observed_at: &'a str, +} + +pub fn build_receiver_feedback( + options: ReceiverFeedbackOptions<'_>, +) -> Result { + let mut missing_frame_ids = options.missing_frame_ids; + missing_frame_ids.sort_unstable(); + missing_frame_ids.dedup(); + let missing_video_chunk_keys = + normalize_video_chunk_feedback_keys(options.missing_video_chunk_keys)?; + let mut late_frame_ids = options.late_frame_ids; + late_frame_ids.sort_unstable(); + late_frame_ids.dedup(); + let requested_keyframe = options.requested_keyframe + || !missing_frame_ids.is_empty() + || !missing_video_chunk_keys.is_empty(); + + let record = GameCultMediaReceiverFeedbackRecord { + stream_id: options.stream_id.to_string(), + session_id: options.session_id.to_string(), + receiver_id: options.receiver_id.to_string(), + highest_decodable_frame_id: options.highest_decodable_frame_id, + missing_frame_ids, + late_frame_ids, + requested_keyframe, + jitter_us: options.jitter_us, + decode_queue_us: options.decode_queue_us, + observed_at: options.observed_at.to_string(), + missing_video_chunk_keys, + }; + validate_feedback_record(&record)?; + Ok(record) +} + +#[cfg(test)] +mod receiver_feedback_tests { + use super::*; + + fn options() -> ReceiverFeedbackOptions<'static> { + ReceiverFeedbackOptions { + stream_id: "muninn.raven.av.rudp", + session_id: "session-1", + receiver_id: "starfire.obs", + highest_decodable_frame_id: Some(40), + missing_frame_ids: Vec::new(), + missing_video_chunk_keys: Vec::new(), + late_frame_ids: Vec::new(), + requested_keyframe: false, + jitter_us: 0, + decode_queue_us: 2_000, + observed_at: "2026-06-18T00:00:00Z", + } + } + + #[test] + fn builds_receiver_feedback_with_sorted_unique_damage_lists() -> Result<()> { + let feedback = build_receiver_feedback(ReceiverFeedbackOptions { + missing_frame_ids: vec![43, 42, 43], + missing_video_chunk_keys: vec![ + video_chunk_feedback_key(43, 2), + video_chunk_feedback_key(42, 1), + video_chunk_feedback_key(42, 1), + ], + late_frame_ids: vec![39, 39, 38], + jitter_us: 700, + ..options() + })?; + + assert_eq!(feedback.missing_frame_ids, vec![42, 43]); + assert_eq!(feedback.missing_video_chunk_keys, vec!["42:1", "43:2"]); + assert_eq!(feedback.late_frame_ids, vec![38, 39]); + assert!(feedback.requested_keyframe, "missing chunks imply a lost reference"); + Ok(()) + } + + #[test] + fn rejects_negative_receiver_feedback_timing() { + let error = build_receiver_feedback(ReceiverFeedbackOptions { jitter_us: -1, ..options() }) + .unwrap_err(); + assert!(error.to_string().contains("jitter_us")); + } + + #[test] + fn rejects_malformed_receiver_feedback_chunk_keys() { + let error = build_receiver_feedback(ReceiverFeedbackOptions { + missing_video_chunk_keys: vec!["frame:chunk".to_string()], + ..options() + }) + .unwrap_err(); + assert!(error.to_string().contains("frame_id"), "{error}"); + } + + #[test] + fn rejects_an_empty_receiver_id() { + let error = build_receiver_feedback(ReceiverFeedbackOptions { receiver_id: "", ..options() }) + .unwrap_err(); + assert!(error.to_string().contains("receiver_id")); + } +} From 4160ab560b15150d8054c5c7f557711ad244b8e0 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 10 Sep 2026 21:35:04 +0200 Subject: [PATCH 168/283] A repair request is not a keyframe request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The builder forced requested_keyframe whenever chunk keys were missing. A producer answers each new keyframe request with an IDR, so every repair request would have cost a keyframe — the thing a repair request exists to avoid. The old C++ receiver sent repairs with the flag off; this builder had never been driven by a real receiver. A whole missing frame still implies one, since the repair cache holds chunks. Co-Authored-By: Claude Fable 5.1 --- packages/cultnet-rs/src/media_stream_wire.rs | 23 +++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/packages/cultnet-rs/src/media_stream_wire.rs b/packages/cultnet-rs/src/media_stream_wire.rs index 6bc30171..fb1b1f8d 100644 --- a/packages/cultnet-rs/src/media_stream_wire.rs +++ b/packages/cultnet-rs/src/media_stream_wire.rs @@ -449,8 +449,9 @@ pub fn validate_feedback_record(record: &GameCultMediaReceiverFeedbackRecord) -> /// What a receiver has to say about a stream. The record it builds is the /// contract's; this normalises it so both ends agree on its shape: damage /// lists sorted and unique, chunk keys well-formed, and a keyframe requested -/// whenever something is missing, since a producer cannot repair a reference -/// the receiver never had. +/// whenever a whole frame is missing, since a producer's repair cache holds +/// chunks, not references. Missing chunks alone are a repair request, which +/// exists precisely so that a keyframe is not needed. #[derive(Clone, Debug)] pub struct ReceiverFeedbackOptions<'a> { pub stream_id: &'a str, @@ -477,9 +478,7 @@ pub fn build_receiver_feedback( let mut late_frame_ids = options.late_frame_ids; late_frame_ids.sort_unstable(); late_frame_ids.dedup(); - let requested_keyframe = options.requested_keyframe - || !missing_frame_ids.is_empty() - || !missing_video_chunk_keys.is_empty(); + let requested_keyframe = options.requested_keyframe || !missing_frame_ids.is_empty(); let record = GameCultMediaReceiverFeedbackRecord { stream_id: options.stream_id.to_string(), @@ -535,7 +534,19 @@ mod receiver_feedback_tests { assert_eq!(feedback.missing_frame_ids, vec![42, 43]); assert_eq!(feedback.missing_video_chunk_keys, vec!["42:1", "43:2"]); assert_eq!(feedback.late_frame_ids, vec![38, 39]); - assert!(feedback.requested_keyframe, "missing chunks imply a lost reference"); + assert!(feedback.requested_keyframe, "a whole missing frame is a lost reference"); + Ok(()) + } + + /// A producer answers a keyframe request with an IDR. A repair request is + /// the cheaper alternative and must not carry one by accident. + #[test] + fn a_repair_request_does_not_ask_for_a_keyframe() -> Result<()> { + let feedback = build_receiver_feedback(ReceiverFeedbackOptions { + missing_video_chunk_keys: vec![video_chunk_feedback_key(42, 1)], + ..options() + })?; + assert!(!feedback.requested_keyframe); Ok(()) } From 780e1a48cdf6ded6d3a6e3e72916817fb3768f05 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 10 Sep 2026 22:07:39 +0200 Subject: [PATCH 169/283] Advertise and request media streams without naming a producer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two state records beside the media wire records, travelling as CultMesh documents through Odin rather than on the media channel: - gamecult.media_stream_advertisement.v1: a stream a producer can serve on request — its video and audio sources, the codecs it can encode, audio sample rate and channels, defaults, and the connection id it dials a receiver with. Keyed by stream_id. A consumer's picker is built from these. - gamecult.media_stream_request.v1: a consumer asking a producer to start or stop serving a stream to a receiver endpoint, with sources, codecs, bitrate and latency budget. Keyed by stream_id:receiver_id so a newer request supersedes; the producer answers on the same key by rewriting state and detail. Until now the only way to pick a stream was Muninn's own muninn.obs_stream_catalog and muninn.capture_stream_command, which live in odin-core and bind every consumer to one producer. Odin persists any well-formed document, so nothing there has to change to carry these. Co-Authored-By: Claude Fable 5.1 --- .../cultnet-rs/src/media_stream_contracts.rs | 343 ++++++++++++++++++ 1 file changed, 343 insertions(+) diff --git a/packages/cultnet-rs/src/media_stream_contracts.rs b/packages/cultnet-rs/src/media_stream_contracts.rs index 815e3392..59761561 100644 --- a/packages/cultnet-rs/src/media_stream_contracts.rs +++ b/packages/cultnet-rs/src/media_stream_contracts.rs @@ -46,6 +46,349 @@ pub const GAMECULT_MEDIA_VIDEO_ACCESS_UNIT_SCHEMA: &str = "gamecult.media_video_ pub const GAMECULT_MEDIA_VIDEO_PARITY_SHARD_SCHEMA: &str = "gamecult.media_video_parity_shard.v2"; pub const GAMECULT_MEDIA_AUDIO_PACKET_SCHEMA: &str = "gamecult.media_audio_packet.v1"; pub const GAMECULT_MEDIA_RECEIVER_FEEDBACK_SCHEMA: &str = "gamecult.media_receiver_feedback.v1"; +pub const GAMECULT_MEDIA_STREAM_ADVERTISEMENT_SCHEMA: &str = + "gamecult.media_stream_advertisement.v1"; +pub const GAMECULT_MEDIA_STREAM_REQUEST_SCHEMA: &str = "gamecult.media_stream_request.v1"; + +/// A media stream a producer can serve on request, as it appears in Odin. +/// +/// This is the record a consumer's picker is built from: which streams exist, +/// which video and audio sources each can capture, which codecs it can encode, +/// and the defaults it would use. It is state, not media — it travels as a +/// CultMesh document through Odin, never on the media channel — and it names no +/// consumer. `producer_id` is the runtime that answers requests for it. +/// +/// Keyed by `stream_id`. +#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] +#[cultcache( + type = "gamecult.media_stream_advertisement", + schema = "gamecult.media_stream_advertisement.v1" +)] +pub struct GameCultMediaStreamAdvertisementRecord { + #[cultcache(key = 0)] + pub stream_id: String, + #[cultcache(key = 1)] + pub producer_id: String, + #[cultcache(key = 2)] + pub label: String, + /// `available`, `streaming`, or `unavailable`. + #[cultcache(key = 3)] + pub state: String, + #[cultcache(key = 4)] + pub video_source_ids: Vec, + #[cultcache(key = 5)] + pub video_source_labels: Vec, + #[cultcache(key = 6)] + pub audio_source_ids: Vec, + #[cultcache(key = 7)] + pub audio_source_labels: Vec, + /// Codecs the producer can encode video as, e.g. `h264`. + #[cultcache(key = 8)] + pub video_codecs: Vec, + /// Codecs the producer can emit audio as, e.g. `pcm-f32le-interleaved`. + #[cultcache(key = 9)] + pub audio_codecs: Vec, + #[cultcache(key = 10)] + pub audio_sample_rate: u32, + #[cultcache(key = 11)] + pub audio_channels: u32, + #[cultcache(key = 12)] + pub default_video_bitrate_kbps: u32, + #[cultcache(key = 13)] + pub default_latency_budget_ms: u32, + #[cultcache(key = 14)] + pub media_packet_bytes: u32, + /// The CultNet RUDP connection id the producer dials the receiver with. + #[cultcache(key = 15)] + pub media_connection_id: u32, + #[cultcache(key = 16)] + pub updated_at: String, +} + +/// A consumer asking a producer to start or stop serving a stream to it. +/// +/// The producer answers by rewriting `state` and `detail` on the same record +/// key, so a consumer watches one document for the outcome. A newer request for +/// the same `stream_id` and `receiver_id` supersedes an older one. +/// +/// Keyed by `media_stream_request_key(stream_id, receiver_id)`. +#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] +#[cultcache( + type = "gamecult.media_stream_request", + schema = "gamecult.media_stream_request.v1" +)] +pub struct GameCultMediaStreamRequestRecord { + #[cultcache(key = 0)] + pub request_id: String, + #[cultcache(key = 1)] + pub stream_id: String, + #[cultcache(key = 2)] + pub producer_id: String, + #[cultcache(key = 3)] + pub receiver_id: String, + /// `host:port` the producer should dial with the advertised connection id. + #[cultcache(key = 4)] + pub receiver_endpoint: String, + /// `start` or `stop`. + #[cultcache(key = 5)] + pub action: String, + /// `pending`, `running`, `stopped`, or `failed`; the producer owns it after + /// `pending`. + #[cultcache(key = 6)] + pub state: String, + /// Empty means no video. + #[cultcache(key = 7)] + pub video_source_id: String, + /// Empty means no audio. + #[cultcache(key = 8)] + pub audio_source_id: String, + #[cultcache(key = 9)] + pub video_codec: String, + #[cultcache(key = 10)] + pub audio_codec: String, + #[cultcache(key = 11)] + pub video_bitrate_kbps: u32, + #[cultcache(key = 12)] + pub latency_budget_ms: u32, + #[cultcache(key = 13)] + pub media_packet_bytes: u32, + #[cultcache(key = 14)] + pub detail: String, + #[cultcache(key = 15)] + pub updated_at: String, +} + +pub const MEDIA_STREAM_REQUEST_ACTIONS: [&str; 2] = ["start", "stop"]; +pub const MEDIA_STREAM_REQUEST_STATES: [&str; 4] = ["pending", "running", "stopped", "failed"]; +pub const MEDIA_STREAM_ADVERTISEMENT_STATES: [&str; 3] = ["available", "streaming", "unavailable"]; + +/// One live request per stream per receiver: a newer one replaces the older. +pub fn media_stream_request_key(stream_id: &str, receiver_id: &str) -> String { + format!("{stream_id}:{receiver_id}") +} + +pub fn validate_media_stream_advertisement( + record: &GameCultMediaStreamAdvertisementRecord, +) -> anyhow::Result<()> { + use anyhow::anyhow; + for (name, value) in [ + ("stream_id", &record.stream_id), + ("producer_id", &record.producer_id), + ("label", &record.label), + ("updated_at", &record.updated_at), + ] { + if value.is_empty() { + return Err(anyhow!("media stream advertisement {name} must be non-empty")); + } + } + if !MEDIA_STREAM_ADVERTISEMENT_STATES.contains(&record.state.as_str()) { + return Err(anyhow!( + "media stream advertisement state {:?} is not one of {:?}", + record.state, + MEDIA_STREAM_ADVERTISEMENT_STATES + )); + } + if record.video_source_ids.len() != record.video_source_labels.len() { + return Err(anyhow!( + "media stream advertisement has {} video source ids and {} labels", + record.video_source_ids.len(), + record.video_source_labels.len() + )); + } + if record.audio_source_ids.len() != record.audio_source_labels.len() { + return Err(anyhow!( + "media stream advertisement has {} audio source ids and {} labels", + record.audio_source_ids.len(), + record.audio_source_labels.len() + )); + } + if !record.audio_source_ids.is_empty() && (record.audio_sample_rate == 0 || record.audio_channels == 0) { + return Err(anyhow!( + "media stream advertisement offers audio without a sample rate and channel count" + )); + } + if record.media_connection_id == 0 { + return Err(anyhow!("media stream advertisement media_connection_id must be non-zero")); + } + Ok(()) +} + +pub fn validate_media_stream_request( + record: &GameCultMediaStreamRequestRecord, +) -> anyhow::Result<()> { + use anyhow::anyhow; + for (name, value) in [ + ("request_id", &record.request_id), + ("stream_id", &record.stream_id), + ("producer_id", &record.producer_id), + ("receiver_id", &record.receiver_id), + ("updated_at", &record.updated_at), + ] { + if value.is_empty() { + return Err(anyhow!("media stream request {name} must be non-empty")); + } + } + if !MEDIA_STREAM_REQUEST_ACTIONS.contains(&record.action.as_str()) { + return Err(anyhow!( + "media stream request action {:?} is not one of {:?}", + record.action, + MEDIA_STREAM_REQUEST_ACTIONS + )); + } + if !MEDIA_STREAM_REQUEST_STATES.contains(&record.state.as_str()) { + return Err(anyhow!( + "media stream request state {:?} is not one of {:?}", + record.state, + MEDIA_STREAM_REQUEST_STATES + )); + } + if record.action == "start" { + if record.receiver_endpoint.parse::().is_err() { + return Err(anyhow!( + "media stream request receiver_endpoint {:?} must be host:port", + record.receiver_endpoint + )); + } + if record.video_source_id.is_empty() && record.audio_source_id.is_empty() { + return Err(anyhow!("media stream request asks for neither video nor audio")); + } + if !record.video_source_id.is_empty() && record.video_codec.is_empty() { + return Err(anyhow!("media stream request names a video source without a codec")); + } + if !record.audio_source_id.is_empty() && record.audio_codec.is_empty() { + return Err(anyhow!("media stream request names an audio source without a codec")); + } + } + Ok(()) +} + +#[cfg(test)] +mod media_stream_catalog_tests { + use super::*; + + fn advertisement() -> GameCultMediaStreamAdvertisementRecord { + GameCultMediaStreamAdvertisementRecord { + stream_id: "muninn.raven.av.rudp".into(), + producer_id: "raven".into(), + label: "Raven desktop".into(), + state: "available".into(), + video_source_ids: vec!["display:0".into()], + video_source_labels: vec!["Display 1".into()], + audio_source_ids: vec!["wasapi-loopback:Realtek".into()], + audio_source_labels: vec!["Realtek loopback".into()], + video_codecs: vec!["h264".into()], + audio_codecs: vec!["pcm-f32le-interleaved".into()], + audio_sample_rate: 48_000, + audio_channels: 2, + default_video_bitrate_kbps: 12_000, + default_latency_budget_ms: 250, + media_packet_bytes: 848, + media_connection_id: 0x6d75_0001, + updated_at: "2026-09-10T00:00:00Z".into(), + } + } + + fn request() -> GameCultMediaStreamRequestRecord { + GameCultMediaStreamRequestRecord { + request_id: "req-1".into(), + stream_id: "muninn.raven.av.rudp".into(), + producer_id: "raven".into(), + receiver_id: "starfire.obs".into(), + receiver_endpoint: "192.168.178.146:5204".into(), + action: "start".into(), + state: "pending".into(), + video_source_id: "display:0".into(), + audio_source_id: "wasapi-loopback:Realtek".into(), + video_codec: "h264".into(), + audio_codec: "pcm-f32le-interleaved".into(), + video_bitrate_kbps: 12_000, + latency_budget_ms: 250, + media_packet_bytes: 848, + detail: String::new(), + updated_at: "2026-09-10T00:00:00Z".into(), + } + } + + #[test] + fn a_complete_advertisement_and_request_validate() -> anyhow::Result<()> { + validate_media_stream_advertisement(&advertisement())?; + validate_media_stream_request(&request())?; + Ok(()) + } + + #[test] + fn source_ids_and_labels_must_pair_up() { + let mut record = advertisement(); + record.video_source_labels.clear(); + let error = validate_media_stream_advertisement(&record).unwrap_err(); + assert!(error.to_string().contains("video source ids"), "{error}"); + } + + #[test] + fn audio_on_offer_needs_a_sample_rate_and_channels() { + let mut record = advertisement(); + record.audio_channels = 0; + assert!(validate_media_stream_advertisement(&record).is_err()); + record.audio_source_ids.clear(); + record.audio_source_labels.clear(); + assert!(validate_media_stream_advertisement(&record).is_ok(), "no audio, no requirement"); + } + + #[test] + fn a_start_needs_somewhere_to_send_and_something_to_send() { + let mut record = request(); + record.receiver_endpoint = "starfire".into(); + assert!(validate_media_stream_request(&record).unwrap_err().to_string().contains("host:port")); + let mut record = request(); + record.video_source_id.clear(); + record.audio_source_id.clear(); + assert!(validate_media_stream_request(&record).unwrap_err().to_string().contains("neither")); + let mut record = request(); + record.video_codec.clear(); + assert!(validate_media_stream_request(&record).unwrap_err().to_string().contains("codec")); + } + + #[test] + fn a_stop_needs_no_endpoint_or_sources() -> anyhow::Result<()> { + let mut record = request(); + record.action = "stop".into(); + record.receiver_endpoint.clear(); + record.video_source_id.clear(); + record.audio_source_id.clear(); + validate_media_stream_request(&record) + } + + #[test] + fn unknown_actions_and_states_are_refused() { + let mut record = request(); + record.action = "pause".into(); + assert!(validate_media_stream_request(&record).is_err()); + let mut record = request(); + record.state = "done".into(); + assert!(validate_media_stream_request(&record).is_err()); + } + + #[test] + fn one_request_per_stream_per_receiver() { + assert_eq!(media_stream_request_key("s", "starfire.obs"), "s:starfire.obs"); + } + + /// The records round-trip through the same positional encoding every + /// other runtime reads, so a Python or TypeScript consumer sees the same + /// slots. + #[test] + fn records_round_trip_positionally() -> anyhow::Result<()> { + let record = advertisement(); + let encoded = rmp_serde::to_vec(&record)?; + let decoded: GameCultMediaStreamAdvertisementRecord = rmp_serde::from_slice(&encoded)?; + assert_eq!(decoded, record); + let record = request(); + let encoded = rmp_serde::to_vec(&record)?; + let decoded: GameCultMediaStreamRequestRecord = rmp_serde::from_slice(&encoded)?; + assert_eq!(decoded, record); + Ok(()) + } +} /// One coded video access unit, possibly split across `chunk_count` records /// sharing a `frame_id`. A consumer reassembles by `(stream_id, session_id, From 61b7bf0e241f0d4cd768e1bc4e589e6eb1531f56 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 10 Sep 2026 22:24:04 +0200 Subject: [PATCH 170/283] Say how Odin admits catalog records, and what it refuses Co-Authored-By: Claude Fable 5.1 --- packages/cultnet-rs/src/media_stream_contracts.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/cultnet-rs/src/media_stream_contracts.rs b/packages/cultnet-rs/src/media_stream_contracts.rs index 59761561..2d16f57a 100644 --- a/packages/cultnet-rs/src/media_stream_contracts.rs +++ b/packages/cultnet-rs/src/media_stream_contracts.rs @@ -52,6 +52,14 @@ pub const GAMECULT_MEDIA_STREAM_REQUEST_SCHEMA: &str = "gamecult.media_stream_re /// A media stream a producer can serve on request, as it appears in Odin. /// +/// Odin admits these without any registration: it derives the document type +/// from the schema id (`prefix.vN` -> `prefix`) and refuses only a short list +/// of authority-owned types (`gamecult.runtime_presence_health`, +/// `odin.runtime_topology_correlation`, `idunn.expected_incarnation`, +/// `idunn.runtime_activation`, `idunn.process_write_lease`, +/// `gamecult.service_trust_anchor`). A new record whose type collided with one +/// of those would be rejected at the catalog with no mention of the collision. +/// /// This is the record a consumer's picker is built from: which streams exist, /// which video and audio sources each can capture, which codecs it can encode, /// and the defaults it would use. It is state, not media — it travels as a From c84cb2e862de6e19614c8bb1be72f08bb6308dac Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 10 Sep 2026 22:50:20 +0200 Subject: [PATCH 171/283] The consumer dials the producer A media stream advertisement now carries `media_endpoint`, where the producer serves it from; the request no longer carries a consumer endpoint. The producer listens and the consumer connects, the same way as every other client/server pair on the mesh, so a viewer's host admits nothing inbound and needs no firewall rule or port forward. Unshipped contract, keys renumbered in place. Audio gets its own channel ("audio": reliable, unordered, media expiry) so one session can carry lossy video under parity and reliable audio together, which is what lets the producer serve both to one dialled-in consumer. Co-Authored-By: Claude Fable 5.1 --- .../cultnet-rs/src/media_stream_contracts.rs | 87 ++++++++++++------- packages/cultnet-rs/src/media_stream_wire.rs | 7 +- packages/cultnet-rs/src/rudp.rs | 13 ++- packages/cultnet-rs/tests/cultnet.rs | 20 +++-- 4 files changed, 89 insertions(+), 38 deletions(-) diff --git a/packages/cultnet-rs/src/media_stream_contracts.rs b/packages/cultnet-rs/src/media_stream_contracts.rs index 2d16f57a..5704912e 100644 --- a/packages/cultnet-rs/src/media_stream_contracts.rs +++ b/packages/cultnet-rs/src/media_stream_contracts.rs @@ -62,7 +62,7 @@ pub const GAMECULT_MEDIA_STREAM_REQUEST_SCHEMA: &str = "gamecult.media_stream_re /// /// This is the record a consumer's picker is built from: which streams exist, /// which video and audio sources each can capture, which codecs it can encode, -/// and the defaults it would use. It is state, not media — it travels as a +/// the defaults it would use, and where it serves the stream from. It is state, not media — it travels as a /// CultMesh document through Odin, never on the media channel — and it names no /// consumer. `producer_id` is the runtime that answers requests for it. /// @@ -106,10 +106,16 @@ pub struct GameCultMediaStreamAdvertisementRecord { pub default_latency_budget_ms: u32, #[cultcache(key = 14)] pub media_packet_bytes: u32, - /// The CultNet RUDP connection id the producer dials the receiver with. + /// `host:port` the producer serves this stream from. A consumer dials it + /// with `media_connection_id` once its request is answered `running`; + /// the producer listens. The consumer's host admits nothing inbound, + /// which is what lets a viewer install a plugin without opening a port. #[cultcache(key = 15)] - pub media_connection_id: u32, + pub media_endpoint: String, + /// The CultNet RUDP connection id a consumer dials `media_endpoint` with. #[cultcache(key = 16)] + pub media_connection_id: u32, + #[cultcache(key = 17)] pub updated_at: String, } @@ -119,6 +125,9 @@ pub struct GameCultMediaStreamAdvertisementRecord { /// key, so a consumer watches one document for the outcome. A newer request for /// the same `stream_id` and `receiver_id` supersedes an older one. /// +/// It carries no consumer endpoint. The consumer dials the advertised +/// `media_endpoint` and identifies itself on the wire by `receiver_id`. +/// /// Keyed by `media_stream_request_key(stream_id, receiver_id)`. #[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] #[cultcache( @@ -134,35 +143,32 @@ pub struct GameCultMediaStreamRequestRecord { pub producer_id: String, #[cultcache(key = 3)] pub receiver_id: String, - /// `host:port` the producer should dial with the advertised connection id. - #[cultcache(key = 4)] - pub receiver_endpoint: String, /// `start` or `stop`. - #[cultcache(key = 5)] + #[cultcache(key = 4)] pub action: String, /// `pending`, `running`, `stopped`, or `failed`; the producer owns it after /// `pending`. - #[cultcache(key = 6)] + #[cultcache(key = 5)] pub state: String, /// Empty means no video. - #[cultcache(key = 7)] + #[cultcache(key = 6)] pub video_source_id: String, /// Empty means no audio. - #[cultcache(key = 8)] + #[cultcache(key = 7)] pub audio_source_id: String, - #[cultcache(key = 9)] + #[cultcache(key = 8)] pub video_codec: String, - #[cultcache(key = 10)] + #[cultcache(key = 9)] pub audio_codec: String, - #[cultcache(key = 11)] + #[cultcache(key = 10)] pub video_bitrate_kbps: u32, - #[cultcache(key = 12)] + #[cultcache(key = 11)] pub latency_budget_ms: u32, - #[cultcache(key = 13)] + #[cultcache(key = 12)] pub media_packet_bytes: u32, - #[cultcache(key = 14)] + #[cultcache(key = 13)] pub detail: String, - #[cultcache(key = 15)] + #[cultcache(key = 14)] pub updated_at: String, } @@ -218,6 +224,12 @@ pub fn validate_media_stream_advertisement( if record.media_connection_id == 0 { return Err(anyhow!("media stream advertisement media_connection_id must be non-zero")); } + if !is_host_port(&record.media_endpoint) { + return Err(anyhow!( + "media stream advertisement media_endpoint {:?} must be host:port", + record.media_endpoint + )); + } Ok(()) } @@ -251,12 +263,6 @@ pub fn validate_media_stream_request( )); } if record.action == "start" { - if record.receiver_endpoint.parse::().is_err() { - return Err(anyhow!( - "media stream request receiver_endpoint {:?} must be host:port", - record.receiver_endpoint - )); - } if record.video_source_id.is_empty() && record.audio_source_id.is_empty() { return Err(anyhow!("media stream request asks for neither video nor audio")); } @@ -270,6 +276,16 @@ pub fn validate_media_stream_request( Ok(()) } +/// A hostname or IP and a non-zero port. Not `SocketAddr`: a producer may +/// advertise a name the consumer resolves. +fn is_host_port(value: &str) -> bool { + let Some((host, port)) = value.rsplit_once(':') else { + return false; + }; + let host = host.trim_start_matches('[').trim_end_matches(']'); + !host.is_empty() && port.parse::().is_ok_and(|port| port != 0) +} + #[cfg(test)] mod media_stream_catalog_tests { use super::*; @@ -291,6 +307,7 @@ mod media_stream_catalog_tests { default_video_bitrate_kbps: 12_000, default_latency_budget_ms: 250, media_packet_bytes: 848, + media_endpoint: "192.168.178.20:5220".into(), media_connection_id: 0x6d75_0001, updated_at: "2026-09-10T00:00:00Z".into(), } @@ -302,7 +319,6 @@ mod media_stream_catalog_tests { stream_id: "muninn.raven.av.rudp".into(), producer_id: "raven".into(), receiver_id: "starfire.obs".into(), - receiver_endpoint: "192.168.178.146:5204".into(), action: "start".into(), state: "pending".into(), video_source_id: "display:0".into(), @@ -342,11 +358,23 @@ mod media_stream_catalog_tests { assert!(validate_media_stream_advertisement(&record).is_ok(), "no audio, no requirement"); } + /// The producer is the listener, so it must say where. #[test] - fn a_start_needs_somewhere_to_send_and_something_to_send() { - let mut record = request(); - record.receiver_endpoint = "starfire".into(); - assert!(validate_media_stream_request(&record).unwrap_err().to_string().contains("host:port")); + fn an_advertisement_says_where_the_stream_is_served() { + for bad in ["", "raven", "raven:", "raven:0", ":5220"] { + let mut record = advertisement(); + record.media_endpoint = bad.into(); + assert!(validate_media_stream_advertisement(&record).unwrap_err().to_string().contains("host:port"), "{bad:?}"); + } + for good in ["raven:5220", "10.77.0.2:5220", "[::1]:5220"] { + let mut record = advertisement(); + record.media_endpoint = good.into(); + assert!(validate_media_stream_advertisement(&record).is_ok(), "{good:?}"); + } + } + + #[test] + fn a_start_needs_something_to_send() { let mut record = request(); record.video_source_id.clear(); record.audio_source_id.clear(); @@ -357,10 +385,9 @@ mod media_stream_catalog_tests { } #[test] - fn a_stop_needs_no_endpoint_or_sources() -> anyhow::Result<()> { + fn a_stop_needs_no_sources() -> anyhow::Result<()> { let mut record = request(); record.action = "stop".into(); - record.receiver_endpoint.clear(); record.video_source_id.clear(); record.audio_source_id.clear(); validate_media_stream_request(&record) diff --git a/packages/cultnet-rs/src/media_stream_wire.rs b/packages/cultnet-rs/src/media_stream_wire.rs index fb1b1f8d..9b7fbc1b 100644 --- a/packages/cultnet-rs/src/media_stream_wire.rs +++ b/packages/cultnet-rs/src/media_stream_wire.rs @@ -35,9 +35,14 @@ use crate::media_stream_contracts::{ GameCultMediaVideoAccessUnitRecord, GameCultMediaVideoParityShardRecord, }; -/// The CultNet channel media rides. +/// The CultNet channel video and receiver feedback ride. pub const GAMECULT_MEDIA_CHANNEL: &str = "media"; +/// The CultNet channel audio rides. Audio has its own channel so one session +/// can carry it reliably with a short expiry while video stays lossy under +/// parity; the RUDP transport profile owns each channel's delivery. +pub const GAMECULT_MEDIA_AUDIO_CHANNEL: &str = "audio"; + /// One media record on its way somewhere. #[derive(Clone, Debug, PartialEq, Eq)] pub enum GameCultMediaWireRecord { diff --git a/packages/cultnet-rs/src/rudp.rs b/packages/cultnet-rs/src/rudp.rs index b6a8fe95..f5a31e76 100644 --- a/packages/cultnet-rs/src/rudp.rs +++ b/packages/cultnet-rs/src/rudp.rs @@ -2187,6 +2187,17 @@ pub fn create_rudp_transport_profile( max_pending_reliable_packets: options.max_pending_reliable_packets, reliable_expire_after_ms: options.media_reliable_expire_after_ms, }, + // Audio beside lossy video on one session: reliable, but a packet + // older than the media expiry is not worth a retransmit. + CultNetTransportChannel { + channel_id: "audio".to_string(), + delivery: CultNetTransportDelivery::Reliable, + ordering: CultNetTransportOrdering::Unordered, + max_payload_bytes: options.max_payload_bytes, + max_fragment_bytes: options.max_fragment_bytes, + max_pending_reliable_packets: options.max_pending_reliable_packets, + reliable_expire_after_ms: options.media_reliable_expire_after_ms, + }, ], }], } @@ -2352,7 +2363,7 @@ fn channel_send_options( // The one channel whose delivery a caller chooses. Media that has gone // stale is worth dropping, not retransmitting: a reliable media channel // under loss adds load exactly when the link has least to give. - "media" => CultNetRudpSendOptions { + "media" | "audio" => CultNetRudpSendOptions { reliable: matches!(delivery, CultNetTransportDelivery::Reliable), ordered: false, sequenced: false, diff --git a/packages/cultnet-rs/tests/cultnet.rs b/packages/cultnet-rs/tests/cultnet.rs index 92401305..b3adc7f4 100644 --- a/packages/cultnet-rs/tests/cultnet.rs +++ b/packages/cultnet-rs/tests/cultnet.rs @@ -428,6 +428,12 @@ fn rudp_transport_profile_advertises_state_and_realtime_channels() { CultNetTransportOrdering::Unordered, Some(64) ), + ( + "audio", + CultNetTransportDelivery::Reliable, + CultNetTransportOrdering::Unordered, + Some(64) + ), ] ); } @@ -2828,7 +2834,7 @@ fn accept_rudp_session(session: &mut CultNetRudpSession, connection_id: u32) -> } #[test] -fn rudp_profile_expires_only_the_media_channel() -> Result<()> { +fn rudp_profile_expires_only_the_media_channels() -> Result<()> { let socket = std::net::UdpSocket::bind("127.0.0.1:0")?; let peer = socket.local_addr()?; let options = CultNetRudpSocketTransportOptions::client("expiry-profile", socket, peer, 11); @@ -2842,12 +2848,14 @@ fn rudp_profile_expires_only_the_media_channel() -> Result<()> { .map(|channel| (channel.channel_id.as_str(), channel.reliable_expire_after_ms)) .collect::>(); - assert!( - channels.contains(&("media", Some(75))), - "the media channel advertises its expiry so a peer can see it: {channels:?}" - ); + for media_channel in ["media", "audio"] { + assert!( + channels.contains(&(media_channel, Some(75))), + "the {media_channel} channel advertises its expiry so a peer can see it: {channels:?}" + ); + } for (channel_id, expiry) in &channels { - if *channel_id != "media" { + if !matches!(*channel_id, "media" | "audio") { assert_eq!( *expiry, None, "state channel {channel_id} must never expire a reliable send" From 47b9fc4ee3a4824327623d7efc9d7614d96b5912 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Fri, 11 Sep 2026 01:21:37 +0200 Subject: [PATCH 172/283] A reader returns "nothing" only when nothing is waiting Both RUDP socket readers returned None after consuming a packet that carried no frame or event for the caller: an acknowledgement, a ping, a fragment that completed nothing yet. A caller that polls once per send therefore read one incoming datagram per outgoing one, and fell behind its peer's acknowledgements as soon as a reliable channel shared the session; every unacknowledged packet was then resent, and the resends starved the sends. Measured on the media path 2026-09-10: 7 video frames in 9 s with reliable audio on, 266 without. Readers now consume no-event packets and keep reading; None means the socket is empty. The client no longer acknowledges unreliable frames. They carry no sequence, so the ACK told the sender nothing and cost it one datagram to read for every one it sent. The fragment-set bound test now asserts eviction, which is what the bound has done since the fuse was cut earlier today; the old assertion was hiding behind a truncated test run. Co-Authored-By: Claude Fable 5.1 --- packages/cultnet-rs/src/rudp.rs | 66 ++++++++++++++------ packages/cultnet-rs/tests/rudp_server_hub.rs | 63 ++++++++++++++++++- 2 files changed, 109 insertions(+), 20 deletions(-) diff --git a/packages/cultnet-rs/src/rudp.rs b/packages/cultnet-rs/src/rudp.rs index f5a31e76..174739be 100644 --- a/packages/cultnet-rs/src/rudp.rs +++ b/packages/cultnet-rs/src/rudp.rs @@ -1538,11 +1538,26 @@ impl CultNetRudpServerHub { Ok(true) } + /// The next event, or `None` only when nothing is waiting on the socket. + /// + /// Packets that carry no event for the caller — acknowledgements, pings, + /// a repeated Connect, a fragment that completes nothing yet — are + /// consumed here and reading continues. Returning `None` after one of + /// those made a caller that polls once per send fall behind its own + /// peers' acknowledgements, and a reliable channel then resent everything. pub fn receive_event_once(&mut self) -> Result> { - if let Some(event) = self.pending_events.pop_front() { - return Ok(Some(event)); + loop { + if let Some(event) = self.pending_events.pop_front() { + return Ok(Some(event)); + } + if !self.receive_packet_once()? { + return Ok(None); + } } + } + /// Reads one datagram and applies it. `false` when the socket is empty. + fn receive_packet_once(&mut self) -> Result { let mut wire = vec![0_u8; 65_535]; let (received, remote_addr) = match self.socket.recv_from(&mut wire) { Ok(value) => value, @@ -1551,7 +1566,7 @@ impl CultNetRudpServerHub { || error.kind() == ErrorKind::TimedOut || error.kind() == ErrorKind::ConnectionReset => { - return Ok(None); + return Ok(false); } Err(error) => return Err(error.into()), }; @@ -1559,7 +1574,7 @@ impl CultNetRudpServerHub { self.stats.bytes_received += received as u64; let packet = decode_rudp_packet(&wire)?; if packet.connection_id != self.connection_id { - return Ok(None); + return Ok(true); } if packet.packet_type == CultNetRudpPacketType::Connect { @@ -1572,7 +1587,7 @@ impl CultNetRudpServerHub { .pending_accept_for_resend(now_ms()) .unwrap_or_else(|| peer.session.create_ack()); self.send_packet(remote_addr, &reply)?; - return Ok(None); + return Ok(true); } if !self.peers.contains_key(&remote_addr) && self.peers.len() >= self.max_peers { return Err(anyhow!("RUDP server hub peer limit reached")); @@ -1613,11 +1628,11 @@ impl CultNetRudpServerHub { } self.pending_events .push_back(CultNetRudpServerEvent::Connected { session: context }); - return Ok(self.pending_events.pop_front()); + return Ok(true); } let Some(peer) = self.peers.get_mut(&remote_addr) else { - return Ok(None); + return Ok(true); }; let result = peer.session.receive(&packet, now_ms())?; let context = peer.context.clone(); @@ -1660,7 +1675,7 @@ impl CultNetRudpServerHub { }); self.peers.remove(&remote_addr); } - Ok(self.pending_events.pop_front()) + Ok(true) } pub fn poll_resends(&mut self) -> Result<()> { @@ -1923,11 +1938,23 @@ impl CultNetRudpSocketTransportConnection { } } + /// The next delivered frame, or `None` only when nothing is waiting on + /// the socket. Acknowledgements, pongs and incomplete fragments are + /// consumed and reading continues; see the hub's `receive_event_once`. pub fn receive_once(&mut self) -> Result> { - if let Some(frame) = self.delivered_frames.pop_front() { - return Ok(Some(frame)); + loop { + if let Some(frame) = self.delivered_frames.pop_front() { + return Ok(Some(frame)); + } + if !self.receive_packet_once()? { + return Ok(None); + } } + } + /// Reads one datagram and applies it. `false` when the socket is empty + /// or the session has been disconnected. + fn receive_packet_once(&mut self) -> Result { let mut wire = vec![0_u8; 65_535]; let (received, remote_addr) = match self.socket.recv_from(&mut wire) { Ok(value) => value, @@ -1936,7 +1963,7 @@ impl CultNetRudpSocketTransportConnection { || error.kind() == ErrorKind::TimedOut || error.kind() == ErrorKind::ConnectionReset => { - return Ok(None); + return Ok(false); } Err(error) => return Err(error.into()), }; @@ -1951,14 +1978,14 @@ impl CultNetRudpSocketTransportConnection { { self.remote_addr = Some(remote_addr); } else { - return Ok(None); + return Ok(true); } } } else { if self.mode == CultNetRudpSocketMode::Server && packet.packet_type != CultNetRudpPacketType::Connect { - return Ok(None); + return Ok(true); } self.remote_addr = Some(remote_addr); } @@ -1968,7 +1995,7 @@ impl CultNetRudpSocketTransportConnection { self.session.reset_peer_state(); let accept = self.session.accept_connect(&packet, now_ms(), Vec::new())?; self.send_packet(&accept)?; - return Ok(None); + return Ok(true); } let result = self.session.receive(&packet, now_ms())?; @@ -1983,7 +2010,7 @@ impl CultNetRudpSocketTransportConnection { } if result.disconnected { self.disconnect_reason = Some(result.disconnect_reason); - return Ok(None); + return Ok(false); } for frame in result.delivered { @@ -1993,13 +2020,14 @@ impl CultNetRudpSocketTransportConnection { }); self.stats.frames_received += 1; } - let frame = self.delivered_frames.pop_front(); - if packet.reliable || packet.packet_type == CultNetRudpPacketType::Accept || frame.is_some() - { + // Only what the sender is waiting on is acknowledged. An unreliable + // frame carries no sequence, so an ACK for it tells the sender + // nothing and costs it one datagram to read for every one it sent. + if packet.reliable || packet.packet_type == CultNetRudpPacketType::Accept { let ack = self.session.create_ack_for_received(packet.sequence); self.send_packet(&ack)?; } - Ok(frame) + Ok(true) } pub fn poll_resends(&mut self) -> Result<()> { diff --git a/packages/cultnet-rs/tests/rudp_server_hub.rs b/packages/cultnet-rs/tests/rudp_server_hub.rs index cb765a33..201cf3b4 100644 --- a/packages/cultnet-rs/tests/rudp_server_hub.rs +++ b/packages/cultnet-rs/tests/rudp_server_hub.rs @@ -399,7 +399,12 @@ fn session_and_hub_reject_configured_memory_bounds() -> Result<()> { )?; let second_set = sender.send_many("schema", vec![5, 6, 7, 8], fragment_options, Some(2))?; receiver.receive(&first_set[0], 2)?; - assert!(receiver.receive(&second_set[0], 2).is_err()); + // The fragment-set bound evicts the stalest incomplete set rather than + // refusing the packet: a receiver that dies at its bound under loss is a + // fuse, not a limit (measured 2026-09-10, see tests/cultnet.rs). + assert_eq!(receiver.fragment_sets_evicted(), 0); + receiver.receive(&second_set[0], 2)?; + assert_eq!(receiver.fragment_sets_evicted(), 1, "the first set was evicted for the second"); let server_socket = socket()?; let server_addr = server_socket.local_addr()?; @@ -511,3 +516,59 @@ fn replay_history_is_bounded_and_idle_hub_sessions_expire() -> Result<()> { assert!(hub.sessions().is_empty()); Ok(()) } + +/// A packet that carries no event — an acknowledgement, a ping — must not +/// make the reader report "nothing waiting" while frames sit behind it. +/// A caller that polls once per send fell behind its peer's acknowledgements +/// this way and a reliable channel resent everything. +#[test] +fn a_reader_does_not_stop_at_a_packet_that_carries_no_event() -> Result<()> { + let mut hub = CultNetRudpServerHub::new(CultNetRudpServerHubOptions::new( + "hub", + socket()?, + CONNECTION_ID, + ))?; + let mut peer = client(hub.local_addr()?)?; + let session = connect(&mut hub, &mut peer, b"evidence")?; + + // Hub side: a ping (reply, no event) ahead of a reliable frame. + peer.ping(b"keepalive".to_vec())?; + peer.send("schema", b"after the ping".to_vec())?; + std::thread::sleep(Duration::from_millis(20)); + match hub.receive_event_once()? { + Some(CultNetRudpServerEvent::Frame { frame, .. }) => { + assert_eq!(frame.payload, b"after the ping"); + } + other => panic!("the first read must reach the frame behind the ping, got {other:?}"), + } + + // Client side: the hub's acknowledgement of that frame is queued ahead of + // two unreliable frames; the client must reach both without a "nothing" + // in between, and must not acknowledge unreliable frames back. + let mut unreliable_hub_options = + CultNetRudpServerHubOptions::new("hub-unreliable", socket()?, CONNECTION_ID); + unreliable_hub_options.media_delivery = Some(CultNetTransportDelivery::Unreliable); + let mut media_hub = CultNetRudpServerHub::new(unreliable_hub_options)?; + let mut media_client = client(media_hub.local_addr()?)?; + let media_session = connect(&mut media_hub, &mut media_client, b"media")?; + media_client.send("schema", b"reliable, will be acked".to_vec())?; + std::thread::sleep(Duration::from_millis(20)); + while media_hub.receive_event_once()?.is_some() {} + media_hub.send(&media_session, "media", b"one".to_vec())?; + media_hub.send(&media_session, "media", b"two".to_vec())?; + std::thread::sleep(Duration::from_millis(20)); + let before = media_hub.stats().bytes_received; + let first = media_client.receive_once()?.expect("the first read reaches the frame behind the ack"); + let second = media_client.receive_once()?.expect("the second frame follows"); + assert_eq!((first.payload, second.payload), (b"one".to_vec(), b"two".to_vec())); + assert!(media_client.receive_once()?.is_none()); + std::thread::sleep(Duration::from_millis(20)); + while media_hub.receive_event_once()?.is_some() {} + assert_eq!( + media_hub.stats().bytes_received, + before, + "unreliable frames are not acknowledged; the hub read nothing back" + ); + let _ = session; + Ok(()) +} From c2a9a6e526390808ef195759056fda0b9a55d8a3 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Fri, 11 Sep 2026 02:44:17 +0200 Subject: [PATCH 173/283] Windows atomic replace waits out a transient reader A concurrent reader of the store's destination file (another process opening it, an indexer, an antivirus scan) makes MoveFileExW fail with a sharing or access error for as long as it holds the handle. That is transient by construction; treating the first refusal as the outcome killed Muninn serve on 2026-09-11 the moment a status CLI overlapped a write. The replace retries such errors for up to half a second. The test holds the destination open from another thread and expects the replace to outlast it. Co-Authored-By: Claude Fable 5.1 --- packages/cultcache-rs/src/lib.rs | 84 ++++++++++++++++++++++++++------ 1 file changed, 69 insertions(+), 15 deletions(-) diff --git a/packages/cultcache-rs/src/lib.rs b/packages/cultcache-rs/src/lib.rs index ba7088e5..36953620 100644 --- a/packages/cultcache-rs/src/lib.rs +++ b/packages/cultcache-rs/src/lib.rs @@ -2662,23 +2662,77 @@ fn replace_file_atomically(staged: &Path, destination: &Path) -> Result<()> { .encode_wide() .chain(std::iter::once(0)) .collect::>(); - let success = unsafe { - MoveFileExW( - staged_wide.as_ptr(), - destination_wide.as_ptr(), - MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH, - ) - }; - if success == 0 { - return Err(std::io::Error::last_os_error()).with_context(|| { - format!( - "failed to atomically replace {} with {}", - destination.display(), - staged.display() + // A concurrent reader of the destination (another process opening the + // store, an indexer, an antivirus scan) makes the replace fail with a + // sharing or access error for as long as it holds the handle. That is + // transient by construction; a daemon that treats it as fatal dies on + // the first overlap (Muninn serve did, 2026-09-11). Retry briefly. + const ERROR_ACCESS_DENIED: i32 = 5; + const ERROR_SHARING_VIOLATION: i32 = 32; + const ERROR_LOCK_VIOLATION: i32 = 33; + const ATTEMPTS: u32 = 25; + const BACKOFF: std::time::Duration = std::time::Duration::from_millis(20); + let mut attempt = 0; + loop { + let success = unsafe { + MoveFileExW( + staged_wide.as_ptr(), + destination_wide.as_ptr(), + MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH, ) - }); + }; + if success != 0 { + return Ok(()); + } + let error = std::io::Error::last_os_error(); + attempt += 1; + let transient = matches!( + error.raw_os_error(), + Some(ERROR_ACCESS_DENIED | ERROR_SHARING_VIOLATION | ERROR_LOCK_VIOLATION) + ); + if !transient || attempt >= ATTEMPTS { + return Err(error).with_context(|| { + format!( + "failed to atomically replace {} with {} after {attempt} attempt(s)", + destination.display(), + staged.display() + ) + }); + } + std::thread::sleep(BACKOFF); + } +} + +#[cfg(all(test, windows))] +mod windows_replace_tests { + use super::replace_file_atomically; + use std::os::windows::fs::OpenOptionsExt; + + /// A reader holding the destination open with no sharing makes the + /// replace fail for as long as it holds on; it must succeed once the + /// reader lets go, not report the first refusal as the outcome. + #[test] + fn a_replace_waits_out_a_reader_that_holds_the_destination() { + let dir = std::env::temp_dir().join(format!("cultcache-replace-{}", std::process::id())); + std::fs::create_dir_all(&dir).unwrap(); + let destination = dir.join("store.cc"); + let staged = dir.join("store.cc.tmp"); + std::fs::write(&destination, b"old").unwrap(); + std::fs::write(&staged, b"new").unwrap(); + let held = std::fs::OpenOptions::new() + .read(true) + .share_mode(0) + .open(&destination) + .unwrap(); + let releaser = std::thread::spawn(move || { + std::thread::sleep(std::time::Duration::from_millis(120)); + drop(held); + }); + replace_file_atomically(&staged, &destination).expect("the replace outlasts the reader"); + releaser.join().unwrap(); + assert_eq!(std::fs::read(&destination).unwrap(), b"new"); + let _ = std::fs::remove_dir_all(&dir); } - Ok(()) } #[cfg(unix)] From e9e9c60b0f537783d6c109713cf66fabd38af453 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 13 Sep 2026 14:10:10 +0200 Subject: [PATCH 174/283] REC-102: cut stale generated mirrors and a dead maintenance receipt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deletes four confirmed-dead tracked files: - CultLib.txt, src/GameCult.Caching/GameCult.Caching.txt, src/GameCult.Unity/Assets/UI/UI.txt: concatenated snapshot copies of live source, carrying stale E: drive provenance and obsolete dependency versions. Live source under src/ remains the owner. - tests/GameCult.Networking.Tests/lcov.info: tracked coverage output. .vscode/tasks.json:14 still generates it fresh via "/p:CoverletOutput=./lcov.info" on every coverage run, so tracking the stale committed copy in git is the liability, not the generation step. - .voidbot/status/void-memory-maintenance.json: a one-time "starting" receipt (added whole in 4813570, never touched again) naming a dead E:\Projects\CultLib path and an unimplemented repo_face_heartbeat launcher. VoidBot's actual heartbeat state lives at .voidbot/status/repo-face-heartbeats.{cc,json} (see packages/config/src/index.ts REPO_FACE_HEARTBEAT_STATE_PATH) — a different file entirely; nothing reads this one. Kill attempts: - git grep -n for each of "CultLib\.txt", "GameCult\.Caching\.txt", "UI\.txt", "lcov\.info" across origin/main, excluding each file's own path: only .voidbot birth/distiller snapshots (auto-generated onboarding file-listing catalogs, not functional readers) and the one real lcov.info producer in .vscode/tasks.json. - rg across all of F:/Projects (excluding target/node_modules/.git): gamecult-site's docs/research/gamecult-org-repo-ledger.json lists "CultLib.txt" as a filename in a static historical repo-file inventory (not a functional consumer); Aetheria/docs/cultcache-migration-cut.md cites GameCult.Caching.txt:157 as an evidence line number in a migration-history note (stale citation after this cut, not a functional break — flagged for the record, not fixed here since that doc is out of scope). - voidbot MCP search for void-memory-maintenance.json / repo_face_heartbeat found only the unrelated repo-face-heartbeats state path, confirming no reader. Collision check: git diff --stat origin/main against each of the other 4 CultLib worktrees (codex/recover-aetheria-authority, codex/delvehold-isosurface, claude/media-stream-catalog, and the two detached-HEAD worktrees, both confirmed ancestors of origin/main) over these five paths: all empty, no in-flight work touches them. REC-102 Co-Authored-By: Claude Sonnet 5 --- .voidbot/status/void-memory-maintenance.json | 7 - CultLib.txt | 132 - src/GameCult.Caching/GameCult.Caching.txt | 1213 -------- src/GameCult.Unity/Assets/UI/UI.txt | 2917 ------------------ tests/GameCult.Networking.Tests/lcov.info | 2537 --------------- 5 files changed, 6806 deletions(-) delete mode 100644 .voidbot/status/void-memory-maintenance.json delete mode 100644 CultLib.txt delete mode 100644 src/GameCult.Caching/GameCult.Caching.txt delete mode 100644 src/GameCult.Unity/Assets/UI/UI.txt delete mode 100644 tests/GameCult.Networking.Tests/lcov.info diff --git a/.voidbot/status/void-memory-maintenance.json b/.voidbot/status/void-memory-maintenance.json deleted file mode 100644 index 0d0b876a..00000000 --- a/.voidbot/status/void-memory-maintenance.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "status": "starting", - "startedAt": "2026-06-14T19:46:12.715Z", - "stateFile": "E:\\Projects\\CultLib\\.voidbot\\state\\libby.cc", - "launcher": "repo_face_heartbeat", - "reason": "repo_face_stale_short_term_memory" -} diff --git a/CultLib.txt b/CultLib.txt deleted file mode 100644 index 4755ac07..00000000 --- a/CultLib.txt +++ /dev/null @@ -1,132 +0,0 @@ - - -// E:\Projects\CultLib\src\GameCult.Caching\GameCult.Caching.csproj - - - - CultCache: Concurrent polymorphic cache with modular backing stores for .NET - - - - - - - - - - -// E:\Projects\CultLib\src\GameCult.Caching.MessagePack\GameCult.Caching.MessagePack.csproj - - - - File-based MessagePack backing store for CultCache - - - - - - - - - -// E:\Projects\CultLib\src\GameCult.Caching.MessagePack.Generator\GameCult.Caching.MessagePack.Generator.csproj - - - - - - true - enable - true - false - - - Source generator that emits MessagePack formatters for DatabaseEntry subclasses. - MessagePack;SourceGenerator;DatabaseEntry - - - - - - - - - - - - - - - - -// E:\Projects\CultLib\src\GameCult.Logging\GameCult.Logging.csproj - - - - Simple pluggable logging interface for CultLib - - - -// E:\Projects\CultLib\src\GameCult.Logging.Unity\GameCult.Logging.Unity.csproj - - - - Unity integration for GameCult.Logging - - - - - - - - -// E:\Projects\CultLib\src\GameCult.Networking\GameCult.Networking.csproj - - - - CultNet: Secure, high-performance messaging for games/servers - - - - - - - - - - - - - -// E:\Projects\CultLib\tests\GameCult.Networking.Tests\GameCult.Networking.Tests.csproj - - - - - net8.0 - false - GameCult.Networking.Tests - - - - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - all - - - - diff --git a/src/GameCult.Caching/GameCult.Caching.txt b/src/GameCult.Caching/GameCult.Caching.txt deleted file mode 100644 index ab959478..00000000 --- a/src/GameCult.Caching/GameCult.Caching.txt +++ /dev/null @@ -1,1213 +0,0 @@ - - -// E:\Projects\CultLib\src\GameCult.Caching\CultCache.cs - -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Threading.Tasks; -using ConcurrentCollections; -using GameCult.Logging; -using MessagePack; -using R3; - -namespace GameCult.Caching -{ - ///

    - /// Specifies that the decorated class contains global settings. - /// Use this attribute to mark classes intended to hold application-wide configuration or settings. - /// - [AttributeUsage(AttributeTargets.Class)] - public class GlobalSettingsAttribute : Attribute { } - - /// - /// Represents an in-memory and persistent cache for objects, supporting global entries, - /// named entries, generic field indexes, and multiple backing stores. Provides thread-safe operations for adding, - /// retrieving, indexing, and removing entries, with support for event notifications and logging. - /// - /// - /// - /// Features: - /// - /// Supports multiple s for persistence and synchronization. - /// Handles global settings entries via . - /// Provides fast lookup by ID, name (for ), and indexed fields. - /// Allows registering generic indexes for any public field of a type. - /// Thread-safe via and . - /// Notifies on entry updates via event. - /// Supports both synchronous and asynchronous add operations. - /// Integrates with for error and event logging. - /// - /// - /// - /// Usage: - /// - /// var cache = new CultCache(); - /// cache.RegisterIndex<PlayerData>("Email"); - /// cache.AddAsync(new PlayerData { ... }).GetAwaiter().GetResult(); - /// var player = cache.GetByIndex<PlayerData>("Email", "user@example.com"); - /// - /// - /// - public class CultCache : IDisposable - { - private readonly object addLock = new object(); // Retained for synchronous Add compatibility - - /// - /// Occurs when a is updated. - /// The event provides the old and new instances. - /// - /// - /// The first parameter is the previous entry, and the second parameter is the updated entry. - /// The first parameter will be null if the entry is newly added, - /// and the second parameter will be null if the entry is deleted. - /// - public event Action? OnUpdate; - - private readonly List _backingStores = new(); - private readonly ConcurrentDictionary _typeStores = new(); - private readonly ConcurrentDictionary _storeTypes = new(); - private readonly ConcurrentDictionary _entries = new(); - private readonly ConcurrentDictionary _globals = new(); - private readonly ConcurrentDictionary> _types = new(); - private readonly ConcurrentDictionary> _nameToIdMap = new(); - // Generic indexes: Map (Type, FieldName) -> (Value -> ID). Allows registering indexes for any field - private readonly ConcurrentDictionary<(Type Type, string FieldName), ConcurrentDictionary> _indexes = new(); - // Cache getters per type (list of (field, getter) for that type only). Avoids scanning all indexes. - private readonly ConcurrentDictionary Getter)>> _typeToGetters = new(); - private ILogger _logger = new NullLogger(); - - /// - /// Gets or sets the instance used for logging within the cache. - /// If set to null, a will be used as a fallback. - /// - public ILogger Logger - { - get => _logger; - set => _logger = value ?? new NullLogger(); - } - - /// - /// Gets all objects currently stored in the cache. - /// - public IEnumerable AllEntries => _entries.Values; - - /// - /// Initializes a new instance of the class. - /// Sets up the cache by registering all child classes of . - /// For each child type: - /// - /// Adds a concurrent hash set for caching entries of that type. - /// If the type is marked with , adds it to the global settings and creates an instance. - /// If the type implements , initializes a name-to-ID mapping dictionary. - /// - /// Also sets the static cache reference in . - /// - public CultCache() - { - DatabaseLinkBase.Cache = this; - - foreach (var type in typeof(DatabaseEntry).GetAllChildClasses()) - { - _types.TryAdd(type, new ConcurrentHashSet()); - if (type.GetCustomAttribute() != null) - { - _globals.TryAdd(type, null); - try - { - var global = (DatabaseEntry)Activator.CreateInstance(type)!; - AddAsync(global).GetAwaiter().GetResult(); - _globals[type] = global; // Update after successful add - } - catch (Exception ex) - { - Logger.LogError($"Failed to initialize global {type.Name}: {ex.Message}"); - _globals[type] = null; - } - } - // Initialize name-to-ID map for INamedEntry types - if (typeof(INamedEntry).IsAssignableFrom(type)) - { - _nameToIdMap.TryAdd(type, new ConcurrentDictionary()); - } - } - } - - /// - /// Adds a backing store to the cache system and configures domain type associations and event subscriptions. - /// - /// The instance to add. - /// - /// Optional array of objects representing domain types associated with the backing store. - /// If provided, the store is mapped to these types; otherwise, the store is added to the general backing store list and subscribes to existing stores. - /// - /// - /// - /// If no domain types are specified, the store subscribes to all existing backing stores to receive their updates, - /// ensuring synchronization across stores, with the first store added acting as the primary source of truth. - /// - /// - /// Specifying domain types allows for targeted storage and retrieval of specific types, - /// for example, using a database store for user data and a file-based store for configuration data or game assets. - /// - /// - public void AddBackingStore(CacheBackingStore store, params Type[] domain) - { - if (domain.Length > 0) - { - _storeTypes.TryAdd(store, domain); - foreach (var t in domain) _typeStores.TryAdd(t, store); - } - else - { - foreach (var existingStore in _backingStores) store.SubscribeTo(existingStore); - _backingStores.Add(store); - } - store.EntryAdded.Subscribe(async entry => - { - try // Try-catch logs without swallowing. Added to EntryDeleted for consistency (even though sync) - { - await AddAsync(entry, store); - OnUpdate?.Invoke(null, entry); - } - catch (Exception ex) - { - Logger.LogError($"EntryAdded processing failed for {entry?.ID}: {ex.Message}"); - } - }); - store.EntryUpdated.Subscribe(async entry => - { - try - { - await AddAsync(entry, store); - OnUpdate?.Invoke(entry, entry); - } - catch (Exception ex) - { - Logger.LogError($"EntryUpdated processing failed for {entry?.ID}: {ex.Message}"); - } - }); - store.EntryDeleted.Subscribe(entry => - { - try - { - Remove(entry, store); - OnUpdate?.Invoke(entry, null); - } - catch (Exception ex) - { - Logger.LogError($"EntryDeleted processing failed for {entry?.ID}: {ex.Message}"); - } - }); - store.Logger = Logger; - } - - /// - /// Asynchronously pulls all data from the backing stores. - /// Initiates parallel tasks to execute the PullAll method on each backing store and store type, - /// and waits for all tasks to complete. - /// - /// A task that represents the asynchronous operation. - public async Task PullAllBackingStoresAsync() - { - var tasks = _backingStores.Select(store => Task.Run(store.PullAll)) - .Concat(_storeTypes.Keys.Select(store => Task.Run(store.PullAll))) - .ToArray(); - await Task.WhenAll(tasks); - } - - /// - /// Adds a to the cache asynchronously, updating all relevant maps and indexes. - /// If the entry already exists, cleans up old mappings before updating. - /// Also persists the entry to the backing store if available. - /// - /// The to add or update in the cache. - /// - /// The source from which the entry originated, used internally to avoid redundant writes. - /// Optional; defaults to null. - /// - /// A representing the asynchronous operation. - public async Task AddAsync(DatabaseEntry entry, CacheBackingStore? source = null) - { - if (entry == null) return; - - var type = entry.GetType(); - - // Pre-fetch existing to detect updates (for map/index cleanup) - if (!_entries.TryGetValue(entry.ID, out var existing)) existing = null; - - // Cleanup old maps/indexes BEFORE updating _entries - if (existing != null) - { - // For name map (if updating existing) - if (existing is INamedEntry existingNamed && _nameToIdMap.TryGetValue(type, out var nameMap)) - { - nameMap.TryRemove(existingNamed.EntryName, out _); - } - - // For generic indexes (if registered) - if (_typeToGetters.TryGetValue(type, out var getters)) - { - foreach (var (fieldName, getter) in getters) - { - var oldValue = getter(existing); - if (!string.IsNullOrEmpty(oldValue)) - { - var indexKey = (type, fieldName); - _indexes[indexKey].TryRemove(oldValue, out _); - } - } - } - - // For type sets - _types[existing.GetType()].TryRemove(existing); - foreach (var parentType in existing.GetType().GetParentTypes()) - { - if (_types.TryGetValue(parentType, out var typeSet)) - typeSet.TryRemove(existing); - } - } - - _entries[entry.ID] = entry; - _types[type].Add(entry); // Assumes exists; throws if not (edge case) - foreach (var parentType in type.GetParentTypes()) - { - if (_types.TryGetValue(parentType, out var typeSet)) - typeSet.Add(entry); - } - - if (_globals.ContainsKey(type)) - { - _globals.AddOrUpdate(type, entry, (_, old) => entry); - } - - // Add new values (always, for both new and updates) - // Update name-to-ID map if INamedEntry - if (entry is INamedEntry namedEntry && _nameToIdMap.TryGetValue(type, out var nameMap2)) - { - nameMap2[namedEntry.EntryName] = entry.ID; - } - - // Update generic indexes if registered for this type - if (_typeToGetters.TryGetValue(type, out var getters2)) - { - foreach (var (fieldName, getter) in getters2) - { - var value = getter(entry); - if (!string.IsNullOrEmpty(value)) - { - var indexKey = (type, fieldName); - _indexes[indexKey][value] = entry.ID; - } - } - } - - // Async file write - try - { - if (_typeStores.TryGetValue(type, out var store)) - await Task.Run(() => store.Push(entry)); - else if (_backingStores.Any() && _backingStores.First() != source) - await Task.Run(() => _backingStores.First().Push(entry)); - } - catch (Exception ex) - { - // Log error but don't revert cache update to ensure consistency - Logger.LogError($"Failed to persist entry {entry.ID}: {ex.Message}"); - } - } - - /// - /// Determines whether the specified is a global settings entry. - /// - /// The to check. - /// true if the entry is global; otherwise, false. - public bool IsGlobal(DatabaseEntry entry) => _globals.ContainsKey(entry.GetType()); - - /// - /// Adds all objects from the specified collection to the cache asynchronously. - /// - /// The collection of objects to add. - /// - /// The source from which the entries originated, used to avoid redundant writes. - /// Optional; defaults to null. - /// - /// A representing the asynchronous operation. - public Task AddAllAsync(IEnumerable entries, CacheBackingStore? source = null) - { - var tasks = entries.Select(entry => AddAsync(entry, source)).ToArray(); - return Task.WhenAll(tasks); - } - - /// - /// Retrieves a from the cache by its unique identifier. - /// - /// The unique identifier of the entry to retrieve. - /// The associated with the specified , or null if not found. - public DatabaseEntry Get(Guid guid) - { - _entries.TryGetValue(guid, out var entry); - return entry; - } - - /// - /// Retrieves a of type from the cache by its unique identifier. - /// - /// The type of to retrieve. - /// The unique identifier of the entry to retrieve. - /// The entry of type associated with the specified , or null if not found or not of type . - public T? Get(Guid guid) where T : DatabaseEntry - { - return Get(guid) as T; - } - - /// - /// Retrieves the global instance for the specified type, if it exists. - /// - /// The type of the global entry to retrieve. - /// The global instance associated with the specified type, or null if not found. - public DatabaseEntry? GetGlobal(Type type) - { - _globals.TryGetValue(type, out var entry); - return entry; - } - - /// - /// Retrieves the global instance of type , if it exists. - /// - /// The type of the global entry to retrieve. - /// The global entry of type , or null if not found. - public T? GetGlobal() where T : DatabaseEntry - { - return GetGlobal(typeof(T)) as T; - } - - /// - /// Retrieves all objects of the specified type from the cache. - /// - /// The type of to retrieve. - /// An enumerable collection of objects of the specified type. - public IEnumerable GetAll(Type type) - { - return _types.TryGetValue(type, out var entries) ? entries : Enumerable.Empty(); - } - - /// - /// Retrieves all objects of type from the cache. - /// - /// The type of to retrieve. - /// An enumerable collection of objects from the cache. - public IEnumerable GetAll() where T : DatabaseEntry - { - return _types.TryGetValue(typeof(T), out var entries) ? entries.Cast() : Enumerable.Empty(); - } - - /// - /// Retrieves the unique identifier () of an entry of type by its name. - /// - /// The type of that implements . - /// The name of the entry to look up. - /// The of the entry if found; otherwise, null. - public Guid? GetIdByName(string name) where T : DatabaseEntry, INamedEntry - { - var type = typeof(T); - if (_nameToIdMap.TryGetValue(type, out var nameMap) && nameMap.TryGetValue(name, out var id)) - return id; - return null; - } - - /// - /// Retrieves an entry of type by its name from the cache. - /// - /// The type of that implements . - /// The name of the entry to retrieve. - /// The entry of type if found; otherwise, null. - public T? GetByName(string name) where T : DatabaseEntry, INamedEntry - { - return GetIdByName(name) is { } id ? Get(id) : null; - } - - /// - /// Registers an index for a public member (field or property) of the specified type. - /// This enables fast lookup of entries by the value of the indexed member. - /// Call this method once per member to be indexed. - /// - /// The type of for which to register the index. - /// The name of the public member to index. - /// Thrown if the specified member does not exist on the type. - public void RegisterIndex(string memberName) where T : DatabaseEntry - { - var type = typeof(T); - var key = (type, memberName); - if (_indexes.ContainsKey(key)) - return; // Already registered; ignore - - _indexes[key] = new ConcurrentDictionary(); - - // Cache a getter func for perf. - if (type.GetField(memberName) is { } field) - { - var getter = (Func)(entry => field.GetValue(entry)?.ToString() ?? string.Empty); - _typeToGetters.AddOrUpdate(type, - _ => new List<(string, Func)> { (memberName, getter) }, - (_, list) => { list.Add((memberName, getter)); return list; }); - } - else if (type.GetProperty(memberName) is { } property) - { - var getter = (Func)(entry => property.GetValue(entry)?.ToString() ?? string.Empty); - _typeToGetters.AddOrUpdate(type, - _ => new List<(string, Func)> { (memberName, getter) }, - (_, list) => { list.Add((memberName, getter)); return list; }); - } - else - { - throw new ArgumentException($"No public field or property '{memberName}' on {type.Name}"); - } - } - - /// - /// Retrieves the unique identifier () of an entry of type by the value of an indexed field. - /// - /// The type of for which the index is registered. - /// The name of the indexed field. - /// The value of the indexed field to look up. - /// The of the entry if found; otherwise, null. - public Guid? GetIdByIndex(string fieldName, string value) where T : DatabaseEntry - { - var key = (typeof(T), fieldName); - if (_indexes.TryGetValue(key, out var indexMap) && indexMap.TryGetValue(value, out var id)) - return id; - return null; - } - - /// - /// Retrieves an entry of type by the value of an indexed field from the cache. - /// - /// The type of for which the index is registered. - /// The name of the indexed field. - /// The value of the indexed field to look up. - /// The entry of type if found; otherwise, null. - public T? GetByIndex(string fieldName, string value) where T : DatabaseEntry - { - return GetIdByIndex(fieldName, value) is { } id ? Get(id) : null; - } - - /// - /// Removes the specified from the cache, including all associated indexes, type stores, - /// global references, parent type sets, and name-to-ID mappings. - /// - /// The to remove from the cache. - /// - /// The to exclude from deletion. Used internally to avoid redundant deletions when the entry originates from a specific store. - /// - public void Remove(DatabaseEntry entry, CacheBackingStore? source = null) - { - var type = entry.GetType(); - if (!_entries.TryRemove(entry.ID, out _)) return; - - // Clean up type sets - _types[type].TryRemove(entry); - foreach (var parentType in type.GetParentTypes()) - { - if (_types.TryGetValue(parentType, out var typeSet)) - typeSet.TryRemove(entry); - } - - // Clean up global if applicable - if (_globals.TryGetValue(type, out var global) && global != null && global.Equals(entry)) _globals[type] = null!; - - // Propagate delete to backing stores (except source) - if (_typeStores.TryGetValue(type, out var typeStore)) - typeStore.Delete(entry); - else - { - foreach (var store in _backingStores) - { - if (store != source) - store.Delete(entry); - } - } - - // Clean up name-to-ID map if INamedEntry - if (entry is INamedEntry namedEntry && _nameToIdMap.TryGetValue(type, out var nameMap)) - { - nameMap.TryRemove(namedEntry.EntryName, out _); - } - - // Clean up generic indexes if registered for this type - if (_typeToGetters.TryGetValue(type, out var getters)) - { - foreach (var (fieldName, getter) in getters) - { - var value = getter(entry); - if (!string.IsNullOrEmpty(value)) - { - var indexKey = (type, fieldName); - _indexes[indexKey].TryRemove(value, out _); - } - } - } - } - - /// - public void Dispose() - { - foreach (var store in _backingStores) - if (store is IDisposable d) d.Dispose(); - foreach (var store in _storeTypes.Keys) - if (store is IDisposable d) d.Dispose(); - } - } - - /// - /// Represents a backing store that supports observing real-time changes. - /// - public interface IRealtimeBackingStore - { - /// - /// Begins observing real-time changes in the backing store and triggers appropriate events when changes occur. - /// - public void ObserveChanges(); - } - - /// - /// Represents an abstract backing store for caching objects. - /// Provides mechanisms for pulling, pushing, deleting, and synchronizing entries, as well as event notifications for entry changes. - /// - public abstract class CacheBackingStore : IDisposable - { - private ILogger _logger = new NullLogger(); - - /// - /// Gets or sets the instance used for logging within the cache. - /// If set to null, a will be used as a fallback. - /// - public ILogger Logger - { - get => _logger; - set => _logger = value ?? new NullLogger(); - } - - /// - /// Initializes a new instance of the class. - /// Sets up subjects for entry added, deleted, and updated events. - /// - protected CacheBackingStore() - { - EntryAdded = new Subject(); - EntryDeleted = new Subject(); - EntryUpdated = new Subject(); - } - - /// - /// Pulls all entries from the backing store into the cache. - /// Implementations should load all persisted objects and notify via . - /// - public abstract void PullAll(); - /// - /// Persists the specified to the backing store. - /// Implementations should save or update the entry in the underlying storage. - /// - /// The to persist. - public abstract void Push(DatabaseEntry entry); - /// - /// Deletes the specified from the backing store. - /// Implementations should remove the entry from the underlying storage. - /// - /// The to delete. - public abstract void Delete(DatabaseEntry entry); - /// - /// Persists all objects to the backing store. - /// Implementations should save or update all entries in the underlying storage. - /// - /// - /// If true, performs a soft push (implementation-specific); otherwise, performs a full push. - /// - public abstract void PushAll(bool soft = false); - - /// - /// Gets the subject that notifies when a is added to the backing store. - /// - public Subject EntryAdded { get; } - /// - /// Gets the subject that notifies when a is deleted from the backing store. - /// - public Subject EntryDeleted { get; } - /// - /// Gets the subject that notifies when a is updated in the backing store. - /// - public Subject EntryUpdated { get; } - - /// - /// Stores all objects managed by this backing store, keyed by their unique identifier. - /// - protected ConcurrentDictionary Entries = new(); - - /// - /// Subscribes this backing store to the entry events of another , - /// so that added, deleted, and updated entries in the target store are automatically pushed or deleted in this store. - /// - /// The target to subscribe to. - public void SubscribeTo(CacheBackingStore targetStore) - { - targetStore.EntryAdded.Subscribe(Push); - targetStore.EntryDeleted.Subscribe(Delete); - targetStore.EntryUpdated.Subscribe(Push); - } - - /// - public void Dispose() - { - EntryAdded?.Dispose(); - EntryDeleted?.Dispose(); - EntryUpdated?.Dispose(); - } - } - - /// - /// An abstract cache backing store that persists objects as individual files, - /// organizing them by entry type in subdirectories under a root directory. Supports real-time change observation - /// via and provides serialization/deserialization hooks for custom formats. - /// - /// - /// - /// Each entry type is mapped to its own directory, and entries are stored as files with a configurable extension. - /// The class maintains a mapping between file paths and entry IDs for efficient lookup and change tracking. - /// - /// - /// Real-time changes (creation, modification, deletion) to files are observed and propagated to upstream subscribers - /// using Rx subjects and debounced event handling. - /// - /// - /// Subclasses must implement , , and - /// to define the file format. - /// - /// - public abstract class MultiFileBackingStore : CacheBackingStore, IRealtimeBackingStore, IDisposable - { - /// - /// Gets the root directory where all entry files are stored. - /// - public DirectoryInfo RootDirectory { get; } - /// - /// Maps each type to its corresponding subdirectory. - /// - protected readonly Dictionary EntryTypeDirectories = new(); - /// - /// Maps file paths to their corresponding IDs for quick lookup during change detection. - /// - protected readonly ConcurrentDictionary _filePathToIdMap = new(); - private FileSystemWatcher? watcher; - private Subject? _changedSubject; - - /// - /// Serializes a into a byte array for file storage. - /// - /// The to serialize. - /// A byte array representing the serialized entry. - public abstract byte[] Serialize(DatabaseEntry entry); - /// - /// Deserializes a byte array into a object. - /// - /// The byte array containing the serialized entry. - /// The deserialized object. - public abstract DatabaseEntry Deserialize(byte[] data); - /// - /// Gets the file extension used for storing entries (e.g., ".json", ".msgpack"). - /// - public abstract string Extension { get; } - - /// - /// Initializes a new instance of the class. - /// Creates the root directory if it does not exist and sets up subdirectories for each child type. - /// - /// The path to the root directory for storing entry files. - public MultiFileBackingStore(string path) - { - RootDirectory = new DirectoryInfo(path); - foreach (var type in typeof(DatabaseEntry).GetAllChildClasses()) - { - EntryTypeDirectories[type] = GetDirectoryForType(type); - } - } - - private DirectoryInfo GetDirectoryForType(Type type) - { - var stack = new Stack(); - var t = type; - while (t != null && t != typeof(DatabaseEntry)) - { - stack.Push(t.Name); - t = t.BaseType; - } - stack.Push(RootDirectory.FullName); - // ToArray() copies in LIFO order (top/first: root, then parents, deepest child last) - // Ensures Path.Combine yields: Root\Parent\...\Child - return Directory.CreateDirectory(Path.Combine(stack.ToArray())); - } - - /// - /// Loads all objects from individual files in the root directory and its subdirectories, - /// organized by entry type. Each file is deserialized using , - /// added to the local dictionary, and notifies upstream via . - /// Skips files that cannot be deserialized, logging errors without failing the entire operation. - /// Only processes files matching the . - /// - public override void PullAll() - { - if (!RootDirectory.Exists) return; - - foreach (var directory in EntryTypeDirectories.Values) - { - foreach (var file in directory.EnumerateFiles($"*.{Extension}")) - { - try - { - var entry = Deserialize(File.ReadAllBytes(file.FullName)); - Entries[entry.ID] = entry; - EntryAdded.OnNext(entry); - _filePathToIdMap[file.FullName] = entry.ID; - } - catch (Exception ex) - { - Logger.LogError($"Failed to pull entry from {file.FullName}: {ex.Message}"); - } - } - } - } - - private string GetFileName(DatabaseEntry entry) - { - string name = entry is INamedEntry namedEntry ? namedEntry.EntryName : entry.ID.ToString(); - // Sanitize to prevent invalid chars/path traversal - foreach (char invalid in Path.GetInvalidFileNameChars()) - name = name.Replace(invalid, '_'); - return $"{name}.{Extension}"; - } - - /// - /// Persists the specified to a file in the appropriate type subdirectory. - /// The file name is generated using , which prefers the entry name if available. - /// The entry is serialized via and written to disk. - /// Updates the local dictionary and the for change tracking. - /// Logs errors if the write fails but re-throws to allow caller handling. - /// - /// The to persist to a file. - public override void Push(DatabaseEntry entry) - { - var type = entry.GetType(); - Entries[entry.ID] = entry; - var directory = EntryTypeDirectories[type]; - var filePath = Path.Combine(directory.FullName, GetFileName(entry)); - File.WriteAllBytes(filePath, Serialize(entry)); - _filePathToIdMap[filePath] = entry.ID; - } - - /// - /// Removes the specified from the local dictionary - /// and deletes its corresponding file in the type subdirectory. - /// Updates the and notifies upstream via . - /// File deletion failures are logged but do not prevent local removal or notification. - /// - /// The to delete from storage. - public override void Delete(DatabaseEntry entry) - { - if (Entries.ContainsKey(entry.ID)) - { - var type = entry.GetType(); - Entries.TryRemove(entry.ID, out _); - var directory = EntryTypeDirectories[type]; - var filePath = Path.Combine(directory.FullName, GetFileName(entry)); - _filePathToIdMap.TryRemove(filePath, out _); - var file = new FileInfo(filePath); - if (file.Exists) - file.Delete(); - } - } - - /// - /// Persists all entries in to their respective files by invoking for each. - /// The parameter is ignored in this implementation, as all pushes are full writes. - /// Errors during individual pushes are logged but do not halt the process. - /// Suitable for batch synchronization after bulk changes. - /// - /// If true, performs a soft push (not supported; treated as full push). - public override void PushAll(bool soft = false) - { - foreach (var entry in Entries.Values.ToArray()) Push(entry); - } - - /// - /// Starts monitoring the root directory and its subdirectories for file system changes related to entry files. - /// Initializes a with filters for creation, modification, and deletion events on files matching . - /// Uses debouncing for change events to handle bursty writes (100ms delay via and R3). - /// Disposes any existing watcher before creating a new one to prevent duplicates. - /// Logs a warning if the root directory does not exist and skips observation. - /// Logs info when observation starts successfully. - /// Call this method to enable real-time synchronization with external file modifications. - /// - public void ObserveChanges() - { - if (watcher != null) // Guard against re-creation - Dispose(); - - watcher = new FileSystemWatcher(RootDirectory.FullName, $"*.{Extension}") - { - NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName, - EnableRaisingEvents = true, - IncludeSubdirectories = true - }; - - // Use R3 to throttle events if file writes are bursty - _changedSubject = new Subject(); // For paths - _changedSubject.Debounce(TimeSpan.FromMilliseconds(100)).Subscribe(HandleFileChange); - - watcher.Changed += (sender, args) => - { - _changedSubject.OnNext(args.FullPath); // Debounced handling - }; - watcher.Created += (sender, args) => - { - HandleFileCreation(args.FullPath); - }; - watcher.Deleted += (sender, args) => - { - HandleFileRemoval(args.FullPath); - }; - } - - private void HandleFileCreation(string fullPath) - { - try - { - var entry = Deserialize(File.ReadAllBytes(fullPath)); - Entries[entry.ID] = entry; - _filePathToIdMap[fullPath] = entry.ID; - EntryAdded.OnNext(entry); // Upstream notify - } - catch (Exception ex) - { - Logger.LogError($"Failed to handle creation of {fullPath}: {ex.Message}"); - } - } - - private void HandleFileChange(string fullPath) - { - try - { - var entry = Deserialize(File.ReadAllBytes(fullPath)); - Entries[entry.ID] = entry; - _filePathToIdMap[fullPath] = entry.ID; - EntryUpdated.OnNext(entry); // Upstream notify - } - catch (Exception ex) - { - Logger.LogError($"Failed to handle change in {fullPath}: {ex.Message}"); - } - } - - private void HandleFileRemoval(string fullPath) - { - try - { - // External deletion detected—handle without deserializing - if (_filePathToIdMap.TryGetValue(fullPath, out var id)) - { - _filePathToIdMap.TryRemove(fullPath, out _); // Clean map immediately - - // Emit delete if we have the entry locally - if (Entries.TryGetValue(id, out var entry)) - { - Entries.TryRemove(id, out _); // Sync local dict - EntryDeleted.OnNext(entry); - } - else - { - // Fallback: Stub if race/removed already (rare) - var type = GetTypeFromPath(fullPath); // See helper below - var stub = CreateStubEntry(id, type); - EntryDeleted.OnNext(stub); - Logger.LogWarning($"External deletion of {fullPath} (ID: {id}) with no local entry; emitted stub for cleanup."); - } - } - } - catch (Exception ex) - { - Logger.LogError($"Failed to handle deletion of {fullPath}: {ex.Message}"); - } - } - - // Helper: Infer type from path (e.g., based on directory name matching EntryTypeDirectories keys) - private Type GetTypeFromPath(string filePath) - { - var currentDir = new DirectoryInfo(Path.GetDirectoryName(filePath) ?? string.Empty); - // Walk up the directory tree to find matching EntryTypeDirectories (handles sub-subdirs) - while (currentDir is { Exists: true }) - { - var matchingType = EntryTypeDirectories.FirstOrDefault(kvp => kvp.Value.FullName == currentDir.FullName).Key; - if (matchingType != null) - return matchingType; - currentDir = currentDir.Parent; // Walk up (e.g., from "PlayerData/backup" to "PlayerData") - } - return typeof(DatabaseEntry); // Fallback if no match (e.g., manual file) - } - - // Stub creator (minimal; only for rare fallback—extend if Deletion events need more data) - private DatabaseEntry CreateStubEntry(Guid id, Type type) - { - var entry = (DatabaseEntry)Activator.CreateInstance(type); - typeof(DatabaseEntry).GetField("ID")?.SetValue(entry, id); // Set ID via reflection - return entry; - } - - /// - public new void Dispose() - { - base.Dispose(); - watcher?.Dispose(); - _changedSubject?.Dispose(); - } - } - - /// - /// An abstract cache backing store that persists all objects in a single file. - /// Supports serialization of the entire collection and provides hooks for custom binary formats. - /// Suitable for smaller datasets or when atomic updates are preferred over individual file management. - /// - /// - /// - /// All entries are loaded and saved as a single array in the specified file. - /// Changes do not trigger a write, must manually call PushAll to persist. - /// - /// - /// Subclasses must implement and - /// to define the storage format (e.g., JSON array, MessagePack array). - /// - /// - public abstract class SingleFileBackingStore : CacheBackingStore - { - /// - /// Gets the file where all entries are stored. - /// - public FileInfo FileInfo { get; } - - /// - /// Serializes an array of objects into a byte array for single-file storage. - /// - /// The array of objects to serialize. - /// A byte array representing the serialized entries. - public abstract byte[] Serialize(DatabaseEntry[] entries); - /// - /// Deserializes a byte array into an array of objects. - /// - /// The byte array containing the serialized entries. - /// An array of deserialized objects. - public abstract DatabaseEntry[] Deserialize(byte[] data); - - /// - /// Initializes a new instance of the class. - /// - /// The path to the single file for storing all entries. - public SingleFileBackingStore(string filePath) - { - FileInfo = new FileInfo(filePath); - } - - /// - /// Loads all objects from the single storage file by reading its contents, - /// deserializing via into an array, and adding each to the local dictionary. - /// Notifies upstream via for each entry. - /// If the file does not exist or deserialization fails, logs an error and returns without adding entries. - /// Logs the number of loaded entries for debugging. - /// - public override void PullAll() - { - if (!FileInfo.Exists) return; - - foreach (var entry in Deserialize(File.ReadAllBytes(FileInfo.FullName))) - { - Entries[entry.ID] = entry; - EntryAdded.OnNext(entry); - } - } - - /// - /// Adds or updates the specified in the local dictionary. - /// Does not immediately persist to the single file; call to save changes. - /// - /// The to persist. - public override void Push(DatabaseEntry entry) - { - var type = entry.GetType(); - Entries[entry.ID] = entry; - } - - /// - /// Removes the specified from the local dictionary. - /// Does not immediately persist to the single file; call to save changes. - /// - /// The to delete. - public override void Delete(DatabaseEntry entry) - { - if (Entries.TryGetValue(entry.ID, out _)) - { - Entries.TryRemove(entry.ID, out _); - } - } - - /// - /// Serializes all entries in to a byte array using - /// and writes it to the single storage file, overwriting any existing content. - /// The parameter is ignored in this implementation, as saves are always full rewrites. - /// Logs the number of saved entries and errors if the write fails, re-throwing for caller handling. - /// - /// If true, performs a soft push (not supported; treated as full push). - public override void PushAll(bool soft = false) - { - var entriesArray = Entries.Values.ToArray(); - File.WriteAllBytes(FileInfo.FullName, Serialize(entriesArray)); - } - } -} - -// E:\Projects\CultLib\src\GameCult.Caching\DatabaseEntry.cs - -using System; -using MessagePack; - -namespace GameCult.Caching -{ - public interface INamedEntry - { - string EntryName { get; set; } - } - - /// - /// Base abstract class for all database entries in the cache. - /// For optional MessagePack integration, define concrete subclasses with [MessagePackObject] and [Key(n)] on fields. - /// The ID field can be serialized via a custom formatter in MessagePack stores. - /// - public abstract class DatabaseEntry - { - /// - /// Unique identifier for the entry. Handled by custom formatters in MessagePack integration. - /// - public Guid ID = Guid.NewGuid(); - - /// - public override int GetHashCode() - { - return ID.GetHashCode(); - } - - /// - public override bool Equals(object obj) - { - if (obj is DatabaseEntry entry) return entry.ID == ID; - return false; - } - } - - /// - /// Generic link to a in the cache. - /// Value is computed from the cache; serializes only LinkID. - /// - public class DatabaseLink : DatabaseLinkBase where T : DatabaseEntry - { - /// - /// Computed value from the cache (not serialized; regenerated post-deserialize). - /// - public T? Value => Cache.Get(LinkID); - } - - /// - /// Base for database links. LinkID is serialized directly; Value is computed in subclasses. - /// - public class DatabaseLinkBase - { - /// - /// ID of the linked entry. - /// - public Guid LinkID; - - /// - /// Static reference to the cache (not serialized). - /// - public static CultCache? Cache; - } - - // Example of a DatabaseEntry implementation in user code - public class PlayerData : DatabaseEntry, INamedEntry - { - [Key(1)] - public string Email; - - [Key(2)] - public string PasswordHash; - - [Key(3)] - public string Username; - - [IgnoreMember] - public string EntryName - { - get => Username; - set => Username = value; - } - } -} - -// E:\Projects\CultLib\src\GameCult.Caching\ReflectionExtensions.cs - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; - -namespace GameCult.Caching -{ - public static class ReflectionExtensions - { - private static Dictionary ParentTypes = new Dictionary(); - - public static Type[] GetParentTypes(this Type type) - { - if (ParentTypes.ContainsKey(type)) - return ParentTypes[type]; - return ParentTypes[type] = type.GetParents().ToArray(); - } - - private static IEnumerable GetParents(this Type type) - { - // is there any base type? - if (type == null) - { - yield break; - } - - // return all inherited types - var currentBaseType = type.BaseType; - while (currentBaseType != null) - { - yield return currentBaseType; - currentBaseType = currentBaseType.BaseType; - } - } - - private static Dictionary ChildClasses = new Dictionary(); - public static Type[] GetAllChildClasses(this Type type) - { - if (ChildClasses.ContainsKey(type)) - return ChildClasses[type]; - return ChildClasses[type] = AppDomain.CurrentDomain.GetAssemblies() - .SelectMany(ass => ass.GetTypes()).Where(type.IsAssignableFrom).ToArray(); - } - - } -} diff --git a/src/GameCult.Unity/Assets/UI/UI.txt b/src/GameCult.Unity/Assets/UI/UI.txt deleted file mode 100644 index 8789f73a..00000000 --- a/src/GameCult.Unity/Assets/UI/UI.txt +++ /dev/null @@ -1,2917 +0,0 @@ - - -// E:\Projects\CultLib\src\GameCult.Unity\Assets\UI\Attributes.cs - -using System; - -namespace GameCult.Unity.UI -{ - [AttributeUsage(AttributeTargets.All, Inherited = false)] - public class InspectableAttribute : Attribute { } - - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] - public abstract class PreferredInspectorAttribute : InspectableAttribute { } - - public class InspectableReadOnlyLabelAttribute : PreferredInspectorAttribute { } - - public class InspectableRangedFloatAttribute : PreferredInspectorAttribute - { - public readonly float Min, Max; - - public InspectableRangedFloatAttribute(float min, float max) - { - Min = min; - Max = max; - } - } - - public class InspectableRangedIntAttribute : PreferredInspectorAttribute - { - public readonly int Min, Max; - - public InspectableRangedIntAttribute(int min, int max) - { - Min = min; - Max = max; - } - } - - public class InspectableIncrementIntAttribute : PreferredInspectorAttribute - { - public readonly int Min, Max; - - public InspectableIncrementIntAttribute(int min, int max) - { - Min = min; - Max = max; - } - } -} - -// E:\Projects\CultLib\src\GameCult.Unity\Assets\UI\ColorConversion.cs - -using Unity.Mathematics; -using UnityEngine; -using static Unity.Mathematics.math; - -namespace GameCult.Unity.UI -{ - // Color conversion functions from https://www.chilliant.com/rgb2hsv.html - public static class ColorConversion - { - private static float Epsilon = 1e-10f; - - public static float3 HUEtoRGB(in float h) - { - float R = abs(h * 6 - 3) - 1; - float G = 2 - abs(h * 6 - 2); - float B = 2 - abs(h * 6 - 4); - return saturate(float3(R,G,B)); - } - - public static float3 RGBtoHCV(in float3 rgb) - { - // Based on work by Sam Hocevar and Emil Persson - float4 P = (rgb.y < rgb.z) ? float4(rgb.zy, -1.0f, 2.0f/3.0f) : float4(rgb.yz, 0.0f, -1.0f/3.0f); - float4 Q = (rgb.x < P.x) ? float4(P.xyw, rgb.x) : float4(rgb.x, P.yzx); - float C = Q.x - min(Q.w, Q.y); - float H = abs((Q.w - Q.y) / (6 * C + Epsilon) + Q.z); - return float3(H, C, Q.x); - } - - public static float3 HSVtoRGB(in float3 hsv) - { - float3 rgb = HUEtoRGB(hsv.x); - return ((rgb - 1) * hsv.y + 1) * hsv.z; - } - - public static float3 HSLtoRGB(in float3 hsl) - { - float3 RGB = HUEtoRGB(hsl.x); - float C = (1 - abs(2 * hsl.z - 1)) * hsl.y; - return (RGB - 0.5f) * C + hsl.z; - } - - // The weights of RGB contributions to luminance. - // Should sum to unity. - private static float3 HCYwts = float3(0.299f, 0.587f, 0.114f); - - public static float3 HCYtoRGB(float3 hcy) - { - float3 RGB = HUEtoRGB(hcy.x); - float Z = dot(RGB, HCYwts); - if (hcy.z < Z) - { - hcy.y *= hcy.z / Z; - } - else if (Z < 1) - { - hcy.y *= (1 - hcy.z) / (1 - Z); - } - return (RGB - Z) * hcy.y + hcy.z; - } - - public static float3 RGBtoHSV(in float3 rgb) - { - float3 HCV = RGBtoHCV(rgb); - float S = HCV.y / (HCV.z + Epsilon); - return float3(HCV.x, S, HCV.z); - } - - public static float3 RGBtoHSL(in float3 rgb) - { - float3 HCV = RGBtoHCV(rgb); - float L = HCV.z - HCV.y * 0.5f; - float S = HCV.y / (1 - abs(L * 2 - 1) + Epsilon); - return float3(HCV.x, S, L); - } - - public static float3 RGBtoHCY(in float3 rgb) - { - // Corrected by David Schaeffer - float3 HCV = RGBtoHCV(rgb); - float Y = dot(rgb, HCYwts); - float Z = dot(HUEtoRGB(HCV.x), HCYwts); - if (Y < Z) - { - HCV.y *= Z / (Epsilon + Y); - } - else - { - HCV.y *= (1 - Z) / (Epsilon + 1 - Y); - } - return float3(HCV.x, HCV.y, Y); - } - - public static Color ToColor(this float3 color) => new Color(color.x, color.y, color.z); - public static float3 ToFloat3(this Color color) => new float3(color.r, color.g, color.b); - } -} - -// E:\Projects\CultLib\src\GameCult.Unity\Assets\UI\DisplayOptions.cs - -using TMPro; - -namespace GameCult.Unity.UI -{ - public class DisplayOptions - { - public TextAlignmentOptions? TextAlignment { get; } - public VerticalAlignmentOptions? VerticalAlignment { get; } - public float? LayoutPriority { get; } - public float? LayoutHeight { get; } - public float? TextSize { get; } - public bool Interactable { get; } - public bool PlaceInContext { get; } - - public DisplayOptions(bool placeInContext = true, - bool interactable = true, - float? layoutHeight = null, - float? textSize = null, - float? layoutPriority = null, - VerticalAlignmentOptions? verticalAlignment = null, - TextAlignmentOptions? textAlignment = null) - { - PlaceInContext = placeInContext; - LayoutHeight = layoutHeight; - Interactable = interactable; - TextSize = textSize; - LayoutPriority = layoutPriority; - VerticalAlignment = verticalAlignment; - TextAlignment = textAlignment; - } - } -} - -// E:\Projects\CultLib\src\GameCult.Unity\Assets\UI\Generator.cs - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using GameCult.Unity.UI.Components; -using UnityEngine; -using ZLinq; - -namespace GameCult.Unity.UI -{ - public class Generator : ResolverComponent, IUIContext - { - [SerializeField] private float inspectorLabelPriority = 3; - [SerializeField] private float inspectorFieldPriority = 2; - [SerializeField] private ReflectiveResolver? resolver; - [SerializeField] private RectTransform? contentRoot; - protected event Action? OnPropertyAdded; - protected event Action? RefreshPropertyValues; - - protected List Elements { get; } = new(); - public IUIResolver Resolver => resolver ?? throw new NullReferenceException("Generator doesn't have an assigned resolver."); - public Action? Refresh - { - get => RefreshPropertyValues; - set => RefreshPropertyValues = value; - } - - public RectTransform ContentRoot => contentRoot ?? (RectTransform)transform; - public Canvas Canvas => GetComponentInParent(); - public RectTransform CanvasRoot => (RectTransform)Canvas.transform; - - public void Inspect(object obj, bool inspectableOnly = false, bool recursive = true) - { - var members = obj.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance); - foreach (var member in members) - { - var inspectable = member.GetCustomAttribute(); - if (inspectable == null && inspectableOnly) continue; - var preferred = inspectable as PreferredInspectorAttribute; - switch (member) - { - case FieldInfo field: - { - var type = field.FieldType; - var handler = Resolver.ResolveField(type, preferred); - // If there's a handler for this field and attribute type, use that - if (handler != null) - { - var group = Resolver.Resolve()?.Configure(this); - if (group == null) continue; - Resolver.Resolve

    rTjYLhZjODP&pTjt_%A61Qe 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 Ce3kD2 literal 86016 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 diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.pdb index 60ce5583b3d4e71f5690e7db0dff0e866ca40597..6b4ea8d7de9b9e7d070118828e3537324acfbf9a 100644 GIT binary patch delta 15874 zcmZ{L2Y3|K`u>^O$?m318Y!d@LMnt3Qb{Nw)C2@VXeyzk5Fn6HQota%*(94yq98IV z%0=NSU7Cg_B2`2#UPMtZUb|uk%T+9>_6vkrjW9*((#uNqN$+guLi{{lZ{8nZn4u0&^$*ck4%@od?I%XvN=mCta%?BS| zxwsVk%vZZsuZwv;|G{I09}mcDv-N%bN&}+Vo!t+4dqy!PA*=zjfh8crWX7JC*l-qt zh>0Lw;lF5NY&v{WCL{t|fRBM_;4DD#P-Cb!>jkWQ=tgW9<<JAhyvn)K0q2U5EusB8!xd&pbc0HtOuS1wgS6>4&W$o z3U~#04R{-PAGiv96EE4=F9_TMJQ5`419SnxfgV6lAQ>11j0dIyGl6oT3aA5|z=Obg zU=y$%H~<_2UIJbP-UQwQt^(J9pMXCACDDdL6D1Y|L;`U@A0Qo=4lD)g0Xy&-@E_nq z;0xe8;1}R8z|vDq<7m;uZIDuG&Hr43Fq@Br{Iuo2h->;?`1 z$AFiBSAlncn}FO)VqQQX5DvruIlyc{1O5ScCZS*;54amB0V;q?fVsEC?gB~x+X6WE z0?z_(0CFFREdq`JEBZ<-x*vuCr~}pk8-VSAk}R>?&h&R>Mm}1=xx}tO_BG&>g5d*t0KI@Q zKp`+6r~{n9!@x%1b-+JWV%>mg!1`2-{}X9?#{1IH+H{GP0`~z|fZiDr%L1kVOMrWT z2A~yK3p@sF26h1Zfg`|4;1%E!a0U1X_!9UY_%%Z>%Oex>4Z8-j5l5@yh``?o!M}hv zfUCd{fN22aKqj`8+kY5$#QS7ni30tB@xUhFT$apU1HJ;j&vK=b*)QPMY?=81@qn!l zoHSr4Fd7&SOaW#9bAY8lJzxjc0FMGYvQ2D1@On07Y+_ds4jpJ>Q9wM<2S@`30>glO zpa7T#%miwIl|b`AlZ`!(z$xH7@H+4g@G^0NZLfj{r{qTY){mLEuH;EbwpOE#N!AJd9fA`bjKy7*+_71`Gm50CxbBfg+#` zSP0Yr_X178{eTAi19*BE*8ejIbO0{^XMhX9W#C=lQ{WrmN8oqBG#u-9I8{JmT@63l z@Ov75f5Xo*{9L5T2POh{0mZ<4Ur;IX2 z?G1T5Wb2IZ6NbMPaeIt#6xk%uf6egMjMDi#@Mn=AVYD8xiu)9%A6k`%R^{o8cp!K< z5CbFusa%GZb?TVda3MT4Py455Y%i>jHF*kq6nL^zs<3U~dj)>T(Dq#`}J04keN%t%y{eyg-cf;OqG2<=2{K4Md}VZpJs zQpD^=%osy20ep|Zt>AkFu7d9qIMsH)8-Lb~KPPZc=y&|hZHy{<;O_`VBXkgatWlv# zfd?Qw0XPKtctaitepuj<;70`B8~k~JPZD?lO*T4zjzVFAks%$XFMt;qd7 z;EceF!Cw;iI|jcS`VNHCfwPcLH_}fr>3lZ0?E_2?AAl5!5%Cqm67Vv3sgYm|GB^ib zW^fv^R|NjP!RJ6e4`H&=&qH2r=zAhR7pJ4^upytzu-Od**$?~+3FaFK#)Dq~uQ2#J zWI%iYar~_?HiTp$*%~UmL-j| zSfT$4oaFBcoYKE1aFV}|{A^+d9|#JR;6pe5ksJS5s8A?mp9(w}{HnmafPW$IKy);? zjn$zCXi3mAA%$h&?FjoDd^z~P5sm@Ag8Uw%$H>t7THrKEzj5Q&z*iXhG=$d$P8Y~; z8H^p50&Ohc2?|u>?*W&bdgO*6?8^^``Hr`jL5bgE- z1nvi(+{w}ZJA?>YMoWSIP*`n@@lyt015TSrHIO2y>_J0L%M=&qPEHNNz4%fQEhKVsy8GjSL}sz$RiM*0~CO7HuPr-ob>wx6CwYn>-@jV6@dh#KvruZ6rM6N zpfQ_-E_HG0;>m7&iW{FQq^BX8CUCM1?v(tQ&6VMLMBIf47pDg+MG~F|7!{xbX9#>Q z_)LM*;WJC%bg`Q4R-s}yUPALvETB}#fLdJUmSBz>FL&c}h4fT`d2aIgZoC5a=WP{O z;HI$9jaRzyDmT8!jV~4|)CUz>;wE28_NUkb)o#4Tjn}&IIyb&d;B=TR7dQ>!Jpw1W ztzL*Ag%tuPg?j}~@|6N7`6_{v{62y60t8O-27yCvV|F2e6dDCi88iu;#-D<(0pDh2A4zau!`DsU=rn;YNm#&@{!odTzwZG0Uy z8KIwsdjw7y>=igwXrI98aM~|$Gx&1?r;E%1fz$SW$i->=y8=gC5eQR-jtZRa`^Vh) zivp(#9TzwqKqmxFR`W?We#+ofKBK$aX+eSP{4<#4u31Y3ye!CxpL64{2%OIM^8%+H z{FfWQpmSb6H$Yw$6sUlI3!IkOMK}JM8^0uQ59q%xaC*1*hQKMm%bXkce^Pi;P@oLn z5;#@pZ8!cOfm8Y`Zu}iL{$GJpe(w`^o&VHDAGj%eEO1)ap9q{X_)Or`Uihf}G~iPXg}_egk}mvGdXG_ZRS; z29E~+O~U=(6+yH7rl1gojlsofM!$u^iSI%N!@+4|BK{0G-FQxe{{g<+C?F2$U7RZa z33Q0>f&40XG;mA8{eQ2KUQ_ zP8BM9byk2TUAVxhUM@ZyvWE?M2Lxm>w;KEaILUefak7fXxk!i~RWSZ`Zes~T1kHh7 z0;dE?ZoIF+_aI*vPlPTRBRZE^75HR;_#vDs(U8%c86f-P0VKv2KQB7}vxEqm#n}R< z9vCQa8j`{2F;@mL;6nsXTX~MaUj)w;_&#v@)p7R=6Uvv_ParbyA``pY#Fz(?FlOcP zl$>;Rm%0(JX%Hi`anLm3j)+OeocNA91@d%yDPJgp(NoU8~x59 zEOP_e#KwawY!O_2;INzX>}V+Qx*HkEMhu1Vc?Xx0@r_Rjprae&2;&a6{pY~E&T%R7tQf^d=!srPK zSsf@}-wtKiFx1H;wsNs2ZwI~GpxiW8B57P2Msu?$QNXxBXq!J&aT)=Ec*} z6f?0DuBo?dDbKBf$DHM9b+?1-lPj@j;G+C$PMlD6be z#}~eh4uPA}vp5>h;q=4)B=5(mwjC$g4xC;c*zfyEedVcAj{K#RD}OH~qGxU>iO77D zMMQ>YS2mU5{QOZdnH2Ve63bl^z7qRRIRp2)a>d)qn$xZXllv=obB7J} zWF8|M;GP_L67KX-Cx?2mRijw0Cp!h#i(ML(i*V@Z2DpnxpM?9>=#zP#Y;r!!_hk3w zYjgS)deqdG%q!PA`ei6{$}7vYtNn77Wfe6QT6FSGuiEO8MKvX5wH1rCbIIpJ%jTCX znpa-KmQe<5_q zso$e7U3|R8cb;?1Wv%JSPoGYA+;MHngrw@Lg*)$g{`dp)3h^o^*5j0ysgkYzrD1bS zX4@ro<*cWl>Dk~l|5~4S0@JTFo$BYmKkbttVUCRpRu=!zu(u(&$UEEq$mWxuwTxf5 z;?2+5lbN3^9CKvcU!VMT>GjC&b@rJazpR?Lpx-i^HYllYSozY>fSX|>HYXhZ^IAb} z^^K0q_1i}MXZFq&7YA)kY-+IutzJ$7~%}KD>}oG<}`l3$t3zSFBsT?((1Y z9~_;u($+Dd+w~LHO(l=27nUx|T$K_YI(Pb$1ud65en`LYk5(kVSNYwJBf}PbH@mLV``4>?SNQewn0fE+4Ow+B zms-bM`(4r+2RM3`WMrhw&CE#69*~|nr!0GJT2@MSYG!suX=zqQRz`YuT1i@2*4*^; zj^wNza@VbEroYV^aDm_MJ8ONy_z@c}K393^jdv539I}pm!nF6MT?+J{TwhaLUe#~P{OaM7uaCL_2e5kS$T#GFRGCC2hH1+OkdBvR~SAOxki$+VZWm)mz#cDsAm4Z5=9Y zoyapC5}|w1+#9afceq~PJiRS>dbP*Ja+PsCxmOsadwS%w-keSA4-aqKigaO-E-cm? zTAal9#o?*m%*SgL*I(F8_w;fW8=hWVjm~Oxw!8<|T%JI8DxZbDk%!fb9GD$lto#Lw z($JV_fz*aT9||Z9E!l>jqxi(`ChMzzi zx=+K_K2&?N9(l00;Tzc=b(MeADE~xXUExHk?!VN_@cZfh`DDXS*Zqr0hHu1QHuNs1 z>G4;x41Y*Gug$@1s!csPK1L`oNV{}*K+pF*&8(|pwUFUy!7Zy^Pxz@(&}V5l9@Qlc z*EP@S<88iiTxt(A{1Dy_#U37`$4ABMevIB6dqT9%lZ^P@dbRAyBlP&RQM#W#RrfRU z@%=!EVjryf;P_0o->C-4F;p*%k-a!hA3b}q-Z}P?2whNOlu~NcqSUBWnLaf3vYxu$ z9DT^_bBy?MeN^n_`l#6F8uGb@e4bJ3c}aXo?Zqn1NM%(tYSYtRt(6o-_p%#3;V{Z> z)BDZ7n)4w0lbLk6Otn9z?JA0p9@Abfik3RGFN)GUPpef5o;KOfYq2w`q))VmW@PmH zQw_kGGQ8144P}9fRc4dSd^|=r2CCGC+{SQqF3oS1g*JBAewtAx6=-+O%#w<=hh`SU zIaL@JriNpU52^lSVyIF>W8)q*MjnX|1HG8saJuo3rp!v0KGU*iMN6tSeO9v6OKYFC zP%71ao;6lFs12KaO1fJ!6>sr$sN*pABb(P~`-{g(+q6H6BSRkXq@GB0`1o0wq}0uz zDmDM6C71N}9xS6$1u|AyZ*5vhf-P1xyJnNc(L0E0AM5DD{gIATeZ(9C22s3^V?Zt+ zA;)07_Z)-ya`bhK9v&LRSb(D-Ab^dPt$3?}W=Y6*X(*O=fTJiNz!W80i(T>7rIe4S zV{S@+FM1FdWS;J*qMnm$9rvnUbe~k&K!<~OX1HUuT0mFCAQtF&MDs2kZJU6>N^qQ0 zRkl*LdShK+#rT@j(P$YZ&$F^vdASwWq$q4qzAVICWM(QpSB0%>^`~0NEW&K{p>|Ux z>#4IM9Ur2!aGBAo+d#*cs);4D1aI8Li+tG>1*IgI>y7f_c!9BID|%P1cgu|CQIO-7 zsy$O0W^3_ArbY=pTDs^ZP}^f#%GH2q#)4ZO!emHgeZ1umd1{Xy=&hEGYJhZ?VhyMD z?vLntoDzC}>irhnvRkDphqfF*4|LVn-SCzd)$TEr{H%)kU}nKc93|tn+FeK;%jA%j z%W4R63~qT}8&(!#yQb$65YMEEEjQF8w9~3GA2aWjM5jshbrsRg>7%A6;9lemQvFzW z1!@+$F?BVg`v;k=Q7likdZM}R{hO1B;+(xzPo~mhNio;^>3bP=j{<KHY2$`9IS` zhZ^hW%-4G_t0(>o!C9!CE{nHCcopHapvjCr&h3Rs;VeOOddSuQR;tt&U>+o4e$miZ zSXijC+>?dLR#@=p6$SH2ULJ&J6})eweP=d&lZ1j)Im%h1X0UKGZY=|4tC@9E>U|}< zmF7TzSACEYrC3KZ$*UgMaFmP=D8^@R9_ZH7212&tQZ}IL%ySVF9?NGf#y~ z0uQPa?xf1{U=}Q+C=51kkTTw5hR_lXHP?I67+P4IVhyHSS_o3s<6A}&L{dh*Y@|I# z#y2rRlms0?Q=H**3Nw?(M|!i7Su^{)&wRbgekgEq?c(b4Ic%a~(z8kBRg0G)BA_=u z?{i*2M-G%(q=K@R^u@$#HDO|9Db{Wnbt~$j)R$PO!huv_ALgrcHrYRKn_-uVL+EK`4ccFmF$Ybds?rNjE+WqNCjRxxLAY%-n} zwT@8zkt>p;{Z=+m!E6~|uD`oKcFVo3leAanOg5+B^>u5V)}y@8uk}fF6qC&L5!i~# zTDNNU@^HEJ1?`FQa9it{ZnOZE*0cIi(0Y#hm91AWzbO9w3FKQ^KhrnE*3Y?bZT*(} z{;l8X$4~1GzA5^)-q1J2)|&}>`kVZ?ifH}oPR`pD-DYXCa($c9<}-*U^w>6kHH79Z zZGgdTk=Sr(8^E*7shvA=LR*~L(3HklMcV+i03FIK%wnd^m+x~H+#r`*XrFV+JqS!9s;x3!^DF(ql&t*1PC zw_eiD&FvoD_9*O`7)9TN^?rIXvEkKBsF+!owu72^-b;Duc&OI)qZ*D%qT!V106f`j z`$LWFjET&`N#E|F+RZF25>Ku2WxSWcdg5JJn2iUS?crL${BdS{LAj)Ts8%*VL2mcc z?w=p-#}8;FLN}136SY0_XG!UrPemNul#0kMgK!Qs9Cn=pX>ySzT`R7@!Orb)ZiH|3 z?r>J5NYY^K`32e15behWHU6R)cKJkY*}_Ruj&^=wp)^#BsGKb2YKtqw;I>tcm4<0= zR;EhBHA_{FG(sC)HAWh#t*sg;jnXbu^?-Z5sxtNO4E;wl77-fY$@*GZ9~u?vIB)wX zvYWhS+eatT+0(W0G41|E5gD6su#Zx(5zeEnqlz5#An)qNZKHL6`#9a-F_BW1H(RuK z7e$2mQhrQn_SfyM=DY2TcpTXW56Mtp{D@-`1J zcy=$CxE{I9Ia>4Lc-uImj0r~SiG%fAC+P-q^Az2{Zr)?)?dhw__Zs?pjk@hKfEe9)-=K_mW<(X2zX3eic2 zjfx%~pz|Yql`G9ha>MeVptAAJCj%^O3T@RzG7IxnFcSGVIYu?Vjra%|o1PC&MLE-4 zPakhYG=GW#4nd66&~C2p&U%}1rs6oJ?0xK~Q^=2ROvl~}3!rh-c=9ccqqtmcJUWzk zSmQBX?ZC$4y!~q93G%&WH=gD;v$w7BbLtR8e8D4po0O51FrY~(Cf~a$AP2s6UQ-RV z)4I6HrW@Z)d!~_GY1%tW*E_+dkayEbp5D9Z^cX$<+d|72GD{Z^B0sTt@j~*uH80V3 z!Jy_PmAasM22ar3kWAZ0&t_+UH%rrPnsEE0p(Kp5zd4uuVU7KUkUzb#99@U_#=U&h zf}2b4Cf>EVvXp!;=ZQ%c%-MM7DXt&sJd;WBeVs4!bfr$)i)18WH+mSW#EXs<*V<@( zoX;TDk;)tD>zK&zJ`s+Yy(vpS$E+mX-^d%RI`$5ytX0Qx?pvL6vh^y=xr2PGvzCv9 zud|uY+(2g=UHxp#+u6no2z1^bO^Uuw{VJk5J4O=^Y>k;h{`+_7KiKpBJQiL zoB2!(byV|={T(%YhQ>Ko@&aQVtN6$Uw7kfdmbYVZC{;Yf;YhaJf%!Mt@mPxG4)P!8 zm(d}P4ct#}IUjGqWirRv6z??wC97<%^MM|ec7*eR5mblh)`XNh3lM-MrNWRL15<&Y zT`BTZKQ>aajw3^wTQh+yo6qY)vXhv_G{bBy!$(}xS#K-DLsW%DSn1e+EQ~fZ97Sa5 zMXKjiC+S1S=K87^i51Ym$;>*rvMW zfnmnCVLnCH|I7G54e$>r3e(za5^c|-l=D>59}R7&E|nAr8#@a2c{=M4`(G|pSue$k zt+Id&Uk_>;C-|n>oAtzhi}8jite06=N~T4RiG@3|!g|n+1IwMa)?!ZJr>++(_r$BO zEgg#o4+IAHAy`LT>|kUcQc< z+AB3VevNWoXI!x3h!$L%@7Jg-oTBTgEUcwUtE`Q{GkP!B`9rD0_-qIy8&#YQ3e5%> zXcJhVl?wd-O@?d88P6M7qnWx~Sxwi0Q7V)Rv(E82)K|>KdI08QmYJ0*$$F{vRs2x|RR{ delta 13408 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 S*09#yb@V2CIHh%lX>lh2 diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Logging.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Logging.dll index bc67fc77ad5d50d767e73d7960b8ba01bd556024..b6116f321cfd18d28feea8b2a869946af2972293 100644 GIT binary patch delta 290 zcmZoLX)u}4!Lqb3>e|L0Ck{rl&F49OvIxvw&KEab&DVL>xlK72F5S%8e1o@v(ZWQ} zfPuk;kwM>3&p^-AL_5*c)G*D=)X37@#4IJ*GR@e+(9+1v(ljZ_!qmdl#L_s?IN2i2 z#ANaW{yQuTj~%~EE)WP1&{KDRIWy1GW7?DUuOi9wD<)qMXjFg-T3mw)0#%pDzdj<` zmzd~w)3Qx0cj%! zO9pcW6CgW?3dDcFav*saU}j)eVrJk1VnHC5m|V~J+O-0x zl7WF4h#48KD6#@+HZYrkfdfc$0|Dr?m7G**n9F_i*LKigt%6EJ1I5_EPuD~i^1x-SNSrQy3WeI;eIOn%gL@c*Vg=I z-G>3arxqzWt=~)V3)bHcvPF!rkUjnzyUlo_W&i z`Q_f><{7)Q1~Pz)Cx`dlvas~tlv!jp=kvvB=dMe~U;M-UgKcw8%(+dUkKTT{CZM~%$VguQ zTza?8`R6xnX6vb01b!~El3n-vLF~mw5U?kxr^tq0Kk-1?-wNgrc^5iu3GL1x2Q^PbfQzJ`r6SI_L%QRyPLrWtw tOVgwz3sVbI6HDVn<7A686O+v>91CO^3nwpCiDoHeTzG0Si>eDF0|4P1GJOC5 delta 772 zcmX@(b;4^xfr5+@1B0?tPJR*t1H-|GW+pl%Y#x2SjL#3pX^Aefc+fU+!ZOcvMMj27 zAnpg^rHVj>3``8$6qy)q0PzzbehtK*fcPg^4kQl)%nS@l%na;6%m>7xlj|8@yOsh~ zGB5yT7#JBYDzXA;HZYrkfdfc$0U1`%0>j_+pP z3vYjLZ9Nyj@=-x^bBcFBGCS98j{|-`1w1%KLLQobW4w@Ak(RwsVS^o4!Oo?guF|=E z0vX!-rnRj8qi_2D_N>FrW}A#Ryjc`byL0zhxs_X%wCvsOvoPMkZ58+J*gujJV*l@n z{;|vPdTcj~Uev3@-g|n5DO2z|Whi~4dn9cTkUR7jgUvD|rf8w#r zl7W@WCVp|5`#Ndamx8QKR!YfFF3nAyoWowMk(!!lVPs-qVQy}jVq#`#Xl!Yom}+2d qk(!!jnv$5BVv=l@l4OybvYDM@fed5bEP0Fzk56V-bpZf>YcY8M diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.dll index 96f9481b7cfcfe45c8b580726362f6404eedbaa0..a5468f11001f30778f1fcb3a72e1b93cddc978bb 100644 GIT binary patch delta 316 zcmXv`Jxc>Y6nv{^VIzrxcmzaH3yECrvTrxL;jmLIL=-z4xw~+`B1I~(5d2s{M6eJ= z)2Y@A@v2=FXjE(std?(L(m} zFmkh34K+aW4M@nRz(G-~sgZOA h!~{k9OQeL;2Tof>TLd(DT?`?3;M-z2&MXVR*$)IoTJQh> delta 316 zcmZpuX{edd!Lr6*?ZU<$14%~H$$KSL8BI4omi#Fsuv9qvA?Nke4(*8t{&{YFQ?U7s z&LS2&V?6@~1`|dGeM3D1JyT=t)YL=^BNGb?b92iS6EjOgV@vbIR0DI1)YLT7l*H5& zlVr1$B#Yz}1_n7s2Fc0uOe8lyHGIyB$$20|ch|i#_(4Y~$HD=VDUEeXW+s z1}2jgpn@|GLIpvpHH=pHp6Z-%eG%KVJDVSytY+jiWnf@n1Y*<8)6Jxr7>ze?wph&= zY|Nm|kP3u}3>FMV3?@L*g25aJEg4dPJTo9|$Y2a4&4DUX84Q551z3F=gDFr2NDQPd j8K^RaAqgm#%#bp9qm?PEF@qk1!Dc}lF~-e|Hvbs`H#1>B diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.pdb index fc8890e2870214b07e8bc13399fa3d0b21db5262..2d70b0ebda4f9d99be3f2cbf41be1d292957ddd8 100644 GIT binary patch delta 1035 zcmbP}upnVVfr5k<1B0?tPJR*t14E#d^mFFrJ{}V-T?M12%>Md1>CB#q6OM(+s4+4q z1F;qm8v?Nf5T60!k3jqbi2thrH8U_Wu&FaLBmnUQAl?nchk^Js5MNOT$%6nR!(AX> zSc8#4Rb#Rvqp%22#9IR*^A1W+-h7$yG85yr$;(+3ZN*vC8Q2&O0!elTarQ6}L7>+Bhdi6D>XOK#olkFh zYAn&?Y~8hG=MMg*{EM%8NJYGzbvLldZsq=q`r6vtk1f;P@t{_~qx#vL#m0x1ynN|+ zzF@+#g5I?|E_dlvifG;YBLBE@O}%A98S6oAwi^rz?-?BD7;8D1f2i!;wus@8LsII= zwgm_IOtv*PtS!4YS?t8hW9emb7sNgsI_BV)5F_xQ=&+jU+O3ui%X=&IIj_Hrw~@D+ z^>6`ij&{Y1rhwwDzgN9mX|kks?%u8o>m`^>cfQp7&$426e0lNpH5bavmF9g8d!dn8 z?-5Wfa_!{D?Rz70PKHXao^$unE_G*#7xf)sbDyu8raMXgexhU31{LXF|1#3APe0fG zcjf)S3-iKv^Yu^a*ZAYJfn$F3HG}+K9gQmwIC~3(rSo(%3+23?KRmgqWG|<>Y2^kL z#|vUFxIe7z73G}6!(JFOX~Cq&d*9yOv{3cu2I&X&9&=abtU34X|Jm=`O7^{!ZhRKs zqCO*aanYo?=i~a-Tjxy`zkKmcjnU~(HM4v-e|*EF|7D9z|M%;EpTu5#^>*LgL}x>P zQRYy?xUGEE^_SemoZFYi$SFLw=ws!2=kx0ntJw41>iLtxCtOilT`+T*sQ2AxUc1%) zzP0P^=b!Vv>F+1m9k=6B3eW1u-P@MK_2W@w#yhTEUn5LYShpM$2w5{(f~!#@(bUv1 z&CJxu(%i%>CD}5~*uv1#$js6-Dapdr!qmjlIMF!SBF)5P^Fgi^OcLtNr*<+t0H)+7 zmWWfkSsfdueLK=2@8U7Jkylqj#cqB-LjwcD0nxVy%?b=0mRuc;oG)&=ny>S$bDMH5 zT)LSv*?><(eB!~$pBNap8K#y9y7aK{`z_b>vtx4kJvo|BT0(8zwh%$@n&XZ007$> BpKt&G delta 1082 zcmZ3GFehO`fr5w@1B0?tPJR*t1H&|bvBy4>Z9E(2TujQiuhnv<>-y=56OM&RsxdMs z0I@m{>jAMT5T69%cR>6Vi2tYoH8U_WFsm~%!~$_I5bpru13-KNh%c&xQf6df5Moha;b1tUp}@k)a7!Zr$ZpbH03<&HNlpgF&8)0{nd-SUIgS?|`<8$B z_T!m*(-U}#C!D|S_S{@>Z=VBmnfHcQjo+$R85q`v+|Ih~AW+NyL!Ql6bxEXUukdY8 zjU{@Vt-H4D+`+$;fAQUkCL3;-xaAMC(`(>Xa>Wf+4@*d=Ni(p>xg28dmb}h&2A0m6#E#i3O7?gT) z+Jb|8Cfg=9%>AY~K}=)CvGi|@7bGhZvll9Cu;VJ&nKpS=*ew~w3sHNfx4izNKkvKj z*#`@H-)L35SQJpa_3x^8E4M6Z-MicC!g>j1)7H0o|5;YdjxRU9uXC}~T&b};?1e#g zy+;7M$hDgnx6h4?IT<>8)t=iAcBy+yysYn-7W-h;G~P+__Y?h^HYkYy{+IDSY`Wc% zyDRSpUTK_un~#5Uzs4UQgZ}x^*9@}Pp3%G}z_GSqveY}7%#Vy-@()gKEZNJcZ^~Mr z5_mz9ht27AkSp8q=4KPU$dH>C&wb0gd8x_i4&R6R5ZMH~W3;OXthxOmFvd z^mi6~sxq0`b3E91*Nl1de2;q^{@Aj@#@r)qiN25F#kBIf{s(7=<$rt2C+$_aN@RuC z$5o*>c2Bn36md)cX%fHW@0xK3%b#@pF{w*R)V zwJW&D{q6MQyke<|OHGaID{gNx{h+$x!WrpZyb-2PShgIM2wgQP)xg{$H8ssNB{4O{B-tz_$s##r^AWBUOcGlQZ_H#kz{n72ut>Ie z(_*hF%*Q4v`CKfWe3DmI!!a*0r?M)ws8}y0CkL3=#j|}n85$TEM2>tePJgz;abwP| zv+~!Dt^z7nu6H`VY6XJ=Bg2JX0ww$Q1v@u-PwmloeS^V0F*nt@G^a$*CqF$sGcO%# z*7H5dV6)sWM6JI3E68!>E32XztpbX0<-V!K8Bn#yY>aL*FmN**d^zRuwzy#DEy152 zr%PmChpY8VEt#Cn$0y-!G~*A00|x`E)D=Coymj8wzjx{U@JZddc_N>IoUkL~G7rXO XL5#}^8JE>EF6(1lwsi9q9dBj;_1?10 diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.dll index 65f566e9d3683aff583d28438c5dc911cf8f16f2..784767429606c97c26791acd2df016bc093e86ac 100644 GIT binary patch delta 383 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 UD=GJnZ!UfA25xcO)$iW_4=;0X^Z)<= delta 27098 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%0A^SOAM-Ijo9xu_?C3PS^wcCoV4=ZGA$X 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 R-#@;&^tqdIoAW{c{{!&$U!nj2 diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.WebSockets.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.WebSockets.dll index 7cfbbf1329f9fc6a106ab8aff8cb25109f1391ed..a01a7704523e60047b20e2c8498770d89d3b91e8 100644 GIT binary patch delta 306 zcmZoDX(*Y{!4joc-LSDIM}pC8@=pm>MzhWGl8XESF|QWy6srI2JynW*bDgt}>E-|p zVO9$hJp%>?6GjGoLp=jMQxok(Q&Yn9Vw3ZX!6ppa42cY;KxoL2 z#$X1djTkH$%o$98>=cG%AUlo0n85-lYYCJw1Cpi;NkC`;q(RsOC}IpW!5FC40;tx6 b!DRALGgDR*20aFY&4Lz8jGGxP{xbpqks?=P delta 306 zcmZoDX(*Y{!4l0nZNtW%90^9#$v-7j8BI6KODggUY;bMg`A5~tb3%+oQ0D)oYc~gI z2(wxk>lrXGm@qQv8|oS8nHp=SrY2e#nOInun_H%sm{}ScTbd`P8kk$8rly&uB&MdA zB%7rqStO@yo~qo2MIbGcg)(UTkunG1!XH5Lz;%0C{FW+K|B*NSXsxq%s%)X$!FWGzL?k3Xm8`T{2K*3PTc5E}0=^ Z@=-HWR$~S|27}Fl7EFwr87=-Z0s!UmT$}&^ diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.dll index 40d4ec74585ecf0077d40ae478ebdbeed3720d96..a68c628de93e648b986589b29f91377245cfbbab 100644 GIT binary patch literal 517120 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%0D{rDa)@q^j0PD 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 Cu>YF? literal 510976 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

    d-m+;lQpG1TVu-TqJ?*7pJ?os7BnZ} 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 Z{||g}4;+$zTlNVWdjH?g|L;8TzW^0#?VbPt diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.MessagePack.pdb index 353d991ff7005e86cfd8296e9cc63d044027a596..b2446e7f105fee9d59a198fdc424fe1fc9835cec 100644 GIT binary patch delta 6274 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 diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.pdb index 978cd4cbe7f222da256c5032c96cc7734ade4931..888adde01b7e91e84e9755e277b93f4fc4872086 100644 GIT binary patch delta 3015 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 diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Logging.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Logging.dll index b2d7efa56592ab744697dcb8dfb495694d677237..be0edb36bdd2b942c5c65bce2fe6491e7effc4e5 100644 GIT binary patch delta 289 zcmZoLX)u}4$$aI=tc^WR9E>KL&vX1_5tzcfoFzi$wfnRjg_i55B6n}T!P~%SVWelk zz+l42pl_&Wpl52NZINhXV4Q4dW}232k(iX4XqsqgmY8OeXkngYU}0foY-yC7l$vH_ zF?j<29Tqp)Wt%4#2m}Zi`WwIavGK3_?suxkjP-fV8CF^kj!An zV8&p|kj9V-7EJ=ui9miLgC$Tr5h!i~BrO=s8IpkNEr8GnsLK*aCIdxMf$~NS7Lzr_ MOo7J7i!EdZ0F!W80{{R3 delta 289 zcmZoLX)u}4$*e5iys^iLgVA{Nd5)hf0#1EFw`?( zU@&21&<8T~ObxY@lPxS06H`qR4U8-;(kzS&k`0p6EG<(_EmDlrQW8xK%#)K-lPwJ< zPvF19BBd`}WH3$xidh0xm;yyp7>t3kDL}QRKsj@;8L2?hlEGlIrkE+v_;|5}%m5O| BQ&0c^ diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Logging.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Logging.pdb index 5aaeb6b14f96eadbd27ea9be13628aac9360ab68..84bb0c96d69e239b2f30c219fd9e52dbd04e044c 100644 GIT binary patch delta 760 zcmX@%b;4^xjfkPY@rxfD|GMvf_j>2nmp=>LWS4E8IANJ*x*{V(B@p)m@lr(wAYfwH zrpUx_1Bjmh@oOOd1jIkVav*saU}j)YVrF0mVm=@iom|iO+O-s@l7Rsz!@$UJQIQo$ zvw_(R3>-k36NuFrSQ(62)Pdr6fh0SFG5a*2`dr3sKr)eunURITaPxYmeN6RX+Z)fB1I=GM<$Ts11A$}j8}}UEuzZ@? zx3tT?bL~Yg>2kKRc$wXl^Ws;o)ZsrdY2q>7x+VME=C8@v9=j)(S#M3=q_n#GAI^GI z)@`|7S~1~yLFe2b%FcaETvOj)YtOX3QZM89d(s0=*uMG9TqpWauz(& zyyQ%mu4A)p#v3I@>$lDdx(iku%YVbXK>K0mT2|MDT9F4?-jipU-I7tf5LTnhIsK=7 z*1hef?d-8B=?OR87d}fWpM5tt)swrre4^9-gq|xJx99(toe=wXSM-l%uGix`S;FRC z==Q94Zn9diVcwoUR8yE52`4{+b((G$OTecaqP4)FPSF1ebrxCJ(Q%gSKV&u+L)3~>@bk}MeiQW1* zXV%&DnKe;qFb#gj;v4%yWk%4itp_yq~szqW_YNBbPrCDN{Nuq^$l7WSVk+G#w fa#CuVk;P^vjs-G|d6O5bM6={EE<8S&N!0}aX0bN7 delta 763 zcmX@%b;4^xjmQV>$!9rAo_XvSj=Udf7$zd9+_rn-gk_$oii`~9K->$&ixnAwfQey? zA``F3Z^f#|(+Q(GC?83A4 zl|6~7`HT2Wbk{3vQv1T}*SIg5Gh){Mvu{gGt~8!82b#Zj%I&N>1_EvGnJe29*GJvD z;dg84YZZ}8x}2>nUS@aWro{C;-DtC*dEznNx+VME=C3(%TkoD+0`qEXPviUce~g3X z&6g>Wm49j(lcfL8W%A+%r?0m^8mw)fR zKlkj%K>3@Q5xjvX;@;$KuFm4oOnk2w^g_I6Voqw?=l#r^R>zln=UbN?p6c;nm3Woe z=6aPCOkAsPeqLW49CLV=f8;&ii0>&J%C@XmcpFQ#g-`UqFK}<#peBC&pT>K$>2^o{ zUVN{)>cCxj(RDY<+7=k^y%sU^O3B*E%ipv(HFque$T)59#OQV3!gr@RXLA*Xzcta` z^fNQ;&H0}Xq~zbc(4O_5FWZnP&>!( z$sbDBFU#HG=zX&7P1)lM|JJaJIkPLS<$sVdYpE1#`LQjZCmwBo7;Lb4x@~ diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.dll index 2e4576da8dffebd0e8db19c1c84be958510744d0..477716731b9682725ad61241d001cf31b06c6be3 100644 GIT binary patch delta 316 zcmZpuX{edd!SXrO=Ih2D14%}c$$KSL8BI1nmi#Fs;CREjiu3my?~V3vmxv_v-rD>| zXAz5?k)8nqg9#&pzM-Cho~e!g?W;Jg@uu^ zrBQNHYMPM+1A`nRgXH9SCX$<<8a`)aIl?r5)#MAt0Rlgj9wg-4zUHuAH~EyCXT|Kv z1}2jgpn?-%fwACVr8VQBwVNNCtY+jiVPIfj1Y(oT)6Jxr7>zb>wph&= zY{a0=V8M{cV8md+V9b!rV8~#`V9JojkO~$}0@8^{s+O0YWp&*JlNF`o!iM^9Hvx9>W5nRM@xx=}0l`e{d(8?(ef`f}n z7RxPN1XnlzhbS)Mo=G32e0-1h{dlj}?R5ti&PY{mhL_YO%)Gj*gxSI^=WAEh>r&oz zc3#TI_NT3%*`M_XC-yxG5E9tH#f$uglw72#3R4;gu6aNum0AcD@r>y#jc8L!B?TTW z5^&9Z=-My;n>d4&*=O^?c56ldWO}*tw*BPk_&quNH8eC!6SHzWF|ob2ceJ0M$D;$; zPEKtR=A_C1fFPN@-KNBSjR@Tg7^WF^ cBg~rP9}1@cYKB|Uj1L}AJJ(tumbCuJKP2N?#sB~S diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.pdb index c53382faa67248dd6046d99d7974d104bc505a4c..31760e9e29a805924895ecabc0be86603ad7e205 100644 GIT binary patch delta 1047 zcmbP{FehO`fr5w@1B0?tPJR*t1H(_H2MIa1uQ{yOO+Mx3Suy(v)BIHvCmaitRAXdN z0Ah6@)&pWwAU+Ai?|}F#5dTpFYGz<$U{+^jhy~(aAl?DQ2Y~nl5MNXW$%6nR!!00R zK!cG%Nn^4jqp%22#6trj^BPJ|*nFAsG85zG$;(+3?L=7A8Q2*10ZDcS5%w?!W(HZt zG9W3%q|C^|AjG1;!ohGxLxF{p;g&`Mklm!Y07!lYlAH{TTASHe|1i}%FgyumQF5Cg z$y>W1%f?eJz1}u$^8enw=Bi(h{armVpz&K3D+9yYklR_e9RzC4f5@}hsxFDN^qZ?C z&b89pX@Op@-aF@)hciqkv4!nUE1$B!|5g5%)2B|Y-I&R(RUyxEX`bct7iSDItM*(s zmRqVBlc@b}hmyBkYuEO_$1CKr>-iSMI(}$kG-Ehn?I7^Hr|SZ5P2A$O8Vwc`A|f{_ zW^7>Y%~eQPJ@@+()}mD(XU=8c!n$XJ;RIm`ah4r-HhB7G=kh(sRKDkZDD;>3`QLqM zHd)NKx#V^!T#0$NZ&kGxZ)Re;zVa9CHV5ClUETJKuYO&>d&g9J%iXOV&-aL0c}Ud@ zU6E@oE&7pb(5<^OD|zbX=$P**9L#_DFRuC=b9IyJr^nVh9s<)+obSuOee>(mPlGwX zY+2t{Zhieh;b+I8^DNyTcBb-vzILL?iFe)w4)cujeIT9z_7@7s8FPqyD>@UOq(a&}pk(I4~oIWKE2n=_r=&(Uu* z$ItKU$(w7I@Dv}CoHsx5r_^TipDL%9Eq@+7H`wxQ+v~bd>oUHU-Ot;&aK`ek##IvQ zquOofe3^LkLY?OH>Jt`y$&F3cllK)h9{u_5iS%Rxx!y?hhz&P2^ z%rq_4A~7j7(KON0EHTX_(ZW2*z{0}F*wQFDDK*W=V)K5k6-*NAZniC8IKarzas8Og zSrc#9+2WJ)&&51qo?OqXD`EL1bv{D_1H*;eGX!0xuJLS7iWfVX9r6e$DJz$flLO2G zr!84;Gbk`J^c_ymQT=|$b;jYm$)~oNB~Sj(E8%?Q$SjcdDa^}RB4l2>Ps>qgxqd2g zw|io4s&i>hiJot2afTkmoLk0mhZz{S8PZ>TkF#A{>bSF|jgNIw>9xsGd{PpYyqR+t z95@(G1bpQy(-(D`{JEz>V0uye<{mx+Iblb}Wgd*nf*6+-GA^rST-L|9Z0Y9nI-bl- G3=9AZbeVnt delta 1031 zcmXZbeK6a190&04S0WyI!XlO|6=I4|-7*g+rk-N;P-jxZ%|lJ(!9?!RyE%%BRF0Om ziAB5JDyC|gG*l(gc^Y9It4`x-8;$O=)@dnGM48&z&u!nk*ZceMzR#cE#_X@NrG*p+ z9{}7Lf`S|Xz%xk&%I%ykw(UJ$*n>~9Oj37@vR*oxO7Mih1>u44MffAe5UYqS#GWTI z3?P7B5M&_g5cd#+h*5;z>##pu5X>QWEENI@RTc>y@yJUw^}lBM|NW|F2F_T(F4^~J zw=f*q3t+$il2!m`l?qUR42zK@S-3+qa6nVg)?l1ULEC^iYBqAN^lnCS14$cj;H|+} z?pp|xK6NG3d&k|d$`g?9uJ^Z)@{NJ+Q@=h7zr0h0=0|Zv=JS>SbR--2h6sm>pj}r? zs7Gs>cV5EUF?`ZjVn*iU%!QiinkoJ8>cX`N1XeZa&K3Fw|IOp|R>e2vp^W+7ufRVHOp6=G4OWWi%Ru8A`JsY))!(XB!Gj4Y3Vs7~O(Mgi& z9!?~;CdAO66BWP73ehY^H}l%l6g_MGA@@(H-JU+3#Rkvel#|X%?l3Z2GTkHJPs?67Q|+A z*}*i;ux*TsNqHjMkD zdpGuqd~_^n)>kj1Ve!Nox5ZWfj(`LelTMDd{^+g>d;f(Sb6A#%B@wym3N47R2FXp` wvqOO^r)!&Wt{Vq^oib>T*R)`rT^z%qA{r`~P*DICWl(V$DsE|}eB)660yxW~DF6Tf diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.dll index 42fbe73ed72db9364eb1ccccc18dec1ad396955d..6d06333d04a1f77851a053138468757cde03b199 100644 GIT binary patch delta 384 zcmZqJq1CWMYeEOhE#tVujXkYBjIBLPtv$@GJuIy~tgSt4TYK1l)G?Y&Z>?wdmo;HP z0Hgf~HY1Q}GW}ycyELOoJ8uI!5OZwjZQ$I_ERg=qfrW*Uv87RR zQfiu!#r9K4TzYyecWi_AP5(22D?osG|C2m5jYRKlvx;vW=`@%#J!T?TwE|Q$y9_D{ zRBzY$rK!5xe@Srb>s!*>zfa_v&cq4w57_P7r%&M$W@0qjzIqy0GGnk2gEoT&Ln4C_ zg8_pvLo$OQgBgP?wdmo;WU z0Hgf~HY1Q}JpE%myELP5J8uI!5OZwjZQ$I_Ea1C3z(UrI!)3#2z9TOb0}gJ#(#*N< zo`s>F0Rw{xBZEGWp=WBSot$i8nV6Vrl4xLLX_01OWRPr-oMvg6YHE>UoR*SkYG9t6 zoSJNDu>DjLm!2NW*R>Tlr~jG26(GQv_v13-_roqz96Be}Jhkng9y5`vS^+950uu$P z4^p!=%w(@nw(@`cV*B@rT+^92LH+@|ef#t&T*6F@hTB(9<4R@>He}FdNCrX+21|xS zAWUU20g?s`MnJv=LmChp0eQ(_oCXxL1gbCvil#6a17%ZyYE6N1=3p~Yfutpa!Suu# ZT&Aps40;R(+XZKFr7>=2oW=E@5dhH)Z-@W@ diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.pdb index 5971d0e3dbcd70ee2dcf381803a9558c4a2f92ac..2b0311d90fe3f0a98b6bc044c7d64f3275652644 100644 GIT binary patch delta 27124 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 DpMz$> diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.WebSockets.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.WebSockets.dll index e5c84a7fd44384e8ecdad34ebec833ab37d6723a..3b4141647f2625001e3f7284147352ff46905243 100644 GIT binary patch delta 306 zcmXYoF-yZx6ou~#tsn(Wafy_of`U*?UT$8}n@u+nECnasUP3bIR#(kfp@TG_gE;9b zRNgKs6cH@>0d*D~`~kY?Q_AI>%l*!|Stsk9c1y1}GyU7%zQsiTWvwuw7Uq{`&Go6; z_1SZ_*&Du(5AOz_s=Yc_CbT(#VBokmw|#7oMDE3I;HL@6D3QJl1DOg*&4?4B7h)VG zDU!Nas~V-{m~606wIU{L@Hpsc#9P=2CN^ouCPk?vozW bU!nF`lSJnTln(>Hj9>#-RWg`j^uvAu5T;q3 delta 306 zcmZoDX(*Y{!4k&6_j6-Ujs&CeKQOFm@qQv0~vazhT6%=7M6*LsV0dAMwS+77Dfii2FYobmZ_!|DaL6jiKYhT z$;qk7mIj+=>k2ZluunHUG>m*yKE8upxssLoyIrFjz7q z0%0nH36L~kFaq)|7}9{)2*^tY<20a{B~XPaP&9?X7$}RxS7%7KO+E~HCGY< diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Networking.dll index ac97186460e3b8907647c411d48de34a23d4150d..a6163a0a9f8604ad0c972867f36d0aab151753bc 100644 GIT binary patch delta 361 zcmXYoJxIe)5XbLn>Z3}fQVQZyU0e$JcuCq92M5JbD2TJXghX9C_<^mhNQp=WK_ne? z6Tv|c(Z0b=L`o+oq2QzlX3@dAs?So6yC3(v|5fXmYCUtXCs~QrFgaDp&m(d0-KSf2%LA}wGAqYCgVDULQc84-IJWB%3NVTw6>7J!6#sY|*ngCMCNA&7 zQUe!~pC{63rPG-|y0{vAc~axya|8S1JzGxq?0>$fEKRyojrG#(*frnfcqkD!004gg3;bkOy1jsVE}8EHNEn aTyZBr!^I{xV+3SS`A7>F5l1cji~azLj&X+o delta 361 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 M4Oe6%XM;ii4+tSb@Bjb+ delta 22994 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 LYv?rpwj%!z%Uw5k diff --git a/unity/org.gamecult.cultlib/package.json b/unity/org.gamecult.cultlib/package.json index b695c7b6..ad99d1ba 100644 --- a/unity/org.gamecult.cultlib/package.json +++ b/unity/org.gamecult.cultlib/package.json @@ -1,7 +1,7 @@ { "name": "org.gamecult.cultlib", "displayName": "CultLib", - "version": "1.0.51", + "version": "1.0.52", "unity": "2021.3", "description": "CultCache, CultNet, and CultMesh managed runtime assemblies for Unity.", "license": "MIT", From 81ca92fe403c11d3100d03459e9fd80b4f9951cb Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 19 Aug 2026 00:56:37 +0200 Subject: [PATCH 103/283] Keep CultCache readers on one committed generation --- .../DirectoryMessagePackBackingStore.cs | 133 ++++++++++-------- .../BackingStoreTests.cs | 97 +++++++++++++ .../Plugins/GameCult.Caching.MessagePack.dll | Bin 47104 -> 47616 bytes .../Plugins/GameCult.Caching.MessagePack.pdb | Bin 20852 -> 21032 bytes .../Runtime/Plugins/GameCult.Caching.dll | Bin 86016 -> 86016 bytes .../Runtime/Plugins/GameCult.Caching.pdb | Bin 30208 -> 30208 bytes .../Runtime/Plugins/GameCult.Logging.dll | Bin 6656 -> 6656 bytes .../Runtime/Plugins/GameCult.Logging.pdb | Bin 9544 -> 9544 bytes .../Plugins/GameCult.Mesh.Quic.Native.dll | Bin 15872 -> 15872 bytes .../Plugins/GameCult.Mesh.Quic.Native.pdb | Bin 12316 -> 12316 bytes .../Runtime/Plugins/GameCult.Mesh.dll | Bin 695296 -> 695296 bytes .../Runtime/Plugins/GameCult.Mesh.pdb | Bin 205548 -> 205548 bytes .../GameCult.Networking.WebSockets.dll | Bin 14848 -> 14848 bytes .../Runtime/Plugins/GameCult.Networking.dll | Bin 510976 -> 510976 bytes .../Runtime/Plugins/GameCult.Networking.pdb | Bin 246920 -> 246920 bytes unity/org.gamecult.cultlib/package.json | 2 +- 16 files changed, 174 insertions(+), 58 deletions(-) diff --git a/src/GameCult.Caching.MessagePack/DirectoryMessagePackBackingStore.cs b/src/GameCult.Caching.MessagePack/DirectoryMessagePackBackingStore.cs index 0c980c61..4f1a2521 100644 --- a/src/GameCult.Caching.MessagePack/DirectoryMessagePackBackingStore.cs +++ b/src/GameCult.Caching.MessagePack/DirectoryMessagePackBackingStore.cs @@ -21,6 +21,8 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore public const string BeforeRecordPageWriteStage = "before-record-page-write"; ///

    S$B9yIBAighj;p= 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

    OU_g@ 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

    PXm5RTJu-2zt9}EifsyA!9HR4($#>s=+}XB zBf8;PsWi;ig*Gw94_Je2n5_>DF$Z`QyG7;_1oW%WUCd!?tvzfady3u9!uaOc3;g|% zj{W<@JOs{}(9?h-L8s^lj`~FYBmOUJk zEBPVXskGvwY7byF{S2^yo(IHXS6iu_qJWoBE#N|00JxYQ09;B30KZ8m05cMPhdx&q z;v=q2TZr0k(=L~8GLn;#oD5zEm+O6!zg_Z&XuyZ+kQ5I=yj8zLiuX(LBPA%zJp$TB7jVQ^hfrsfD;QyH!1 zQ!ahmz=mvYQ$QEjbe0#Bb(1G%`f{84*Y#)8oBEdCoNnuwP2cX@bkp)>R}|l@i;w)d zZWUKoq;K6^yrTYw;*0gq7Qa8GZR8JA6l>%}^9C(CZ2kS&%!9dWo;rJA?)xLvcNAC8 zZ1mk5P$bO758}+}EmL%-*TDWby-u%YC=oM)1v`bK$OgxxBq*X9%<+s0r*I#0`|;W> zu^1UChF8uyd}%^#CaA*gV=?@cptzeOCf6f2DLmp7-iW%JO@RV`OC>g)M_|-c6HGBd za>X#zTDTRQh+-vpZKPIl3df6c+a`6MGKsl`$K1lO2qI|)K@<)OpGm>OkHm=fu%J^~ zf}pD!yr#IPE$&;et2u>3X2c>a@#T}Sq zG|32?Zo(}btkr6`DIyy8V2I^`j|dSua)2)kX(H(uCT^1YrD)_zpRvVSo)Q0gaZ?E| z-IOw4AB>%UqvhS+X&EX$*1lo=daiR*FQrb=-BlPhNcl$02~|fNR!NFI1$kJ2XEbpH z2>D=|SV66(VzIpf4WL^EoV%+c2}LB`?RQtX>z$3o;aOEJz3zH!n2Mc>MC^oE6&C1h z3?-OU6*zKST5R#ytR(9#Djn^36E1djtPX|I1D5pN+Ls>aEAH#q(cLk#HHH67VssIZ z){dFYnM_xAI^8!booeguTG!Q<%A_*uy1V;2y4JR@Tbu4kb!IYsneNoc>e+*=c(U_O z@fp6SK|e_B+Uq#*A7j+uXM~zr#cf@2{Ux9;%_{Egni4(zgS=9oJ95<%t?TB!y7a~~ z#n-#89}mXs?r1A1m^YUcV0Ol`H7kC)W8U+tGIN)13oV81($y&N#BhC_S1v6c=$=vh zr|voT&VQ&FxwwG$lT!Z}`QgPAxza&1M@HrxWXplzv6R7I7v7oD`0K-e#HA@kZJ@ho z9Y!0dj2!F0>xM=LxNFg|)&ZtLrSRi~u+fLnO{wDHdF_U<+)AktXF;4<_;nTUgVfay K@?$ofGX4)6ziC$h literal 16896 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 Yud7&KkNd6t-`sMQy8kBqe{X^R3-rqFnE(I) diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.Quic.Native.pdb index a73f4ef6cf4dec36f835d3c95792602d11f3df4f..c53382faa67248dd6046d99d7974d104bc505a4c 100644 GIT binary patch delta 2860 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%0DwZ-XGMgyh47MG(G@(wDrM#$@> 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

    d-m+;lQpG1TVu-TqJ?*7pJ?os7BnZ} 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 Z{||g}4;+$zTlNVWdjH?g|L;8TzW^0#?VbPt literal 45568 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 jxj^+f;Hh|g?f|8#Q9wor9Dv;IyTyzQy`x%&d5 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 delta 12537 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 G%Krnp`LD|W diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.dll b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Caching.dll index 4d90585e932b6b1706e3b6a74b7fc03263176086..5a8974074bd1e8c87e707fa4d73ae141b1f2192d 100644 GIT binary patch literal 86016 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

    OU_g@ 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

  • J&xxr&Ly11OkE#;rE?_*CoUGz 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 diff --git a/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.pdb b/unity/org.gamecult.cultlib/Runtime/Plugins/GameCult.Mesh.pdb index b212292531091089b87d9c32e8947a81885455b7..87fe95e4256f70e0e4b9ab4d121f99fef3aa6656 100644 GIT binary patch delta 38407 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 delta 38331 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­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 delta 24190 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 B6+8d{ diff --git a/unity/org.gamecult.geometry/package.json b/unity/org.gamecult.geometry/package.json index 7ac223b5..27877abd 100644 --- a/unity/org.gamecult.geometry/package.json +++ b/unity/org.gamecult.geometry/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "org.gamecult.cultmath": "0.1.0", - "org.gamecult.cultlib": "1.0.7" + "org.gamecult.cultlib": "1.0.44" }, "samples": [{"displayName":"Planetary Field Viewer","description":"Planetary geometry CPU/HLSL parity viewer.","path":"Samples~/PlanetaryViewer"}] } From b65619ff95f21633217a9ccae4d09cf9665a1719 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 22 Jul 2026 05:44:34 +0100 Subject: [PATCH 051/283] Reference Geometry test plugins explicitly --- .../Tests/Editor/GameCult.Geometry.Tests.Editor.asmdef | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/unity/org.gamecult.geometry/Tests/Editor/GameCult.Geometry.Tests.Editor.asmdef b/unity/org.gamecult.geometry/Tests/Editor/GameCult.Geometry.Tests.Editor.asmdef index 817ba8f6..1b93ed0d 100644 --- a/unity/org.gamecult.geometry/Tests/Editor/GameCult.Geometry.Tests.Editor.asmdef +++ b/unity/org.gamecult.geometry/Tests/Editor/GameCult.Geometry.Tests.Editor.asmdef @@ -2,15 +2,16 @@ "name": "GameCult.Geometry.Tests.Editor", "rootNamespace": "GameCult.Geometry.Tests.Editor", "references": [ - "CultMath", - "GameCult.Geometry", "GameCult.Geometry.Unity" ], "includePlatforms": ["Editor"], "excludePlatforms": [], "allowUnsafeCode": false, - "overrideReferences": false, - "precompiledReferences": [], + "overrideReferences": true, + "precompiledReferences": [ + "CultMath.dll", + "GameCult.Geometry.dll" + ], "autoReferenced": false, "defineConstraints": [], "versionDefines": [], From c4543b9443e96d848260ef00254d2d3c0fa6a9d2 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Fri, 7 Aug 2026 20:02:24 +0100 Subject: [PATCH 052/283] Add canonical min-max rectangle --- src/CultMath/CultMath.csproj | 2 +- src/CultMath/rect.cs | 59 ++++++++++++++++++++++++ src/CultMath/rect.cs.meta | 2 + tests/CultMath.Tests/MathTests.cs | 35 ++++++++++++++ unity/org.gamecult.cultmath/package.json | 2 +- 5 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 src/CultMath/rect.cs create mode 100644 src/CultMath/rect.cs.meta diff --git a/src/CultMath/CultMath.csproj b/src/CultMath/CultMath.csproj index 73b3fd51..dfa5475d 100644 --- a/src/CultMath/CultMath.csproj +++ b/src/CultMath/CultMath.csproj @@ -8,7 +8,7 @@ CultMath CultMath CultMath - 0.1.0 + 0.1.1 Clean-room C# math shaped for HLSL-style renderer code. GameCult https://github.com/GameCult/CultMath diff --git a/src/CultMath/rect.cs b/src/CultMath/rect.cs new file mode 100644 index 00000000..51e05c19 --- /dev/null +++ b/src/CultMath/rect.cs @@ -0,0 +1,59 @@ +namespace CultMath; + +///