Tons of minor fixes

This commit is contained in:
derek.holloway committed 2026-08-03 10:01:31 -07:00
1 parent 873a6fa455
commit 37a6b5d59b
12 files changed
+219 -147

No files matched your search

+43 -16
View File
@@ -2,35 +2,51 @@
using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using Mistox.ResevedPackets;
namespace Mistox.Client {
public class MistoxClient {
public string ServerName { get; set; } = ""; // The Name of the server
public string ServerName { get; private set; } = ""; // The Name of the server
public string UserName { get; private set; } = ""; // My UserName
public bool Alive { get; set; } = true; // Is the server running
public mTCPClient ServerConnection;
public UdpClient ClientSocket;
public UDPReceiver UdpReceiver;
public ConcurrentDictionary<UInt128, mUDPClient> clientConnections; // IP Address, Client
public bool isAuthenticated { get; set; } = false; // Is the server authenticated
public ConcurrentDictionary<IPEndPoint, mUDPClient> clientConnections; // UserName, Connection
public mTCPClient ServerConnection {get; private set; } // Global TCP Server Connection
public UdpClient ClientSocket { get; private set; } // Global UDP Sender
public UDPReceiver UdpReceiver { get; private set; } // Global UDP Receiver
private readonly string ConnectionKey = ""; // Server Connection Key
public MistoxClient(IPEndPoint Server) {
public MistoxClient(string userName, string connectionKey, IPEndPoint Server) {
// Create and listen on UDP
ClientSocket = new UdpClient( Server.Port );
UdpReceiver = new UDPReceiver( this );
UserName = userName;
ConnectionKey = connectionKey;
// Create and connect to server on TCP
Console.WriteLine( "The client is initilized and trying to connect to the server at ip : " + Server.Address );
try {
ServerConnection = new mTCPClient( this, Server );
Console.WriteLine( "Connected to the server sucessfully" );
Alive = true;
} catch( Exception e ) {
Console.WriteLine( "An error has occured with the connection to the server. Error { " );
Console.WriteLine( e.ToString() );
Console.WriteLine( "}" );
Alive = false;
}
Alive = true;
}
public async Task TryAuth() {
Console.WriteLine("Attempting to authenticate against the server...");
await ServerConnection.Send(new UserAuthPacket {
UserName = UserName,
ConnectionKey = ConnectionKey
});
}
/////////////////////////////
@@ -38,27 +54,33 @@ namespace Mistox.Client {
/////////////////////////////
public void UserConnected(UserConnectedPacket packet) {
mUDPClient user = new mUDPClient(this, packet.ClientIPAddress, packet.ClientPort) {
IPEndPoint remoteUser = new IPEndPoint(packet.ClientIPAddress, packet.ClientPort);
mUDPClient user = new mUDPClient(this, remoteUser) {
UserName = packet.UserName
};
clientConnections[user.GetConnectionKey()] = user;
clientConnections[remoteUser] = user;
InvokeOnUserConnected(user);
}
public void UserDisconnected(UserDisconnectedPacket packet) {
mUDPClient client;
bool found = clientConnections.TryGetValue(packet.ConnectionKey, out client);
if (found) {
mUDPClient client = null;
foreach(mUDPClient cur in clientConnections.Values) {
if (cur.UserName.ToLower() == packet.UserName.ToLower()) {
client = cur;
break;
}
}
if (client != null) {
InvokeOnUserDisconnected( client );
client.Alive = false;
client.Dispose();
clientConnections[packet.ConnectionKey] = null;
clientConnections[client._remoteHost] = null;
}
}
/////////////////////////////
// Events
/////////////////////////////
/////////////////////////////
// Events
/////////////////////////////
public event Action<dynamic> onDataReceived;
public void InvokeOnReceived(dynamic DataPacket, mUDPClient remote = null){
@@ -81,6 +103,11 @@ namespace Mistox.Client {
public event Action onServerConnected;
public void InvokeOnServerConnected(){
Alive = true;
Task.Run(async () => {
try {
await TryAuth();
} catch {}
});
onServerConnected?.Invoke();
}
+19 -11
View File
@@ -9,16 +9,17 @@ using System.Threading.Tasks;
namespace Mistox.Client {
public class mTCPClient : IDisposable {
TcpClient _connection;
MistoxClient _parent;
private readonly TcpClient _connection;
private readonly MistoxClient _parent;
private readonly SemaphoreSlim _sendLock = new SemaphoreSlim(1, 1);
public mTCPClient( MistoxClient parent, IPEndPoint ServerAddress ) {
_connection = new TcpClient( AddressFamily.InterNetwork );
_connection.NoDelay = true;
_connection.Connect( ServerAddress );
_parent.InvokeOnServerConnected();
Thread RThread = new Thread(async () => { await ReceiveThread(); });
RThread.Start();
// Start the receive thread
Task.Run(ReceiveThread);
}
async Task ReceiveThread() {
@@ -32,19 +33,21 @@ namespace Mistox.Client {
await ns.ReadExactlyAsync(headerBuffer, 0, 3);
// Parse the header
byte packetbyte = headerBuffer[0];
ushort dataLength = (ushort)((headerBuffer[1] << 8) | headerBuffer[2]);
DataPacketHeader Header = new DataPacketHeader {
Type = headerBuffer[0],
DataLength = (ushort)((headerBuffer[1] << 8) | headerBuffer[2])
};
// Make sure the data looks valid
if (dataLength > payloadBuffer.Length) {
if (Header.DataLength > payloadBuffer.Length) {
throw new Exception("Incoming TCP payload is too large for the pre-allocated buffer.");
}
// Read off the data
await ns.ReadExactlyAsync(payloadBuffer, 0, dataLength);
await ns.ReadExactlyAsync(payloadBuffer, 0, Header.DataLength);
// Create the dataobject
dynamic dataobject = DataPacket.Deserialize( packetbyte, dataLength, payloadBuffer.AsMemory(DataPacket.HeaderLength, dataLength) );
dynamic dataobject = DataPacket.Deserialize( Header, payloadBuffer.AsMemory(DataPacket.HeaderLength, Header.DataLength) );
// Return the object
_parent.InvokeOnReceived(dataobject);
@@ -60,13 +63,18 @@ namespace Mistox.Client {
public async Task Send<T>(T packet) {
byte[] data = DataPacket.Serialize( packet );
await _connection.GetStream().WriteAsync( data, 0, data.Length );
await _sendLock.WaitAsync();
try {
await _connection.GetStream().WriteAsync( data, 0, data.Length );
} finally {
_sendLock.Release();
}
}
public void Dispose() {
_parent.InvokeOnServerDisconnected();
_connection.Close();
_connection = null;
_connection.Dispose();
}
}
}
+12 -18
View File
@@ -1,5 +1,6 @@
using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
namespace Mistox.Client {
@@ -7,38 +8,31 @@ namespace Mistox.Client {
public string UserName { get; set; } = ""; // The remote players UserName
public bool Alive { get; set; } = true; // Is the connection alive
public IPEndPoint IPAddress { get; set; } // The remote IP Address
public IPEndPoint _remoteHost { get; set; } // The remote IP Address
IPEndPoint _remoteHost;
MistoxClient _parent;
private readonly SemaphoreSlim _sendLock = new SemaphoreSlim(1, 1);
private readonly MistoxClient _parent;
public mUDPClient( MistoxClient parent, IPAddress RemoteIP, int Port ) {
public mUDPClient( MistoxClient parent, IPEndPoint remoteHost ) {
_parent = parent;
_remoteHost = new IPEndPoint( RemoteIP, Port );
_remoteHost = remoteHost;
_parent.Alive = true;
}
public async Task Send<T>( T Data ) {
byte[] byteData = DataPacket.Serialize( Data );
await _parent.ClientSocket.SendAsync( byteData, byteData.Length, _remoteHost );
}
public static UInt128 GetConnectionKey(IPAddress ipAddress) {
byte[] bytes = ipAddress.GetAddressBytes();
if (bytes.Length == 4) {
bytes = ipAddress.MapToIPv6().GetAddressBytes();
await _sendLock.WaitAsync();
try {
await _parent.ClientSocket.SendAsync( byteData, byteData.Length, _remoteHost );
} finally {
_sendLock.Release();
}
return BitConverter.ToUInt128(bytes, 0);
}
public UInt128 GetConnectionKey() {
return GetConnectionKey( IPAddress.Address );
}
public void Dispose() {
_parent.Alive = false;
_parent.ClientSocket.Close();
_parent.ClientSocket = null;
_parent.ClientSocket.Dispose();
}
}
}
+13 -13
View File
@@ -1,17 +1,16 @@
using System;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
namespace Mistox.Client {
public class UDPReceiver : IDisposable {
MistoxClient _parent;
private readonly MistoxClient _parent;
public UDPReceiver( MistoxClient parent) {
_parent = parent;
Thread Client = new Thread(async() => { await ReceiveThread(); });
Client.Start();
// Start the receive thread
Task.Run(ReceiveThread);
}
async Task ReceiveThread() {
@@ -21,25 +20,26 @@ namespace Mistox.Client {
// As UDP reads the whole next packet then drops. Im guaranteed to receive 1 packet at a time
UdpReceiveResult udpPacket = await _parent.ClientSocket.ReceiveAsync();
// Compute the connectionKey
UInt128 ConnectionKey = mUDPClient.GetConnectionKey(udpPacket.RemoteEndPoint.Address);
// Try find the user
mUDPClient client = null;
bool clientExists = _parent.clientConnections.TryGetValue(ConnectionKey, out client);
bool clientExists = _parent.clientConnections.TryGetValue(udpPacket.RemoteEndPoint, out client);
if (clientExists) {
// Create the data readers
ReadOnlyMemory<byte> dataMemory = udpPacket.Buffer.AsMemory();
ReadOnlySpan<byte> dataPacket = dataMemory.Span;
// Split apart the packet
byte dataType = dataPacket[0];
ushort DataLength = (ushort)((dataPacket[1] << 8) | dataPacket[2]);
ReadOnlyMemory<byte> data = dataMemory.Slice(DataPacket.HeaderLength, DataLength);
// Create the packet header
DataPacketHeader Header = new DataPacketHeader {
Type = dataPacket[0],
DataLength = (ushort)((dataPacket[1] << 8) | dataPacket[2])
};
// Slice out the data part of the packet
ReadOnlyMemory<byte> data = dataMemory.Slice(DataPacket.HeaderLength, Header.DataLength);
// Extract the object
dynamic buildObj = DataPacket.Deserialize( dataType, DataLength, data );
dynamic buildObj = DataPacket.Deserialize( Header, data );
// Return the object
_parent.InvokeOnReceived( buildObj, client );
+7 -8
View File
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
using Mistox.Client;
@@ -15,7 +14,7 @@ namespace Mistox {
public event Action<mUDPClient> onUserDisconnected;
public event Action onServerDisconnected;
public ClientInterface( string IpOrHostName, int Port ) {
public ClientInterface( string UserName, string ConnectionKey, string IpOrHostName, int Port ) {
// Get Server IP
IPHostEntry host = Dns.GetHostEntry( IpOrHostName );
@@ -27,7 +26,7 @@ namespace Mistox {
}
// Start and wire up the Mistox server client
serverInstance = new MistoxClient( ServerDenstination );
serverInstance = new MistoxClient( UserName, ConnectionKey, ServerDenstination );
serverInstance.onServerConnected += onServerConnected;
serverInstance.onUserConnected += (mUDPClient endpoint) => { onUserConnected?.Invoke(endpoint); };
serverInstance.onDataReceived += (dynamic data) => { onDataReceived?.Invoke(data); };
@@ -36,15 +35,15 @@ namespace Mistox {
}
public async Task SendAllClients<Packet>(Packet data) {
foreach( KeyValuePair<UInt128, mUDPClient> cur in serverInstance.clientConnections ){
await cur.Value.Send( data );
foreach( mUDPClient cur in serverInstance.clientConnections.Values ){
await cur.Send( data );
}
}
public async Task SendClient<Packet>(string UserName, Packet data) {
foreach( KeyValuePair<UInt128, mUDPClient> cur in serverInstance.clientConnections) {
if (cur.Value.UserName.ToLower() == UserName.ToLower()) {
await cur.Value.Send( data );
foreach( mUDPClient cur in serverInstance.clientConnections.Values ) {
if (cur.UserName.ToLower() == UserName.ToLower()) {
await cur.Send( data );
break;
}
}
+2 -2
View File
@@ -10,7 +10,7 @@ namespace Mistox {
return new ServerInterface(port, serverName);
}
public static ClientInterface newClient( string ServerIPOrHostName, int Port ) {
public static ClientInterface newClient( string UserName, string ServerIPOrHostName, int Port, string ConnectionKey = "" ) {
NetworkPacketDictionary.BuildNetworkPacketList();
int index = 0;
IPAddress[] remoteAddress = Dns.GetHostAddresses(ServerIPOrHostName);
@@ -21,7 +21,7 @@ namespace Mistox {
}
string ipAddress = remoteAddress[index].ToString();
if ( remoteAddress.Length > 0) {
return new ClientInterface(ipAddress, Port);
return new ClientInterface(UserName, ConnectionKey, ipAddress, Port);
} else {
Console.WriteLine("The server at " + ServerIPOrHostName + " doesn't exit or cannot be found");
return null;
+3 -3
View File
@@ -13,9 +13,9 @@ namespace Mistox.Server {
public float ConnectionRange { get; set; } = 40; // InGame distance for valid conections
public int ConnectionTimeoutSeconds { get; set; } = 10; // If no reply in time kill the connection
public bool Alive { get; set; } = true; // Is the server running
ServerListener Listener { get; set;}
public ConcurrentDictionary<string, ServerConnection> Connections;
public ConcurrentDictionary<string, ServerConnection> Connections; // All the active connections. key is username
private readonly ServerListener Listener; // The Connection Listener singleton
public ServerEntity(IPEndPoint ListenerAddress) {
Listener = new ServerListener(ListenerAddress, this);
+36 -28
View File
@@ -11,23 +11,24 @@ namespace Mistox.Server {
public string UserName { get; set; } = ""; // The Players UserName
public bool IsAuthenticated { get; set; } = false; // Has the player authenticated
public Vector3 Position { get; set; } // The ingame position of the player
public DateTime LastHeartbeat { get; set; } = DateTime.UtcNow; // Connection heartbeat for integrity
public bool Connected { get; set; } = true; // Is the connection valid
ServerEntity _parent;
TcpClient _client;
IPEndPoint _remoteAddress;
private readonly ServerEntity _parent;
private readonly TcpClient _client;
private readonly IPEndPoint _remoteAddress;
private readonly SemaphoreSlim _sendLock = new SemaphoreSlim(1, 1);
private readonly CancellationTokenSource _cts = new();
public ServerConnection( TcpClient tcpClient, ServerEntity parent, IPEndPoint remote ) {
_parent = parent;
_client = tcpClient;
_remoteAddress = remote;
_client = tcpClient;
_client.NoDelay = true;
_client.ReceiveTimeout = _parent.ConnectionTimeoutSeconds * 1000;
ServerInterface.ServerInstance.InvokeUserConnected( this );
// Start the receive thread
Thread receiveThread = new Thread(async () => await ReceiveThread() );
receiveThread.Start();
Task.Run(ReceiveThread);
}
async Task ReceiveThread() {
@@ -36,33 +37,26 @@ namespace Mistox.Server {
byte[] headerBuffer = new byte[DataPacket.HeaderLength];
byte[] payloadBuffer = new byte[65535]; // Upper limit for safety
while( Connected && _parent.Alive ) {
// Tick the last heartbeat or drop
DateTime now = DateTime.UtcNow;
if (LastHeartbeat.AddSeconds(_parent.ConnectionTimeoutSeconds) >= now) {
Connected = false;
Dispose();
break;
}
LastHeartbeat = DateTime.UtcNow;
// Read the header off
await ns.ReadExactlyAsync(headerBuffer, 0, 3);
await ns.ReadExactlyAsync(headerBuffer, 0, DataPacket.HeaderLength, _cts.Token);
// Parse the header
byte packetbyte = headerBuffer[0];
ushort dataLength = (ushort)((headerBuffer[1] << 8) | headerBuffer[2]);
// Pack the header variables for faster memory passing
DataPacketHeader Header = new DataPacketHeader {
Type = headerBuffer[0],
DataLength = (ushort)((headerBuffer[1] << 8) | headerBuffer[2])
};
// Make sure the data looks valid
if (dataLength > payloadBuffer.Length) {
if (Header.DataLength > payloadBuffer.Length) {
throw new Exception("Incoming TCP payload is too large for the pre-allocated buffer.");
}
// Read off the data
await ns.ReadExactlyAsync(payloadBuffer, 0, dataLength);
await ns.ReadExactlyAsync(payloadBuffer, 0, Header.DataLength, _cts.Token);
// Create the dataobject
dynamic dataobject = DataPacket.Deserialize( packetbyte, dataLength, payloadBuffer.AsMemory(DataPacket.HeaderLength, dataLength) );
dynamic dataobject = DataPacket.Deserialize( Header, payloadBuffer.AsMemory(DataPacket.HeaderLength) );
// Return the object
_parent.InvokeDataReceived(dataobject);
@@ -71,20 +65,34 @@ namespace Mistox.Server {
} catch (Exception e) {
_parent.Alive = false;
Dispose();
Console.WriteLine("TCP Receive exception: " + e.Message);
Console.WriteLine($"[TCP] Connection lost ({_remoteAddress}): {e.Message}");
} finally {
Dispose();
}
}
}
public async Task Send<T>( T packet ) {
byte[] byteData = DataPacket.Serialize( packet );
await _client.GetStream().WriteAsync( byteData, 0, byteData.Length );
byte[] byteData = DataPacket.Serialize(packet);
await _sendLock.WaitAsync();
try {
await _client.GetStream().WriteAsync(byteData, 0, byteData.Length);
} finally {
_sendLock.Release();
}
}
public void Dispose() {
if (!Connected) return;
Connected = false;
_parent.InvokeUserDisconnected( this );
Connected = false;
_cts.Cancel();
_client.Close();
_sendLock.Dispose();
_cts.Dispose();
_parent.Connections.TryRemove(UserName, out _);
_parent.InvokeUserDisconnected(this);
_parent.Alive = false;
// Remove this item from the Dictionary on the Server for garbage collection
}
+11 -9
View File
@@ -1,7 +1,6 @@
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
// Client Connections
@@ -9,20 +8,22 @@ using System.Threading.Tasks;
namespace Mistox.Server {
public class ServerListener : IDisposable {
ServerEntity _parent;
IPEndPoint _bindAddress;
TcpListener _Listener;
private readonly ServerEntity _parent;
private readonly IPEndPoint _bindAddress;
private readonly TcpListener _Listener;
public ServerListener(IPEndPoint listenerAddress, ServerEntity parent) {
_bindAddress = listenerAddress;
_parent = parent;
Thread ConnectionThread = new Thread(async () => await ListenerThread() );
ConnectionThread.Start();
_Listener = new TcpListener( _bindAddress );
_Listener.Start();
// Start the thread
Task.Run(ListenerThread);
}
async Task ListenerThread() {
_Listener = new TcpListener( _bindAddress );
_Listener.Start();
while( _parent.Alive ) {
TcpClient client = await _Listener.AcceptTcpClientAsync();
@@ -37,11 +38,12 @@ namespace Mistox.Server {
Console.WriteLine( "New User Connected" );
}
Dispose();
}
public void Dispose() {
_Listener.Stop();
_Listener = null;
_Listener.Dispose();
}
}
+40 -28
View File
@@ -1,69 +1,81 @@
using System;
using System.Buffers;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using MessagePack;
using Mistox.Attributes;
namespace Mistox {
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct DataPacketHeader {
public byte Type { get; set; }
public ushort DataLength { get; set; }
}
public class DataPacket {
// The length of the packet header in bytes
public static readonly int HeaderLength = 3;
public static int HeaderLength => Unsafe.SizeOf<DataPacketHeader>();
// 8b. 16b. value of datalength
// Data Packet [ Type | DataLength | Data ]
public DataPacketHeader Header { get; set; }
public dynamic Data { get; set; }
// Helper classes
public static byte[] Serialize<T>( T Object ) {
// Get your custom packet attribute to find the ID
// Get the attribute ID
mPacket attribute = typeof(T).GetCustomAttribute<mPacket>(false);
if (attribute == null) {
throw new Exception($"The datastructure {typeof(T).Name} is not an mPacket");
}
// Serialize the payload directly to a temporary byte array.
byte[] payloadData = MessagePackSerializer.Serialize(Object);
ushort dataLength = (ushort)payloadData.Length;
// Use an expandable buffer writer from the system stack
var writer = new ArrayBufferWriter<byte>(256);
// Allocate an array for the final output (1 byte Type + 2 bytes Length + Payload)
byte[] finalPacket = new byte[HeaderLength + dataLength];
// Advance the writer past the 3-byte header slot so MessagePack doesn't overwrite it
writer.Advance(HeaderLength);
// Write the 3-byte header directly into the final array
finalPacket[0] = attribute.ID;
finalPacket[1] = (byte)((dataLength >> 8) & 0xFF); // High byte of ushort
finalPacket[2] = (byte)(dataLength & 0xFF); // Low byte of ushort
// Serialize the payload DIRECTLY into the final buffer memory
MessagePackSerializer.Serialize(writer, Object);
// Copy the payload directly into the final array right after the header
// This replaces all your .Join() allocations with a single ultra-fast CPU copy
Buffer.BlockCopy(payloadData, 0, finalPacket, HeaderLength, dataLength);
// Build our header struct on the stack
DataPacketHeader header = new DataPacketHeader {
Type = attribute.ID,
DataLength = (ushort)(writer.WrittenCount - HeaderLength)
};
return finalPacket;
// Map the struct directly onto the 3-byte reservation we left at the front
writer.WrittenMemory.Slice(0, HeaderLength);
MemoryMarshal.Write(writer.GetSpan(HeaderLength).Slice(0, HeaderLength), in header);
// 7. Extract the finished byte array.
// Note: In a production socket pipeline, you would pass writer.WrittenMemory directly
// to the socket instead of converting it to an array here!
return writer.WrittenSpan.ToArray();
}
public static object Deserialize( byte PacketByte, ushort DataLength, ReadOnlyMemory<byte> Data ) {
public static object Deserialize( DataPacketHeader Header, ReadOnlyMemory<byte> Data ) {
// Get the type from the tag
if (!NetworkPacketDictionary.ServerToClientPackets.TryGetValue(PacketByte, out Type resolvedType)) {
throw new Exception($"Unknown packet type ID: {PacketByte}");
if (!NetworkPacketDictionary.ServerToClientPackets.TryGetValue(Header.Type, out Type resolvedType)) {
throw new Exception($"Unknown packet type ID: {Header.Type}");
}
// Sanity check: Ensure the packet we received actually has the payload bytes it claims to have
if ( DataLength < Data.Length ) {
// Ensure the packet we received actually has the payload bytes it claims to have
if ( Header.DataLength < Data.Length ) {
throw new Exception("Malformed packet: Payload size mismatch.");
}
// Make sure the data is exactly the size requested
ReadOnlyMemory<byte> payloadSlice = Data.Slice(0, DataLength);
ReadOnlyMemory<byte> payloadSlice = Data.Slice(0, Header.DataLength);
// Create the low-level reader struct directly over the memory slice
var reader = new MessagePackReader(payloadSlice);
// Extract the object
dynamic obj = MessagePackSerializer.Deserialize( resolvedType, ref reader, MessagePackSerializerOptions.Standard );
return obj;
return MessagePackSerializer.Deserialize( resolvedType, ref reader, MessagePackSerializerOptions.Standard );
}
+14 -7
View File
@@ -5,21 +5,28 @@ using Mistox.Attributes;
namespace Mistox.ResevedPackets {
[mPacket(0xFF)]
public class EntityPacket {
public ushort ObjectId { get; set; }
public byte[] InnerPayload { get; set; }
}
[mPacket(0xFE)]
public class UserConnectedPacket {
public string UserName { get; set; }
public IPAddress ClientIPAddress { get; set; }
public int ClientPort { get; set; }
}
[mPacket(0xFE)]
public class UserAuthPacket {
public string UserName { get; set; } = "";
public string ConnectionKey { get; set; } = "";
public int AuthSuccessful { get; set; } = 0; // 0 is standard, -1 is auth failure, 1 is auth success
}
[mPacket(0xFD)]
public class EntityPacket {
public ushort ObjectId { get; set; }
public byte[] InnerPayload { get; set; }
}
[mPacket(0xFC)]
public class UserDisconnectedPacket {
public UInt128 ConnectionKey { get; set; }
public string UserName { get; set; }
}
}
+19 -4
View File
@@ -1,10 +1,9 @@
Make a username -> connectionID dictionary for quick lookups instaed of using foreach loops with breaks.
1. Allow the server to setup a server name
2. Allow the client to setup a user name
3. Have the client connect to the server with a welcome packet
4. Have the server use the welcome packet to fillout the user information on the server
5. Respond to the client from the server with a server list of UDPEndpoints
6. Instead of looping through a list of avalible users have a local user dictionary that can be used to lookup clients IPEndPoints
Test that the datapacket is formatted correctly. The packet size might be off from the actual packet size
@@ -20,6 +19,22 @@ When user a joins a server
The IP gets added to the servers master list
The user needs to authenticate for username
When user leaves a server
when the server connection closes
Notify all clients to drop the connections
Remove the user from the server table
Remove the user from the server table
Use the Server TCP connection to notify all clients when a user disconnects
Connection Flow:
1. Connection to server is made working
Server object is created working
ServerConnection gets added to the Connections table working
Server fires user connected event working
2. User sends an Auth Packet to server working
Server responds with Auth sucess or fail and marks the users auth status in the server table. needs work
After sucessfull auth share the users IPEndPoint with close connections not started
3. If the TCP connection closes not started
Disconnect the user and tell all clients that the user is gone not started