Compare commits
No commits in common. "8581cf6fb8d3dd08e1bcb30a6959f4c3ddde55c98b6e748efd36f95b02fec27a" and "f7ee533d5a05795c407257d49cc01779e30768fb06ac1ae86b88fadfe907bc1f" have entirely different histories.
8581cf6fb8
...
f7ee533d5a
13 changed files with 206 additions and 524 deletions
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://cbt6p1bhh4o8q" path="res://scripts/GameObjects/Nodes/StarNode.cs" id="1_o2f8k"]
|
[ext_resource type="Script" uid="uid://cbt6p1bhh4o8q" path="res://scripts/GameObjects/Nodes/StarNode.cs" id="1_o2f8k"]
|
||||||
|
|
||||||
[sub_resource type="SphereMesh" id="SphereMesh_2pyv3"]
|
[sub_resource type="SphereMesh" id="SphereMesh_o2f8k"]
|
||||||
radius = 5.0
|
radius = 5.0
|
||||||
height = 10.0
|
height = 10.0
|
||||||
|
|
||||||
|
|
@ -13,7 +13,7 @@ radius = 5.0
|
||||||
script = ExtResource("1_o2f8k")
|
script = ExtResource("1_o2f8k")
|
||||||
|
|
||||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="." unique_id=1423841842]
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="." unique_id=1423841842]
|
||||||
mesh = SubResource("SphereMesh_2pyv3")
|
mesh = SubResource("SphereMesh_o2f8k")
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=1898956937]
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=1898956937]
|
||||||
shape = SubResource("SphereShape3D_o2f8k")
|
shape = SubResource("SphereShape3D_o2f8k")
|
||||||
|
|
|
||||||
|
|
@ -55,8 +55,9 @@ GameMenu = NodePath("../GameMenu")
|
||||||
[node name="QueueManager" type="Node" parent="." unique_id=355148200]
|
[node name="QueueManager" type="Node" parent="." unique_id=355148200]
|
||||||
script = ExtResource("4_iywne")
|
script = ExtResource("4_iywne")
|
||||||
|
|
||||||
[node name="NetworkManager" type="Node" parent="." unique_id=1765485895]
|
[node name="NetworkManager" type="Node" parent="." unique_id=1765485895 node_paths=PackedStringArray("RPCNode")]
|
||||||
script = ExtResource("5_p57ef")
|
script = ExtResource("5_p57ef")
|
||||||
|
RPCNode = NodePath("../RPC")
|
||||||
|
|
||||||
[node name="RPC" type="Node" parent="." unique_id=498537245]
|
[node name="RPC" type="Node" parent="." unique_id=498537245]
|
||||||
script = ExtResource("6_u5sy4")
|
script = ExtResource("6_u5sy4")
|
||||||
|
|
|
||||||
|
|
@ -16,29 +16,25 @@ public partial class GameManager : Node3D
|
||||||
[Export] public int maxFarThreads = 16;
|
[Export] public int maxFarThreads = 16;
|
||||||
|
|
||||||
public static bool Loading { get; private set; } = true;
|
public static bool Loading { get; private set; } = true;
|
||||||
public static GameManager Instance { get; private set; }
|
public static GameManager Singleton { get; private set; }
|
||||||
public static IGenerator Generator { get; private set; }
|
public static IGenerator Generator { get; private set; }
|
||||||
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 List<Player> Players { get; private set; } = [];
|
||||||
|
|
||||||
private double closeTickTimer = 0;
|
private double closeTickTimer = 0;
|
||||||
private double farTickTimer = 0;
|
private double farTickTimer = 0;
|
||||||
|
|
||||||
public bool simulatingClose = false;
|
public bool simulating = false;
|
||||||
public bool simulatingFar = false;
|
|
||||||
public bool playerReady = false;
|
public bool playerReady = false;
|
||||||
|
|
||||||
private readonly Dictionary<GameObject, Node3D> spawnedObjects = [];
|
private readonly Dictionary<GameObject, Node3D> spawnedObjects = [];
|
||||||
private readonly ConcurrentQueue<GameObject> spawnQueue = [];
|
private readonly ConcurrentQueue<GameObject> spawnQueue = [];
|
||||||
|
|
||||||
public override void _EnterTree()
|
|
||||||
{
|
|
||||||
Instance = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
|
Singleton = this;
|
||||||
|
|
||||||
Generator = new TestGenerator();
|
Generator = new TestGenerator();
|
||||||
|
|
||||||
if (Global.IsGameHost)
|
if (Global.IsGameHost)
|
||||||
|
|
@ -57,7 +53,7 @@ public partial class GameManager : Node3D
|
||||||
public override void _ExitTree()
|
public override void _ExitTree()
|
||||||
{
|
{
|
||||||
Loading = true;
|
Loading = true;
|
||||||
Instance = null;
|
Singleton = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _Process(double delta)
|
public override void _Process(double delta)
|
||||||
|
|
@ -68,14 +64,20 @@ public partial class GameManager : Node3D
|
||||||
}
|
}
|
||||||
|
|
||||||
closeTickTimer += delta;
|
closeTickTimer += delta;
|
||||||
if (closeTickTimer >= closeTickInterval && !simulatingClose)
|
farTickTimer += delta;
|
||||||
|
|
||||||
|
if (closeTickTimer >= closeTickInterval)
|
||||||
{
|
{
|
||||||
SimulateClose(closeTickTimer);
|
SimulateClose(closeTickTimer);
|
||||||
closeTickTimer = 0;
|
closeTickTimer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
farTickTimer += delta;
|
if (simulating)
|
||||||
if (farTickTimer >= farTickInterval && !simulatingFar)
|
{
|
||||||
|
farTickTimer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (farTickTimer >= farTickInterval)
|
||||||
{
|
{
|
||||||
double taskFarTickTimer = farTickTimer;
|
double taskFarTickTimer = farTickTimer;
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
|
|
@ -92,48 +94,22 @@ public partial class GameManager : Node3D
|
||||||
return MainPlayer.PlayerData.CurrentSector;
|
return MainPlayer.PlayerData.CurrentSector;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Player GetPlayer(long id)
|
|
||||||
{
|
|
||||||
Players.TryGetValue(id, out Player player);
|
|
||||||
return player;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SimulateClose(double delta)
|
private void SimulateClose(double delta)
|
||||||
{
|
{
|
||||||
simulatingClose = true;
|
List<Sector> neighbours = GetCurrentSector().GetNeighbouringSectors();
|
||||||
|
|
||||||
List<Sector> sectorsClose = GetCurrentSector().GetNeighbouringSectors();
|
neighbours.ForEach(sector =>
|
||||||
|
|
||||||
List<Task> tasks = [];
|
|
||||||
sectorsClose.ForEach(sector =>
|
|
||||||
{
|
{
|
||||||
Task simulateTask = Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
sector.Simulate(delta);
|
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)
|
private void SimulateFar(double delta)
|
||||||
{
|
{
|
||||||
simulatingFar = true;
|
simulating = true;
|
||||||
|
|
||||||
List<Task> tasks = [];
|
List<Task> tasks = [];
|
||||||
|
|
||||||
|
|
@ -158,7 +134,7 @@ public partial class GameManager : Node3D
|
||||||
|
|
||||||
Task.WaitAll([.. tasks]);
|
Task.WaitAll([.. tasks]);
|
||||||
|
|
||||||
simulatingFar = false;
|
simulating = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SimulateFarClustered(double delta, int startX, int countX)
|
private void SimulateFarClustered(double delta, int startX, int countX)
|
||||||
|
|
@ -219,7 +195,7 @@ public partial class GameManager : Node3D
|
||||||
neighbours.ForEach(sector => sector.SpawnObjects());
|
neighbours.ForEach(sector => sector.SpawnObjects());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Player SpawnPlayer(Character character, long networkId, bool isMainPlayer = false)
|
public Player SpawnPlayer(Character character, bool isMainPlayer = false)
|
||||||
{
|
{
|
||||||
Player player = character.InstantiatePlayer();
|
Player player = character.InstantiatePlayer();
|
||||||
player.GameMenu = GameMenu;
|
player.GameMenu = GameMenu;
|
||||||
|
|
@ -230,7 +206,7 @@ public partial class GameManager : Node3D
|
||||||
OnPlayerReady();
|
OnPlayerReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
Players.Add(networkId, player);
|
Players.Add(player);
|
||||||
|
|
||||||
character.UpdateSector();
|
character.UpdateSector();
|
||||||
|
|
||||||
|
|
@ -286,10 +262,10 @@ public partial class GameManager : Node3D
|
||||||
{
|
{
|
||||||
Sector current = GetCurrentSector();
|
Sector current = GetCurrentSector();
|
||||||
|
|
||||||
foreach (KeyValuePair<long, Player> player in Players)
|
foreach (Player player in Players)
|
||||||
{
|
{
|
||||||
player.Value.PlayerData.UpdateSectorOffset(current);
|
player.PlayerData.UpdateSectorOffset(current);
|
||||||
player.Value.PlayerData.UpdateNodePosition();
|
player.PlayerData.UpdateNodePosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Sector> nearby = current.GetNeighbouringSectors();
|
List<Sector> nearby = current.GetNeighbouringSectors();
|
||||||
|
|
@ -305,18 +281,20 @@ public partial class GameManager : Node3D
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gameObject.UpdateSectorOffset(current);
|
gameObject.UpdateSectorOffset(current);
|
||||||
node._Process(0);
|
node.GlobalPosition = gameObject.LocalCoordinates + gameObject.SectorOffset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nearby.ForEach(sector => sector.SpawnObjects());
|
nearby.ForEach(sector => sector.SpawnObjects());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// These should be in RPCNode and should be queued
|
||||||
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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// These should be in RPCNode and should be queued
|
||||||
[Rpc(MultiplayerApi.RpcMode.Authority)]
|
[Rpc(MultiplayerApi.RpcMode.Authority)]
|
||||||
public void RpcDownloadUniverse(Vector3I universeSize, Vector3 sectorSize)
|
public void RpcDownloadUniverse(Vector3I universeSize, Vector3 sectorSize)
|
||||||
{
|
{
|
||||||
|
|
@ -324,4 +302,96 @@ public partial class GameManager : Node3D
|
||||||
|
|
||||||
Loading = false;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,107 +4,13 @@ using Godot;
|
||||||
|
|
||||||
public abstract class GameObject
|
public abstract class GameObject
|
||||||
{
|
{
|
||||||
[Flags]
|
public Guid UUID { get; set; }
|
||||||
public enum DirtyFlags : ulong
|
|
||||||
{
|
|
||||||
None = 0,
|
|
||||||
UUID = 1UL << 0,
|
|
||||||
Sector = 1UL << 1,
|
|
||||||
LocalCoordinates = 1UL << 2,
|
|
||||||
Rotation = 1UL << 3,
|
|
||||||
Velocity = 1UL << 4,
|
|
||||||
AngularVelocity = 1UL << 5
|
|
||||||
}
|
|
||||||
public DirtyFlags DirtyBits { get; protected set; } = DirtyFlags.None;
|
|
||||||
|
|
||||||
protected Guid _uuid;
|
|
||||||
public Guid UUID
|
|
||||||
{
|
|
||||||
get => _uuid;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_uuid != value)
|
|
||||||
{
|
|
||||||
_uuid = value;
|
|
||||||
DirtyBits |= DirtyFlags.UUID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Vector3I _currentSectorCoordinates;
|
|
||||||
protected Sector _currentSector;
|
|
||||||
public Sector CurrentSector
|
|
||||||
{
|
|
||||||
get => _currentSector;
|
|
||||||
protected set
|
|
||||||
{
|
|
||||||
if (_currentSector != value)
|
|
||||||
{
|
|
||||||
_currentSector = value;
|
|
||||||
_currentSectorCoordinates = value.Coordinates;
|
|
||||||
DirtyBits |= DirtyFlags.Sector;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Vector3 _localCoordinates;
|
|
||||||
public Vector3 LocalCoordinates
|
|
||||||
{
|
|
||||||
get => _localCoordinates;
|
|
||||||
protected set
|
|
||||||
{
|
|
||||||
if (_localCoordinates != value)
|
|
||||||
{
|
|
||||||
_localCoordinates = value;
|
|
||||||
DirtyBits |= DirtyFlags.LocalCoordinates;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Vector3 _rotation;
|
|
||||||
public Vector3 Rotation
|
|
||||||
{
|
|
||||||
get => _rotation;
|
|
||||||
protected set
|
|
||||||
{
|
|
||||||
if (_rotation != value)
|
|
||||||
{
|
|
||||||
_rotation = value;
|
|
||||||
DirtyBits |= DirtyFlags.Rotation;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Vector3 _velocity;
|
|
||||||
public Vector3 Velocity
|
|
||||||
{
|
|
||||||
get => _velocity;
|
|
||||||
protected set
|
|
||||||
{
|
|
||||||
if (_velocity != value)
|
|
||||||
{
|
|
||||||
_velocity = value;
|
|
||||||
DirtyBits |= DirtyFlags.Velocity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Vector3 _angularVelocity;
|
|
||||||
public Vector3 AngularVelocity
|
|
||||||
{
|
|
||||||
get => _angularVelocity;
|
|
||||||
protected set
|
|
||||||
{
|
|
||||||
if (_angularVelocity != value)
|
|
||||||
{
|
|
||||||
_angularVelocity = value;
|
|
||||||
DirtyBits |= DirtyFlags.AngularVelocity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public Sector CurrentSector { get; protected set; }
|
||||||
|
public Vector3 LocalCoordinates { get; protected set; }
|
||||||
public Vector3Dec GlobalCoordinates { get; protected set; }
|
public Vector3Dec GlobalCoordinates { get; protected set; }
|
||||||
public Vector3 SectorOffset { get; protected set; }
|
|
||||||
|
public Vector3 SectorOffset { get; set; }
|
||||||
|
|
||||||
protected bool reassigning = false;
|
protected bool reassigning = false;
|
||||||
|
|
||||||
|
|
@ -115,10 +21,6 @@ public abstract class GameObject
|
||||||
CurrentSector = sector;
|
CurrentSector = sector;
|
||||||
LocalCoordinates = localCoordinates;
|
LocalCoordinates = localCoordinates;
|
||||||
|
|
||||||
Velocity = new(0, 0, 1);
|
|
||||||
AngularVelocity = Vector3.Zero;
|
|
||||||
Rotation = Vector3.Zero;
|
|
||||||
|
|
||||||
GlobalCoordinates = CalculateGlobalCoordinates(sector.GlobalCenterCoordinates, localCoordinates);
|
GlobalCoordinates = CalculateGlobalCoordinates(sector.GlobalCenterCoordinates, localCoordinates);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -144,12 +46,6 @@ public abstract class GameObject
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ApplyVelocity(double delta)
|
|
||||||
{
|
|
||||||
SetCoordinatesFromLocal(LocalCoordinates + Velocity * delta);
|
|
||||||
Rotation += AngularVelocity * delta;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsInCurrentSector()
|
public bool IsInCurrentSector()
|
||||||
{
|
{
|
||||||
return Helpers.IsInsideArea(CurrentSector.Size / 2, LocalCoordinates);
|
return Helpers.IsInsideArea(CurrentSector.Size / 2, LocalCoordinates);
|
||||||
|
|
@ -191,15 +87,15 @@ public abstract class GameObject
|
||||||
|
|
||||||
UpdateSectorOffsetToMainPlayer();
|
UpdateSectorOffsetToMainPlayer();
|
||||||
|
|
||||||
List<Sector> neighbours = GameManager.Instance.GetCurrentSector().GetNeighbouringSectors();
|
List<Sector> neighbours = GameManager.Singleton.GetCurrentSector().GetNeighbouringSectors();
|
||||||
|
|
||||||
if (neighbours.Contains(sector))
|
if (neighbours.Contains(sector))
|
||||||
{
|
{
|
||||||
GameManager.Instance.Spawn(this);
|
GameManager.Singleton.Spawn(this);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GameManager.Instance.Despawn(this);
|
GameManager.Singleton.Despawn(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
reassigning = false;
|
reassigning = false;
|
||||||
|
|
@ -218,7 +114,7 @@ public abstract class GameObject
|
||||||
|
|
||||||
public void UpdateSectorOffsetToMainPlayer()
|
public void UpdateSectorOffsetToMainPlayer()
|
||||||
{
|
{
|
||||||
UpdateSectorOffset(GameManager.Instance.GetCurrentSector());
|
UpdateSectorOffset(GameManager.Singleton.GetCurrentSector());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetCoordinatesFromGlobal(Vector3Dec globalCoordinates)
|
public void SetCoordinatesFromGlobal(Vector3Dec globalCoordinates)
|
||||||
|
|
@ -246,8 +142,6 @@ public abstract class GameObject
|
||||||
|
|
||||||
public virtual void Simulate(double delta)
|
public virtual void Simulate(double delta)
|
||||||
{
|
{
|
||||||
ApplyVelocity(delta);
|
|
||||||
|
|
||||||
if (!reassigning && !IsInCurrentSector())
|
if (!reassigning && !IsInCurrentSector())
|
||||||
{
|
{
|
||||||
UpdateSector();
|
UpdateSector();
|
||||||
|
|
@ -263,70 +157,4 @@ public abstract class GameObject
|
||||||
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual Godot.Collections.Dictionary NetworkWrite(long id, bool full)
|
|
||||||
{
|
|
||||||
Godot.Collections.Dictionary gameObjectData = [];
|
|
||||||
|
|
||||||
if (full)
|
|
||||||
gameObjectData.Add("type", GetType().ToString());
|
|
||||||
|
|
||||||
if (DirtyBits.HasFlag(DirtyFlags.Sector) || full)
|
|
||||||
gameObjectData.Add("sectorCoordinates", _currentSectorCoordinates);
|
|
||||||
|
|
||||||
if (DirtyBits.HasFlag(DirtyFlags.LocalCoordinates) || full)
|
|
||||||
gameObjectData.Add("localCoordinates", _localCoordinates);
|
|
||||||
|
|
||||||
if (DirtyBits.HasFlag(DirtyFlags.Rotation) || full)
|
|
||||||
gameObjectData.Add("rotation", _rotation);
|
|
||||||
|
|
||||||
if (DirtyBits.HasFlag(DirtyFlags.Velocity) || full)
|
|
||||||
gameObjectData.Add("velocity", _velocity);
|
|
||||||
|
|
||||||
if (DirtyBits.HasFlag(DirtyFlags.AngularVelocity) || full)
|
|
||||||
gameObjectData.Add("angularVelocity", _angularVelocity);
|
|
||||||
|
|
||||||
if (gameObjectData.Count > 0)
|
|
||||||
{
|
|
||||||
gameObjectData.Add("uuid", UUID.ToString());
|
|
||||||
return gameObjectData;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void NetworkRead(Godot.Collections.Dictionary gameObjectData)
|
|
||||||
{
|
|
||||||
if (gameObjectData.TryGetValue("sectorCoordinates", out var sectorCoordinatesData))
|
|
||||||
{
|
|
||||||
Sector newSector = GameManager.GameUniverse.GetSector((Vector3I)sectorCoordinatesData);
|
|
||||||
CurrentSector.GameObjects.Remove(this);
|
|
||||||
newSector.GameObjects.Add(this);
|
|
||||||
|
|
||||||
AssignSector(newSector);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gameObjectData.TryGetValue("localCoordinates", out var localCoordinatesData))
|
|
||||||
LocalCoordinates = (Vector3)localCoordinatesData;
|
|
||||||
|
|
||||||
if (gameObjectData.TryGetValue("rotation", out var rotationData))
|
|
||||||
Rotation = (Vector3)rotationData;
|
|
||||||
|
|
||||||
if (gameObjectData.TryGetValue("velocity", out var velocityData))
|
|
||||||
Velocity = (Vector3)velocityData;
|
|
||||||
|
|
||||||
if (gameObjectData.TryGetValue("angularVelocity", out var angularVelocityData))
|
|
||||||
AngularVelocity = (Vector3)angularVelocityData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
GameObject gameObj = (GameObject)obj;
|
|
||||||
return gameObj.UUID == UUID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
return UUID.GetHashCode();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,17 @@ public class Character(Sector sector, Vector3 localCoordinates) : GameObject(sec
|
||||||
|
|
||||||
if (IsMainPlayer())
|
if (IsMainPlayer())
|
||||||
{
|
{
|
||||||
GameManager.Instance.ApplyOrigin();
|
GameManager.Singleton.ApplyOrigin();
|
||||||
|
|
||||||
|
if (!Global.IsGameHost)
|
||||||
|
{
|
||||||
|
GameManager.Singleton.RpcId(
|
||||||
|
1,
|
||||||
|
nameof(GameManager.Singleton.RpcSendNearbySectors),
|
||||||
|
CurrentSector.Coordinates,
|
||||||
|
NetworkManager.Singleton.LocalNetId
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reassigning = false;
|
reassigning = false;
|
||||||
|
|
@ -24,7 +34,7 @@ public class Character(Sector sector, Vector3 localCoordinates) : GameObject(sec
|
||||||
|
|
||||||
public bool IsMainPlayer()
|
public bool IsMainPlayer()
|
||||||
{
|
{
|
||||||
return player == GameManager.Instance.MainPlayer;
|
return player == GameManager.Singleton.MainPlayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Player InstantiatePlayer()
|
public Player InstantiatePlayer()
|
||||||
|
|
@ -38,14 +48,6 @@ public class Character(Sector sector, Vector3 localCoordinates) : GameObject(sec
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Simulate(double delta)
|
|
||||||
{
|
|
||||||
if (!reassigning && !IsInCurrentSector())
|
|
||||||
{
|
|
||||||
UpdateSector();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void UpdateNodePosition()
|
public override void UpdateNodePosition()
|
||||||
{
|
{
|
||||||
if (IsMainPlayer())
|
if (IsMainPlayer())
|
||||||
|
|
|
||||||
|
|
@ -4,41 +4,13 @@ public partial class StarNode : StaticBody3D
|
||||||
{
|
{
|
||||||
public Star StarData { get; set; }
|
public Star StarData { get; set; }
|
||||||
|
|
||||||
private Vector3 lastFrameCoordinates = Vector3.Zero;
|
|
||||||
private Vector3 lastFrameRotation = Vector3.Zero;
|
|
||||||
|
|
||||||
private Vector3 velocityOffset = Vector3.Zero;
|
|
||||||
private Vector3 angularVelocityOffset = Vector3.Zero;
|
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
GlobalPosition = StarData.LocalCoordinates + StarData.SectorOffset;
|
GlobalPosition = StarData.LocalCoordinates + StarData.SectorOffset;
|
||||||
GlobalRotation = StarData.Rotation;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _Process(double delta)
|
public override void _Process(double delta)
|
||||||
{
|
{
|
||||||
if (StarData.LocalCoordinates == lastFrameCoordinates)
|
GlobalPosition = StarData.LocalCoordinates + StarData.SectorOffset;
|
||||||
{
|
|
||||||
velocityOffset += StarData.Velocity * delta;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
lastFrameCoordinates = StarData.LocalCoordinates;
|
|
||||||
velocityOffset = Vector3.Zero;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StarData.Rotation == lastFrameRotation)
|
|
||||||
{
|
|
||||||
angularVelocityOffset += StarData.AngularVelocity * delta;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
lastFrameRotation = StarData.Rotation;
|
|
||||||
angularVelocityOffset = Vector3.Zero;
|
|
||||||
}
|
|
||||||
|
|
||||||
GlobalPosition = StarData.LocalCoordinates + StarData.SectorOffset + velocityOffset;
|
|
||||||
GlobalRotation = StarData.Rotation + angularVelocityOffset;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ public class Star(Sector sector, Vector3 localCoordinates) : GameObject(sector,
|
||||||
public override void Simulate(double delta)
|
public override void Simulate(double delta)
|
||||||
{
|
{
|
||||||
base.Simulate(delta);
|
base.Simulate(delta);
|
||||||
|
|
||||||
|
//SetCoordinatesFromGlobal(new(GlobalCoordinates.X, GlobalCoordinates.Y, GlobalCoordinates.Z + 1 * (decimal)delta));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Node3D Instantiate(Sector sector)
|
public override Node3D Instantiate(Sector sector)
|
||||||
|
|
@ -18,22 +20,4 @@ public class Star(Sector sector, Vector3 localCoordinates) : GameObject(sector,
|
||||||
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Godot.Collections.Dictionary NetworkWrite(long id, bool full)
|
|
||||||
{
|
|
||||||
Godot.Collections.Dictionary gameObjectData = base.NetworkWrite(id, full);
|
|
||||||
|
|
||||||
if (gameObjectData != null)
|
|
||||||
{
|
|
||||||
QueueManager.NetworkSyncQueue.Enqueue((id, gameObjectData));
|
|
||||||
}
|
|
||||||
DirtyBits = DirtyFlags.None;
|
|
||||||
|
|
||||||
return gameObjectData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void NetworkRead(Godot.Collections.Dictionary gameObjectData)
|
|
||||||
{
|
|
||||||
base.NetworkRead(gameObjectData);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,9 +30,9 @@ public class TestGenerator : IGenerator
|
||||||
public Vector3I GetSectorOffset(Vector3I universeSize)
|
public Vector3I GetSectorOffset(Vector3I universeSize)
|
||||||
{
|
{
|
||||||
return new(
|
return new(
|
||||||
(int)Mathf.Floor(universeSize.X / 2),
|
(int)Mathf.Floor(UNIVERSE_SIZE.X / 2),
|
||||||
(int)Mathf.Floor(universeSize.X / 2),
|
(int)Mathf.Floor(UNIVERSE_SIZE.X / 2),
|
||||||
(int)Mathf.Floor(universeSize.X / 2)
|
(int)Mathf.Floor(UNIVERSE_SIZE.X / 2)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -117,15 +117,12 @@ public class TestGenerator : IGenerator
|
||||||
starCount = Mathf.Clamp(starCount, 0, int.MaxValue);
|
starCount = Mathf.Clamp(starCount, 0, int.MaxValue);
|
||||||
|
|
||||||
for (int i = 0; i < starCount; i++)
|
for (int i = 0; i < starCount; i++)
|
||||||
{
|
|
||||||
if (coordinates.X == 5 && coordinates.Y == 5 && coordinates.Z == 5)
|
|
||||||
{
|
{
|
||||||
Vector3 localCoordinates = GenerateLocalCoordinates();
|
Vector3 localCoordinates = GenerateLocalCoordinates();
|
||||||
Star star = GenerateStar(sector, localCoordinates);
|
Star star = GenerateStar(sector, localCoordinates);
|
||||||
|
|
||||||
sector.GameObjects.Add(star);
|
sector.GameObjects.Add(star);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
int shipCount = rng.RandiRange(
|
int shipCount = rng.RandiRange(
|
||||||
SHIPS_PER_SECTOR - SHIPS_PER_SECTOR_VARIANCE,
|
SHIPS_PER_SECTOR - SHIPS_PER_SECTOR_VARIANCE,
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,15 @@ using Godot;
|
||||||
|
|
||||||
public partial class NetworkManager : Node
|
public partial class NetworkManager : Node
|
||||||
{
|
{
|
||||||
public static NetworkManager Instance { get; private set; }
|
[Export] public RPCNode RPCNode { get; private set; }
|
||||||
|
|
||||||
|
public static NetworkManager Singleton { get; private set; }
|
||||||
|
|
||||||
public int LocalNetId { get; private set; } = -1;
|
public int LocalNetId { get; private set; } = -1;
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
Instance = this;
|
Singleton = this;
|
||||||
|
|
||||||
if (Global.IsGameHost)
|
if (Global.IsGameHost)
|
||||||
{
|
{
|
||||||
|
|
@ -64,7 +66,7 @@ public partial class NetworkManager : Node
|
||||||
{
|
{
|
||||||
if (Global.IsGameHost)
|
if (Global.IsGameHost)
|
||||||
{
|
{
|
||||||
GameManager.Instance.SendUniverseToClient(id);
|
GameManager.Singleton.SendUniverseToClient(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = SpawnNetPlayer(id);
|
_ = SpawnNetPlayer(id);
|
||||||
|
|
@ -73,7 +75,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.Singleton.DespawnPlayer(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SpawnNetPlayer(long id)
|
private async Task SpawnNetPlayer(long id)
|
||||||
|
|
@ -86,9 +88,14 @@ public partial class NetworkManager : Node
|
||||||
bool isMainPlayer = LocalNetId == id;
|
bool isMainPlayer = LocalNetId == id;
|
||||||
|
|
||||||
Character character = new(GameManager.GameUniverse.Sectors[5, 5, 5], new(0, 0, 0));
|
Character character = new(GameManager.GameUniverse.Sectors[5, 5, 5], new(0, 0, 0));
|
||||||
Player player = GameManager.Instance.SpawnPlayer(character, id, isMainPlayer);
|
Player player = GameManager.Singleton.SpawnPlayer(character, isMainPlayer);
|
||||||
player.Name = $"Player-{id}";
|
player.Name = $"Player-{id}";
|
||||||
|
|
||||||
player.SetMultiplayerAuthority((int)id);
|
player.SetMultiplayerAuthority((int)id);
|
||||||
|
|
||||||
|
if (isMainPlayer && !Global.IsGameHost)
|
||||||
|
{
|
||||||
|
GameManager.Singleton.RpcId(1, nameof(GameManager.Singleton.RpcSendNearbySectors), character.CurrentSector.Coordinates, id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,11 @@ public partial class Player : CharacterBody3D
|
||||||
[Export] public double NetworkPhysicsSyncInterval = 0.05;
|
[Export] public double NetworkPhysicsSyncInterval = 0.05;
|
||||||
|
|
||||||
public Control GameMenu { get; set; }
|
public Control GameMenu { get; set; }
|
||||||
|
|
||||||
public Character PlayerData { get; set; }
|
public Character PlayerData { get; set; }
|
||||||
|
|
||||||
public Vector3 GravityVelocity { get; set; } = Vector3.Zero;
|
private Vector3 gravityVelocity = Vector3.Zero;
|
||||||
public Vector3 MovementVelocity { get; set; } = Vector3.Zero;
|
private Vector3 movementVelocity = Vector3.Zero;
|
||||||
|
|
||||||
private GravityReceiver gravityReceiver;
|
private GravityReceiver gravityReceiver;
|
||||||
private double cameraPitch = 0;
|
private double cameraPitch = 0;
|
||||||
private Camera3D camera;
|
private Camera3D camera;
|
||||||
|
|
@ -35,20 +35,18 @@ public partial class Player : CharacterBody3D
|
||||||
{
|
{
|
||||||
if (IsMultiplayerAuthority())
|
if (IsMultiplayerAuthority())
|
||||||
{
|
{
|
||||||
RPCNode rpc = RPCNode.Instance;
|
|
||||||
|
|
||||||
networkPhysicsSyncCounter += delta;
|
networkPhysicsSyncCounter += delta;
|
||||||
if (networkPhysicsSyncCounter >= NetworkPhysicsSyncInterval)
|
if (networkPhysicsSyncCounter >= NetworkPhysicsSyncInterval)
|
||||||
{
|
{
|
||||||
networkPhysicsSyncCounter = 0;
|
networkPhysicsSyncCounter = 0;
|
||||||
rpc.Rpc(nameof(rpc.RpcSyncPlayerPhysics), GetMultiplayerAuthority(), MovementVelocity, GravityVelocity, GlobalRotation);
|
Rpc(nameof(RpcSyncPhysics), movementVelocity, gravityVelocity, GlobalRotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
networkSyncCounter += delta;
|
networkSyncCounter += delta;
|
||||||
if (networkSyncCounter >= NetworkSyncInterval)
|
if (networkSyncCounter >= NetworkSyncInterval)
|
||||||
{
|
{
|
||||||
networkSyncCounter = 0;
|
networkSyncCounter = 0;
|
||||||
rpc.Rpc(nameof(rpc.RpcSyncPlayer), GetMultiplayerAuthority(), GlobalPosition, PlayerData.CurrentSector.Coordinates);
|
Rpc(nameof(RpcSync), GlobalPosition, PlayerData.CurrentSector.Coordinates);
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerData.SetCoordinatesFromLocal(GlobalPosition);
|
PlayerData.SetCoordinatesFromLocal(GlobalPosition);
|
||||||
|
|
@ -59,8 +57,8 @@ public partial class Player : CharacterBody3D
|
||||||
|
|
||||||
public override void _PhysicsProcess(double delta)
|
public override void _PhysicsProcess(double delta)
|
||||||
{
|
{
|
||||||
Vector3 newGravityVelocity = GravityVelocity;
|
Vector3 newGravityVelocity = gravityVelocity;
|
||||||
Vector3 newMovementVelocity = MovementVelocity;
|
Vector3 newMovementVelocity = movementVelocity;
|
||||||
|
|
||||||
if (!GameMenu.Visible && IsMultiplayerAuthority())
|
if (!GameMenu.Visible && IsMultiplayerAuthority())
|
||||||
{
|
{
|
||||||
|
|
@ -78,8 +76,8 @@ public partial class Player : CharacterBody3D
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GravityVelocity = newGravityVelocity;
|
gravityVelocity = newGravityVelocity;
|
||||||
MovementVelocity = newMovementVelocity;
|
movementVelocity = newMovementVelocity;
|
||||||
Velocity = newGravityVelocity + newMovementVelocity;
|
Velocity = newGravityVelocity + newMovementVelocity;
|
||||||
|
|
||||||
MoveAndSlide();
|
MoveAndSlide();
|
||||||
|
|
@ -239,4 +237,33 @@ public partial class Player : CharacterBody3D
|
||||||
|
|
||||||
RotateObjectLocal(Vector3.Forward, rotateAmountZ);
|
RotateObjectLocal(Vector3.Forward, rotateAmountZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Rpc(MultiplayerApi.RpcMode.AnyPeer)]
|
||||||
|
public void RpcSync(Vector3 position, Vector3I sectorCoordinates)
|
||||||
|
{
|
||||||
|
Sector sector = GameManager.GameUniverse.GetSector(sectorCoordinates);
|
||||||
|
if (sector == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3Dec newGlobal = PlayerData.CalculateGlobalCoordinates(sector.GlobalCenterCoordinates, position);
|
||||||
|
PlayerData.SetCoordinatesFromGlobal(newGlobal);
|
||||||
|
|
||||||
|
if (PlayerData.CurrentSector.Coordinates != sectorCoordinates)
|
||||||
|
{
|
||||||
|
sector.AssignObject(PlayerData);
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalPosition = position + PlayerData.SectorOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Rpc(MultiplayerApi.RpcMode.AnyPeer)]
|
||||||
|
public void RpcSyncPhysics(Vector3 _movementVelocity, Vector3 _gravityVelocity, Vector3 rotation)
|
||||||
|
{
|
||||||
|
movementVelocity = _movementVelocity;
|
||||||
|
gravityVelocity = _gravityVelocity;
|
||||||
|
|
||||||
|
GlobalRotation = rotation;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,18 +8,11 @@ public partial class QueueManager : Node
|
||||||
public static ConcurrentQueue<Action> ActionQueue = new();
|
public static ConcurrentQueue<Action> ActionQueue = new();
|
||||||
|
|
||||||
public static ConcurrentQueue<(Sector, GameObject)> SectorReassignQueue = new();
|
public static ConcurrentQueue<(Sector, GameObject)> SectorReassignQueue = new();
|
||||||
public static ConcurrentQueue<(long, Godot.Collections.Dictionary)> NetworkSyncQueue = new();
|
|
||||||
|
|
||||||
private readonly int sectorReassignQueueRateLimit = 500;
|
private readonly int sectorReassignQueueRateLimit = 500;
|
||||||
private readonly int networkSyncQueueRateLimit = 10;
|
|
||||||
|
|
||||||
public override void _Process(double delta)
|
public override void _Process(double delta)
|
||||||
{
|
{
|
||||||
if (!GameManager.Instance.playerReady)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (LogQueue.TryDequeue(out string text))
|
while (LogQueue.TryDequeue(out string text))
|
||||||
{
|
{
|
||||||
GD.Print(text);
|
GD.Print(text);
|
||||||
|
|
@ -32,7 +25,7 @@ public partial class QueueManager : Node
|
||||||
|
|
||||||
int sectorReassignQueueProcessed = 0;
|
int sectorReassignQueueProcessed = 0;
|
||||||
while (
|
while (
|
||||||
!GameManager.Instance.simulatingFar
|
!GameManager.Singleton.simulating
|
||||||
&& sectorReassignQueueProcessed++ < sectorReassignQueueRateLimit
|
&& sectorReassignQueueProcessed++ < sectorReassignQueueRateLimit
|
||||||
&& SectorReassignQueue.TryDequeue(out var item)
|
&& SectorReassignQueue.TryDequeue(out var item)
|
||||||
)
|
)
|
||||||
|
|
@ -44,16 +37,5 @@ public partial class QueueManager : Node
|
||||||
|
|
||||||
gameObject.AssignSector(sector);
|
gameObject.AssignSector(sector);
|
||||||
}
|
}
|
||||||
|
|
||||||
int networkSyncQueueProcessed = 0;
|
|
||||||
while (
|
|
||||||
networkSyncQueueProcessed++ < networkSyncQueueRateLimit
|
|
||||||
&& NetworkSyncQueue.TryDequeue(out var item)
|
|
||||||
)
|
|
||||||
{
|
|
||||||
var (clientId, gameObjectData) = item;
|
|
||||||
|
|
||||||
RPCNode.Instance.RpcId(clientId, nameof(RPCNode.RpcSyncGameObject), gameObjectData);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,171 +1,5 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
public partial class RPCNode : Node
|
public partial class RPCNode : Node
|
||||||
{
|
{
|
||||||
public static RPCNode Instance { get; private set; }
|
|
||||||
|
|
||||||
private readonly HashSet<Guid> requestedFullGameObjects = [];
|
|
||||||
|
|
||||||
public override void _EnterTree()
|
|
||||||
{
|
|
||||||
Instance = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void _ExitTree()
|
|
||||||
{
|
|
||||||
Instance = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Rpc(MultiplayerApi.RpcMode.Authority)]
|
|
||||||
public void RpcSyncGameObject(Godot.Collections.Dictionary gameObjectData)
|
|
||||||
{
|
|
||||||
GD.Print("READING: " + gameObjectData);
|
|
||||||
|
|
||||||
if (!GameManager.Instance.playerReady)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!gameObjectData.TryGetValue("uuid", out var uuidData))
|
|
||||||
return;
|
|
||||||
|
|
||||||
Guid uuid = Guid.Parse((string)uuidData);
|
|
||||||
|
|
||||||
List<Sector> sectors = GameManager.Instance.GetCurrentSector().GetNeighbouringSectors();
|
|
||||||
foreach (Sector sector in sectors)
|
|
||||||
{
|
|
||||||
GameObject gameObject = sector.GetObjectById(uuid);
|
|
||||||
if (gameObject != null)
|
|
||||||
{
|
|
||||||
gameObject.NetworkRead(gameObjectData);
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
if (!gameObjectData.TryGetValue("type", out var typeData))
|
|
||||||
return false;
|
|
||||||
if (!gameObjectData.TryGetValue("sectorCoordinates", out var sectorCoordinatesData))
|
|
||||||
return false;
|
|
||||||
if (!gameObjectData.TryGetValue("localCoordinates", out var localCoordinatesData))
|
|
||||||
return false;
|
|
||||||
if (!gameObjectData.TryGetValue("uuid", out var uuidData))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
string type = (string)typeData;
|
|
||||||
Vector3I sectorCoordinates = (Vector3I)sectorCoordinatesData;
|
|
||||||
Vector3 localCoordinates = (Vector3)localCoordinatesData;
|
|
||||||
Guid uuid = Guid.Parse((string)uuidData);
|
|
||||||
|
|
||||||
Sector sector = GameManager.GameUniverse.GetSector(sectorCoordinates);
|
|
||||||
if (sector == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
GameObject gameObject;
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case "Star":
|
|
||||||
gameObject = new Star(sector, localCoordinates);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
gameObject.UUID = uuid;
|
|
||||||
gameObject.NetworkRead(gameObjectData);
|
|
||||||
requestedFullGameObjects.Remove(uuid);
|
|
||||||
|
|
||||||
sector.AssignObject(gameObject);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
[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)]
|
|
||||||
public void RpcSyncPlayer(long id, Vector3 position, Vector3I sectorCoordinates)
|
|
||||||
{
|
|
||||||
if (!GameManager.Instance.playerReady)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
GameManager.Instance.Players.TryGetValue(id, out Player player);
|
|
||||||
if (player == null || !player.IsInsideTree())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Character playerData = player.PlayerData;
|
|
||||||
|
|
||||||
Sector sector = GameManager.GameUniverse.GetSector(sectorCoordinates);
|
|
||||||
if (sector == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector3Dec newGlobal = playerData.CalculateGlobalCoordinates(sector.GlobalCenterCoordinates, position);
|
|
||||||
playerData.SetCoordinatesFromGlobal(newGlobal);
|
|
||||||
|
|
||||||
if (playerData.CurrentSector.Coordinates != sectorCoordinates)
|
|
||||||
{
|
|
||||||
sector.AssignObject(playerData);
|
|
||||||
}
|
|
||||||
|
|
||||||
player.GlobalPosition = position + playerData.SectorOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Rpc(MultiplayerApi.RpcMode.AnyPeer)]
|
|
||||||
public void RpcSyncPlayerPhysics(long id, Vector3 _movementVelocity, Vector3 _gravityVelocity, Vector3 rotation)
|
|
||||||
{
|
|
||||||
if (!GameManager.Instance.playerReady)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
GameManager.Instance.Players.TryGetValue(id, out Player player);
|
|
||||||
if (player == null || !player.IsInsideTree())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
player.MovementVelocity = _movementVelocity;
|
|
||||||
player.GravityVelocity = _gravityVelocity;
|
|
||||||
|
|
||||||
player.GlobalRotation = rotation;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
|
|
@ -47,14 +46,6 @@ public class Sector
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void NetworkSync(long id)
|
|
||||||
{
|
|
||||||
GameObjects.ForEach(gameObject =>
|
|
||||||
{
|
|
||||||
gameObject.NetworkWrite(id, false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsObjectInSector(GameObject gameObject)
|
public bool IsObjectInSector(GameObject gameObject)
|
||||||
{
|
{
|
||||||
return Helpers.IsInsideGlobalArea(GlobalStartCoordinates, GlobalEndCoordinates, gameObject.GlobalCoordinates);
|
return Helpers.IsInsideGlobalArea(GlobalStartCoordinates, GlobalEndCoordinates, gameObject.GlobalCoordinates);
|
||||||
|
|
@ -67,20 +58,7 @@ public class Sector
|
||||||
|
|
||||||
public void SpawnObjects()
|
public void SpawnObjects()
|
||||||
{
|
{
|
||||||
GameObjects.ForEach(GameManager.Instance.Spawn);
|
GameObjects.ForEach(GameManager.Singleton.Spawn);
|
||||||
}
|
|
||||||
|
|
||||||
public GameObject GetObjectById(Guid id)
|
|
||||||
{
|
|
||||||
foreach (GameObject gameObject in GameObjects)
|
|
||||||
{
|
|
||||||
if (gameObject.UUID.Equals(id))
|
|
||||||
{
|
|
||||||
return gameObject;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Sector> GetNeighbouringSectors()
|
public List<Sector> GetNeighbouringSectors()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue