diff --git a/OmsiExtensions.sln b/OmsiExtensions.sln index 61137bc..abbb0de 100644 --- a/OmsiExtensions.sln +++ b/OmsiExtensions.sln @@ -25,7 +25,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TriggersSample", "_OmsiHook EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VideoDemo", "_OmsiHookExamples\VideoDemo\VideoDemo.csproj", "{D94FF6D3-08AA-41CB-B9B9-F82E860E6E96}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClickablePlaneDemo", "_OmsiHookExamples\ClickablePlaneDemo\ClickablePlaneDemo.csproj", "{49428923-732C-4541-8C97-C6D9C004D726}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Multiplayer_Server", "_OmsiHookExamples\Multiplayer_Server\Multiplayer_Server.csproj", "{2D4DDEF6-2C5D-4348-8DCE-33201BFF046C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Multiplayer_Client", "_OmsiHookExamples\Multiplayer_Client\Multiplayer_Client.csproj", "{33EBE989-3BB8-4773-96E6-A7D68E5655CD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClickablePlaneDemo", "_OmsiHookExamples\ClickablePlaneDemo\ClickablePlaneDemo.csproj", "{49428923-732C-4541-8C97-C6D9C004D726}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -157,6 +161,30 @@ Global {D94FF6D3-08AA-41CB-B9B9-F82E860E6E96}.ReleaseAndDocs|Any CPU.Build.0 = Release|x86 {D94FF6D3-08AA-41CB-B9B9-F82E860E6E96}.ReleaseAndDocs|x86.ActiveCfg = Release|x86 {D94FF6D3-08AA-41CB-B9B9-F82E860E6E96}.ReleaseAndDocs|x86.Build.0 = Release|x86 + {2D4DDEF6-2C5D-4348-8DCE-33201BFF046C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2D4DDEF6-2C5D-4348-8DCE-33201BFF046C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2D4DDEF6-2C5D-4348-8DCE-33201BFF046C}.Debug|x86.ActiveCfg = Debug|Any CPU + {2D4DDEF6-2C5D-4348-8DCE-33201BFF046C}.Debug|x86.Build.0 = Debug|Any CPU + {2D4DDEF6-2C5D-4348-8DCE-33201BFF046C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2D4DDEF6-2C5D-4348-8DCE-33201BFF046C}.Release|Any CPU.Build.0 = Release|Any CPU + {2D4DDEF6-2C5D-4348-8DCE-33201BFF046C}.Release|x86.ActiveCfg = Release|Any CPU + {2D4DDEF6-2C5D-4348-8DCE-33201BFF046C}.Release|x86.Build.0 = Release|Any CPU + {2D4DDEF6-2C5D-4348-8DCE-33201BFF046C}.ReleaseAndDocs|Any CPU.ActiveCfg = Release|Any CPU + {2D4DDEF6-2C5D-4348-8DCE-33201BFF046C}.ReleaseAndDocs|Any CPU.Build.0 = Release|Any CPU + {2D4DDEF6-2C5D-4348-8DCE-33201BFF046C}.ReleaseAndDocs|x86.ActiveCfg = Release|Any CPU + {2D4DDEF6-2C5D-4348-8DCE-33201BFF046C}.ReleaseAndDocs|x86.Build.0 = Release|Any CPU + {33EBE989-3BB8-4773-96E6-A7D68E5655CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {33EBE989-3BB8-4773-96E6-A7D68E5655CD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {33EBE989-3BB8-4773-96E6-A7D68E5655CD}.Debug|x86.ActiveCfg = Debug|Any CPU + {33EBE989-3BB8-4773-96E6-A7D68E5655CD}.Debug|x86.Build.0 = Debug|Any CPU + {33EBE989-3BB8-4773-96E6-A7D68E5655CD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {33EBE989-3BB8-4773-96E6-A7D68E5655CD}.Release|Any CPU.Build.0 = Release|Any CPU + {33EBE989-3BB8-4773-96E6-A7D68E5655CD}.Release|x86.ActiveCfg = Release|Any CPU + {33EBE989-3BB8-4773-96E6-A7D68E5655CD}.Release|x86.Build.0 = Release|Any CPU + {33EBE989-3BB8-4773-96E6-A7D68E5655CD}.ReleaseAndDocs|Any CPU.ActiveCfg = Release|Any CPU + {33EBE989-3BB8-4773-96E6-A7D68E5655CD}.ReleaseAndDocs|Any CPU.Build.0 = Release|Any CPU + {33EBE989-3BB8-4773-96E6-A7D68E5655CD}.ReleaseAndDocs|x86.ActiveCfg = Release|Any CPU + {33EBE989-3BB8-4773-96E6-A7D68E5655CD}.ReleaseAndDocs|x86.Build.0 = Release|Any CPU {49428923-732C-4541-8C97-C6D9C004D726}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {49428923-732C-4541-8C97-C6D9C004D726}.Debug|Any CPU.Build.0 = Debug|Any CPU {49428923-732C-4541-8C97-C6D9C004D726}.Debug|x86.ActiveCfg = Debug|Any CPU @@ -178,6 +206,8 @@ Global {47659503-9923-4E74-AD26-103C1F9FF2B0} = {3F0BF441-D76C-4E0D-A5A8-B20895438EA5} {1DF326AE-4D10-4545-B36A-5622B76987EC} = {3F0BF441-D76C-4E0D-A5A8-B20895438EA5} {D94FF6D3-08AA-41CB-B9B9-F82E860E6E96} = {3F0BF441-D76C-4E0D-A5A8-B20895438EA5} + {2D4DDEF6-2C5D-4348-8DCE-33201BFF046C} = {3F0BF441-D76C-4E0D-A5A8-B20895438EA5} + {33EBE989-3BB8-4773-96E6-A7D68E5655CD} = {3F0BF441-D76C-4E0D-A5A8-B20895438EA5} {49428923-732C-4541-8C97-C6D9C004D726} = {3F0BF441-D76C-4E0D-A5A8-B20895438EA5} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution diff --git a/OmsiHook/OmsiStructs.cs b/OmsiHook/OmsiStructs.cs index be5d986..33bcadf 100644 --- a/OmsiHook/OmsiStructs.cs +++ b/OmsiHook/OmsiStructs.cs @@ -29,11 +29,15 @@ public D3DVector(float x, float y, float z) public static implicit operator Vector3(D3DVector v) => new(v.x, v.y, v.z); public static implicit operator D3DVector(Vector3 v) => new() { x = v.X, y = v.Y, z = v.Z }; } + public struct D3DXVector2 { public float x, y; public override readonly string ToString() => $"[{x,8:F3}, {y,8:F3}]"; + + public static implicit operator Vector2(D3DXVector2 v) => new(v.x, v.y); + public static implicit operator D3DXVector2(Vector2 v) => new() { x = v.X, y = v.Y }; } /// @@ -107,6 +111,9 @@ public struct D3DXQuaternion public float x, y, z, w; public override readonly string ToString() => $"[{x,8:F3}, {y,8:F3}, {z,8:F3}, {w,8:F3}]"; + + public static implicit operator Quaternion(D3DXQuaternion v) => new (v.x, v.y, v.z, v.w); + public static implicit operator D3DXQuaternion(Quaternion v) => new() { x=v.X, y=v.Y, z=v.Z, w=v.W }; } /// diff --git a/OmsiHook/WrappedOmsiClasses/OmsiMapObjInst.cs b/OmsiHook/WrappedOmsiClasses/OmsiMapObjInst.cs index fabbf01..6f4419e 100644 --- a/OmsiHook/WrappedOmsiClasses/OmsiMapObjInst.cs +++ b/OmsiHook/WrappedOmsiClasses/OmsiMapObjInst.cs @@ -28,8 +28,16 @@ public float Scale get => Memory.ReadMemory(Address + 0x60); set => Memory.WriteMemory(Address + 0x60, value); } - public D3DMatrix RelMatrix => Memory.ReadMemory(Address + 0x64); - public D3DMatrix Used_RelVec => Memory.ReadMemory(Address + 0x68); + public D3DMatrix RelMatrix + { + get => Memory.ReadMemory(Memory.ReadMemory(Address + 0x64)); + set => Memory.WriteMemory(Memory.ReadMemory(Address + 0x64), value); + } + public D3DVector Used_RelVec + { + get => Memory.ReadMemory(Address + 0x68); + set => Memory.WriteMemory(Address + 0x68, value); + } public int Kachel { get => Memory.ReadMemory(Address + 0x74); @@ -40,7 +48,15 @@ public D3DMatrix AbsPosition get => Memory.ReadMemory(Address + 0x78); set => Memory.WriteMemory(Address + 0x78, value); } - public D3DMatrix AbsPosition_Inv => Memory.ReadMemory(Address + 0xb8); - public D3DMatrix AbsPosition_ThreadFree => Memory.ReadMemory(Address + 0xf8); + public D3DMatrix AbsPosition_Inv + { + get => Memory.ReadMemory(Address + 0xb8); + set => Memory.WriteMemory(Address + 0xb8, value); + } + public D3DMatrix AbsPosition_ThreadFree + { + get => Memory.ReadMemory(Address + 0xf8); + set => Memory.WriteMemory(Address + 0xf8, value); + } } } \ No newline at end of file diff --git a/_OmsiHookExamples/Multiplayer_Client/GameClient.cs b/_OmsiHookExamples/Multiplayer_Client/GameClient.cs new file mode 100644 index 0000000..b3f724d --- /dev/null +++ b/_OmsiHookExamples/Multiplayer_Client/GameClient.cs @@ -0,0 +1,85 @@ +using OmsiHook; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace OmsiHook.Examples.Multiplayer_Client +{ + internal class GameClient + { + public Tuple LastPing; + private OmsiHook omsi; + private Dictionary Vehicles = new Dictionary(); + private int frameCounter = 0; + public GameClient() + { + omsi = new OmsiHook(); + omsi.AttachToOMSI().Wait(); + var OMSIRM = omsi.RemoteMethods; + OMSIRM.OmsiSetCriticalSectionLock(omsi.Globals.ProgamManager.CS_MakeVehiclePtr).ContinueWith((_) => + { + OMSIRM.MakeVehicle(@"Vehicles\GPM_MAN_LionsCity_M\MAN_A47.bus", __copyToMainList: true).ContinueWith((id) => + { + Console.WriteLine($"Spawned Vehicle ID: {id.Result}"); + Vehicles[0] = omsi.Globals.RoadVehicles.FList[1]; + OMSIRM.OmsiReleaseCriticalSectionLock(omsi.Globals.ProgamManager.CS_MakeVehiclePtr).ContinueWith((_) => Console.WriteLine($"Unlock")); + }); + }); + } + + public void UpdateVehicles(OMSIMPMessages.Vehicle_Position_Update update) + { + if (Vehicles.TryGetValue(update.ID, out var vehicle)) + { + if (frameCounter % 20 == 0) + vehicle.Position = update.position; + vehicle.Rotation = update.rotation; + vehicle.Velocity = update.velocity; + vehicle.MyKachelPnt = update.tile; + vehicle.RelMatrix = update.relmatrix; + vehicle.Acc_Local = update.acclocal; + + var posMat = Matrix4x4.CreateFromQuaternion(update.rotation); + posMat.Translation = update.position; + var absPosMat = Matrix4x4.Multiply(posMat, Matrix4x4.Identity/*update.relmatrix*/); + Matrix4x4.Invert(absPosMat, out var absPosMatInv); + + vehicle.Pos_Mat = posMat; + vehicle.AbsPosition = absPosMat; + vehicle.AbsPosition_Inv = absPosMatInv; + vehicle.Used_RelVec = ((Matrix4x4)update.relmatrix).Translation; + vehicle.AI_Blinker_L = 1; + vehicle.AI_Blinker_R = 1; + vehicle.AI_var = 1; + frameCounter++; + } + else + { + + } + } + + public void Tick(Telepathy.Client client) + { + if (omsi.Globals.PlayerVehicle.IsNull || !client.Connected) + return; + + var vehicle = omsi.Globals.PlayerVehicle; + Console.WriteLine($"\x1b[8;0HP:{vehicle.Position}/{vehicle.MyKachelPnt}\x1b[9;0HR:{vehicle.Rotation}\x1b[10;0HV:{vehicle.Velocity}\x1b[11;0HB:{vehicle.Acc_Local} / {((Vehicles.ContainsKey(0)) ? (Vehicles[0].Acc_Local.ToString()) : "-")}"); + byte[] buff = new byte[Unsafe.SizeOf() + 4]; + int out_pos = 0; + FastBinaryWriter.Write(buff, ref out_pos, OMSIMPMessages.Messages.UPDATE_PLAYER_POSITION); + FastBinaryWriter.Write(buff, ref out_pos, new OMSIMPMessages.Player_Position_Update() + { + position = vehicle.Position, + tile = vehicle.MyKachelPnt, + rotation = vehicle.Rotation, + velocity = vehicle.Velocity, + relmatrix = vehicle.RelMatrix, + acclocal = vehicle.Acc_Local + //vehicle = vehicle.RoadVehicle.MyPath + + }); ; + client.Send(buff); + } + } +} diff --git a/_OmsiHookExamples/Multiplayer_Client/MessageParser.cs b/_OmsiHookExamples/Multiplayer_Client/MessageParser.cs new file mode 100644 index 0000000..4043afa --- /dev/null +++ b/_OmsiHookExamples/Multiplayer_Client/MessageParser.cs @@ -0,0 +1,49 @@ +namespace OmsiHook.Examples.Multiplayer_Client +{ + internal class MessageParser + { + readonly static int MAJOR_VERSION = 1; + readonly static int MINOR_VERSION = 0; + public static void ParseMessage(byte[] message, Telepathy.Client client, GameClient gameClient) + { + message.AsSpan(0, message.Length); + int parse_pos = 0; + switch ((OMSIMPMessages.Messages)FastBinaryReader.ReadI32(message, ref parse_pos)) + { + case OMSIMPMessages.Messages.PING: + { + byte[] buff = new byte[8]; + int out_pos = 0; + FastBinaryWriter.Write(buff, ref out_pos, OMSIMPMessages.Messages.PONG); + FastBinaryWriter.Write(buff, ref out_pos, FastBinaryReader.ReadI32(message, ref parse_pos)); + client.Send(buff); + } + break; + case OMSIMPMessages.Messages.PONG: + { + if (gameClient.LastPing.Item1 == FastBinaryReader.ReadI32(message, ref parse_pos)) + { + gameClient.LastPing = new Tuple(gameClient.LastPing.Item1, gameClient.LastPing.Item2, DateTime.Now.Ticks); + Console.WriteLine($"Last Ping time: {((gameClient.LastPing.Item3 - gameClient.LastPing.Item2) / 10000):f3}ms"); + } + } + break; + case OMSIMPMessages.Messages.REPLY_VERSION: + { + Console.WriteLine($"Server Version: {FastBinaryReader.ReadI32(message, ref parse_pos)}.{FastBinaryReader.ReadI32(message, ref parse_pos):D2}"); + } + break; + case OMSIMPMessages.Messages.UPDATE_VEHICLE_POSITION: + { + gameClient.UpdateVehicles(FastBinaryReader.Read(message, ref parse_pos)); + } + break; + default: + { + Console.WriteLine($"Data received {message}"); + break; + } + } + } + } +} diff --git a/_OmsiHookExamples/Multiplayer_Client/Multiplayer_Client.csproj b/_OmsiHookExamples/Multiplayer_Client/Multiplayer_Client.csproj new file mode 100644 index 0000000..f7cf4fc --- /dev/null +++ b/_OmsiHookExamples/Multiplayer_Client/Multiplayer_Client.csproj @@ -0,0 +1,23 @@ + + + + Exe + net6.0-windows + enable + enable + OMSIClient + x86 + + + + + + + + + + + + + + diff --git a/_OmsiHookExamples/Multiplayer_Client/OMSIClient.cs b/_OmsiHookExamples/Multiplayer_Client/OMSIClient.cs new file mode 100644 index 0000000..c37ca86 --- /dev/null +++ b/_OmsiHookExamples/Multiplayer_Client/OMSIClient.cs @@ -0,0 +1,48 @@ +using OmsiHook.Examples.Multiplayer_Client; +using Telepathy; + +class OMSIClient +{ + static void Main(string[] args) + { + Client client = new Client(); + GameClient gameClient = new GameClient(); + client.Connect("127.0.0.1", 1337); + + + while (true) + { + Telepathy.Message msg; + while (client.GetNextMessage(out msg)) + { + switch (msg.eventType) + { + case EventType.Connected: + { + Console.WriteLine($"Client connected: {msg.connectionId}"); + byte[] buff = new byte[4]; + int out_pos = 0; + FastBinaryWriter.Write(buff, ref out_pos, OMSIMPMessages.Messages.REQUEST_VERSION); + client.Send(buff); + byte[] buff2 = new byte[8]; + out_pos = 0; + gameClient.LastPing = new Tuple(787, DateTime.Now.Ticks, 0); + FastBinaryWriter.Write(buff2, ref out_pos, OMSIMPMessages.Messages.PING); + FastBinaryWriter.Write(buff2, ref out_pos, 787); + client.Send(buff2); + } + break; + case EventType.Data: + MessageParser.ParseMessage(msg.data, client, gameClient); + break; + case EventType.Disconnected: + Console.WriteLine($"Client disconnected: {msg.connectionId}"); + break; + } + } + gameClient.Tick(client); + System.Threading.Thread.Sleep(33); + } + client.Disconnect(); + } +} diff --git a/_OmsiHookExamples/Multiplayer_Server/Client.cs b/_OmsiHookExamples/Multiplayer_Server/Client.cs new file mode 100644 index 0000000..f6cd488 --- /dev/null +++ b/_OmsiHookExamples/Multiplayer_Server/Client.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OmsiHook.Examples.Multiplayer_Server +{ + internal class Client + { + public int ClientId { get; private set; } + public Client(int clientId) + { + ClientId = clientId; + } + } +} diff --git a/_OmsiHookExamples/Multiplayer_Server/Lib/FastBinaryReader.cs b/_OmsiHookExamples/Multiplayer_Server/Lib/FastBinaryReader.cs new file mode 100644 index 0000000..458b62a --- /dev/null +++ b/_OmsiHookExamples/Multiplayer_Server/Lib/FastBinaryReader.cs @@ -0,0 +1,74 @@ +using System; +using System.Buffers.Binary; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +internal static class FastBinaryReader +{ + public static int ReadI32(Span buffer, ref int pos) + { + var ret = BitConverter.ToInt32(buffer[pos..]); + pos += 4; + return ret; + } + + public static uint ReadU32(Span buffer, ref int pos) + { + var ret = BitConverter.ToUInt32(buffer[pos..]); + pos += 4; + return ret; + } + + public static short ReadI16(Span buffer, ref int pos) + { + var ret = BitConverter.ToInt16(buffer[pos..]); + pos += 2; + return ret; + } + + public static ushort ReadU16(Span buffer, ref int pos) + { + var ret = BitConverter.ToUInt16(buffer[pos..]); + pos += 2; + return ret; + } + + public static sbyte ReadI8(Span buffer, ref int pos) + { + var ret = (sbyte)buffer[pos]; + pos += 1; + return ret; + } + + public static byte ReadU8(Span buffer, ref int pos) + { + var ret = buffer[pos]; + pos += 1; + return ret; + } + + public static bool ReadBool(Span buffer, ref int pos) + { + var ret = BitConverter.ToBoolean(buffer[pos..]); + pos += 1; + return ret; + } + + public static float ReadFloat(Span buffer, ref int pos) + { + var ret = BitConverter.ToSingle(buffer[pos..]); + pos += 4; + return ret; + } + + public static T Read(Span buffer, ref int pos) where T : struct + { + var ret = MemoryMarshal.Read(buffer[pos..]); + pos += Unsafe.SizeOf(); + return ret; + } +} diff --git a/_OmsiHookExamples/Multiplayer_Server/Lib/FastBinaryWriter.cs b/_OmsiHookExamples/Multiplayer_Server/Lib/FastBinaryWriter.cs new file mode 100644 index 0000000..db16d34 --- /dev/null +++ b/_OmsiHookExamples/Multiplayer_Server/Lib/FastBinaryWriter.cs @@ -0,0 +1,71 @@ +using System; +using System.Buffers.Binary; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +internal static class FastBinaryWriter +{ + public static void Write(Span buffer, ref int pos, int data) + { + BitConverter.TryWriteBytes(buffer[pos..], data); + pos += 4; + } + + public static void Write(Span buffer, ref int pos, uint data) + { + BitConverter.TryWriteBytes(buffer[pos..], data); + pos += 4; + } + + public static void Write(Span buffer, ref int pos, short data) + { + BitConverter.TryWriteBytes(buffer[pos..], data); + pos += 2; + } + public static void Write(Span buffer, ref int pos, ushort data) + { + BitConverter.TryWriteBytes(buffer[pos..], data); + pos += 2; + } + + public static void Write(Span buffer, ref int pos, byte data, int advance = 1) + { + BitConverter.TryWriteBytes(buffer[pos..], data); + pos += advance; + } + + public static void Write(Span buffer, ref int pos, sbyte data) + { + BitConverter.TryWriteBytes(buffer[pos..], data); + pos += 1; + } + + public static void Write(Span buffer, ref int pos, bool data) + { + BitConverter.TryWriteBytes(buffer[pos..], data); + pos += 1; + } + + public static void Write(Span buffer, ref int pos, float data) + { + BitConverter.TryWriteBytes(buffer[pos..], data); + pos += 4; + } + + public static void Write(byte[] buffer, ref int pos, int data) + { + BitConverter.TryWriteBytes(buffer.AsSpan()[pos..], data); + pos += 4; + } + + public static void Write(Span buffer, ref int pos, T dataStruct) where T : struct + { + MemoryMarshal.Write(buffer[pos..], ref dataStruct); + pos += Unsafe.SizeOf(); + } +} diff --git a/_OmsiHookExamples/Multiplayer_Server/Lib/OMSIMPMessages.cs b/_OmsiHookExamples/Multiplayer_Server/Lib/OMSIMPMessages.cs new file mode 100644 index 0000000..15b9cbe --- /dev/null +++ b/_OmsiHookExamples/Multiplayer_Server/Lib/OMSIMPMessages.cs @@ -0,0 +1,48 @@ +using OmsiHook; +using System.Runtime.InteropServices; + +public static class OMSIMPMessages +{ + public enum Messages : int + { // Arguments + REQUEST_VERSION = 0, // - + REPLY_VERSION = 1, // Struct Version_Reply + UPDATE_PLAYER_POSITION = 2, // Struct Player_Position_Update + UPDATE_VEHICLE_POSITION = 3, + REQUEST_PLAYERS = 4, + REPLY_PLAYERS = 5, + PING = 6, // Int32 Nonce + PONG = 7, // Int32 Nonce + } + + [StructLayout(LayoutKind.Sequential)] + public struct Version_Reply + { + public int Major; + public int Minor; + } + + [StructLayout(LayoutKind.Sequential)] + public struct Player_Position_Update + { + public OmsiPoint tile; + public D3DXQuaternion rotation; + public D3DVector velocity; + public D3DVector position; + public D3DMatrix relmatrix; + public D3DVector acclocal; + } + + [StructLayout(LayoutKind.Sequential)] + public struct Vehicle_Position_Update + { + public int ID; + public OmsiPoint tile; + public D3DXQuaternion rotation; + public D3DVector velocity; + public D3DVector position; + public D3DMatrix relmatrix; + public D3DVector acclocal; + + } +} diff --git a/_OmsiHookExamples/Multiplayer_Server/MessageParser.cs b/_OmsiHookExamples/Multiplayer_Server/MessageParser.cs new file mode 100644 index 0000000..30db0f9 --- /dev/null +++ b/_OmsiHookExamples/Multiplayer_Server/MessageParser.cs @@ -0,0 +1,67 @@ +using System.Runtime.CompilerServices; + +namespace OmsiHook.Examples.Multiplayer_Server +{ + internal class MessageParser + { + readonly static int MAJOR_VERSION = 1; + readonly static int MINOR_VERSION = 0; + public static void ParseMessage(byte[] message, Client client, Telepathy.Server server) + { + message.AsSpan(0, message.Length); + int parse_pos = 0; + switch ((OMSIMPMessages.Messages)FastBinaryReader.ReadI32(message, ref parse_pos)) + { + case OMSIMPMessages.Messages.REQUEST_VERSION: + { + byte[] buff = new byte[12]; + int out_pos = 0; + FastBinaryWriter.Write(buff, ref out_pos, OMSIMPMessages.Messages.REPLY_VERSION); + FastBinaryWriter.Write(buff, ref out_pos, new OMSIMPMessages.Version_Reply() { Major = MAJOR_VERSION, Minor = MINOR_VERSION }); + server.Send(client.ClientId, buff); + } + break; + + case OMSIMPMessages.Messages.UPDATE_PLAYER_POSITION: + { + var position = FastBinaryReader.Read(message, ref parse_pos); + Console.WriteLine($"\u001b[8;0HP:{position.position}/{position.tile}\u001b[9;0HR:{position.rotation}\u001b[10;0HV:{position.velocity}"); + + byte[] buff = new byte[Unsafe.SizeOf() + 4]; + int out_pos = 0; + FastBinaryWriter.Write(buff, ref out_pos, OMSIMPMessages.Messages.UPDATE_VEHICLE_POSITION); + FastBinaryWriter.Write(buff, ref out_pos, new OMSIMPMessages.Vehicle_Position_Update() + { + ID = 0, + rotation = position.rotation, + tile = position.tile, + velocity = position.velocity, + position = (new D3DVector(position.position.x + 4, position.position.y, position.position.z)), + relmatrix = position.relmatrix, + acclocal = position.acclocal, + }); + server.Send(client.ClientId, buff); + + } + break; + + case OMSIMPMessages.Messages.REQUEST_PLAYERS: break; + + case OMSIMPMessages.Messages.PING: + { + byte[] buff = new byte[8]; + int out_pos = 0; + FastBinaryWriter.Write(buff, ref out_pos, OMSIMPMessages.Messages.PONG); + FastBinaryWriter.Write(buff, ref out_pos, FastBinaryReader.ReadI32(message, ref parse_pos)); + server.Send(client.ClientId, buff); + } + break; + default: + { + Console.WriteLine($"Data received from {client.ClientId}: {message}"); + break; + } + } + } + } +} diff --git a/_OmsiHookExamples/Multiplayer_Server/Multiplayer_Server.csproj b/_OmsiHookExamples/Multiplayer_Server/Multiplayer_Server.csproj new file mode 100644 index 0000000..b9b22d1 --- /dev/null +++ b/_OmsiHookExamples/Multiplayer_Server/Multiplayer_Server.csproj @@ -0,0 +1,16 @@ + + + + Exe + net6.0-windows + enable + enable + x86 + + + + + + + + diff --git a/_OmsiHookExamples/Multiplayer_Server/OMSIServer.cs b/_OmsiHookExamples/Multiplayer_Server/OMSIServer.cs new file mode 100644 index 0000000..71bb467 --- /dev/null +++ b/_OmsiHookExamples/Multiplayer_Server/OMSIServer.cs @@ -0,0 +1,41 @@ +using OmsiHook.Examples.Multiplayer_Server; +using Telepathy; +using Client = OmsiHook.Examples.Multiplayer_Server.Client; + +internal class OMSIServer +{ + + static void Main(string[] args) + { + Dictionary? Clients = new Dictionary(); + Server server = new Server(); + server.Start(1337); + + Console.WriteLine("Server started. Press Ctrl+C to stop..."); + + while (true) + { + Message msg; + while (server.GetNextMessage(out msg)) + { + switch (msg.eventType) + { + case EventType.Connected: + Clients.Add(msg.connectionId, new Client(msg.connectionId)); + Console.WriteLine($"Client connected: {server.GetClientAddress(msg.connectionId)}"); + break; + case EventType.Data: + MessageParser.ParseMessage(msg.data, Clients[msg.connectionId], server); + break; + case EventType.Disconnected: + Console.WriteLine($"Client disconnected: {Clients[msg.connectionId].ClientId}"); + Clients.Remove(msg.connectionId); + break; + } + } + System.Threading.Thread.Sleep(10); + } + + server.Stop(); + } +}