Compare commits
2 commits
8581cf6fb8
...
bd0aeeb159
| Author | SHA256 | Date | |
|---|---|---|---|
| bd0aeeb159 | |||
| 0ef5652cea |
16 changed files with 508 additions and 651 deletions
6
global.json
Normal file
6
global.json
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"sdk": {
|
||||||
|
"version": "8.0.123",
|
||||||
|
"rollForward": "disable"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,6 +11,7 @@ public partial class GameManager : Node3D
|
||||||
[Export] public QueueManager QueueManager { get; private set; }
|
[Export] public QueueManager QueueManager { get; private set; }
|
||||||
[Export] public Node3D SpaceRoot { get; private set; }
|
[Export] public Node3D SpaceRoot { get; private set; }
|
||||||
|
|
||||||
|
[Export] public double closeDistance = 50;
|
||||||
[Export] public double closeTickInterval = 1;
|
[Export] public double closeTickInterval = 1;
|
||||||
[Export] public double farTickInterval = 10;
|
[Export] public double farTickInterval = 10;
|
||||||
[Export] public int maxFarThreads = 16;
|
[Export] public int maxFarThreads = 16;
|
||||||
|
|
@ -21,6 +22,7 @@ public partial class GameManager : Node3D
|
||||||
public static Universe GameUniverse { get; private set; }
|
public static Universe GameUniverse { get; private set; }
|
||||||
public Player MainPlayer { get; private set; }
|
public Player MainPlayer { get; private set; }
|
||||||
public Dictionary<long, Player> Players { get; private set; } = [];
|
public Dictionary<long, Player> Players { get; private set; } = [];
|
||||||
|
public Dictionary<long, HashSet<GameObject>> PlayerSpawnedObjects { get; private set; } = [];
|
||||||
|
|
||||||
private double closeTickTimer = 0;
|
private double closeTickTimer = 0;
|
||||||
private double farTickTimer = 0;
|
private double farTickTimer = 0;
|
||||||
|
|
@ -29,7 +31,7 @@ public partial class GameManager : Node3D
|
||||||
public bool simulatingFar = false;
|
public bool simulatingFar = false;
|
||||||
public bool playerReady = false;
|
public bool playerReady = false;
|
||||||
|
|
||||||
private readonly Dictionary<GameObject, Node3D> spawnedObjects = [];
|
private readonly Dictionary<GameObject, Node3D> localSpawnedObjects = [];
|
||||||
private readonly ConcurrentQueue<GameObject> spawnQueue = [];
|
private readonly ConcurrentQueue<GameObject> spawnQueue = [];
|
||||||
|
|
||||||
public override void _EnterTree()
|
public override void _EnterTree()
|
||||||
|
|
@ -51,7 +53,6 @@ public partial class GameManager : Node3D
|
||||||
private void OnPlayerReady()
|
private void OnPlayerReady()
|
||||||
{
|
{
|
||||||
playerReady = true;
|
playerReady = true;
|
||||||
SpawnClose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _ExitTree()
|
public override void _ExitTree()
|
||||||
|
|
@ -71,11 +72,12 @@ public partial class GameManager : Node3D
|
||||||
if (closeTickTimer >= closeTickInterval && !simulatingClose)
|
if (closeTickTimer >= closeTickInterval && !simulatingClose)
|
||||||
{
|
{
|
||||||
SimulateClose(closeTickTimer);
|
SimulateClose(closeTickTimer);
|
||||||
|
SyncClose();
|
||||||
closeTickTimer = 0;
|
closeTickTimer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
farTickTimer += delta;
|
farTickTimer += delta;
|
||||||
if (farTickTimer >= farTickInterval && !simulatingFar)
|
if (farTickTimer >= farTickInterval && !simulatingFar && QueueManager.SectorReassignQueue.IsEmpty)
|
||||||
{
|
{
|
||||||
double taskFarTickTimer = farTickTimer;
|
double taskFarTickTimer = farTickTimer;
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
|
|
@ -102,106 +104,122 @@ public partial class GameManager : Node3D
|
||||||
{
|
{
|
||||||
simulatingClose = true;
|
simulatingClose = true;
|
||||||
|
|
||||||
List<Sector> sectorsClose = GetCurrentSector().GetNeighbouringSectors();
|
HashSet<GameObject> objectsToSimulate = [];
|
||||||
|
|
||||||
List<Task> tasks = [];
|
|
||||||
sectorsClose.ForEach(sector =>
|
|
||||||
{
|
|
||||||
Task simulateTask = Task.Run(() =>
|
|
||||||
{
|
|
||||||
sector.Simulate(delta);
|
|
||||||
});
|
|
||||||
|
|
||||||
tasks.Add(simulateTask);
|
|
||||||
});
|
|
||||||
Task.WaitAll([.. tasks]);
|
|
||||||
|
|
||||||
foreach (KeyValuePair<long, Player> player in Players)
|
foreach (KeyValuePair<long, Player> player in Players)
|
||||||
{
|
{
|
||||||
List<Sector> playerSectors = player.Value.PlayerData.CurrentSector.GetNeighbouringSectors();
|
Character character = player.Value.PlayerData;
|
||||||
|
|
||||||
|
List<Sector> playerSectors = character.CurrentSector.GetNeighbouringSectors();
|
||||||
playerSectors.ForEach(sector =>
|
playerSectors.ForEach(sector =>
|
||||||
{
|
{
|
||||||
if (player.Key != 1)
|
sector.GameObjects.ForEach(gameObject =>
|
||||||
{
|
{
|
||||||
sector.NetworkSync(player.Key);
|
double distance = character.GetDistanceToObject(gameObject);
|
||||||
|
if (distance <= closeDistance)
|
||||||
|
{
|
||||||
|
objectsToSimulate.Add(gameObject);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (GameObject gameObject in objectsToSimulate)
|
||||||
|
{
|
||||||
|
gameObject.Simulate(delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
simulatingClose = false;
|
simulatingClose = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SyncClose()
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<long, Player> player in Players)
|
||||||
|
{
|
||||||
|
bool isHostPlayer = player.Key == 1;
|
||||||
|
long playerKey = player.Key;
|
||||||
|
Character character = player.Value.PlayerData;
|
||||||
|
|
||||||
|
PlayerSpawnedObjects.TryGetValue(playerKey, out HashSet<GameObject> playerSpawnedObjects);
|
||||||
|
playerSpawnedObjects ??= [];
|
||||||
|
HashSet<GameObject> playerNewSpawnedObjects = [];
|
||||||
|
|
||||||
|
List<Sector> playerSectors = character.CurrentSector.GetNeighbouringSectors();
|
||||||
|
|
||||||
|
// Spawn/Send object
|
||||||
|
playerSectors.ForEach(sector =>
|
||||||
|
{
|
||||||
|
sector.GameObjects.ForEach(gameObject =>
|
||||||
|
{
|
||||||
|
double distance = character.GetDistanceToObject(gameObject);
|
||||||
|
if (distance <= closeDistance)
|
||||||
|
{
|
||||||
|
if (isHostPlayer)
|
||||||
|
Spawn(gameObject);
|
||||||
|
else
|
||||||
|
gameObject.NetworkWrite(playerKey, !playerSpawnedObjects.Contains(gameObject));
|
||||||
|
|
||||||
|
playerNewSpawnedObjects.Add(gameObject);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Despawn object
|
||||||
|
foreach (GameObject gameObject in playerSpawnedObjects)
|
||||||
|
{
|
||||||
|
if (!playerNewSpawnedObjects.Contains(gameObject))
|
||||||
|
{
|
||||||
|
if (isHostPlayer)
|
||||||
|
Despawn(gameObject);
|
||||||
|
else
|
||||||
|
RPCNode.Instance.RpcId(playerKey, nameof(RPCNode.RpcDespawnGameObject), gameObject.UUID.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerSpawnedObjects[playerKey] = playerNewSpawnedObjects;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void SimulateFar(double delta)
|
private void SimulateFar(double delta)
|
||||||
{
|
{
|
||||||
simulatingFar = true;
|
simulatingFar = true;
|
||||||
|
|
||||||
List<Task> tasks = [];
|
|
||||||
|
|
||||||
Sector[,,] sectors = GameUniverse.Sectors;
|
Sector[,,] sectors = GameUniverse.Sectors;
|
||||||
|
|
||||||
int sizeX = sectors.GetLength(0);
|
HashSet<GameObject> allSpawnedObjects = [];
|
||||||
int countX = Mathf.Clamp(sizeX / maxFarThreads, 1, int.MaxValue);
|
foreach (HashSet<GameObject> item in PlayerSpawnedObjects.Values)
|
||||||
|
|
||||||
for (int x = 0; x < sizeX; x += countX)
|
|
||||||
{
|
{
|
||||||
double taskDelta = delta;
|
foreach (GameObject gameObject in item)
|
||||||
int taskStartX = x;
|
|
||||||
int taskCountX = countX;
|
|
||||||
|
|
||||||
Task clusteredTask = Task.Run(() =>
|
|
||||||
{
|
{
|
||||||
SimulateFarClustered(taskDelta, taskStartX, taskCountX);
|
allSpawnedObjects.Add(gameObject);
|
||||||
});
|
}
|
||||||
|
|
||||||
tasks.Add(clusteredTask);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Task.WaitAll([.. tasks]);
|
int sizeX = sectors.GetLength(0);
|
||||||
|
|
||||||
|
double taskDelta = delta;
|
||||||
|
Parallel.For(0, sizeX, x =>
|
||||||
|
{
|
||||||
|
SimulateFarClustered(allSpawnedObjects, taskDelta, x);
|
||||||
|
});
|
||||||
|
|
||||||
simulatingFar = false;
|
simulatingFar = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SimulateFarClustered(double delta, int startX, int countX)
|
private static void SimulateFarClustered(HashSet<GameObject> ignoreObjects, double delta, int x)
|
||||||
{
|
{
|
||||||
Vector3I currentCoordinates = GetCurrentSector().Coordinates;
|
|
||||||
|
|
||||||
Sector[,,] sectors = GameUniverse.Sectors;
|
Sector[,,] sectors = GameUniverse.Sectors;
|
||||||
|
|
||||||
int sizeX = sectors.GetLength(0);
|
|
||||||
int sizeY = sectors.GetLength(1);
|
int sizeY = sectors.GetLength(1);
|
||||||
int sizeZ = sectors.GetLength(2);
|
int sizeZ = sectors.GetLength(2);
|
||||||
|
|
||||||
int startSkipX = Mathf.Clamp(currentCoordinates.X - 1, 0, sizeX);
|
|
||||||
int startSkipY = Mathf.Clamp(currentCoordinates.Y - 1, 0, sizeY);
|
|
||||||
int startSkipZ = Mathf.Clamp(currentCoordinates.Z - 1, 0, sizeZ);
|
|
||||||
|
|
||||||
int endSkipX = Mathf.Clamp(currentCoordinates.X + 1, 0, sizeX);
|
|
||||||
int endSkipY = Mathf.Clamp(currentCoordinates.Y + 1, 0, sizeY);
|
|
||||||
int endSkipZ = Mathf.Clamp(currentCoordinates.Z + 1, 0, sizeZ);
|
|
||||||
|
|
||||||
int endX = Mathf.Clamp(startX + countX, 0, sizeX);
|
|
||||||
|
|
||||||
for (int x = startX; x < endX; x++)
|
|
||||||
{
|
|
||||||
for (int y = 0; y < sizeY; y++)
|
for (int y = 0; y < sizeY; y++)
|
||||||
{
|
{
|
||||||
Thread.Sleep(5);
|
|
||||||
for (int z = 0; z < sizeZ; z++)
|
for (int z = 0; z < sizeZ; z++)
|
||||||
{
|
{
|
||||||
if (Helpers.IsBetweenInclusive(x, startSkipX, endSkipX))
|
|
||||||
{
|
|
||||||
if (Helpers.IsBetweenInclusive(y, startSkipY, endSkipY))
|
|
||||||
{
|
|
||||||
if (Helpers.IsBetweenInclusive(z, startSkipZ, endSkipZ))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
sectors[x, y, z].Simulate(delta);
|
sectors[x, y, z].Simulate(delta, ignoreObjects);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
@ -210,14 +228,6 @@ public partial class GameManager : Node3D
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void SpawnClose()
|
|
||||||
{
|
|
||||||
List<Sector> neighbours = GetCurrentSector().GetNeighbouringSectors();
|
|
||||||
|
|
||||||
neighbours.ForEach(sector => sector.SpawnObjects());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Player SpawnPlayer(Character character, long networkId, bool isMainPlayer = false)
|
public Player SpawnPlayer(Character character, long networkId, bool isMainPlayer = false)
|
||||||
{
|
{
|
||||||
|
|
@ -238,8 +248,10 @@ public partial class GameManager : Node3D
|
||||||
return player;
|
return player;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DespawnPlayer(Player player)
|
public void DespawnPlayer(Player player, long id)
|
||||||
{
|
{
|
||||||
|
Players.Remove(id);
|
||||||
|
|
||||||
SpaceRoot.CallDeferred("remove_child", player);
|
SpaceRoot.CallDeferred("remove_child", player);
|
||||||
player.CallDeferred("queue_free");
|
player.CallDeferred("queue_free");
|
||||||
}
|
}
|
||||||
|
|
@ -257,31 +269,43 @@ public partial class GameManager : Node3D
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (spawnedObjects.ContainsKey(gameObject))
|
if (localSpawnedObjects.ContainsKey(gameObject))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node3D instance = gameObject.Instantiate(GetCurrentSector());
|
Node3D instance = gameObject.Instantiate(GetCurrentSector());
|
||||||
spawnedObjects.Add(gameObject, instance);
|
localSpawnedObjects.Add(gameObject, instance);
|
||||||
|
|
||||||
SpaceRoot.CallDeferred("add_child", instance);
|
SpaceRoot.CallDeferred("add_child", instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Despawn(GameObject gameObject)
|
public void Despawn(GameObject gameObject)
|
||||||
{
|
{
|
||||||
if (!spawnedObjects.ContainsKey(gameObject))
|
if (!localSpawnedObjects.ContainsKey(gameObject))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node3D nodeToDespawn = spawnedObjects.GetValueOrDefault(gameObject);
|
Node3D nodeToDespawn = localSpawnedObjects.GetValueOrDefault(gameObject);
|
||||||
spawnedObjects.Remove(gameObject);
|
localSpawnedObjects.Remove(gameObject);
|
||||||
|
|
||||||
SpaceRoot.CallDeferred("remove_child", nodeToDespawn);
|
SpaceRoot.CallDeferred("remove_child", nodeToDespawn);
|
||||||
nodeToDespawn.CallDeferred("queue_free");
|
nodeToDespawn.CallDeferred("queue_free");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Despawn(Guid uuid)
|
||||||
|
{
|
||||||
|
foreach (GameObject gameObject in localSpawnedObjects.Keys)
|
||||||
|
{
|
||||||
|
if (gameObject.UUID == uuid)
|
||||||
|
{
|
||||||
|
Despawn(gameObject);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void ApplyOrigin()
|
public void ApplyOrigin()
|
||||||
{
|
{
|
||||||
Sector current = GetCurrentSector();
|
Sector current = GetCurrentSector();
|
||||||
|
|
@ -292,26 +316,16 @@ public partial class GameManager : Node3D
|
||||||
player.Value.PlayerData.UpdateNodePosition();
|
player.Value.PlayerData.UpdateNodePosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Sector> nearby = current.GetNeighbouringSectors();
|
foreach (KeyValuePair<GameObject, Node3D> spawned in localSpawnedObjects)
|
||||||
foreach (KeyValuePair<GameObject, Node3D> spawned in spawnedObjects)
|
|
||||||
{
|
{
|
||||||
GameObject gameObject = spawned.Key;
|
GameObject gameObject = spawned.Key;
|
||||||
Node3D node = spawned.Value;
|
Node3D node = spawned.Value;
|
||||||
|
|
||||||
if (!nearby.Contains(gameObject.CurrentSector))
|
|
||||||
{
|
|
||||||
Despawn(gameObject);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gameObject.UpdateSectorOffset(current);
|
gameObject.UpdateSectorOffset(current);
|
||||||
node._Process(0);
|
node._Process(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nearby.ForEach(sector => sector.SpawnObjects());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SendUniverseToClient(long id)
|
public void SendUniverseToClient(long id)
|
||||||
{
|
{
|
||||||
RpcId(id, nameof(RpcDownloadUniverse), Generator.GetUniverseSize(), Generator.GetSectorSize());
|
RpcId(id, nameof(RpcDownloadUniverse), Generator.GetUniverseSize(), Generator.GetSectorSize());
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
public abstract class GameObject
|
public abstract class GameObject
|
||||||
|
|
@ -103,7 +102,6 @@ public abstract class GameObject
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3Dec GlobalCoordinates { get; protected set; }
|
|
||||||
public Vector3 SectorOffset { get; protected set; }
|
public Vector3 SectorOffset { get; protected set; }
|
||||||
|
|
||||||
protected bool reassigning = false;
|
protected bool reassigning = false;
|
||||||
|
|
@ -118,97 +116,65 @@ public abstract class GameObject
|
||||||
Velocity = new(0, 0, 1);
|
Velocity = new(0, 0, 1);
|
||||||
AngularVelocity = Vector3.Zero;
|
AngularVelocity = Vector3.Zero;
|
||||||
Rotation = Vector3.Zero;
|
Rotation = Vector3.Zero;
|
||||||
|
|
||||||
GlobalCoordinates = CalculateGlobalCoordinates(sector.GlobalCenterCoordinates, localCoordinates);
|
|
||||||
}
|
|
||||||
|
|
||||||
public GameObject(Vector3Dec coordinates)
|
|
||||||
{
|
|
||||||
GlobalCoordinates = coordinates;
|
|
||||||
UpdateSector();
|
|
||||||
}
|
|
||||||
|
|
||||||
public GameObject(decimal x, decimal y, decimal z)
|
|
||||||
{
|
|
||||||
GlobalCoordinates = new(x, y, z);
|
|
||||||
UpdateSector();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector3Dec CalculateGlobalCoordinates(Vector3Dec sectorCenter, Vector3 local)
|
|
||||||
{
|
|
||||||
return new
|
|
||||||
(
|
|
||||||
sectorCenter.X + (decimal)local.X,
|
|
||||||
sectorCenter.Y + (decimal)local.Y,
|
|
||||||
sectorCenter.Z + (decimal)local.Z
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ApplyVelocity(double delta)
|
public void ApplyVelocity(double delta)
|
||||||
{
|
{
|
||||||
SetCoordinatesFromLocal(LocalCoordinates + Velocity * delta);
|
SetCoordinates(LocalCoordinates + Velocity * delta);
|
||||||
Rotation += AngularVelocity * delta;
|
Rotation += AngularVelocity * delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsInCurrentSector()
|
public bool IsInCurrentSector()
|
||||||
{
|
{
|
||||||
return Helpers.IsInsideArea(CurrentSector.Size / 2, LocalCoordinates);
|
return Helpers.IsInsideArea(GameManager.Generator.GetSectorSize() / 2, LocalCoordinates);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateSector()
|
public void UpdateSector()
|
||||||
{
|
{
|
||||||
List<Sector> neighbours = CurrentSector.GetNeighbouringSectors();
|
|
||||||
foreach (Sector sector in neighbours)
|
|
||||||
{
|
|
||||||
if (sector.IsObjectInSector(this))
|
|
||||||
{
|
|
||||||
reassigning = true;
|
|
||||||
sector.AssignObject(this);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!GameManager.GameUniverse.IsInside(CurrentSector.Coordinates, LocalCoordinates))
|
if (!GameManager.GameUniverse.IsInside(CurrentSector.Coordinates, LocalCoordinates))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Sector sector in GameManager.GameUniverse.Sectors)
|
Vector3 sectorSize = GameManager.Generator.GetSectorSize() / 2;
|
||||||
{
|
|
||||||
if (sector.IsObjectInSector(this))
|
bool? x = null;
|
||||||
|
bool? y = null;
|
||||||
|
bool? z = null;
|
||||||
|
|
||||||
|
if (LocalCoordinates.X > sectorSize.X) x = true;
|
||||||
|
else if (LocalCoordinates.X < -sectorSize.X) x = false;
|
||||||
|
|
||||||
|
if (LocalCoordinates.Y > sectorSize.Y) y = true;
|
||||||
|
else if (LocalCoordinates.Y < -sectorSize.Y) y = false;
|
||||||
|
|
||||||
|
if (LocalCoordinates.Z > sectorSize.Z) z = true;
|
||||||
|
else if (LocalCoordinates.Z < -sectorSize.Z) z = false;
|
||||||
|
|
||||||
|
Sector sector = GameManager.GameUniverse.GetNeighbouringSector(CurrentSector, x, y, z);
|
||||||
|
if (sector != null)
|
||||||
{
|
{
|
||||||
reassigning = true;
|
reassigning = true;
|
||||||
sector.AssignObject(this);
|
sector.AssignObject(this);
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void AssignSector(Sector sector)
|
public virtual void AssignSector(Sector sector)
|
||||||
{
|
{
|
||||||
|
Vector3 sectorOffset = GetSectorOffset(sector);
|
||||||
|
|
||||||
CurrentSector = sector;
|
CurrentSector = sector;
|
||||||
ResetLocalCoordinates();
|
LocalCoordinates += sectorOffset;
|
||||||
|
|
||||||
UpdateSectorOffsetToMainPlayer();
|
UpdateSectorOffsetToMainPlayer();
|
||||||
|
|
||||||
List<Sector> neighbours = GameManager.Instance.GetCurrentSector().GetNeighbouringSectors();
|
|
||||||
|
|
||||||
if (neighbours.Contains(sector))
|
|
||||||
{
|
|
||||||
GameManager.Instance.Spawn(this);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GameManager.Instance.Despawn(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
reassigning = false;
|
reassigning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3 GetSectorOffset(Sector sector)
|
public Vector3 GetSectorOffset(Sector sector)
|
||||||
{
|
{
|
||||||
Vector3Dec relative = CurrentSector.GlobalCenterCoordinates - sector.GlobalCenterCoordinates;
|
Vector3I relative = CurrentSector.Coordinates - sector.Coordinates;
|
||||||
return relative.ToVector3();
|
return relative * GameManager.Generator.GetSectorSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateSectorOffset(Sector sector)
|
public void UpdateSectorOffset(Sector sector)
|
||||||
|
|
@ -221,25 +187,22 @@ public abstract class GameObject
|
||||||
UpdateSectorOffset(GameManager.Instance.GetCurrentSector());
|
UpdateSectorOffset(GameManager.Instance.GetCurrentSector());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetCoordinatesFromGlobal(Vector3Dec globalCoordinates)
|
public void SetCoordinates(Vector3 localCoordinates)
|
||||||
{
|
|
||||||
GlobalCoordinates = globalCoordinates;
|
|
||||||
LocalCoordinates = (globalCoordinates - CurrentSector.GlobalCenterCoordinates).ToVector3();
|
|
||||||
|
|
||||||
UpdateNodePosition();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetCoordinatesFromLocal(Vector3 localCoordinates)
|
|
||||||
{
|
{
|
||||||
LocalCoordinates = localCoordinates;
|
LocalCoordinates = localCoordinates;
|
||||||
GlobalCoordinates = Vector3Dec.FromVector3(localCoordinates) + CurrentSector.GlobalCenterCoordinates;
|
|
||||||
|
|
||||||
UpdateNodePosition();
|
UpdateNodePosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResetLocalCoordinates()
|
public double GetDistanceToObject(GameObject gameObject)
|
||||||
{
|
{
|
||||||
SetCoordinatesFromGlobal(GlobalCoordinates);
|
Sector sector = gameObject.CurrentSector;
|
||||||
|
Vector3 sectorOffset = GetSectorOffset(sector);
|
||||||
|
|
||||||
|
Vector3 position1 = LocalCoordinates;
|
||||||
|
Vector3 position2 = gameObject.LocalCoordinates - sectorOffset;
|
||||||
|
|
||||||
|
return Helpers.GetDistance(position1, position2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void UpdateNodePosition() { }
|
public virtual void UpdateNodePosition() { }
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,14 @@ public class Character(Sector sector, Vector3 localCoordinates) : GameObject(sec
|
||||||
|
|
||||||
public override void AssignSector(Sector sector)
|
public override void AssignSector(Sector sector)
|
||||||
{
|
{
|
||||||
CurrentSector = sector;
|
Vector3 sectorOffset = GetSectorOffset(sector);
|
||||||
|
|
||||||
|
CurrentSector = sector;
|
||||||
|
if (IsMainPlayer())
|
||||||
|
{
|
||||||
|
LocalCoordinates += sectorOffset;
|
||||||
|
}
|
||||||
|
|
||||||
ResetLocalCoordinates();
|
|
||||||
UpdateSectorOffsetToMainPlayer();
|
UpdateSectorOffsetToMainPlayer();
|
||||||
UpdateNodePosition();
|
UpdateNodePosition();
|
||||||
|
|
||||||
|
|
@ -47,14 +52,7 @@ public class Character(Sector sector, Vector3 localCoordinates) : GameObject(sec
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdateNodePosition()
|
public override void UpdateNodePosition()
|
||||||
{
|
|
||||||
if (IsMainPlayer())
|
|
||||||
{
|
|
||||||
player.GlobalPosition = LocalCoordinates;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
player.GlobalPosition = LocalCoordinates + SectorOffset;
|
player.GlobalPosition = LocalCoordinates + SectorOffset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ public class Star(Sector sector, Vector3 localCoordinates) : GameObject(sector,
|
||||||
|
|
||||||
if (gameObjectData != null)
|
if (gameObjectData != null)
|
||||||
{
|
{
|
||||||
QueueManager.NetworkSyncQueue.Enqueue((id, gameObjectData));
|
QueueManager.NetworkSyncQueue.Enqueue((id, full, gameObjectData));
|
||||||
}
|
}
|
||||||
DirtyBits = DirtyFlags.None;
|
DirtyBits = DirtyFlags.None;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,12 @@ public interface IGenerator
|
||||||
|
|
||||||
public Universe InitializeEmptyUniverse(Vector3I universeSize, Vector3 sectorSize);
|
public Universe InitializeEmptyUniverse(Vector3I universeSize, Vector3 sectorSize);
|
||||||
public Universe GenerateUniverse();
|
public Universe GenerateUniverse();
|
||||||
public Sector GenerateSector(Vector3I coordinates);
|
public Sector GenerateSector(Vector3I coordinates, RandomNumberGenerator rng);
|
||||||
|
|
||||||
public Star GenerateStar(Sector sector, Vector3 localCoordinates);
|
public Star GenerateStar(Sector sector, Vector3 localCoordinates);
|
||||||
public Star GenerateStar(Sector sector);
|
public Star GenerateStar(Sector sector, RandomNumberGenerator rng);
|
||||||
public Vessel GenerateShip(Sector sector, Vector3 localCoordinates);
|
public Vessel GenerateShip(Sector sector, Vector3 localCoordinates);
|
||||||
public Vessel GenerateShip(Sector sector);
|
public Vessel GenerateShip(Sector sector, RandomNumberGenerator rng);
|
||||||
public Vessel GenerateStation(Sector sector, Vector3 localCoordinates);
|
public Vessel GenerateStation(Sector sector, Vector3 localCoordinates);
|
||||||
public Vessel GenerateStation(Sector sector);
|
public Vessel GenerateStation(Sector sector, RandomNumberGenerator rng);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,16 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
public class TestGenerator : IGenerator
|
public class TestGenerator : IGenerator
|
||||||
{
|
{
|
||||||
public static Vector3I UNIVERSE_SIZE = new(10, 10, 10);
|
public readonly static Vector3I UNIVERSE_SIZE = new(10, 10, 10);
|
||||||
public static Vector3 SECTOR_SIZE = new(50, 50, 50);
|
public readonly static Vector3 SECTOR_SIZE = new(50, 50, 50);
|
||||||
public static int STARS_PER_SECTOR = 1;
|
public readonly static int STARS_PER_SECTOR = 1;
|
||||||
public static int STARS_PER_SECTOR_VARIANCE = 0;
|
public readonly static int STARS_PER_SECTOR_VARIANCE = 0;
|
||||||
public static int SHIPS_PER_SECTOR = 0;
|
public readonly static int SHIPS_PER_SECTOR = 0;
|
||||||
public static int SHIPS_PER_SECTOR_VARIANCE = 0;
|
public readonly static int SHIPS_PER_SECTOR_VARIANCE = 0;
|
||||||
public static int STATIONS_PER_SECTOR = 0;
|
public readonly static int STATIONS_PER_SECTOR = 0;
|
||||||
public static int STATIONS_PER_SECTOR_VARIANCE = 0;
|
public readonly static int STATIONS_PER_SECTOR_VARIANCE = 0;
|
||||||
|
|
||||||
private readonly int threads = 16;
|
|
||||||
|
|
||||||
private RandomNumberGenerator rng;
|
|
||||||
|
|
||||||
public Vector3I GetUniverseSize()
|
public Vector3I GetUniverseSize()
|
||||||
{
|
{
|
||||||
|
|
@ -27,7 +22,7 @@ public class TestGenerator : IGenerator
|
||||||
return SECTOR_SIZE;
|
return SECTOR_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3I GetSectorOffset(Vector3I universeSize)
|
public static Vector3I GetSectorOffset(Vector3I universeSize)
|
||||||
{
|
{
|
||||||
return new(
|
return new(
|
||||||
(int)Mathf.Floor(universeSize.X / 2),
|
(int)Mathf.Floor(universeSize.X / 2),
|
||||||
|
|
@ -36,7 +31,7 @@ public class TestGenerator : IGenerator
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3I GetSectorOffset()
|
public static Vector3I GetSectorOffset()
|
||||||
{
|
{
|
||||||
return GetSectorOffset(UNIVERSE_SIZE);
|
return GetSectorOffset(UNIVERSE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
@ -52,9 +47,7 @@ public class TestGenerator : IGenerator
|
||||||
for (int z = 0; z < universeSize.Z; z++)
|
for (int z = 0; z < universeSize.Z; z++)
|
||||||
{
|
{
|
||||||
universe.Sectors[x, y, z] = new Sector(
|
universe.Sectors[x, y, z] = new Sector(
|
||||||
new(x, y, z),
|
new(x, y, z)
|
||||||
GetSectorOffset(universeSize),
|
|
||||||
sectorSize
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -65,50 +58,33 @@ public class TestGenerator : IGenerator
|
||||||
|
|
||||||
public Universe GenerateUniverse()
|
public Universe GenerateUniverse()
|
||||||
{
|
{
|
||||||
rng = new();
|
|
||||||
|
|
||||||
List<Task> tasks = [];
|
|
||||||
|
|
||||||
Universe universe = new(UNIVERSE_SIZE);
|
Universe universe = new(UNIVERSE_SIZE);
|
||||||
int countX = Mathf.Clamp(UNIVERSE_SIZE.X / threads, 1, int.MaxValue);
|
|
||||||
|
|
||||||
for (int x = 0; x < UNIVERSE_SIZE.X; x += countX)
|
Parallel.For(0, UNIVERSE_SIZE.X, x =>
|
||||||
{
|
{
|
||||||
int taskStartX = x;
|
GenerateClustered(universe, x);
|
||||||
int taskCountX = countX;
|
|
||||||
|
|
||||||
Task clusteredTask = Task.Run(() =>
|
|
||||||
{
|
|
||||||
GenerateClustered(universe, taskStartX, taskCountX);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
tasks.Add(clusteredTask);
|
|
||||||
}
|
|
||||||
|
|
||||||
Task.WaitAll([.. tasks]);
|
|
||||||
|
|
||||||
return universe;
|
return universe;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GenerateClustered(Universe universe, int startX, int countX)
|
private void GenerateClustered(Universe universe, int x)
|
||||||
{
|
{
|
||||||
int endX = Mathf.Clamp(startX + countX, 0, UNIVERSE_SIZE.X);
|
RandomNumberGenerator rng = new();
|
||||||
|
rng.Randomize();
|
||||||
|
|
||||||
for (int x = startX; x < endX; x++)
|
|
||||||
{
|
|
||||||
for (int y = 0; y < UNIVERSE_SIZE.Y; y++)
|
for (int y = 0; y < UNIVERSE_SIZE.Y; y++)
|
||||||
{
|
{
|
||||||
for (int z = 0; z < UNIVERSE_SIZE.Z; z++)
|
for (int z = 0; z < UNIVERSE_SIZE.Z; z++)
|
||||||
{
|
{
|
||||||
universe.Sectors[x, y, z] = GenerateSector(new(x, y, z));
|
universe.Sectors[x, y, z] = GenerateSector(new(x, y, z), rng);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Sector GenerateSector(Vector3I coordinates)
|
public Sector GenerateSector(Vector3I coordinates, RandomNumberGenerator rng)
|
||||||
{
|
{
|
||||||
Sector sector = new(coordinates, GetSectorOffset(), SECTOR_SIZE);
|
Sector sector = new(coordinates);
|
||||||
|
|
||||||
int starCount = rng.RandiRange(
|
int starCount = rng.RandiRange(
|
||||||
STARS_PER_SECTOR - STARS_PER_SECTOR_VARIANCE,
|
STARS_PER_SECTOR - STARS_PER_SECTOR_VARIANCE,
|
||||||
|
|
@ -120,7 +96,7 @@ public class TestGenerator : IGenerator
|
||||||
{
|
{
|
||||||
if (coordinates.X == 5 && coordinates.Y == 5 && coordinates.Z == 5)
|
if (coordinates.X == 5 && coordinates.Y == 5 && coordinates.Z == 5)
|
||||||
{
|
{
|
||||||
Vector3 localCoordinates = GenerateLocalCoordinates();
|
Vector3 localCoordinates = GenerateLocalCoordinates(rng);
|
||||||
Star star = GenerateStar(sector, localCoordinates);
|
Star star = GenerateStar(sector, localCoordinates);
|
||||||
|
|
||||||
sector.GameObjects.Add(star);
|
sector.GameObjects.Add(star);
|
||||||
|
|
@ -135,7 +111,7 @@ public class TestGenerator : IGenerator
|
||||||
|
|
||||||
for (int i = 0; i < shipCount; i++)
|
for (int i = 0; i < shipCount; i++)
|
||||||
{
|
{
|
||||||
Vector3 localCoordinates = GenerateLocalCoordinates();
|
Vector3 localCoordinates = GenerateLocalCoordinates(rng);
|
||||||
Vessel ship = GenerateShip(sector, localCoordinates);
|
Vessel ship = GenerateShip(sector, localCoordinates);
|
||||||
|
|
||||||
sector.GameObjects.Add(ship);
|
sector.GameObjects.Add(ship);
|
||||||
|
|
@ -149,7 +125,7 @@ public class TestGenerator : IGenerator
|
||||||
|
|
||||||
for (int i = 0; i < stationCount; i++)
|
for (int i = 0; i < stationCount; i++)
|
||||||
{
|
{
|
||||||
Vector3 localCoordinates = GenerateLocalCoordinates();
|
Vector3 localCoordinates = GenerateLocalCoordinates(rng);
|
||||||
Vessel station = GenerateStation(sector, localCoordinates);
|
Vessel station = GenerateStation(sector, localCoordinates);
|
||||||
|
|
||||||
sector.GameObjects.Add(station);
|
sector.GameObjects.Add(station);
|
||||||
|
|
@ -163,9 +139,9 @@ public class TestGenerator : IGenerator
|
||||||
return new Star(sector, localCoordinates);
|
return new Star(sector, localCoordinates);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Star GenerateStar(Sector sector)
|
public Star GenerateStar(Sector sector, RandomNumberGenerator rng)
|
||||||
{
|
{
|
||||||
return GenerateStar(sector, GenerateLocalCoordinates());
|
return GenerateStar(sector, GenerateLocalCoordinates(rng));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vessel GenerateShip(Sector sector, Vector3 localCoordinates)
|
public Vessel GenerateShip(Sector sector, Vector3 localCoordinates)
|
||||||
|
|
@ -173,9 +149,9 @@ public class TestGenerator : IGenerator
|
||||||
return new Vessel(sector, localCoordinates);
|
return new Vessel(sector, localCoordinates);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vessel GenerateShip(Sector sector)
|
public Vessel GenerateShip(Sector sector, RandomNumberGenerator rng)
|
||||||
{
|
{
|
||||||
return GenerateShip(sector, GenerateLocalCoordinates());
|
return GenerateShip(sector, GenerateLocalCoordinates(rng));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vessel GenerateStation(Sector sector, Vector3 localCoordinates)
|
public Vessel GenerateStation(Sector sector, Vector3 localCoordinates)
|
||||||
|
|
@ -183,12 +159,12 @@ public class TestGenerator : IGenerator
|
||||||
return new Vessel(sector, localCoordinates);
|
return new Vessel(sector, localCoordinates);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vessel GenerateStation(Sector sector)
|
public Vessel GenerateStation(Sector sector, RandomNumberGenerator rng)
|
||||||
{
|
{
|
||||||
return GenerateStation(sector, GenerateLocalCoordinates());
|
return GenerateStation(sector, GenerateLocalCoordinates(rng));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3 GenerateLocalCoordinates()
|
public static Vector3 GenerateLocalCoordinates(RandomNumberGenerator rng)
|
||||||
{
|
{
|
||||||
double x = (rng.Randf() - 0.5) * SECTOR_SIZE.X;
|
double x = (rng.Randf() - 0.5) * SECTOR_SIZE.X;
|
||||||
double y = (rng.Randf() - 0.5) * SECTOR_SIZE.Y;
|
double y = (rng.Randf() - 0.5) * SECTOR_SIZE.Y;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
public static class Helpers
|
public static class Helpers
|
||||||
|
|
@ -27,18 +28,12 @@ public static class Helpers
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsInsideGlobalArea(Vector3Dec areaStart, Vector3Dec areaEnd, Vector3Dec coordinates)
|
public static double GetDistance(Vector3 position1, Vector3 position2)
|
||||||
{
|
{
|
||||||
if (coordinates.X >= areaEnd.X || coordinates.Y >= areaEnd.Y || coordinates.Z >= areaEnd.Z)
|
double diffX = Math.Abs(position1.X - position2.X);
|
||||||
{
|
double diffY = Math.Abs(position1.Y - position2.Y);
|
||||||
return false;
|
double diffZ = Math.Abs(position1.Z - position2.Z);
|
||||||
}
|
|
||||||
|
|
||||||
if (coordinates.X < areaStart.X || coordinates.Y < areaStart.Y || coordinates.Z < areaStart.Z)
|
return Math.Sqrt(diffX * diffX + diffY * diffY + diffZ * diffZ);
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ public partial class NetworkManager : Node
|
||||||
public void OnPlayerDisconnected(long id)
|
public void OnPlayerDisconnected(long id)
|
||||||
{
|
{
|
||||||
Player player = GetNode<Player>($"/root/Game/Space/Player-{id}");
|
Player player = GetNode<Player>($"/root/Game/Space/Player-{id}");
|
||||||
GameManager.Instance.DespawnPlayer(player);
|
GameManager.Instance.DespawnPlayer(player, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SpawnNetPlayer(long id)
|
private async Task SpawnNetPlayer(long id)
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ public partial class Player : CharacterBody3D
|
||||||
rpc.Rpc(nameof(rpc.RpcSyncPlayer), GetMultiplayerAuthority(), GlobalPosition, PlayerData.CurrentSector.Coordinates);
|
rpc.Rpc(nameof(rpc.RpcSyncPlayer), GetMultiplayerAuthority(), GlobalPosition, PlayerData.CurrentSector.Coordinates);
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerData.SetCoordinatesFromLocal(GlobalPosition);
|
PlayerData.SetCoordinates(GlobalPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerData.Simulate(delta);
|
PlayerData.Simulate(delta);
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,13 @@ using Godot;
|
||||||
|
|
||||||
public partial class QueueManager : Node
|
public partial class QueueManager : Node
|
||||||
{
|
{
|
||||||
public static ConcurrentQueue<string> LogQueue = new();
|
public static readonly ConcurrentQueue<string> LogQueue = new();
|
||||||
public static ConcurrentQueue<Action> ActionQueue = new();
|
public static readonly ConcurrentQueue<Action> ActionQueue = new();
|
||||||
|
|
||||||
public static ConcurrentQueue<(Sector, GameObject)> SectorReassignQueue = new();
|
public static readonly ConcurrentQueue<(Sector, GameObject)> SectorReassignQueue = new();
|
||||||
public static ConcurrentQueue<(long, Godot.Collections.Dictionary)> NetworkSyncQueue = new();
|
public static readonly ConcurrentQueue<(long, bool, Godot.Collections.Dictionary)> NetworkSyncQueue = new();
|
||||||
|
|
||||||
private readonly int sectorReassignQueueRateLimit = 500;
|
private readonly int sectorReassignQueueRateLimit = 5000;
|
||||||
private readonly int networkSyncQueueRateLimit = 10;
|
private readonly int networkSyncQueueRateLimit = 10;
|
||||||
|
|
||||||
public override void _Process(double delta)
|
public override void _Process(double delta)
|
||||||
|
|
@ -51,8 +51,11 @@ public partial class QueueManager : Node
|
||||||
&& NetworkSyncQueue.TryDequeue(out var item)
|
&& NetworkSyncQueue.TryDequeue(out var item)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
var (clientId, gameObjectData) = item;
|
var (clientId, full, gameObjectData) = item;
|
||||||
|
|
||||||
|
if (full)
|
||||||
|
RPCNode.Instance.RpcId(clientId, nameof(RPCNode.RpcSpawnGameObject), gameObjectData);
|
||||||
|
else
|
||||||
RPCNode.Instance.RpcId(clientId, nameof(RPCNode.RpcSyncGameObject), gameObjectData);
|
RPCNode.Instance.RpcId(clientId, nameof(RPCNode.RpcSyncGameObject), gameObjectData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,6 @@ public partial class RPCNode : Node
|
||||||
{
|
{
|
||||||
public static RPCNode Instance { get; private set; }
|
public static RPCNode Instance { get; private set; }
|
||||||
|
|
||||||
private readonly HashSet<Guid> requestedFullGameObjects = [];
|
|
||||||
|
|
||||||
public override void _EnterTree()
|
public override void _EnterTree()
|
||||||
{
|
{
|
||||||
Instance = this;
|
Instance = this;
|
||||||
|
|
@ -18,6 +16,31 @@ public partial class RPCNode : Node
|
||||||
Instance = null;
|
Instance = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Rpc(MultiplayerApi.RpcMode.Authority)]
|
||||||
|
public void RpcDespawnGameObject(string uuidData)
|
||||||
|
{
|
||||||
|
GD.Print("DESPAWNING: " + uuidData);
|
||||||
|
|
||||||
|
if (!GameManager.Instance.playerReady)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Guid uuid = Guid.Parse(uuidData);
|
||||||
|
|
||||||
|
List<Sector> sectors = GameManager.Instance.GetCurrentSector().GetNeighbouringSectors();
|
||||||
|
foreach (Sector sector in sectors)
|
||||||
|
{
|
||||||
|
bool removed = sector.RemoveObjectById(uuid);
|
||||||
|
if (removed)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GameManager.Instance.Despawn(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
[Rpc(MultiplayerApi.RpcMode.Authority)]
|
[Rpc(MultiplayerApi.RpcMode.Authority)]
|
||||||
public void RpcSyncGameObject(Godot.Collections.Dictionary gameObjectData)
|
public void RpcSyncGameObject(Godot.Collections.Dictionary gameObjectData)
|
||||||
{
|
{
|
||||||
|
|
@ -43,28 +66,22 @@ public partial class RPCNode : Node
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TrySyncFullGameObject(gameObjectData))
|
|
||||||
{
|
|
||||||
if (requestedFullGameObjects.Contains(uuid))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
requestedFullGameObjects.Add(uuid);
|
|
||||||
RpcId(1, nameof(RequestFullGameObject), NetworkManager.Instance.LocalNetId, (string)uuidData);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TrySyncFullGameObject(Godot.Collections.Dictionary gameObjectData)
|
|
||||||
|
[Rpc(MultiplayerApi.RpcMode.Authority)]
|
||||||
|
public void RpcSpawnGameObject(Godot.Collections.Dictionary gameObjectData)
|
||||||
{
|
{
|
||||||
|
GD.Print("SPAWNING: " + gameObjectData);
|
||||||
|
|
||||||
if (!gameObjectData.TryGetValue("type", out var typeData))
|
if (!gameObjectData.TryGetValue("type", out var typeData))
|
||||||
return false;
|
return;
|
||||||
if (!gameObjectData.TryGetValue("sectorCoordinates", out var sectorCoordinatesData))
|
if (!gameObjectData.TryGetValue("sectorCoordinates", out var sectorCoordinatesData))
|
||||||
return false;
|
return;
|
||||||
if (!gameObjectData.TryGetValue("localCoordinates", out var localCoordinatesData))
|
if (!gameObjectData.TryGetValue("localCoordinates", out var localCoordinatesData))
|
||||||
return false;
|
return;
|
||||||
if (!gameObjectData.TryGetValue("uuid", out var uuidData))
|
if (!gameObjectData.TryGetValue("uuid", out var uuidData))
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
string type = (string)typeData;
|
string type = (string)typeData;
|
||||||
Vector3I sectorCoordinates = (Vector3I)sectorCoordinatesData;
|
Vector3I sectorCoordinates = (Vector3I)sectorCoordinatesData;
|
||||||
|
|
@ -73,7 +90,7 @@ public partial class RPCNode : Node
|
||||||
|
|
||||||
Sector sector = GameManager.GameUniverse.GetSector(sectorCoordinates);
|
Sector sector = GameManager.GameUniverse.GetSector(sectorCoordinates);
|
||||||
if (sector == null)
|
if (sector == null)
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
GameObject gameObject;
|
GameObject gameObject;
|
||||||
switch (type)
|
switch (type)
|
||||||
|
|
@ -83,38 +100,15 @@ public partial class RPCNode : Node
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
gameObject.UUID = uuid;
|
gameObject.UUID = uuid;
|
||||||
gameObject.NetworkRead(gameObjectData);
|
gameObject.NetworkRead(gameObjectData);
|
||||||
requestedFullGameObjects.Remove(uuid);
|
|
||||||
|
|
||||||
sector.AssignObject(gameObject);
|
sector.AssignObject(gameObject);
|
||||||
|
|
||||||
return true;
|
GameManager.Instance.Spawn(gameObject);
|
||||||
}
|
|
||||||
|
|
||||||
[Rpc(MultiplayerApi.RpcMode.AnyPeer)]
|
|
||||||
public void RequestFullGameObject(long id, string uuidString)
|
|
||||||
{
|
|
||||||
if (!Global.IsGameHost)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Guid uuid = Guid.Parse(uuidString);
|
|
||||||
|
|
||||||
List<Sector> sectors = GameManager.Instance.GetPlayer(id).PlayerData.CurrentSector.GetNeighbouringSectors();
|
|
||||||
foreach (Sector sector in sectors)
|
|
||||||
{
|
|
||||||
GameObject gameObject = sector.GetObjectById(uuid);
|
|
||||||
if (gameObject != null)
|
|
||||||
{
|
|
||||||
gameObject.NetworkWrite(id, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Rpc(MultiplayerApi.RpcMode.AnyPeer)]
|
[Rpc(MultiplayerApi.RpcMode.AnyPeer)]
|
||||||
|
|
@ -138,8 +132,7 @@ public partial class RPCNode : Node
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3Dec newGlobal = playerData.CalculateGlobalCoordinates(sector.GlobalCenterCoordinates, position);
|
playerData.SetCoordinates(position);
|
||||||
playerData.SetCoordinatesFromGlobal(newGlobal);
|
|
||||||
|
|
||||||
if (playerData.CurrentSector.Coordinates != sectorCoordinates)
|
if (playerData.CurrentSector.Coordinates != sectorCoordinates)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5,45 +5,22 @@ using Godot;
|
||||||
public class Sector
|
public class Sector
|
||||||
{
|
{
|
||||||
public Vector3I Coordinates;
|
public Vector3I Coordinates;
|
||||||
public Vector3Dec GlobalStartCoordinates;
|
|
||||||
public Vector3Dec GlobalCenterCoordinates;
|
|
||||||
public Vector3Dec GlobalEndCoordinates;
|
|
||||||
public Vector3 Size;
|
|
||||||
|
|
||||||
public FastUniqueList<GameObject> GameObjects = new();
|
public FastUniqueList<GameObject> GameObjects = new();
|
||||||
|
|
||||||
public Sector(Vector3I coordinates, Vector3I offset, Vector3 size)
|
public Sector(Vector3I coordinates)
|
||||||
{
|
{
|
||||||
Coordinates = coordinates;
|
Coordinates = coordinates;
|
||||||
|
|
||||||
Vector3Dec sizeDec = Vector3Dec.FromVector3(size);
|
|
||||||
|
|
||||||
decimal startX = (coordinates.X - offset.X) * sizeDec.X;
|
|
||||||
decimal startY = (coordinates.Y - offset.Y) * sizeDec.Y;
|
|
||||||
decimal startZ = (coordinates.Z - offset.Z) * sizeDec.Z;
|
|
||||||
|
|
||||||
GlobalStartCoordinates = new(startX, startY, startZ);
|
|
||||||
|
|
||||||
GlobalCenterCoordinates = new(
|
|
||||||
startX + sizeDec.X / 2,
|
|
||||||
startY + sizeDec.Y / 2,
|
|
||||||
startZ + sizeDec.Z / 2
|
|
||||||
);
|
|
||||||
|
|
||||||
GlobalEndCoordinates = new(
|
|
||||||
startX + sizeDec.X,
|
|
||||||
startY + sizeDec.Y,
|
|
||||||
startZ + sizeDec.Z
|
|
||||||
);
|
|
||||||
|
|
||||||
Size = size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Simulate(double delta)
|
public void Simulate(double delta, HashSet<GameObject> ignoreObjects = null)
|
||||||
{
|
{
|
||||||
GameObjects.ForEach(gameObject =>
|
GameObjects.ForEach(gameObject =>
|
||||||
|
{
|
||||||
|
if (ignoreObjects == null || !ignoreObjects.Contains(gameObject))
|
||||||
{
|
{
|
||||||
gameObject.Simulate(delta);
|
gameObject.Simulate(delta);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -55,11 +32,6 @@ public class Sector
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsObjectInSector(GameObject gameObject)
|
|
||||||
{
|
|
||||||
return Helpers.IsInsideGlobalArea(GlobalStartCoordinates, GlobalEndCoordinates, gameObject.GlobalCoordinates);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AssignObject(GameObject gameObject)
|
public void AssignObject(GameObject gameObject)
|
||||||
{
|
{
|
||||||
QueueManager.SectorReassignQueue.Enqueue((this, gameObject));
|
QueueManager.SectorReassignQueue.Enqueue((this, gameObject));
|
||||||
|
|
@ -83,6 +55,20 @@ public class Sector
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool RemoveObjectById(Guid id)
|
||||||
|
{
|
||||||
|
foreach (GameObject gameObject in GameObjects)
|
||||||
|
{
|
||||||
|
if (gameObject.UUID.Equals(id))
|
||||||
|
{
|
||||||
|
GameObjects.Remove(gameObject);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public List<Sector> GetNeighbouringSectors()
|
public List<Sector> GetNeighbouringSectors()
|
||||||
{
|
{
|
||||||
List<Sector> neighbours = [];
|
List<Sector> neighbours = [];
|
||||||
|
|
@ -114,4 +100,15 @@ public class Sector
|
||||||
|
|
||||||
return neighbours;
|
return neighbours;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
Sector sector = (Sector)obj;
|
||||||
|
return sector.Coordinates == Coordinates;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return Coordinates.GetHashCode();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,10 +28,29 @@ public class Universe
|
||||||
return Sectors[x, y, z];
|
return Sectors[x, y, z];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Sector GetNeighbouringSector(Sector sector, bool? x, bool? y, bool? z)
|
||||||
|
{
|
||||||
|
Vector3I coordinates = sector.Coordinates;
|
||||||
|
|
||||||
|
if (x == true) coordinates.X++;
|
||||||
|
else if (x == false) coordinates.X--;
|
||||||
|
|
||||||
|
if (y == true) coordinates.Y++;
|
||||||
|
else if (y == false) coordinates.Y--;
|
||||||
|
|
||||||
|
if (z == true) coordinates.Z++;
|
||||||
|
else if (z == false) coordinates.Z--;
|
||||||
|
|
||||||
|
coordinates.X = Math.Clamp(coordinates.X, 0, Size.X);
|
||||||
|
coordinates.Y = Math.Clamp(coordinates.Y, 0, Size.Y);
|
||||||
|
coordinates.Z = Math.Clamp(coordinates.Z, 0, Size.Z);
|
||||||
|
|
||||||
|
return GetSector(coordinates);
|
||||||
|
}
|
||||||
|
|
||||||
public bool IsInside(Vector3I sectorCoordinates, Vector3 localCoordinates)
|
public bool IsInside(Vector3I sectorCoordinates, Vector3 localCoordinates)
|
||||||
{
|
{
|
||||||
Vector3 sectorSize = GameManager.Generator.GetSectorSize() / 2;
|
Vector3 sectorSize = GameManager.Generator.GetSectorSize() / 2;
|
||||||
Vector3I universeSize = GameManager.GameUniverse.Size;
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
sectorCoordinates.X == 0 && localCoordinates.X < -sectorSize.X ||
|
sectorCoordinates.X == 0 && localCoordinates.X < -sectorSize.X ||
|
||||||
|
|
@ -43,9 +62,9 @@ public class Universe
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
sectorCoordinates.X == universeSize.X - 1 && localCoordinates.X >= sectorSize.X ||
|
sectorCoordinates.X == Size.X - 1 && localCoordinates.X >= sectorSize.X ||
|
||||||
sectorCoordinates.Y == universeSize.Y - 1 && localCoordinates.Y >= sectorSize.Y ||
|
sectorCoordinates.Y == Size.Y - 1 && localCoordinates.Y >= sectorSize.Y ||
|
||||||
sectorCoordinates.Z == universeSize.Z - 1 && localCoordinates.Z >= sectorSize.Z
|
sectorCoordinates.Z == Size.Z - 1 && localCoordinates.Z >= sectorSize.Z
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -1,106 +0,0 @@
|
||||||
using System;
|
|
||||||
using Godot;
|
|
||||||
|
|
||||||
public readonly struct Vector3Dec(decimal x, decimal y, decimal z)
|
|
||||||
{
|
|
||||||
public static Vector3Dec Zero { get; } = new(0, 0, 0);
|
|
||||||
|
|
||||||
public decimal X { get; } = x;
|
|
||||||
public decimal Y { get; } = y;
|
|
||||||
public decimal Z { get; } = z;
|
|
||||||
|
|
||||||
public Vector3 ToVector3()
|
|
||||||
{
|
|
||||||
return new((double)X, (double)Y, (double)Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector3Dec FromVector3(Vector3 vec)
|
|
||||||
{
|
|
||||||
return new((decimal)vec.X, (decimal)vec.Y, (decimal)vec.Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector3Dec operator +(Vector3Dec vec1, Vector3Dec vec2)
|
|
||||||
{
|
|
||||||
return new(vec1.X + vec2.X, vec1.Y + vec2.Y, vec1.Z + vec2.Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector3Dec operator -(Vector3Dec vec1, Vector3Dec vec2)
|
|
||||||
{
|
|
||||||
return new(vec1.X - vec2.X, vec1.Y - vec2.Y, vec1.Z - vec2.Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector3Dec operator *(Vector3Dec vec1, Vector3Dec vec2)
|
|
||||||
{
|
|
||||||
return new(vec1.X * vec2.X, vec1.Y * vec2.Y, vec1.Z * vec2.Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector3Dec operator /(Vector3Dec vec1, Vector3Dec vec2)
|
|
||||||
{
|
|
||||||
return new(vec1.X / vec2.X, vec1.Y / vec2.Y, vec1.Z / vec2.Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector3Dec operator +(Vector3Dec vec, decimal value)
|
|
||||||
{
|
|
||||||
return new(vec.X + value, vec.Y + value, vec.Z + value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector3Dec operator +(decimal value, Vector3Dec vec)
|
|
||||||
{
|
|
||||||
return vec + value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector3Dec operator -(Vector3Dec vec, decimal value)
|
|
||||||
{
|
|
||||||
return new(vec.X - value, vec.Y - value, vec.Z - value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector3Dec operator -(decimal value, Vector3Dec vec)
|
|
||||||
{
|
|
||||||
return vec - value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector3Dec operator *(Vector3Dec vec, decimal value)
|
|
||||||
{
|
|
||||||
return new(vec.X * value, vec.Y * value, vec.Z * value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector3Dec operator *(decimal value, Vector3Dec vec)
|
|
||||||
{
|
|
||||||
return vec * value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector3Dec operator /(Vector3Dec vec, decimal value)
|
|
||||||
{
|
|
||||||
return new(vec.X / value, vec.Y / value, vec.Z / value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector3Dec operator /(decimal value, Vector3Dec vec)
|
|
||||||
{
|
|
||||||
return vec / value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector3Dec operator -(Vector3Dec vec)
|
|
||||||
{
|
|
||||||
return new(-vec.X, -vec.Y, -vec.Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator ==(Vector3Dec vec1, Vector3Dec vec2)
|
|
||||||
{
|
|
||||||
return vec1.X == vec2.X && vec1.Y == vec2.Y && vec1.Z == vec2.Z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator !=(Vector3Dec vec1, Vector3Dec vec2)
|
|
||||||
{
|
|
||||||
return !(vec1 == vec2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
return obj != null && obj is Vector3Dec vec && this == vec;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
return HashCode.Combine(X, Y, Z);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
uid://def7cpbdn6gjm
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue