Implement RPC Node

This commit is contained in:
Aslan 2026-02-02 12:17:04 -05:00
parent f7ee533d5a
commit 605e43273e
13 changed files with 524 additions and 206 deletions

View file

@ -16,25 +16,29 @@ public partial class GameManager : Node3D
[Export] public int maxFarThreads = 16;
public static bool Loading { get; private set; } = true;
public static GameManager Singleton { get; private set; }
public static GameManager Instance { get; private set; }
public static IGenerator Generator { get; private set; }
public static Universe GameUniverse { get; private set; }
public Player MainPlayer { get; private set; }
public List<Player> Players { get; private set; } = [];
public Dictionary<long, Player> Players { get; private set; } = [];
private double closeTickTimer = 0;
private double farTickTimer = 0;
public bool simulating = false;
public bool simulatingClose = false;
public bool simulatingFar = false;
public bool playerReady = false;
private readonly Dictionary<GameObject, Node3D> spawnedObjects = [];
private readonly ConcurrentQueue<GameObject> spawnQueue = [];
public override void _EnterTree()
{
Instance = this;
}
public override void _Ready()
{
Singleton = this;
Generator = new TestGenerator();
if (Global.IsGameHost)
@ -53,7 +57,7 @@ public partial class GameManager : Node3D
public override void _ExitTree()
{
Loading = true;
Singleton = null;
Instance = null;
}
public override void _Process(double delta)
@ -64,20 +68,14 @@ public partial class GameManager : Node3D
}
closeTickTimer += delta;
farTickTimer += delta;
if (closeTickTimer >= closeTickInterval)
if (closeTickTimer >= closeTickInterval && !simulatingClose)
{
SimulateClose(closeTickTimer);
closeTickTimer = 0;
}
if (simulating)
{
farTickTimer = 0;
}
if (farTickTimer >= farTickInterval)
farTickTimer += delta;
if (farTickTimer >= farTickInterval && !simulatingFar)
{
double taskFarTickTimer = farTickTimer;
Task.Run(() =>
@ -94,22 +92,48 @@ public partial class GameManager : Node3D
return MainPlayer.PlayerData.CurrentSector;
}
public Player GetPlayer(long id)
{
Players.TryGetValue(id, out Player player);
return player;
}
private void SimulateClose(double delta)
{
List<Sector> neighbours = GetCurrentSector().GetNeighbouringSectors();
simulatingClose = true;
neighbours.ForEach(sector =>
List<Sector> sectorsClose = GetCurrentSector().GetNeighbouringSectors();
List<Task> tasks = [];
sectorsClose.ForEach(sector =>
{
Task.Run(() =>
Task simulateTask = Task.Run(() =>
{
sector.Simulate(delta);
});
tasks.Add(simulateTask);
});
Task.WaitAll([.. tasks]);
foreach (KeyValuePair<long, Player> player in Players)
{
List<Sector> playerSectors = player.Value.PlayerData.CurrentSector.GetNeighbouringSectors();
playerSectors.ForEach(sector =>
{
if (player.Key != 1)
{
sector.NetworkSync(player.Key);
}
});
}
simulatingClose = false;
}
private void SimulateFar(double delta)
{
simulating = true;
simulatingFar = true;
List<Task> tasks = [];
@ -134,7 +158,7 @@ public partial class GameManager : Node3D
Task.WaitAll([.. tasks]);
simulating = false;
simulatingFar = false;
}
private void SimulateFarClustered(double delta, int startX, int countX)
@ -195,7 +219,7 @@ public partial class GameManager : Node3D
neighbours.ForEach(sector => sector.SpawnObjects());
}
public Player SpawnPlayer(Character character, bool isMainPlayer = false)
public Player SpawnPlayer(Character character, long networkId, bool isMainPlayer = false)
{
Player player = character.InstantiatePlayer();
player.GameMenu = GameMenu;
@ -206,7 +230,7 @@ public partial class GameManager : Node3D
OnPlayerReady();
}
Players.Add(player);
Players.Add(networkId, player);
character.UpdateSector();
@ -262,10 +286,10 @@ public partial class GameManager : Node3D
{
Sector current = GetCurrentSector();
foreach (Player player in Players)
foreach (KeyValuePair<long, Player> player in Players)
{
player.PlayerData.UpdateSectorOffset(current);
player.PlayerData.UpdateNodePosition();
player.Value.PlayerData.UpdateSectorOffset(current);
player.Value.PlayerData.UpdateNodePosition();
}
List<Sector> nearby = current.GetNeighbouringSectors();
@ -281,20 +305,18 @@ public partial class GameManager : Node3D
else
{
gameObject.UpdateSectorOffset(current);
node.GlobalPosition = gameObject.LocalCoordinates + gameObject.SectorOffset;
node._Process(0);
}
}
nearby.ForEach(sector => sector.SpawnObjects());
}
// These should be in RPCNode and should be queued
public void SendUniverseToClient(long id)
{
RpcId(id, nameof(RpcDownloadUniverse), Generator.GetUniverseSize(), Generator.GetSectorSize());
}
// These should be in RPCNode and should be queued
[Rpc(MultiplayerApi.RpcMode.Authority)]
public void RpcDownloadUniverse(Vector3I universeSize, Vector3 sectorSize)
{
@ -302,96 +324,4 @@ public partial class GameManager : Node3D
Loading = false;
}
// These should be in RPCNode and should be queued
[Rpc(MultiplayerApi.RpcMode.AnyPeer)]
public void RpcSendNearbySectors(Vector3I coordinates, long id = -1)
{
Sector sector = GameUniverse.GetSector(coordinates);
if (sector == null)
{
return;
}
List<Sector> sectors = sector.GetNeighbouringSectors();
sectors.ForEach(sector => SendSectorToClients(sector, id == -1 ? null : id));
}
// These should be in RPCNode and should be queued
public void SendSectorToClients(Sector sector, long? id = null)
{
foreach (GameObject gameObject in sector.GameObjects)
{
if (gameObject is Character)
{
continue;
}
Godot.Collections.Dictionary gameObjectData = new() {
{ "type", gameObject.GetType().Name },
{ "sectorCoordinates", sector.Coordinates },
{ "coordinates", gameObject.LocalCoordinates },
{ "uuid", gameObject.UUID.ToString() },
};
if (id.HasValue)
{
RpcId(id.Value, nameof(RpcDownloadGameObject), gameObjectData);
}
else
{
Rpc(nameof(RpcDownloadGameObject), gameObjectData);
}
}
}
// These should be in RPCNode and should be queued
[Rpc(MultiplayerApi.RpcMode.Authority)]
public void RpcDownloadGameObject(Godot.Collections.Dictionary gameObjectData)
{
if (!gameObjectData.TryGetValue("type", out var typeData))
{
return;
}
if (!gameObjectData.TryGetValue("sectorCoordinates", out var sectorCoordinatesData))
{
return;
}
if (!gameObjectData.TryGetValue("coordinates", out var coordinatesData))
{
return;
}
if (!gameObjectData.TryGetValue("uuid", out var uuidData))
{
return;
}
string type = (string)typeData;
Vector3I sectorCoordinates = (Vector3I)sectorCoordinatesData;
Vector3 coordinates = (Vector3)coordinatesData;
Guid uuid = Guid.Parse((string)uuidData);
Sector sector = GameUniverse.GetSector(sectorCoordinates);
if (sector == null)
{
return;
}
GameObject gameObject;
switch (type)
{
case "Star":
gameObject = new Star(sector, coordinates);
break;
default:
return;
}
gameObject.UUID = uuid;
Spawn(gameObject);
sector.AssignObject(gameObject);
}
}