init commit over here

This commit is contained in:
2025-05-12 18:04:18 -07:00
commit c00d3b1426
21 changed files with 973 additions and 0 deletions
+15
View File
@@ -0,0 +1,15 @@
The servers default port is 25566
TCPServer.cs
Void TCPServer() Initilizes the server object on the default game port of 25566
Void SendAll(string Data) Send data to all the clients
Event onReceived Fires when data is received from a client
TCPClient.cs
Void TCPClient(String ServerIP) Initilizes the client object
Void Send(String Data) Sends data to the server
Event onReceived Fires when data is received from the server
UDPClient.cs
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 MiB

+33
View File
@@ -0,0 +1,33 @@
using MistoxServer;
using System;
namespace MistoxHolePunch {
class HelpDocumentation {
public static string HelpText = @"
-------------- Help Page for Mistox Game Server --------------
Usage: MistServer ServerIP [Command] [Options]
Command Linux Style Command Meaning
/c -c Start The Client
/s -s Start The Server
ServerOptions
/s -s [options]
/p -p The port that will be used for the server [Includes {port} + 1]
/a -a Uses the Athoratative model for the server
ClientOptions
/c -c [options]
/h -h The Hostname or IP of the server
/p -p The port of the server
Examples:
MistServer.exe /c 127.0.0.1 /p 25550 /u Mistox Start the client connecting to server 127.0.0.1 using port 25550
MistServer.exe /c 127.0.0.1 Start the client connecting to server 127.0.0.1 using port 25567
MistServer.exe /s Start the server
"
;
}
}
+25
View File
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<StartupObject>MistoxHolePunch.Program</StartupObject>
<PackageId>Mistox Game Server</PackageId>
<Authors>Mistox</Authors>
<Company>Mistox.net</Company>
<Product>Mistox Game Server</Product>
<Description>Game Server for Mistox Games and partners</Description>
<SignAssembly>false</SignAssembly>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<ErrorReport>none</ErrorReport>
<DebugType>none</DebugType>
<DebugSymbols>false</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\MistoxServer\MistServerModule.csproj" />
</ItemGroup>
</Project>
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<_LastSelectedProfileId>F:\Users\Derek\Desktop\GameServerStandard\CLI\Properties\PublishProfiles\FolderProfile.pubxml</_LastSelectedProfileId>
<ActiveDebugProfile>MistServer</ActiveDebugProfile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebuggerFlavor>ProjectDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>
+114
View File
@@ -0,0 +1,114 @@
using System;
using System.Threading.Tasks;
using MistoxServer;
namespace MistoxHolePunch {
class Program {
static IMistoxServer serverObj;
static bool running = true;
void onConnected( object sender, EventArgs e ) {
// sender and e are always null
// put connected functions in here
}
void slowReceive( object obj, EventArgs e ) {
if ( serverObj is ServerInterface ) {
// If ServerMode is passive obj is byte[] and Send takes in byte[]
// If Servermode is Athoritiative obj is the Class type sent and Send takes in any Class type except generic object
// Check to make sure data is correct before relaying
// Also perform server specific checks in here
// IE player didnt teleport or is shooting from 20 feet from his body
serverObj.Send( obj, SendType.SlowUpdate );
}
Console.Write( "Received TCP : " );
Console.WriteLine( obj );
}
void fastReceive( object obj, EventArgs e ) {
if( serverObj is ServerInterface ) {
// If ServerMode is passive obj is byte[] and Send takes in byte[]
// If Servermode is Athoritiative obj is the Class type sent and Send takes in any Class type except generic object
// Check to make sure data is correct before relaying
// Also perform server specific checks in here
// IE player didnt teleport or is shooting from 20 feet from his body
serverObj.Send( obj, SendType.FastUpdate );
}
Console.Write( "Received UDP : " );
Console.WriteLine( obj );
}
void onDisconnected( object sender, EventArgs e ) {
// sender and e are always null
// put disconnected functions in here
}
static string host = "example.com";
static int port = 7300;
static ServerMode mode = ServerMode.Passive;
async Task RunServer() {
serverObj = mServer.newServer( Convert.ToInt32( port ), mode );
serverObj.onConnected += onConnected;
serverObj.onSlowReceive += slowReceive;
serverObj.onFastReceive += fastReceive;
serverObj.onDisconnected += onDisconnected;
while ( running ) {
// Stop this thread for 1 second so the CPU isnt 100%
// All the real work is on different threads
// While loop needs to exist so our main thread doesnt close
await Task.Delay( 1000 );
}
}
async Task RunClient() {
serverObj = mServer.newClient( host, Convert.ToInt32( port ) );
serverObj.onConnected += onConnected;
serverObj.onSlowReceive += slowReceive;
serverObj.onFastReceive += fastReceive;
serverObj.onDisconnected += onDisconnected;
while( running ) {
// Stop this thread for 1 second so the CPU isnt 100%
// All the real work is on different threads
// While loop needs to exist so our main thread doesnt close
await Task.Delay( 1000 );
}
}
static async Task Main(string[] args) {
string Task = args.Length > 0 ? args[0].ToLower() : null;
for( int i = 0; i < args.Length; i++ ) {
string cur = args[i].ToLower();
if( cur == "/h" || cur == "-h" ) {
host = args [i + 1];
} else if( cur == "/p" || cur == "-p" ) {
port = Convert.ToInt32( args [i + 1] );
} else if( cur == "/a" || cur == "-a" ) {
mode = ServerMode.Authoritative;
}
}
if (Task == "/?" || Task == "--help") {
Console.WriteLine(HelpDocumentation.HelpText);
} else if (Task == "/s" || Task == "-s") {
Program prog = new Program();
await prog.RunServer();
} else if (Task == "/c" || Task == "-c") {
Program prog = new Program();
await prog.RunClient();
} else {
host = "example.com";
port = 1500;
Program prog = new Program();
//prog.RunClient();
await prog.RunServer();
}
}
}
}
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>F:\Users\Derek\Desktop</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<_TargetId>Folder</_TargetId>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>true</PublishSingleFile>
<PublishTrimmed>true</PublishTrimmed>
</PropertyGroup>
</Project>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<History>True|2023-12-26T22:53:03.7982931Z;True|2023-12-25T20:43:03.3448404-08:00;True|2023-12-25T20:38:14.9173619-08:00;True|2023-12-25T15:49:11.8551513-08:00;True|2023-12-25T15:43:58.6114277-08:00;True|2023-12-25T13:38:16.4384268-08:00;True|2023-12-25T13:05:11.8207105-08:00;True|2023-12-25T12:52:06.9027395-08:00;True|2023-12-25T12:49:31.5840138-08:00;True|2023-12-25T12:44:52.1638218-08:00;True|2023-12-25T12:44:04.8184020-08:00;True|2023-12-25T12:23:48.6142003-08:00;True|2023-12-25T12:19:14.4957590-08:00;True|2023-12-25T12:15:47.1143818-08:00;True|2023-12-25T12:01:00.8637339-08:00;</History>
<LastFailureDetails />
</PropertyGroup>
</Project>
+71
View File
@@ -0,0 +1,71 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.2.32519.379
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MistServer", "CLI\MistServer.csproj", "{FA40271A-DDC7-4F53-AD00-D6034A524403}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MistServerModule", "MistoxServer\MistServerModule.csproj", "{E9C6F813-3AF5-4273-9845-5D9E4D7842F1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|ARM = Debug|ARM
Debug|ARM64 = Debug|ARM64
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|ARM = Release|ARM
Release|ARM64 = Release|ARM64
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{FA40271A-DDC7-4F53-AD00-D6034A524403}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FA40271A-DDC7-4F53-AD00-D6034A524403}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FA40271A-DDC7-4F53-AD00-D6034A524403}.Debug|ARM.ActiveCfg = Debug|Any CPU
{FA40271A-DDC7-4F53-AD00-D6034A524403}.Debug|ARM.Build.0 = Debug|Any CPU
{FA40271A-DDC7-4F53-AD00-D6034A524403}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{FA40271A-DDC7-4F53-AD00-D6034A524403}.Debug|ARM64.Build.0 = Debug|Any CPU
{FA40271A-DDC7-4F53-AD00-D6034A524403}.Debug|x64.ActiveCfg = Debug|Any CPU
{FA40271A-DDC7-4F53-AD00-D6034A524403}.Debug|x64.Build.0 = Debug|Any CPU
{FA40271A-DDC7-4F53-AD00-D6034A524403}.Debug|x86.ActiveCfg = Debug|Any CPU
{FA40271A-DDC7-4F53-AD00-D6034A524403}.Debug|x86.Build.0 = Debug|Any CPU
{FA40271A-DDC7-4F53-AD00-D6034A524403}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FA40271A-DDC7-4F53-AD00-D6034A524403}.Release|Any CPU.Build.0 = Release|Any CPU
{FA40271A-DDC7-4F53-AD00-D6034A524403}.Release|ARM.ActiveCfg = Release|Any CPU
{FA40271A-DDC7-4F53-AD00-D6034A524403}.Release|ARM.Build.0 = Release|Any CPU
{FA40271A-DDC7-4F53-AD00-D6034A524403}.Release|ARM64.ActiveCfg = Release|Any CPU
{FA40271A-DDC7-4F53-AD00-D6034A524403}.Release|ARM64.Build.0 = Release|Any CPU
{FA40271A-DDC7-4F53-AD00-D6034A524403}.Release|x64.ActiveCfg = Release|Any CPU
{FA40271A-DDC7-4F53-AD00-D6034A524403}.Release|x64.Build.0 = Release|Any CPU
{FA40271A-DDC7-4F53-AD00-D6034A524403}.Release|x86.ActiveCfg = Release|Any CPU
{FA40271A-DDC7-4F53-AD00-D6034A524403}.Release|x86.Build.0 = Release|Any CPU
{E9C6F813-3AF5-4273-9845-5D9E4D7842F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E9C6F813-3AF5-4273-9845-5D9E4D7842F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E9C6F813-3AF5-4273-9845-5D9E4D7842F1}.Debug|ARM.ActiveCfg = Debug|Any CPU
{E9C6F813-3AF5-4273-9845-5D9E4D7842F1}.Debug|ARM.Build.0 = Debug|Any CPU
{E9C6F813-3AF5-4273-9845-5D9E4D7842F1}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{E9C6F813-3AF5-4273-9845-5D9E4D7842F1}.Debug|ARM64.Build.0 = Debug|Any CPU
{E9C6F813-3AF5-4273-9845-5D9E4D7842F1}.Debug|x64.ActiveCfg = Debug|Any CPU
{E9C6F813-3AF5-4273-9845-5D9E4D7842F1}.Debug|x64.Build.0 = Debug|Any CPU
{E9C6F813-3AF5-4273-9845-5D9E4D7842F1}.Debug|x86.ActiveCfg = Debug|Any CPU
{E9C6F813-3AF5-4273-9845-5D9E4D7842F1}.Debug|x86.Build.0 = Debug|Any CPU
{E9C6F813-3AF5-4273-9845-5D9E4D7842F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E9C6F813-3AF5-4273-9845-5D9E4D7842F1}.Release|Any CPU.Build.0 = Release|Any CPU
{E9C6F813-3AF5-4273-9845-5D9E4D7842F1}.Release|ARM.ActiveCfg = Release|Any CPU
{E9C6F813-3AF5-4273-9845-5D9E4D7842F1}.Release|ARM.Build.0 = Release|Any CPU
{E9C6F813-3AF5-4273-9845-5D9E4D7842F1}.Release|ARM64.ActiveCfg = Release|Any CPU
{E9C6F813-3AF5-4273-9845-5D9E4D7842F1}.Release|ARM64.Build.0 = Release|Any CPU
{E9C6F813-3AF5-4273-9845-5D9E4D7842F1}.Release|x64.ActiveCfg = Release|Any CPU
{E9C6F813-3AF5-4273-9845-5D9E4D7842F1}.Release|x64.Build.0 = Release|Any CPU
{E9C6F813-3AF5-4273-9845-5D9E4D7842F1}.Release|x86.ActiveCfg = Release|Any CPU
{E9C6F813-3AF5-4273-9845-5D9E4D7842F1}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C6AB3FF2-DA2C-4A0F-8A5D-488A3D103106}
EndGlobalSection
EndGlobal
+71
View File
@@ -0,0 +1,71 @@
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
//IP Range Updater
namespace MistoxServer.Client {
public class mTCPClient : IDisposable {
TcpClient Server;
public event EventHandler onConnected;
public event EventHandler onReceived;
public event EventHandler onDisconnected;
public bool Alive;
bool notified = false;
public mTCPClient( IPEndPoint ServerAddress ) {
Server = new TcpClient( AddressFamily.InterNetwork );
Server.NoDelay = true;
Server.Connect( ServerAddress );
Alive = true;
Thread RThread = new Thread(async () => { await ReceiveThread(); });
RThread.Start();
}
async Task ReceiveThread() {
using( NetworkStream ns = Server.GetStream() ) {
try {
while( Alive ) {
if( Server.Connected && !notified ) {
Console.WriteLine( "Connected to server" );
onConnected?.Invoke( new object(), new EventArgs() );
notified = true;
} else if( !Server.Connected ) {
Console.WriteLine( "Disconnected from server" );
onDisconnected?.Invoke( new object(), new EventArgs() );
Alive = false;
}
byte[] StreamData = new byte[1024];
int bytesRead = await ns.ReadAsync(StreamData, 0, StreamData.Length);
if( bytesRead > 0 ) {
dynamic data = mSerialize.tReceive( StreamData.Sub( 0, bytesRead ) );
if( data != null ) {
onReceived?.Invoke( data, new EventArgs() );
}
}
}
} catch( Exception ) {
Console.WriteLine( "You have disconnected from the server" );
onDisconnected?.Invoke( new object(), new EventArgs() );
Alive = false;
}
}
}
public async Task Send<Packet>(Packet packet) {
byte[] data = mSerialize.PacketSerialize( packet );
await Server.GetStream().WriteAsync( data, 0, data.Length );
}
public void Dispose() {
Alive = false;
Server.Close();
Server = null;
}
}
}
+66
View File
@@ -0,0 +1,66 @@
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
// Network Sync
namespace MistoxServer.Client {
public class mUDPClient : IDisposable {
public event EventHandler onReceived;
ServerMode Mode;
Socket udpClient;
bool Alive;
int Port;
public mUDPClient( IPEndPoint ServerAddress, ServerMode mode ) {
udpClient = new Socket( AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp );
udpClient.SetSocketOption( SocketOptionLevel.IP, SocketOptionName.ReuseAddress, true );
udpClient.SetSocketOption( SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, 128 );
udpClient.Bind( new IPEndPoint( IPAddress.Any, ServerAddress.Port ) );
Alive = true;
Port = ServerAddress.Port;
Mode = mode;
Thread Client = new Thread(async() => { await ReceiveThread(); });
Client.Start();
}
async Task ReceiveThread() {
while( Alive ) {
try {
byte[] buffer = new byte[1024];
int bytesRead = await udpClient.ReceiveAsync( buffer );
if (Mode == ServerMode.Passive) {
onReceived?.Invoke( buffer.Sub( 0, bytesRead ), new EventArgs() );
} else if (Mode == ServerMode.Authoritative) {
dynamic data = mSerialize.uReceive( buffer.Sub(0, bytesRead) );
if( data != null ) {
onReceived?.Invoke( data, new EventArgs() );
}
}
} catch( Exception ) {
}
}
}
public async Task Send<Packet>( Packet Data, IPEndPoint remoteHost ) {
if (Mode == ServerMode.Authoritative) {
byte[] byteData = mSerialize.PacketSerialize( Data );
await udpClient.SendToAsync( byteData, SocketFlags.None, new IPEndPoint( remoteHost.Address, Port ) );
} else if (Mode == ServerMode.Passive) {
byte[] byteData = Data as byte[];
await udpClient.SendToAsync( byteData, SocketFlags.None, new IPEndPoint( remoteHost.Address, Port ) );
}
}
public void Dispose() {
Alive = false;
udpClient.Close();
udpClient = null;
}
}
}
+59
View File
@@ -0,0 +1,59 @@
using MistoxServer.Client;
using System;
using System.Net;
using System.Threading.Tasks;
namespace MistoxServer {
public class ClientInterface : IMistoxServer {
mTCPClient SlowUpdate;
mUDPClient FastUpdate;
IPEndPoint mPEndPoint;
public event EventHandler onConnected;
public event EventHandler onSlowReceive;
public event EventHandler onFastReceive;
public event EventHandler onDisconnected;
public ClientInterface( string IpOrHostName, int Port ) {
// Get Server IP
IPHostEntry host = Dns.GetHostEntry( IpOrHostName );
foreach( IPAddress entry in host.AddressList ) {
if ( entry.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork ) {
mPEndPoint = new IPEndPoint( entry, Port );
}
}
Console.WriteLine( "The client is initilized and trying to connect to the server at ip : " + mPEndPoint.Address );
// Make a UDP connection to the server
try {
FastUpdate = new mUDPClient( mPEndPoint, ServerMode.Authoritative );
FastUpdate.onReceived += (object o, EventArgs e) => { onFastReceive?.Invoke( o, e ); };
} catch( Exception e ) {
Console.WriteLine( "An error has occured with the connection to the server. Error { " );
Console.WriteLine( e.ToString() );
Console.WriteLine( "}" );
}
// Make a TCP connection to the server
try {
SlowUpdate = new mTCPClient( mPEndPoint );
SlowUpdate.onConnected += ( object o, EventArgs e ) => { onConnected?.Invoke( o, e ); };
SlowUpdate.onReceived += ( object o, EventArgs e ) => { onSlowReceive?.Invoke( o, e ); };
SlowUpdate.onDisconnected += ( object o, EventArgs e ) => { onDisconnected?.Invoke( o, e ); };
} catch( Exception e ) {
Console.WriteLine( "An error has occured with the connection to the server. Error { " );
Console.WriteLine( e.ToString() );
Console.WriteLine( "}" );
}
}
public async Task Send<Packet>(Packet data, SendType speed) {
if (SendType.SlowUpdate == speed) {
await SlowUpdate.Send( data );
} else {
await FastUpdate.Send( data, mPEndPoint );
}
}
}
}
+50
View File
@@ -0,0 +1,50 @@
using System;
using System.Net;
using System.Threading.Tasks;
namespace MistoxServer {
public partial class mServer {
public static IMistoxServer newServer(int port, ServerMode mode) {
return new ServerInterface(port, mode);
}
public static IMistoxServer newClient(string ServerIPOrHostName, int Port) {
int index = 0;
IPAddress[] remoteAddress = Dns.GetHostAddresses(ServerIPOrHostName);
for( int i=0; i< remoteAddress.Length; i++ ) {
if( remoteAddress[i].AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork || remoteAddress [i].AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6 ) {
index = i;
}
}
string ipAddress = remoteAddress[index].ToString();
if ( remoteAddress.Length > 0) {
return new ClientInterface(ipAddress, Port);
} else {
Console.WriteLine("The server at " + ServerIPOrHostName + " doesn't exit or cannot be found");
return null;
}
}
}
public interface IMistoxServer {
public event EventHandler onConnected;
public event EventHandler onSlowReceive;
public event EventHandler onFastReceive;
public event EventHandler onDisconnected;
public Task Send<Packet>(Packet data, SendType speed);
}
public enum SendType {
SlowUpdate,
FastUpdate
}
public enum ServerMode {
Passive,
Authoritative
}
}
+57
View File
@@ -0,0 +1,57 @@
using MistoxServer.Client;
using MistoxServer.Server;
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
namespace MistoxServer {
public class ServerInterface : IMistoxServer {
mUDPClient FastUpdateServer;
mTCPListener SlowUpdateServer;
List<Connection> Connections = new List<Connection>();
public event EventHandler onConnected;
public event EventHandler onSlowReceive;
public event EventHandler onFastReceive;
public event EventHandler onDisconnected;
public ServerInterface( int port, ServerMode mode ) {
FastUpdateServer = new mUDPClient( new IPEndPoint( IPAddress.IPv6Any, port ), mode );
SlowUpdateServer = new mTCPListener( port, mode );
SlowUpdateServer.onConnected += OnConnected;
FastUpdateServer.onReceived += ( object o, EventArgs e ) => { onFastReceive?.Invoke( o, e ); };
SlowUpdateServer.onDisconnected += OnDisconnected;
Console.WriteLine( "The Server is initilized and waiting for clients to connect at port : " + port );
}
void OnConnected( object sender, EventArgs e ) {
Connection user = (Connection)sender;
onConnected?.Invoke( sender, e );
user.slowClient.onReceived+= ( object o, EventArgs e ) => { onSlowReceive?.Invoke( o, e ); };
user.slowClient.onDisconnected += OnDisconnected;
Connections.Add( user );
}
void OnDisconnected( object sender, EventArgs e ) {
Connection user = (Connection)sender;
onDisconnected?.Invoke( sender, e );
Connections.Remove( user );
}
public async Task Send<Packet>( Packet data, SendType speed ) {
if (speed == SendType.SlowUpdate) {
foreach( Connection cur in Connections ) {
await cur.slowClient.Send( data );
}
} else {
foreach( Connection cur in Connections ) {
await FastUpdateServer.Send( data, cur.fastClient );
}
}
}
}
}
+11
View File
@@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MsgPack.Cli" Version="1.0.1" />
</ItemGroup>
</Project>
+31
View File
@@ -0,0 +1,31 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31729.503
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MistoxServer", "MistoxServer.csproj", "{947D92F0-B737-4D1D-857B-F4EAB70D6980}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CLI", "..\CLI\CLI.csproj", "{B8EA2F11-62A3-45B2-8FDC-E734FD6B87E1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{947D92F0-B737-4D1D-857B-F4EAB70D6980}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{947D92F0-B737-4D1D-857B-F4EAB70D6980}.Debug|Any CPU.Build.0 = Debug|Any CPU
{947D92F0-B737-4D1D-857B-F4EAB70D6980}.Release|Any CPU.ActiveCfg = Release|Any CPU
{947D92F0-B737-4D1D-857B-F4EAB70D6980}.Release|Any CPU.Build.0 = Release|Any CPU
{B8EA2F11-62A3-45B2-8FDC-E734FD6B87E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B8EA2F11-62A3-45B2-8FDC-E734FD6B87E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B8EA2F11-62A3-45B2-8FDC-E734FD6B87E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B8EA2F11-62A3-45B2-8FDC-E734FD6B87E1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {59213D9A-3888-4C3D-9EB7-BB116FAB1EB7}
EndGlobalSection
EndGlobal
+10
View File
@@ -0,0 +1,10 @@
using System.Net;
namespace MistoxServer.Server {
public class Connection {
public mTCPServer slowClient { get; set; }
public IPEndPoint fastClient { get; set; }
}
}
+58
View File
@@ -0,0 +1,58 @@
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
// Client Connections
namespace MistoxServer.Server {
public class mTCPListener : IDisposable {
public event EventHandler onConnected;
public event EventHandler onDisconnected;
public event EventHandler onReceive;
TcpListener Listener;
ServerMode ServerMode;
bool Alive;
int port;
public mTCPListener( int Port, ServerMode mode ) {
port = Port;
Alive = true;
ServerMode = mode;
Thread ConnectionThread = new Thread(async () => await ListenerThread() );
ConnectionThread.Start();
}
async Task ListenerThread() {
Listener = new TcpListener( IPAddress.Any, port );
Listener.Start();
while( Alive ) {
TcpClient client = await Listener.AcceptTcpClientAsync();
Connection user = new Connection(){
slowClient = new mTCPServer(client, ServerMode),
fastClient = new IPEndPoint( ((IPEndPoint)client.Client.RemoteEndPoint).Address, port )
};
Console.WriteLine( "New User Connected" );
onConnected?.Invoke( user, new EventArgs() );
user.slowClient.onDisconnected += onDisconnected;
user.slowClient.onReceived += onReceive;
Thread receiveThread = new Thread(async () => await user.slowClient.ReceiveThread(user) );
receiveThread.Start();
}
}
public void Dispose() {
Alive = false;
Listener.Stop();
Listener = null;
}
}
}
+58
View File
@@ -0,0 +1,58 @@
using System;
using System.Net.Sockets;
using System.Threading.Tasks;
namespace MistoxServer.Server {
public class mTCPServer : IDisposable {
public TcpClient slowClient;
ServerMode Mode;
public event EventHandler onReceived;
public event EventHandler onDisconnected;
public mTCPServer( TcpClient client, ServerMode mode ) {
slowClient = client;
slowClient.Client.NoDelay = true;
Mode = mode;
}
bool Alive = true;
public async Task ReceiveThread( Connection Client ) {
bool connected = true;
while( Alive && connected ) {
try {
byte[] StreamData = new byte[1024];
int bytesRead = await slowClient.GetStream().ReadAsync(StreamData, 0, StreamData.Length);
if( bytesRead > 0 ) {
if ( Mode == ServerMode.Passive) {
onReceived?.Invoke( StreamData.Sub( 0, bytesRead ), new EventArgs() );
} else if ( Mode == ServerMode.Authoritative) {
dynamic data = mSerialize.tReceive( StreamData.Sub( 0, bytesRead ) );
if( data != null ) {
onReceived?.Invoke( data, new EventArgs() );
}
}
}
} catch( Exception ) {
Console.WriteLine( "User disconnected" );
connected = false;
onDisconnected?.Invoke( Client, new EventArgs() );
}
}
}
public async Task Send<T>( T packet ) {
if( Mode == ServerMode.Authoritative ) {
byte[] byteData = mSerialize.PacketSerialize( packet );
await slowClient.GetStream().WriteAsync( byteData, 0, byteData.Length );
} else if( Mode == ServerMode.Passive ) {
byte[] byteData = packet as byte[];
await slowClient.GetStream().WriteAsync( byteData, 0, byteData.Length );
}
}
public void Dispose() {
Alive = false;
}
}
}
+95
View File
@@ -0,0 +1,95 @@
using System;
using System.IO;
using System.Net;
using System.Text;
using MsgPack.Serialization;
namespace MistoxServer {
static class Extensions {
public static T[] Join<T>( this T[] first, T[] second ) {
T[] bytes = new T[first.Length + second.Length];
Buffer.BlockCopy( first, 0, bytes, 0, first.Length );
Buffer.BlockCopy( second, 0, bytes, first.Length, second.Length );
return bytes;
}
public static T[] Sub<T>( this T[] data, int index, int length ) {
T[] result = new T[length];
Array.Copy( data, index, result, 0, length );
return result;
}
}
public class mSerialize {
public static byte[] PacketSerialize<T>( T Packet ) {
MessagePackSerializer serializer = MessagePackSerializer.Get<T>();
using( MemoryStream stream = new MemoryStream() ) {
serializer.Pack( stream, Packet );
byte[] typename = Encoding.UTF8.GetBytes(typeof(T).FullName + "," + typeof(T).Assembly.FullName);
byte[] typelength = BitConverter.GetBytes(typename.Length);
byte[] packetdata = stream.ToArray();
byte[] paketlength = BitConverter.GetBytes(packetdata.Length);
return typelength.Join( typename ).Join( paketlength ).Join( packetdata );
}
}
public static object PacketDeserialize( string typeData, byte[] Data ) {
Type type = Type.GetType( typeData );
MessagePackSerializer Serilizer = MessagePackSerializer.Get(type);
using( MemoryStream ms = new MemoryStream( Data ) ) {
return (object)Serilizer.Unpack( ms );
}
}
static byte[] TBufferedData = new byte[0];
public static dynamic tReceive( byte [] BytesRead ) {
TBufferedData = TBufferedData.Join( BytesRead );
if( TBufferedData.Length > 4 ) {
int typeLength = BitConverter.ToInt32( TBufferedData.Sub(0, 4) );
if( TBufferedData.Length > (8 + typeLength) ) {
int dataLength = BitConverter.ToInt32( TBufferedData.Sub( typeLength + 4, 4 ) );
int TotalLength = 8 + typeLength + dataLength;
if ( TBufferedData.Length >= TotalLength ) {
string typeData = Encoding.UTF8.GetString( TBufferedData.Sub(4, typeLength) );
if ( typeData.Substring(0, 13) != "System.Object" ) {
byte[] dataBytes = TBufferedData.Sub( (typeLength + 8), dataLength );
dynamic data = mSerialize.PacketDeserialize( typeData, dataBytes );
TBufferedData = TBufferedData.Sub( TotalLength, TBufferedData.Length - TotalLength );
return data;
} else {
TBufferedData = TBufferedData.Sub( TotalLength, TBufferedData.Length - TotalLength );
}
}
}
}
return null;
}
static byte[] UBufferedData = new byte[0];
public static dynamic uReceive( byte [] BytesRead ) {
UBufferedData = UBufferedData.Join( BytesRead );
if( UBufferedData.Length > 4 ) {
int typeLength = BitConverter.ToInt32( UBufferedData.Sub(0, 4) );
if( UBufferedData.Length > (8 + typeLength) ) {
int dataLength = BitConverter.ToInt32( UBufferedData.Sub( typeLength + 4, 4 ) );
int TotalLength = 8 + typeLength + dataLength;
if( UBufferedData.Length >= TotalLength ) {
string typeData = Encoding.UTF8.GetString( UBufferedData.Sub(4, typeLength) );
if( typeData.Substring( 0, 13 ) != "System.Object" ) {
byte[] dataBytes = UBufferedData.Sub( (typeLength + 8), dataLength );
dynamic data = mSerialize.PacketDeserialize( typeData, dataBytes );
UBufferedData = UBufferedData.Sub( TotalLength, UBufferedData.Length - TotalLength );
return data;
} else {
UBufferedData = UBufferedData.Sub( TotalLength, UBufferedData.Length - TotalLength );
}
}
}
}
return null;
}
}
}
+111
View File
@@ -0,0 +1,111 @@
# Server Standard
This is a central server and client model based server. The basis of the networking is on msgpack. works on IPv4 only at the moment. In a future release I might add IPV6 but not on any roadmap. Fully threaded and asynchrous to scale easily.
## Library
This is a library with a CLI attached to it to show usage. You can send and receive any data type except the standard 'Object' type
## Usage
Follow the example listed in Program.cs inside the CLI
Note: All datatypes that are sent to the server, The server needs to be aware of when in Athouritative mode.
Create the server
```c#
IMistoxServer serverobj = mServer.newServer( int Port, ServerMode mode )
```
Create the client
```c#
IMistoxServer serverobj = mServer.newClient( string HostNameOrIP, int Port )
```
Sending data
```c#
serverobj.Send( dynamic Object, SendType Speed )
```
Connected and Disconnected
```c#
serverobj.onConnected += OnConnected;
serverobj.onDisconnected += OnDisconnected;
void OnConnected( object Data, EventArgs e ){
// Sender and e are always null
// Put on connected funtions here
// such as when connected spawn a player
}
void OnDisconnected( object Data, EventArgs e ){
// Sender and e are always null
// Put on disconnected funtions here
// such as when disconnected return to main menu
}
```
Receiving data
```c#
serverobj.onSlowReceive += SlowReceivedData;
serverobj.onFastReceive += FastReceivedData;
void SlowReceivedData( object Data, EventArgs e ){
if (Data is Datatype dt){ // Only works in Athoritative mode on server | will always work on client
}
}
void FastReceivedData( object Data, EventArgs e ){
if (Data is Datatype dt){ // Only works in Athoritative mode on server | will always work on client
}
}
```
SendType *Enumeration
Where SlowUpdate is sent over TCP
And FastUpate is sent over UDP
```c#
public enum SendType {
SlowUpdate,
FastUpdate
}
```
ServerMode *Enumeration
The Servermode tells the server if it should Deserialize examine then Reserialize the data passing through.
This can be useful to make sure data is
1 actually belonging to the server
2 the ability to keep track of objects within the server [ prevent cheating ]
This requires alot of overhead on the server though.
Passive doesnt use a serdes and instead just passes the data in and out
In this mode the server doesnt need to know data types
Athoritative will Deserialize and Serialize the data
Refer to the CLI/Program.CS for reference
In this mode the server needs to know the data types being sent
Therefore you need to put all your data classes into a library and and the library to both the application and the server
```c#
public enum ServerMode {
Passive,
Authoritative
}
```
## Setup
Place all your networked data types into a library
Copy the library to the application and to the server
reference the library for the networked data types
## Contributing
All Credits to Derek Holloway
## License
[MIT](https://choosealicense.com/licenses/mit/)