Files
GameServer/MistoxServer/Server/MistoxServer.cs
T
2026-08-06 09:36:18 -07:00

127 lines
4.9 KiB
C#

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
using Mistox.ResevedPackets;
namespace Mistox.Server {
public class MistoxServer {
public string ServerName { get; private set; } = ""; // The name of the server
public int MaxClients { get; set; } = 10; // The max players per server
public float ConnectionRange { get; set; } = 40; // InGame distance for valid conections
public string ConnectionKey { get; set; } = ""; // The connection key for the server
public int ConnectionTimeoutSeconds { get; set; } = 10; // If no reply in time kill the connection
public bool Alive { get; set; } = true; // Is the server running
public ConcurrentDictionary<string, ServerConnection> Connections; // All the active connections. key is username
private readonly ServerListener Listener; // The Connection Listener singleton
public MistoxServer(IPEndPoint ListenerAddress, string serverName) {
Connections = new ConcurrentDictionary<string, ServerConnection>();
ServerName = serverName;
Listener = new ServerListener(ListenerAddress, this);
Console.WriteLine( "The Server is initilized and waiting for clients to connect at port : " + ListenerAddress.Port );
}
async Task RunAsync(Func<Task> work) {
try{
await work();
} catch (Exception ex) {
Console.WriteLine($"Error during background packet processing: {ex.Message}");
}
}
/////////////////////////////
// Heartbeat
/////////////////////////////
async Task BuildServerList(ServerConnection user, HeartbeatPacket packet) {
packet.ServerList = new List<UserTableObject>();
foreach( ServerConnection cur in Connections.Values) {
packet.ServerList.Add( new UserTableObject() {
UserName = cur.UserName,
Position = cur.Position,
IpAddress = cur.getRemote()
} );
}
await user.Send( packet );
}
/////////////////////////////
// Auth
/////////////////////////////
async Task ProcessAuthRequest(ServerConnection user, UserAuthPacket packet) {
packet.ServerName = ServerName;
if (packet.ConnectionKey == ConnectionKey) {
packet.AuthSuccessful = 1;
Connections.TryRemove(user.UserName, out _);
user.UserName = packet.UserName;
Connections[packet.UserName] = user;
user.IsAuthenticated = true;
InvokeUserConnected(user);
} else {
packet.AuthSuccessful = -1;
}
await user.Send(packet);
}
/////////////////////////////
// Events
/////////////////////////////
public event Action<ServerConnection> onUserConnected;
public void InvokeUserConnected( ServerConnection user ){
Connections[user.UserName] = user;
onUserConnected?.Invoke( user );
}
public event Action<ServerConnection, object> onDataReceived;
public void InvokeDataReceived( ServerConnection user, dynamic data ){
switch (data) {
case UserAuthPacket packet when !user.IsAuthenticated:
_ = RunAsync(async () => {
await ProcessAuthRequest(user, packet);
});
break;
case HeartbeatPacket packet when user.IsAuthenticated:
user.Position = packet.Position;
_ = RunAsync(async () => {
await BuildServerList(user, packet);
});
break;
case null:
Console.WriteLine("Received a null packet.");
break;
default:
onDataReceived?.Invoke(user, data);
break;
}
}
public event Action<ServerConnection> onUserDisconnected;
public void InvokeUserDisconnected( ServerConnection user ){
Connections.Remove(user.UserName, out _);
onUserDisconnected?.Invoke( user );
}
/////////////////////////////
// Send Methods
/////////////////////////////
public async Task SendAllClients<Packet>(Packet data) {
foreach( ServerConnection cur in Connections.Values ) {
await cur.Send(data);
}
}
public async Task SendClient<Packet>(string UserName, Packet data) {
await Connections[UserName].Send( data );
}
}
}