Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/RunUnityTests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ jobs:
# - 2019.4.40f1
- 2020.3.48f1
- 2021.3.45f1
- 2022.3.55f1
- 2022.3.60f1
- 2023.2.20f1
- 6000.0.32f1
- 6000.0.43f1

steps:
- name: Checkout repository
Expand Down
9 changes: 2 additions & 7 deletions Assets/Mirror/CompilerSymbols/PreprocessorDefine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,10 @@ public static void AddDefineSymbols()
HashSet<string> defines = new HashSet<string>(currentDefines.Split(';'))
{
"MIRROR",
"MIRROR_81_OR_NEWER",
"MIRROR_82_OR_NEWER",
"MIRROR_83_OR_NEWER",
"MIRROR_84_OR_NEWER",
"MIRROR_85_OR_NEWER",
"MIRROR_86_OR_NEWER",
"MIRROR_89_OR_NEWER",
"MIRROR_90_OR_NEWER",
"MIRROR_93_OR_NEWER"
"MIRROR_93_OR_NEWER",
"MIRROR_96_OR_NEWER"
};

// only touch PlayerSettings if we actually modified it,
Expand Down
2 changes: 2 additions & 0 deletions Assets/Mirror/Components/Discovery/NetworkDiscoveryHUD.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ void Reset()
}
#endif

#if !UNITY_SERVER
void OnGUI()
{
if (NetworkManager.singleton == null)
Expand Down Expand Up @@ -126,6 +127,7 @@ void StopButtons()

GUILayout.EndArea();
}
#endif

void Connect(ServerResponse info)
{
Expand Down
2 changes: 2 additions & 0 deletions Assets/Mirror/Components/GUIConsole.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ void Update()
visible = !visible;
}

#if !UNITY_SERVER
void OnGUI()
{
if (!visible) return;
Expand All @@ -129,5 +130,6 @@ void OnGUI()

GUILayout.EndArea();
}
#endif
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,8 @@ public override void OnRebuildObservers(NetworkIdentity identity, HashSet<Networ
}
}

