Packet refactoring
This commit is contained in:
parent
599556334f
commit
f04cc984b0
|
|
@ -1,2 +1,3 @@
|
|||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SDL/@EntryIndexedValue">SDL</s:String></wpf:ResourceDictionary>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SDL/@EntryIndexedValue">SDL</s:String>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=interactor/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
|
|
@ -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<string, HashSet<Delegate>> subscribers =
|
||||
new();
|
||||
private readonly HashSet<string> clientOnlySubscriptions = new();
|
||||
private readonly HashSet<string> serverSubscriptions = new();
|
||||
private readonly Dictionary<PacketType, HashSet<MethodInfo>> subscribers = new();
|
||||
private readonly HashSet<PacketType> clientOnlySubscriptions = new();
|
||||
private readonly HashSet<PacketType> serverSubscriptions = new();
|
||||
private readonly InteractorKind kind;
|
||||
|
||||
public Publisher(InteractorKind kind)
|
||||
{
|
||||
Enum.GetValues<PacketType>()
|
||||
.ForEach(type => this.subscribers[type] = new HashSet<MethodInfo>());
|
||||
|
||||
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<InteractorAttribute>())
|
||||
.SelectMany(t => t.GetMethods())
|
||||
.Where(m => m.HasAttribute<InteractionAttribute>())
|
||||
.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<InteractionAttribute>()!;
|
||||
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<Delegate>();
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
using Mine2d.game;
|
||||
|
||||
namespace Mine2d.engine;
|
||||
|
||||
public class TextureFactory
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
namespace Mine2d.engine.extensions;
|
||||
|
||||
public static class EnumerableExtensions
|
||||
{
|
||||
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
|
||||
{
|
||||
foreach (var item in source)
|
||||
{
|
||||
action(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
using System.Reflection;
|
||||
|
||||
namespace Mine2d.engine.extensions;
|
||||
|
||||
public static class MethodInfoExtensions
|
||||
{
|
||||
public static bool HasAttribute<T>(this MethodInfo methodInfo) where T : Attribute
|
||||
=> methodInfo.GetCustomAttributes(typeof(T), false).Length > 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
namespace Mine2d.engine.extensions;
|
||||
|
||||
public static class TypeExtensions
|
||||
{
|
||||
public static bool HasAttribute<T>(this Type type) where T : Attribute
|
||||
=> type.GetCustomAttributes(typeof(T), false).Length > 0;
|
||||
}
|
||||
|
|
@ -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<ValueType> pendingPackets = new();
|
||||
private readonly Queue<Packet> 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()
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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<ValueType> pendingPackets = new();
|
||||
private readonly Queue<Packet> 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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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<PacketType>();
|
||||
|
||||
if (packetType == null)
|
||||
throw new PacketException("Packet has no type");
|
||||
}
|
||||
var packetType = type.Value<string>();
|
||||
|
||||
Console.WriteLine("Packet type: " + packetType);
|
||||
return packetType switch
|
||||
Packet packet = packetType switch
|
||||
{
|
||||
"move" => parsedRaw.ToObject<MovePacket>(),
|
||||
"connect" => parsedRaw.ToObject<ConnectPacket>(),
|
||||
_ => throw new PacketException("Unknown packet type")
|
||||
PacketType.Connect => parsedRaw.ToObject<ConnectPacket>(),
|
||||
PacketType.Disconnect => parsedRaw.ToObject<DisconnectPacket>(),
|
||||
PacketType.Tick => parsedRaw.ToObject<TickPacket>(),
|
||||
_ => 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)
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
namespace Mine2d.game.backend.network.packets;
|
||||
|
||||
public abstract class Packet
|
||||
{
|
||||
public abstract PacketType Type { get; }
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
namespace Mine2d.game.backend.network.packets;
|
||||
|
||||
public enum PacketType
|
||||
{
|
||||
Connect,
|
||||
Disconnect,
|
||||
Tick,
|
||||
Move,
|
||||
SelfMoved,
|
||||
Break,
|
||||
PlayerMoved,
|
||||
BlockBroken
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
namespace Mine2d.game.backend.network.packets;
|
||||
|
||||
public class PlayerInputPacket
|
||||
{
|
||||
public Vector2 InputVector { get; set; }
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
using Mine2d.engine;
|
||||
using Mine2d.game.core.data;
|
||||
|
||||
namespace Mine2d.game.core.tiles;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue