From f04cc984b038184b42ec11552ea76848bfc4d099 Mon Sep 17 00:00:00 2001 From: Erik Simon Date: Wed, 14 Dec 2022 16:31:38 +0100 Subject: [PATCH] Packet refactoring --- Mine2d.sln.DotSettings | 3 +- Mine2d/engine/Publisher.cs | 139 +++++++----------- Mine2d/engine/TextureFactory.cs | 2 - .../engine/extensions/EnumerableExtensions.cs | 12 ++ .../engine/extensions/MethodInfoExtensions.cs | 9 ++ Mine2d/engine/extensions/TypeExtensions.cs | 7 + Mine2d/engine/networking/Backend.cs | 27 ++-- Mine2d/engine/networking/Frontend.cs | 8 +- Mine2d/engine/networking/IBackend.cs | 4 +- Mine2d/engine/networking/PacketUtils.cs | 22 --- Mine2d/engine/networking/RemoteBackend.cs | 17 ++- .../engine/system/annotations/Interactor.cs | 6 +- Mine2d/game/backend/data/Packet.cs | 98 ------------ Mine2d/game/backend/interactor/Audio.cs | 3 +- Mine2d/game/backend/interactor/Breaking.cs | 16 +- Mine2d/game/backend/interactor/Connect.cs | 4 +- Mine2d/game/backend/interactor/ItemPhysics.cs | 16 +- Mine2d/game/backend/interactor/Move.cs | 16 +- .../backend/interactor/WorldGeneration.cs | 6 +- Mine2d/game/backend/network/Converter.cs | 33 +++-- .../network/packets/BlockBrokenPacket.cs | 12 ++ .../backend/network/packets/BreakPacket.cs | 9 ++ .../backend/network/packets/ConnectPacket.cs | 9 ++ .../network/packets/DisconnectPacket.cs | 9 ++ .../backend/network/packets/MovePacket.cs | 9 ++ Mine2d/game/backend/network/packets/Packet.cs | 6 + .../backend/network/packets/PacketType.cs | 13 ++ .../network/packets/PlayerInputPacket.cs | 6 + .../network/packets/PlayerMovedPacket.cs | 9 ++ .../network/packets/SelfMovedPacked.cs | 8 + .../backend/network/packets/TickPacket.cs | 8 + Mine2d/game/core/tiles/OreTile.cs | 1 - .../game/frontend/events/PlayerBreakInput.cs | 26 +++- .../game/frontend/events/PlayerController.cs | 48 ++++++ Mine2d/game/frontend/events/PlayerInput.cs | 8 +- Mine2d/game/frontend/renderer/HudRenderer.cs | 4 +- Mine2d/game/frontend/renderer/ItemRenderer.cs | 8 +- Mine2d/game/state/Player.cs | 2 +- 38 files changed, 358 insertions(+), 285 deletions(-) create mode 100644 Mine2d/engine/extensions/EnumerableExtensions.cs create mode 100644 Mine2d/engine/extensions/MethodInfoExtensions.cs create mode 100644 Mine2d/engine/extensions/TypeExtensions.cs delete mode 100644 Mine2d/engine/networking/PacketUtils.cs delete mode 100644 Mine2d/game/backend/data/Packet.cs create mode 100644 Mine2d/game/backend/network/packets/BlockBrokenPacket.cs create mode 100644 Mine2d/game/backend/network/packets/BreakPacket.cs create mode 100644 Mine2d/game/backend/network/packets/ConnectPacket.cs create mode 100644 Mine2d/game/backend/network/packets/DisconnectPacket.cs create mode 100644 Mine2d/game/backend/network/packets/MovePacket.cs create mode 100644 Mine2d/game/backend/network/packets/Packet.cs create mode 100644 Mine2d/game/backend/network/packets/PacketType.cs create mode 100644 Mine2d/game/backend/network/packets/PlayerInputPacket.cs create mode 100644 Mine2d/game/backend/network/packets/PlayerMovedPacket.cs create mode 100644 Mine2d/game/backend/network/packets/SelfMovedPacked.cs create mode 100644 Mine2d/game/backend/network/packets/TickPacket.cs create mode 100644 Mine2d/game/frontend/events/PlayerController.cs diff --git a/Mine2d.sln.DotSettings b/Mine2d.sln.DotSettings index 8d8ab74..f5e3247 100644 --- a/Mine2d.sln.DotSettings +++ b/Mine2d.sln.DotSettings @@ -1,2 +1,3 @@  - SDL \ No newline at end of file + SDL + True \ No newline at end of file diff --git a/Mine2d/engine/Publisher.cs b/Mine2d/engine/Publisher.cs index d43da77..56f3dc2 100644 --- a/Mine2d/engine/Publisher.cs +++ b/Mine2d/engine/Publisher.cs @@ -1,78 +1,86 @@ using System.Reflection; -using Mine2d.engine.networking; +using Mine2d.engine.extensions; using Mine2d.engine.system.annotations; +using Mine2d.game.backend.network.packets; using Mine2d.game.core.extensions; namespace Mine2d.engine; +public delegate void InteractionHandler(Packet packet); + public class Publisher { - private readonly Dictionary> subscribers = - new(); - private readonly HashSet clientOnlySubscriptions = new(); - private readonly HashSet serverSubscriptions = new(); + private readonly Dictionary> subscribers = new(); + private readonly HashSet clientOnlySubscriptions = new(); + private readonly HashSet serverSubscriptions = new(); private readonly InteractorKind kind; public Publisher(InteractorKind kind) { + Enum.GetValues() + .ForEach(type => this.subscribers[type] = new HashSet()); + this.kind = kind; this.Scan(); } private void Scan() { - var types = Assembly + Assembly .GetAssembly(this.GetType())! - .GetTypesSafe(); - foreach (var type in types) - { - var classAttrs = type.GetCustomAttributes(typeof(InteractorAttribute), false); - if (classAttrs.Length == 0) + .GetTypesSafe() + .Where(t => t.HasAttribute()) + .SelectMany(t => t.GetMethods()) + .Where(m => m.HasAttribute()) + .ForEach(method => { - continue; - } - var methods = type.GetMethods(); - foreach (var method in methods) - { - var methodAttrs = method.GetCustomAttributes(typeof(InteractionAttribute), false); - if (methodAttrs.Length == 0) + var attribute = method.GetCustomAttribute()!; + Console.WriteLine($"Registering interaction method {method.Name} declared in {method.DeclaringType}"); + Console.WriteLine($"InteractorKind: {attribute.Kind}"); + Console.WriteLine($"PacketType: {attribute.Type}"); + + switch (attribute.Kind) { - continue; + case InteractorKind.Hybrid: + case InteractorKind.Server: + this.serverSubscriptions.Add(attribute.Type); + break; + case InteractorKind.Client: + this.clientOnlySubscriptions.Add(attribute.Type); + break; + default: + throw new ArgumentOutOfRangeException(nameof(attribute.Kind), attribute.Kind, null); } - var attr = (InteractionAttribute)methodAttrs[0]; - if (attr.Kind is InteractorKind.Server or InteractorKind.Hybrid) + + if (attribute.Kind == this.kind || this.kind == InteractorKind.Hybrid) { - this.serverSubscriptions.Add(attr.Type); + this.subscribers[attribute.Type].Add(method); + Console.WriteLine("Subscribed!"); } - if (attr.Kind is InteractorKind.Client) - { - this.clientOnlySubscriptions.Add(attr.Type); - } - if (attr.Kind != this.kind && this.kind != InteractorKind.Hybrid) - { - continue; - } - var del = method.GetParameters().Length == 0 ? - Delegate.CreateDelegate(typeof(Action), method) : - Delegate.CreateDelegate( - typeof(Action<>).MakeGenericTypeSafely(method.GetParameters()[0].ParameterType), - method - ); - this.Subscribe(attr.Type, del); - } - } - this.clientOnlySubscriptions.ExceptWith(this.serverSubscriptions); + + Console.WriteLine(); + }); } - private void Subscribe(string type, Delegate callback) + public void Publish(Packet packet) { - if (!this.subscribers.ContainsKey(type)) - { - this.subscribers[type] = new HashSet(); - } - this.subscribers[type].Add(callback); + if (packet.Type != PacketType.Tick) + Console.WriteLine($"[{nameof(Publisher)}] Publishing {packet.Type}"); + + this.subscribers[packet.Type] + .ForEach(handler => + { + var parameterCount = handler.GetParameters().Length; + handler.Invoke(null, parameterCount > 0 ? new object[] { packet } : null); + }); } + public bool IsClientOnlyPacket(Packet packet) + => this.clientOnlySubscriptions.Contains(packet.Type); + + public bool IsServerPacket(Packet packet) + => this.serverSubscriptions.Contains(packet.Type); + public void Dump() { foreach (var pair in this.subscribers) @@ -84,41 +92,4 @@ public class Publisher } } } - - public void Publish(ValueType packet) - { - var type = PacketUtils.GetType(packet); - if (type != "tick") - { - Console.WriteLine("Publishing packet: " + type); - } - if (this.subscribers.ContainsKey(type)) - { - if (type != "tick") - { - Console.WriteLine("Found " + this.subscribers[type].Count + " subscribers"); - } - foreach (var del in this.subscribers[type]) - { - if (del.Method.GetParameters().Length == 0) - { - del.DynamicInvoke(); - } - else - { - del.DynamicInvoke(packet); - } - } - } - } - - public bool IsClientOnlyPacket(string type) - { - return this.clientOnlySubscriptions.Contains(type); - } - - public bool IsServerPacket(string type) - { - return this.serverSubscriptions.Contains(type); - } -} +} \ No newline at end of file diff --git a/Mine2d/engine/TextureFactory.cs b/Mine2d/engine/TextureFactory.cs index befb031..617229d 100644 --- a/Mine2d/engine/TextureFactory.cs +++ b/Mine2d/engine/TextureFactory.cs @@ -1,5 +1,3 @@ -using Mine2d.game; - namespace Mine2d.engine; public class TextureFactory diff --git a/Mine2d/engine/extensions/EnumerableExtensions.cs b/Mine2d/engine/extensions/EnumerableExtensions.cs new file mode 100644 index 0000000..d9d1eae --- /dev/null +++ b/Mine2d/engine/extensions/EnumerableExtensions.cs @@ -0,0 +1,12 @@ +namespace Mine2d.engine.extensions; + +public static class EnumerableExtensions +{ + public static void ForEach(this IEnumerable source, Action action) + { + foreach (var item in source) + { + action(item); + } + } +} \ No newline at end of file diff --git a/Mine2d/engine/extensions/MethodInfoExtensions.cs b/Mine2d/engine/extensions/MethodInfoExtensions.cs new file mode 100644 index 0000000..a3c0fae --- /dev/null +++ b/Mine2d/engine/extensions/MethodInfoExtensions.cs @@ -0,0 +1,9 @@ +using System.Reflection; + +namespace Mine2d.engine.extensions; + +public static class MethodInfoExtensions +{ + public static bool HasAttribute(this MethodInfo methodInfo) where T : Attribute + => methodInfo.GetCustomAttributes(typeof(T), false).Length > 0; +} \ No newline at end of file diff --git a/Mine2d/engine/extensions/TypeExtensions.cs b/Mine2d/engine/extensions/TypeExtensions.cs new file mode 100644 index 0000000..a9b733d --- /dev/null +++ b/Mine2d/engine/extensions/TypeExtensions.cs @@ -0,0 +1,7 @@ +namespace Mine2d.engine.extensions; + +public static class TypeExtensions +{ + public static bool HasAttribute(this Type type) where T : Attribute + => type.GetCustomAttributes(typeof(T), false).Length > 0; +} \ No newline at end of file diff --git a/Mine2d/engine/networking/Backend.cs b/Mine2d/engine/networking/Backend.cs index 8b1c87e..f635ba5 100644 --- a/Mine2d/engine/networking/Backend.cs +++ b/Mine2d/engine/networking/Backend.cs @@ -1,8 +1,8 @@ using System.Text; using Mine2d.engine.system.annotations; using Mine2d.game; -using Mine2d.game.backend.data; using Mine2d.game.backend.network; +using Mine2d.game.backend.network.packets; using Newtonsoft.Json; using WatsonTcp; @@ -12,22 +12,25 @@ public class Backend : IBackend { private WatsonTcpServer server; private Publisher publisher; - private readonly Queue pendingPackets = new(); + private readonly Queue pendingPackets = new(); private uint tick; public void Process(double dt) { - this.ProcessPacket(new TickPacket(this.tick++)); + this.ProcessPacket(new TickPacket + { + Tick = ++this.tick + }); + Context.Get().GameState.Tick = this.tick; while (this.pendingPackets.Count > 0) { - var packet = this.pendingPackets.Dequeue(); - this.publisher.Publish(packet); + this.publisher.Publish(this.pendingPackets.Dequeue()); } this.SendGameState(); } - public void ProcessPacket(ValueType packet) + public void ProcessPacket(Packet packet) { this.pendingPackets.Enqueue(packet); } @@ -36,6 +39,7 @@ public class Backend : IBackend { Task.Run(this.Run); this.publisher = new Publisher(InteractorKind.Hybrid); + this.publisher.Dump(); } public void Run() @@ -65,15 +69,12 @@ public class Backend : IBackend private void MessageReceived(object sender, MessageReceivedEventArgs args) { - var time = DateTime.Now; Console.WriteLine("Message Received: " + args.IpPort); + var packet = Converter.ParsePacket(args.Data); - Console.WriteLine("Received packet: " + packet); - if (packet != null) - { - this.pendingPackets.Enqueue(packet); - } - Console.WriteLine(DateTime.Now - time); + Console.WriteLine($"Received packet: {packet.Type}"); + + this.pendingPackets.Enqueue(packet); } private void SendGameState() diff --git a/Mine2d/engine/networking/Frontend.cs b/Mine2d/engine/networking/Frontend.cs index dfc33a1..d882f46 100644 --- a/Mine2d/engine/networking/Frontend.cs +++ b/Mine2d/engine/networking/Frontend.cs @@ -1,5 +1,5 @@ using Mine2d.game; -using Mine2d.game.backend.data; +using Mine2d.game.backend.network.packets; using Mine2d.game.frontend.renderer; namespace Mine2d.engine.networking; @@ -14,7 +14,11 @@ public class Frontend : IFrontend ctx.FrontendGameState.PlayerName = ctx.IsHost ? "Host" : "Client"; var guid = Guid.NewGuid(); ctx.FrontendGameState.PlayerGuid = guid; - var connectPacket = new ConnectPacket(ctx.FrontendGameState.PlayerName, guid); + var connectPacket = new ConnectPacket + { + PlayerName = ctx.FrontendGameState.PlayerName, + PlayerGuid = guid + }; ctx.Backend.ProcessPacket(connectPacket); ctx.TileRegistry.RegisterTile(); ctx.ItemRegistry.RegisterItems(); diff --git a/Mine2d/engine/networking/IBackend.cs b/Mine2d/engine/networking/IBackend.cs index 9718ae2..51937c8 100644 --- a/Mine2d/engine/networking/IBackend.cs +++ b/Mine2d/engine/networking/IBackend.cs @@ -1,8 +1,10 @@ +using Mine2d.game.backend.network.packets; + namespace Mine2d.engine.networking; public interface IBackend { public void Process(double dt); - public void ProcessPacket(ValueType packet); + public void ProcessPacket(Packet packet); public void Init(); } diff --git a/Mine2d/engine/networking/PacketUtils.cs b/Mine2d/engine/networking/PacketUtils.cs deleted file mode 100644 index 585702a..0000000 --- a/Mine2d/engine/networking/PacketUtils.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Mine2d.game.backend.data; - -namespace Mine2d.engine.networking; - -public static class PacketUtils -{ - public static string GetType(ValueType packet) - { - var t = packet.GetType(); - var p = t.GetProperty(nameof(IPacket.Type)); - if (p == null) - { - throw new ArgumentNullException(nameof(p), "p undef"); - } - var v = p.GetValue(packet); - if (v == null) - { - throw new ArgumentNullException(nameof(v), "v undef"); - } - return (string)v; - } -} diff --git a/Mine2d/engine/networking/RemoteBackend.cs b/Mine2d/engine/networking/RemoteBackend.cs index 9177c8d..fd2c825 100644 --- a/Mine2d/engine/networking/RemoteBackend.cs +++ b/Mine2d/engine/networking/RemoteBackend.cs @@ -1,7 +1,7 @@ using System.Text; using Mine2d.engine.system.annotations; using Mine2d.game; -using Mine2d.game.backend.data; +using Mine2d.game.backend.network.packets; using Mine2d.game.state; using Newtonsoft.Json; using WatsonTcp; @@ -12,12 +12,16 @@ public class RemoteBackend : IBackend { private WatsonTcpClient client; private Publisher publisher; - private readonly Queue pendingPackets = new(); + private readonly Queue pendingPackets = new(); private uint tick; public void Process(double dt) { - this.ProcessPacket(new TickPacket(this.tick++)); + this.ProcessPacket(new TickPacket + { + Tick = ++this.tick + }); + while (this.pendingPackets.Count > 0) { var packet = this.pendingPackets.Dequeue(); @@ -25,13 +29,12 @@ public class RemoteBackend : IBackend } } - public void ProcessPacket(ValueType packet) + public void ProcessPacket(Packet packet) { this.publisher.Publish(packet); - if (this.publisher.IsClientOnlyPacket(PacketUtils.GetType(packet))) - { + if (this.publisher.IsClientOnlyPacket(packet)) return; - } + var json = JsonConvert.SerializeObject(packet); var bytes = Encoding.UTF8.GetBytes(json); this.client.Send(bytes); diff --git a/Mine2d/engine/system/annotations/Interactor.cs b/Mine2d/engine/system/annotations/Interactor.cs index 6896c33..40bd0e6 100644 --- a/Mine2d/engine/system/annotations/Interactor.cs +++ b/Mine2d/engine/system/annotations/Interactor.cs @@ -1,3 +1,5 @@ +using Mine2d.game.backend.network.packets; + namespace Mine2d.engine.system.annotations; public enum InteractorKind @@ -13,10 +15,10 @@ public class InteractorAttribute : Attribute { } [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] public class InteractionAttribute : Attribute { - public string Type { get; set; } + public PacketType Type { get; set; } public InteractorKind Kind { get; set; } - public InteractionAttribute(InteractorKind kind, string type) + public InteractionAttribute(InteractorKind kind, PacketType type) { this.Type = type; this.Kind = kind; diff --git a/Mine2d/game/backend/data/Packet.cs b/Mine2d/game/backend/data/Packet.cs deleted file mode 100644 index 2b79525..0000000 --- a/Mine2d/game/backend/data/Packet.cs +++ /dev/null @@ -1,98 +0,0 @@ -using Mine2d.game.core.data; - -namespace Mine2d.game.backend.data; - -public interface IPacket -{ - public string Type { get; } -} - -public struct MovePacket : IPacket -{ - public readonly string Type => "move"; - - public readonly string PlayerName { get; } - public readonly Vector2 Movement { get; } - - public MovePacket(string playerName, Vector2 movement) - { - this.PlayerName = playerName; - this.Movement = movement; - } -} - -public readonly struct ConnectPacket : IPacket -{ - public readonly string Type => "connect"; - public readonly string PlayerName { get; } - public readonly Guid PlayerGuid { get; } - - public ConnectPacket(string playerName, Guid playerGuid) - { - this.PlayerName = playerName; - this.PlayerGuid = playerGuid; - } -} - -public readonly struct TickPacket : IPacket -{ - public readonly string Type => "tick"; - public readonly uint Tick { get; } - - public TickPacket(uint tick) - { - this.Tick = tick; - } -} - -public readonly struct SelfMovedPacket : IPacket -{ - public readonly string Type => "selfMoved"; - public readonly Vector2 Target { get; } - - public SelfMovedPacket(Vector2 target) - { - this.Target = target; - } -} - -public readonly struct BreakPacket : IPacket -{ - public readonly string Type => "break"; - public readonly Guid PlayerGuid { get; } - public readonly Vector2 Target { get; } - - public BreakPacket(Guid playerGuid, Vector2 target) - { - this.PlayerGuid = playerGuid; - this.Target = target; - } -} - -public readonly struct PlayerMovedPacket : IPacket -{ - public readonly string Type => "playerMoved"; - public readonly Guid PlayerId { get; } - public readonly Vector2 Target { get; } - - public PlayerMovedPacket(Guid playerId, Vector2 target) - { - this.PlayerId = playerId; - this.Target = target; - } -} - -public readonly struct BlockBrokenPacket : IPacket -{ - public readonly string Type => "blockBroken"; - public readonly Guid PlayerId { get; } - public readonly Vector2 Target { get; } - public readonly STile Tile { get; } - - public BlockBrokenPacket(Guid playerId, Vector2 target, STile tile) - { - this.PlayerId = playerId; - this.Target = target; - this.Tile = tile; - } -} diff --git a/Mine2d/game/backend/interactor/Audio.cs b/Mine2d/game/backend/interactor/Audio.cs index 207c676..3fff16b 100644 --- a/Mine2d/game/backend/interactor/Audio.cs +++ b/Mine2d/game/backend/interactor/Audio.cs @@ -1,12 +1,13 @@ using Mine2d.engine; using Mine2d.engine.system.annotations; +using Mine2d.game.backend.network.packets; namespace Mine2d.game.backend.interactor; [Interactor] public class Audio { - [Interaction(InteractorKind.Client, "blockBroken")] + [Interaction(InteractorKind.Client, PacketType.BlockBroken)] public static void BlockBroken() { var ctx = Context.Get(); diff --git a/Mine2d/game/backend/interactor/Breaking.cs b/Mine2d/game/backend/interactor/Breaking.cs index 37475b9..7f9626d 100644 --- a/Mine2d/game/backend/interactor/Breaking.cs +++ b/Mine2d/game/backend/interactor/Breaking.cs @@ -1,6 +1,5 @@ -using Mine2d.engine; using Mine2d.engine.system.annotations; -using Mine2d.game.backend.data; +using Mine2d.game.backend.network.packets; using Mine2d.game.core; using Mine2d.game.core.data; @@ -9,7 +8,7 @@ namespace Mine2d.game.backend.interactor; [Interactor] public class Breaking { - [Interaction(InteractorKind.Hybrid, "tick")] + [Interaction(InteractorKind.Hybrid, PacketType.Tick)] public static void TickHybrid() { var ctx = Context.Get(); @@ -45,7 +44,12 @@ public class Breaking if (tile.Hits >= hardness) { var blockPos = new Vector2((int)Math.Floor(player.Mining.X / 16) * 16, (int)Math.Floor(player.Mining.Y / 16) * 16); - ctx.Backend.ProcessPacket(new BlockBrokenPacket(player.Id, blockPos, tile)); + ctx.Backend.ProcessPacket(new BlockBrokenPacket + { + PlayerGuid = player.Id, + Target = blockPos, + Tile = tile + }); chunk.SetTileAt(player.Mining, STile.From(0)); } } @@ -53,7 +57,7 @@ public class Breaking } } - [Interaction(InteractorKind.Server, "break")] + [Interaction(InteractorKind.Server, PacketType.Break)] public static void BreakServer(BreakPacket packet) { var ctx = Context.Get(); @@ -65,7 +69,7 @@ public class Breaking player.Mining = packet.Target; } - [Interaction(InteractorKind.Server, "blockBroken")] + [Interaction(InteractorKind.Server, PacketType.BlockBroken)] public static void BreakServer(BlockBrokenPacket packet) { var ctx = Context.Get(); diff --git a/Mine2d/game/backend/interactor/Connect.cs b/Mine2d/game/backend/interactor/Connect.cs index 7e46436..f0f62d3 100644 --- a/Mine2d/game/backend/interactor/Connect.cs +++ b/Mine2d/game/backend/interactor/Connect.cs @@ -1,5 +1,5 @@ using Mine2d.engine.system.annotations; -using Mine2d.game.backend.data; +using Mine2d.game.backend.network.packets; using Mine2d.game.state; namespace Mine2d.game.backend.interactor; @@ -7,7 +7,7 @@ namespace Mine2d.game.backend.interactor; [Interactor] public class Connect { - [Interaction(InteractorKind.Server, "connect")] + [Interaction(InteractorKind.Server, PacketType.Connect)] public static void ConnectServer(ConnectPacket packet) { var ctx = Context.Get(); diff --git a/Mine2d/game/backend/interactor/ItemPhysics.cs b/Mine2d/game/backend/interactor/ItemPhysics.cs index 2316d3e..bb4886a 100644 --- a/Mine2d/game/backend/interactor/ItemPhysics.cs +++ b/Mine2d/game/backend/interactor/ItemPhysics.cs @@ -1,6 +1,6 @@ using Mine2d.engine; using Mine2d.engine.system.annotations; -using Mine2d.game.backend.data; +using Mine2d.game.backend.network.packets; using Mine2d.game.core.data; using Mine2d.game.core.data.entities; @@ -10,8 +10,8 @@ namespace Mine2d.game.backend.interactor; public class ItemPhysics { - [Interaction(InteractorKind.Hybrid, "tick")] - public static void TickHybrid() + [Interaction(InteractorKind.Hybrid, PacketType.Tick)] + public static void TickHybrid(TickPacket packet) { var gameState = Context.Get().GameState; var world = gameState.World; @@ -36,8 +36,8 @@ public class ItemPhysics } } - [Interaction(InteractorKind.Hybrid, "tick")] - public static void Pickup(TickPacket tickPacket) + [Interaction(InteractorKind.Hybrid, PacketType.Tick)] + public static void Pickup(TickPacket packet) { var gameState = Context.Get().GameState; var world = gameState.World; @@ -51,12 +51,12 @@ public class ItemPhysics Console.WriteLine("Where"); return e is ItemEntity itemEntity && (player.Position + new Vector2(7, 3) - itemEntity.Position).LengthSquared() < 8 * 8 && - player.inventory.PickupItemStack(new ItemStack { Id = itemEntity.ItemId, Count = 1 }); - }); + player.Inventory.PickupItemStack(new ItemStack { Id = itemEntity.ItemId, Count = 1 }); + }).ToList(); if (items.Any()) { Context.Get().GameAudio.Play(Sound.ItemPickup); - Console.WriteLine(tickPacket.Tick + " " + items.Count()); + Console.WriteLine(packet.Tick + " " + items.Count()); } _ = chunk.Value.Entities.RemoveAll(e => items.Contains(e)); } diff --git a/Mine2d/game/backend/interactor/Move.cs b/Mine2d/game/backend/interactor/Move.cs index 4e67f42..1bbbb75 100644 --- a/Mine2d/game/backend/interactor/Move.cs +++ b/Mine2d/game/backend/interactor/Move.cs @@ -1,5 +1,5 @@ using Mine2d.engine.system.annotations; -using Mine2d.game.backend.data; +using Mine2d.game.backend.network.packets; using Mine2d.game.core; namespace Mine2d.game.backend.interactor; @@ -7,7 +7,7 @@ namespace Mine2d.game.backend.interactor; [Interactor] public class Move { - [Interaction(InteractorKind.Hybrid, "move")] + [Interaction(InteractorKind.Hybrid, PacketType.Move)] public static void MoveHybrid(MovePacket packet) { var ctx = Context.Get(); @@ -18,7 +18,7 @@ public class Move } } - [Interaction(InteractorKind.Hybrid, "tick")] + [Interaction(InteractorKind.Hybrid, PacketType.Tick)] public static void TickHybrid() { var ctx = Context.Get(); @@ -33,12 +33,16 @@ public class Move { if (player.Position != fromPositions[player.Id]) { - ctx.Backend.ProcessPacket(new PlayerMovedPacket(player.Id, player.Position)); + ctx.Backend.ProcessPacket(new PlayerMovedPacket + { + PlayerGuid = player.Id, + Target = player.Position + }); } } } - - [Interaction(InteractorKind.Client, "tick")] + + [Interaction(InteractorKind.Client, PacketType.Tick)] public static void SelfMovedClient() { var camera = Context.Get().FrontendGameState.Camera; diff --git a/Mine2d/game/backend/interactor/WorldGeneration.cs b/Mine2d/game/backend/interactor/WorldGeneration.cs index 2f76edf..356f471 100644 --- a/Mine2d/game/backend/interactor/WorldGeneration.cs +++ b/Mine2d/game/backend/interactor/WorldGeneration.cs @@ -1,5 +1,5 @@ using Mine2d.engine.system.annotations; -using Mine2d.game.backend.data; +using Mine2d.game.backend.network.packets; using Mine2d.game.core.data; using Mine2d.game.core.world; @@ -19,7 +19,7 @@ public class WorldGeneration new(-1, 1) }; - [Interaction(InteractorKind.Server, "playerMoved")] + [Interaction(InteractorKind.Server, PacketType.PlayerMoved)] public static void PlayerMovedServer(PlayerMovedPacket packet) { var ctx = Context.Get(); @@ -28,7 +28,7 @@ public class WorldGeneration { var generationTarget = packet.Target + direction * 16 * 32; var hasChunkGenerated = world.HasChunkAt(generationTarget); - + if (!hasChunkGenerated) { var chunkPos = World.ToChunkPos(generationTarget); diff --git a/Mine2d/game/backend/network/Converter.cs b/Mine2d/game/backend/network/Converter.cs index 665f502..4b234e9 100644 --- a/Mine2d/game/backend/network/Converter.cs +++ b/Mine2d/game/backend/network/Converter.cs @@ -1,34 +1,43 @@ using System.Text; -using Mine2d.game.backend.data; +using Mine2d.game.backend.network.packets; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using ConnectPacket = Mine2d.game.backend.network.packets.ConnectPacket; +using TickPacket = Mine2d.game.backend.network.packets.TickPacket; namespace Mine2d.game.backend.network; public class Converter { - public static ValueType ParsePacket(byte[] bytes) + public static Packet ParsePacket(byte[] bytes) { var jsonString = Encoding.UTF8.GetString(bytes); return ParsePacket(jsonString); } - public static ValueType ParsePacket(string jsonString) + public static Packet ParsePacket(string jsonString) { var parsedRaw = JObject.Parse(jsonString); - var type = parsedRaw.GetValue("type"); - if (type == null) - { + var packetType = parsedRaw + .GetValue("type")? + .Value(); + + if (packetType == null) throw new PacketException("Packet has no type"); - } - var packetType = type.Value(); + Console.WriteLine("Packet type: " + packetType); - return packetType switch + Packet packet = packetType switch { - "move" => parsedRaw.ToObject(), - "connect" => parsedRaw.ToObject(), - _ => throw new PacketException("Unknown packet type") + PacketType.Connect => parsedRaw.ToObject(), + PacketType.Disconnect => parsedRaw.ToObject(), + PacketType.Tick => parsedRaw.ToObject(), + _ => throw new PacketException($"Unknown packet type: {packetType}") }; + + if (packet is null) + throw new PacketException($"Failed to parse packet of type: {packetType}"); + + return packet; } public static byte[] SerializePacket(ValueType packet) diff --git a/Mine2d/game/backend/network/packets/BlockBrokenPacket.cs b/Mine2d/game/backend/network/packets/BlockBrokenPacket.cs new file mode 100644 index 0000000..b110194 --- /dev/null +++ b/Mine2d/game/backend/network/packets/BlockBrokenPacket.cs @@ -0,0 +1,12 @@ +using Mine2d.game.core.data; + +namespace Mine2d.game.backend.network.packets; + +public class BlockBrokenPacket : Packet +{ + public override PacketType Type => PacketType.BlockBroken; + + public Guid PlayerGuid { get; init; } + public Vector2 Target { get; init; } + public STile Tile { get; init; } +} \ No newline at end of file diff --git a/Mine2d/game/backend/network/packets/BreakPacket.cs b/Mine2d/game/backend/network/packets/BreakPacket.cs new file mode 100644 index 0000000..7af6709 --- /dev/null +++ b/Mine2d/game/backend/network/packets/BreakPacket.cs @@ -0,0 +1,9 @@ +namespace Mine2d.game.backend.network.packets; + +public class BreakPacket : Packet +{ + public override PacketType Type => PacketType.Break; + + public Guid PlayerGuid { get; init; } + public Vector2 Target { get; init; } +} \ No newline at end of file diff --git a/Mine2d/game/backend/network/packets/ConnectPacket.cs b/Mine2d/game/backend/network/packets/ConnectPacket.cs new file mode 100644 index 0000000..490a6d0 --- /dev/null +++ b/Mine2d/game/backend/network/packets/ConnectPacket.cs @@ -0,0 +1,9 @@ +namespace Mine2d.game.backend.network.packets; + +public class ConnectPacket : Packet +{ + public override PacketType Type => PacketType.Connect; + + public string PlayerName { get; init; } + public Guid PlayerGuid { get; init; } +} \ No newline at end of file diff --git a/Mine2d/game/backend/network/packets/DisconnectPacket.cs b/Mine2d/game/backend/network/packets/DisconnectPacket.cs new file mode 100644 index 0000000..68ac71e --- /dev/null +++ b/Mine2d/game/backend/network/packets/DisconnectPacket.cs @@ -0,0 +1,9 @@ +namespace Mine2d.game.backend.network.packets; + +public class DisconnectPacket : Packet +{ + public override PacketType Type => PacketType.Disconnect; + + public string PlayerName { get; init; } + public string PlayerGuid { get; init; } +} \ No newline at end of file diff --git a/Mine2d/game/backend/network/packets/MovePacket.cs b/Mine2d/game/backend/network/packets/MovePacket.cs new file mode 100644 index 0000000..7c03e0f --- /dev/null +++ b/Mine2d/game/backend/network/packets/MovePacket.cs @@ -0,0 +1,9 @@ +namespace Mine2d.game.backend.network.packets; + +public class MovePacket : Packet +{ + public override PacketType Type => PacketType.Move; + + public string PlayerName { get; init; } + public Vector2 Movement { get; init; } +} \ No newline at end of file diff --git a/Mine2d/game/backend/network/packets/Packet.cs b/Mine2d/game/backend/network/packets/Packet.cs new file mode 100644 index 0000000..4d8d6d0 --- /dev/null +++ b/Mine2d/game/backend/network/packets/Packet.cs @@ -0,0 +1,6 @@ +namespace Mine2d.game.backend.network.packets; + +public abstract class Packet +{ + public abstract PacketType Type { get; } +} \ No newline at end of file diff --git a/Mine2d/game/backend/network/packets/PacketType.cs b/Mine2d/game/backend/network/packets/PacketType.cs new file mode 100644 index 0000000..26bdd5a --- /dev/null +++ b/Mine2d/game/backend/network/packets/PacketType.cs @@ -0,0 +1,13 @@ +namespace Mine2d.game.backend.network.packets; + +public enum PacketType +{ + Connect, + Disconnect, + Tick, + Move, + SelfMoved, + Break, + PlayerMoved, + BlockBroken +} \ No newline at end of file diff --git a/Mine2d/game/backend/network/packets/PlayerInputPacket.cs b/Mine2d/game/backend/network/packets/PlayerInputPacket.cs new file mode 100644 index 0000000..b2b714d --- /dev/null +++ b/Mine2d/game/backend/network/packets/PlayerInputPacket.cs @@ -0,0 +1,6 @@ +namespace Mine2d.game.backend.network.packets; + +public class PlayerInputPacket +{ + public Vector2 InputVector { get; set; } +} \ No newline at end of file diff --git a/Mine2d/game/backend/network/packets/PlayerMovedPacket.cs b/Mine2d/game/backend/network/packets/PlayerMovedPacket.cs new file mode 100644 index 0000000..e34c45f --- /dev/null +++ b/Mine2d/game/backend/network/packets/PlayerMovedPacket.cs @@ -0,0 +1,9 @@ +namespace Mine2d.game.backend.network.packets; + +public class PlayerMovedPacket : Packet +{ + public override PacketType Type => PacketType.PlayerMoved; + + public Guid PlayerGuid { get; init; } + public Vector2 Target { get; init; } +} \ No newline at end of file diff --git a/Mine2d/game/backend/network/packets/SelfMovedPacked.cs b/Mine2d/game/backend/network/packets/SelfMovedPacked.cs new file mode 100644 index 0000000..d584a6b --- /dev/null +++ b/Mine2d/game/backend/network/packets/SelfMovedPacked.cs @@ -0,0 +1,8 @@ +namespace Mine2d.game.backend.network.packets; + +public class SelfMovedPacked : Packet +{ + public override PacketType Type => PacketType.SelfMoved; + + public Vector2 Target { get; init; } +} \ No newline at end of file diff --git a/Mine2d/game/backend/network/packets/TickPacket.cs b/Mine2d/game/backend/network/packets/TickPacket.cs new file mode 100644 index 0000000..cbafeef --- /dev/null +++ b/Mine2d/game/backend/network/packets/TickPacket.cs @@ -0,0 +1,8 @@ +namespace Mine2d.game.backend.network.packets; + +public class TickPacket : Packet +{ + public override PacketType Type => PacketType.Tick; + + public uint Tick { get; init; } +} \ No newline at end of file diff --git a/Mine2d/game/core/tiles/OreTile.cs b/Mine2d/game/core/tiles/OreTile.cs index c09c124..84dff0b 100644 --- a/Mine2d/game/core/tiles/OreTile.cs +++ b/Mine2d/game/core/tiles/OreTile.cs @@ -1,4 +1,3 @@ -using Mine2d.engine; using Mine2d.game.core.data; namespace Mine2d.game.core.tiles; diff --git a/Mine2d/game/frontend/events/PlayerBreakInput.cs b/Mine2d/game/frontend/events/PlayerBreakInput.cs index 63825e7..b7537c4 100644 --- a/Mine2d/game/frontend/events/PlayerBreakInput.cs +++ b/Mine2d/game/frontend/events/PlayerBreakInput.cs @@ -1,6 +1,6 @@ using Mine2d.engine.system; using Mine2d.engine.system.annotations; -using Mine2d.game.backend.data; +using Mine2d.game.backend.network.packets; namespace Mine2d.game.frontend.events; @@ -18,7 +18,12 @@ public class PlayerBreakInput var amp = ctx.FrontendGameState.MousePosition / ctx.FrontendGameState.Settings.GameScale + ctx.FrontendGameState.Camera.Position; - ctx.Backend.ProcessPacket(new BreakPacket(ctx.FrontendGameState.PlayerGuid, amp)); + + ctx.Backend.ProcessPacket(new BreakPacket + { + PlayerGuid = ctx.FrontendGameState.PlayerGuid, + Target = amp + }); } } @@ -31,8 +36,15 @@ public class PlayerBreakInput } var ctx = Context.Get(); - var amp = ctx.FrontendGameState.MousePosition / ctx.FrontendGameState.Settings.GameScale + ctx.FrontendGameState.Camera.Position; - ctx.Backend.ProcessPacket(new BreakPacket(ctx.FrontendGameState.PlayerGuid, amp)); + var amp = ctx.FrontendGameState.MousePosition + / ctx.FrontendGameState.Settings.GameScale + + ctx.FrontendGameState.Camera.Position; + + ctx.Backend.ProcessPacket(new BreakPacket + { + PlayerGuid = ctx.FrontendGameState.PlayerGuid, + Target = amp + }); } [EventListener(EventType.MouseButtonUp)] @@ -44,6 +56,10 @@ public class PlayerBreakInput } var ctx = Context.Get(); - ctx.Backend.ProcessPacket(new BreakPacket(ctx.FrontendGameState.PlayerGuid, Vector2.Zero)); + ctx.Backend.ProcessPacket(new BreakPacket + { + PlayerGuid = ctx.FrontendGameState.PlayerGuid, + Target = Vector2.Zero + }); } } diff --git a/Mine2d/game/frontend/events/PlayerController.cs b/Mine2d/game/frontend/events/PlayerController.cs new file mode 100644 index 0000000..ad69da5 --- /dev/null +++ b/Mine2d/game/frontend/events/PlayerController.cs @@ -0,0 +1,48 @@ +using Mine2d.engine.system; +using Mine2d.engine.system.annotations; + +namespace Mine2d.game.frontend.events; + +public class PlayerController +{ + [EventListener(EventType.KeyDown)] + public static void OnKeyDown(SDL_Event e) + { + if (!IsMovementKey(e.key.keysym.scancode)) + return; + + // Context + // .Get() + // .Backend + // .ProcessPacket(new PlayerInputPacket + // { + // InputVector = e.key.keysym.scancode switch + // { + // SDL_Scancode.SDL_SCANCODE_A + // => new Vector2(-1, 0), + // SDL_Scancode.SDL_SCANCODE_D + // => new Vector2(1, 0), + // SDL_Scancode.SDL_SCANCODE_W or SDL_Scancode.SDL_SCANCODE_SPACE + // => new Vector2(0, 1), + // SDL_Scancode.SDL_SCANCODE_S + // => new Vector2(0, -1) + // } + // }); + } + + [EventListener(EventType.KeyUp)] + public static void OnKeyUp(SDL_Event e) + { + if (!IsMovementKey(e.key.keysym.scancode)) + return; + } + + private static bool IsMovementKey(SDL_Scancode scancode) + { + return scancode + is SDL_Scancode.SDL_SCANCODE_A + or SDL_Scancode.SDL_SCANCODE_D + or SDL_Scancode.SDL_SCANCODE_W + or SDL_Scancode.SDL_SCANCODE_S; + } +} diff --git a/Mine2d/game/frontend/events/PlayerInput.cs b/Mine2d/game/frontend/events/PlayerInput.cs index ab178c5..da74733 100644 --- a/Mine2d/game/frontend/events/PlayerInput.cs +++ b/Mine2d/game/frontend/events/PlayerInput.cs @@ -1,6 +1,6 @@ using Mine2d.engine.system; using Mine2d.engine.system.annotations; -using Mine2d.game.backend.data; +using Mine2d.game.backend.network.packets; namespace Mine2d.game.frontend.events; @@ -80,6 +80,10 @@ public class PlayerInput { movement = Vector2.Normalize(movement); } - ctx.Backend.ProcessPacket(new MovePacket(ctx.FrontendGameState.PlayerName, movement)); + ctx.Backend.ProcessPacket(new MovePacket + { + PlayerName = ctx.FrontendGameState.PlayerName, + Movement = movement + }); } } diff --git a/Mine2d/game/frontend/renderer/HudRenderer.cs b/Mine2d/game/frontend/renderer/HudRenderer.cs index 7ce683e..20bc58b 100644 --- a/Mine2d/game/frontend/renderer/HudRenderer.cs +++ b/Mine2d/game/frontend/renderer/HudRenderer.cs @@ -30,9 +30,9 @@ public class HudRenderer : IRenderer var (hotbarWidth, hotbarHeight) = renderer.GetTextureSize(this.hotbarTexture); var player = PlayerEntity.GetSelf(); renderer.DrawTexture(this.hotbarTexture, 0, 0, hotbarWidth * uiScale, hotbarHeight * uiScale); - for (var i = 0; i < player?.inventory.Hotbar.Length; i++) + for (var i = 0; i < player?.Inventory.Hotbar.Length; i++) { - var stack = player.inventory.Hotbar[i]; + var stack = player.Inventory.Hotbar[i]; if (stack == null) { continue; diff --git a/Mine2d/game/frontend/renderer/ItemRenderer.cs b/Mine2d/game/frontend/renderer/ItemRenderer.cs index 0d91e7c..86ac6c8 100644 --- a/Mine2d/game/frontend/renderer/ItemRenderer.cs +++ b/Mine2d/game/frontend/renderer/ItemRenderer.cs @@ -12,23 +12,23 @@ public class ItemRenderer : IRenderer var world = gameState.World; foreach (var chunk in world.Chunks) { - renderChunk(chunk.Value); + RenderChunk(chunk.Value); } } - private static void renderChunk(Chunk chunk) + private static void RenderChunk(Chunk chunk) { var entities = chunk.Entities; foreach (var entity in entities) { if (entity is ItemEntity itemEntity) { - renderItem(itemEntity); + RenderItem(itemEntity); } } } - private static void renderItem(ItemEntity itemEntity) + private static void RenderItem(ItemEntity itemEntity) { var item = itemEntity.ItemId; var position = itemEntity.Position; diff --git a/Mine2d/game/state/Player.cs b/Mine2d/game/state/Player.cs index 18c3ac8..c19cbd0 100644 --- a/Mine2d/game/state/Player.cs +++ b/Mine2d/game/state/Player.cs @@ -8,7 +8,7 @@ public class Player public Guid Id { get; set; } public Vector2 Mining { get; set; } public int MiningCooldown { get; set; } - public PlayerInventory inventory { get; set; } = new(); + public PlayerInventory Inventory { get; set; } = new(); public Vector2 GetCenter() {