Implement basic networking
This commit is contained in:
parent
c320d9ddcb
commit
994823a9c3
25 changed files with 643 additions and 217 deletions
|
|
@ -9,22 +9,24 @@ public partial class GameManager : Node3D
|
|||
{
|
||||
[Export] public Control GameMenu { get; private set; }
|
||||
[Export] public QueueManager QueueManager { get; private set; }
|
||||
[Export] public Node3D SpaceRoot { get; private set; }
|
||||
|
||||
[Export] public double closeTickInterval = 1;
|
||||
[Export] public double farTickInterval = 10;
|
||||
[Export] public int maxFarThreads = 16;
|
||||
|
||||
public Player MainPlayer { get; private set; }
|
||||
|
||||
public static bool Loading { get; private set; } = true;
|
||||
public static GameManager Singleton { get; private set; }
|
||||
public IGenerator Generator { get; private set; }
|
||||
|
||||
public Universe GameUniverse { 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; } = [];
|
||||
|
||||
private double closeTickTimer = 0;
|
||||
private double farTickTimer = 0;
|
||||
|
||||
public bool simulating = false;
|
||||
public bool playerReady = false;
|
||||
|
||||
private readonly Dictionary<GameObject, Node3D> spawnedObjects = [];
|
||||
private readonly ConcurrentQueue<GameObject> spawnQueue = [];
|
||||
|
|
@ -34,19 +36,33 @@ public partial class GameManager : Node3D
|
|||
Singleton = this;
|
||||
|
||||
Generator = new TestGenerator();
|
||||
GameUniverse = Generator.GenerateUniverse();
|
||||
|
||||
Character character = new(GameUniverse.Sectors[50, 50, 50], new(0, 0, 0));
|
||||
MainPlayer = character.InstantiatePlayer();
|
||||
MainPlayer.GameMenu = GameMenu;
|
||||
spawnedObjects.Add(character, MainPlayer);
|
||||
CallDeferred("add_child", MainPlayer);
|
||||
if (Global.IsGameHost)
|
||||
{
|
||||
GameUniverse = Generator.GenerateUniverse();
|
||||
Loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPlayerReady()
|
||||
{
|
||||
playerReady = true;
|
||||
SpawnClose();
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
Loading = true;
|
||||
Singleton = null;
|
||||
}
|
||||
|
||||
public override void _Process(double delta)
|
||||
{
|
||||
if (!playerReady || !Global.IsGameHost)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
closeTickTimer += delta;
|
||||
farTickTimer += delta;
|
||||
|
||||
|
|
@ -143,7 +159,6 @@ public partial class GameManager : Node3D
|
|||
|
||||
for (int x = startX; x < endX; x++)
|
||||
{
|
||||
QueueManager.LogQueue.Enqueue("Simulating: " + x);
|
||||
for (int y = 0; y < sizeY; y++)
|
||||
{
|
||||
Thread.Sleep(5);
|
||||
|
|
@ -180,10 +195,34 @@ public partial class GameManager : Node3D
|
|||
neighbours.ForEach(sector => sector.SpawnObjects());
|
||||
}
|
||||
|
||||
public Player SpawnPlayer(Character character, bool isMainPlayer = false)
|
||||
{
|
||||
Player player = character.InstantiatePlayer();
|
||||
player.GameMenu = GameMenu;
|
||||
|
||||
if (isMainPlayer)
|
||||
{
|
||||
MainPlayer = player;
|
||||
OnPlayerReady();
|
||||
}
|
||||
|
||||
Players.Add(player);
|
||||
|
||||
character.UpdateSector();
|
||||
|
||||
SpaceRoot.CallDeferred("add_child", player);
|
||||
return player;
|
||||
}
|
||||
|
||||
public void DespawnPlayer(Player player)
|
||||
{
|
||||
SpaceRoot.CallDeferred("remove_child", player);
|
||||
player.CallDeferred("queue_free");
|
||||
}
|
||||
|
||||
public void Spawn(GameObject gameObject)
|
||||
{
|
||||
spawnQueue.Enqueue(gameObject);
|
||||
|
||||
CallDeferred(nameof(ProcessSpawnQueue));
|
||||
}
|
||||
|
||||
|
|
@ -202,7 +241,7 @@ public partial class GameManager : Node3D
|
|||
Node3D instance = gameObject.Instantiate(GetCurrentSector());
|
||||
spawnedObjects.Add(gameObject, instance);
|
||||
|
||||
CallDeferred("add_child", instance);
|
||||
SpaceRoot.CallDeferred("add_child", instance);
|
||||
}
|
||||
|
||||
public void Despawn(GameObject gameObject)
|
||||
|
|
@ -215,7 +254,7 @@ public partial class GameManager : Node3D
|
|||
Node3D nodeToDespawn = spawnedObjects.GetValueOrDefault(gameObject);
|
||||
spawnedObjects.Remove(gameObject);
|
||||
|
||||
CallDeferred("remove_child", nodeToDespawn);
|
||||
SpaceRoot.CallDeferred("remove_child", nodeToDespawn);
|
||||
nodeToDespawn.CallDeferred("queue_free");
|
||||
}
|
||||
|
||||
|
|
@ -223,24 +262,136 @@ public partial class GameManager : Node3D
|
|||
{
|
||||
Sector current = GetCurrentSector();
|
||||
|
||||
List<Sector> nearby = current.GetNeighbouringSectors();
|
||||
|
||||
foreach (Sector sector in nearby)
|
||||
foreach (Player player in Players)
|
||||
{
|
||||
foreach (GameObject gameObject in sector.GameObjects)
|
||||
{
|
||||
gameObject.UpdateSectorOffset(current);
|
||||
}
|
||||
player.PlayerData.UpdateSectorOffset(current);
|
||||
player.PlayerData.UpdateNodePosition();
|
||||
}
|
||||
|
||||
foreach (GameObject spawned in spawnedObjects.Keys)
|
||||
List<Sector> nearby = current.GetNeighbouringSectors();
|
||||
foreach (KeyValuePair<GameObject, Node3D> spawned in spawnedObjects)
|
||||
{
|
||||
if (!nearby.Contains(spawned.CurrentSector))
|
||||
GameObject gameObject = spawned.Key;
|
||||
Node3D node = spawned.Value;
|
||||
|
||||
if (!nearby.Contains(gameObject.CurrentSector))
|
||||
{
|
||||
Despawn(spawned);
|
||||
Despawn(gameObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
gameObject.UpdateSectorOffset(current);
|
||||
node.GlobalPosition = gameObject.LocalCoordinates + gameObject.SectorOffset;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
GameUniverse = Generator.InitializeEmptyUniverse(universeSize, sectorSize);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue