From 94bd99a478e1f9b8f1824800dd8e92b9a3078138 Mon Sep 17 00:00:00 2001 From: copygirl Date: Sun, 9 May 2021 09:41:59 +0200 Subject: [PATCH] Undo weeks of work - Remove DeSerialization, RPC and Sync code - Use Godot's built-in Rpc and Rset methods - Use built-in Multiplayer with Root set to World - Add World class, handles spawning, getting players and blocks - No more custom packets - No more reflection or attributes - Reintroduce LocalPlayer scene - Keep it simple, stupid! --- scene/GameScene.tscn | 12 +- scene/LocalPlayer.tscn | 11 ++ scene/Player.tscn | 3 - src/CreativeBuilding.cs | 70 ++++---- src/EscapeMenuAppearance.cs | 11 +- src/EscapeMenuMultiplayer.cs | 18 +-- src/EscapeMenuWorld.cs | 69 ++++---- src/IO/DeSerializer.Impl.cs | 261 ------------------------------ src/IO/DeSerializer.Interfaces.cs | 53 ------ src/IO/DeSerializerRegistry.cs | 69 -------- src/IO/PropertyDeSerializer.cs | 48 ------ src/IO/Save.cs | 103 ------------ src/IO/SaveRegistry.cs | 69 -------- src/Network/IntegratedServer.cs | 13 +- src/Network/NetworkPackets.cs | 96 ----------- src/Network/NetworkRPC.cs | 205 ----------------------- src/Network/Sync.cs | 153 ------------------ src/Network/SyncClient.cs | 45 ------ src/Network/SyncRegistry.cs | 65 -------- src/Network/SyncServer.cs | 73 --------- src/Objects/Block.cs | 16 +- src/Objects/LocalPlayer.cs | 60 +++++++ src/Objects/ObjectHolder.cs | 77 --------- src/Objects/Player.cs | 121 +++----------- src/Objects/SpawnRegistry.cs | 70 -------- src/Scenes/Client.cs | 58 ++----- src/Scenes/Game.cs | 18 +-- src/Scenes/Server.cs | 119 ++++---------- src/Utility/Extensions.cs | 46 +----- src/World.cs | 92 +++++++++++ 30 files changed, 348 insertions(+), 1776 deletions(-) create mode 100644 scene/LocalPlayer.tscn delete mode 100644 src/IO/DeSerializer.Impl.cs delete mode 100644 src/IO/DeSerializer.Interfaces.cs delete mode 100644 src/IO/DeSerializerRegistry.cs delete mode 100644 src/IO/PropertyDeSerializer.cs delete mode 100644 src/IO/Save.cs delete mode 100644 src/IO/SaveRegistry.cs delete mode 100644 src/Network/NetworkPackets.cs delete mode 100644 src/Network/NetworkRPC.cs delete mode 100644 src/Network/Sync.cs delete mode 100644 src/Network/SyncClient.cs delete mode 100644 src/Network/SyncRegistry.cs delete mode 100644 src/Network/SyncServer.cs create mode 100644 src/Objects/LocalPlayer.cs delete mode 100644 src/Objects/ObjectHolder.cs delete mode 100644 src/Objects/SpawnRegistry.cs create mode 100644 src/World.cs diff --git a/scene/GameScene.tscn b/scene/GameScene.tscn index 97024f3..0a24d21 100644 --- a/scene/GameScene.tscn +++ b/scene/GameScene.tscn @@ -1,9 +1,17 @@ -[gd_scene load_steps=2 format=2] +[gd_scene load_steps=3 format=2] +[ext_resource path="res://src/World.cs" type="Script" id=1] [ext_resource path="res://src/Scenes/Game.cs" type="Script" id=3] -[node name="Game" type="Node2D"] +[node name="Game" type="Node"] pause_mode = 2 script = ExtResource( 3 ) [node name="World" type="Node" parent="."] +script = ExtResource( 1 ) +PlayerContainerPath = NodePath("Players") +BlockContainerPath = NodePath("Blocks") + +[node name="Players" type="Node" parent="World"] + +[node name="Blocks" type="Node" parent="World"] diff --git a/scene/LocalPlayer.tscn b/scene/LocalPlayer.tscn new file mode 100644 index 0000000..9bb3ce7 --- /dev/null +++ b/scene/LocalPlayer.tscn @@ -0,0 +1,11 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://scene/Player.tscn" type="PackedScene" id=1] +[ext_resource path="res://src/Objects/LocalPlayer.cs" type="Script" id=2] + +[node name="LocalPlayer" instance=ExtResource( 1 )] +script = ExtResource( 2 ) + +[node name="Camera" type="Camera2D" parent="." index="0"] +pause_mode = 2 +current = true diff --git a/scene/Player.tscn b/scene/Player.tscn index 692e401..beaeb26 100644 --- a/scene/Player.tscn +++ b/scene/Player.tscn @@ -38,8 +38,5 @@ __meta__ = { z_index = -5 texture = ExtResource( 2 ) -[node name="Camera" type="Camera2D" parent="."] -pause_mode = 2 - [node name="CreativeBuilding" type="Node2D" parent="."] script = ExtResource( 4 ) diff --git a/src/CreativeBuilding.cs b/src/CreativeBuilding.cs index 517cfd7..78bf99b 100644 --- a/src/CreativeBuilding.cs +++ b/src/CreativeBuilding.cs @@ -13,9 +13,11 @@ public class CreativeBuilding : Node2D [Export] public int MaxLength { get; set; } = 6; - private Player _player; private Texture _blockTex; + public Cursor Cursor { get; private set; } + public Player Player { get; private set; } + private BlockPos _startPos; private Facing _direction; private int _length; @@ -25,17 +27,18 @@ public class CreativeBuilding : Node2D public override void _Ready() { - _player = GetParent(); _blockTex = GD.Load("res://gfx/block.png"); + + Cursor = this.GetClient()?.Cursor; + Player = GetParent(); } - public override void _PhysicsProcess(float delta) + public override void _Process(float delta) { - if (!_player.IsLocal) return; - var client = this.GetClient(); + if (!(Player is LocalPlayer)) return; Update(); // Make sure _Draw is being called. - if (EscapeMenu.Instance.Visible || !client.Cursor.Visible) + if (EscapeMenu.Instance.Visible || !Cursor.Visible) { _currentMode = null; return; } switch (_currentMode) { @@ -48,14 +51,14 @@ public class CreativeBuilding : Node2D case BuildMode.Placing: if (Input.IsActionJustPressed("interact_break")) _currentMode = null; else if (!Input.IsActionPressed("interact_place")) { - if (_canBuild) this.GetClient()?.RPC(PlaceLine, _startPos, _direction, _length); + if (_canBuild) RpcId(1, nameof(PlaceLine), _startPos.X, _startPos.Y, _direction, _length); _currentMode = null; } break; case BuildMode.Breaking: if (Input.IsActionJustPressed("interact_place")) _currentMode = null; else if (!Input.IsActionPressed("interact_break")) { - this.GetClient()?.RPC(BreakLine, _startPos, _direction, _length); + RpcId(1, nameof(BreakLine), _startPos.X, _startPos.Y, _direction, _length); _currentMode = null; } break; @@ -63,28 +66,30 @@ public class CreativeBuilding : Node2D if (_currentMode != null) { var start = _startPos.ToVector(); - var angle = client.Cursor.Position.AngleToPoint(start); // angle_to_point appears reversed. + var angle = Cursor.Position.AngleToPoint(start); // angle_to_point appears reversed. _direction = Facings.FromAngle(angle); - _length = Math.Min(MaxLength, Mathf.RoundToInt(start.DistanceTo(client.Cursor.Position) / 16)); + _length = Math.Min(MaxLength, Mathf.RoundToInt(start.DistanceTo(Cursor.Position) / 16)); } else { - _startPos = BlockPos.FromVector(client.Cursor.Position); + _startPos = BlockPos.FromVector(Cursor.Position); _length = 0; } - bool IsBlockAt(BlockPos pos) => client.GetBlockAt(pos) != null; + var world = this.GetWorld(); + bool IsBlockAt(BlockPos pos) => world.GetBlockAt(pos) != null; _canBuild = !IsBlockAt(_startPos) && Facings.All.Any(pos => IsBlockAt(_startPos + pos.ToBlockPos())); } public override void _Draw() { - if (!(this.GetGame() is Client client) || !client.Cursor.Visible || EscapeMenu.Instance.Visible) return; + if ((this.GetGame() is Server) || !Cursor.Visible || EscapeMenu.Instance.Visible) return; var green = Color.FromHsv(1.0F / 3, 1.0F, 1.0F, 0.4F); var red = Color.FromHsv(0.0F, 1.0F, 1.0F, 0.4F); var black = new Color(0.0F, 0.0F, 0.0F, 0.65F); + var world = this.GetWorld(); foreach (var pos in GetBlockPositions(_startPos, _direction, _length)) { - var hasBlock = client.GetBlockAt(pos) != null; + var hasBlock = world.GetBlockAt(pos) != null; var color = (_currentMode != BuildMode.Breaking) ? ((_canBuild && !hasBlock) ? green : red) : (hasBlock ? black : red); @@ -96,33 +101,36 @@ public class CreativeBuilding : Node2D => Enumerable.Range(0, length + 1).Select(i => start + direction.ToBlockPos() * i); - [RPC(PacketDirection.ClientToServer)] - private static void PlaceLine(Server server, NetworkID networkID, BlockPos start, Facing direction, int length) + [Master] + private void PlaceLine(int x, int y, Facing direction, int length) { - var player = server.GetPlayer(networkID); - // TODO: Test if starting block is valid. + if (Player.NetworkID != GetTree().GetRpcSenderId()) return; + // TODO: Test if starting block is valid. // FIXME: Test if there is a player in the way. - var validLocations = GetBlockPositions(start, direction, length) - .Where(pos => server.GetBlockAt(pos) == null) - .ToArray(); - - foreach (var pos in validLocations) { - var block = server.Spawn(); - block.Position = pos; - block.Color = player.Color.Blend(Color.FromHsv(0.0F, 0.0F, GD.Randf(), 0.2F)); + + var start = new BlockPos(x, y); + var world = this.GetWorld(); + foreach (var pos in GetBlockPositions(start, direction, length)) { + if (world.GetBlockAt(pos) != null) continue; + var color = Player.Color.Blend(Color.FromHsv(0.0F, 0.0F, GD.Randf(), 0.2F)); + world.Rpc(nameof(World.SpawnBlock), pos.X, pos.Y, color, false); } } - [RPC(PacketDirection.ClientToServer)] - private static void BreakLine(Server server, NetworkID networkID, BlockPos start, Facing direction, int length) + [Master] + private void BreakLine(int x, int y, Facing direction, int length) { - // var player = server.GetPlayer(networkID); + if (Player.NetworkID != GetTree().GetRpcSenderId()) return; + // TODO: Do additional verification on the packet. + + var start = new BlockPos(x, y); + var world = this.GetWorld(); foreach (var pos in GetBlockPositions(start, direction, length)) { - var block = server.GetBlockAt(pos); + var block = world.GetBlockAt(pos); if (block?.Unbreakable != false) continue; - block.RemoveFromParent(); + world.Rpc(nameof(World.Despawn), world.GetPathTo(block)); } } } diff --git a/src/EscapeMenuAppearance.cs b/src/EscapeMenuAppearance.cs index a2a2477..79899b7 100644 --- a/src/EscapeMenuAppearance.cs +++ b/src/EscapeMenuAppearance.cs @@ -20,11 +20,12 @@ public class EscapeMenuAppearance : CenterContainer ColorSlider.Value = GD.Randf(); ColorPreview.Modulate = Color.FromHsv((float)ColorSlider.Value, 1.0F, 1.0F); - this.GetClient().Connected += () => - this.GetClient().RPC(Player.ChangeAppearance, DisplayName.Text, ColorPreview.Modulate); + // FIXME: LocalPlayer hasn't spawned yet on connection. + // var client = this.GetClient(); + // client.Connected += () => client.LocalPlayer.RpcId(1, + // nameof(Player.ChangeAppearance), DisplayName.Text, ColorPreview.Modulate); } - #pragma warning disable IDE0051 #pragma warning disable IDE1006 @@ -49,8 +50,8 @@ public class EscapeMenuAppearance : CenterContainer { if (IsVisibleInTree()) return; var client = this.GetClient(); - // TODO: Find a better way to know if we're connected? if (client.Status == NetworkedMultiplayerPeer.ConnectionStatus.Connected) - client.RPC(Player.ChangeAppearance, DisplayName.Text, ColorPreview.Modulate); + client.LocalPlayer.RpcId(1, nameof(Player.ChangeAppearance), + DisplayName.Text, ColorPreview.Modulate); } } diff --git a/src/EscapeMenuMultiplayer.cs b/src/EscapeMenuMultiplayer.cs index 6f8635d..c1099ba 100644 --- a/src/EscapeMenuMultiplayer.cs +++ b/src/EscapeMenuMultiplayer.cs @@ -38,7 +38,7 @@ public class EscapeMenuMultiplayer : Container private void SetupIntegratedServer() { IntegratedServer = new IntegratedServer(); - this.GetClient().AddChild(IntegratedServer, true); + this.GetClient().AddChild(IntegratedServer); CallDeferred(nameof(StartIntegratedServerAndConnect)); } private void StartIntegratedServerAndConnect() @@ -77,9 +77,10 @@ public class EscapeMenuMultiplayer : Container ServerOpenClose.Text = (IntegratedServer?.Server.IsSingleplayer == false) ? "Close Server" : "Open Server"; ClientDisConnect.Text = ((IntegratedServer != null) || (status == ConnectionStatus.Disconnected)) ? "Connect" : "Disconnect"; - var pauseMode = (IntegratedServer?.Server.IsSingleplayer == true) ? PauseModeEnum.Stop : PauseModeEnum.Process; - this.GetClient().GetNode("World").PauseMode = pauseMode; - if (IntegratedServer != null) IntegratedServer.Server.GetNode("World").PauseMode = pauseMode; + var isSingleplayer = IntegratedServer?.Server.IsSingleplayer == true; + var pauseMode = isSingleplayer ? PauseModeEnum.Stop : PauseModeEnum.Process; + this.GetWorld().PauseMode = pauseMode; + if (IntegratedServer != null) IntegratedServer.Server.GetWorld().PauseMode = pauseMode; // TODO: Allow starting up the integrated server again when disconnected. } @@ -135,13 +136,12 @@ public class EscapeMenuMultiplayer : Container if (IntegratedServer != null) { IntegratedServer.Server.Stop(); - // TODO: Have a single method to "reset" the state? - IntegratedServer.Server.Objects.Clear(); - IntegratedServer.RemoveFromParent(); + client.RemoveChild(IntegratedServer); + IntegratedServer.QueueFree(); IntegratedServer = null; client.Disconnect(); - client.Objects.Clear(); + this.GetWorld().Clear(); } if (client.Status == ConnectionStatus.Disconnected) { @@ -156,7 +156,7 @@ public class EscapeMenuMultiplayer : Container client.Connect(address, port); } else { client.Disconnect(); - client.Objects.Clear(); + this.GetWorld().Clear(); } } } diff --git a/src/EscapeMenuWorld.cs b/src/EscapeMenuWorld.cs index 79228a6..f184d3a 100644 --- a/src/EscapeMenuWorld.cs +++ b/src/EscapeMenuWorld.cs @@ -25,14 +25,11 @@ public class EscapeMenuWorld : CenterContainer public FileDialog SaveFileDialog { get; private set; } public FileDialog LoadFileDialog { get; private set; } - private Node _world; private TimeSpan _playtime; private string _currentWorld; public override void _Ready() { - _world = this.GetClient().GetNode("World"); - FilenameLabel = GetNode