Development Log: A Rant About Packets & Dependency Injection

So I wanted to just have a quick little rant about a complication I ran into while working on my game’s engine and networking code this morning. I ran into this slight complication when trying code the packets that allow the server to close a client’s connection gracefully with an error message instead of just forcefully closing the ssl and tcp connections without providing any details or way to handle these in a way that won’t abort them mid-game loop.

So originally my idea was to create a packet class like this,

using LiteNetLib.Utils;
using Microsoft.Extensions.Logging;
using Reoria.Engine.Networking.Packets.Interfaces;
using Reoria.Engine.Networking.Sockets.Interfaces;

namespace Reoria.Engine.Networking.Sockets.Packets;

public class CloseSecureSocketPacket(ILogger<CloseSecureSocketPacket> logger, ISecureSocket secureSocket) : IPacket
{
    protected readonly ILogger<CloseSecureSocketPacket> Logger = logger;
    protected readonly ISecureSocket SecureSocket = secureSocket;

    public string PacketIdentifier => "Sockets.CloseSecureSocketPacket";

    public void Deserialize(NetDataReader reader)
    {
        string message = reader.GetString();

        _ = this.SecureSocket.DisconnectAsync();

        this.Logger.LogInformation("Secure socket was closed by remote host, reason: {message}", message);
    }

    public void Serialize(NetDataWriter writer) 
        => writer.Put("Connection has been closed by the server.");
}

The problem I ran into with this code is while the packet system has full dependency injection support, at the time I am writing this my ISecureSocket is what handles and makes calls to the IPacketRegistry class, which takes IEnumerable<IPacket> from the dependency injection container. The problem with all of this is it creates a circular dependency loop as ISecureSocket needs IPacketRegistry which needs CloseSecureSocketPacket (an IPacket), which needs ISecureSocket, and repeat that loop on end.

The solution I put in for now was to just have a basically random class that just holds a boolean that the sockets check if something wants to close them, and in the game loop it checks this class at the end of the update loop, but while this simple fix works for now it’s not what I want going forward in the code.

That being said trying to code a game from (mostly) scratch using only MonoGame and some other libraries for handing some of the more complex things and discovering little nightmares like this one in the vision and style I want the games code to be in is part of the fun and reason I chose to do this instead of using something like Godot, RPG Maker, Game Maker, and/or Unity or some other indie game engine.

Anyhow for now I have everything working and wrote up some mock timeout code into the server to send the CloseSecureSocketPacket after 5 seconds in the server’s game loop. I need to go and improve the core networking code now, but it is a start considering this morning the only way I had to close a connection was just literally killing the sockets mid-game loop, which can cause its own problems. Below are some screenshots of the server and client running the mock code, I will post another log when I have some updates on how this networking system development is going.

If you want to follow the project, while I don’t post every little update on the website you can view and track the commit history for my game on my GitHub at https://github.com/XerShade/Reoria and for the networking code specifically it’s repository at https://github.com/XerShade/Reoria.Engine.Networking

Leave a Reply