Implement basic networking
This commit is contained in:
parent
c320d9ddcb
commit
994823a9c3
25 changed files with 643 additions and 217 deletions
|
|
@ -1,11 +0,0 @@
|
||||||
<Project Sdk="Godot.NET.Sdk/4.6.0-rc.2">
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<TargetFramework
|
|
||||||
Condition=" '$(GodotTargetPlatform)' == 'android' "
|
|
||||||
>net9.0</TargetFramework>
|
|
||||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
|
||||||
<RootNamespace>ImperfectSpace</RootNamespace>
|
|
||||||
<SuppressImplicitGitSourceLink>true</SuppressImplicitGitSourceLink>
|
|
||||||
</PropertyGroup>
|
|
||||||
</Project>
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
<Project Sdk="Godot.NET.Sdk/4.6.0-rc.1">
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<TargetFramework Condition=" '$(GodotTargetPlatform)' == 'android' ">net9.0</TargetFramework>
|
|
||||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
|
||||||
<RootNamespace>ImperfectSpace</RootNamespace>
|
|
||||||
<SuppressImplicitGitSourceLink>true</SuppressImplicitGitSourceLink>
|
|
||||||
</PropertyGroup>
|
|
||||||
</Project>
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
[gd_scene format=3 uid="uid://b6c17xutiecq5"]
|
[gd_scene format=3 uid="uid://b6c17xutiecq5"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://dknsws58ej0bp" path="res://scripts/GameObject.cs" id="1_gt1sn"]
|
|
||||||
|
|
||||||
[node name="Node" type="StaticBody3D" unique_id=1306600716]
|
[node name="Node" type="StaticBody3D" unique_id=1306600716]
|
||||||
script = ExtResource("1_gt1sn")
|
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,9 @@
|
||||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_uwrxv"]
|
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_uwrxv"]
|
||||||
|
|
||||||
[node name="Player" type="CharacterBody3D" unique_id=1391068938]
|
[node name="Player" type="CharacterBody3D" unique_id=1391068938]
|
||||||
|
transform = Transform3D(-1, 0, 1.2246467991473532e-16, 0, 1, 0, -1.2246467991473532e-16, 0, -1, 0, 0, 0)
|
||||||
script = ExtResource("1_74mkb")
|
script = ExtResource("1_74mkb")
|
||||||
SprintMultiplier = 500.0
|
SprintMultiplier = 5.0
|
||||||
|
|
||||||
[node name="Camera" type="Camera3D" parent="." unique_id=1639995310]
|
[node name="Camera" type="Camera3D" parent="." unique_id=1639995310]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.6, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.6, 0)
|
||||||
|
|
@ -28,4 +29,5 @@ script = ExtResource("2_y1ton")
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.06334634196567002, -0.29036251889898157)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.06334634196567002, -0.29036251889898157)
|
||||||
shadow_enabled = true
|
shadow_enabled = true
|
||||||
spot_range = 25.0
|
spot_range = 25.0
|
||||||
spot_angle = 90.0
|
spot_angle = 85.0
|
||||||
|
spot_angle_attenuation = 0.73204285
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@
|
||||||
[ext_resource type="Script" uid="uid://n557xfrv0i6x" path="res://scripts/GameControlManager.cs" id="4_lbhrr"]
|
[ext_resource type="Script" uid="uid://n557xfrv0i6x" path="res://scripts/GameControlManager.cs" id="4_lbhrr"]
|
||||||
[ext_resource type="Script" uid="uid://bwgjvm21oi3d6" path="res://scripts/GameManager.cs" id="4_p57ef"]
|
[ext_resource type="Script" uid="uid://bwgjvm21oi3d6" path="res://scripts/GameManager.cs" id="4_p57ef"]
|
||||||
[ext_resource type="Script" uid="uid://betypbypf6bf2" path="res://scripts/GameMenuController.cs" id="5_iywne"]
|
[ext_resource type="Script" uid="uid://betypbypf6bf2" path="res://scripts/GameMenuController.cs" id="5_iywne"]
|
||||||
|
[ext_resource type="Script" uid="uid://bo57chobyuegg" path="res://scripts/NetworkManager.cs" id="5_p57ef"]
|
||||||
|
[ext_resource type="Script" uid="uid://by0357lop0qge" path="res://scripts/RPCNode.cs" id="6_u5sy4"]
|
||||||
|
|
||||||
[sub_resource type="BoxMesh" id="BoxMesh_p57ef"]
|
[sub_resource type="BoxMesh" id="BoxMesh_p57ef"]
|
||||||
size = Vector3(2, 0.1, 2)
|
size = Vector3(2, 0.1, 2)
|
||||||
|
|
@ -15,31 +17,37 @@ size = Vector3(10, 0.5, 10)
|
||||||
[sub_resource type="BoxShape3D" id="BoxShape3D_uwrxv"]
|
[sub_resource type="BoxShape3D" id="BoxShape3D_uwrxv"]
|
||||||
size = Vector3(10, 5, 10)
|
size = Vector3(10, 5, 10)
|
||||||
|
|
||||||
[node name="Game" type="Node3D" unique_id=1201210338 node_paths=PackedStringArray("GameMenu", "QueueManager")]
|
[node name="Game" type="Node3D" unique_id=1201210338 node_paths=PackedStringArray("GameMenu", "QueueManager", "SpaceRoot")]
|
||||||
script = ExtResource("4_p57ef")
|
script = ExtResource("4_p57ef")
|
||||||
GameMenu = NodePath("GameMenu")
|
GameMenu = NodePath("GameMenu")
|
||||||
QueueManager = NodePath("QueueManager")
|
QueueManager = NodePath("QueueManager")
|
||||||
closeTickInterval = 0.01
|
SpaceRoot = NodePath("Space")
|
||||||
|
closeTickInterval = 0.1
|
||||||
|
|
||||||
[node name="Plane" type="StaticBody3D" parent="." unique_id=1260154250]
|
[node name="Space" type="Node3D" parent="." unique_id=1006247987]
|
||||||
|
|
||||||
|
[node name="Plane" type="StaticBody3D" parent="Space" unique_id=1260154250]
|
||||||
transform = Transform3D(1, 0, 0, 0, 0.99999994, 0, 0, 0, 0.99999994, 0, -10, 0)
|
transform = Transform3D(1, 0, 0, 0, 0.99999994, 0, 0, 0, 0.99999994, 0, -10, 0)
|
||||||
|
|
||||||
[node name="PlaneMesh" type="MeshInstance3D" parent="Plane" unique_id=107049489]
|
[node name="PlaneMesh" type="MeshInstance3D" parent="Space/Plane" unique_id=107049489]
|
||||||
transform = Transform3D(5, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0)
|
transform = Transform3D(5, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0)
|
||||||
mesh = SubResource("BoxMesh_p57ef")
|
mesh = SubResource("BoxMesh_p57ef")
|
||||||
|
|
||||||
[node name="PlaneCollider" type="CollisionShape3D" parent="Plane" unique_id=970373853]
|
[node name="PlaneCollider" type="CollisionShape3D" parent="Space/Plane" unique_id=970373853]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.2, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.2, 0)
|
||||||
shape = SubResource("BoxShape3D_8cj0n")
|
shape = SubResource("BoxShape3D_8cj0n")
|
||||||
|
|
||||||
[node name="GravityZone" type="Area3D" parent="Plane" unique_id=1326543003]
|
[node name="GravityZone" type="Area3D" parent="Space/Plane" unique_id=1326543003]
|
||||||
gravity_space_override = 2
|
gravity_space_override = 2
|
||||||
script = ExtResource("1_yqjtg")
|
script = ExtResource("1_yqjtg")
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="Plane/GravityZone" unique_id=772916098]
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="Space/Plane/GravityZone" unique_id=772916098]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.5, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.5, 0)
|
||||||
shape = SubResource("BoxShape3D_uwrxv")
|
shape = SubResource("BoxShape3D_uwrxv")
|
||||||
|
|
||||||
|
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="Space/Plane" unique_id=226559047]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1.0000000600000036, 0, 0, 0, 1.0000000600000036, 0, 10.000000600000035, 0)
|
||||||
|
|
||||||
[node name="GameControlManager" type="Node" parent="." unique_id=1751385863 node_paths=PackedStringArray("GameMenu")]
|
[node name="GameControlManager" type="Node" parent="." unique_id=1751385863 node_paths=PackedStringArray("GameMenu")]
|
||||||
script = ExtResource("4_lbhrr")
|
script = ExtResource("4_lbhrr")
|
||||||
GameMenu = NodePath("../GameMenu")
|
GameMenu = NodePath("../GameMenu")
|
||||||
|
|
@ -47,6 +55,13 @@ 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_paths=PackedStringArray("RPCNode")]
|
||||||
|
script = ExtResource("5_p57ef")
|
||||||
|
RPCNode = NodePath("../RPC")
|
||||||
|
|
||||||
|
[node name="RPC" type="Node" parent="." unique_id=498537245]
|
||||||
|
script = ExtResource("6_u5sy4")
|
||||||
|
|
||||||
[node name="GameMenu" type="Control" parent="." unique_id=223510406]
|
[node name="GameMenu" type="Control" parent="." unique_id=223510406]
|
||||||
visible = false
|
visible = false
|
||||||
layout_mode = 3
|
layout_mode = 3
|
||||||
|
|
@ -77,8 +92,6 @@ offset_bottom = 63.0
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
text = "Main Menu"
|
text = "Main Menu"
|
||||||
|
|
||||||
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="." unique_id=226559047]
|
[connection signal="body_entered" from="Space/Plane/GravityZone" to="Space/Plane/GravityZone" method="OnBodyEntered"]
|
||||||
|
[connection signal="body_exited" from="Space/Plane/GravityZone" to="Space/Plane/GravityZone" method="OnBodyExited"]
|
||||||
[connection signal="body_entered" from="Plane/GravityZone" to="Plane/GravityZone" method="OnBodyEntered"]
|
|
||||||
[connection signal="body_exited" from="Plane/GravityZone" to="Plane/GravityZone" method="OnBodyExited"]
|
|
||||||
[connection signal="pressed" from="GameMenu/VBoxContainer/MainMenuButton" to="GameMenu" method="OnMainMenu"]
|
[connection signal="pressed" from="GameMenu/VBoxContainer/MainMenuButton" to="GameMenu" method="OnMainMenu"]
|
||||||
|
|
|
||||||
|
|
@ -23,13 +23,18 @@ grow_vertical = 2
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
alignment = 1
|
alignment = 1
|
||||||
|
|
||||||
[node name="StartGameButton" type="Button" parent="CenterContainer/VBoxContainer" unique_id=364461644]
|
[node name="HostGameButton" type="Button" parent="CenterContainer/VBoxContainer" unique_id=364461644]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
text = "Start Game"
|
text = "Host Game"
|
||||||
|
|
||||||
|
[node name="JoinGameButton" type="Button" parent="CenterContainer/VBoxContainer" unique_id=1719078976]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Join Game"
|
||||||
|
|
||||||
[node name="ExitGameButton" type="Button" parent="CenterContainer/VBoxContainer" unique_id=1050417063]
|
[node name="ExitGameButton" type="Button" parent="CenterContainer/VBoxContainer" unique_id=1050417063]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
text = "Exit Game"
|
text = "Exit Game"
|
||||||
|
|
||||||
[connection signal="pressed" from="CenterContainer/VBoxContainer/StartGameButton" to="." method="OnStartGame"]
|
[connection signal="pressed" from="CenterContainer/VBoxContainer/HostGameButton" to="." method="OnHostGame"]
|
||||||
|
[connection signal="pressed" from="CenterContainer/VBoxContainer/JoinGameButton" to="." method="OnJoinGame"]
|
||||||
[connection signal="pressed" from="CenterContainer/VBoxContainer/ExitGameButton" to="." method="OnExitGame"]
|
[connection signal="pressed" from="CenterContainer/VBoxContainer/ExitGameButton" to="." method="OnExitGame"]
|
||||||
|
|
|
||||||
|
|
@ -9,22 +9,24 @@ public partial class GameManager : Node3D
|
||||||
{
|
{
|
||||||
[Export] public Control GameMenu { get; private set; }
|
[Export] public Control GameMenu { get; private set; }
|
||||||
[Export] public QueueManager QueueManager { 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 closeTickInterval = 1;
|
||||||
[Export] public double farTickInterval = 10;
|
[Export] public double farTickInterval = 10;
|
||||||
[Export] public int maxFarThreads = 16;
|
[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 static GameManager Singleton { get; private set; }
|
||||||
public IGenerator Generator { get; private set; }
|
public static IGenerator Generator { get; private set; }
|
||||||
|
public static Universe GameUniverse { get; private set; }
|
||||||
public Universe GameUniverse { get; private set; }
|
public Player MainPlayer { 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 simulating = false;
|
public bool simulating = 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 = [];
|
||||||
|
|
@ -34,19 +36,33 @@ public partial class GameManager : Node3D
|
||||||
Singleton = this;
|
Singleton = this;
|
||||||
|
|
||||||
Generator = new TestGenerator();
|
Generator = new TestGenerator();
|
||||||
GameUniverse = Generator.GenerateUniverse();
|
|
||||||
|
|
||||||
Character character = new(GameUniverse.Sectors[50, 50, 50], new(0, 0, 0));
|
if (Global.IsGameHost)
|
||||||
MainPlayer = character.InstantiatePlayer();
|
{
|
||||||
MainPlayer.GameMenu = GameMenu;
|
GameUniverse = Generator.GenerateUniverse();
|
||||||
spawnedObjects.Add(character, MainPlayer);
|
Loading = false;
|
||||||
CallDeferred("add_child", MainPlayer);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPlayerReady()
|
||||||
|
{
|
||||||
|
playerReady = true;
|
||||||
SpawnClose();
|
SpawnClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void _ExitTree()
|
||||||
|
{
|
||||||
|
Loading = true;
|
||||||
|
Singleton = null;
|
||||||
|
}
|
||||||
|
|
||||||
public override void _Process(double delta)
|
public override void _Process(double delta)
|
||||||
{
|
{
|
||||||
|
if (!playerReady || !Global.IsGameHost)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
closeTickTimer += delta;
|
closeTickTimer += delta;
|
||||||
farTickTimer += delta;
|
farTickTimer += delta;
|
||||||
|
|
||||||
|
|
@ -143,7 +159,6 @@ public partial class GameManager : Node3D
|
||||||
|
|
||||||
for (int x = startX; x < endX; x++)
|
for (int x = startX; x < endX; x++)
|
||||||
{
|
{
|
||||||
QueueManager.LogQueue.Enqueue("Simulating: " + x);
|
|
||||||
for (int y = 0; y < sizeY; y++)
|
for (int y = 0; y < sizeY; y++)
|
||||||
{
|
{
|
||||||
Thread.Sleep(5);
|
Thread.Sleep(5);
|
||||||
|
|
@ -180,10 +195,34 @@ public partial class GameManager : Node3D
|
||||||
neighbours.ForEach(sector => sector.SpawnObjects());
|
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)
|
public void Spawn(GameObject gameObject)
|
||||||
{
|
{
|
||||||
spawnQueue.Enqueue(gameObject);
|
spawnQueue.Enqueue(gameObject);
|
||||||
|
|
||||||
CallDeferred(nameof(ProcessSpawnQueue));
|
CallDeferred(nameof(ProcessSpawnQueue));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -202,7 +241,7 @@ public partial class GameManager : Node3D
|
||||||
Node3D instance = gameObject.Instantiate(GetCurrentSector());
|
Node3D instance = gameObject.Instantiate(GetCurrentSector());
|
||||||
spawnedObjects.Add(gameObject, instance);
|
spawnedObjects.Add(gameObject, instance);
|
||||||
|
|
||||||
CallDeferred("add_child", instance);
|
SpaceRoot.CallDeferred("add_child", instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Despawn(GameObject gameObject)
|
public void Despawn(GameObject gameObject)
|
||||||
|
|
@ -215,7 +254,7 @@ public partial class GameManager : Node3D
|
||||||
Node3D nodeToDespawn = spawnedObjects.GetValueOrDefault(gameObject);
|
Node3D nodeToDespawn = spawnedObjects.GetValueOrDefault(gameObject);
|
||||||
spawnedObjects.Remove(gameObject);
|
spawnedObjects.Remove(gameObject);
|
||||||
|
|
||||||
CallDeferred("remove_child", nodeToDespawn);
|
SpaceRoot.CallDeferred("remove_child", nodeToDespawn);
|
||||||
nodeToDespawn.CallDeferred("queue_free");
|
nodeToDespawn.CallDeferred("queue_free");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -223,24 +262,136 @@ public partial class GameManager : Node3D
|
||||||
{
|
{
|
||||||
Sector current = GetCurrentSector();
|
Sector current = GetCurrentSector();
|
||||||
|
|
||||||
List<Sector> nearby = current.GetNeighbouringSectors();
|
foreach (Player player in Players)
|
||||||
|
|
||||||
foreach (Sector sector in nearby)
|
|
||||||
{
|
{
|
||||||
foreach (GameObject gameObject in sector.GameObjects)
|
player.PlayerData.UpdateSectorOffset(current);
|
||||||
{
|
player.PlayerData.UpdateNodePosition();
|
||||||
gameObject.UpdateSectorOffset(current);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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());
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,157 +1,160 @@
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
public abstract class GameObject
|
public abstract class GameObject
|
||||||
{
|
{
|
||||||
public Sector CurrentSector { get; protected set; }
|
public Guid UUID { get; set; }
|
||||||
public Vector3 LocalCoordinates { get; protected set; }
|
|
||||||
public Vector3Dec GlobalCoordinates { get; protected set; }
|
|
||||||
|
|
||||||
public Vector3 SectorOffset { get; set; }
|
public Sector CurrentSector { get; protected set; }
|
||||||
|
public Vector3 LocalCoordinates { get; protected set; }
|
||||||
|
public Vector3Dec GlobalCoordinates { get; protected set; }
|
||||||
|
|
||||||
private bool reassigning = false;
|
public Vector3 SectorOffset { get; set; }
|
||||||
|
|
||||||
public GameObject(Sector sector, Vector3 localCoordinates)
|
protected bool reassigning = false;
|
||||||
{
|
|
||||||
CurrentSector = sector;
|
|
||||||
LocalCoordinates = localCoordinates;
|
|
||||||
|
|
||||||
GlobalCoordinates = new
|
public GameObject(Sector sector, Vector3 localCoordinates)
|
||||||
(
|
{
|
||||||
sector.GlobalCenterCoordinates.X + (decimal)localCoordinates.X,
|
UUID = Guid.NewGuid();
|
||||||
sector.GlobalCenterCoordinates.Y + (decimal)localCoordinates.Y,
|
|
||||||
sector.GlobalCenterCoordinates.Z + (decimal)localCoordinates.Z
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public GameObject(Sector sector, double localX, double localY, double localZ)
|
CurrentSector = sector;
|
||||||
{
|
LocalCoordinates = localCoordinates;
|
||||||
CurrentSector = sector;
|
|
||||||
LocalCoordinates = new(localX, localY, localZ);
|
|
||||||
|
|
||||||
GlobalCoordinates = new
|
GlobalCoordinates = CalculateGlobalCoordinates(sector.GlobalCenterCoordinates, localCoordinates);
|
||||||
(
|
}
|
||||||
sector.GlobalStartCoordinates.X + (decimal)localX,
|
|
||||||
sector.GlobalStartCoordinates.Y + (decimal)localY,
|
|
||||||
sector.GlobalStartCoordinates.Z + (decimal)localZ
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public GameObject(Vector3Dec coordinates)
|
public GameObject(Vector3Dec coordinates)
|
||||||
{
|
{
|
||||||
GlobalCoordinates = coordinates;
|
GlobalCoordinates = coordinates;
|
||||||
UpdateSector();
|
UpdateSector();
|
||||||
}
|
}
|
||||||
|
|
||||||
public GameObject(decimal x, decimal y, decimal z)
|
public GameObject(decimal x, decimal y, decimal z)
|
||||||
{
|
{
|
||||||
GlobalCoordinates = new(x, y, z);
|
GlobalCoordinates = new(x, y, z);
|
||||||
UpdateSector();
|
UpdateSector();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsInCurrentSector()
|
public Vector3Dec CalculateGlobalCoordinates(Vector3Dec sectorCenter, Vector3 local)
|
||||||
{
|
{
|
||||||
return Helpers.IsInsideArea(CurrentSector.Size / 2, LocalCoordinates);
|
return new
|
||||||
}
|
(
|
||||||
|
sectorCenter.X + (decimal)local.X,
|
||||||
|
sectorCenter.Y + (decimal)local.Y,
|
||||||
|
sectorCenter.Z + (decimal)local.Z
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public void UpdateSector()
|
public bool IsInCurrentSector()
|
||||||
{
|
{
|
||||||
List<Sector> neighbours = CurrentSector.GetNeighbouringSectors();
|
return Helpers.IsInsideArea(CurrentSector.Size / 2, LocalCoordinates);
|
||||||
foreach (Sector sector in neighbours)
|
}
|
||||||
{
|
|
||||||
if (sector.IsObjectInSector(this))
|
|
||||||
{
|
|
||||||
sector.AssignObject(this);
|
|
||||||
reassigning = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (Sector sector in GameManager.Singleton.GameUniverse.Sectors)
|
public void UpdateSector()
|
||||||
{
|
{
|
||||||
if (sector.IsObjectInSector(this))
|
List<Sector> neighbours = CurrentSector.GetNeighbouringSectors();
|
||||||
{
|
foreach (Sector sector in neighbours)
|
||||||
sector.AssignObject(this);
|
{
|
||||||
reassigning = true;
|
if (sector.IsObjectInSector(this))
|
||||||
return;
|
{
|
||||||
}
|
reassigning = true;
|
||||||
}
|
sector.AssignObject(this);
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void AssignSector(Sector sector)
|
if (!GameManager.GameUniverse.IsInside(CurrentSector.Coordinates, LocalCoordinates))
|
||||||
{
|
{
|
||||||
CurrentSector = sector;
|
return;
|
||||||
ResetLocalCoordinates();
|
}
|
||||||
|
|
||||||
SectorOffset = GetSectorOffset(GameManager.Singleton.GetCurrentSector());
|
foreach (Sector sector in GameManager.GameUniverse.Sectors)
|
||||||
|
{
|
||||||
|
if (sector.IsObjectInSector(this))
|
||||||
|
{
|
||||||
|
reassigning = true;
|
||||||
|
sector.AssignObject(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (this is Character)
|
public virtual void AssignSector(Sector sector)
|
||||||
{
|
{
|
||||||
GameManager.Singleton.ApplyOrigin();
|
CurrentSector = sector;
|
||||||
}
|
ResetLocalCoordinates();
|
||||||
|
|
||||||
if (this is not Character)
|
UpdateSectorOffsetToMainPlayer();
|
||||||
{
|
|
||||||
List<Sector> neighbours = GameManager.Singleton.GetCurrentSector().GetNeighbouringSectors();
|
|
||||||
|
|
||||||
if (neighbours.Contains(sector))
|
List<Sector> neighbours = GameManager.Singleton.GetCurrentSector().GetNeighbouringSectors();
|
||||||
{
|
|
||||||
GameManager.Singleton.Spawn(this);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GameManager.Singleton.Despawn(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
reassigning = false;
|
if (neighbours.Contains(sector))
|
||||||
}
|
{
|
||||||
|
GameManager.Singleton.Spawn(this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GameManager.Singleton.Despawn(this);
|
||||||
|
}
|
||||||
|
|
||||||
public Vector3 GetSectorOffset(Sector sector)
|
reassigning = false;
|
||||||
{
|
}
|
||||||
Vector3Dec relative = CurrentSector.GlobalCenterCoordinates - sector.GlobalCenterCoordinates;
|
|
||||||
return relative.ToVector3();
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void UpdateSectorOffset(Sector sector)
|
public Vector3 GetSectorOffset(Sector sector)
|
||||||
{
|
{
|
||||||
SectorOffset = GetSectorOffset(sector);
|
Vector3Dec relative = CurrentSector.GlobalCenterCoordinates - sector.GlobalCenterCoordinates;
|
||||||
}
|
return relative.ToVector3();
|
||||||
|
}
|
||||||
|
|
||||||
public void SetCoordinatesFromGlobal(Vector3Dec globalCoordinates)
|
public void UpdateSectorOffset(Sector sector)
|
||||||
{
|
{
|
||||||
GlobalCoordinates = globalCoordinates;
|
SectorOffset = GetSectorOffset(sector);
|
||||||
LocalCoordinates = (globalCoordinates - CurrentSector.GlobalCenterCoordinates).ToVector3();
|
}
|
||||||
|
|
||||||
UpdateNodePosition();
|
public void UpdateSectorOffsetToMainPlayer()
|
||||||
}
|
{
|
||||||
|
UpdateSectorOffset(GameManager.Singleton.GetCurrentSector());
|
||||||
|
}
|
||||||
|
|
||||||
public void SetCoordinatesFromLocal(Vector3 localCoordinates)
|
public void SetCoordinatesFromGlobal(Vector3Dec globalCoordinates)
|
||||||
{
|
{
|
||||||
LocalCoordinates = localCoordinates;
|
GlobalCoordinates = globalCoordinates;
|
||||||
GlobalCoordinates = Vector3Dec.FromVector3(localCoordinates) + CurrentSector.GlobalCenterCoordinates;
|
LocalCoordinates = (globalCoordinates - CurrentSector.GlobalCenterCoordinates).ToVector3();
|
||||||
|
|
||||||
UpdateNodePosition();
|
UpdateNodePosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResetLocalCoordinates()
|
public void SetCoordinatesFromLocal(Vector3 localCoordinates)
|
||||||
{
|
{
|
||||||
SetCoordinatesFromGlobal(GlobalCoordinates);
|
LocalCoordinates = localCoordinates;
|
||||||
}
|
GlobalCoordinates = Vector3Dec.FromVector3(localCoordinates) + CurrentSector.GlobalCenterCoordinates;
|
||||||
|
|
||||||
public virtual void UpdateNodePosition() { }
|
UpdateNodePosition();
|
||||||
|
}
|
||||||
|
|
||||||
public virtual void Simulate(double delta)
|
public void ResetLocalCoordinates()
|
||||||
{
|
{
|
||||||
if (!reassigning && !IsInCurrentSector())
|
SetCoordinatesFromGlobal(GlobalCoordinates);
|
||||||
{
|
}
|
||||||
UpdateSector();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual Node3D Instantiate(Sector sector)
|
public virtual void UpdateNodePosition() { }
|
||||||
{
|
|
||||||
PackedScene modulePrefab = ResourceLoader.Load<PackedScene>("res://prefabs/gameObjects/node.tscn");
|
public virtual void Simulate(double delta)
|
||||||
return modulePrefab.Instantiate<Node3D>();
|
{
|
||||||
}
|
if (!reassigning && !IsInCurrentSector())
|
||||||
|
{
|
||||||
|
UpdateSector();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual Node3D Instantiate(Sector sector)
|
||||||
|
{
|
||||||
|
PackedScene modulePrefab = ResourceLoader.Load<PackedScene>("res://prefabs/gameObjects/node.tscn");
|
||||||
|
Node3D instance = modulePrefab.Instantiate<Node3D>();
|
||||||
|
|
||||||
|
instance.Name = $"GameObject-{UUID}";
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,39 @@ public class Character(Sector sector, Vector3 localCoordinates) : GameObject(sec
|
||||||
{
|
{
|
||||||
private Player player;
|
private Player player;
|
||||||
|
|
||||||
|
public bool SheduledUpdateNode = false;
|
||||||
|
|
||||||
|
public override void AssignSector(Sector sector)
|
||||||
|
{
|
||||||
|
CurrentSector = sector;
|
||||||
|
|
||||||
|
ResetLocalCoordinates();
|
||||||
|
UpdateSectorOffsetToMainPlayer();
|
||||||
|
UpdateNodePosition();
|
||||||
|
|
||||||
|
if (IsMainPlayer())
|
||||||
|
{
|
||||||
|
GameManager.Singleton.ApplyOrigin();
|
||||||
|
|
||||||
|
if (!Global.IsGameHost)
|
||||||
|
{
|
||||||
|
GameManager.Singleton.RpcId(
|
||||||
|
1,
|
||||||
|
nameof(GameManager.Singleton.RpcSendNearbySectors),
|
||||||
|
CurrentSector.Coordinates,
|
||||||
|
NetworkManager.Singleton.LocalNetId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reassigning = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsMainPlayer()
|
||||||
|
{
|
||||||
|
return player == GameManager.Singleton.MainPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
public Player InstantiatePlayer()
|
public Player InstantiatePlayer()
|
||||||
{
|
{
|
||||||
PackedScene prefab = ResourceLoader.Load<PackedScene>("res://prefabs/gameObjects/player.tscn");
|
PackedScene prefab = ResourceLoader.Load<PackedScene>("res://prefabs/gameObjects/player.tscn");
|
||||||
|
|
@ -17,6 +50,13 @@ public class Character(Sector sector, Vector3 localCoordinates) : GameObject(sec
|
||||||
|
|
||||||
public override void UpdateNodePosition()
|
public override void UpdateNodePosition()
|
||||||
{
|
{
|
||||||
player.GlobalPosition = LocalCoordinates;
|
if (IsMainPlayer())
|
||||||
|
{
|
||||||
|
player.GlobalPosition = LocalCoordinates;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
player.GlobalPosition = LocalCoordinates + SectorOffset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ public class Star(Sector sector, Vector3 localCoordinates) : GameObject(sector,
|
||||||
{
|
{
|
||||||
base.Simulate(delta);
|
base.Simulate(delta);
|
||||||
|
|
||||||
SetCoordinatesFromGlobal(new(GlobalCoordinates.X, GlobalCoordinates.Y, GlobalCoordinates.Z + 1 * (decimal)delta));
|
//SetCoordinatesFromGlobal(new(GlobalCoordinates.X, GlobalCoordinates.Y, GlobalCoordinates.Z + 1 * (decimal)delta));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Node3D Instantiate(Sector sector)
|
public override Node3D Instantiate(Sector sector)
|
||||||
|
|
@ -14,8 +14,9 @@ public class Star(Sector sector, Vector3 localCoordinates) : GameObject(sector,
|
||||||
PackedScene prefab = ResourceLoader.Load<PackedScene>("res://prefabs/gameObjects/star.tscn");
|
PackedScene prefab = ResourceLoader.Load<PackedScene>("res://prefabs/gameObjects/star.tscn");
|
||||||
StarNode instance = prefab.Instantiate<StarNode>();
|
StarNode instance = prefab.Instantiate<StarNode>();
|
||||||
|
|
||||||
|
instance.Name = $"Star-{UUID}";
|
||||||
instance.StarData = this;
|
instance.StarData = this;
|
||||||
SectorOffset = GetSectorOffset(sector);
|
UpdateSectorOffsetToMainPlayer();
|
||||||
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
using System;
|
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
public interface IGenerator
|
public interface IGenerator
|
||||||
|
|
@ -6,6 +5,7 @@ public interface IGenerator
|
||||||
public Vector3I GetUniverseSize();
|
public Vector3I GetUniverseSize();
|
||||||
public Vector3 GetSectorSize();
|
public Vector3 GetSectorSize();
|
||||||
|
|
||||||
|
public Universe InitializeEmptyUniverse(Vector3I universeSize, Vector3 sectorSize);
|
||||||
public Universe GenerateUniverse();
|
public Universe GenerateUniverse();
|
||||||
public Sector GenerateSector(Vector3I coordinates);
|
public Sector GenerateSector(Vector3I coordinates);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,10 @@ using Godot;
|
||||||
|
|
||||||
public class TestGenerator : IGenerator
|
public class TestGenerator : IGenerator
|
||||||
{
|
{
|
||||||
public static Vector3I UNIVERSE_SIZE = new(100, 100, 100);
|
public static Vector3I UNIVERSE_SIZE = new(10, 10, 10);
|
||||||
public static Vector3 SECTOR_SIZE = new(5000, 5000, 5000);
|
public static Vector3 SECTOR_SIZE = new(50, 50, 50);
|
||||||
public static int STARS_PER_SECTOR = 100;
|
public static int STARS_PER_SECTOR = 1;
|
||||||
public static int STARS_PER_SECTOR_VARIANCE = 5;
|
public static int STARS_PER_SECTOR_VARIANCE = 0;
|
||||||
public static int SHIPS_PER_SECTOR = 0;
|
public static int SHIPS_PER_SECTOR = 0;
|
||||||
public static int SHIPS_PER_SECTOR_VARIANCE = 0;
|
public static int SHIPS_PER_SECTOR_VARIANCE = 0;
|
||||||
public static int STATIONS_PER_SECTOR = 0;
|
public static int STATIONS_PER_SECTOR = 0;
|
||||||
|
|
@ -22,7 +22,12 @@ public class TestGenerator : IGenerator
|
||||||
return UNIVERSE_SIZE;
|
return UNIVERSE_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3I GetSectorOffset()
|
public Vector3 GetSectorSize()
|
||||||
|
{
|
||||||
|
return SECTOR_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3I GetSectorOffset(Vector3I universeSize)
|
||||||
{
|
{
|
||||||
return new(
|
return new(
|
||||||
(int)Mathf.Floor(UNIVERSE_SIZE.X / 2),
|
(int)Mathf.Floor(UNIVERSE_SIZE.X / 2),
|
||||||
|
|
@ -31,9 +36,31 @@ public class TestGenerator : IGenerator
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3 GetSectorSize()
|
public Vector3I GetSectorOffset()
|
||||||
{
|
{
|
||||||
return SECTOR_SIZE;
|
return GetSectorOffset(UNIVERSE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Universe InitializeEmptyUniverse(Vector3I universeSize, Vector3 sectorSize)
|
||||||
|
{
|
||||||
|
Universe universe = new(universeSize);
|
||||||
|
|
||||||
|
for (int x = 0; x < universeSize.X; x++)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < universeSize.Y; y++)
|
||||||
|
{
|
||||||
|
for (int z = 0; z < universeSize.Z; z++)
|
||||||
|
{
|
||||||
|
universe.Sectors[x, y, z] = new Sector(
|
||||||
|
new(x, y, z),
|
||||||
|
GetSectorOffset(universeSize),
|
||||||
|
sectorSize
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return universe;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Universe GenerateUniverse()
|
public Universe GenerateUniverse()
|
||||||
|
|
|
||||||
4
scripts/Global.cs
Normal file
4
scripts/Global.cs
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
public static class Global
|
||||||
|
{
|
||||||
|
public static bool IsGameHost = false;
|
||||||
|
}
|
||||||
1
scripts/Global.cs.uid
Normal file
1
scripts/Global.cs.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://dufeaph62nh7y
|
||||||
|
|
@ -16,7 +16,7 @@ public partial class GravityReceiver : Node3D
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
owner = GetParent<Node3D>();
|
owner = GetParent<Node3D>();
|
||||||
root = GetTree().Root.GetNode<Node3D>("Game");
|
root = GetTree().Root.GetNode<Node3D>("Game/Space");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _PhysicsProcess(double delta)
|
public override void _PhysicsProcess(double delta)
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,11 @@ public static class Helpers
|
||||||
return value >= min && value <= max;
|
return value >= min && value <= max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool IsBetween(double value, double min, int max)
|
||||||
|
{
|
||||||
|
return value >= min && value < max;
|
||||||
|
}
|
||||||
|
|
||||||
public static bool IsInsideArea(Vector3 area, Vector3 coordinates)
|
public static bool IsInsideArea(Vector3 area, Vector3 coordinates)
|
||||||
{
|
{
|
||||||
if (coordinates.X >= area.X || coordinates.Y >= area.Y || coordinates.Z >= area.Z)
|
if (coordinates.X >= area.X || coordinates.Y >= area.Y || coordinates.Z >= area.Z)
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,17 @@ using Godot;
|
||||||
|
|
||||||
public partial class MainMenuController : Node
|
public partial class MainMenuController : Node
|
||||||
{
|
{
|
||||||
public void OnStartGame()
|
public void OnHostGame()
|
||||||
{
|
{
|
||||||
|
Global.IsGameHost = true;
|
||||||
|
|
||||||
|
GetTree().ChangeSceneToFile("res://scenes/game.tscn");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnJoinGame()
|
||||||
|
{
|
||||||
|
Global.IsGameHost = false;
|
||||||
|
|
||||||
GetTree().ChangeSceneToFile("res://scenes/game.tscn");
|
GetTree().ChangeSceneToFile("res://scenes/game.tscn");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
101
scripts/NetworkManager.cs
Normal file
101
scripts/NetworkManager.cs
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
public partial class NetworkManager : Node
|
||||||
|
{
|
||||||
|
[Export] public RPCNode RPCNode { get; private set; }
|
||||||
|
|
||||||
|
public static NetworkManager Singleton { get; private set; }
|
||||||
|
|
||||||
|
public int LocalNetId { get; private set; } = -1;
|
||||||
|
|
||||||
|
public override void _Ready()
|
||||||
|
{
|
||||||
|
Singleton = this;
|
||||||
|
|
||||||
|
if (Global.IsGameHost)
|
||||||
|
{
|
||||||
|
CreateServer();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CreateClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
GetTree().GetMultiplayer().PeerConnected += OnPlayerConnected;
|
||||||
|
GetTree().GetMultiplayer().PeerDisconnected += OnPlayerDisconnected;
|
||||||
|
GetTree().GetMultiplayer().ServerDisconnected += OnServerClosed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void _ExitTree()
|
||||||
|
{
|
||||||
|
GetTree().GetMultiplayer().MultiplayerPeer.Close();
|
||||||
|
GetTree().GetMultiplayer().MultiplayerPeer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CreateServer()
|
||||||
|
{
|
||||||
|
ENetMultiplayerPeer peer = new();
|
||||||
|
peer.CreateServer(2142, 128);
|
||||||
|
|
||||||
|
GetTree().GetMultiplayer().MultiplayerPeer = peer;
|
||||||
|
|
||||||
|
LocalNetId = GetTree().GetMultiplayer().GetUniqueId();
|
||||||
|
|
||||||
|
_ = SpawnNetPlayer(LocalNetId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CreateClient()
|
||||||
|
{
|
||||||
|
ENetMultiplayerPeer peer = new();
|
||||||
|
peer.CreateClient("127.0.0.1", 2142);
|
||||||
|
|
||||||
|
GetTree().GetMultiplayer().MultiplayerPeer = peer;
|
||||||
|
|
||||||
|
LocalNetId = GetTree().GetMultiplayer().GetUniqueId();
|
||||||
|
|
||||||
|
_ = SpawnNetPlayer(LocalNetId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnServerClosed()
|
||||||
|
{
|
||||||
|
GetTree().ChangeSceneToFile("res://scenes/main_menu.tscn");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnPlayerConnected(long id)
|
||||||
|
{
|
||||||
|
if (Global.IsGameHost)
|
||||||
|
{
|
||||||
|
GameManager.Singleton.SendUniverseToClient(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = SpawnNetPlayer(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnPlayerDisconnected(long id)
|
||||||
|
{
|
||||||
|
Player player = GetNode<Player>($"/root/Game/Space/Player-{id}");
|
||||||
|
GameManager.Singleton.DespawnPlayer(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SpawnNetPlayer(long id)
|
||||||
|
{
|
||||||
|
while (GameManager.Loading)
|
||||||
|
{
|
||||||
|
await Task.Delay(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isMainPlayer = LocalNetId == id;
|
||||||
|
|
||||||
|
Character character = new(GameManager.GameUniverse.Sectors[5, 5, 5], new(0, 0, 0));
|
||||||
|
Player player = GameManager.Singleton.SpawnPlayer(character, isMainPlayer);
|
||||||
|
player.Name = $"Player-{id}";
|
||||||
|
|
||||||
|
player.SetMultiplayerAuthority((int)id);
|
||||||
|
|
||||||
|
if (isMainPlayer && !Global.IsGameHost)
|
||||||
|
{
|
||||||
|
GameManager.Singleton.RpcId(1, nameof(GameManager.Singleton.RpcSendNearbySectors), character.CurrentSector.Coordinates, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1
scripts/NetworkManager.cs.uid
Normal file
1
scripts/NetworkManager.cs.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://bo57chobyuegg
|
||||||
|
|
@ -2,11 +2,12 @@ using Godot;
|
||||||
|
|
||||||
public partial class Player : CharacterBody3D
|
public partial class Player : CharacterBody3D
|
||||||
{
|
{
|
||||||
|
|
||||||
[Export] public double Speed = 5;
|
[Export] public double Speed = 5;
|
||||||
[Export] public double SprintMultiplier = 2;
|
[Export] public double SprintMultiplier = 2;
|
||||||
[Export] public double JumpForce = 5;
|
[Export] public double JumpForce = 5;
|
||||||
[Export] public double MouseSensitivity = 0.2;
|
[Export] public double MouseSensitivity = 0.2;
|
||||||
|
[Export] public double NetworkSyncInterval = 0.2;
|
||||||
|
[Export] public double NetworkPhysicsSyncInterval = 0.05;
|
||||||
|
|
||||||
public Control GameMenu { get; set; }
|
public Control GameMenu { get; set; }
|
||||||
|
|
||||||
|
|
@ -14,13 +15,17 @@ public partial class Player : CharacterBody3D
|
||||||
|
|
||||||
private Vector3 gravityVelocity = Vector3.Zero;
|
private Vector3 gravityVelocity = Vector3.Zero;
|
||||||
private Vector3 movementVelocity = Vector3.Zero;
|
private Vector3 movementVelocity = Vector3.Zero;
|
||||||
|
private GravityReceiver gravityReceiver;
|
||||||
private double cameraPitch = 0;
|
private double cameraPitch = 0;
|
||||||
private Camera3D camera;
|
private Camera3D camera;
|
||||||
private GravityReceiver gravityReceiver;
|
private double networkSyncCounter = 0;
|
||||||
|
private double networkPhysicsSyncCounter = 0;
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
camera = GetNode<Camera3D>("Camera");
|
camera = GetNode<Camera3D>("Camera");
|
||||||
|
camera.Current = IsMultiplayerAuthority();
|
||||||
|
|
||||||
gravityReceiver = GetNode<GravityReceiver>("GravityReceiver");
|
gravityReceiver = GetNode<GravityReceiver>("GravityReceiver");
|
||||||
|
|
||||||
PlayerData.UpdateNodePosition();
|
PlayerData.UpdateNodePosition();
|
||||||
|
|
@ -28,7 +33,25 @@ public partial class Player : CharacterBody3D
|
||||||
|
|
||||||
public override void _Process(double delta)
|
public override void _Process(double delta)
|
||||||
{
|
{
|
||||||
PlayerData.SetCoordinatesFromLocal(GlobalPosition);
|
if (IsMultiplayerAuthority())
|
||||||
|
{
|
||||||
|
networkPhysicsSyncCounter += delta;
|
||||||
|
if (networkPhysicsSyncCounter >= NetworkPhysicsSyncInterval)
|
||||||
|
{
|
||||||
|
networkPhysicsSyncCounter = 0;
|
||||||
|
Rpc(nameof(RpcSyncPhysics), movementVelocity, gravityVelocity, GlobalRotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
networkSyncCounter += delta;
|
||||||
|
if (networkSyncCounter >= NetworkSyncInterval)
|
||||||
|
{
|
||||||
|
networkSyncCounter = 0;
|
||||||
|
Rpc(nameof(RpcSync), GlobalPosition, PlayerData.CurrentSector.Coordinates);
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerData.SetCoordinatesFromLocal(GlobalPosition);
|
||||||
|
}
|
||||||
|
|
||||||
PlayerData.Simulate(delta);
|
PlayerData.Simulate(delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -37,21 +60,18 @@ public partial class Player : CharacterBody3D
|
||||||
Vector3 newGravityVelocity = gravityVelocity;
|
Vector3 newGravityVelocity = gravityVelocity;
|
||||||
Vector3 newMovementVelocity = movementVelocity;
|
Vector3 newMovementVelocity = movementVelocity;
|
||||||
|
|
||||||
if (IsInGravity())
|
if (!GameMenu.Visible && IsMultiplayerAuthority())
|
||||||
{
|
{
|
||||||
ProcessGravity(delta, ref newGravityVelocity);
|
if (IsInGravity())
|
||||||
if (!GameMenu.Visible)
|
|
||||||
{
|
{
|
||||||
|
ProcessGravity(delta, ref newGravityVelocity);
|
||||||
ProcessControlsGravity(ref newGravityVelocity, ref newMovementVelocity);
|
ProcessControlsGravity(ref newGravityVelocity, ref newMovementVelocity);
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
else
|
|
||||||
{
|
|
||||||
newGravityVelocity = Vector3.Zero;
|
|
||||||
|
|
||||||
ProcessCamera(delta);
|
|
||||||
if (!GameMenu.Visible)
|
|
||||||
{
|
{
|
||||||
|
newGravityVelocity = Vector3.Zero;
|
||||||
|
|
||||||
|
ProcessCamera(delta);
|
||||||
ProcessControls(ref newMovementVelocity);
|
ProcessControls(ref newMovementVelocity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -69,6 +89,10 @@ public partial class Player : CharacterBody3D
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!IsMultiplayerAuthority())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (@event is InputEventMouseMotion motion)
|
if (@event is InputEventMouseMotion motion)
|
||||||
{
|
{
|
||||||
|
|
@ -213,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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,6 @@ public partial class QueueManager : Node
|
||||||
action();
|
action();
|
||||||
}
|
}
|
||||||
|
|
||||||
GD.Print(SectorReassignQueue.Count);
|
|
||||||
|
|
||||||
int sectorReassignQueueProcessed = 0;
|
int sectorReassignQueueProcessed = 0;
|
||||||
while (
|
while (
|
||||||
!GameManager.Singleton.simulating
|
!GameManager.Singleton.simulating
|
||||||
|
|
|
||||||
5
scripts/RPCNode.cs
Normal file
5
scripts/RPCNode.cs
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
public partial class RPCNode : Node
|
||||||
|
{
|
||||||
|
}
|
||||||
1
scripts/RPCNode.cs.uid
Normal file
1
scripts/RPCNode.cs.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://by0357lop0qge
|
||||||
|
|
@ -65,7 +65,7 @@ public class Sector
|
||||||
{
|
{
|
||||||
List<Sector> neighbours = [];
|
List<Sector> neighbours = [];
|
||||||
|
|
||||||
Sector[,,] allSectors = GameManager.Singleton.GameUniverse.Sectors;
|
Sector[,,] allSectors = GameManager.GameUniverse.Sectors;
|
||||||
|
|
||||||
int sizeX = allSectors.GetLength(0);
|
int sizeX = allSectors.GetLength(0);
|
||||||
int sizeY = allSectors.GetLength(1);
|
int sizeY = allSectors.GetLength(1);
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,18 @@ using Godot;
|
||||||
public class Universe
|
public class Universe
|
||||||
{
|
{
|
||||||
public Sector[,,] Sectors;
|
public Sector[,,] Sectors;
|
||||||
|
public Vector3I Size;
|
||||||
|
|
||||||
public Universe(Vector3I size)
|
public Universe(Vector3I size)
|
||||||
{
|
{
|
||||||
Sectors = new Sector[size.X, size.Y, size.Z];
|
Sectors = new Sector[size.X, size.Y, size.Z];
|
||||||
|
Size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Universe(int sizeX, int sizeY, int sizeZ)
|
public Universe(int sizeX, int sizeY, int sizeZ)
|
||||||
{
|
{
|
||||||
Sectors = new Sector[sizeX, sizeY, sizeZ];
|
Sectors = new Sector[sizeX, sizeY, sizeZ];
|
||||||
|
Size = new(sizeX, sizeY, sizeZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Sector GetSector(Vector3I coordinates)
|
public Sector GetSector(Vector3I coordinates)
|
||||||
|
|
@ -25,6 +28,32 @@ public class Universe
|
||||||
return Sectors[x, y, z];
|
return Sectors[x, y, z];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsInside(Vector3I sectorCoordinates, Vector3 localCoordinates)
|
||||||
|
{
|
||||||
|
Vector3 sectorSize = GameManager.Generator.GetSectorSize() / 2;
|
||||||
|
Vector3I universeSize = GameManager.GameUniverse.Size;
|
||||||
|
|
||||||
|
if (
|
||||||
|
sectorCoordinates.X == 0 && localCoordinates.X < -sectorSize.X ||
|
||||||
|
sectorCoordinates.Y == 0 && localCoordinates.Y < -sectorSize.Y ||
|
||||||
|
sectorCoordinates.Z == 0 && localCoordinates.Z < -sectorSize.Z
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
sectorCoordinates.X == universeSize.X - 1 && localCoordinates.X >= sectorSize.X ||
|
||||||
|
sectorCoordinates.Y == universeSize.Y - 1 && localCoordinates.Y >= sectorSize.Y ||
|
||||||
|
sectorCoordinates.Z == universeSize.Z - 1 && localCoordinates.Z >= sectorSize.Z
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public void ForEachSector(Action<Sector> action)
|
public void ForEachSector(Action<Sector> action)
|
||||||
{
|
{
|
||||||
int sizeX = Sectors.GetLength(0);
|
int sizeX = Sectors.GetLength(0);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue