Nebula
Interest

InterestGrid

A uniform spatial hash over absolute world coordinates: the region arithmetic every part of interest management shares (gateway, worker, standalone services).

generated from the sources
public readonly struct InterestGrid : IEquatable<InterestGrid>

A uniform spatial hash over absolute world coordinates: the region arithmetic every part of interest management shares (gateway, worker, standalone services). One region is one cell of the grid; its id is the pinned three-axis 21-bit packing RuntimeGrid.PackId uses, so a chunked world's region ids and its container ids are literally the same numbers.

Positions are doubles because a region key must not depend on the floating origin: wire poses are container-local, and both ends add the container's absolute center in double before asking for a key. Shift the origin and every key stays what it was, which is what lets a gateway and a worker with different origins agree on one set of subscribed regions.

The packing is duplicated here rather than called: RuntimeGrid lives in the Unity-only Nebula.World assembly, which the standalone gateway does not compile. InterestPackingPinTests asserts the two agree for sample coordinates, and neither may change: ids are persisted.

The far band. 21 bits of edge-sized regions reach ±2^20 edges from the origin (±67,108 km at 64 m), which a star system outgrows. The packing uses 63 bits, so the top bit marks a far region: the same three 21-bit fields counting cells FarScale edges wide (2,048 m at 64 m, so ±2,147,483 km). A position inside the near cube [MinCoordinate, MaxCoordinate] on every axis gets exactly the key it always had; a position outside it gets a far key. The near cube's faces lie on far-cell edges, so the two bands partition space with no overlap, and a far key for a cell inside the near cube is never made. Both ends derive the band from the grid alone, so no setting, message or protocol version changed.

Constructors

InterestGrid

public InterestGrid(double edge, bool planar = true);
public InterestGrid(double edgeX, double edgeY, double edgeZ, double offsetX, double offsetY, double offsetZ, bool planar);

Fields

MinCoordinate

public const int MinCoordinate = -(1 << 20);

Coordinates outside [MinCoordinate, MaxCoordinate] cannot be packed; collectors clamp to this range.

MaxCoordinate

public const int MaxCoordinate = (1 << 20) - 1;

FarScale

public const int FarScale = 32;

A far region is this many edges wide on each axis. Never change this: both ends must agree.

FarBit

public const ulong FarBit = 1UL << 63;

The bit that marks a far region's key (IsFar); the plain packing never sets it.

EdgeX, EdgeY, EdgeZ

public readonly double EdgeX, EdgeY, EdgeZ;

Region edge in meters per axis. Y is unused (and meaningless) when Planar.

OffsetX, OffsetY, OffsetZ

public readonly double OffsetX, OffsetY, OffsetZ;

World coordinate of the region-0 lower corner per axis; see Resolve.

Planar

public readonly bool Planar;

Regions are infinite columns: the Y coordinate of every region is 0 and Y never enters a key.

Properties

IsValid

public bool IsValid { get; }

A grid with a positive edge on every axis it uses. A default-constructed grid is not valid.

Methods

IsFar

public static bool IsFar(ulong region);

Whether a (plain, unsalted) region key is a far region, outside the near cube.

Resolve

public static InterestGrid Resolve(in InterestSettings settings, double worldCellX, double worldCellY, double worldCellZ, bool cellsCentred);
public static InterestGrid Resolve(in InterestSettings settings, double worldCellSize = 0, bool cellsCentred = false);

Derive the grid both ends must agree on from the resolved settings and, when the game has a world definition, its cell size. The edge is snapped to an integer division of the cell so region edges coincide with cell edges, and the offset places region boundaries on those cell edges. Baked cells are centered on coord × CellSize (cellsCentred: offset −CellSize/2); RuntimeGrid cells start at coord × CellSize (offset 0). Pass 0 for no world definition.

SnapEdge

public static double SnapEdge(double wanted, double cell);

The snapped edge the settings ask for, before a key is ever made; for logging and validation.

PackRegion

public static ulong PackRegion(int x, int y, int z);

Pack a region coordinate: three signed 21-bit fields, x in the high bits. Never change this.

UnpackRegion

public static void UnpackRegion(ulong region, out int x, out int y, out int z);

RegionOf

public ulong RegionOf(double x, double y, double z);

The only place a region key is made. Absolute world position in, packed region id out: a near region inside ±2^20 edges of the origin on every axis, a far region (IsFar) outside it.

CoordOf

public void CoordOf(double x, double y, double z, out int cx, out int cy, out int cz);

Near-band region coordinate of an absolute world position, clamped to the near cube (Y is always 0 on a planar grid).

BoundsOf

public void BoundsOf(ulong region, out double minX, out double minY, out double minZ, out double maxX, out double maxY, out double maxZ);

The region's box in absolute world coordinates. A planar grid's regions are columns, so Y spans ±infinity: a caller measuring a distance to the box gets the column distance it wants.

CenterOf

public void CenterOf(ulong region, out double x, out double y, out double z);

Center of a region in absolute world coordinates (Y = 0 on a planar grid, where there is no center).

SqrDistanceToRegion

public double SqrDistanceToRegion(ulong region, double x, double y, double z);

Squared distance from a point to a region's box; 0 inside. Planar grids measure in the XZ plane only.

CollectDisc

public void CollectDisc(double x, double y, double z, double radius, List<ulong> into);

Append every region whose box is within radius of the point. Each region appears once per call; a caller unioning several foci deduplicates (a HashSet or the subscription set itself).

CollectBox

public void CollectBox(double minX, double minY, double minZ, double maxX, double maxY, double maxZ, List<ulong> into);

Append every region overlapping an absolute box (a portal's window, a container).

Matches

public bool Matches(in InterestGrid other, double tolerance = 1e-3);

Whether two grids would produce the same keys. The subscribe message carries the grid so the worker can reject a mismatch loudly instead of filtering with ids the gateway never meant; the tolerance absorbs the f32 round trip of that message, nothing more.

Equals

public bool Equals(InterestGrid other);
public override bool Equals(object obj);

GetHashCode

public override int GetHashCode();

ToString

public override string ToString();

On this page