// internal so we can update from tests
[ServerCallback]
internal void Update()
void LateUpdate()
{
// rebuild all spawned NetworkIdentity's observers every interval
if (NetworkTime.localTime >= lastRebuildTime + rebuildInterval)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ public override void OnSpawned(NetworkIdentity identity)
[ServerCallback]
public override void OnDestroyed(NetworkIdentity identity)
{
// Don't RebuildSceneObservers here - that will happen in Update.
// Don't RebuildSceneObservers here - that will happen in LateUpdate.
// Multiple objects could be destroyed in same frame and we don't
// want to rebuild for each one...let Update do it once.
// We must add the current scene to dirtyScenes for Update to rebuild it.
// want to rebuild for each one...let LateUpdate do it once.
// We must add the current scene to dirtyScenes for LateUpdate to rebuild it.
if (lastObjectScene.TryGetValue(identity, out Scene currentScene))
{
lastObjectScene.Remove(identity);
Expand All @@ -47,9 +47,8 @@ public override void OnDestroyed(NetworkIdentity identity)
}
}

// internal so we can update from tests
[ServerCallback]
internal void Update()
void LateUpdate()
{
// for each spawned:
// if scene changed:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,10 @@ public override void OnDestroyed(NetworkIdentity identity)
{
CustomRanges.Remove(identity);

// Don't RebuildSceneObservers here - that will happen in Update.
// Don't RebuildSceneObservers here - that will happen in LateUpdate.
// Multiple objects could be destroyed in same frame and we don't
// want to rebuild for each one...let Update do it once.
// We must add the current scene to dirtyScenes for Update to rebuild it.
// want to rebuild for each one...let LateUpdate do it once.
// We must add the current scene to dirtyScenes for LateUpdate to rebuild it.
if (lastObjectScene.TryGetValue(identity, out Scene currentScene))
{
lastObjectScene.Remove(identity);
Expand All @@ -76,9 +76,8 @@ public override void OnDestroyed(NetworkIdentity identity)
}
}

// internal so we can update from tests
[ServerCallback]
internal void Update()
void LateUpdate()
{
// for each spawned:
// if scene changed:
Expand All @@ -101,7 +100,7 @@ internal void Update()
lastRebuildTime = NetworkTime.localTime;
}

// no scehe change, so we're done here
// no scene change, so we're done here
continue;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
using UnityEngine;

namespace Mirror
{
internal class HexGrid2D
{
// Radius of each hexagonal cell (half the width)
internal float cellRadius;

// Offset applied to align the grid with the world origin
Vector2 originOffset;

// Precomputed constants for hexagon math to improve performance
readonly float sqrt3Div3; // sqrt(3) / 3, used in coordinate conversions
readonly float oneDiv3; // 1 / 3, used in coordinate conversions
readonly float twoDiv3; // 2 / 3, used in coordinate conversions
readonly float sqrt3; // sqrt(3), used in world coordinate calculations
readonly float sqrt3Div2; // sqrt(3) / 2, used in world coordinate calculations

internal HexGrid2D(ushort visRange)
{
// Set cell radius as half the visibility range
cellRadius = visRange / 2f;

// Offset to center the grid at world origin (2D XZ plane)
originOffset = Vector2.zero;

// Precompute mathematical constants for efficiency
sqrt3Div3 = Mathf.Sqrt(3) / 3f;
oneDiv3 = 1f / 3f;
twoDiv3 = 2f / 3f;
sqrt3 = Mathf.Sqrt(3);
sqrt3Div2 = Mathf.Sqrt(3) / 2f;
}

// Precomputed array of neighbor offsets as Cell2D structs (center + 6 neighbors)
static readonly Cell2D[] neighborCellsBase = new Cell2D[]
{
new Cell2D(0, 0), // Center
new Cell2D(1, -1), // Top-right
new Cell2D(1, 0), // Right
new Cell2D(0, 1), // Bottom-right
new Cell2D(-1, 1), // Bottom-left
new Cell2D(-1, 0), // Left
new Cell2D(0, -1) // Top-left
};

// Converts a grid cell (q, r) to a world position (x, z)
internal Vector2 CellToWorld(Cell2D cell)
{
// Calculate X and Z using hexagonal coordinate formulas
float x = cellRadius * (sqrt3 * cell.q + sqrt3Div2 * cell.r);
float z = cellRadius * (1.5f * cell.r);

// Subtract the origin offset to align with world space and return the position
return new Vector2(x, z) - originOffset;
}

// Converts a world position (x, z) to a grid cell (q, r)
internal Cell2D WorldToCell(Vector2 position)
{
// Apply the origin offset to adjust the position before conversion
position += originOffset;

// Convert world X, Z to axial q, r coordinates using inverse hexagonal formulas
float q = (sqrt3Div3 * position.x - oneDiv3 * position.y) / cellRadius;
float r = (twoDiv3 * position.y) / cellRadius;

// Round to the nearest valid cell and return
return RoundToCell(q, r);
}

// Rounds floating-point axial coordinates (q, r) to the nearest integer cell coordinates
Cell2D RoundToCell(float q, float r)
{
// Calculate the third hexagonal coordinate (s) for consistency
float s = -q - r;
int qInt = Mathf.RoundToInt(q); // Round q to nearest integer
int rInt = Mathf.RoundToInt(r); // Round r to nearest integer
int sInt = Mathf.RoundToInt(s); // Round s to nearest integer

// Calculate differences to determine which coordinate needs adjustment
float qDiff = Mathf.Abs(q - qInt);
float rDiff = Mathf.Abs(r - rInt);
float sDiff = Mathf.Abs(s - sInt);

// Adjust q or r based on which has the largest rounding error (ensures q + r + s = 0)
if (qDiff > rDiff && qDiff > sDiff)
qInt = -rInt - sInt; // Adjust q if it has the largest error
else if (rDiff > sDiff)
rInt = -qInt - sInt; // Adjust r if it has the largest error

return new Cell2D(qInt, rInt);
}

// Populates the provided array with neighboring cells around a given center cell
internal void GetNeighborCells(Cell2D center, Cell2D[] neighbors)
{
// Ensure the array has the correct size (7: center + 6 neighbors)
if (neighbors.Length != 7)
throw new System.ArgumentException("Neighbor array must have exactly 7 elements");

// Populate the array by adjusting precomputed offsets with the center cell's coordinates
for (int i = 0; i < neighborCellsBase.Length; i++)
{
neighbors[i] = new Cell2D(
center.q + neighborCellsBase[i].q,
center.r + neighborCellsBase[i].r
);
}
}

#if UNITY_EDITOR
// Draws a 2D hexagonal gizmo in the Unity Editor for visualization
internal void DrawHexGizmo(Vector3 center, float radius, HexSpatialHash2DInterestManagement.CheckMethod checkMethod)
{
// Hexagon has 6 sides
const int segments = 6;

// Array to store the 6 corner points in 3D
Vector3[] corners = new Vector3[segments];

// Calculate the corner positions based on the plane (XZ or XY)
for (int i = 0; i < segments; i++)
{
// Angle for each corner, offset by 90 degrees
float angle = 2 * Mathf.PI / segments * i + Mathf.PI / 2;

if (checkMethod == HexSpatialHash2DInterestManagement.CheckMethod.XZ_FOR_3D)
{
// XZ plane: flat hexagon, Y=0
corners[i] = center + new Vector3(radius * Mathf.Cos(angle), 0, radius * Mathf.Sin(angle));
}
else // XY_FOR_2D
{
// XY plane: vertical hexagon, Z=0
corners[i] = center + new Vector3(radius * Mathf.Cos(angle), radius * Mathf.Sin(angle), 0);
}
}

// Draw each side of the hexagon
for (int i = 0; i < segments; i++)
{
Vector3 cornerA = corners[i];
Vector3 cornerB = corners[(i + 1) % segments];
Gizmos.DrawLine(cornerA, cornerB);
}
}
#endif
}

// Struct representing a single cell in the 2D hexagonal grid
internal struct Cell2D
{
internal readonly int q; // Axial q coordinate (horizontal axis)
internal readonly int r; // Axial r coordinate (diagonal axis)

internal Cell2D(int q, int r)
{
this.q = q;
this.r = r;
}

public override bool Equals(object obj) =>
obj is Cell2D other && q == other.q && r == other.r;

// Generate a unique hash code for the cell
public override int GetHashCode() => (q << 16) ^ r;
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading