fix(render): eliminate EnvCell identity collisions
This commit is contained in:
parent
999201cca7
commit
b7b9aaa9dd
7 changed files with 129 additions and 23 deletions
|
|
@ -120,7 +120,9 @@ public sealed class EnvCellLandblockBuildBuilder
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Source: WB EnvCellRenderManager.cs:94-103 (verbatim arithmetic).
|
||||
/// Collision-resistant successor to WB EnvCellRenderManager.cs:94-103.
|
||||
/// The legacy polynomial and its installed-DAT collision remain covered by
|
||||
/// Core conformance tests.
|
||||
/// </summary>
|
||||
public static ulong ComputeGeometryId(
|
||||
uint environmentId,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
// four reverted RR7 variants couldn't fix.
|
||||
//
|
||||
// Sources ported byte-for-byte:
|
||||
// GetEnvCellGeomId <- WB EnvCellRenderManager.cs:94-103
|
||||
// GetEnvCellGeomId <- collision-resistant successor to WB's content key
|
||||
// PrepareRenderBatches <- WB EnvCellRenderManager.cs:247-373
|
||||
// Render(filter:) <- WB EnvCellRenderManager.cs:395-511
|
||||
// RenderModernMDIInternal <- WB BaseObjectRenderManager.cs:709-848 (single-slot variant)
|
||||
|
|
@ -353,14 +353,15 @@ public sealed unsafe class EnvCellRenderer : IDisposable
|
|||
|
||||
// ---------------------------------------------------------------------------
|
||||
// GetEnvCellGeomId
|
||||
// Verbatim copy of WB EnvCellRenderManager.cs:94-103.
|
||||
// Shared collision-resistant content identity. Core retains WB's original
|
||||
// polynomial for conformance evidence and the installed-DAT collision test.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Returns a deduplicated geometry ID for an EnvCell based on its environment,
|
||||
/// cell structure index, and surface IDs. Bit 33 is set to distinguish from
|
||||
/// per-cell IDs (which use bit 32).
|
||||
/// Source: WB EnvCellRenderManager.cs:94-103 (verbatim).
|
||||
/// See <see cref="AcDream.Core.Rendering.Wb.EnvCellGeometryIdentity"/>.
|
||||
/// </summary>
|
||||
public static ulong GetEnvCellGeomId(uint environmentId, ushort cellStructure, List<ushort> surfaces)
|
||||
=> EnvCellLandblockBuildBuilder.ComputeGeometryId(
|
||||
|
|
|
|||
|
|
@ -3,21 +3,52 @@ using System.Collections.Generic;
|
|||
namespace AcDream.Core.Rendering.Wb;
|
||||
|
||||
/// <summary>
|
||||
/// Computes WorldBuilder's content identity for an EnvCell shell.
|
||||
/// Computes acdream's collision-resistant content identity for an EnvCell shell.
|
||||
/// Equal environment, cell-structure, and ordered surface tuples share one
|
||||
/// prepared geometry payload even when they occur under different cell IDs.
|
||||
/// </summary>
|
||||
public static class EnvCellGeometryIdentity
|
||||
{
|
||||
private const ulong FnvOffsetBasis = 14695981039346656037UL;
|
||||
private const ulong FnvPrime = 1099511628211UL;
|
||||
private const ulong PayloadMask = 0x0FFF_FFFD_FFFF_FFFFUL;
|
||||
private const ulong Namespace = 0xE000_0002_0000_0000UL;
|
||||
|
||||
/// <summary>
|
||||
/// Source: WorldBuilder <c>EnvCellRenderManager.GetEnvCellGeomId</c>,
|
||||
/// lines 94-103. Bit 33 separates content identities from per-cell IDs,
|
||||
/// whose synthetic geometry requests use bit 32.
|
||||
/// Hashes the complete typed tuple with FNV-1a and places it in a dedicated
|
||||
/// high-bit namespace. Bit 33 remains set for compatibility with existing
|
||||
/// synthetic-geometry diagnostics; the top nibble prevents overlap with
|
||||
/// DAT IDs and older low-bit synthetic IDs.
|
||||
///
|
||||
/// WorldBuilder's original 31× polynomial is retained in
|
||||
/// <see cref="ComputeLegacyWorldBuilder"/> for conformance evidence, but it
|
||||
/// is not a valid resource identity: installed retail DAT cells 0x00030175
|
||||
/// and 0x01BC0105 produce the same value for different geometry tuples.
|
||||
/// </summary>
|
||||
public static ulong Compute(
|
||||
uint environmentId,
|
||||
ushort cellStructure,
|
||||
IReadOnlyList<ushort> surfaces)
|
||||
{
|
||||
ulong hash = FnvOffsetBasis;
|
||||
AddUInt32(ref hash, environmentId);
|
||||
AddUInt16(ref hash, cellStructure);
|
||||
AddUInt32(ref hash, checked((uint)surfaces.Count));
|
||||
for (int i = 0; i < surfaces.Count; i++)
|
||||
AddUInt16(ref hash, surfaces[i]);
|
||||
|
||||
return (hash & PayloadMask) | Namespace;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verbatim WorldBuilder <c>EnvCellRenderManager.GetEnvCellGeomId</c>
|
||||
/// lines 94-103. Kept only to demonstrate and regression-test the real DAT
|
||||
/// collision that required the stronger internal identity.
|
||||
/// </summary>
|
||||
public static ulong ComputeLegacyWorldBuilder(
|
||||
uint environmentId,
|
||||
ushort cellStructure,
|
||||
IReadOnlyList<ushort> surfaces)
|
||||
{
|
||||
long hash = 17;
|
||||
hash = unchecked(hash * 31 + environmentId);
|
||||
|
|
@ -26,4 +57,24 @@ public static class EnvCellGeometryIdentity
|
|||
hash = unchecked(hash * 31 + surfaces[i]);
|
||||
return (ulong)hash | 0x2_0000_0000UL;
|
||||
}
|
||||
|
||||
private static void AddUInt16(ref ulong hash, ushort value)
|
||||
{
|
||||
AddByte(ref hash, (byte)value);
|
||||
AddByte(ref hash, (byte)(value >> 8));
|
||||
}
|
||||
|
||||
private static void AddUInt32(ref ulong hash, uint value)
|
||||
{
|
||||
AddByte(ref hash, (byte)value);
|
||||
AddByte(ref hash, (byte)(value >> 8));
|
||||
AddByte(ref hash, (byte)(value >> 16));
|
||||
AddByte(ref hash, (byte)(value >> 24));
|
||||
}
|
||||
|
||||
private static void AddByte(ref ulong hash, byte value)
|
||||
{
|
||||
hash ^= value;
|
||||
hash = unchecked(hash * FnvPrime);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue