diff --git a/.filenesting.json b/.filenesting.json new file mode 100644 index 0000000..0b71966 --- /dev/null +++ b/.filenesting.json @@ -0,0 +1,3 @@ +{ + "help":"https://go.microsoft.com/fwlink/?linkid=866610" +} \ No newline at end of file diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 395369e..5843dad 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -16,9 +16,9 @@ jobs: steps: - uses: actions/checkout@v3 - name: Generate docs - uses: nikeee/docfx-action@v1.0.0 + uses: nunit/docfx-action@v2.4.0 with: - args: OmsiHook/docfx.json + args: OmsiHook/docs/docfx.json # Archive the generated site as an artifact - name: Archive artifact diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 50bbc69..c83badd 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -11,6 +11,9 @@ jobs: runs-on: windows-2022 + env: + BuildProjects: "['OmsiExtensionsCLI/OmsiExtensionsCLI.csproj', 'OmsiExtensionsUI/OmsiExtensionsUI.csproj','OmsiHookRPCPlugin/OmsiHookRPCPlugin.csproj']" + steps: - uses: actions/checkout@v3 - name: Setup .NET @@ -22,6 +25,14 @@ jobs: - name: Setup Windows 10 SDK uses: GuillaumeFalourd/setup-windows10-sdk-action@v1.4 - name: Restore dependencies - run: dotnet restore + shell: pwsh + run: | + foreach($proj in (ConvertFrom-JSON "${{env.BuildProjects}}")) { + dotnet restore ${{ github.workspace }}/$proj + } - name: Build - run: msbuild D:\a\Omsi-Extensions\Omsi-Extensions\OmsiExtensions.sln -t:rebuild -property:Configuration=Release + shell: pwsh + run: | + foreach($proj in (ConvertFrom-JSON "${{env.BuildProjects}}")) { + msbuild ${{ github.workspace }}/$proj -t:rebuild -property:Configuration=Release + } diff --git a/.gitignore b/.gitignore index dfcfd56..3416106 100644 --- a/.gitignore +++ b/.gitignore @@ -348,3 +348,5 @@ MigrationBackup/ # Ionide (cross platform F# VS Code tools) working folder .ionide/ +/OmsiHook/log.txt +docfx_log.txt diff --git a/OmsiExtensions.sln b/OmsiExtensions.sln index c6129e3..fd2db97 100644 --- a/OmsiExtensions.sln +++ b/OmsiExtensions.sln @@ -15,87 +15,93 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OmsiHookInvoker", "OmsiHook EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OmsiHookRPCPlugin", "OmsiHookRPCPlugin\OmsiHookRPCPlugin.csproj", "{CDB17143-5653-48BE-AAC8-8419D5B4FD2C}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BasicCLI", "_OmsiHookExamples\BasicCLI\BasicCLI.csproj", "{BA833C68-E8BD-4C86-9555-85542DF02015}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventSample", "_OmsiHookExamples\EventSample\EventSample.csproj", "{47659503-9923-4E74-AD26-103C1F9FF2B0}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{3F0BF441-D76C-4E0D-A5A8-B20895438EA5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TriggersSample", "_OmsiHookExamples\TriggersSample\TriggersSample.csproj", "{1DF326AE-4D10-4545-B36A-5622B76987EC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VideoDemo", "_OmsiHookExamples\VideoDemo\VideoDemo.csproj", "{D94FF6D3-08AA-41CB-B9B9-F82E860E6E96}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 Release|x86 = Release|x86 + ReleaseAndDocs|x86 = ReleaseAndDocs|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {2E750CBE-F868-4AB7-96C2-27560F53E06B}.Debug|Any CPU.ActiveCfg = Debug|x86 - {2E750CBE-F868-4AB7-96C2-27560F53E06B}.Debug|Any CPU.Build.0 = Debug|x86 - {2E750CBE-F868-4AB7-96C2-27560F53E06B}.Debug|x64.ActiveCfg = Debug|x86 - {2E750CBE-F868-4AB7-96C2-27560F53E06B}.Debug|x64.Build.0 = Debug|x86 {2E750CBE-F868-4AB7-96C2-27560F53E06B}.Debug|x86.ActiveCfg = Debug|x86 {2E750CBE-F868-4AB7-96C2-27560F53E06B}.Debug|x86.Build.0 = Debug|x86 - {2E750CBE-F868-4AB7-96C2-27560F53E06B}.Release|Any CPU.ActiveCfg = Release|x86 - {2E750CBE-F868-4AB7-96C2-27560F53E06B}.Release|Any CPU.Build.0 = Release|x86 - {2E750CBE-F868-4AB7-96C2-27560F53E06B}.Release|x64.ActiveCfg = Release|x86 {2E750CBE-F868-4AB7-96C2-27560F53E06B}.Release|x86.ActiveCfg = Release|x86 - {28DA0165-EAA7-4171-A065-319409682BD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {28DA0165-EAA7-4171-A065-319409682BD1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {28DA0165-EAA7-4171-A065-319409682BD1}.Debug|x64.ActiveCfg = Debug|Any CPU - {28DA0165-EAA7-4171-A065-319409682BD1}.Debug|x64.Build.0 = Debug|Any CPU - {28DA0165-EAA7-4171-A065-319409682BD1}.Debug|x86.ActiveCfg = Debug|Any CPU - {28DA0165-EAA7-4171-A065-319409682BD1}.Debug|x86.Build.0 = Debug|Any CPU - {28DA0165-EAA7-4171-A065-319409682BD1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {28DA0165-EAA7-4171-A065-319409682BD1}.Release|Any CPU.Build.0 = Release|Any CPU - {28DA0165-EAA7-4171-A065-319409682BD1}.Release|x64.ActiveCfg = Release|Any CPU - {28DA0165-EAA7-4171-A065-319409682BD1}.Release|x64.Build.0 = Release|Any CPU - {28DA0165-EAA7-4171-A065-319409682BD1}.Release|x86.ActiveCfg = Release|Any CPU - {28DA0165-EAA7-4171-A065-319409682BD1}.Release|x86.Build.0 = Release|Any CPU - {FDA9A525-9722-46D3-B80C-8D2A76ABCA2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FDA9A525-9722-46D3-B80C-8D2A76ABCA2D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FDA9A525-9722-46D3-B80C-8D2A76ABCA2D}.Debug|x64.ActiveCfg = Debug|Any CPU - {FDA9A525-9722-46D3-B80C-8D2A76ABCA2D}.Debug|x64.Build.0 = Debug|Any CPU - {FDA9A525-9722-46D3-B80C-8D2A76ABCA2D}.Debug|x86.ActiveCfg = Debug|Any CPU - {FDA9A525-9722-46D3-B80C-8D2A76ABCA2D}.Debug|x86.Build.0 = Debug|Any CPU - {FDA9A525-9722-46D3-B80C-8D2A76ABCA2D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FDA9A525-9722-46D3-B80C-8D2A76ABCA2D}.Release|Any CPU.Build.0 = Release|Any CPU - {FDA9A525-9722-46D3-B80C-8D2A76ABCA2D}.Release|x64.ActiveCfg = Release|Any CPU - {FDA9A525-9722-46D3-B80C-8D2A76ABCA2D}.Release|x64.Build.0 = Release|Any CPU - {FDA9A525-9722-46D3-B80C-8D2A76ABCA2D}.Release|x86.ActiveCfg = Release|Any CPU - {FDA9A525-9722-46D3-B80C-8D2A76ABCA2D}.Release|x86.Build.0 = Release|Any CPU - {D5CA6EEA-D436-456E-BCA5-34C3DFD5BFC7}.Debug|Any CPU.ActiveCfg = Debug|x86 - {D5CA6EEA-D436-456E-BCA5-34C3DFD5BFC7}.Debug|Any CPU.Build.0 = Debug|x86 - {D5CA6EEA-D436-456E-BCA5-34C3DFD5BFC7}.Debug|x64.ActiveCfg = Debug|x86 - {D5CA6EEA-D436-456E-BCA5-34C3DFD5BFC7}.Debug|x64.Build.0 = Debug|x86 + {2E750CBE-F868-4AB7-96C2-27560F53E06B}.Release|x86.Build.0 = Release|x86 + {2E750CBE-F868-4AB7-96C2-27560F53E06B}.ReleaseAndDocs|x86.ActiveCfg = ReleaseAndDocs|x86 + {2E750CBE-F868-4AB7-96C2-27560F53E06B}.ReleaseAndDocs|x86.Build.0 = ReleaseAndDocs|x86 + {28DA0165-EAA7-4171-A065-319409682BD1}.Debug|x86.ActiveCfg = Debug|x86 + {28DA0165-EAA7-4171-A065-319409682BD1}.Debug|x86.Build.0 = Debug|x86 + {28DA0165-EAA7-4171-A065-319409682BD1}.Release|x86.ActiveCfg = Release|x86 + {28DA0165-EAA7-4171-A065-319409682BD1}.Release|x86.Build.0 = Release|x86 + {28DA0165-EAA7-4171-A065-319409682BD1}.ReleaseAndDocs|x86.ActiveCfg = Release|x86 + {28DA0165-EAA7-4171-A065-319409682BD1}.ReleaseAndDocs|x86.Build.0 = Release|x86 + {FDA9A525-9722-46D3-B80C-8D2A76ABCA2D}.Debug|x86.ActiveCfg = Debug|x86 + {FDA9A525-9722-46D3-B80C-8D2A76ABCA2D}.Debug|x86.Build.0 = Debug|x86 + {FDA9A525-9722-46D3-B80C-8D2A76ABCA2D}.Release|x86.ActiveCfg = Release|x86 + {FDA9A525-9722-46D3-B80C-8D2A76ABCA2D}.Release|x86.Build.0 = Release|x86 + {FDA9A525-9722-46D3-B80C-8D2A76ABCA2D}.ReleaseAndDocs|x86.ActiveCfg = Release|x86 + {FDA9A525-9722-46D3-B80C-8D2A76ABCA2D}.ReleaseAndDocs|x86.Build.0 = Release|x86 {D5CA6EEA-D436-456E-BCA5-34C3DFD5BFC7}.Debug|x86.ActiveCfg = Debug|x86 {D5CA6EEA-D436-456E-BCA5-34C3DFD5BFC7}.Debug|x86.Build.0 = Debug|x86 - {D5CA6EEA-D436-456E-BCA5-34C3DFD5BFC7}.Release|Any CPU.ActiveCfg = Release|x86 - {D5CA6EEA-D436-456E-BCA5-34C3DFD5BFC7}.Release|Any CPU.Build.0 = Release|x86 - {D5CA6EEA-D436-456E-BCA5-34C3DFD5BFC7}.Release|x64.ActiveCfg = Release|x86 {D5CA6EEA-D436-456E-BCA5-34C3DFD5BFC7}.Release|x86.ActiveCfg = Release|x86 {D5CA6EEA-D436-456E-BCA5-34C3DFD5BFC7}.Release|x86.Build.0 = Release|x86 - {CBCB99EF-DD1A-4D4D-A9A8-9BF251FDCD1B}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {CBCB99EF-DD1A-4D4D-A9A8-9BF251FDCD1B}.Debug|Any CPU.Build.0 = Debug|Win32 - {CBCB99EF-DD1A-4D4D-A9A8-9BF251FDCD1B}.Debug|x64.ActiveCfg = Debug|Win32 - {CBCB99EF-DD1A-4D4D-A9A8-9BF251FDCD1B}.Debug|x64.Build.0 = Debug|Win32 + {D5CA6EEA-D436-456E-BCA5-34C3DFD5BFC7}.ReleaseAndDocs|x86.ActiveCfg = Release|x86 + {D5CA6EEA-D436-456E-BCA5-34C3DFD5BFC7}.ReleaseAndDocs|x86.Build.0 = Release|x86 {CBCB99EF-DD1A-4D4D-A9A8-9BF251FDCD1B}.Debug|x86.ActiveCfg = Debug|Win32 {CBCB99EF-DD1A-4D4D-A9A8-9BF251FDCD1B}.Debug|x86.Build.0 = Debug|Win32 - {CBCB99EF-DD1A-4D4D-A9A8-9BF251FDCD1B}.Release|Any CPU.ActiveCfg = Release|Win32 - {CBCB99EF-DD1A-4D4D-A9A8-9BF251FDCD1B}.Release|Any CPU.Build.0 = Release|Win32 - {CBCB99EF-DD1A-4D4D-A9A8-9BF251FDCD1B}.Release|x64.ActiveCfg = Release|Win32 {CBCB99EF-DD1A-4D4D-A9A8-9BF251FDCD1B}.Release|x86.ActiveCfg = Release|Win32 {CBCB99EF-DD1A-4D4D-A9A8-9BF251FDCD1B}.Release|x86.Build.0 = Release|Win32 - {CDB17143-5653-48BE-AAC8-8419D5B4FD2C}.Debug|Any CPU.ActiveCfg = Debug|x86 - {CDB17143-5653-48BE-AAC8-8419D5B4FD2C}.Debug|Any CPU.Build.0 = Debug|x86 - {CDB17143-5653-48BE-AAC8-8419D5B4FD2C}.Debug|x64.ActiveCfg = Debug|x86 - {CDB17143-5653-48BE-AAC8-8419D5B4FD2C}.Debug|x64.Build.0 = Debug|x86 + {CBCB99EF-DD1A-4D4D-A9A8-9BF251FDCD1B}.ReleaseAndDocs|x86.ActiveCfg = Release|Win32 + {CBCB99EF-DD1A-4D4D-A9A8-9BF251FDCD1B}.ReleaseAndDocs|x86.Build.0 = Release|Win32 {CDB17143-5653-48BE-AAC8-8419D5B4FD2C}.Debug|x86.ActiveCfg = Debug|x86 {CDB17143-5653-48BE-AAC8-8419D5B4FD2C}.Debug|x86.Build.0 = Debug|x86 - {CDB17143-5653-48BE-AAC8-8419D5B4FD2C}.Release|Any CPU.ActiveCfg = Release|x86 - {CDB17143-5653-48BE-AAC8-8419D5B4FD2C}.Release|Any CPU.Build.0 = Release|x86 - {CDB17143-5653-48BE-AAC8-8419D5B4FD2C}.Release|x64.ActiveCfg = Release|x86 {CDB17143-5653-48BE-AAC8-8419D5B4FD2C}.Release|x86.ActiveCfg = Release|x86 {CDB17143-5653-48BE-AAC8-8419D5B4FD2C}.Release|x86.Build.0 = Release|x86 + {CDB17143-5653-48BE-AAC8-8419D5B4FD2C}.ReleaseAndDocs|x86.ActiveCfg = Release|x86 + {CDB17143-5653-48BE-AAC8-8419D5B4FD2C}.ReleaseAndDocs|x86.Build.0 = Release|x86 + {BA833C68-E8BD-4C86-9555-85542DF02015}.Debug|x86.ActiveCfg = Debug|x86 + {BA833C68-E8BD-4C86-9555-85542DF02015}.Debug|x86.Build.0 = Debug|x86 + {BA833C68-E8BD-4C86-9555-85542DF02015}.Release|x86.ActiveCfg = Release|x86 + {BA833C68-E8BD-4C86-9555-85542DF02015}.Release|x86.Build.0 = Release|x86 + {BA833C68-E8BD-4C86-9555-85542DF02015}.ReleaseAndDocs|x86.ActiveCfg = Release|x86 + {BA833C68-E8BD-4C86-9555-85542DF02015}.ReleaseAndDocs|x86.Build.0 = Release|x86 + {47659503-9923-4E74-AD26-103C1F9FF2B0}.Debug|x86.ActiveCfg = Debug|x86 + {47659503-9923-4E74-AD26-103C1F9FF2B0}.Debug|x86.Build.0 = Debug|x86 + {47659503-9923-4E74-AD26-103C1F9FF2B0}.Release|x86.ActiveCfg = Release|x86 + {47659503-9923-4E74-AD26-103C1F9FF2B0}.Release|x86.Build.0 = Release|x86 + {47659503-9923-4E74-AD26-103C1F9FF2B0}.ReleaseAndDocs|x86.ActiveCfg = Release|x86 + {47659503-9923-4E74-AD26-103C1F9FF2B0}.ReleaseAndDocs|x86.Build.0 = Release|x86 + {1DF326AE-4D10-4545-B36A-5622B76987EC}.Debug|x86.ActiveCfg = Debug|x86 + {1DF326AE-4D10-4545-B36A-5622B76987EC}.Debug|x86.Build.0 = Debug|x86 + {1DF326AE-4D10-4545-B36A-5622B76987EC}.Release|x86.ActiveCfg = Release|x86 + {1DF326AE-4D10-4545-B36A-5622B76987EC}.Release|x86.Build.0 = Release|x86 + {1DF326AE-4D10-4545-B36A-5622B76987EC}.ReleaseAndDocs|x86.ActiveCfg = Release|x86 + {1DF326AE-4D10-4545-B36A-5622B76987EC}.ReleaseAndDocs|x86.Build.0 = Release|x86 + {D94FF6D3-08AA-41CB-B9B9-F82E860E6E96}.Debug|x86.ActiveCfg = Debug|x86 + {D94FF6D3-08AA-41CB-B9B9-F82E860E6E96}.Debug|x86.Build.0 = Debug|x86 + {D94FF6D3-08AA-41CB-B9B9-F82E860E6E96}.Release|x86.ActiveCfg = Release|x86 + {D94FF6D3-08AA-41CB-B9B9-F82E860E6E96}.Release|x86.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 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {BA833C68-E8BD-4C86-9555-85542DF02015} = {3F0BF441-D76C-4E0D-A5A8-B20895438EA5} + {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} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A5F55305-C8FF-444C-9B98-FD487ADC583A} EndGlobalSection diff --git a/OmsiExtensionsCLI/OmsiExtensionsCLI.csproj b/OmsiExtensionsCLI/OmsiExtensionsCLI.csproj index 8af62ea..0bfd17a 100644 --- a/OmsiExtensionsCLI/OmsiExtensionsCLI.csproj +++ b/OmsiExtensionsCLI/OmsiExtensionsCLI.csproj @@ -1,13 +1,19 @@ - + Exe net6.0-windows x86 + x86 + favicon.ico + + + + diff --git a/OmsiExtensionsCLI/Program.cs b/OmsiExtensionsCLI/Program.cs index 8655891..9a59d3e 100644 --- a/OmsiExtensionsCLI/Program.cs +++ b/OmsiExtensionsCLI/Program.cs @@ -1,4 +1,7 @@ using System; +using System.Linq; +using System.Numerics; +using System.Reflection; using System.Threading; using OmsiHook; @@ -17,34 +20,54 @@ static void Main(string[] args) dXTests.Init(omsi); bool toggle = false; var playerVehicle = omsi.Globals.PlayerVehicle; + var progMan = omsi.Globals.ProgamManager; + var meshes = playerVehicle?.ComplObjInst?.ComplObj?.Meshes; + var meshInsts = playerVehicle?.ComplObjInst?.AnimSubMeshInsts; + var map = omsi.Globals.Map; + var cam = omsi.Globals.Camera; + var weather = omsi.Globals.Weather; + var tickets = omsi.Globals.TicketPack; + var materialMan = omsi.Globals.MaterialMan; + var textureMan = omsi.Globals.TextureMan; + var textures = textureMan?.TextureItems; + var roadVehicles = omsi.Globals.RoadVehicles; while (true) { playerVehicle ??= omsi.Globals.PlayerVehicle; - var pos = playerVehicle?.Position ?? default; - var posa = playerVehicle?.AbsPosition ?? default; - var vel = playerVehicle?.Velocity ?? default; - var map = omsi.Globals.Map; - var cam = omsi.Globals.Camera; - var camPos = cam?.Pos ?? default; - var weather = omsi.Globals.Weather; - var tickets = omsi.Globals.TicketPack; - var humans = omsi.Globals.Humans; + progMan ??= omsi.Globals.ProgamManager; + meshes ??= playerVehicle?.ComplObjInst?.ComplObj?.Meshes; + meshInsts ??= playerVehicle?.ComplObjInst?.AnimSubMeshInsts; + map ??= omsi.Globals.Map; + cam ??= omsi.Globals.Camera; + weather ??= omsi.Globals.Weather; + tickets = omsi.Globals.TicketPack; + materialMan ??= omsi.Globals.MaterialMan; + textureMan ??= omsi.Globals.TextureMan; + textures ??= textureMan?.TextureItems; + roadVehicles ??= omsi.Globals.RoadVehicles; Console.SetCursorPosition(0, 0); - Console.WriteLine(($"Read data: x:{pos.x:F3} y:{pos.y:F3} z:{pos.z:F3} " + - $"tile:{playerVehicle?.Kachel??0}").PadRight(Console.WindowWidth - 1)); - Console.WriteLine($"Read data: vx:{vel.x:F3} vy:{vel.y:F3} vz:{vel.z:F3}".PadRight(Console.WindowWidth-1)); - Console.WriteLine($"Read data: ax:{posa._30:F3} ay:{posa._31:F3} az:{posa._32:F3}".PadRight(Console.WindowWidth-1)); - - Console.WriteLine($"Read data: map:{map?.Name} path:{map?.Filename} friendly:{map?.FriendlyName}".PadRight(Console.WindowWidth-1)); - Console.WriteLine($"{omsi.Globals.Time.Day}/{omsi.Globals.Time.Month}/{omsi.Globals.Time.Year} - {omsi.Globals.Time.Hour}:{omsi.Globals.Time.Minute}:{omsi.Globals.Time.Second:F2}"); - Console.WriteLine($"Camera data: x:{camPos.x:F3} y:{camPos.y:F3} z:{camPos.z:F3} ".PadRight(Console.WindowWidth - 1)); + Console.WriteLine($"Vehicle pos: {playerVehicle.Position} tile: {playerVehicle?.Kachel ?? 0}".PadRight(Console.WindowWidth - 1)); + Console.WriteLine($"Vehicle vel: {playerVehicle.Velocity}".PadRight(Console.WindowWidth - 1)); + Console.WriteLine($"Vehicle pos_abs: {playerVehicle.AbsPosition.Position}".PadRight(Console.WindowWidth - 1)); + + Console.WriteLine($"Read data: map:{map?.Name} path:{map?.Filename} friendly:{map?.FriendlyName}".PadRight(Console.WindowWidth - 1)); + Console.WriteLine($"Time: {omsi.Globals.Time.Day}/{omsi.Globals.Time.Month}/{omsi.Globals.Time.Year} - {omsi.Globals.Time.Hour}:{omsi.Globals.Time.Minute}:{omsi.Globals.Time.Second:F2} "); + Console.WriteLine($"Camera pos: {cam.Pos} ".PadRight(Console.WindowWidth - 1)); Console.WriteLine($"{omsi.Globals.Drivers}".PadRight(Console.WindowWidth - 1)); - if(!dXTests.IsReady) + /*if(!dXTests.IsReady) dXTests.CreateTexture(); if(dXTests.IsReady) - dXTests.UpdateTexture(); + dXTests.UpdateTexture();*/ + + Console.WriteLine($"[MOUSE] pos: {progMan.MausPos}".PadRight(Console.WindowWidth - 1)); + Console.WriteLine($"[MOUSE] ray_pos: {progMan.MausLine3DPos} ray_dir: {progMan.MausLine3DDir}".PadRight(Console.WindowWidth - 1)); + Console.WriteLine($"[MOUSE] mouse_mesh_event: {progMan.Maus_MeshEvent}".PadRight(Console.WindowWidth - 1)); + CheckClickPos(progMan, meshes, meshInsts); + + Console.WriteLine($"Loaded textures: {textures.Count}"); + Console.WriteLine($"Path id: {playerVehicle.PathInfo.path.path}"); /*Console.WriteLine("".PadRight(Console.WindowWidth-1)); try @@ -63,6 +86,63 @@ static void Main(string[] args) Thread.Sleep(20); } } + + private static void CheckClickPos(OmsiProgMan progMan, MemArrayList meshes, MemArrayList meshInsts) + { + // A small experiment, with the aim of being able to determine where the user clicks on an object in local space. + if (meshes != null) + { + /*int i = 0; + foreach (var mesh in meshes) + { + if (mesh.MausEvent != null) + { + Console.WriteLine($" Mesh '{mesh.Filename_Int}' has event: {mesh.MausEvent}"); + i++; + } + if (i > 20) + { + Console.WriteLine(" ..."); + break; + } + }*/ + } + OmsiAnimSubMesh clickMesh = null; + OmsiAnimSubMeshInst clickMeshInst = null; + string mouseEventName = "INEO_Click"; + if (meshes != null) + clickMesh = meshes.FirstOrDefault(mesh => mesh.MausEvent == mouseEventName); + if (clickMesh != null) + clickMeshInst = meshInsts[meshes.IndexOf(clickMesh)]; + if (clickMesh != null && progMan.Maus_MeshEvent == mouseEventName && (progMan.Maus_Clicked)) + { + // Work out object space coords of the mouse click + // Note that (if wrapped) we could use D3DXIntersect to find the UV coords given the submesh's d3d mesh + + // Transform the mouse ray from world space to object space + Matrix4x4.Invert((Matrix4x4)clickMeshInst.Matrix, out Matrix4x4 invMat); + Matrix4x4.Invert(clickMesh.OriginMatrix, out Matrix4x4 invOriginMat); + invMat = Matrix4x4.Multiply(invMat, invOriginMat); + + var rayStart = Vector3.Transform(progMan.MausLine3DPos, invMat); + var rayDir = Vector3.Transform(progMan.MausLine3DDir, invMat); + // Now trace the ray, in our simplification we assume the surface of the mesh we want to hit is coplanar to the xz plane + // Taken from: https://stackoverflow.com/a/18543221 + Vector3 planeNrm = new(0, 1, 0); + float planeD = 0; + float dot = Vector3.Dot(planeNrm, rayDir); + var intersect = new Vector3(); + if (Math.Abs(dot) > 1e-9) + { + var w = rayStart - planeNrm * planeD; + var fac = -Vector3.Dot(planeNrm, w) / dot; + var u = rayDir * fac; + intersect = rayStart + u; + } + + Console.WriteLine($" Clicked on {clickMesh.Filename_Int} at local coords: {(D3DVector)intersect}"); + } + } } public class DXTests @@ -115,6 +195,9 @@ public void CreateTexture() public void UpdateTexture() { + // Note that writing texture data like this is very slow, if possible, try to use SIMD accelerated + // operations (such as those in System.Numerics) or if you need to copy data into a texture buffer + // System.Buffer.BlockCopy() is extremely fast. for (int y = 0; y < texHeight; y++) for(int x = 0; x < texWidth; x++) { diff --git a/OmsiHook/images/favicon.ico b/OmsiExtensionsCLI/favicon.ico similarity index 100% rename from OmsiHook/images/favicon.ico rename to OmsiExtensionsCLI/favicon.ico diff --git a/OmsiExtensionsUI/OmsiExtensionsUI.csproj b/OmsiExtensionsUI/OmsiExtensionsUI.csproj index 871c1a7..ced68a6 100644 --- a/OmsiExtensionsUI/OmsiExtensionsUI.csproj +++ b/OmsiExtensionsUI/OmsiExtensionsUI.csproj @@ -3,6 +3,7 @@ WinExe net6.0-windows enable + x86 diff --git a/OmsiHook/.gitignore b/OmsiHook/.gitignore index 4378419..260486e 100644 --- a/OmsiHook/.gitignore +++ b/OmsiHook/.gitignore @@ -6,4 +6,5 @@ /**/packages/ /**/bin/ /**/obj/ -_site +/**/_site/ +docfx_log.txt diff --git a/OmsiHook/CustomAttributes.cs b/OmsiHook/CustomAttributes.cs index 7febc9a..a026f7d 100644 --- a/OmsiHook/CustomAttributes.cs +++ b/OmsiHook/CustomAttributes.cs @@ -160,7 +160,7 @@ public OmsiObjPtrAttribute(Type objType) } /// - /// Marks a field to be converted from an int to an . + /// Marks a field to be converted from an int to an OmsiObject[]. /// Used by /// [System.AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)] diff --git a/OmsiHook/D3DTexture.cs b/OmsiHook/D3DTexture.cs index ff4a2d3..f04aeb9 100644 --- a/OmsiHook/D3DTexture.cs +++ b/OmsiHook/D3DTexture.cs @@ -44,15 +44,32 @@ public D3DTexture() : base() { } /// /// Returns true if this object is initialised. /// - public bool IsValid => TextureAddress != 0; + public bool IsValid => TextureAddress != 0 && isCreated; + /// + /// Returns true if this texture is valid and can be written too. + /// + public bool CanWrite => IsValid && remoteStagingBufferPtr != 0; + + private volatile bool isCreated = false; + + internal override void InitObject(Memory memory, int address) + { + base.InitObject(memory, address); + // This method may be called repeadedly when marshalling an array of textures. To save performance, + // we don't await the texture creation (which reads the width/height/... of the texture) and don't + // enable writing by default. + if(address != 0) + _ = CreateFromExisting((uint)address, false); + } /// /// Initialises this from an existing IDirect3DTexture9. /// /// the address of the existing texture + /// whether to allow writing to this texture /// /// - public async Task CreateFromExisting(uint address) + public async Task CreateFromExisting(uint address, bool initialiseForWriting = true) { if (Address == 0) throw new NullReferenceException("Texture was already null!"); @@ -67,6 +84,18 @@ public async Task CreateFromExisting(uint address) Address = unchecked((int)address); stagingBufferSize = (int)width * (int)height * BitsPerPixel(format) / 8; //stagingBuffer = new byte[stagingBufferSize]; + if(initialiseForWriting) + remoteStagingBufferPtr = unchecked((uint)await Memory.AllocRemoteMemory(stagingBufferSize, fastAlloc: true)); + isCreated = true; + } + + /// + /// Initialises the texture for writing operations. + /// + public async Task InitialiseForWriting() + { + if (!IsValid) + throw new NotInitialisedException("The texture has not been created yet! Make sure to call CreateD3DTexture()."); remoteStagingBufferPtr = unchecked((uint)await Memory.AllocRemoteMemory(stagingBufferSize, fastAlloc: true)); } @@ -76,8 +105,9 @@ public async Task CreateFromExisting(uint address) /// the width of the texture /// the height of the texture /// the of the texture + /// whether to allow writing to this texture /// - public async Task CreateD3DTexture(uint width, uint height, D3DFORMAT format = D3DFORMAT.D3DFMT_A8R8G8B8) + public async Task CreateD3DTexture(uint width, uint height, D3DFORMAT format = D3DFORMAT.D3DFMT_A8R8G8B8, bool initialiseForWriting = true) { if(Address != 0) await ReleaseTexture(); @@ -92,7 +122,9 @@ public async Task CreateD3DTexture(uint width, uint height, D3DFORMAT format = D Address = unchecked((int)pTexture); stagingBufferSize = (int)width * (int)height * BitsPerPixel(format) / 8; //stagingBuffer = new byte[stagingBufferSize]; - remoteStagingBufferPtr = unchecked((uint)await Memory.AllocRemoteMemory(stagingBufferSize, fastAlloc: true)); + if (initialiseForWriting) + remoteStagingBufferPtr = unchecked((uint)await Memory.AllocRemoteMemory(stagingBufferSize, fastAlloc: true)); + isCreated = true; } /// @@ -105,6 +137,7 @@ public async Task ReleaseTexture() if(Address == 0) throw new NullReferenceException("Texture was already null!"); + isCreated = false; HRESULT hr = await OmsiReleaseTextureAsync(unchecked((uint)Address)); if(HRESULTFailed(hr)) throw new Exception(hr.ToString()); @@ -125,6 +158,8 @@ public async Task ReleaseTexture() /// public async Task UpdateTexture(Memory textureData, Rectangle? updateArea = null) where T : unmanaged { + if (!IsInitialised || remoteStagingBufferPtr == 0) + throw new NotInitialisedException("D3DTexture object must be initialised for write before it can be updated! "); if((textureData.Length * Marshal.SizeOf()) > stagingBufferSize) throw new ArgumentOutOfRangeException(nameof(textureData)); Memory.WriteMemory(remoteStagingBufferPtr, textureData); diff --git a/OmsiHook/MemArray.cs b/OmsiHook/MemArray.cs deleted file mode 100644 index ff0a1eb..0000000 --- a/OmsiHook/MemArray.cs +++ /dev/null @@ -1,506 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; - -namespace OmsiHook -{ - /// - /// Wrapper for Arrays / Lists in OMSI's Memory. - /// - /// - /// This is a heavyweight wrapper for native arrays that provides methods for reading and writing to arrays as well as - /// helping with memory management. For fast, low-level access, use the methods in the class. - /// For better performance in c# the contents of the wrapped array can be copied to managed memory when constructed - /// or whenever is called. - /// Cached arrays are generally faster when accessed or searched frequently by C#, but they are slower to update and - /// the user is responsible for ensuring that they are synchronised with the native array it wraps. - /// - /// The type of struct to wrap - /// Internal struct type to marshal Struct from - public class MemArray : MemArrayBase - where InternalStruct : unmanaged - where Struct : struct - { - - /// - /// Gets the current contents of the wrapped array. On non-cached arrays this is slow. - /// - public override Struct[] WrappedArray => cached ? arrayCache - : Memory.MarshalStructs(Memory.ReadMemoryStructArray(Address)); - - public MemArray() : base() { } - - internal MemArray(Memory memory, int address, bool cached = true) : base(memory, address, cached) { } - - public override void UpdateFromHook(int index = -1) - { - if (cached) - { - if (index < 0) - arrayCache = Memory.MarshalStructs(Memory.ReadMemoryStructArray(Address)); - else - arrayCache[index] = Memory.MarshalStruct(Memory.ReadMemoryArrayItem(Address, index)); - } - } - - public override Struct this[int index] - { - get => cached ? arrayCache[index] - : Memory.MarshalStruct( - Memory.ReadMemoryArrayItemSafe(Address, index)); - set - { - if (cached) - arrayCache[index] = value; - Memory.WriteMemoryArrayItemSafe(Address, Memory.UnMarshalStruct(value), index); - } - } - - /// - /// TODO: Implement efficient enumerator for non-cached arrays. - /// - /// - public override IEnumerator GetEnumerator() => ((IEnumerable)WrappedArray).GetEnumerator(); - - /// - /// Adds an item to the native array. This is slow and might cause memory leaks because it reallocates the whole array. - /// - /// - /// Since this method doesn't call , if the native array is out of sync - /// with the cached array, then data may be lost when adding new items. - /// In the following case though, it should usually be safe (as long as the native array isn't updated by Omsi while this runs): - /// - /// memArray.UpdateFromHook(); - /// foreach(int item in localObjects) - /// memArray.Add(item); - /// - /// - /// The item to add to the native array. - public override void Add(Struct item) - { - int arr = Memory.ReadMemory(Address); - int len = Memory.ReadMemory(arr - 4); - int narr = Memory.AllocateStructArray(++len).Result; - Memory.WriteMemory(Address, narr); - if (cached) - { - // Copy native array from cache - for (int i = 0; i < Math.Min(len, arrayCache.Length); i++) - Memory.WriteMemoryArrayItem(narr, Memory.UnMarshalStruct(arrayCache[i]), i); - - // Update cached array - Array.Resize(ref arrayCache, len); - arrayCache[len - 1] = item; - } - else - { - // Copy native array - Memory.CopyMemory(arr, narr, (len-1) * Marshal.SizeOf()); - } - - // Add the new item to the native array - Memory.WriteMemoryArrayItem(Address, Memory.UnMarshalStruct(item), len - 1); - } - - public override void Clear() - { - base.Clear(); - if(cached) - arrayCache = Array.Empty(); - } - - public override bool Remove(Struct item) => throw new NotImplementedException(); - - public override void Insert(int index, Struct item) => throw new NotImplementedException(); - - public override void RemoveAt(int index) => throw new NotImplementedException(); - - public override int IndexOf(Struct item) => Array.IndexOf(WrappedArray, item); - - public override bool Contains(Struct item) => WrappedArray.Contains(item); - - public override void CopyTo(Struct[] array, int arrayIndex) => WrappedArray.CopyTo(array, arrayIndex); - } - - /// - /// Wrapper for Arrays / Lists in OMSI's Memory. - /// - /// - /// This is a heavyweight wrapper for native arrays that provides methods for reading and writing to arrays as well as - /// helping with memory management. For fast, low-level access, use the methods in the class. - /// For better performance in c# the contents of the wrapped array can be copied to managed memory when constructed - /// or whenever is called. - /// Cached arrays are generally faster when accessed or searched frequently by C#, but they are slower to update and - /// the user is responsible for ensuring that they are synchronised with the native array it wraps. - /// - /// The type of struct to wrap. - public class MemArray : MemArray where T : unmanaged - { - public override T[] WrappedArray => cached ? arrayCache : Memory.ReadMemoryStructArray(Address); - - public MemArray() : base() { } - internal MemArray(Memory memory, int address, bool cached = true) : base(memory, address, cached) { } - - public override void UpdateFromHook(int index = -1) - { - if (cached) - { - if(index >= 0) - arrayCache[index] = Memory.ReadMemoryArrayItem(Address, index); - else - arrayCache = Memory.ReadMemoryStructArray(Address); - } - } - - public override T this[int index] - { - get => cached ? arrayCache [index] : Memory.ReadMemoryArrayItemSafe(Address, index); - set - { - if (cached) - arrayCache[index] = value; - Memory.WriteMemoryArrayItemSafe(Address, value, index); - } - } - - /// - /// Adds an item to the native array. This is slow and might cause memory leaks because it reallocates the whole array. - /// - /// - /// Since this method doesn't call , if the native array is out of sync - /// with the cached array, then data may be lost when adding new items. - /// In the following case though, it should usually be safe (as long as the native array isn't updated by Omsi while this runs): - /// - /// memArray.UpdateFromHook(); - /// foreach(int item in localObjects) - /// memArray.Add(item); - /// - /// - /// The item to add to the native array. - public override void Add(T item) - { - int arr = Memory.ReadMemory(Address); - int len = Memory.ReadMemory(arr - 4); - int narr = Memory.AllocateStructArray(++len).Result; - Memory.WriteMemory(Address, narr); - if(cached) - { - // Copy native array from cache - for(int i = 0; i < Math.Min(len, arrayCache.Length); i++) - Memory.WriteMemoryArrayItem(narr, arrayCache[i], i); - - // Update cached array - Array.Resize(ref arrayCache, len); - arrayCache[len - 1] = item; - } - else - { - // Copy native array - Memory.CopyMemory(arr, narr, (len - 1) * Marshal.SizeOf()); - } - - // Add the new item to the native array - Memory.WriteMemoryArrayItem(Address, item, len-1); - } - - /// - /// Clears the native array but maintains the reference to prevent the GC from destroying it. - /// - public override void Clear() - { - base.Clear(); - if (cached) - arrayCache = Array.Empty(); - } - - public override bool Remove(T item) => throw new NotImplementedException(); - - public override void Insert(int index, T item) => throw new NotImplementedException(); - - public override void RemoveAt(int index) => throw new NotImplementedException(); - } - - /// - /// Wrapper for Arrays / Lists in OMSI's Memory. - /// - /// - /// This is a heavyweight wrapper for native arrays that provides methods for reading and writing to arrays as well as - /// helping with memory management. For fast, low-level access, use the methods in the class. - /// For better performance in c# the contents of the wrapped array can be copied to managed memory when constructed - /// or whenever is called. - /// Cached arrays are generally faster when accessed or searched frequently by C#, but they are slower to update and - /// the user is responsible for ensuring that they are synchronised with the native array it wraps. - /// - /// The type of struct to wrap. - public class MemArrayPtr : MemArray where T : unmanaged - { - public override T[] WrappedArray => cached ? arrayCache : Memory.ReadMemoryStructPtrArray(Address); - - public MemArrayPtr() : base() { } - internal MemArrayPtr(Memory memory, int address, bool cached = true) : base(memory, address, cached) { } - - public override void UpdateFromHook(int index = -1) - { - if (cached) - { - if(index >= 0) - arrayCache[index] = Memory.ReadMemoryArrayItem(Address, index, true); - else - arrayCache = Memory.ReadMemoryStructPtrArray(Address); - } - } - - public override T this[int index] - { - get => cached ? arrayCache[index] : Memory.ReadMemoryArrayItemSafe(Address, index, true); - set - { - if (cached) - arrayCache[index] = value; - Memory.WriteMemoryArrayItemSafe(Address, value, index, true); - } - } - - public override void Add(T item) - { - int arr = Memory.ReadMemory(Address); - int len = Memory.ReadMemory(arr - 4); - var allocTask = Task.WhenAll(Memory.AllocateStructArray(++len), Memory.AllocateStruct(item)); - int narr = allocTask.Result[0]; - int ndata = allocTask.Result[1]; - Memory.WriteMemory(Address, narr); - if (cached) - { - // Copy native array - Memory.CopyMemory(arr, narr, (len - 1) * 4); - - // Update cached array - Array.Resize(ref arrayCache, len); - arrayCache[len - 1] = item; - } - else - { - // Copy native array - Memory.CopyMemory(arr, narr, (len - 1) * 4); - } - - // Add the new item to the native array - Memory.WriteMemoryArrayItem(Address, ndata, len - 1, false); - } - - /// - /// Clears the native array but maintains the reference to prevent the GC from destroying it. - /// Note that this does not free or dereference the items pointed to by the array elements. - /// - public override void Clear() - { - base.Clear(); - if (cached) - arrayCache = Array.Empty(); - } - - public override bool Remove(T item) => throw new NotImplementedException(); - - public override void Insert(int index, T item) => throw new NotImplementedException(); - - public override void RemoveAt(int index) => throw new NotImplementedException(); - } - - /// - /// Wrapper for Arrays / Lists in OMSI's Memory. - /// - /// - /// This is a heavyweight wrapper for native arrays that provides methods for reading and writing to arrays as well as - /// helping with memory management. For fast, low-level access, use the methods in the class. - /// For better performance in c# the contents of the wrapped array can be copied to managed memory when constructed - /// or whenever is called. - /// Cached arrays are generally faster when accessed or searched frequently by C#, but they are slower to update and - /// the user is responsible for ensuring that they are synchronised with the native array it wraps. - /// - public class MemArrayString : MemArrayBase - { - internal readonly bool wide; - - public override string this[int index] - { - get => cached ? arrayCache[index] : Memory.ReadMemoryArrayItemStringSafe(Address, index, wide); - set - { - if (cached) - arrayCache[index] = value; - Memory.WriteMemoryArrayItemSafe(Address, Memory.AllocateString(value).Result, index); - } - } - - public override string[] WrappedArray => cached ? arrayCache - : Memory.ReadMemoryStringArray(Address, wide); - - /// - /// Whether or not the string is in UTF-16. - /// - public bool Wide => wide; - - public MemArrayString() : base() { } - /// - /// Constructs a new MemArray to wrap a native array at a given address. - /// - /// Instance of the memory manager - /// Address of the native array to wrap - /// Whether or not the string is in UTF-16 - /// Whether or not to copy the contents of the array to a local cache - internal MemArrayString(Memory memory, int address, bool wide = false, bool cached = true) : base(memory, address, cached) - { - this.wide = wide; - } - - public override void UpdateFromHook(int index = -1) - { - if (cached) - { - if(index >= 0) - arrayCache[index] = Memory.ReadMemoryArrayItemString(Address, index, wide); - else - arrayCache = Memory.ReadMemoryStringArray(Address, wide); - } - } - - /// - /// Adds an item to the native array. This is slow and might cause memory leaks because it reallocates the whole array. - /// - /// - /// This method is probably slower (and much more memory intensive) on cached arrays. - /// Since this method doesn't call , if the native array is out of sync - /// with the cached array, then data may be lost when adding new items. - /// In the following case though, it should usually be safe (as long as the native array isn't updated by Omsi while this runs): - /// - /// memArray.UpdateFromHook(); - /// foreach(int item in localObjects) - /// memArray.Add(item); - /// - /// - /// The item to add to the native array. - public override void Add(string item) - { - int arr = Memory.ReadMemory(Address); - int len = Memory.ReadMemory(arr - 4); - int narr = Memory.AllocateStructArray(++len).Result; - Memory.WriteMemory(Address, narr); - if (cached) - { - // Copy native array from cache, this will never be faster... - /*Span allocatedStrings = stackalloc int[Math.Min(len, arrayCache.Length)]; - Task.WhenAll(); - for (int i = 0; i < allocatedStrings.Length; i++) - allocatedStrings[i] = Memory.AllocateString(arrayCache[i]); - for (int i = 0; i < Math.Min(len, arrayCache.Length); i++) - Memory.WriteMemoryArrayItem(narr, allocatedStrings[i], i);*/ - // Copy native array - Memory.CopyMemory(arr, narr, (len - 1) * Marshal.SizeOf()); - - // Update cached array - Array.Resize(ref arrayCache, len); - arrayCache[len - 1] = item; - } - else - { - // Copy native array - Memory.CopyMemory(arr, narr, (len - 1) * Marshal.SizeOf()); - } - - // Add the new item to the native array - Memory.WriteMemoryArrayItem(Address, Memory.AllocateString(item).Result, len - 1); - } - - public override void Clear() - { - base.Clear(); - if (cached) - arrayCache = Array.Empty(); - } - - public override bool Contains(string item) => WrappedArray.Contains(item); - - public override void CopyTo(string[] array, int arrayIndex) => WrappedArray.CopyTo(array, arrayIndex); - - //TODO: Implement efficient enumerator for non-cached arrays. - public override IEnumerator GetEnumerator() => (IEnumerator)WrappedArray.GetEnumerator(); - - public override int IndexOf(string item) => Array.IndexOf(WrappedArray, item); - - public override void Insert(int index, string item) => throw new NotImplementedException(); - - public override bool Remove(string item) => throw new NotImplementedException(); - - public override void RemoveAt(int index) => throw new NotImplementedException(); - } - - /// - /// Wrapper for Arrays / Lists in OMSI's Memory with automatic index caching. - /// - /// - /// This type of MemArray relies on it being cached and as such no option exists to use it uncached. - /// This is a heavyweight wrapper for native arrays that provides methods for reading and writing to arrays as well as - /// helping with memory management. For fast, low-level access, use the methods in the class. - /// For better performance in c# the contents of the wrapped array can be copied to managed memory when constructed - /// or whenever is called. - /// Cached arrays are generally faster when accessed or searched frequently by C#, but they are slower to update and - /// the user is responsible for ensuring that they are synchronised with the native array it wraps. - /// - public class MemArrayStringDict : MemArrayString - { - private Dictionary indexDictionary = new(); - - public Dictionary IndexDictionary => indexDictionary; - - internal MemArrayStringDict(Memory memory, int address, bool wide = false) : base(memory, address, wide, true) { } - public MemArrayStringDict() : base() { } - - /// - /// Gets the index of the string in the native array from it's value. - /// - /// - /// - public int this[string item] => indexDictionary[item]; - - public override bool Cached { get => cached; } - - public override void UpdateFromHook(int index = -1) - { - if (index >= 0) - { - string prevValue = arrayCache[index]; - base.UpdateFromHook(index); - if (prevValue != arrayCache[index]) - { - indexDictionary.Remove(prevValue); - indexDictionary.Add(arrayCache[index], index); - } - } - else - { - base.UpdateFromHook(index); - indexDictionary.Clear(); - for (int i = 0; i < Count; i++) - { - if (arrayCache[i] != null) - indexDictionary.TryAdd(arrayCache[i], i); - } - } - } - - public override bool Contains(string item) => indexDictionary.ContainsKey(item); - public override int IndexOf(string item) => indexDictionary[item]; - public override bool Remove(string item) - { - if (indexDictionary.ContainsKey(item)) - base.RemoveAt(indexDictionary[item]); - else - return false; - return true; - } - } -} diff --git a/OmsiHook/MemArrayBase.cs b/OmsiHook/MemArray/MemArrayBase.cs similarity index 78% rename from OmsiHook/MemArrayBase.cs rename to OmsiHook/MemArray/MemArrayBase.cs index 5ab5284..748dea5 100644 --- a/OmsiHook/MemArrayBase.cs +++ b/OmsiHook/MemArray/MemArrayBase.cs @@ -4,6 +4,18 @@ namespace OmsiHook { + /// + /// Base class for wrappers for Arrays / Lists in OMSI's Memory. + /// + /// + /// This is a heavyweight wrapper for native arrays that provides methods for reading and writing to arrays as well as + /// helping with memory management. For fast, low-level access, use the methods in the class. + /// For better performance in c# the contents of the wrapped array can be copied to managed memory when constructed + /// or whenever is called. + /// Cached arrays are generally faster when accessed or searched frequently by C#, but they are slower to update and + /// the user is responsible for ensuring that they are synchronised with the native array it wraps. + /// + /// The type of struct to wrap public abstract class MemArrayBase : OmsiObject, IDisposable, IEnumerable, ICollection, IList { internal bool cached; @@ -23,12 +35,13 @@ public int Count get { if (cached) - return arrayCache.Length; + return arrayCache?.Length ?? 0; else { int start = Memory.ReadMemory(Address); if (start == 0) - throw new NullReferenceException(); + return 0; + //throw new NullReferenceException(); return Memory.ReadMemory(start - 4); } } diff --git a/OmsiHook/MemArray/MemArrayObjList.cs b/OmsiHook/MemArray/MemArrayObjList.cs new file mode 100644 index 0000000..e974cc8 --- /dev/null +++ b/OmsiHook/MemArray/MemArrayObjList.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OmsiHook +{ + /// + /// Wrapper for Lists in OMSI's Memory. + /// + /// + /// + /// + /// + public class MemArrayList : MemArrayBase where T : OmsiObject, new() + { + private T[] ReadList() + { + uint arr = Memory.ReadMemory(Address); + if (arr == 0) + return Array.Empty(); + uint len = Memory.ReadMemory(arr + 8); + uint arrayData = Memory.ReadMemory(arr + 4); + T[] ret = new T[len]; + for (uint i = 0; i < len; i++) + { + var objAddr = Memory.ReadMemory(arrayData + i * 4); + if (objAddr == 0) + { + ret[i] = null; + continue; + } + + var n = new T(); + n.InitObject(Memory, (int)objAddr); + ret[i] = n; + } + + return ret; + } + + private T ReadListItem(int index) + { + int arr = Memory.ReadMemory(Address); + if (arr == 0) + return null; + + int len = Memory.ReadMemory(arr + 8); + int arrayData = Memory.ReadMemory(arr + 4); + + if (index >= len || index < 0) + throw new ArgumentOutOfRangeException(nameof(index)); + + var objAddr = Memory.ReadMemory(arrayData + index * 4); + if (objAddr == 0) + return null; + + var n = new T(); + n.InitObject(Memory, objAddr); + + return n; + } + + /// + /// Gets the current contents of the wrapped array. On non-cached arrays this is slow. + /// + public override T[] WrappedArray => cached ? arrayCache : ReadList(); + + public MemArrayList() : base() { } + + internal MemArrayList(Memory memory, int address, bool cached = true) : base(memory, address, cached) { } + + public override void UpdateFromHook(int index = -1) + { + if (cached) + { + if (index < 0) + arrayCache = ReadList(); + else + arrayCache[index] = ReadListItem(index); + } + } + + public override T this[int index] + { + get => cached ? arrayCache[index] : ReadListItem(index); + set => throw new NotSupportedException(); + } + + /// + /// TODO: Implement efficient enumerator for non-cached arrays. + /// + /// + public override IEnumerator GetEnumerator() => ((IEnumerable)WrappedArray).GetEnumerator(); + + public override void Add(T item) + { + throw new NotSupportedException(); + } + + public override void Clear() + { + base.Clear(); + if (cached) + arrayCache = Array.Empty(); + } + + public override bool Remove(T item) => throw new NotImplementedException(); + + public override void Insert(int index, T item) => throw new NotImplementedException(); + + public override void RemoveAt(int index) => throw new NotImplementedException(); + + public override int IndexOf(T item) => Array.IndexOf(WrappedArray, item); + + public override bool Contains(T item) => WrappedArray.Contains(item); + + public override void CopyTo(T[] array, int arrayIndex) => WrappedArray.CopyTo(array, arrayIndex); + } +} diff --git a/OmsiHook/MemArray/MemArraySimpleStruct.cs b/OmsiHook/MemArray/MemArraySimpleStruct.cs new file mode 100644 index 0000000..44ba5cb --- /dev/null +++ b/OmsiHook/MemArray/MemArraySimpleStruct.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace OmsiHook +{ + /// + /// Wrapper for dynamic arrays in OMSI's Memory. + /// + /// + /// + /// + /// + public class MemArray : MemArray where T : unmanaged + { + public override T[] WrappedArray => cached ? arrayCache : Memory.ReadMemoryStructArray(Address); + + public MemArray() : base() { } + internal MemArray(Memory memory, int address, bool cached = true) : base(memory, address, cached) { } + + public override void UpdateFromHook(int index = -1) + { + if (cached) + { + if (index >= 0) + arrayCache[index] = Memory.ReadMemoryArrayItem(Address, index); + else + arrayCache = Memory.ReadMemoryStructArray(Address); + } + } + + public override T this[int index] + { + get => cached ? arrayCache[index] : Memory.ReadMemoryArrayItemSafe(Address, index); + set + { + if (cached) + arrayCache[index] = value; + Memory.WriteMemoryArrayItemSafe(Address, value, index); + } + } + + /// + /// Adds an item to the native array. This is slow and might cause memory leaks because it reallocates the whole array. + /// + /// + /// Since this method doesn't call , if the native array is out of sync + /// with the cached array, then data may be lost when adding new items. + /// In the following case though, it should usually be safe (as long as the native array isn't updated by Omsi while this runs): + /// + /// memArray.UpdateFromHook(); + /// foreach(int item in localObjects) + /// memArray.Add(item); + /// + /// + /// The item to add to the native array. + public override void Add(T item) + { + int arr = Memory.ReadMemory(Address); + int len = Memory.ReadMemory(arr - 4); + int narr = Memory.AllocateStructArray(++len).Result; + Memory.WriteMemory(Address, narr); + if (cached) + { + // Copy native array from cache + for (int i = 0; i < Math.Min(len, arrayCache.Length); i++) + Memory.WriteMemoryArrayItem(narr, arrayCache[i], i); + + // Update cached array + Array.Resize(ref arrayCache, len); + arrayCache[len - 1] = item; + } + else + { + // Copy native array + Memory.CopyMemory(arr, narr, (len - 1) * Marshal.SizeOf()); + } + + // Add the new item to the native array + Memory.WriteMemoryArrayItem(Address, item, len - 1); + } + + /// + /// Clears the native array but maintains the reference to prevent the GC from destroying it. + /// + public override void Clear() + { + base.Clear(); + if (cached) + arrayCache = Array.Empty(); + } + + public override bool Remove(T item) => throw new NotImplementedException(); + + public override void Insert(int index, T item) => throw new NotImplementedException(); + + public override void RemoveAt(int index) => throw new NotImplementedException(); + } +} diff --git a/OmsiHook/MemArray/MemArraySimpleStructPtr.cs b/OmsiHook/MemArray/MemArraySimpleStructPtr.cs new file mode 100644 index 0000000..bff9308 --- /dev/null +++ b/OmsiHook/MemArray/MemArraySimpleStructPtr.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OmsiHook +{ + /// + /// Wrapper for dynamic arrays of pointers in OMSI's Memory. + /// + /// + /// + /// + /// + public class MemArrayPtr : MemArray where T : unmanaged + { + public override T[] WrappedArray => cached ? arrayCache : Memory.ReadMemoryStructPtrArray(Address); + + public MemArrayPtr() : base() { } + internal MemArrayPtr(Memory memory, int address, bool cached = true) : base(memory, address, cached) { } + + public override void UpdateFromHook(int index = -1) + { + if (cached) + { + if (index >= 0) + arrayCache[index] = Memory.ReadMemoryArrayItem(Address, index, true); + else + arrayCache = Memory.ReadMemoryStructPtrArray(Address); + } + } + + public override T this[int index] + { + get => cached ? arrayCache[index] : Memory.ReadMemoryArrayItemSafe(Address, index, true); + set + { + if (cached) + arrayCache[index] = value; + Memory.WriteMemoryArrayItemSafe(Address, value, index, true); + } + } + + public override void Add(T item) + { + int arr = Memory.ReadMemory(Address); + int len = Memory.ReadMemory(arr - 4); + var allocTask = Task.WhenAll(Memory.AllocateStructArray(++len), Memory.AllocateStruct(item)); + int narr = allocTask.Result[0]; + int ndata = allocTask.Result[1]; + Memory.WriteMemory(Address, narr); + if (cached) + { + // Copy native array + Memory.CopyMemory(arr, narr, (len - 1) * 4); + + // Update cached array + Array.Resize(ref arrayCache, len); + arrayCache[len - 1] = item; + } + else + { + // Copy native array + Memory.CopyMemory(arr, narr, (len - 1) * 4); + } + + // Add the new item to the native array + Memory.WriteMemoryArrayItem(Address, ndata, len - 1, false); + } + + /// + /// Clears the native array but maintains the reference to prevent the GC from destroying it. + /// Note that this does not free or dereference the items pointed to by the array elements. + /// + public override void Clear() + { + base.Clear(); + if (cached) + arrayCache = Array.Empty(); + } + + public override bool Remove(T item) => throw new NotImplementedException(); + + public override void Insert(int index, T item) => throw new NotImplementedException(); + + public override void RemoveAt(int index) => throw new NotImplementedException(); + } +} diff --git a/OmsiHook/MemArray/MemArrayString.cs b/OmsiHook/MemArray/MemArrayString.cs new file mode 100644 index 0000000..7ed5ae4 --- /dev/null +++ b/OmsiHook/MemArray/MemArrayString.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace OmsiHook +{ + /// + /// Wrapper for arrays of strings in OMSI's memmory. + /// + /// + /// + /// + public class MemArrayString : MemArrayBase + { + internal readonly bool wide; + + public override string this[int index] + { + get => cached ? arrayCache[index] : Memory.ReadMemoryArrayItemStringSafe(Address, index, wide); + set + { + if (cached) + arrayCache[index] = value; + Memory.WriteMemoryArrayItemSafe(Address, Memory.AllocateString(value).Result, index); + } + } + + public override string[] WrappedArray => cached ? arrayCache + : Memory.ReadMemoryStringArray(Address, wide); + + /// + /// Whether or not the string is in UTF-16. + /// + public bool Wide => wide; + + public MemArrayString() : base() { } + /// + /// Constructs a new MemArray to wrap a native array at a given address. + /// + /// Instance of the memory manager + /// Address of the native array to wrap + /// Whether or not the string is in UTF-16 + /// Whether or not to copy the contents of the array to a local cache + internal MemArrayString(Memory memory, int address, bool wide = false, bool cached = true) : base(memory, address, cached) + { + this.wide = wide; + } + + public override void UpdateFromHook(int index = -1) + { + if (cached) + { + if (index >= 0) + arrayCache[index] = Memory.ReadMemoryArrayItemString(Address, index, wide); + else + arrayCache = Memory.ReadMemoryStringArray(Address, wide); + } + } + + /// + /// Adds an item to the native array. This is slow and might cause memory leaks because it reallocates the whole array. + /// + /// + /// This method is probably slower (and much more memory intensive) on cached arrays. + /// Since this method doesn't call , if the native array is out of sync + /// with the cached array, then data may be lost when adding new items. + /// In the following case though, it should usually be safe (as long as the native array isn't updated by Omsi while this runs): + /// + /// memArray.UpdateFromHook(); + /// foreach(int item in localObjects) + /// memArray.Add(item); + /// + /// + /// The item to add to the native array. + public override void Add(string item) + { + int arr = Memory.ReadMemory(Address); + int len = Memory.ReadMemory(arr - 4); + int narr = Memory.AllocateStructArray(++len).Result; + Memory.WriteMemory(Address, narr); + if (cached) + { + // Copy native array from cache, this will never be faster... + /*Span allocatedStrings = stackalloc int[Math.Min(len, arrayCache.Length)]; + Task.WhenAll(); + for (int i = 0; i < allocatedStrings.Length; i++) + allocatedStrings[i] = Memory.AllocateString(arrayCache[i]); + for (int i = 0; i < Math.Min(len, arrayCache.Length); i++) + Memory.WriteMemoryArrayItem(narr, allocatedStrings[i], i);*/ + // Copy native array + Memory.CopyMemory(arr, narr, (len - 1) * Marshal.SizeOf()); + + // Update cached array + Array.Resize(ref arrayCache, len); + arrayCache[len - 1] = item; + } + else + { + // Copy native array + Memory.CopyMemory(arr, narr, (len - 1) * Marshal.SizeOf()); + } + + // Add the new item to the native array + Memory.WriteMemoryArrayItem(Address, Memory.AllocateString(item).Result, len - 1); + } + + public override void Clear() + { + base.Clear(); + if (cached) + arrayCache = Array.Empty(); + } + + public override bool Contains(string item) => WrappedArray.Contains(item); + + public override void CopyTo(string[] array, int arrayIndex) => WrappedArray.CopyTo(array, arrayIndex); + + //TODO: Implement efficient enumerator for non-cached arrays. + public override IEnumerator GetEnumerator() => (IEnumerator)WrappedArray.GetEnumerator(); + + public override int IndexOf(string item) => Array.IndexOf(WrappedArray, item); + + public override void Insert(int index, string item) => throw new NotImplementedException(); + + public override bool Remove(string item) => throw new NotImplementedException(); + + public override void RemoveAt(int index) => throw new NotImplementedException(); + } +} diff --git a/OmsiHook/MemArray/MemArrayStringDict.cs b/OmsiHook/MemArray/MemArrayStringDict.cs new file mode 100644 index 0000000..93de102 --- /dev/null +++ b/OmsiHook/MemArray/MemArrayStringDict.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OmsiHook +{ + /// + /// Wrapper for arrays of strings in OMSI's Memory with automatic index caching. + /// + /// + /// + /// + public class MemArrayStringDict : MemArrayString + { + private Dictionary indexDictionary = new(); + + public Dictionary IndexDictionary => indexDictionary; + + internal MemArrayStringDict(Memory memory, int address, bool wide = false) : base(memory, address, wide, true) { } + public MemArrayStringDict() : base() { } + + /// + /// Gets the index of the string in the native array from it's value. + /// + /// + /// + public int this[string item] => indexDictionary[item]; + + public override bool Cached { get => cached; } + + public override void UpdateFromHook(int index = -1) + { + if (index >= 0) + { + string prevValue = arrayCache[index]; + base.UpdateFromHook(index); + if (prevValue != arrayCache[index]) + { + indexDictionary.Remove(prevValue); + indexDictionary.Add(arrayCache[index], index); + } + } + else + { + base.UpdateFromHook(index); + indexDictionary.Clear(); + for (int i = 0; i < Count; i++) + { + if (arrayCache[i] != null) + indexDictionary.TryAdd(arrayCache[i], i); + } + } + } + + public override bool Contains(string item) => indexDictionary.ContainsKey(item); + public override int IndexOf(string item) => indexDictionary[item]; + public override bool Remove(string item) + { + if (indexDictionary.ContainsKey(item)) + base.RemoveAt(indexDictionary[item]); + else + return false; + return true; + } + } +} diff --git a/OmsiHook/MemArray/MemArrayStringList.cs b/OmsiHook/MemArray/MemArrayStringList.cs new file mode 100644 index 0000000..8498c93 --- /dev/null +++ b/OmsiHook/MemArray/MemArrayStringList.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OmsiHook +{ + /// + /// Wrapper for String Lists in OMSI's Memory. + /// + /// + /// + /// + public class MemArrayStringList : MemArrayBase + { + private StrPtrType stringType = StrPtrType.RawDelphiAnsiString; + + private string[] ReadList() + { + uint arr = Memory.ReadMemory(Address); + if (arr == 0) + return Array.Empty(); + uint len = Memory.ReadMemory(arr + 8); + uint arrayData = Memory.ReadMemory(arr + 4); + string[] ret = new string[len]; + for (uint i = 0; i < len; i++) + { + var objAddr = Memory.ReadMemory(arrayData + i * 4); + if (objAddr == 0) + { + ret[i] = null; + continue; + } + + var n = Memory.ReadMemoryString(objAddr, stringType); + ret[i] = n; + } + + return ret; + } + + private string ReadListItem(int index) + { + int arr = Memory.ReadMemory(Address); + if (arr == 0) + return null; + + int len = Memory.ReadMemory(arr + 8); + int arrayData = Memory.ReadMemory(arr + 4); + + if (index >= len || index < 0) + throw new ArgumentOutOfRangeException(nameof(index)); + + var objAddr = Memory.ReadMemory(arrayData + index * 4); + if (objAddr == 0) + return null; + + var n = Memory.ReadMemoryString(objAddr, stringType); + + return n; + } + + /// + /// Gets the current contents of the wrapped array. On non-cached arrays this is slow. + /// + public override string[] WrappedArray => cached ? arrayCache : ReadList(); + + public MemArrayStringList() : base() { } + + internal MemArrayStringList(Memory memory, int address, bool cached = true, StrPtrType stringType = StrPtrType.RawDelphiAnsiString) : base(memory, address, cached) + { + this.stringType = stringType; + } + + public override void UpdateFromHook(int index = -1) + { + if (cached) + { + if (index < 0) + arrayCache = ReadList(); + else + arrayCache[index] = ReadListItem(index); + } + } + + public override string this[int index] + { + get => cached ? arrayCache[index] : ReadListItem(index); + set => throw new NotSupportedException(); + } + + /// + /// TODO: Implement efficient enumerator for non-cached arrays. + /// + /// + public override IEnumerator GetEnumerator() => ((IEnumerable)WrappedArray).GetEnumerator(); + + public override void Add(string item) + { + throw new NotSupportedException(); + } + + public override void Clear() + { + base.Clear(); + if (cached) + arrayCache = Array.Empty(); + } + + public override bool Remove(string item) => throw new NotImplementedException(); + + public override void Insert(int index, string item) => throw new NotImplementedException(); + + public override void RemoveAt(int index) => throw new NotImplementedException(); + + public override int IndexOf(string item) => Array.IndexOf(WrappedArray, item); + + public override bool Contains(string item) => WrappedArray.Contains(item); + + public override void CopyTo(string[] array, int arrayIndex) => WrappedArray.CopyTo(array, arrayIndex); + } +} diff --git a/OmsiHook/MemArray/MemArrayStruct.cs b/OmsiHook/MemArray/MemArrayStruct.cs new file mode 100644 index 0000000..f0ca7a9 --- /dev/null +++ b/OmsiHook/MemArray/MemArrayStruct.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace OmsiHook +{ + /// + /// Wrapper for Arrays / Lists in OMSI's Memory. + /// + /// + /// + /// + /// + /// Internal struct type to marshal Struct from + public class MemArray : MemArrayBase + where InternalStruct : unmanaged + where Struct : struct + { + + /// + /// Gets the current contents of the wrapped array. On non-cached arrays this is slow. + /// + public override Struct[] WrappedArray => cached ? arrayCache + : Memory.MarshalStructs(Memory.ReadMemoryStructArray(Address)); + + public MemArray() : base() { } + + internal MemArray(Memory memory, int address, bool cached = true) : base(memory, address, cached) { } + + public override void UpdateFromHook(int index = -1) + { + if (cached) + { + if (index < 0) + arrayCache = Memory.MarshalStructs(Memory.ReadMemoryStructArray(Address)); + else + arrayCache[index] = Memory.MarshalStruct(Memory.ReadMemoryArrayItem(Address, index)); + } + } + + public override Struct this[int index] + { + get => cached ? arrayCache[index] + : Memory.MarshalStruct( + Memory.ReadMemoryArrayItemSafe(Address, index)); + set + { + if (cached) + arrayCache[index] = value; + Memory.WriteMemoryArrayItemSafe(Address, Memory.UnMarshalStruct(value), index); + } + } + + /// + /// TODO: Implement efficient enumerator for non-cached arrays. + /// + /// + public override IEnumerator GetEnumerator() => ((IEnumerable)WrappedArray).GetEnumerator(); + + /// + /// Adds an item to the native array. This is slow and might cause memory leaks because it reallocates the whole array. + /// + /// + /// Since this method doesn't call , if the native array is out of sync + /// with the cached array, then data may be lost when adding new items. + /// In the following case though, it should usually be safe (as long as the native array isn't updated by Omsi while this runs): + /// + /// memArray.UpdateFromHook(); + /// foreach(int item in localObjects) + /// memArray.Add(item); + /// + /// + /// The item to add to the native array. + public override void Add(Struct item) + { + int arr = Memory.ReadMemory(Address); + int len = Memory.ReadMemory(arr - 4); + int narr = Memory.AllocateStructArray(++len).Result; + Memory.WriteMemory(Address, narr); + if (cached) + { + // Copy native array from cache + for (int i = 0; i < Math.Min(len, arrayCache.Length); i++) + Memory.WriteMemoryArrayItem(narr, Memory.UnMarshalStruct(arrayCache[i]), i); + + // Update cached array + Array.Resize(ref arrayCache, len); + arrayCache[len - 1] = item; + } + else + { + // Copy native array + Memory.CopyMemory(arr, narr, (len-1) * Marshal.SizeOf()); + } + + // Add the new item to the native array + Memory.WriteMemoryArrayItem(Address, Memory.UnMarshalStruct(item), len - 1); + } + + public override void Clear() + { + base.Clear(); + if(cached) + arrayCache = Array.Empty(); + } + + public override bool Remove(Struct item) => throw new NotImplementedException(); + + public override void Insert(int index, Struct item) => throw new NotImplementedException(); + + public override void RemoveAt(int index) => throw new NotImplementedException(); + + public override int IndexOf(Struct item) => Array.IndexOf(WrappedArray, item); + + public override bool Contains(Struct item) => WrappedArray.Contains(item); + + public override void CopyTo(Struct[] array, int arrayIndex) => WrappedArray.CopyTo(array, arrayIndex); + } +} diff --git a/OmsiHook/MemArray/MemArrayStructList.cs b/OmsiHook/MemArray/MemArrayStructList.cs new file mode 100644 index 0000000..bbd0068 --- /dev/null +++ b/OmsiHook/MemArray/MemArrayStructList.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OmsiHook +{ + /// + /// Wrapper for Lists in OMSI's Memory. + /// + /// + /// + /// + /// + /// Internal struct type to marshal Struct from + public class MemArrayList : MemArrayBase + where InternalStruct : unmanaged + where Struct : struct + { + private Struct[] ReadList() + { + uint arr = Memory.ReadMemory(Address); + if (arr == 0) + return Array.Empty(); + uint len = Memory.ReadMemory(arr + 8); + uint arrayData = Memory.ReadMemory(arr + 4); + Struct[] ret = new Struct[len]; + for (uint i = 0; i < len; i++) + { + var objAddr = Memory.ReadMemory(arrayData + i * 4); + if (objAddr == 0) + { + ret[i] = default; + continue; + } + + var n = Memory.MarshalStruct(Memory.ReadMemory(objAddr)); + ret[i] = n; + } + + return ret; + } + + private Struct ReadListItem(int index) + { + int arr = Memory.ReadMemory(Address); + if (arr == 0) + return default; + + int len = Memory.ReadMemory(arr + 8); + int arrayData = Memory.ReadMemory(arr + 4); + + if (index >= len || index < 0) + throw new ArgumentOutOfRangeException(nameof(index)); + + var objAddr = Memory.ReadMemory(arrayData + index * 4); + if (objAddr == 0) + return default; + + var n = Memory.MarshalStruct(Memory.ReadMemory(objAddr)); + + return n; + } + + /// + /// Gets the current contents of the wrapped array. On non-cached arrays this is slow. + /// + public override Struct[] WrappedArray => cached ? arrayCache : ReadList(); + + public MemArrayList() : base() { } + + internal MemArrayList(Memory memory, int address, bool cached = true) : base(memory, address, cached) { } + + public override void UpdateFromHook(int index = -1) + { + if (cached) + { + if (index < 0) + arrayCache = ReadList(); + else + arrayCache[index] = ReadListItem(index); + } + } + + public override Struct this[int index] + { + get => cached ? arrayCache[index] : ReadListItem(index); + set => throw new NotSupportedException(); + } + + /// + /// TODO: Implement efficient enumerator for non-cached arrays. + /// + /// + public override IEnumerator GetEnumerator() => ((IEnumerable)WrappedArray).GetEnumerator(); + + public override void Add(Struct item) + { + throw new NotSupportedException(); + } + + public override void Clear() + { + base.Clear(); + if (cached) + arrayCache = Array.Empty(); + } + + public override bool Remove(Struct item) => throw new NotImplementedException(); + + public override void Insert(int index, Struct item) => throw new NotImplementedException(); + + public override void RemoveAt(int index) => throw new NotImplementedException(); + + public override int IndexOf(Struct item) => Array.IndexOf(WrappedArray, item); + + public override bool Contains(Struct item) => WrappedArray.Contains(item); + + public override void CopyTo(Struct[] array, int arrayIndex) => WrappedArray.CopyTo(array, arrayIndex); + } +} diff --git a/OmsiHook/Memory.cs b/OmsiHook/Memory.cs index 805dd19..87f0bf3 100644 --- a/OmsiHook/Memory.cs +++ b/OmsiHook/Memory.cs @@ -407,6 +407,19 @@ public void WriteMemory(int address, string value, bool wide = false, bool copyR //Imports.WriteProcessMemory((int)omsiProcessHandle, address, buffer, buffer.Length, out _); } + /// + /// Sets the value of a string at a given address. + /// + /// The address of the data to set + /// The new value of the string to set; this must be of the + /// correct encoding to avoid memory corruption + /// The type of string to copy to + public void WriteMemory(int address, string value, StrPtrType strType) + { + WriteMemory(address, value, + (strType & StrPtrType.Wide) != 0); + } + /// public async Task WriteMemoryAsync(int address, string value, bool wide = false, bool copyReferences = true) { @@ -429,17 +442,17 @@ public T ReadMemory(int address) where T : unmanaged { int byteSize = Marshal.SizeOf(typeof(T)); if (byteSize > readBuffer.Value.Length) - throw new ArgumentException($"Couldn't read memory for object of type {typeof(T).Name} @ {address}; it wouldn't fit in the read buffer!"); + throw new ArgumentException($"Couldn't read memory for object of type {typeof(T).Name} @ 0x{address:X8}; it wouldn't fit in the read buffer!"); int bytesRead = -1; if (!Imports.ReadProcessMemory((int)omsiProcessHandle, address, readBuffer.Value, byteSize, ref bytesRead)) #if DEBUG && SILENCE_ACCESS_VIOLATION { - Debug.WriteLine($"Couldn't read {byteSize} bytes of process memory @ {address:X}!\n{new System.Diagnostics.StackTrace(true)}"); + Debug.WriteLine($"Couldn't read {byteSize} bytes of process memory @ 0x{address:X8}!\n{new System.Diagnostics.StackTrace(true)}"); return new T(); } #else - throw new MemoryAccessException($"Couldn't read {byteSize} bytes of process memory @ {address:X}!"); + throw new MemoryAccessException($"Couldn't read {byteSize} bytes of process memory @ 0x{address:X8}!"); #endif return ByteArrayToStructure(readBuffer.Value); @@ -475,6 +488,36 @@ public T ReadMemory(uint address) where T : unmanaged return obj; } + /// + /// Reads and constructs an OmsiObject from unmanaged memory. + /// + /// + /// This version of the method performs a null-check on the base address before the offset is applied + /// to prevent attempting to dereference an objject belonging to a null-parent. + /// + /// The type of OmsiObject to construct + /// The address of the object this field belongs to. + /// The offset from the base address of the object. + /// When false, dereferences the object pointer again before construcing the new object. + /// A new OmsiObject. + public T ReadMemoryObject(int address, int offset, bool raw=true) where T : OmsiObject, new() + { + if (address == 0) + return null; + var addr = ReadMemory(address + offset); + if (addr == 0) + return null; + if (raw) + { + addr = ReadMemory(addr); + if (addr == 0) + return null; + } + var obj = new T(); + obj.InitObject(this, addr); + return obj; + } + /// /// Returns the value of a null terminated/length prefixed string at a given address. /// @@ -510,10 +553,12 @@ public string ReadMemoryString(int address, bool wide = false, bool raw = false, if (pascalString) { - int strLen = ReadMemory(i - 4); + uint strLen = ReadMemory(i - 4); + if (strLen > 4096) + throw new MemoryAccessException($"Tried reading a very long string ({strLen} > 4096 characters long). This is probably not a valid string"); if(wide) strLen *= 2; - var bytes = ReadMemory(i, strLen, readBuffer.Value); + var bytes = ReadMemory(i, (int)strLen, readBuffer.Value); sb.Append(wide ? Encoding.Unicode.GetString(bytes) : Encoding.ASCII.GetString(bytes)); } else diff --git a/OmsiHook/OmsiGlobals.cs b/OmsiHook/OmsiGlobals.cs index 57397fc..cef2732 100644 --- a/OmsiHook/OmsiGlobals.cs +++ b/OmsiHook/OmsiGlobals.cs @@ -16,10 +16,15 @@ public class OmsiGlobals : OmsiObject private OmsiHook hook; + private MemArrayList roadVehicles = null; + /// + /// Gets the list of active road vehicles. + /// + public OmsiMyOmsiList RoadVehicles => Memory.ReadMemoryObject>(0x00861508); /// /// Gets the vehicle instance being driven by the player. /// - public OmsiRoadVehicleInst PlayerVehicle => hook.GetRoadVehicleInst(PlayerVehicleIndex); + public OmsiRoadVehicleInst PlayerVehicle => roadVehicles == null ? (roadVehicles = RoadVehicles.FList)[PlayerVehicleIndex] : roadVehicles[PlayerVehicleIndex]; /// /// Gets the current vehicle index driven by the player. /// @@ -28,7 +33,7 @@ public class OmsiGlobals : OmsiObject /// /// Current Weather /// - public OmsiWeather Weather => new(Memory, Memory.ReadMemory(0x008617D0)); + public OmsiWeather Weather => Memory.ReadMemoryObject(0x008617D0); /// /// Current Map @@ -84,5 +89,15 @@ public class OmsiGlobals : OmsiObject /// Main Camera Object /// public OmsiCamera Camera => Memory.ReadMemoryObject(0x008616e0); + + /// + /// Central Material Manager + /// + public OmsiMaterialMan MaterialMan => Memory.ReadMemoryObject(0x00861ca8); + + /// + /// Central Texture Manager + /// + public OmsiTextureMan TextureMan => Memory.ReadMemoryObject(0x00861bc4); } } diff --git a/OmsiHook/OmsiHook.cs b/OmsiHook/OmsiHook.cs index cb243d3..3e04aa7 100644 --- a/OmsiHook/OmsiHook.cs +++ b/OmsiHook/OmsiHook.cs @@ -70,7 +70,7 @@ public class OmsiHook /// /// /// - public event EventHandler OnMapChange; + public event EventHandler OnMapChange; /// /// An event raised when Omsi has loaded or unloaded a new map. The EventArgs is a boolean representing whether the map is loaded. /// @@ -82,10 +82,18 @@ public class OmsiHook /// /// public event EventHandler OnMapLoaded; + /// + /// An event raised when the active vehicle is changed. The EventArgs is a OmsiRoadVehicleInst of the new bus. + /// + /// + /// + /// + public event EventHandler OnActiveVehicleChanged; private int lastD3DState = 0; private int lastMapState = 0; private bool lastMapLoaded = false; + private int lastVehiclePtr = 0; #endregion /// @@ -141,7 +149,7 @@ public D3DTexture CreateTextureObject() return new D3DTexture(omsiMemory, 0); } - private void OmsiHook_OnMapChange(object sender, EventArgs e) + private void OmsiHook_OnMapChange(object sender, OmsiMap e) { Task.Run(() => { while(!isD3DReady) @@ -165,8 +173,9 @@ private void OmsiHook_OnOmsiGotD3DContext(object sender, EventArgs e) [Obsolete("This will be obselete once TMyOMSIList is wrapped! The list of vehicles will be moved to OmsiGlobals.")] public OmsiRoadVehicleInst GetRoadVehicleInst(int index) { + // TODO: A More permanant fix should be done at some point. var vehPtr = GetListItem(0x00861508, index); - return vehPtr == 0 ? null : new OmsiRoadVehicleInst(omsiMemory, vehPtr); + return vehPtr < 1000 ? null : new OmsiRoadVehicleInst(omsiMemory, vehPtr); } /// @@ -214,7 +223,7 @@ private void MonitorStateTask() if(lastMapState != currentMapName) { if(currentMapName != 0) - OnMapChange?.Invoke(this, new()); + OnMapChange?.Invoke(this, Globals.Map); lastMapState = currentMapName; } if(lastMapLoaded != currentMapLoaded) @@ -223,6 +232,12 @@ private void MonitorStateTask() lastMapLoaded = currentMapLoaded; } } + var vehPtr = GetListItem(0x00861508, omsiMemory.ReadMemory(0x00861740)); + if (vehPtr != lastVehiclePtr) + { + lastVehiclePtr = vehPtr; + OnActiveVehicleChanged?.Invoke(this, Globals.PlayerVehicle); + } Thread.Sleep(20); } diff --git a/OmsiHook/OmsiHook.csproj b/OmsiHook/OmsiHook.csproj index 1450bda..b97d414 100644 --- a/OmsiHook/OmsiHook.csproj +++ b/OmsiHook/OmsiHook.csproj @@ -1,83 +1,108 @@  - - net6.0-windows - Thomas Mathieson et al - Copyright Thomas Mathieson 2023 all rights reserved - https://github.com/space928/Omsi-Extensions - https://github.com/space928/Omsi-Extensions - - OmsiHook is a simple library for hooking into Omsi's memory for modding. - true - true - 2.3.2.1 - 2.3.2.1 - 2.3.2 - LGPL-3.0-only - False - README.md - Logo.png - true - snupkg - disable - x86 - + + net6.0-windows + Thomas Mathieson et al + Copyright Thomas Mathieson 2022-2024 all rights reserved + https://github.com/space928/Omsi-Extensions + https://github.com/space928/Omsi-Extensions + + OmsiHook is a simple library for hooking into Omsi's memory for modding. + true + true + 2.4.4.1 + 2.4.4.1 + 2.4.4 + LGPL-3.0-only + False + README.md + Logo.png + true + snupkg + disable + x86 + False + Debug;Release;ReleaseAndDocs + - + - - - - True - \ - - - True - \ - - - PreserveNewest - True - \lib\net6.0 - - - PreserveNewest - True - \lib\net6.0 - - - PreserveNewest - True - \lib\net6.0 - - - PreserveNewest - True - \lib\net6.0 - - + + + + + <_ConfigurationNormalized>$(Configuration) + false + + + + + <_ConfigurationNormalized>Release + $(MSBuildProjectDirectory)/bin/$(Platform)/Release/$(TargetFramework)/ + $(MSBuildProjectDirectory)/bin/$(Platform)/Release/ - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - + true + $(MSBuildProjectDirectory)/docs/docfx.json + $(MSBuildProjectDirectory)/docs/_site + $(MSBuildProjectDirectory)/docs + $(MSBuildProjectDirectory)/docs/docfx_log.txt + Info + + + - - - false - - - + + + + True + \ + + + True + \ + + + PreserveNewest + True + \lib\net6.0 + + + PreserveNewest + True + \lib\net6.0 + + + PreserveNewest + True + \lib\net6.0 + + + PreserveNewest + True + \lib\net6.0 + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + True + + + - - - + + + false + + + + + + + + diff --git a/OmsiHook/OmsiHookRPCMethods.cs b/OmsiHook/OmsiHookRPCMethods.cs index ccdaaa3..b345f7f 100644 --- a/OmsiHook/OmsiHookRPCMethods.cs +++ b/OmsiHook/OmsiHookRPCMethods.cs @@ -23,7 +23,9 @@ internal enum RemoteMethod : int UpdateSubresource, ReleaseTexture, GetTextureDesc, - IsTexture + IsTexture, + RVTriggerXML, + SoundTrigger } internal static readonly ReadOnlyDictionary RemoteMethodsArgsSizes = new(new Dictionary() @@ -40,6 +42,8 @@ internal enum RemoteMethod : int { RemoteMethod.ReleaseTexture, 4 }, { RemoteMethod.GetTextureDesc, 32 }, { RemoteMethod.IsTexture, 4 }, + { RemoteMethod.RVTriggerXML, 12 }, + { RemoteMethod.SoundTrigger, 12 }, }); } } diff --git a/OmsiHook/OmsiMovingMapObjInst.cs b/OmsiHook/OmsiMovingMapObjInst.cs deleted file mode 100644 index b72b8dd..0000000 --- a/OmsiHook/OmsiMovingMapObjInst.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace OmsiHook -{ - /// - /// Base Class for all instances of moving map objects - vehicles / humans - /// - public class OmsiMovingMapObjInst : OmsiComplMapObjInst - { - internal OmsiMovingMapObjInst(Memory omsiMemory, int baseAddress) : base(omsiMemory, baseAddress) { } - public OmsiMovingMapObjInst() : base() { } - // TODO: this one - } -} \ No newline at end of file diff --git a/OmsiHook/OmsiObject.cs b/OmsiHook/OmsiObject.cs index 1e473e3..aa16368 100644 --- a/OmsiHook/OmsiObject.cs +++ b/OmsiHook/OmsiObject.cs @@ -14,6 +14,8 @@ public class OmsiObject internal Memory Memory { get; private set; } internal int Address { get; set; } + public bool IsNull => Address == 0; + public OmsiObject() { } internal OmsiObject(Memory memory, int address) { diff --git a/OmsiHook/OmsiRemoteMethods.cs b/OmsiHook/OmsiRemoteMethods.cs index e943fc6..c2ce069 100644 --- a/OmsiHook/OmsiRemoteMethods.cs +++ b/OmsiHook/OmsiRemoteMethods.cs @@ -83,8 +83,8 @@ private static void ResultReaderTask() int promiseHash = reader.ReadInt32(); int value = reader.ReadInt32(); - resultPromises.TryRemove(promiseHash, out var promise); - promise.SetResult(value); + if(resultPromises.TryRemove(promiseHash, out var promise)) + promise.SetResult(value); } } @@ -454,6 +454,102 @@ public static async Task OmsiIsTextureAsync(uint texturePtr) } } + /// + /// Sets a trigger on a given road vehicle. + /// + /// The OmsiRoadVehicleInst to set the trigger on + /// The name of the trigger to set + /// Whether to enable or disable the trigger + public static async Task OmsiSetTrigger(OmsiRoadVehicleInst roadVehicle, string trigger, bool enabled) + { + var triggerPtr = await memory.AllocateString(trigger); + await OmsiSetTrigger(roadVehicle, triggerPtr, enabled); + } + + /// + /// Sets a trigger on a given road vehicle. + /// + /// The OmsiRoadVehicleInst to set the trigger on + /// A pointer to an Omsi string containing the name of the trigger to set + /// Whether to enable or disable the trigger + public static async Task OmsiSetTrigger(OmsiRoadVehicleInst roadVehicle, int triggerPtr, bool enabled) + { + if (localPlugin) + { + RVTriggerXML(roadVehicle.Address, triggerPtr, enabled?1:0); + return; + } + else + { + if (!IsInitialised) + throw new NotInitialisedException("OmsiHook RPC plugin is not connected! Did you make sure to call OmsiRemoteMethods.InitRemoteMethods() before this call?"); + + int argPos = 0; + var method = OmsiHookRPCMethods.RemoteMethod.RVTriggerXML; + int writeBufferSize = OmsiHookRPCMethods.RemoteMethodsArgsSizes[method] + 8; + // This should be thread safe as the asyncWriteBuff is thread local + byte[] writeBuffer = asyncWriteBuff.Value; + (int resultPromise, TaskCompletionSource promise) = CreateResultPromise(); + BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos)..], (int)method); + BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], resultPromise); + BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], roadVehicle.Address); + BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], triggerPtr); + BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], enabled ? 1 : 0); + lock (pipeTX) + pipeTX.Write(writeBuffer.AsSpan()[..writeBufferSize]); + await promise.Task; + } + } + + /// + /// Triggers a sound for a given OmsiComplMapObjInst + /// + /// The OmsiComplMapObjInst to trigger the sound from + /// The name of the sound pack + /// The filename of the sound to play + public static async Task OmsiSoundTrigger(OmsiComplMapObjInst mapObj, string trigger, string filename) + { + var triggerPtr = memory.AllocateString(trigger); + var filenamePtr = memory.AllocateString(filename); + await Task.WhenAll(triggerPtr, filenamePtr); + await OmsiSoundTrigger(mapObj, triggerPtr.Result, filenamePtr.Result); + } + + /// + /// Triggers a sound for a given OmsiComplMapObjInst + /// + /// The OmsiComplMapObjInst to trigger the sound from + /// A pointer to an Omsi string containing the name of the sound pack + /// A pointer to an Omsi string containing the filename of the sound to play + public static async Task OmsiSoundTrigger(OmsiComplMapObjInst mapObj, int triggerPtr, int filenamePtr) + { + if (localPlugin) + { + SoundTrigger(mapObj.Address, triggerPtr, filenamePtr); + return; + } + else + { + if (!IsInitialised) + throw new NotInitialisedException("OmsiHook RPC plugin is not connected! Did you make sure to call OmsiRemoteMethods.InitRemoteMethods() before this call?"); + + int argPos = 0; + var method = OmsiHookRPCMethods.RemoteMethod.SoundTrigger; + int writeBufferSize = OmsiHookRPCMethods.RemoteMethodsArgsSizes[method] + 8; + // This should be thread safe as the asyncWriteBuff is thread local + byte[] writeBuffer = asyncWriteBuff.Value; + (int resultPromise, TaskCompletionSource promise) = CreateResultPromise(); + BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos)..], (int)method); + BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], resultPromise); + BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], mapObj.Address); + BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], triggerPtr); + BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], filenamePtr); + lock (pipeTX) + pipeTX.Write(writeBuffer.AsSpan()[..writeBufferSize]); + await promise.Task; + } + } + [DllImport("OmsiHookInvoker.dll")] private static extern int TProgManMakeVehicle(int progMan, int vehList, int _RoadVehicleTypes, bool onlyvehlist, bool CS, float TTtime, bool situationload, bool dialog, bool setdriver, bool thread, @@ -482,6 +578,10 @@ private static extern int TProgManPlaceRandomBus(int progMan, int aityp, private static extern int GetTextureDesc(uint Texture, uint pWidth, uint pHeight, uint pFormat); [DllImport("OmsiHookInvoker.dll")] private static extern int IsTexture(uint Texture); + [DllImport("OmsiHookInvoker.dll")] + private static extern void RVTriggerXML(int roadVehicle, int trigger, int value); + [DllImport("OmsiHookInvoker.dll")] + internal static extern void SoundTrigger(int complMapObj, int trigger, int filename); public enum D3DFORMAT : uint { diff --git a/OmsiHook/OmsiStructs.cs b/OmsiHook/OmsiStructs.cs index b04ee06..0929197 100644 --- a/OmsiHook/OmsiStructs.cs +++ b/OmsiHook/OmsiStructs.cs @@ -1,4 +1,5 @@ using System; +using System.Numerics; using System.Runtime.InteropServices; #pragma warning disable CS0649 @@ -11,10 +12,28 @@ namespace OmsiHook public struct D3DVector { public float x, y, z; + + public D3DVector() + { + x = y = z = 0; + } + public D3DVector(float x, float y, float z) + { + this.x = x; + this.y = y; + this.z = z; + } + + public override readonly string ToString() => $"[{x,8:F3}, {y,8:F3}, {z,8:F3}]"; + + 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}]"; } /// @@ -26,6 +45,58 @@ public struct D3DMatrix _10, _11, _12, _13, _20, _21, _22, _23, _30, _31, _32, _33; + public override readonly string ToString() => $"[ [{_00,8:F3}, {_01,8:F3}, {_02,8:F3}, {_03,8:F3}],\n" + + $"[{_10,8:F3}, {_11,8:F3}, {_12,8:F3}, {_13,8:F3}],\n" + + $"[{_20,8:F3}, {_21,8:F3}, {_22,8:F3}, {_23,8:F3}],\n" + + $"[{_30,8:F3}, {_31,8:F3}, {_32,8:F3}, {_33,8:F3}] ]"; + + public readonly D3DVector Position => new(_30, _31, _32); + + public static implicit operator Matrix4x4(D3DMatrix m) + { + return new Matrix4x4() + { + M11 = m._00, + M12 = m._01, + M13 = m._02, + M14 = m._03, + M21 = m._10, + M22 = m._11, + M23 = m._12, + M24 = m._13, + M31 = m._20, + M32 = m._21, + M33 = m._22, + M34 = m._23, + M41 = m._30, + M42 = m._31, + M43 = m._32, + M44 = m._33 + }; + } + + public static implicit operator D3DMatrix(Matrix4x4 m) + { + return new() + { + _00 = m.M11, + _01 = m.M12, + _02 = m.M13, + _03 = m.M14, + _10 = m.M21, + _11 = m.M22, + _12 = m.M23, + _13 = m.M24, + _20 = m.M31, + _21 = m.M32, + _22 = m.M33, + _23 = m.M34, + _30 = m.M41, + _31 = m.M42, + _32 = m.M43, + _33 = m.M44 + }; + } } /// @@ -34,6 +105,8 @@ public struct D3DMatrix 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}]"; } /// @@ -42,6 +115,8 @@ public struct D3DXQuaternion public struct D3DXPlane { public float a, b, c, d; + + public override readonly string ToString() => $"[{a,8:F3}, {b,8:F3}, {c,8:F3}, {d,8:F3}]"; } /// @@ -50,6 +125,8 @@ public struct D3DXPlane public struct D3DColorValue { public float r, g, b, a; + + public override readonly string ToString() => $"[{r,8:F3}, {g,8:F3}, {b,8:F3}, {a,8:F3}]"; } /// @@ -77,7 +154,7 @@ public struct OmsiPoint public int x, y; } - internal struct OmsiMaterialPropInternal + public struct OmsiMaterialPropInternal { public int mainTexture; public bool standard; @@ -87,7 +164,8 @@ internal struct OmsiMaterialPropInternal public bool horizontal; public bool water; public bool useEnvirReflx, useEnvirMask, useBumpMap, useRainDropAreaMap, - useTransMap, useTextTexture, useScriptTexture; + useTransMap; + public int useTextTexture, useScriptTexture; public int texCoordTransX, texCoordTransY; public int raindropAreaMapVar; public int alphaScale_Var; @@ -128,7 +206,8 @@ public struct OmsiMaterialProp public bool horizontal; public bool water; public bool useEnvirReflx, useEnvirMask, useBumpMap, useRainDropAreaMap, - useTransMap, useTextTexture, useScriptTexture; + useTransMap; + public int useTextTexture, useScriptTexture; public int texCoordTransX, texCoordTransY; public int raindropAreaMapVar; public int alphaScale_Var; @@ -372,17 +451,17 @@ public struct OmsiTicketPack internal struct OmsiTicketInternal { //TODO: I don't think these are decoding correctly (I saw nothing when I looked), check this actually works. - [FieldOffset(0x0)] [OmsiStrPtr(StrPtrType.RawDelphiAnsiString)] public int name; - [FieldOffset(0x4)] [OmsiStrPtr(StrPtrType.RawDelphiAnsiString)] public int name_english; - [FieldOffset(0x8)] [OmsiStrPtr(StrPtrType.RawDelphiAnsiString)] public int name_display; + [FieldOffset(0x0)][OmsiStrPtr(StrPtrType.RawDelphiAnsiString)] public int name; + [FieldOffset(0x4)][OmsiStrPtr(StrPtrType.RawDelphiAnsiString)] public int name_english; + [FieldOffset(0x8)][OmsiStrPtr(StrPtrType.RawDelphiAnsiString)] public int name_display; [FieldOffset(0xc)] public int max_stations; [FieldOffset(0x10)] public int age_min; [FieldOffset(0x14)] public int age_max; [FieldOffset(0x18)] public float value; [FieldOffset(0x1c)] public bool dayTicket; [FieldOffset(0x20)] public float propability; - [FieldOffset(0x24)] [OmsiObjPtr(typeof(D3DMeshFileObject))] public int mesh_block; - [FieldOffset(0x28)] [OmsiObjPtr(typeof(D3DMeshFileObject))] public int mesh_single; + [FieldOffset(0x24)][OmsiObjPtr(typeof(D3DMeshFileObject))] public int mesh_block; + [FieldOffset(0x28)][OmsiObjPtr(typeof(D3DMeshFileObject))] public int mesh_single; } public struct OmsiTicket @@ -637,57 +716,66 @@ public struct OmsiPathBelegung } //TODO: Bug when dereferencing this + [StructLayout(LayoutKind.Explicit, Size = 0x110)] internal struct OmsiPathInfoInternal { - public byte veh_type; - public byte uvg; - public bool railroad; - public bool freeOrLarge; - public D3DVector pathPos; - public OmsiPathID path; - public int subPath; - public bool reverse; - public float hdg; - [OmsiStructPtr(typeof(uint))] public int idCode; - [OmsiObjPtr(typeof(OmsiObject))] public int vehicle; - public float veloc; - public float x_L, x_R, z_B, z_F; - public float radius; - public float drehpunkt; - [OmsiStructPtr(typeof(D3DMatrix))] public int absPosition; - public byte waitMode; - public int reserveGroup; - public byte blinker; - public byte einOrdnen;//TODO: Check data type - public bool prevVisible_logical; + [FieldOffset(0x0)] public byte veh_type; + [FieldOffset(0x1)] public byte uvg; + [FieldOffset(0x2)] public bool railroad; + [FieldOffset(0x3)] public bool freeOrLarge; + [FieldOffset(0x4)] public D3DVector pathPos; + [FieldOffset(0x10)] public OmsiPathID path; + [FieldOffset(0x18)] public int subPath; + [FieldOffset(0x1c)] public bool reverse; + [FieldOffset(0x20)] public float hdg; + [FieldOffset(0x24)][OmsiStructPtr(typeof(uint))] public int idCode; + [FieldOffset(0x28)][OmsiObjPtr(typeof(OmsiObject))] public int vehicle; + [FieldOffset(0x2c)] public float veloc; + [FieldOffset(0x30)] public float x_L; + [FieldOffset(0x34)] public float x_R; + [FieldOffset(0x38)] public float z_B; + [FieldOffset(0x3c)] public float z_F; + [FieldOffset(0x40)] public float radius; + [FieldOffset(0x44)] public float drehpunkt; + [FieldOffset(0x48)][OmsiStructPtr(typeof(D3DMatrix))] public int absPosition; + [FieldOffset(0x4c)] public byte waitMode; + [FieldOffset(0x50)] public int reserveGroup; + [FieldOffset(0x54)] public byte blinker; + [FieldOffset(0x55)] public byte einOrdnen;//TODO: Check data type + [FieldOffset(0x56)] public bool prevVisible_logical; //TODO: Determine actual type - public int nextPath_a, nextPath_b, nextPath_c, nextPath_d, nextPath_e; - public OmsiNextPathSegment nextPathSeg; - public OmsiNextPathID nextPathID; - [OmsiStructArrayPtr(typeof(OmsiPathID))] - public int reservePaths; - public int spurwechsel; //TODO: Check data type - public uint spurwechselTime; - public bool spurwechselAuto; - public bool noScheduledSpurwechsel; - public bool on_crossing; - public float leftFree, rightFree; - public byte relPosError; //TODO: Check data type - public bool setPosOnNearTile; - public float rowdy_factor; - public bool eilig; - public bool einSatzFahrzeug; - public float martinshorn; - public float getrieben_von_einSatz; - public uint getrieben_von_einSatz_time; - public byte setSoll; - public int track; - public int trackEntry; - public int stnLink; - public int next_stnLink; - public bool zwangsEinsetzen; - public bool allowHupen; - [OmsiStrPtr] public int debug_aiData_limit; + [FieldOffset(0x58)] public int nextPath_a; + [FieldOffset(0x5c)] public int nextPath_b; + [FieldOffset(0x60)] public int nextPath_c; + [FieldOffset(0x64)] public int nextPath_d; + [FieldOffset(0x68)] public int nextPath_e; + [FieldOffset(0x6c)] public OmsiNextPathSegment nextPathSeg; + [FieldOffset(0x94)] public OmsiNextPathID nextPathID; + [FieldOffset(0xbc)][OmsiStructArrayPtr(typeof(OmsiPathID), raw: true)] public int reservePaths; + [FieldOffset(0xc0)] public int spurwechsel; //TODO: Check data type + [FieldOffset(0xc4)] public uint spurwechselTime; + [FieldOffset(0xc8)] public bool spurwechselAuto; + [FieldOffset(0xc9)] public bool noScheduledSpurwechsel; + [FieldOffset(0xca)] public bool on_crossing; + [FieldOffset(0xcc)] public float leftFree; + [FieldOffset(0xd0)] public float rightFree; + [FieldOffset(0xd4)] public byte relPosError; //TODO: Check data type + [FieldOffset(0xd5)] public bool setPosOnNearTile; + [FieldOffset(0xd8)] public float rowdy_factor; + [FieldOffset(0xdc)] public bool eilig; + [FieldOffset(0xdd)] public bool einSatzFahrzeug; + [FieldOffset(0xe0)] public float martinshorn; + [FieldOffset(0xe4)] public float getrieben_von_einSatz; + [FieldOffset(0xe8)] public uint getrieben_von_einSatz_time; + [FieldOffset(0xec)] public byte setSoll; + [FieldOffset(0xf0)] public int track; + [FieldOffset(0xf4)] public int trackEntry; + [FieldOffset(0xf8)] public int stnLink; + [FieldOffset(0xfc)] public int next_stnLink; + [FieldOffset(0x100)] public bool zwangsEinsetzen; + [FieldOffset(0x104)] public float normBrakedDist; + [FieldOffset(0x108)] public bool allowHupen; + [FieldOffset(0x10c)][OmsiStrPtr(StrPtrType.RawDelphiString)] public int debug_aiData_limit; } public struct OmsiPathInfo @@ -720,7 +808,7 @@ public struct OmsiPathInfo /// /// Order /// - public byte einordnen;//TODO: Check data type + public byte einOrdnen;//TODO: Check data type public bool prevVisible_logical; //TODO: Determine actual type public int nextPath_a, nextPath_b, nextPath_c, nextPath_d, nextPath_e; @@ -755,7 +843,7 @@ public struct OmsiPathInfo /// /// Emergency vehicles /// - public bool einsatzfahrzeug; + public bool einSatzFahrzeug; /// /// Siren /// @@ -763,7 +851,7 @@ public struct OmsiPathInfo /// /// Driven by emergency? /// - public float getrieben_von_einsatz; + public float getrieben_von_einSatz; /// /// Driven by emergency time? /// @@ -780,6 +868,7 @@ public struct OmsiPathInfo /// Forced insertion? /// public bool zwangsEinsetzen; + public float normBrakedDist; /// /// Allow horns /// @@ -1114,13 +1203,13 @@ public struct OmsiHOFTarget internal struct OmsiHOFTargetInternal { public int nummer; - [OmsiStrPtr(raw:true)] public int name; // ANSI String + [OmsiStrPtr(raw: true)] public int name; // ANSI String /// /// Terminus /// [OmsiStrPtr(raw: true)] public int endstelle; // ANSI String public int texNummer; - [OmsiStrArrayPtr(wide:true, raw:true)] public int strings; + [OmsiStrArrayPtr(wide: true, raw: true)] public int strings; public byte allExit; } @@ -1149,7 +1238,7 @@ internal struct OmsiHofFISTripInternal [OmsiStrPtr(raw: true)] public int name; // ANSI String public int target; [OmsiStrPtr(raw: true)] public int line; // ANSI String - [OmsiStrArrayPtr(raw:true)] public int busstops; + [OmsiStrArrayPtr(raw: true)] public int busstops; } public struct OmsiCollFeedback { @@ -1331,7 +1420,7 @@ internal struct OmsiDriverInternal [FieldOffset(0x54)] public uint passCount; [FieldOffset(0x58)] public uint ticket_cnt; [FieldOffset(0x5c)] public float tickets_cash; - [FieldOffset(0x60)][OmsiStructArrayPtr(typeof(OmsiPerbus),typeof(OmsiPerbusInternal), true)] public int perbus; + [FieldOffset(0x60)][OmsiStructArrayPtr(typeof(OmsiPerbus), typeof(OmsiPerbusInternal), true)] public int perbus; } public struct OmsiTTLogDetailed { @@ -1426,9 +1515,9 @@ internal struct OmsiTTTrackEntryInternal [FieldOffset(0x14)] public float dist; [FieldOffset(0x18)] public bool valid; [FieldOffset(0x19)] public byte pathOrderCheck; - [FieldOffset(0x1c)] [OmsiStructArrayPtr(typeof(int), raw: true)] public int fstrn_allowed; + [FieldOffset(0x1c)][OmsiStructArrayPtr(typeof(int), raw: true)] public int fstrn_allowed; [FieldOffset(0x20)] public int chronon_origin; - [FieldOffset(0x24)] [OmsiStrArrayPtr(raw: true)] public int chronos_bad; + [FieldOffset(0x24)][OmsiStrArrayPtr(raw: true)] public int chronos_bad; } public struct OmsiTTTrack @@ -1482,7 +1571,7 @@ internal struct OmsiTTBusstopInternal public uint IDCode_real; public int index; public int index_ownList; - [OmsiStructArrayPtr(typeof(int), raw:true)] public int index_alternatives; + [OmsiStructArrayPtr(typeof(int), raw: true)] public int index_alternatives; public float preset_Aussteiger; // Dropouts? [OmsiStruct(typeof(OmsiPathID))] public OmsiPathID pathIndex; public int trackEntry; @@ -1514,7 +1603,7 @@ internal struct OmsiTTProfileInternal [OmsiStrPtr(raw: true)] public int name; public float time_all; [OmsiStructArrayPtr(typeof(OmsiTTStopTime), raw: true)] public int stop_times; - [OmsiStructArrayPtr(typeof(float), raw:true)] public int TrackEntryTime; + [OmsiStructArrayPtr(typeof(float), raw: true)] public int TrackEntryTime; public bool serviceTrip; } @@ -1534,7 +1623,7 @@ public struct OmsiTTTrip } internal struct OmsiTTTripInternal { - [OmsiStrPtr(raw:true)] public int filename; + [OmsiStrPtr(raw: true)] public int filename; public int chrono_origin; [OmsiStrPtr(raw: true)] public int target; [OmsiStrPtr(raw: true)] public int linie; @@ -1726,10 +1815,10 @@ public struct OmsiTTLine internal struct OmsiTTLineInternal { [FieldOffset(0x0)][OmsiStrPtr(raw: true)] public int name; - [FieldOffset(0x4)]public byte userAllowed; - [FieldOffset(0x5)]public byte priority; + [FieldOffset(0x4)] public byte userAllowed; + [FieldOffset(0x5)] public byte priority; [FieldOffset(0x8)][OmsiStructArrayPtr(typeof(OmsiTTTour), typeof(OmsiTTTourInternal), raw: true)] public int tours; - [FieldOffset(0xc)]public int chrono_origin; + [FieldOffset(0xc)] public int chrono_origin; } public struct OmsiRVNumTour @@ -1863,9 +1952,13 @@ public struct OmsiScriptTex { public OmsiPoint size; } - /// - /// This is a place holder struct, confirmation of exact struct data TBC - /// + [StructLayout(LayoutKind.Explicit, Size = 0x20)] + public struct OmsiCriticalSectionInternal + { + [FieldOffset(0x00)] public RTL_CRITICAL_SECTION cs; + [FieldOffset(0x18)] [OmsiStrPtr(StrPtrType.RawDelphiString)] public int name; + [FieldOffset(0x1c)] public uint ident; + } public struct OmsiCriticalSection { public RTL_CRITICAL_SECTION cs; @@ -1941,5 +2034,126 @@ public struct OmsiFileSplinePathInfoInternal [OmsiStructArrayPtr(typeof(OmsiPathRule), typeof(OmsiPathRuleInternal))] public int Rules; } + [StructLayout(LayoutKind.Explicit)] + public struct OmsiBoogieInternal + { + [OmsiStruct(typeof(OmsiPathInfo), typeof(OmsiPathInfoInternal))] + [FieldOffset(0x0)] internal OmsiPathInfoInternal pathInfo; + [FieldOffset(0x110)] internal D3DVector pos; + [FieldOffset(0x11c)] internal D3DXVector2 y_soll; + [FieldOffset(0x124)] internal D3DXVector2 y_harmon; + [FieldOffset(0x12c)] internal float y_gleisfehler; + [FieldOffset(0x130)] internal float z_gleisfehler; + } + + public struct OmsiBoogie + { + public OmsiPathInfo pathInfo; + public D3DVector pos; + public D3DXVector2 y_soll; + public D3DXVector2 y_harmon; + public float y_gleisfehler; + public float z_gleisfehler; + } + + /// + /// Omsi Path Setpoints + /// + public struct OmsiPathSollwerte + { + public float v, x, curve_x_offset, ai_stdbrems; + } + + public struct OmsiMaterialItemInternal + { + [OmsiStruct(typeof(OmsiMaterialProp), typeof(OmsiMaterialPropInternal))] + public OmsiMaterialPropInternal Properties; + } + + public struct OmsiMaterialItem + { + public OmsiMaterialProp Properties; + } + + [StructLayout(LayoutKind.Explicit, Size = 0x68)] + public struct OmsiTextureItemInternal + { + [FieldOffset(0x0)] public ushort size_x; + [FieldOffset(0x2)] public ushort size_y; + [FieldOffset(0x8)] public double mem; + [FieldOffset(0x10)] public int datasize; + [FieldOffset(0x14)] public bool dataready; + [FieldOffset(0x18)] [OmsiObjPtr(typeof(D3DTexture))] public int Texture; + [FieldOffset(0x1c)] [OmsiObjPtr(typeof(D3DTexture))] public int oldTexture; + [FieldOffset(0x20)] [OmsiStrPtr(StrPtrType.RawDelphiAnsiString)] public int path; + [FieldOffset(0x24)] [OmsiStrPtr(StrPtrType.RawDelphiAnsiString)] public int justfilename; + [FieldOffset(0x28)] [OmsiStrPtr(StrPtrType.RawDelphiAnsiString)] public int loadpath; + [FieldOffset(0x2c)] public byte loaded; + [FieldOffset(0x2d)] public byte load_request; + [FieldOffset(0x2e)] public bool managed; + [FieldOffset(0x30)] public uint failed; + [FieldOffset(0x34)] public ushort used; + [FieldOffset(0x36)] public ushort used_highres; + [FieldOffset(0x38)] public bool threadloading; + [FieldOffset(0x39)] public bool hasspecials; + [FieldOffset(0x3a)] public bool no_unload; + [FieldOffset(0x3b)] public bool onlyalpha; + [FieldOffset(0x3c)] public int NightMap; + [FieldOffset(0x40)] public int WinterSnowMap; + [FieldOffset(0x44)] public int WinterSnowfallMap; + [FieldOffset(0x48)] public int FallMap; + [FieldOffset(0x4c)] public int SpringMap; + [FieldOffset(0x50)] public int WinterMap; + [FieldOffset(0x54)] public int SummerDryMap; + [FieldOffset(0x58)] public int SurfMap; + [FieldOffset(0x5c)] public bool moisture; + [FieldOffset(0x5d)] public bool puddles; + [FieldOffset(0x5e)] public bool moisture_ic; + [FieldOffset(0x5f)] public bool puddles_ic; + [FieldOffset(0x60)] public byte surface; + [FieldOffset(0x61)] public byte surface_ic; + [FieldOffset(0x62)] public bool terrainmapping; + [FieldOffset(0x63)] public bool terrainmapping_alpha; + } + + public struct OmsiTextureItem + { + public ushort size_x; + public ushort size_y; + public double mem; + public int datasize; + public bool dataready; + public D3DTexture Texture; + public D3DTexture oldTexture; + public string path; + public string justfilename; + public string loadpath; + public byte loaded; + public byte load_request; + public bool managed; + public uint failed; + public ushort used; + public ushort used_highres; + public bool threadloading; + public bool hasspecials; + public bool no_unload; + public bool onlyalpha; + public int NightMap; + public int WinterSnowMap; + public int WinterSnowfallMap; + public int FallMap; + public int SpringMap; + public int WinterMap; + public int SummerDryMap; + public int SurfMap; + public bool moisture; + public bool puddles; + public bool moisture_ic; + public bool puddles_ic; + public byte surface; + public byte surface_ic; + public bool terrainmapping; + public bool terrainmapping_alpha; + } } diff --git a/OmsiHook/D3DMeshFileObject.cs b/OmsiHook/WrappedOmsiClasses/D3DMeshFileObject.cs similarity index 87% rename from OmsiHook/D3DMeshFileObject.cs rename to OmsiHook/WrappedOmsiClasses/D3DMeshFileObject.cs index d0e46a4..9a61d53 100644 --- a/OmsiHook/D3DMeshFileObject.cs +++ b/OmsiHook/WrappedOmsiClasses/D3DMeshFileObject.cs @@ -15,8 +15,8 @@ public bool Loaded_MeshFileObject } public string Filename { - get => Memory.ReadMemoryString(Address + 0x178); - set => Memory.WriteMemory(Address + 0x178, value); + get => Memory.ReadMemoryString(Address + 0x17c, StrPtrType.DelphiAnsiString); + set => Memory.WriteMemory(Address + 0x17c, value); } public OmsiWeightData[] WeightData { diff --git a/OmsiHook/D3DMeshObject.cs b/OmsiHook/WrappedOmsiClasses/D3DMeshObject.cs similarity index 100% rename from OmsiHook/D3DMeshObject.cs rename to OmsiHook/WrappedOmsiClasses/D3DMeshObject.cs diff --git a/OmsiHook/D3DObject.cs b/OmsiHook/WrappedOmsiClasses/D3DObject.cs similarity index 100% rename from OmsiHook/D3DObject.cs rename to OmsiHook/WrappedOmsiClasses/D3DObject.cs diff --git a/OmsiHook/D3DTransformObject.cs b/OmsiHook/WrappedOmsiClasses/D3DTransformObject.cs similarity index 100% rename from OmsiHook/D3DTransformObject.cs rename to OmsiHook/WrappedOmsiClasses/D3DTransformObject.cs diff --git a/OmsiHook/OmsiActuWeather.cs b/OmsiHook/WrappedOmsiClasses/OmsiActuWeather.cs similarity index 100% rename from OmsiHook/OmsiActuWeather.cs rename to OmsiHook/WrappedOmsiClasses/OmsiActuWeather.cs diff --git a/OmsiHook/WrappedOmsiClasses/OmsiAnimSubMesh.cs b/OmsiHook/WrappedOmsiClasses/OmsiAnimSubMesh.cs new file mode 100644 index 0000000..2651f8b --- /dev/null +++ b/OmsiHook/WrappedOmsiClasses/OmsiAnimSubMesh.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OmsiHook +{ + /// + /// A mesh within a complex mmap object. This represents a single [mesh] tag in a cfg file. + /// + public class OmsiAnimSubMesh : D3DMeshFileObject + { + internal OmsiAnimSubMesh(Memory omsiMemory, int baseAddress) : base(omsiMemory, baseAddress) { } + public OmsiAnimSubMesh() : base() { } + + public string Filename_Int + { + get => Memory.ReadMemoryString(Address + 0x18c, StrPtrType.DelphiAnsiString); + set => Memory.WriteMemory(Address + 0x18c, value, StrPtrType.DelphiAnsiString); + } + public string ident + { + get => Memory.ReadMemoryString(Address + 0x190, StrPtrType.DelphiAnsiString); + set => Memory.WriteMemory(Address + 0x190, value, StrPtrType.DelphiAnsiString); + } + public int AnimParent + { + get => Memory.ReadMemory(Address + 0x194); + set => Memory.WriteMemory(Address + 0x194, value); + } + //public MemArrayList origin + //public MemArrayList originI + //public MemArrayList anim + public int Visible + { + get => Memory.ReadMemory(Address + 0x1a4); + set => Memory.WriteMemory(Address + 0x1a4, value); + } + public int VisibleValue + { + get => Memory.ReadMemory(Address + 0x1a8); + set => Memory.WriteMemory(Address + 0x1a8, value); + } + //public MemArrayList Rauchs + //public MemArrayList LampenSettings + //public MemArrayList InteriorLights + //public MemArrayList BoneProps + public bool SmoothSkin + { + get => Memory.ReadMemory(Address + 0x1bc); + set => Memory.WriteMemory(Address + 0x1bc, value); + } + public float Skin_MaxRelDist + { + get => Memory.ReadMemory(Address + 0x1c0); + set => Memory.WriteMemory(Address + 0x1c0, value); + } + public string MausEvent + { + get => Memory.ReadMemoryString(Address + 0x1c4, StrPtrType.DelphiAnsiString); + set => Memory.WriteMemory(Address + 0x1c4, value, StrPtrType.DelphiAnsiString); + } + public int MyLOD + { + get => Memory.ReadMemory(Address + 0x1c8); + set => Memory.WriteMemory(Address + 0x1c8, value); + } + public byte Flag_GetLights + { + get => Memory.ReadMemory(Address + 0x1cc); + set => Memory.WriteMemory(Address + 0x1cc, value); + } + /* TODO: + public int GetInteriorLights + { + get => Memory.ReadMemory(Address + 0x1cd); + set => Memory.WriteMemory(Address + 0x1cd, value); + }*/ + public byte Flag_ViewPoint + { + get => Memory.ReadMemory(Address + 0x1d1); + set => Memory.WriteMemory(Address + 0x1d1, value); + } + public bool HasShadow + { + get => Memory.ReadMemory(Address + 0x1d2); + set => Memory.WriteMemory(Address + 0x1d2, value); + } + public bool Shadow + { + get => Memory.ReadMemory(Address + 0x1d2); + set => Memory.WriteMemory(Address + 0x1d2, value); + } + } +} diff --git a/OmsiHook/WrappedOmsiClasses/OmsiAnimSubMeshInst.cs b/OmsiHook/WrappedOmsiClasses/OmsiAnimSubMeshInst.cs new file mode 100644 index 0000000..ac742d3 --- /dev/null +++ b/OmsiHook/WrappedOmsiClasses/OmsiAnimSubMeshInst.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OmsiHook +{ + /// + /// A mesh within a complex mmap object. This represents a single [mesh] tag in a cfg file. + /// + public class OmsiAnimSubMeshInst : OmsiObject + { + internal OmsiAnimSubMeshInst(Memory omsiMemory, int baseAddress) : base(omsiMemory, baseAddress) { } + public OmsiAnimSubMeshInst() : base() { } + + public D3DTransformObject ShadowObject // TODO: Should be a D3DShadowObject + { + get => Memory.ReadMemoryObject(Address, 0x4); + } + public D3DMatrix Matrix + { + get => Memory.ReadMemory(Address + 0x8); + set => Memory.WriteMemory(Address + 0x8, value); + } + /// + /// Normalized matrix + /// + public D3DMatrix EntzerrteMatrix + { + get => Memory.ReadMemory(Address + 0x48); + set => Memory.WriteMemory(Address + 0x48, value); + } + public D3DMatrix LocalMatrix + { + get => Memory.ReadMemory(Address + 0x88); + set => Memory.WriteMemory(Address + 0x88, value); + } + /* TODO: + public MemArrayList Matl + { + get => new(Memory, Address + 0xc8); + }*/ + public int Tex + { + get => Memory.ReadMemory(Address + 0xcc); + set => Memory.WriteMemory(Address + 0xcc, value); + } + public bool Visible + { + get => Memory.ReadMemory(Address + 0xd0); + set => Memory.WriteMemory(Address + 0xd0, value); + } + // TODO: MemArrayList Lampen @ 0xd4 + // TODO: MemArrayList InteriorLights @ 0xd8 + // TODO: MemArrayList Anim_LastValue @ 0xdc + public IntPtr SkinMesh // ID3DXMesh + { + get => Memory.ReadMemory(Address + 0xe0); + set => Memory.WriteMemory(Address + 0xe0, value); + } + public bool SkinMesh_Use + { + get => Memory.ReadMemory(Address + 0xe4); + set => Memory.WriteMemory(Address + 0xe4, value); + } + public bool RefreshSkinMesh_Render + { + get => Memory.ReadMemory(Address + 0xe5); + set => Memory.WriteMemory(Address + 0xe5, value); + } + } +} diff --git a/OmsiHook/OmsiBoolClass.cs b/OmsiHook/WrappedOmsiClasses/OmsiBoolClass.cs similarity index 100% rename from OmsiHook/OmsiBoolClass.cs rename to OmsiHook/WrappedOmsiClasses/OmsiBoolClass.cs diff --git a/OmsiHook/WrappedOmsiClasses/OmsiCSReadWrite.cs b/OmsiHook/WrappedOmsiClasses/OmsiCSReadWrite.cs new file mode 100644 index 0000000..e7b62d3 --- /dev/null +++ b/OmsiHook/WrappedOmsiClasses/OmsiCSReadWrite.cs @@ -0,0 +1,16 @@ +namespace OmsiHook +{ + /// + /// Base class for all lockable objects supporting read/write. + /// + public class OmsiCSReadWrite : OmsiCriticalSectionClass + { + internal OmsiCSReadWrite(Memory omsiMemory, int baseAddress) : base(omsiMemory, baseAddress) { } + public OmsiCSReadWrite() : base() { } + + public OmsiCriticalSection[] LockCounter + { + get => Memory.MarshalStructs(Memory.ReadMemoryStructArray(Address + 0x24)); + } + } +} \ No newline at end of file diff --git a/OmsiHook/OmsiCamera.cs b/OmsiHook/WrappedOmsiClasses/OmsiCamera.cs similarity index 100% rename from OmsiHook/OmsiCamera.cs rename to OmsiHook/WrappedOmsiClasses/OmsiCamera.cs diff --git a/OmsiHook/OmsiChrono.cs b/OmsiHook/WrappedOmsiClasses/OmsiChrono.cs similarity index 96% rename from OmsiHook/OmsiChrono.cs rename to OmsiHook/WrappedOmsiClasses/OmsiChrono.cs index d64e31c..b20d4a9 100644 --- a/OmsiHook/OmsiChrono.cs +++ b/OmsiHook/WrappedOmsiClasses/OmsiChrono.cs @@ -6,7 +6,7 @@ public class OmsiChrono : OmsiObject { internal OmsiChrono(Memory omsiMemory, int baseAddress) : base(omsiMemory, baseAddress) { } - internal OmsiChrono() : base() { } + public OmsiChrono() : base() { } /* TODO: public Array? Timeline diff --git a/OmsiHook/OmsiChronoChange.cs b/OmsiHook/WrappedOmsiClasses/OmsiChronoChange.cs similarity index 100% rename from OmsiHook/OmsiChronoChange.cs rename to OmsiHook/WrappedOmsiClasses/OmsiChronoChange.cs diff --git a/OmsiHook/OmsiChronoChangeDel.cs b/OmsiHook/WrappedOmsiClasses/OmsiChronoChangeDel.cs similarity index 100% rename from OmsiHook/OmsiChronoChangeDel.cs rename to OmsiHook/WrappedOmsiClasses/OmsiChronoChangeDel.cs diff --git a/OmsiHook/OmsiChronoChangeLabels.cs b/OmsiHook/WrappedOmsiClasses/OmsiChronoChangeLabels.cs similarity index 100% rename from OmsiHook/OmsiChronoChangeLabels.cs rename to OmsiHook/WrappedOmsiClasses/OmsiChronoChangeLabels.cs diff --git a/OmsiHook/OmsiChronoChangeTyp.cs b/OmsiHook/WrappedOmsiClasses/OmsiChronoChangeTyp.cs similarity index 100% rename from OmsiHook/OmsiChronoChangeTyp.cs rename to OmsiHook/WrappedOmsiClasses/OmsiChronoChangeTyp.cs diff --git a/OmsiHook/OmsiComplMapObj.cs b/OmsiHook/WrappedOmsiClasses/OmsiComplMapObj.cs similarity index 95% rename from OmsiHook/OmsiComplMapObj.cs rename to OmsiHook/WrappedOmsiClasses/OmsiComplMapObj.cs index 7a0e0e0..b7944e5 100644 --- a/OmsiHook/OmsiComplMapObj.cs +++ b/OmsiHook/WrappedOmsiClasses/OmsiComplMapObj.cs @@ -20,7 +20,7 @@ public string Model_Int get => Memory.ReadMemoryString(Address + 0x18c); set => Memory.WriteMemory(Address + 0x18c, value); } - public OmsiPassengerCabin PassengerCabin => new(Memory, Memory.ReadMemory(Address + 0x190)); + public OmsiPassengerCabin PassengerCabin => Memory.ReadMemoryObject(Address, 0x190, false); public bool AbsHeight { get => Memory.ReadMemory(Address + 0x194); @@ -102,7 +102,7 @@ public bool Depot get => Memory.ReadMemory(Address + 0x1c5); set => Memory.WriteMemory(Address + 0x1c5, value); } - public D3DMeshFileObject HeightDeform => new(Memory, Address + 0x1c8); + public D3DMeshFileObject HeightDeform => Memory.ReadMemoryObject(Address, 0x1c8); public string HeightDeform_FileName { get => Memory.ReadMemoryString(Address + 0x1cc); @@ -190,12 +190,11 @@ public OmsiXPC_CreateReturn Script_Return get => Memory.ReadMemory(Address + 0x208); set => Memory.WriteMemory(Address + 0x208, value); } */ - /* TODO: - public OmsiXPC_ConstBlock Script_ConstBlock + + public OmsiConstBlock Script_ConstBlock { - get => Memory.ReadMemory(Address + 0x220); - set => Memory.WriteMemory(Address + 0x220, value); - } */ + get => Memory.ReadMemoryObject(Address, 0x220, false); + } public D3DMatrix[] AttatchmentPnts { get => Memory.ReadMemoryStructArray(Address + 0x224); @@ -241,7 +240,7 @@ public OmsiComplObjPtr ComplObj }*/ public OmsiPathManager ComplObj { - get => new(Memory, Memory.ReadMemory(Address + 0x250)); + get => Memory.ReadMemoryObject(Address, 0x250, false); } public MemArray Paths { diff --git a/OmsiHook/OmsiComplMapObjInst.cs b/OmsiHook/WrappedOmsiClasses/OmsiComplMapObjInst.cs similarity index 71% rename from OmsiHook/OmsiComplMapObjInst.cs rename to OmsiHook/WrappedOmsiClasses/OmsiComplMapObjInst.cs index c3fee26..f4e8d89 100644 --- a/OmsiHook/OmsiComplMapObjInst.cs +++ b/OmsiHook/WrappedOmsiClasses/OmsiComplMapObjInst.cs @@ -11,6 +11,10 @@ public class OmsiComplMapObjInst : OmsiPhysObjInst private MemArrayStringDict varStrings; private MemArrayPtr publicVars; private MemArrayStringDict sVarStrings; + private MemArrayStringDict constStrings; + private MemArrayStringDict funcsStrings; + private OmsiFuncClass[] funcs; + private float[] consts; private MemArray stringVars; internal OmsiComplMapObjInst(Memory omsiMemory, int baseAddress) : base(omsiMemory, baseAddress) { } @@ -24,6 +28,10 @@ internal override void InitObject(Memory memory, int address) publicVars = PublicVars; sVarStrings = ComplMapObj.SVarStrings; stringVars = ComplObjInst.StringVars; + constStrings = ComplMapObj.Script_ConstBlock.Consts_str; + funcsStrings = ComplMapObj.Script_ConstBlock.Funcs_str; + consts = ComplMapObj.Script_ConstBlock.Consts; + funcs = ComplMapObj.Script_ConstBlock.Funcs; } public uint IDCode @@ -33,7 +41,7 @@ public uint IDCode } public OmsiObject MyFileObject { - get => new(Memory, Address + 0x1e8); + get => Memory.ReadMemoryObject(Address, 0x1e8); } public float EinsVar { @@ -81,12 +89,12 @@ public float FarbSchema } public OmsiComplMapObj ComplMapObj { - get => new(Memory, Memory.ReadMemory(Address + 0x210)); + get => Memory.ReadMemoryObject(Address, 0x210, false); } public OmsiComplObjInst ComplObjInst { - get => new(Memory, Memory.ReadMemory(Address + 0x214)); + get => Memory.ReadMemoryObject(Address, 0x214, false); } public bool UseSound { @@ -95,7 +103,7 @@ public bool UseSound } public OmsiSoundPack SoundPack { - get => new(Memory, Memory.ReadMemory(Address + 0x21c)); + get => Memory.ReadMemoryObject(Address, 0x21c, false); } public OmsiCamera[] ReflCameras { @@ -121,7 +129,7 @@ public MemArrayPtr PublicVars } public OmsiComplMapObjInst ScriptShareParent { - get => new(Memory, Memory.ReadMemory(Address + 0x240)); + get => Memory.ReadMemoryObject(Address, 0x240, false); } public float[] UserVars { @@ -204,5 +212,61 @@ public void SetStringVariable(string varName, string value) throw new KeyNotFoundException($"String Variable '{varName}' not found in object. - Index Out Of Bounds"); stringVars[index] = new(value); } + + /// + /// Get a constant for an object from its name. + /// + /// Const Name + /// requested float value + /// + public float GetConst(string varName) + { + int index = constStrings[varName]; + if (index >= consts.Length || index < 0) + throw new KeyNotFoundException($"Const Variable '{varName}' not found in object. - Index Out Of Bounds"); + return consts[index]; + } + + /// + /// Get a value at a point for a predifined curve for an object from its name. + /// + /// Const Name + /// X Coordinate to read on curve + /// requested float value + /// + public float GetCurve(string varName, float x) + { + int index = funcsStrings[varName]; + if (index >= consts.Length || index < 0) + throw new KeyNotFoundException($"Curve Variable '{varName}' not found in object. - Index Out Of Bounds"); + + var curve = funcs[index].Pnts; + for (int i = 0; i < curve.Length - 1; i++) + { + float x1 = curve[i].x; + float y1 = curve[i].y; + + float x2 = curve[i + 1].x; + float y2 = curve[i + 1].y; + + if (x >= x1 && x <= x2) + { + // Perform linear interpolation + float y = y1 + (x - x1) * (y2 - y1) / (x2 - x1); + return y; + } + } + if (x <= curve[0].x) + return curve[0].y; + if (x >= curve[curve.Length-1].x) + return curve[curve.Length - 1].y; + return float.NaN; + } + + /// + public async void SoundTrigger(string trigger, string filename) + { + await OmsiRemoteMethods.OmsiSoundTrigger(this, trigger, filename); + } } } \ No newline at end of file diff --git a/OmsiHook/OmsiComplMapSceneObjInst.cs b/OmsiHook/WrappedOmsiClasses/OmsiComplMapSceneObjInst.cs similarity index 100% rename from OmsiHook/OmsiComplMapSceneObjInst.cs rename to OmsiHook/WrappedOmsiClasses/OmsiComplMapSceneObjInst.cs diff --git a/OmsiHook/OmsiComplObj.cs b/OmsiHook/WrappedOmsiClasses/OmsiComplObj.cs similarity index 91% rename from OmsiHook/OmsiComplObj.cs rename to OmsiHook/WrappedOmsiClasses/OmsiComplObj.cs index f1fe62b..c500a20 100644 --- a/OmsiHook/OmsiComplObj.cs +++ b/OmsiHook/WrappedOmsiClasses/OmsiComplObj.cs @@ -20,14 +20,14 @@ public bool Lighting_Human set => Memory.WriteMemory(Address + 0x4, value); } // TODO: Check this data type, should be a TStringList - public string[] FileText + /*public string[] FileText { get => Memory.ReadMemoryStringArray(Address + 0x8); //set => Memory.WriteMemory(Address + 0x4, value); - } + }*/ public string Code { - get => Memory.ReadMemoryString(Address + 0xc); + get => Memory.ReadMemoryString(Address + 0xc, StrPtrType.DelphiAnsiString); set => Memory.WriteMemory(Address + 0xc, value); } public D3DVector VFDMax @@ -42,12 +42,12 @@ public D3DVector VFDMin } public string FileName { - get => Memory.ReadMemoryString(Address + 0x28); + get => Memory.ReadMemoryString(Address + 0x28, StrPtrType.DelphiAnsiString); set => Memory.WriteMemory(Address + 0x28, value); } public string MyPath { - get => Memory.ReadMemoryString(Address + 0x2c); + get => Memory.ReadMemoryString(Address + 0x2c, StrPtrType.DelphiAnsiString); set => Memory.WriteMemory(Address + 0x2c, value); } public int FileVersion @@ -60,12 +60,10 @@ public int FileVersion_Hole get => Memory.ReadMemory(Address + 0x34); set => Memory.WriteMemory(Address + 0x34, value); } - /* TODO: - public OmsiAnimSubMesh[] Meshs + public MemArrayList Meshes { - get => Memory.ReadMemoryObjArray(Address + 0x38); - //set => Memory.WriteMemory(Address + 0x34, value); - }*/ + get => new(Memory, Address + 0x38); + } /* TODO: public OmsiTexChangeMaster[] TexChangeMasters { @@ -149,7 +147,7 @@ public bool Inc_SkinMesh } public string TerrainHole_FileName { - get => Memory.ReadMemoryString(Address + 0xb0); + get => Memory.ReadMemoryString(Address + 0xb0, StrPtrType.DelphiAnsiString); set => Memory.WriteMemory(Address + 0xb0, value); } public bool GotAllTerrainHoles diff --git a/OmsiHook/OmsiComplObjInst.cs b/OmsiHook/WrappedOmsiClasses/OmsiComplObjInst.cs similarity index 96% rename from OmsiHook/OmsiComplObjInst.cs rename to OmsiHook/WrappedOmsiClasses/OmsiComplObjInst.cs index 5305d9f..e20331e 100644 --- a/OmsiHook/OmsiComplObjInst.cs +++ b/OmsiHook/WrappedOmsiClasses/OmsiComplObjInst.cs @@ -61,7 +61,7 @@ public float Refresh_OFT } public OmsiComplObj ComplObj { - get => new(Memory, Address + 0x20); + get => Memory.ReadMemoryObject(Address, 0x20, false); } public byte ViewPoint_Opt { @@ -151,11 +151,10 @@ public D3DMatrix Shadow_Matrix get => Memory.ReadMemory(Address + 0x9d); set => Memory.WriteMemory(Address + 0x9d, value); } - /* TODO: - public OmsiAnimSubMeshInst[] AnimSubMeshInsts + public MemArrayList AnimSubMeshInsts { - get => Memory.ReadMemoryObjArray(Address + 0xe0); - }*/ + get => new(Memory, Address + 0xe0); + } /* TODO: public OmsiInteriorLightInst[] AnimSubMeshInsts { diff --git a/OmsiHook/WrappedOmsiClasses/OmsiConstBlock.cs b/OmsiHook/WrappedOmsiClasses/OmsiConstBlock.cs new file mode 100644 index 0000000..1ce9e6c --- /dev/null +++ b/OmsiHook/WrappedOmsiClasses/OmsiConstBlock.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OmsiHook +{ + /// + /// An object's ConstFile Structure + /// + public class OmsiConstBlock : OmsiObject + { + internal OmsiConstBlock(Memory omsiMemory, int baseAddress) : base(omsiMemory, baseAddress) { } + public OmsiConstBlock() : base() { } + public float[] Consts => Memory.ReadMemoryStructArray(Address + 0x4); + + private MemArrayStringDict consts_str; + public MemArrayStringDict Consts_str => consts_str ??= new (Memory, Address + 0x8, true); + + public OmsiFuncClass[] Funcs => Memory.ReadMemoryObjArray(Address + 0xc); + + private MemArrayStringDict funcs_str; + public MemArrayStringDict Funcs_str => funcs_str ??= new(Memory, Address + 0x10, true); + } +} diff --git a/OmsiHook/OmsiCoordSystem.cs b/OmsiHook/WrappedOmsiClasses/OmsiCoordSystem.cs similarity index 100% rename from OmsiHook/OmsiCoordSystem.cs rename to OmsiHook/WrappedOmsiClasses/OmsiCoordSystem.cs diff --git a/OmsiHook/WrappedOmsiClasses/OmsiCriticalSectionClass.cs b/OmsiHook/WrappedOmsiClasses/OmsiCriticalSectionClass.cs new file mode 100644 index 0000000..778031e --- /dev/null +++ b/OmsiHook/WrappedOmsiClasses/OmsiCriticalSectionClass.cs @@ -0,0 +1,19 @@ +using System.Net; + +namespace OmsiHook +{ + /// + /// Base class for all lockable objects. + /// + public class OmsiCriticalSectionClass : OmsiObject + { + internal OmsiCriticalSectionClass(Memory omsiMemory, int baseAddress) : base(omsiMemory, baseAddress) { } + public OmsiCriticalSectionClass() : base() { } + + public OmsiCriticalSection CS + { + get => Memory.MarshalStruct(Memory.ReadMemory(Address + 0x4)); + set => Memory.WriteMemory(Address + 0x4, Memory.UnMarshalStruct(value)); + } + } +} \ No newline at end of file diff --git a/OmsiHook/OmsiDynHelperMan.cs b/OmsiHook/WrappedOmsiClasses/OmsiDynHelperMan.cs similarity index 100% rename from OmsiHook/OmsiDynHelperMan.cs rename to OmsiHook/WrappedOmsiClasses/OmsiDynHelperMan.cs diff --git a/OmsiHook/OmsiFileObject.cs b/OmsiHook/WrappedOmsiClasses/OmsiFileObject.cs similarity index 94% rename from OmsiHook/OmsiFileObject.cs rename to OmsiHook/WrappedOmsiClasses/OmsiFileObject.cs index d6d463b..412d03f 100644 --- a/OmsiHook/OmsiFileObject.cs +++ b/OmsiHook/WrappedOmsiClasses/OmsiFileObject.cs @@ -11,7 +11,7 @@ internal OmsiFileObject(Memory memory, int address) : base(memory, address) { } public OmsiComplMapObj MyComplMapObj { - get => new(Memory, Memory.ReadMemory(Address + 0x4)); + get => Memory.ReadMemoryObject(Address, 0x4, false); } public uint IDCode { @@ -70,11 +70,11 @@ public float Bank } public OmsiFileObject AttObj { - get => new(Memory, Memory.ReadMemory(Address + 0x34)); + get => Memory.ReadMemoryObject(Address, 0x34, false); } public OmsiFileSpline AttSpln { - get => new(Memory, Memory.ReadMemory(Address + 0x38)); + get => Memory.ReadMemoryObject(Address, 0x38, false); } public int AttPnt { @@ -149,7 +149,7 @@ public OmsiChronoChange[] Chrono_Changes } public OmsiObjChronoVars Chrono_Active { - get => new(Memory, Memory.ReadMemory(Address + 0x70)); + get => Memory.ReadMemoryObject(Address, 0x70, false); } public bool Chrono_Own { diff --git a/OmsiHook/OmsiFileSpline.cs b/OmsiHook/WrappedOmsiClasses/OmsiFileSpline.cs similarity index 95% rename from OmsiHook/OmsiFileSpline.cs rename to OmsiHook/WrappedOmsiClasses/OmsiFileSpline.cs index 0e88567..acf1cc5 100644 --- a/OmsiHook/OmsiFileSpline.cs +++ b/OmsiHook/WrappedOmsiClasses/OmsiFileSpline.cs @@ -123,7 +123,7 @@ public bool Mirror get => Memory.ReadMemory(Address + 0x58); set => Memory.WriteMemory(Address + 0x58, value); } - public OmsiSplineSegment MySegment => new(Memory, Memory.ReadMemory(Address + 0x5c)); + public OmsiSplineSegment MySegment => Memory.ReadMemoryObject(Address, 0x5c, false); public MemArray Paths => new(Memory, Memory.ReadMemory(Address + 0x60), true); public int Chrono_Origin { @@ -131,6 +131,6 @@ public int Chrono_Origin set => Memory.WriteMemory(Address + 0x64, value); } public OmsiChronoChange[] Chrono_Changes => Memory.ReadMemoryObjArray(Address + 0x68); - public OmsiObjChronoVars Chrono_Active => new(Memory, Memory.ReadMemory(Address + 0x6c)); + public OmsiObjChronoVars Chrono_Active => Memory.ReadMemoryObject(Address, 0x6c, false); } } \ No newline at end of file diff --git a/OmsiHook/OmsiFileTerrain.cs b/OmsiHook/WrappedOmsiClasses/OmsiFileTerrain.cs similarity index 100% rename from OmsiHook/OmsiFileTerrain.cs rename to OmsiHook/WrappedOmsiClasses/OmsiFileTerrain.cs diff --git a/OmsiHook/OmsiFileWater.cs b/OmsiHook/WrappedOmsiClasses/OmsiFileWater.cs similarity index 100% rename from OmsiHook/OmsiFileWater.cs rename to OmsiHook/WrappedOmsiClasses/OmsiFileWater.cs diff --git a/OmsiHook/OmsiFreeTexInst.cs b/OmsiHook/WrappedOmsiClasses/OmsiFreeTexInst.cs similarity index 100% rename from OmsiHook/OmsiFreeTexInst.cs rename to OmsiHook/WrappedOmsiClasses/OmsiFreeTexInst.cs diff --git a/OmsiHook/OmsiFuncClass.cs b/OmsiHook/WrappedOmsiClasses/OmsiFuncClass.cs similarity index 100% rename from OmsiHook/OmsiFuncClass.cs rename to OmsiHook/WrappedOmsiClasses/OmsiFuncClass.cs diff --git a/OmsiHook/OmsiHOF.cs b/OmsiHook/WrappedOmsiClasses/OmsiHOF.cs similarity index 100% rename from OmsiHook/OmsiHOF.cs rename to OmsiHook/WrappedOmsiClasses/OmsiHOF.cs diff --git a/OmsiHook/OmsiHumanBeing.cs b/OmsiHook/WrappedOmsiClasses/OmsiHumanBeing.cs similarity index 99% rename from OmsiHook/OmsiHumanBeing.cs rename to OmsiHook/WrappedOmsiClasses/OmsiHumanBeing.cs index e59680e..3c0f2f1 100644 --- a/OmsiHook/OmsiHumanBeing.cs +++ b/OmsiHook/WrappedOmsiClasses/OmsiHumanBeing.cs @@ -8,7 +8,7 @@ namespace OmsiHook public class OmsiHumanBeing : OmsiComplMapObj { internal OmsiHumanBeing(Memory omsiMemory, int baseAddress) : base(omsiMemory, baseAddress) { } - internal OmsiHumanBeing() : base() { } + public OmsiHumanBeing() : base() { } public string Voice { diff --git a/OmsiHook/OmsiHumanBeingInst.cs b/OmsiHook/WrappedOmsiClasses/OmsiHumanBeingInst.cs similarity index 96% rename from OmsiHook/OmsiHumanBeingInst.cs rename to OmsiHook/WrappedOmsiClasses/OmsiHumanBeingInst.cs index 74b14f9..221d83e 100644 --- a/OmsiHook/OmsiHumanBeingInst.cs +++ b/OmsiHook/WrappedOmsiClasses/OmsiHumanBeingInst.cs @@ -31,14 +31,14 @@ public bool Tutorial_Created get => Memory.ReadMemory(Address + 0x5a8); set => Memory.WriteMemory(Address + 0x5a8, value); } - public int Index + public int HBIndex { get => Memory.ReadMemory(Address + 0x5ac); set => Memory.WriteMemory(Address + 0x5ac, value); } public OmsiHumanBeing Human { - get => new(Memory, Memory.ReadMemory(Address + 0x5b0)); + get => Memory.ReadMemoryObject(Address, 0x5b0, false); } public float FreeDist { @@ -92,19 +92,19 @@ public D3DMatrix TargetMat } public OmsiPathManager PathManager { - get => new(Memory, Memory.ReadMemory(Address + 0x5dc)); + get => Memory.ReadMemoryObject(Address, 0x5dc, false); } public OmsiPathPointBasic PathPointTarget { - get => new(Memory, Memory.ReadMemory(Address + 0x5e0)); + get => Memory.ReadMemoryObject(Address, 0x5e0, false); } public OmsiPathPointBasic PathPointNext { - get => new(Memory, Memory.ReadMemory(Address + 0x5e4)); + get => Memory.ReadMemoryObject(Address, 0x5e4, false); } public OmsiPathPointBasic ActPathPoint { - get => new(Memory, Memory.ReadMemory(Address + 0x5e8)); + get => Memory.ReadMemoryObject(Address, 0x5e8, false); } public bool WaitBeforeEnd { @@ -380,7 +380,7 @@ public int MyBusIndex_Temp } public OmsiRoadVehicleInst MyBus { - get => new(Memory, Memory.ReadMemory(Address + 0x6b4)); + get => Memory.ReadMemoryObject(Address, 0x6b4, false); } public uint MyBusCode { diff --git a/OmsiHook/OmsiKachelForest.cs b/OmsiHook/WrappedOmsiClasses/OmsiKachelForest.cs similarity index 93% rename from OmsiHook/OmsiKachelForest.cs rename to OmsiHook/WrappedOmsiClasses/OmsiKachelForest.cs index d50fffa..ac9ecd1 100644 --- a/OmsiHook/OmsiKachelForest.cs +++ b/OmsiHook/WrappedOmsiClasses/OmsiKachelForest.cs @@ -41,6 +41,6 @@ public bool Visible } public OmsiTree[] Trees => Memory.ReadMemoryStructArray(Address + 0x18); - public D3DMeshObject MeshObject => new(Memory, Memory.ReadMemory(Address + 0x1c)); + public D3DMeshObject MeshObject => Memory.ReadMemoryObject(Address, 0x1c, false); } } \ No newline at end of file diff --git a/OmsiHook/OmsiMap.cs b/OmsiHook/WrappedOmsiClasses/OmsiMap.cs similarity index 95% rename from OmsiHook/OmsiMap.cs rename to OmsiHook/WrappedOmsiClasses/OmsiMap.cs index 9abde2f..aa7e508 100644 --- a/OmsiHook/OmsiMap.cs +++ b/OmsiHook/WrappedOmsiClasses/OmsiMap.cs @@ -64,7 +64,7 @@ public bool Ignore_TruckFlags set => Memory.WriteMemory(Address + 0x24, value); } - public OmsiChrono Chrono => new(Memory, Memory.ReadMemory(Address + 0x28)); + public OmsiChrono Chrono => Memory.ReadMemoryObject(Address, 0x28, false); public bool Splines_Refreshed { @@ -127,12 +127,12 @@ public bool DynHelperActive public OmsiFuncClass Func_TrafficDensity_Passenger { - get => new(Memory, Memory.ReadMemory(Address + 0x104)); + get => Memory.ReadMemoryObject(Address, 0x104, false); } public OmsiFuncClass Func_TrafficDensity_Road { - get => new(Memory, Memory.ReadMemory(Address + 0x108)); + get => Memory.ReadMemoryObject(Address, 0x108, false); } public float Acct_TrafficDensity_Passenger @@ -279,13 +279,13 @@ public float WellenAnimation //TODO: This is meant to be an array of pointers to floats, which can't be marshalled yet //public float[] WellenAnimation_P => Memory.ReadMemoryStructArray(Address + 0x190); - public OmsiStringList Registers => new(Memory, Memory.ReadMemory(Address + 0x194)); + public OmsiStringList Registers => Memory.ReadMemoryObject(Address, 0x194, false); public OmsiStringList[] CarsParked_Array => Memory.ReadMemoryObjArray(Address + 0x198); - public OmsiStringList Humans => new(Memory, Memory.ReadMemory(Address + 0x19c)); + public OmsiStringList Humans => Memory.ReadMemoryObject(Address, 0x19c, false); - public OmsiStringList Drivers => new(Memory, Memory.ReadMemory(Address + 0x1a0)); + public OmsiStringList Drivers => Memory.ReadMemoryObject(Address, 0x1a0, false); /*TODO: There's a bug when dereferencing this public OmsiAIList AIList diff --git a/OmsiHook/OmsiMapKachel.cs b/OmsiHook/WrappedOmsiClasses/OmsiMapKachel.cs similarity index 90% rename from OmsiHook/OmsiMapKachel.cs rename to OmsiHook/WrappedOmsiClasses/OmsiMapKachel.cs index 87ec262..ba0dd96 100644 --- a/OmsiHook/OmsiMapKachel.cs +++ b/OmsiHook/WrappedOmsiClasses/OmsiMapKachel.cs @@ -98,8 +98,8 @@ public float Width_N } public OmsiFileObject[] ObjectsFromFile => Memory.ReadMemoryObjArray(Address + 0x48); - public OmsiFileTerrain TerrainFromFile => new(Memory, Memory.ReadMemory(Address + 0x4c)); - public OmsiFileWater WaterFromFile => new(Memory, Memory.ReadMemory(Address + 0x50)); + public OmsiFileTerrain TerrainFromFile => Memory.ReadMemoryObject(Address, 0x4c, false); + public OmsiFileWater WaterFromFile => Memory.ReadMemoryObject(Address, 0x50, false); public OmsiFileSpline[] SplinesFromFile => Memory.ReadMemoryObjArray(Address + 0x54); public bool Splines_Refreshed @@ -130,7 +130,7 @@ public bool PathsLinkedWithFstrn } public OmsiAmpelGroup[] AmpelGroups => Memory.MarshalStructs( Memory.ReadMemoryStructArray(Address + 0x6c)); - public D3DMeshFileObject TileMesh => new(Memory, Memory.ReadMemory(Address + 0x70)); + public D3DMeshFileObject TileMesh => Memory.ReadMemoryObject(Address, 0x70, false); public string TexPath { get => Memory.ReadMemoryString(Address + 0x74); @@ -145,8 +145,8 @@ public bool Trees_Refreshed get => Memory.ReadMemory(Address + 0x80); set => Memory.WriteMemory(Address + 0x80, value); } - public OmsiKachelForest MyForest => new(Memory, Memory.ReadMemory(Address + 0x84)); - public OmsiKachelForest MyScrubs => new(Memory, Memory.ReadMemory(Address + 0x88)); + public OmsiKachelForest MyForest => Memory.ReadMemoryObject(Address, 0x84, false); + public OmsiKachelForest MyScrubs => Memory.ReadMemoryObject(Address, 0x88, false); //TODO: Many more... } } \ No newline at end of file diff --git a/OmsiHook/OmsiMapObjInst.cs b/OmsiHook/WrappedOmsiClasses/OmsiMapObjInst.cs similarity index 100% rename from OmsiHook/OmsiMapObjInst.cs rename to OmsiHook/WrappedOmsiClasses/OmsiMapObjInst.cs diff --git a/OmsiHook/WrappedOmsiClasses/OmsiMaterialMan.cs b/OmsiHook/WrappedOmsiClasses/OmsiMaterialMan.cs new file mode 100644 index 0000000..bd87646 --- /dev/null +++ b/OmsiHook/WrappedOmsiClasses/OmsiMaterialMan.cs @@ -0,0 +1,26 @@ +namespace OmsiHook +{ + /// + /// In material manager + /// + public class OmsiMaterialMan : OmsiObject + { + internal OmsiMaterialMan(Memory omsiMemory, int baseAddress) : base(omsiMemory, baseAddress) { } + public OmsiMaterialMan() : base() { } + + /// + /// Note that this field seems to be mostly unused by Omsi, hence it's always empty... + /// + public MemArray MaterialItems => new(Memory, Address + 0x4); + public D3DMaterial9 StdMaterial + { + get => Memory.ReadMemory(Address + 0x8); + set => Memory.WriteMemory(Address + 0x8, value); + } + public D3DMaterial9 ReflMaterial + { + get => Memory.ReadMemory(Address + 0x4c); + set => Memory.WriteMemory(Address + 0x4c, value); + } + } +} \ No newline at end of file diff --git a/OmsiHook/WrappedOmsiClasses/OmsiMovingMapObjInst.cs b/OmsiHook/WrappedOmsiClasses/OmsiMovingMapObjInst.cs new file mode 100644 index 0000000..039de74 --- /dev/null +++ b/OmsiHook/WrappedOmsiClasses/OmsiMovingMapObjInst.cs @@ -0,0 +1,241 @@ +namespace OmsiHook +{ + /// + /// Base Class for all instances of moving map objects - vehicles / humans + /// + public class OmsiMovingMapObjInst : OmsiComplMapObjInst + { + internal OmsiMovingMapObjInst(Memory omsiMemory, int baseAddress) : base(omsiMemory, baseAddress) { } + public OmsiMovingMapObjInst() : base() { } + + public int Index + { + get => Memory.ReadMemory(Address + 0x258); + set => Memory.WriteMemory(Address + 0x258, value); + } + public bool MarkedForKilling + { + get => Memory.ReadMemory(Address + 0x25c); + set => Memory.WriteMemory(Address + 0x25c, value); + } + public MemArray Boogies + { + get => new(Memory, Address + 0x260); + } + /// + /// Boogies Init Virbrations + /// + public bool Boogies_InitSchwingungen + { + get => Memory.ReadMemory(Address + 0x264); + set => Memory.WriteMemory(Address + 0x264, value); + } + /// + /// Steering arm + /// + public float Lenkhebel + { + get => Memory.ReadMemory(Address + 0x268); + set => Memory.WriteMemory(Address + 0x268, value); + } + public bool UserTrain + { + get => Memory.ReadMemory(Address + 0x26c); + set => Memory.WriteMemory(Address + 0x26c, value); + } + public bool UserTrain_Render + { + get => Memory.ReadMemory(Address + 0x26c); + set => Memory.WriteMemory(Address + 0x26c, value); + } + public D3DVector Last_Position + { + get => Memory.ReadMemory(Address + 0x26e); + set => Memory.WriteMemory(Address + 0x26e, value); + } + public D3DXQuaternion Last_Rotation + { + get => Memory.ReadMemory(Address + 0x27a); + set => Memory.WriteMemory(Address + 0x27a, value); + } + public D3DMatrix RelMatrixVar + { + get => Memory.ReadMemory(Address + 0x28a); + set => Memory.WriteMemory(Address + 0x28a, value); + } + public OmsiPoint MyKachelPnt + { + get => Memory.ReadMemory(Address + 0x2cc); + set => Memory.WriteMemory(Address + 0x2cc, value); + } + public OmsiPoint CenterKachel + { + get => Memory.ReadMemory(Memory.ReadMemory(Address + 0x2d44)); + } + public uint CalcTimer + { + get => Memory.ReadMemory(Address + 0x2d8); + set => Memory.WriteMemory(Address + 0x2d8, value); + } + public bool Visible_Logical + { + get => Memory.ReadMemory(Address + 0x2dc); + set => Memory.WriteMemory(Address + 0x2dc, value); + } + public bool Visible_Logical_RenderThread + { + get => Memory.ReadMemory(Address + 0x2dd); + set => Memory.WriteMemory(Address + 0x2dd, value); + } + public bool PathFixed + { + get => Memory.ReadMemory(Address + 0x2de); + set => Memory.WriteMemory(Address + 0x2de, value); + } + public OmsiPathInfo PathInfo + { + get => Memory.MarshalStruct(Memory.ReadMemory(Address + 0x2e0)); + set => Memory.WriteMemory(Address + 0x2e0, Memory.UnMarshalStruct(value)); + } + public float PathVOffset + { + get => Memory.ReadMemory(Address + 0x3f0); + set => Memory.WriteMemory(Address + 0x3f0, value); + } + public byte TrafficType + { + get => Memory.ReadMemory(Address + 0x3f4); + set => Memory.WriteMemory(Address + 0x3f4, value); + } + public float PAI_Hdg_Soll + { + get => Memory.ReadMemory(Address + 0x3f8); + set => Memory.WriteMemory(Address + 0x3f8, value); + } + public float PAI_Hdg_Ist + { + get => Memory.ReadMemory(Address + 0x3fc); + set => Memory.WriteMemory(Address + 0x3fc, value); + } + public float PAI_Wagenwinkel + { + get => Memory.ReadMemory(Address + 0x400); + set => Memory.WriteMemory(Address + 0x400, value); + } + public float PAI_DeltaBeta + { + get => Memory.ReadMemory(Address + 0x404); + set => Memory.WriteMemory(Address + 0x404, value); + } + public float PAI_DeltaAlpha + { + get => Memory.ReadMemory(Address + 0x408); + set => Memory.WriteMemory(Address + 0x408, value); + } + public float PAI_InvLenk_Ist + { + get => Memory.ReadMemory(Address + 0x40c); + set => Memory.WriteMemory(Address + 0x40c, value); + } + public float PAI_MovingDistance + { + get => Memory.ReadMemory(Address + 0x410); + set => Memory.WriteMemory(Address + 0x410, value); + } + public OmsiPathSollwerte PAI_Soll + { + get => Memory.ReadMemory(Address + 0x414); + set => Memory.WriteMemory(Address + 0x414, value); + } + public float Tacho + { + get => Memory.ReadMemory(Address + 0x424); + set => Memory.WriteMemory(Address + 0x424, value); + } + public float Groundspeed + { + get => Memory.ReadMemory(Address + 0x428); + set => Memory.WriteMemory(Address + 0x428, value); + } + public double KMCounter + { + get => Memory.ReadMemory (Address + 0x430); + set => Memory.WriteMemory(Address + 0x430, value); + } + public double KMCounter_Init + { + get => Memory.ReadMemory(Address + 0x438); + set => Memory.WriteMemory(Address + 0x438, value); + } + public float KMCounter_KM + { + get => Memory.ReadMemory(Address + 0x440); + set => Memory.WriteMemory(Address + 0x440, value); + } + public float KMCounter_M + { + get => Memory.ReadMemory(Address + 0x444); + set => Memory.WriteMemory(Address + 0x444, value); + } + public float RelRange + { + get => Memory.ReadMemory(Address + 0x448); + set => Memory.WriteMemory(Address + 0x448, value); + } + public D3DMatrix OutsideMatrix + { + get => Memory.ReadMemory(Address + 0x44c); + set => Memory.WriteMemory(Address + 0x44c, value); + } + public D3DMatrix OutsideMatrix_ThreadFree + { + get => Memory.ReadMemory(Address + 0x48c); + set => Memory.WriteMemory(Address + 0x48c, value); + } + public float Sound_Reverb_Dist + { + get => Memory.ReadMemory(Address + 0x4cc); + set => Memory.WriteMemory(Address + 0x4cc, value); + } + public OmsiMovingMapObjInst VB_First + { + get => Memory.ReadMemoryObject(Address, 0x4d0, false); + } + public OmsiMovingMapObjInst VB_Last + { + get => Memory.ReadMemoryObject(Address, 0x4d4, false); + } + public OmsiMovingMapObjInst VB_Next + { + get => Memory.ReadMemoryObject(Address, 0x4d8, false); + } + public OmsiMovingMapObjInst VB_Prev + { + get => Memory.ReadMemoryObject(Address, 0x4dc, false); + } + public bool VB_Me_Reverse + { + get => Memory.ReadMemory(Address + 0x4e0); + set => Memory.WriteMemory(Address + 0x4e0, value); + } + public bool VB_SchedUnit_Reverse + { + get => Memory.ReadMemory(Address + 0x4e1); + set => Memory.WriteMemory(Address + 0x4e1, value); + } + public bool VB_Leading + { + get => Memory.ReadMemory(Address + 0x4e2); + set => Memory.WriteMemory(Address + 0x4e2, value); + } + public OmsiMovingMapObjInst VB_SoundRef + { + get => Memory.ReadMemoryObject(Address, 0x4e4, false); + } + public bool RL_ExitReq + { + get => Memory.ReadMemory(Address + 0x4e8); + set => Memory.WriteMemory(Address + 0x4e8, value); + } + } +} \ No newline at end of file diff --git a/OmsiHook/WrappedOmsiClasses/OmsiMyOmsiList.cs b/OmsiHook/WrappedOmsiClasses/OmsiMyOmsiList.cs new file mode 100644 index 0000000..6312dd0 --- /dev/null +++ b/OmsiHook/WrappedOmsiClasses/OmsiMyOmsiList.cs @@ -0,0 +1,18 @@ +using System.Net; + +namespace OmsiHook +{ + /// + /// A somewhat specialised version of a generic list; used to store road vehicles. + /// + public class OmsiMyOmsiList : OmsiCSReadWrite where T : OmsiObject, new() + { + internal OmsiMyOmsiList(Memory omsiMemory, int baseAddress) : base(omsiMemory, baseAddress) { } + public OmsiMyOmsiList() : base() { } + + public MemArrayList FList => new(Memory, Address + 0x28, false); + public int FCount => Memory.ReadMemory(Address + 0x2c); + public string Name => Memory.ReadMemoryString(Address + 0x30, StrPtrType.DelphiString); + public bool FAI => Memory.ReadMemory(Address + 0x34); + } +} \ No newline at end of file diff --git a/OmsiHook/OmsiObjBlackRect.cs b/OmsiHook/WrappedOmsiClasses/OmsiObjBlackRect.cs similarity index 100% rename from OmsiHook/OmsiObjBlackRect.cs rename to OmsiHook/WrappedOmsiClasses/OmsiObjBlackRect.cs diff --git a/OmsiHook/OmsiObjChronoVars.cs b/OmsiHook/WrappedOmsiClasses/OmsiObjChronoVars.cs similarity index 100% rename from OmsiHook/OmsiObjChronoVars.cs rename to OmsiHook/WrappedOmsiClasses/OmsiObjChronoVars.cs diff --git a/OmsiHook/OmsiPartikel.cs b/OmsiHook/WrappedOmsiClasses/OmsiPartikel.cs similarity index 100% rename from OmsiHook/OmsiPartikel.cs rename to OmsiHook/WrappedOmsiClasses/OmsiPartikel.cs diff --git a/OmsiHook/OmsiPartikelemitter.cs b/OmsiHook/WrappedOmsiClasses/OmsiPartikelemitter.cs similarity index 100% rename from OmsiHook/OmsiPartikelemitter.cs rename to OmsiHook/WrappedOmsiClasses/OmsiPartikelemitter.cs diff --git a/OmsiHook/OmsiPassengerCabin.cs b/OmsiHook/WrappedOmsiClasses/OmsiPassengerCabin.cs similarity index 100% rename from OmsiHook/OmsiPassengerCabin.cs rename to OmsiHook/WrappedOmsiClasses/OmsiPassengerCabin.cs diff --git a/OmsiHook/OmsiPathGroup.cs b/OmsiHook/WrappedOmsiClasses/OmsiPathGroup.cs similarity index 100% rename from OmsiHook/OmsiPathGroup.cs rename to OmsiHook/WrappedOmsiClasses/OmsiPathGroup.cs diff --git a/OmsiHook/OmsiPathManager.cs b/OmsiHook/WrappedOmsiClasses/OmsiPathManager.cs similarity index 90% rename from OmsiHook/OmsiPathManager.cs rename to OmsiHook/WrappedOmsiClasses/OmsiPathManager.cs index 2c0675c..8dc5e42 100644 --- a/OmsiHook/OmsiPathManager.cs +++ b/OmsiHook/WrappedOmsiClasses/OmsiPathManager.cs @@ -14,7 +14,7 @@ public int StepSoundPacks } public OmsiPathPointBasic MyClass { - get => new OmsiPathPointBasic(Memory, Memory.ReadMemory(Address + 0x8)); + get => Memory.ReadMemoryObject(Address, 0x8, false); } /* TODO: public OmsiPathPoint[] PathPoints diff --git a/OmsiHook/OmsiPathPointBasic.cs b/OmsiHook/WrappedOmsiClasses/OmsiPathPointBasic.cs similarity index 100% rename from OmsiHook/OmsiPathPointBasic.cs rename to OmsiHook/WrappedOmsiClasses/OmsiPathPointBasic.cs diff --git a/OmsiHook/OmsiPathSegment.cs b/OmsiHook/WrappedOmsiClasses/OmsiPathSegment.cs similarity index 97% rename from OmsiHook/OmsiPathSegment.cs rename to OmsiHook/WrappedOmsiClasses/OmsiPathSegment.cs index 79e3734..ff57104 100644 --- a/OmsiHook/OmsiPathSegment.cs +++ b/OmsiHook/WrappedOmsiClasses/OmsiPathSegment.cs @@ -27,7 +27,7 @@ public int Parent_PathIndex } public OmsiObject Parent { - get => new(Memory, Memory.ReadMemory(Address + 0x140)); + get => Memory.ReadMemoryObject(Address, 0x140, false); } public byte Type { @@ -36,7 +36,7 @@ public byte Type } public OmsiCoordSystem CoordSystem { - get => new(Memory, Memory.ReadMemory(Address + 0x148)); + get => Memory.ReadMemoryObject(Address, 0x148, false); } public bool CoordSystemIsMine { @@ -199,7 +199,7 @@ public float[] AIDensRel }*/ public OmsiSplineSegment Helper { - get => new(Memory, Memory.ReadMemory(Address + 0x1c4)); + get => Memory.ReadMemoryObject(Address, 0x1c4, false); } /* WAITING FOR PR#25 public OmsiPathRule[] Rules diff --git a/OmsiHook/OmsiPhysObj.cs b/OmsiHook/WrappedOmsiClasses/OmsiPhysObj.cs similarity index 100% rename from OmsiHook/OmsiPhysObj.cs rename to OmsiHook/WrappedOmsiClasses/OmsiPhysObj.cs diff --git a/OmsiHook/OmsiPhysObjInst.cs b/OmsiHook/WrappedOmsiClasses/OmsiPhysObjInst.cs similarity index 97% rename from OmsiHook/OmsiPhysObjInst.cs rename to OmsiHook/WrappedOmsiClasses/OmsiPhysObjInst.cs index 2944e0a..f7d9860 100644 --- a/OmsiHook/OmsiPhysObjInst.cs +++ b/OmsiHook/WrappedOmsiClasses/OmsiPhysObjInst.cs @@ -130,6 +130,6 @@ public byte Contact set => Memory.WriteMemory(Address + 0x1d8, value); } - public OmsiCamera Camera => new(Memory, Memory.ReadMemory(Address + 0x1dc)); + public OmsiCamera Camera => Memory.ReadMemoryObject(Address, 0x1dc, false); } } diff --git a/OmsiHook/OmsiProgMan.cs b/OmsiHook/WrappedOmsiClasses/OmsiProgMan.cs similarity index 93% rename from OmsiHook/OmsiProgMan.cs rename to OmsiHook/WrappedOmsiClasses/OmsiProgMan.cs index d0085bc..8c6128a 100644 --- a/OmsiHook/OmsiProgMan.cs +++ b/OmsiHook/WrappedOmsiClasses/OmsiProgMan.cs @@ -51,7 +51,7 @@ public D3DText Text2D_Hinweise_H }*/ public OmsiCamera MapCam { - get => new(Memory, Memory.ReadMemory(Address + 0x14)); + get => Memory.ReadMemoryObject(Address, 0x14, false); } public D3DVector MapCamTargetPos { @@ -205,15 +205,15 @@ public bool Maus_Last_Clicked } public OmsiFileObject SelObjPri { - get => new(Memory, Memory.ReadMemory(Address + 0xf0)); + get => Memory.ReadMemoryObject(Address, 0xf0, false); } public OmsiFileObject SelObjSec { - get => new(Memory, Memory.ReadMemory(Address + 0xf4)); + get => Memory.ReadMemoryObject(Address, 0xf4, false); } public OmsiFileObject OrgObj { - get => new(Memory, Memory.ReadMemory(Address + 0xf8)); + get => Memory.ReadMemoryObject(Address, 0xf8, false); } public int SelObjEscInst { @@ -222,15 +222,15 @@ public int SelObjEscInst } public OmsiFileSpline SelSplPri { - get => new(Memory, Memory.ReadMemory(Address + 0x100)); + get => Memory.ReadMemoryObject(Address, 0x100, false); } public OmsiFileSpline SelSplSec { - get => new(Memory, Memory.ReadMemory(Address + 0x104)); + get => Memory.ReadMemoryObject(Address, 0x104, false); } public OmsiFileSpline OrgSpl { - get => new(Memory, Memory.ReadMemory(Address + 0x108)); + get => Memory.ReadMemoryObject(Address, 0x108, false); } public OmsiFileSpline[] SelSplExp { @@ -287,7 +287,7 @@ public bool Path_Deact } public D3DMeshFileObject SplHelper { - get => new(Memory, Memory.ReadMemory(Address + 0x134)); + get => Memory.ReadMemoryObject(Address, 0x134, false); } public D3DOBB SplHelperBounding { @@ -296,7 +296,7 @@ public D3DOBB SplHelperBounding } public OmsiDynHelperMan DynHelperMan { - get => new(Memory, Memory.ReadMemory(0x174)); + get => Memory.ReadMemoryObject(Address, 0x174, false); } /* TODO: public OmsiSplineObject PathHelperSplines @@ -321,7 +321,7 @@ public IntPtr[] PathHelperTextures } public OmsiVisu_OBB Visu_OBB { - get => new(Memory, Memory.ReadMemory(Address + 0x19c)); + get => Memory.ReadMemoryObject(Address, 0x19c, false); } public float Coll_Pos_X_Var { @@ -345,7 +345,7 @@ public float Coll_Energy_Var } public OmsiObjBlackRect ScreenRect { - get => new(Memory, Memory.ReadMemory(0x1b0)); + get => Memory.ReadMemoryObject(Address, 0x1b0, false); } // TODO: Write internal structs for these so that they can be marhsalled /*public OmsiCriticalSection CS_MakeVehicle diff --git a/OmsiHook/OmsiRoadVehicle.cs b/OmsiHook/WrappedOmsiClasses/OmsiRoadVehicle.cs similarity index 100% rename from OmsiHook/OmsiRoadVehicle.cs rename to OmsiHook/WrappedOmsiClasses/OmsiRoadVehicle.cs diff --git a/OmsiHook/OmsiRoadVehicleInst.cs b/OmsiHook/WrappedOmsiClasses/OmsiRoadVehicleInst.cs similarity index 95% rename from OmsiHook/OmsiRoadVehicleInst.cs rename to OmsiHook/WrappedOmsiClasses/OmsiRoadVehicleInst.cs index 82230c6..8ba6e3c 100644 --- a/OmsiHook/OmsiRoadVehicleInst.cs +++ b/OmsiHook/WrappedOmsiClasses/OmsiRoadVehicleInst.cs @@ -8,7 +8,7 @@ namespace OmsiHook public class OmsiRoadVehicleInst : OmsiVehicleInst { internal OmsiRoadVehicleInst(Memory omsiMemory, int baseAddress) : base(omsiMemory, baseAddress) { } - internal OmsiRoadVehicleInst() : base() { } + public OmsiRoadVehicleInst() : base() { } /* TODO: public OmsiCriticalSection CS_Ticket_Items { @@ -17,7 +17,7 @@ public OmsiCriticalSection CS_Ticket_Items }*/ public OmsiRoadVehicle RoadVehicle { - get => new(Memory, Memory.ReadMemory(Address + 0x710)); + get => Memory.ReadMemoryObject(Address, 0x710, false); } public bool OnLoadedKachel { @@ -393,7 +393,7 @@ public float VB_Var_Me_Reverse get => Memory.ReadMemory(Address + 0x8bc); set => Memory.WriteMemory(Address + 0x8bc, value); } - public OmsiRoadVehicleInst ScriptParent => new(Memory, Memory.ReadMemory(Address + 0x8c0)); + public OmsiRoadVehicleInst ScriptParent => Memory.ReadMemoryObject(Address, 0x8c0, false); public D3DXVector2 Wagenkasten_RotZPhys { get => Memory.ReadMemory(Address + 0x8c4); @@ -424,5 +424,15 @@ public bool Debug_B get => Memory.ReadMemory(Address + 0x8ec); set => Memory.WriteMemory(Address + 0x8ec, value); } + + /// + /// + /// + /// The name of the trigger to set + /// Whether to enable or disable the trigger + public async void SetTrigger(string trigger, bool enabled) + { + await OmsiRemoteMethods.OmsiSetTrigger(this, trigger, enabled); + } } } \ No newline at end of file diff --git a/OmsiHook/OmsiSound.cs b/OmsiHook/WrappedOmsiClasses/OmsiSound.cs similarity index 98% rename from OmsiHook/OmsiSound.cs rename to OmsiHook/WrappedOmsiClasses/OmsiSound.cs index baf608a..54f527b 100644 --- a/OmsiHook/OmsiSound.cs +++ b/OmsiHook/WrappedOmsiClasses/OmsiSound.cs @@ -179,7 +179,7 @@ public OmsiFuncClass[] VolCurves } public OmsiBoolClass BoolClass { - get => new(Memory, Memory.ReadMemory(Address + 0x78)); + get => Memory.ReadMemoryObject(Address, 0x78, false); } public bool Playing { @@ -204,9 +204,5 @@ public IntPtr Int3D get => new(Memory.ReadMemory(Address + 0x80)); set => Memory.WriteMemory(Address + 0x80, value.ToInt32()); } - - - - } } \ No newline at end of file diff --git a/OmsiHook/OmsiSoundPack.cs b/OmsiHook/WrappedOmsiClasses/OmsiSoundPack.cs similarity index 98% rename from OmsiHook/OmsiSoundPack.cs rename to OmsiHook/WrappedOmsiClasses/OmsiSoundPack.cs index e4f23a5..7587589 100644 --- a/OmsiHook/OmsiSoundPack.cs +++ b/OmsiHook/WrappedOmsiClasses/OmsiSoundPack.cs @@ -6,7 +6,7 @@ public class OmsiSoundPack : OmsiObject { internal OmsiSoundPack(Memory omsiMemory, int baseAddress) : base(omsiMemory, baseAddress) { } - internal OmsiSoundPack() : base() { } + public OmsiSoundPack() : base() { } /*public DirectSound8 Device { diff --git a/OmsiHook/OmsiSplineSegment.cs b/OmsiHook/WrappedOmsiClasses/OmsiSplineSegment.cs similarity index 100% rename from OmsiHook/OmsiSplineSegment.cs rename to OmsiHook/WrappedOmsiClasses/OmsiSplineSegment.cs diff --git a/OmsiHook/OmsiStringList.cs b/OmsiHook/WrappedOmsiClasses/OmsiStringList.cs similarity index 100% rename from OmsiHook/OmsiStringList.cs rename to OmsiHook/WrappedOmsiClasses/OmsiStringList.cs diff --git a/OmsiHook/WrappedOmsiClasses/OmsiTextureMan.cs b/OmsiHook/WrappedOmsiClasses/OmsiTextureMan.cs new file mode 100644 index 0000000..4693ea0 --- /dev/null +++ b/OmsiHook/WrappedOmsiClasses/OmsiTextureMan.cs @@ -0,0 +1,18 @@ +namespace OmsiHook +{ + /// + /// The global texture manager + /// + public class OmsiTextureMan : OmsiObject + { + internal OmsiTextureMan(Memory omsiMemory, int baseAddress) : base(omsiMemory, baseAddress) { } + public OmsiTextureMan() : base() { } + + public byte LoadFlag + { + get => Memory.ReadMemory(Address + 0x4); + set => Memory.WriteMemory(Address + 0x4, value); + } + public MemArray TextureItems => new(Memory, Address + 0x8, false); + } +} \ No newline at end of file diff --git a/OmsiHook/OmsiTime.cs b/OmsiHook/WrappedOmsiClasses/OmsiTime.cs similarity index 100% rename from OmsiHook/OmsiTime.cs rename to OmsiHook/WrappedOmsiClasses/OmsiTime.cs diff --git a/OmsiHook/OmsiTimeTableMan.cs b/OmsiHook/WrappedOmsiClasses/OmsiTimeTableMan.cs similarity index 100% rename from OmsiHook/OmsiTimeTableMan.cs rename to OmsiHook/WrappedOmsiClasses/OmsiTimeTableMan.cs diff --git a/OmsiHook/OmsiVehicle.cs b/OmsiHook/WrappedOmsiClasses/OmsiVehicle.cs similarity index 100% rename from OmsiHook/OmsiVehicle.cs rename to OmsiHook/WrappedOmsiClasses/OmsiVehicle.cs diff --git a/OmsiHook/OmsiVehicleInst.cs b/OmsiHook/WrappedOmsiClasses/OmsiVehicleInst.cs similarity index 98% rename from OmsiHook/OmsiVehicleInst.cs rename to OmsiHook/WrappedOmsiClasses/OmsiVehicleInst.cs index 5f84c87..6faedce 100644 --- a/OmsiHook/OmsiVehicleInst.cs +++ b/OmsiHook/WrappedOmsiClasses/OmsiVehicleInst.cs @@ -70,9 +70,9 @@ public float CS_AI_BusStopData public OmsiCamera[] Cameras_Pax => Memory.ReadMemoryObjArray(Address + 0x5b4); - public OmsiCamera Camera_Driver => new(Memory, Memory.ReadMemory(Address + 0x5b8)); + public OmsiCamera Camera_Driver => Memory.ReadMemoryObject(Address, 0x5b8, false); - public OmsiCamera Camera_Pax => new(Memory, Memory.ReadMemory(Address + 0x5bc)); + public OmsiCamera Camera_Pax => Memory.ReadMemoryObject(Address, 0x5bc, false); public int Act_Camera_Driver { @@ -215,7 +215,7 @@ public D3DVector A_Rot set => Memory.WriteMemory(Address + 0x614, value); } - public OmsiCamera OutsideCamera => new(Memory, Memory.ReadMemory(Address + 0x620)); + public OmsiCamera OutsideCamera => Memory.ReadMemoryObject(Address, 0x620, false); public bool PAI { diff --git a/OmsiHook/OmsiVisu_OBB.cs b/OmsiHook/WrappedOmsiClasses/OmsiVisu_OBB.cs similarity index 100% rename from OmsiHook/OmsiVisu_OBB.cs rename to OmsiHook/WrappedOmsiClasses/OmsiVisu_OBB.cs diff --git a/OmsiHook/OmsiWeather.cs b/OmsiHook/WrappedOmsiClasses/OmsiWeather.cs similarity index 99% rename from OmsiHook/OmsiWeather.cs rename to OmsiHook/WrappedOmsiClasses/OmsiWeather.cs index be61e3b..8c6ba9b 100644 --- a/OmsiHook/OmsiWeather.cs +++ b/OmsiHook/WrappedOmsiClasses/OmsiWeather.cs @@ -8,7 +8,7 @@ namespace OmsiHook public class OmsiWeather : OmsiObject { internal OmsiWeather(Memory omsiMemory, int baseAddress) : base(omsiMemory, baseAddress) { } - internal OmsiWeather() : base() { } + public OmsiWeather() : base() { } //Todo: WeatherSchemes - OmsiWeatherProp[] @ 0x4 diff --git a/OmsiHook/articles/toc.yml b/OmsiHook/articles/toc.yml deleted file mode 100644 index f2ba49b..0000000 --- a/OmsiHook/articles/toc.yml +++ /dev/null @@ -1,6 +0,0 @@ -- name: Introduction - href: intro.md -- name: Building Native Omsi Plugins - href: building-native-plugins.md -- name: Performance Tips - href: performance-tips.md \ No newline at end of file diff --git a/OmsiHook/api/.gitignore b/OmsiHook/docs/api/.gitignore similarity index 100% rename from OmsiHook/api/.gitignore rename to OmsiHook/docs/api/.gitignore diff --git a/OmsiHook/api/index.md b/OmsiHook/docs/api/index.md similarity index 100% rename from OmsiHook/api/index.md rename to OmsiHook/docs/api/index.md diff --git a/OmsiHook/articles/building-native-plugins.md b/OmsiHook/docs/articles/building-native-plugins.md similarity index 100% rename from OmsiHook/articles/building-native-plugins.md rename to OmsiHook/docs/articles/building-native-plugins.md diff --git a/OmsiHook/docs/articles/examples/basic-cli.md b/OmsiHook/docs/articles/examples/basic-cli.md new file mode 100644 index 0000000..aadb9a7 --- /dev/null +++ b/OmsiHook/docs/articles/examples/basic-cli.md @@ -0,0 +1,28 @@ +# Basic Trigger & Sound Trigger Example + +This article provides a basic understanding to a basic C# .NET example leveraging the OMSIHook library. The example focuses on retrieving crucial information about the map, weather, date, and the current vehicle. + +_This article is in direct relation to the Sample Project available [here](https://github.com/space928/Omsi-Extensions/tree/main/_OmsiHookExamples/BasicCLI)._ + +## Initialization + +Initialize an instance of the `OmsiHook` class and establish a connection to the OMSI game: + +```cs +OmsiHook.OmsiHook omsi = new(); +omsi.AttachToOMSI().Wait(); +``` + +## Caching of Globals + +Efficiently cache top-level global variables outside the loop for optimized performance: + +```cs +// Cache global variables for faster access +var playerVehicle = omsi.Globals.PlayerVehicle; +var time = omsi.Globals.Time; +var map = omsi.Globals.Map; +var weather = omsi.Globals.Weather; +``` + +By caching these variables outside the loop, you significantly enhance access speed during subsequent iterations. diff --git a/OmsiHook/docs/articles/examples/event-sample.md b/OmsiHook/docs/articles/examples/event-sample.md new file mode 100644 index 0000000..9db7a42 --- /dev/null +++ b/OmsiHook/docs/articles/examples/event-sample.md @@ -0,0 +1,63 @@ +# Basic Events Example + +This article provides a basic understanding to a basic C# .NET example leveraging the OMSIHook library. The example focuses using the event handlers provided by OMSIHook. + +_This article is in direct relation to the Sample Project available [here](https://github.com/space928/Omsi-Extensions/tree/main/_OmsiHookExamples/Event_Sample)._ + +## Basic Usage +Similar to most C# .NET event handlers, you simply need to append the handler to the field as demonstraited below. + +```cs +OmsiHook.OmsiHook omsi = new(); +omsi.OnMapChange += Omsi_OnMapChange; +omsi.OnMapLoaded += Omsi_OnMapLoaded; +omsi.OnActiveVehicleChanged += Omsi_OnActiveVehicleChanged; +omsi.OnOmsiExited += Omsi_OnOmsiExited; +omsi.OnOmsiGotD3DContext += Omsi_OnOmsiGotD3DContext; +omsi.OnOmsiLostD3DContext += Omsi_OnOmsiLostD3DContext; +``` + +## Event Descriptions +The events all provide the current `OMSIHook` object as well as several of them provide references to the object that has changed. + +### _MapChange_ Event +Triggered any time the current map has changed. +```cs +Omsi_OnMapChange(object? sender, OmsiMap e) +``` +The `sender` object as with all the other events refers to the current `OMSIHook` object, the `e` object is a reference to the new `OmsiMap` object or `null`. + +### _MapLoaded_ Event +Triggered any time a map is loaded or unloaded. +```cs +Omsi_OnMapLoaded(object? sender, bool e) +``` +The `sender` object as with all the other events refers to the current `OMSIHook` object, the `e` is a bool that contains weather or not the event if for a map loading or unloading. + +### _ActiveVehicleChanged_ Event +Triggered any time a player changes vehicle. +```cs +Omsi_OnActiveVehicleChanged(object? sender, OmsiRoadVehicleInst e) +``` +The `sender` object as with all the other events refers to the current `OMSIHook` object, the `e` is a reference to the current player vehicle instance. + +### _OmsiExited_ Event +Triggered upon OMSI exiting. +```cs +Omsi_OnOmsiExited(object? sender, EventArgs e) +``` +The `sender` object as with all the other events refers to the current `OMSIHook` object, the `e` object is not used for this event. + +### _OmsiGotD3DContext_ Event +Triggered upon OMSI's Direct3D context being initialised. +```cs +Omsi_OnOmsiGotD3DContext(object? sender, EventArgs e) +``` +The `sender` object as with all the other events refers to the current `OMSIHook` object, the `e` object is not used for this event. + +### _OmsiLostD3DContext_ Event +Triggered upon OMSI's Direct3D context being lost. +```cs +Omsi_OnOmsiLostD3DContext(object? sender, EventArgs e) +``` +The `sender` object as with all the other events refers to the current `OMSIHook` object, the `e` object is not used for this event. diff --git a/OmsiHook/docs/articles/examples/triggers-sample.md b/OmsiHook/docs/articles/examples/triggers-sample.md new file mode 100644 index 0000000..3e67b27 --- /dev/null +++ b/OmsiHook/docs/articles/examples/triggers-sample.md @@ -0,0 +1,23 @@ +# Basic Trigger & Sound Trigger Example + +This article offers a foundational exploration of a C# .NET example that utilizes the OMSIHook library. The focus of this example is on activating existing OMSI Mouse Events (triggers) and initiating sound playback (sound triggers). + +_For a hands-on experience, you can access the associated Sample Project [here](https://github.com/space928/Omsi-Extensions/tree/main/_OmsiHookExamples/TriggersSample)._ + +## Mouse Triggers + +To manipulate the state of any trigger within OMSI, a straightforward remote call to the `SetTrigger()` method is employed. This method allows you to alter the boolean state of a specific trigger identified by its name. The code snippet below illustrates this process: + +```cs +playerVehicle.SetTrigger("bus_doorfront0", true); +``` + +## Sound Triggers + +In a similar fashion, sound manipulation is achieved through a remote call to OMSI's `SoundTrigger()` method. This method facilitates the playback of any sound by referencing its file name and the designated point specified in the `\sound.cfg\` file. The following code snippet demonstrates this operation: + +```cs +playerVehicle.SoundTrigger("ev_IBIS_Ansagen", @"..\..\MAN_NL_NG\Sound\Matrix_Ziel.wav"); +``` + +These examples showcase the simplicity and effectiveness of leveraging the OMSIHook library to interact with mouse events and sound triggers within OMSI, enhancing the extensibility and functionality of your C# .NET applications. \ No newline at end of file diff --git a/OmsiHook/docs/articles/examples/video-demo.md b/OmsiHook/docs/articles/examples/video-demo.md new file mode 100644 index 0000000..01b3d2b --- /dev/null +++ b/OmsiHook/docs/articles/examples/video-demo.md @@ -0,0 +1,26 @@ +# Video Playback Demo + +This article provides a basic understanding to a basic C# .NET example leveraging the OMSIHook library. This demo is a more advanced +demo using FFmpeg's library to decode video files then pipe the frame data into OMSI's ScriptTextures. + +_This article is in direct relation to the Sample Project available [here](https://github.com/space928/Omsi-Extensions/tree/main/_OmsiHookExamples/Video_Demo)._ + +![youtube.com/embed 1](https://www.youtube.com/embed/61sMzpSCn0M) + +## First Steps +Before trying the project, the FFmpeg binaries need to be compiled - they should be compiled for **Win32** with shared libraries. +Prebuilt binaries are available [here](https://rwijnsma.home.xs4all.nl/files/ffmpeg/). A video file is also required to +demonstrate it, MPEG-4/H.264 format is recommended however many formats are compatible with FFmpeg. + +Once the required resources are acquired, some configuration is needed; At the top of `Program.cs` the consts are defined as follows: +```cs +const string VIDEO_PATH = @"sample.mp4"; // Path/URL to the video file +const string FFMPEG_PATH = @"ffmpeg-shared\bin"; // Path to your FFmpeg binaries +const int ST_INDEX = 0; // The index of the Script Texture to replace +``` + +## What's Going On +The main program is split in two main classes `Program` and `DXTextureManager`. + - `Program` is the entry point to the demo, it initialises OMSIHook and FFmpeg, and loads the video file. + - `DXTextureManager` handles initialising textures in OMSI, assigning them to ScriptTextures and updating them. + diff --git a/OmsiHook/articles/intro.md b/OmsiHook/docs/articles/intro.md similarity index 100% rename from OmsiHook/articles/intro.md rename to OmsiHook/docs/articles/intro.md diff --git a/OmsiHook/articles/performance-tips.md b/OmsiHook/docs/articles/performance-tips.md similarity index 100% rename from OmsiHook/articles/performance-tips.md rename to OmsiHook/docs/articles/performance-tips.md diff --git a/OmsiHook/docs/articles/toc.yml b/OmsiHook/docs/articles/toc.yml new file mode 100644 index 0000000..f2d29ea --- /dev/null +++ b/OmsiHook/docs/articles/toc.yml @@ -0,0 +1,16 @@ +- name: Introduction + href: intro.md +- name: Building Native Omsi Plugins + href: building-native-plugins.md +- name: Performance Tips + href: performance-tips.md +- name: Examples + items: + - name: Basic CLI Example + href: examples\basic-cli.md + - name: Basic Mouse Trigger & Sound Trigger Example + href: examples\triggers-sample.md + - name: Basic Events Example + href: examples\event-sample.md + - name: Video Playback Demo + href: examples\video-demo.md \ No newline at end of file diff --git a/OmsiHook/docfx.json b/OmsiHook/docs/docfx.json similarity index 92% rename from OmsiHook/docfx.json rename to OmsiHook/docs/docfx.json index dbe8736..00b0381 100644 --- a/OmsiHook/docfx.json +++ b/OmsiHook/docs/docfx.json @@ -6,7 +6,7 @@ "files": [ "**.csproj" ], - "src": "" + "src": "../" } ], "dest": "api", @@ -23,13 +23,13 @@ "_appFaviconPath": "images/favicon.ico", "_appLogoPath": "images/logo.svg", "_appFooter": "DocFX + OmsiHook = ♥", - "_copyrightFooter": "© Thomas/Adam Mathieson 2023. All rights reserved.", + "_copyrightFooter": "© Thomas/Adam Mathieson 2024. All rights reserved.", "_enableSearch": true, "_disableSideFilter": false, "_enableNewTab": true, "_disableContribution": true, "_disableBreadcrumb": false, - "_DocumentationVersion": "2.3.1" + "_DocumentationVersion": "2.4.3" }, "content": [ { diff --git a/OmsiHook/docs/images/favicon.ico b/OmsiHook/docs/images/favicon.ico new file mode 100644 index 0000000..b407cbd Binary files /dev/null and b/OmsiHook/docs/images/favicon.ico differ diff --git a/OmsiHook/images/logo.svg b/OmsiHook/docs/images/logo.svg similarity index 100% rename from OmsiHook/images/logo.svg rename to OmsiHook/docs/images/logo.svg diff --git a/OmsiHook/index.md b/OmsiHook/docs/index.md similarity index 100% rename from OmsiHook/index.md rename to OmsiHook/docs/index.md diff --git a/OmsiHook/plugins/memberpage.2.59.2/.signature.p7s b/OmsiHook/docs/plugins/memberpage.2.59.2/.signature.p7s similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/.signature.p7s rename to OmsiHook/docs/plugins/memberpage.2.59.2/.signature.p7s diff --git a/OmsiHook/plugins/memberpage.2.59.2/content/ManagedReference.extension.js b/OmsiHook/docs/plugins/memberpage.2.59.2/content/ManagedReference.extension.js similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/content/ManagedReference.extension.js rename to OmsiHook/docs/plugins/memberpage.2.59.2/content/ManagedReference.extension.js diff --git a/OmsiHook/plugins/memberpage.2.59.2/content/ManagedReference.overwrite.js b/OmsiHook/docs/plugins/memberpage.2.59.2/content/ManagedReference.overwrite.js similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/content/ManagedReference.overwrite.js rename to OmsiHook/docs/plugins/memberpage.2.59.2/content/ManagedReference.overwrite.js diff --git a/OmsiHook/plugins/memberpage.2.59.2/content/partials/class.tmpl.partial b/OmsiHook/docs/plugins/memberpage.2.59.2/content/partials/class.tmpl.partial similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/content/partials/class.tmpl.partial rename to OmsiHook/docs/plugins/memberpage.2.59.2/content/partials/class.tmpl.partial diff --git a/OmsiHook/plugins/memberpage.2.59.2/content/partials/collection.tmpl.partial b/OmsiHook/docs/plugins/memberpage.2.59.2/content/partials/collection.tmpl.partial similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/content/partials/collection.tmpl.partial rename to OmsiHook/docs/plugins/memberpage.2.59.2/content/partials/collection.tmpl.partial diff --git a/OmsiHook/plugins/memberpage.2.59.2/content/partials/customMREFContent.tmpl.partial b/OmsiHook/docs/plugins/memberpage.2.59.2/content/partials/customMREFContent.tmpl.partial similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/content/partials/customMREFContent.tmpl.partial rename to OmsiHook/docs/plugins/memberpage.2.59.2/content/partials/customMREFContent.tmpl.partial diff --git a/OmsiHook/plugins/memberpage.2.59.2/content/partials/item.tmpl.partial b/OmsiHook/docs/plugins/memberpage.2.59.2/content/partials/item.tmpl.partial similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/content/partials/item.tmpl.partial rename to OmsiHook/docs/plugins/memberpage.2.59.2/content/partials/item.tmpl.partial diff --git a/OmsiHook/plugins/memberpage.2.59.2/content/plugins/HtmlAgilityPack.dll b/OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/HtmlAgilityPack.dll similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/content/plugins/HtmlAgilityPack.dll rename to OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/HtmlAgilityPack.dll diff --git a/OmsiHook/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.Build.Common.dll b/OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.Build.Common.dll similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.Build.Common.dll rename to OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.Build.Common.dll diff --git a/OmsiHook/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.Build.MemberLevelManagedReference.dll b/OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.Build.MemberLevelManagedReference.dll similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.Build.MemberLevelManagedReference.dll rename to OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.Build.MemberLevelManagedReference.dll diff --git a/OmsiHook/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.Common.dll b/OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.Common.dll similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.Common.dll rename to OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.Common.dll diff --git a/OmsiHook/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.DataContracts.Common.dll b/OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.DataContracts.Common.dll similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.DataContracts.Common.dll rename to OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.DataContracts.Common.dll diff --git a/OmsiHook/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.DataContracts.ManagedReference.dll b/OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.DataContracts.ManagedReference.dll similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.DataContracts.ManagedReference.dll rename to OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.DataContracts.ManagedReference.dll diff --git a/OmsiHook/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.MarkdownLite.dll b/OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.MarkdownLite.dll similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.MarkdownLite.dll rename to OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.MarkdownLite.dll diff --git a/OmsiHook/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.Plugins.dll b/OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.Plugins.dll similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.Plugins.dll rename to OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.Plugins.dll diff --git a/OmsiHook/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.YamlSerialization.dll b/OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.YamlSerialization.dll similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.YamlSerialization.dll rename to OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/Microsoft.DocAsCode.YamlSerialization.dll diff --git a/OmsiHook/plugins/memberpage.2.59.2/content/plugins/Newtonsoft.Json.dll b/OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/Newtonsoft.Json.dll similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/content/plugins/Newtonsoft.Json.dll rename to OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/Newtonsoft.Json.dll diff --git a/OmsiHook/plugins/memberpage.2.59.2/content/plugins/System.Buffers.dll b/OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/System.Buffers.dll similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/content/plugins/System.Buffers.dll rename to OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/System.Buffers.dll diff --git a/OmsiHook/plugins/memberpage.2.59.2/content/plugins/System.Collections.Immutable.dll b/OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/System.Collections.Immutable.dll similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/content/plugins/System.Collections.Immutable.dll rename to OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/System.Collections.Immutable.dll diff --git a/OmsiHook/plugins/memberpage.2.59.2/content/plugins/System.Composition.AttributedModel.dll b/OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/System.Composition.AttributedModel.dll similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/content/plugins/System.Composition.AttributedModel.dll rename to OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/System.Composition.AttributedModel.dll diff --git a/OmsiHook/plugins/memberpage.2.59.2/content/plugins/System.Composition.Convention.dll b/OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/System.Composition.Convention.dll similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/content/plugins/System.Composition.Convention.dll rename to OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/System.Composition.Convention.dll diff --git a/OmsiHook/plugins/memberpage.2.59.2/content/plugins/System.Composition.Hosting.dll b/OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/System.Composition.Hosting.dll similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/content/plugins/System.Composition.Hosting.dll rename to OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/System.Composition.Hosting.dll diff --git a/OmsiHook/plugins/memberpage.2.59.2/content/plugins/System.Composition.Runtime.dll b/OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/System.Composition.Runtime.dll similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/content/plugins/System.Composition.Runtime.dll rename to OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/System.Composition.Runtime.dll diff --git a/OmsiHook/plugins/memberpage.2.59.2/content/plugins/System.Composition.TypedParts.dll b/OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/System.Composition.TypedParts.dll similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/content/plugins/System.Composition.TypedParts.dll rename to OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/System.Composition.TypedParts.dll diff --git a/OmsiHook/plugins/memberpage.2.59.2/content/plugins/System.Memory.dll b/OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/System.Memory.dll similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/content/plugins/System.Memory.dll rename to OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/System.Memory.dll diff --git a/OmsiHook/plugins/memberpage.2.59.2/content/plugins/System.Numerics.Vectors.dll b/OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/System.Numerics.Vectors.dll similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/content/plugins/System.Numerics.Vectors.dll rename to OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/System.Numerics.Vectors.dll diff --git a/OmsiHook/plugins/memberpage.2.59.2/content/plugins/System.Runtime.CompilerServices.Unsafe.dll b/OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/System.Runtime.CompilerServices.Unsafe.dll similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/content/plugins/System.Runtime.CompilerServices.Unsafe.dll rename to OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/System.Runtime.CompilerServices.Unsafe.dll diff --git a/OmsiHook/plugins/memberpage.2.59.2/content/plugins/YamlDotNet.dll b/OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/YamlDotNet.dll similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/content/plugins/YamlDotNet.dll rename to OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/YamlDotNet.dll diff --git a/OmsiHook/plugins/memberpage.2.59.2/content/plugins/docfx.plugins.config b/OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/docfx.plugins.config similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/content/plugins/docfx.plugins.config rename to OmsiHook/docs/plugins/memberpage.2.59.2/content/plugins/docfx.plugins.config diff --git a/OmsiHook/plugins/memberpage.2.59.2/content/toc.html.js b/OmsiHook/docs/plugins/memberpage.2.59.2/content/toc.html.js similarity index 100% rename from OmsiHook/plugins/memberpage.2.59.2/content/toc.html.js rename to OmsiHook/docs/plugins/memberpage.2.59.2/content/toc.html.js diff --git a/OmsiHook/templates/singulinkfx/layout/_master.tmpl b/OmsiHook/docs/templates/singulinkfx/layout/_master.tmpl similarity index 100% rename from OmsiHook/templates/singulinkfx/layout/_master.tmpl rename to OmsiHook/docs/templates/singulinkfx/layout/_master.tmpl diff --git a/OmsiHook/templates/singulinkfx/partials/footer.tmpl.partial b/OmsiHook/docs/templates/singulinkfx/partials/footer.tmpl.partial similarity index 100% rename from OmsiHook/templates/singulinkfx/partials/footer.tmpl.partial rename to OmsiHook/docs/templates/singulinkfx/partials/footer.tmpl.partial diff --git a/OmsiHook/templates/singulinkfx/partials/head.tmpl.partial b/OmsiHook/docs/templates/singulinkfx/partials/head.tmpl.partial similarity index 100% rename from OmsiHook/templates/singulinkfx/partials/head.tmpl.partial rename to OmsiHook/docs/templates/singulinkfx/partials/head.tmpl.partial diff --git a/OmsiHook/templates/singulinkfx/partials/li.tmpl.partial b/OmsiHook/docs/templates/singulinkfx/partials/li.tmpl.partial similarity index 100% rename from OmsiHook/templates/singulinkfx/partials/li.tmpl.partial rename to OmsiHook/docs/templates/singulinkfx/partials/li.tmpl.partial diff --git a/OmsiHook/templates/singulinkfx/partials/logo.tmpl.partial b/OmsiHook/docs/templates/singulinkfx/partials/logo.tmpl.partial similarity index 100% rename from OmsiHook/templates/singulinkfx/partials/logo.tmpl.partial rename to OmsiHook/docs/templates/singulinkfx/partials/logo.tmpl.partial diff --git a/OmsiHook/templates/singulinkfx/partials/namespace.tmpl.partial b/OmsiHook/docs/templates/singulinkfx/partials/namespace.tmpl.partial similarity index 100% rename from OmsiHook/templates/singulinkfx/partials/namespace.tmpl.partial rename to OmsiHook/docs/templates/singulinkfx/partials/namespace.tmpl.partial diff --git a/OmsiHook/templates/singulinkfx/partials/navbar.tmpl.partial b/OmsiHook/docs/templates/singulinkfx/partials/navbar.tmpl.partial similarity index 100% rename from OmsiHook/templates/singulinkfx/partials/navbar.tmpl.partial rename to OmsiHook/docs/templates/singulinkfx/partials/navbar.tmpl.partial diff --git a/OmsiHook/templates/singulinkfx/partials/scripts.tmpl.partial b/OmsiHook/docs/templates/singulinkfx/partials/scripts.tmpl.partial similarity index 100% rename from OmsiHook/templates/singulinkfx/partials/scripts.tmpl.partial rename to OmsiHook/docs/templates/singulinkfx/partials/scripts.tmpl.partial diff --git a/OmsiHook/templates/singulinkfx/partials/searchResults.tmpl.partial b/OmsiHook/docs/templates/singulinkfx/partials/searchResults.tmpl.partial similarity index 100% rename from OmsiHook/templates/singulinkfx/partials/searchResults.tmpl.partial rename to OmsiHook/docs/templates/singulinkfx/partials/searchResults.tmpl.partial diff --git a/OmsiHook/templates/singulinkfx/partials/toc.tmpl.partial b/OmsiHook/docs/templates/singulinkfx/partials/toc.tmpl.partial similarity index 100% rename from OmsiHook/templates/singulinkfx/partials/toc.tmpl.partial rename to OmsiHook/docs/templates/singulinkfx/partials/toc.tmpl.partial diff --git a/OmsiHook/templates/singulinkfx/styles/config.css b/OmsiHook/docs/templates/singulinkfx/styles/config.css similarity index 100% rename from OmsiHook/templates/singulinkfx/styles/config.css rename to OmsiHook/docs/templates/singulinkfx/styles/config.css diff --git a/OmsiHook/templates/singulinkfx/styles/discord.css b/OmsiHook/docs/templates/singulinkfx/styles/discord.css similarity index 100% rename from OmsiHook/templates/singulinkfx/styles/discord.css rename to OmsiHook/docs/templates/singulinkfx/styles/discord.css diff --git a/OmsiHook/templates/singulinkfx/styles/down-arrow.svg b/OmsiHook/docs/templates/singulinkfx/styles/down-arrow.svg similarity index 100% rename from OmsiHook/templates/singulinkfx/styles/down-arrow.svg rename to OmsiHook/docs/templates/singulinkfx/styles/down-arrow.svg diff --git a/OmsiHook/templates/singulinkfx/styles/jquery.twbsPagination.js b/OmsiHook/docs/templates/singulinkfx/styles/jquery.twbsPagination.js similarity index 100% rename from OmsiHook/templates/singulinkfx/styles/jquery.twbsPagination.js rename to OmsiHook/docs/templates/singulinkfx/styles/jquery.twbsPagination.js diff --git a/OmsiHook/templates/singulinkfx/styles/main.css b/OmsiHook/docs/templates/singulinkfx/styles/main.css similarity index 100% rename from OmsiHook/templates/singulinkfx/styles/main.css rename to OmsiHook/docs/templates/singulinkfx/styles/main.css diff --git a/OmsiHook/templates/singulinkfx/styles/main.js b/OmsiHook/docs/templates/singulinkfx/styles/main.js similarity index 100% rename from OmsiHook/templates/singulinkfx/styles/main.js rename to OmsiHook/docs/templates/singulinkfx/styles/main.js diff --git a/OmsiHook/templates/singulinkfx/styles/singulink.css b/OmsiHook/docs/templates/singulinkfx/styles/singulink.css similarity index 100% rename from OmsiHook/templates/singulinkfx/styles/singulink.css rename to OmsiHook/docs/templates/singulinkfx/styles/singulink.css diff --git a/OmsiHook/templates/singulinkfx/styles/singulink.js b/OmsiHook/docs/templates/singulinkfx/styles/singulink.js similarity index 100% rename from OmsiHook/templates/singulinkfx/styles/singulink.js rename to OmsiHook/docs/templates/singulinkfx/styles/singulink.js diff --git a/OmsiHook/templates/singulinkfx/styles/url.min.js b/OmsiHook/docs/templates/singulinkfx/styles/url.min.js similarity index 100% rename from OmsiHook/templates/singulinkfx/styles/url.min.js rename to OmsiHook/docs/templates/singulinkfx/styles/url.min.js diff --git a/OmsiHook/templates/singulinkfx/toc.html.tmpl b/OmsiHook/docs/templates/singulinkfx/toc.html.tmpl similarity index 100% rename from OmsiHook/templates/singulinkfx/toc.html.tmpl rename to OmsiHook/docs/templates/singulinkfx/toc.html.tmpl diff --git a/OmsiHook/toc.yml b/OmsiHook/docs/toc.yml similarity index 100% rename from OmsiHook/toc.yml rename to OmsiHook/docs/toc.yml diff --git a/OmsiHook/log.txt b/OmsiHook/log.txt deleted file mode 100644 index e69de29..0000000 diff --git a/OmsiHookInvoker/FunctionHooks.cpp b/OmsiHookInvoker/FunctionHooks.cpp index 88b6545..25ca8a3 100644 --- a/OmsiHookInvoker/FunctionHooks.cpp +++ b/OmsiHookInvoker/FunctionHooks.cpp @@ -3,9 +3,7 @@ FunctionHooks::FunctionHooks() { - DWORD oldProtect; - VirtualProtect(hookTrampolineFunc, sizeof(hookTrampolineFunc), PAGE_EXECUTE_READWRITE, &oldProtect); - ZeroMemory(hookTrampolineFunc, sizeof(hookTrampolineFunc)); + } FunctionHooks::~FunctionHooks() @@ -13,7 +11,7 @@ FunctionHooks::~FunctionHooks() } -void FunctionHooks::InstallHook(UINT32 funcToHook) +void FunctionHooks::InstallHook(UINT32 funcToHook, BYTE* hookTrampolineFunc) { DWORD oldProtect; VirtualProtect((LPVOID)funcToHook, 256, PAGE_EXECUTE_READWRITE, &oldProtect); @@ -28,11 +26,21 @@ void FunctionHooks::InstallHook(UINT32 funcToHook) #define AsLEBytes(addr) ((addr>>3)&0xff), ((addr>>2)&0xff), ((addr>>1)&0xff), ((addr>>0)&0xff) -void FunctionHooks::OnTrigger(void(*callback)(LPCSTR trigger, int value)) +void FunctionHooks::OnTrigger(void(*callback)(int complMapObjInst, LPCSTR trigger, int value)) { + // TComplMapObjInst.TriggerXML(TComplMapObjInst *this,PascalString255 *trigger,int value) + UINT32 funcAddr = 0x007bae90; + UINT32 retAddr = 0x007bae96; + + DWORD oldProtect; + byte* hookTrampolineFunc = (byte*)malloc(256); + if (hookTrampolineFunc == 0) + return; + VirtualProtect(hookTrampolineFunc, sizeof(hookTrampolineFunc), PAGE_EXECUTE_READWRITE, &oldProtect); + ZeroMemory(hookTrampolineFunc, sizeof(hookTrampolineFunc)); // Bouncy bounce UINT32 callbackRelAddr = (UINT32)callback - ((UINT32)hookTrampolineFunc + 11); - UINT32 returnRelAddr = (UINT32)0x007bae96 - ((UINT32)hookTrampolineFunc + 25); + UINT32 returnRelAddr = (UINT32)retAddr - ((UINT32)hookTrampolineFunc + 25); // Setup the hook handler so that it calls the callback and then jumps back to the original function byte hookTrampolineTemp[] = { // Save the register args for later @@ -59,5 +67,5 @@ void FunctionHooks::OnTrigger(void(*callback)(LPCSTR trigger, int value)) }; memcpy(hookTrampolineFunc, hookTrampolineTemp, sizeof(hookTrampolineTemp)); - InstallHook(0x007bae90); + InstallHook(funcAddr, hookTrampolineFunc); } diff --git a/OmsiHookInvoker/FunctionHooks.h b/OmsiHookInvoker/FunctionHooks.h index ce4c485..2197388 100644 --- a/OmsiHookInvoker/FunctionHooks.h +++ b/OmsiHookInvoker/FunctionHooks.h @@ -4,11 +4,9 @@ class FunctionHooks public: FunctionHooks(); ~FunctionHooks(); - void OnTrigger(void (*callback) (LPCSTR trigger, int value)); + void OnTrigger(void(*callback)(int complMapObjInst, LPCSTR trigger, int value)); private: - void InstallHook(UINT32 funcToHook); - - byte hookTrampolineFunc[256]; + void InstallHook(UINT32 funcToHook, BYTE* hookTrampolineFunc); }; diff --git a/OmsiHookInvoker/OmsiHookInvoker.vcxproj.filters b/OmsiHookInvoker/OmsiHookInvoker.vcxproj.filters index 0028927..c2457aa 100644 --- a/OmsiHookInvoker/OmsiHookInvoker.vcxproj.filters +++ b/OmsiHookInvoker/OmsiHookInvoker.vcxproj.filters @@ -27,6 +27,9 @@ Header Files + + Header Files + @@ -38,5 +41,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/OmsiHookInvoker/dllmain.cpp b/OmsiHookInvoker/dllmain.cpp index e88dcb5..2fceef7 100644 --- a/OmsiHookInvoker/dllmain.cpp +++ b/OmsiHookInvoker/dllmain.cpp @@ -175,6 +175,18 @@ extern "C" __declspec(dllexport) int FreeMem(int addr) addr); } +extern "C" __declspec(dllexport) void RVTriggerXML(int roadVehicle, int trigger, int value) +{ + BorlandFastCall(0x007e9338, 3, 3, + roadVehicle, trigger, value); +} + +extern "C" __declspec(dllexport) void SoundTrigger(int complMapObj, int trigger, int filename) +{ + BorlandFastCall(0x007bb1a8, 3, 3, + complMapObj, trigger, filename); +} + extern "C" __declspec(dllexport) BOOL HookD3D() { if (!m_dxHook) diff --git a/OmsiHookPlugin/OmsiHookPlugin.cs b/OmsiHookPlugin/OmsiHookPlugin.cs index 7d15fa0..ac1cf40 100644 --- a/OmsiHookPlugin/OmsiHookPlugin.cs +++ b/OmsiHookPlugin/OmsiHookPlugin.cs @@ -52,7 +52,7 @@ private static void Hook_OnOmsiExited(object sender, EventArgs e) Log($"Omsi exited!"); } - private static void Hook_OnMapChange(object sender, EventArgs e) + private static void Hook_OnMapChange(object sender, OmsiMap e) { Log($"Map changed!"); } diff --git a/OmsiHookRPCPlugin/NativeImports.cs b/OmsiHookRPCPlugin/NativeImports.cs index b5b560e..d0875c2 100644 --- a/OmsiHookRPCPlugin/NativeImports.cs +++ b/OmsiHookRPCPlugin/NativeImports.cs @@ -32,5 +32,9 @@ internal static extern int TProgManPlaceRandomBus(int progMan, int aityp, internal static extern int GetTextureDesc(uint Texture, uint pWidth, uint pHeight, uint pFormat); [DllImport("OmsiHookInvoker.dll")] internal static extern int IsTexture(uint Texture); + [DllImport("OmsiHookInvoker.dll")] + internal static extern void RVTriggerXML(int roadVehicle, int trigger, int value); + [DllImport("OmsiHookInvoker.dll")] + internal static extern void SoundTrigger(int complMapObj, int trigger, int filename); } } diff --git a/OmsiHookRPCPlugin/OmsiHookRPCPlugin.cs b/OmsiHookRPCPlugin/OmsiHookRPCPlugin.cs index 245b396..cb6c104 100644 --- a/OmsiHookRPCPlugin/OmsiHookRPCPlugin.cs +++ b/OmsiHookRPCPlugin/OmsiHookRPCPlugin.cs @@ -83,6 +83,11 @@ public static void PluginStart(IntPtr aOwner) } catch { } Log("############## Omsi Hook RPC Plugin ##############"); Log($" version: {Assembly.GetExecutingAssembly().GetName().Version}"); + Log($" copyright Thomas Mathieson 2023"); + Log($"~ Omsi Hook RPC plugin is a simple plugin allowing OMSI mods which use the OmsiHook SDK ~"); + Log($"~ to interact with OMSI from an external process. The source code is available at: ~"); + Log($"~ https://github.com/space928/Omsi-Extensions ~"); + Log($""); Log($@"Starting RPC server on named pipe: \\.\pipe\{PIPE_NAME_RX} and \\.\pipe\{PIPE_NAME_TX} with {MAX_CLIENTS} threads..."); argumentArrayPool = ArrayPool.Create(256,8); @@ -320,6 +325,22 @@ private static void ProcessCall(MethodData methodData) BitConverter.ToUInt32(methodData.args, argInd) ); break; + case RemoteMethod.RVTriggerXML: + ret = 0; + NativeImports.RVTriggerXML( + BitConverter.ToInt32(methodData.args, argInd), + BitConverter.ToInt32(methodData.args, argInd += 4), + BitConverter.ToInt32(methodData.args, argInd += 4) + ); + break; + case RemoteMethod.SoundTrigger: + ret = 0; + NativeImports.SoundTrigger( + BitConverter.ToInt32(methodData.args, argInd), + BitConverter.ToInt32(methodData.args, argInd += 4), + BitConverter.ToInt32(methodData.args, argInd += 4) + ); + break; default: Log($"Unknown message type: {methodData.method} encountered!"); break; diff --git a/OmsiHookRPCPlugin/OmsiHookRPCPlugin.csproj b/OmsiHookRPCPlugin/OmsiHookRPCPlugin.csproj index 5b031d8..30059cc 100644 --- a/OmsiHookRPCPlugin/OmsiHookRPCPlugin.csproj +++ b/OmsiHookRPCPlugin/OmsiHookRPCPlugin.csproj @@ -5,7 +5,7 @@ Thomas Mathieson - 1.3.3 + 1.3.4 Thomas Mathieson @@ -109,6 +109,6 @@ True - + \ No newline at end of file diff --git a/README.md b/README.md index 721c612..dbf9a08 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,10 @@ Omsi hooking and modding sdk. [![.NET](https://github.com/space928/Omsi-Extensions/actions/workflows/dotnet.yml/badge.svg)](https://github.com/space928/Omsi-Extensions/actions/workflows/dotnet.yml) -[![DocFX](https://github.com/space928/Omsi-Extensions/actions/workflows/docs.yml/badge.svg)](https://github.com/space928/Omsi-Extensions/actions/workflows/docs.yml) -[![Nuget](https://img.shields.io/nuget/v/omsihook)](https://www.nuget.org/packages/OmsiHook/) -[![OMSI Version](https://img.shields.io/badge/OMSI%20Version-2.3.004-orange)](https://store.steampowered.com/app/252530/OMSI_2_Steam_Edition/) +[![DocFX](https://github.com/space928/Omsi-Extensions/actions/workflows/docs.yml/badge.svg)](https://space928.github.io/Omsi-Extensions/index.html) +[![Discord](https://img.shields.io/discord/1192462752527163503?logo=Discord&logoColor=fff&label=Discord)](https://discord.gg/FG9P6PW23w) +[![Nuget](https://img.shields.io/nuget/v/omsihook?logo=Nuget&logoColor=fff)](https://www.nuget.org/packages/OmsiHook/) +[![OMSI Version](https://img.shields.io/badge/OMSI%20Version-2.3.004-orange?logo=steam&logoColor=fff)](https://store.steampowered.com/app/252530/OMSI_2_Steam_Edition/) The dead simple way to hook into Omsi and fiddle with it's memory. In it's current state we only have mappings for a limited number of Omsi objects, but it's easy to extend. Allows both reading and writing @@ -25,9 +26,9 @@ class Program { static void Main(string[] args) { - // Create an OmsiHook and attach to any running instance of Omsi + // Create an OmsiHook and attach to any running instance of OMSI OmsiHook.OmsiHook omsi = new(); - omsi.AttachToOMSI(); + omsi.AttachToOMSI().Wait(); while (true) { @@ -35,7 +36,7 @@ class Program var pos = omsi.Globals.PlayerVehicle.Position; // Print the position to the console - Console.WriteLine($"Player vehicle pos: x:{pos.x:F3}\ty:{pos.y:F3}\tz:{pos.z:F3}"); + Console.WriteLine($"Player vehicle pos: {pos}"); Thread.Sleep(500); } @@ -52,6 +53,8 @@ Here's a summary of the project structure: ``` \Omsi-Extensions\ ┃ +┠─► \_OmsiHookExamples\ -> A collection of sample projects demonstrating various OmsiHook +┃ features. ┠─► \OmsiHook\ -> Base library containing all the Omsi hooking code and ┃ exposing Omsi's internal data. ┠─► \OmsiHookInvoker\ -> C++ plugin for invoking native Omsi methods from OmsiHook, @@ -63,7 +66,7 @@ Here's a summary of the project structure: ┠─► \OmsiExtensionsUI\ -> Example Avalonia UI (similar to WPF) application that uses ┃ OmsiHook; runs outside of Omsi. ┖─► \OmsiHookPlugin\ -> Example plugin that uses OmsiHook and compiles to a native - Omsi plugin by using DNNE. + Omsi plugin by using DNNE. ``` ## Building diff --git a/_OmsiHookExamples/BasicCLI/BasicCLI.csproj b/_OmsiHookExamples/BasicCLI/BasicCLI.csproj new file mode 100644 index 0000000..c66fed0 --- /dev/null +++ b/_OmsiHookExamples/BasicCLI/BasicCLI.csproj @@ -0,0 +1,16 @@ + + + + Exe + net6.0-windows + disable + enable + x86 + BasicCLI.Program + + + + + + + diff --git a/_OmsiHookExamples/BasicCLI/Program.cs b/_OmsiHookExamples/BasicCLI/Program.cs new file mode 100644 index 0000000..729e36e --- /dev/null +++ b/_OmsiHookExamples/BasicCLI/Program.cs @@ -0,0 +1,63 @@ +using System; +using System.Threading; +using OmsiHook; + +namespace BasicCLI +{ + // Most basic example of reading various values exposed by OMSIHook + class Program + { + static void Main(string[] args) + { + Console.WriteLine("#=#=#=#=#=# OMSIHook Basic CLI Sample #=#=#=#=#=#"); + + // Attach OmsiHook to the running instance of Omsi; this method is async and will complete when a running + // instance of Omsi is detected and has been connected to. We can wait synchronously for the method to + // complete by either using the await operator or calling it's Wait() method. + OmsiHook.OmsiHook omsi = new(); + omsi.AttachToOMSI().Wait(); + + // Set the console output encoding to support emoji + Console.OutputEncoding = System.Text.Encoding.UTF8; + + var playerVehicle = omsi.Globals.PlayerVehicle; + var time = omsi.Globals.Time; + var map = omsi.Globals.Map; + var weather = omsi.Globals.Weather; + while (true) + { + // These variables will return null until they have a valid value (they will become null if Omsi is in + // the title screen or is changing map). By using the null assignment operator, we can continously + // check if the object is valid, if so we get it only if it doesn't already exist; which saves + // constructing a new wrapper object every iteration of the while loop. + map ??= omsi.Globals.Map; + time ??= omsi.Globals.Time; + weather ??= omsi.Globals.Weather; + playerVehicle ??= omsi.Globals.PlayerVehicle; + var pos = playerVehicle?.Position ?? default; + var rot = playerVehicle?.Rotation ?? default; + + Console.SetCursorPosition(0, 1); + Console.WriteLine($"Map: {map?.FriendlyName}".PadRight(Console.WindowWidth - 17) + $"Date: {time.Day:00}/{time.Month:00}/{time.Year:0000}"); + Console.WriteLine($"Weather: {WeatherEmoji(weather)}".PadRight(Console.WindowWidth - 15) + $"Time: {time.Hour:00}:{time.Minute:00}:{time.Second:00}"); + Console.WriteLine($"Bus: {playerVehicle?.RoadVehicle?.FileName}".PadRight(Console.WindowWidth - 1)); + Console.WriteLine($"Position: {pos}".PadRight(Console.WindowWidth - 10) + $"Tile: {playerVehicle?.Kachel ?? 0, 3}"); + Console.WriteLine(($"Rotation: {rot}".PadRight(Console.WindowWidth - 1))); + + Thread.Sleep(20); + } + } + + // Pick an emoji to show for the weather + static string WeatherEmoji(OmsiWeather weather) + { + if (weather == null) + return "N/A"; + if (weather?.ActWeather.fogDensity < 900) + return "🌫️"; + if (weather?.ActWeather.percipitation > 0) + return "🌧️"; + return "☀️"; + } + } +} diff --git a/_OmsiHookExamples/EventSample/EventSample.csproj b/_OmsiHookExamples/EventSample/EventSample.csproj new file mode 100644 index 0000000..1b40390 --- /dev/null +++ b/_OmsiHookExamples/EventSample/EventSample.csproj @@ -0,0 +1,17 @@ + + + + Exe + net6.0-windows + enable + enable + EventSample.Program + x86 + x86 + + + + + + + diff --git a/_OmsiHookExamples/EventSample/Program.cs b/_OmsiHookExamples/EventSample/Program.cs new file mode 100644 index 0000000..b724624 --- /dev/null +++ b/_OmsiHookExamples/EventSample/Program.cs @@ -0,0 +1,65 @@ +using System; +using System.Threading; +using OmsiHook; + +namespace EventSample +{ + // Most Basic example of reading various values exposed by OMSIHook + class Program + { + static void Main(string[] args) + { + Console.OutputEncoding = System.Text.Encoding.UTF8; + Console.WriteLine("#=#=#=#=#=# OMSIHook Events Sample #=#=#=#=#=#"); + + OmsiHook.OmsiHook omsi = new(); + omsi.AttachToOMSI().Wait(); + + Console.WriteLine("Waiting for events..."); + + omsi.OnMapChange += Omsi_OnMapChange; + omsi.OnMapLoaded += Omsi_OnMapLoaded; + omsi.OnActiveVehicleChanged += Omsi_OnActiveVehicleChanged; + omsi.OnOmsiExited += Omsi_OnOmsiExited; + omsi.OnOmsiGotD3DContext += Omsi_OnOmsiGotD3DContext; + omsi.OnOmsiLostD3DContext += Omsi_OnOmsiLostD3DContext; + // Await callbacks + while (true) + { + Thread.Sleep(1000); + } + } + + private static void Omsi_OnOmsiLostD3DContext(object? sender, EventArgs e) + { + Console.WriteLine("💻 D3D Context Lost"); + } + + private static void Omsi_OnOmsiGotD3DContext(object? sender, EventArgs e) + { + Console.WriteLine("💻 D3D Context Secured"); + } + + private static void Omsi_OnOmsiExited(object? sender, EventArgs e) + { + Console.WriteLine("🛑 OMSI Has Exited"); + } + + private static void Omsi_OnMapLoaded(object? sender, bool e) + { + if (sender != null) + Console.WriteLine($"🗺️ Map Loaded: {e}"); + } + + private static void Omsi_OnMapChange(object? sender, OmsiMap e) + { + if (e != null) + Console.WriteLine($"🗺️ Map Changed: {e.FriendlyName}"); + } + + private static void Omsi_OnActiveVehicleChanged(object? sender, OmsiRoadVehicleInst e) + { + Console.WriteLine($"🚌 Active Vehicle Changed: {e.RoadVehicle.FriendlyName}"); + } + } +} diff --git a/_OmsiHookExamples/TriggersSample/Program.cs b/_OmsiHookExamples/TriggersSample/Program.cs new file mode 100644 index 0000000..4afad05 --- /dev/null +++ b/_OmsiHookExamples/TriggersSample/Program.cs @@ -0,0 +1,34 @@ +using System; +using System.Threading; +using OmsiHook; + +namespace TriggersSample +{ + // Basic sample of Triggers with OMSIHook + class Program + { + static void Main(string[] args) + { + Console.WriteLine("#=#=#=#=#=# OMSIHook Trigger Sample #=#=#=#=#=#"); + Console.OutputEncoding = System.Text.Encoding.UTF8; + + OmsiHook.OmsiHook omsi = new(); + omsi.AttachToOMSI().Wait(); + + var playerVehicle = omsi.Globals.PlayerVehicle; + bool triggerState = false; + + while (true) + { + playerVehicle ??= omsi.Globals.PlayerVehicle; + Console.SetCursorPosition(0, 1); + Console.WriteLine($"Trigger State: {triggerState}".PadRight(Console.WindowWidth - 1)); + Console.WriteLine($"Playing Sound...".PadRight(Console.WindowWidth - 1)); + playerVehicle.SetTrigger("bus_doorfront0", triggerState); + playerVehicle.SoundTrigger("ev_IBIS_Ansagen", @"..\..\MAN_NL_NG\Sound\Matrix_Ziel.wav"); + triggerState = !triggerState; + Thread.Sleep(1000); + } + } + } +} diff --git a/_OmsiHookExamples/TriggersSample/TriggersSample.csproj b/_OmsiHookExamples/TriggersSample/TriggersSample.csproj new file mode 100644 index 0000000..1ee32ba --- /dev/null +++ b/_OmsiHookExamples/TriggersSample/TriggersSample.csproj @@ -0,0 +1,17 @@ + + + + Exe + net6.0-windows + enable + enable + TriggersSample.Program + x86 + x86 + + + + + + + diff --git a/_OmsiHookExamples/VideoDemo/DXTextureManager.cs b/_OmsiHookExamples/VideoDemo/DXTextureManager.cs new file mode 100644 index 0000000..daf154f --- /dev/null +++ b/_OmsiHookExamples/VideoDemo/DXTextureManager.cs @@ -0,0 +1,79 @@ +using FFMediaToolkit.Decoding; +using OmsiHook; + +namespace VideoDemo +{ + public class DXTextureManager + { + private readonly ManualResetEventSlim d3dGotContext = new(false); + private OmsiHook.OmsiHook? omsi; + + // Width and height of the texture + private uint texWidth; + private uint texHeight; + + private D3DTexture? texture = null; + + public bool IsReady => texture != null && texture.IsValid; + + // Initialize the DXTextureManager with an OmsiHook instance + public void Init(OmsiHook.OmsiHook omsi) + { + texture = omsi.CreateTextureObject(); + this.omsi = omsi; + + // Subscribe to the OnMapLoaded event + omsi.OnMapLoaded += Omsi_OnMapLoaded; + } + + // Method to create a Direct3D texture based on video stream information + public bool CreateTexture(VideoStreamInfo info, int scriptTextureIndex) + { + if (omsi == null || !omsi.IsD3DReady || texture == null) + return false; + + // Set the texture width and height based on the video stream information + texWidth = (uint)info.FrameSize.Width; + texHeight = (uint)info.FrameSize.Height; + + try + { + texture.CreateD3DTexture(texWidth, texHeight); + } + catch (Exception ex) + { + Console.WriteLine(ex); + return false; + } + + // Access the script textures of the player vehicle in OmsiHook + var scriptTexes = omsi.Globals.PlayerVehicle.ComplObjInst.ScriptTextures; + + // Check if the provided script_texture_index is within bounds + if (scriptTextureIndex >= scriptTexes.Count) + return false; + + // Update the script texture at the specified index with the new Direct3D texture information + var old = scriptTexes[scriptTextureIndex]; + scriptTexes[scriptTextureIndex] = new() + { + TexPn = old.TexPn, + color = old.color, + tex = unchecked((IntPtr)texture.TextureAddress) + }; + return true; + } + + // Method to update the contents of the Direct3D texture with new video frame data + public void UpdateTexture(Memory data) + { + texture?.UpdateTexture(data); + } + + // Event handler for the OnMapLoaded event, signals when the Direct3D context is obtained + private void Omsi_OnMapLoaded(object? sender, bool e) + { + d3dGotContext.Set(); + } + } +} \ No newline at end of file diff --git a/_OmsiHookExamples/VideoDemo/Program.cs b/_OmsiHookExamples/VideoDemo/Program.cs new file mode 100644 index 0000000..0fc92ea --- /dev/null +++ b/_OmsiHookExamples/VideoDemo/Program.cs @@ -0,0 +1,69 @@ +using System; +using System.Threading; +using FFMediaToolkit; +using FFMediaToolkit.Decoding; +using FFMediaToolkit.Graphics; +using OmsiHook; + +namespace VideoDemo +{ + class Program + { + const string VIDEO_PATH = @"https://adam.mathieson.dev/sample.mp4"; + const string FFMPEG_PATH = @"ffmpeg-shared\bin"; + const int ST_INDEX = 0; + + static void Main(string[] args) + { + Console.OutputEncoding = System.Text.Encoding.UTF8; + Console.WriteLine("#=#=#=#=#=# OMSIHook Video Playback Demo #=#=#=#=#=#"); + + OmsiHook.OmsiHook omsi = new(); + omsi.AttachToOMSI().Wait(); + + DXTextureManager textureManager = new(); + textureManager.Init(omsi); + + var markerBlink = false; + // Configure the FFmpeg path to accelerate the video decode + FFmpegLoader.FFmpegPath = FFMPEG_PATH; + var videoFile = MediaFile.Open(VIDEO_PATH, new MediaOptions() + { + VideoPixelFormat = ImagePixelFormat.Bgra32 + }); + var frameBuffer = new byte[videoFile.Video.Info.FrameSize.Width * videoFile.Video.Info.FrameSize.Height * 4]; + var FPS = videoFile.Video.Info.AvgFrameRate; + while (true) + { + if (!textureManager.IsReady) + { + Console.SetCursorPosition(0, 1); + if (textureManager.CreateTexture(videoFile.Video.Info, ST_INDEX)) + { + Console.WriteLine("💻 Successfully created a texture... " + (markerBlink ? "🔴" : "⚫")); + } + else + { + Console.WriteLine("💻 Trying to create texture... " + (markerBlink ? "🔴" : "⚫")); + } + } else + { + int counter = 0; + while (videoFile.Video.TryGetNextFrame(frameBuffer.AsSpan())) + { + textureManager.UpdateTexture(frameBuffer); + Console.SetCursorPosition(0, 2); + Console.WriteLine("💿 Video Playing... " + (markerBlink ? "🔴" : "⚫")); + if (counter % 10 == 0) + markerBlink = !markerBlink; + counter++; + Thread.Sleep((int)Math.Round((1.0 / FPS) * 1000)); + } + return; + } + markerBlink = !markerBlink; + Thread.Sleep(20); + } + } + } +} diff --git a/_OmsiHookExamples/VideoDemo/VideoDemo.csproj b/_OmsiHookExamples/VideoDemo/VideoDemo.csproj new file mode 100644 index 0000000..a9498e9 --- /dev/null +++ b/_OmsiHookExamples/VideoDemo/VideoDemo.csproj @@ -0,0 +1,18 @@ + + + + Exe + net6.0-windows + enable + enable + VideoDemo.Program + x86 + x86 + + + + + + + +