diff --git a/OmsiExtensionsCLI/Program.cs b/OmsiExtensionsCLI/Program.cs
index 9eadbdf..8655891 100644
--- a/OmsiExtensionsCLI/Program.cs
+++ b/OmsiExtensionsCLI/Program.cs
@@ -92,7 +92,7 @@ public void CreateTexture()
try
{
- texture.CreateD3DTexture(texWidth, texHeight);
+ texture.CreateD3DTexture(texWidth, texHeight).Wait();
} catch (Exception ex)
{
Console.WriteLine(ex);
@@ -128,17 +128,19 @@ public void UpdateTexture()
}
iter++;
- texture.UpdateTexture(texBuffer.AsMemory(), new OmsiRemoteMethods.Rectangle() { left=0, top=0, right=texWidth/2, bottom=texHeight/2});
+ texture.UpdateTexture(texBuffer.AsMemory(), new OmsiRemoteMethods.Rectangle() { left=0, top=0, right=texWidth, bottom=texHeight}).Wait();
}
private void Omsi_OnOmsiGotD3DContext(object sender, EventArgs e)
{
// d3dGotContext.Set();
+ Console.WriteLine("Got D3D Context!");
}
private void Omsi_OnMapLoaded(object sender, bool e)
{
d3dGotContext.Set();
+ Console.WriteLine("Map Loaded!");
}
}
}
diff --git a/OmsiHook/D3DTexture.cs b/OmsiHook/D3DTexture.cs
index ad1003a..ff4a2d3 100644
--- a/OmsiHook/D3DTexture.cs
+++ b/OmsiHook/D3DTexture.cs
@@ -52,7 +52,7 @@ public D3DTexture() : base() { }
/// the address of the existing texture
///
///
- public async void CreateFromExisting(uint address)
+ public async Task CreateFromExisting(uint address)
{
if (Address == 0)
throw new NullReferenceException("Texture was already null!");
@@ -77,10 +77,10 @@ public async void CreateFromExisting(uint address)
/// the height of the texture
/// the of the texture
///
- public async void CreateD3DTexture(uint width, uint height, D3DFORMAT format = D3DFORMAT.D3DFMT_A8R8G8B8)
+ public async Task CreateD3DTexture(uint width, uint height, D3DFORMAT format = D3DFORMAT.D3DFMT_A8R8G8B8)
{
if(Address != 0)
- ReleaseTexture();
+ await ReleaseTexture();
var (hresult, pTexture) = await OmsiCreateTextureAsync(width, height, format);
if (HRESULTFailed(hresult))
@@ -100,7 +100,7 @@ public async void CreateD3DTexture(uint width, uint height, D3DFORMAT format = D
///
///
///
- public async void ReleaseTexture()
+ public async Task ReleaseTexture()
{
if(Address == 0)
throw new NullReferenceException("Texture was already null!");
@@ -123,7 +123,7 @@ public async void ReleaseTexture()
/// must match the size of this rectangle; pass in to update the whole texture
///
///
- public void UpdateTexture(Memory textureData, Rectangle? updateArea = null) where T : unmanaged
+ public async Task UpdateTexture(Memory textureData, Rectangle? updateArea = null) where T : unmanaged
{
if((textureData.Length * Marshal.SizeOf()) > stagingBufferSize)
throw new ArgumentOutOfRangeException(nameof(textureData));
@@ -132,7 +132,7 @@ public void UpdateTexture(Memory textureData, Rectangle? updateArea = null
uint dataWidth = (updateArea?.right - updateArea?.left) ?? width;
uint dataHeight = (updateArea?.bottom - updateArea?.top) ?? height;
- HRESULT hr = OmsiUpdateTextureAsync(TextureAddress, remoteStagingBufferPtr, dataWidth, dataHeight, updateArea).Result;
+ HRESULT hr = await OmsiUpdateTextureAsync(TextureAddress, remoteStagingBufferPtr, dataWidth, dataHeight, updateArea);
if (HRESULTFailed(hr))
throw new Exception("Couldn't update D3D texture! Result: " + hr);
}
diff --git a/OmsiHook/OmsiHook.cs b/OmsiHook/OmsiHook.cs
index cd8c559..cb243d3 100644
--- a/OmsiHook/OmsiHook.cs
+++ b/OmsiHook/OmsiHook.cs
@@ -57,6 +57,8 @@ public class OmsiHook
public event EventHandler OnOmsiGotD3DContext;
///
/// An event raised when Omsi gets a DirectX context.
+ ///
+ /// Note that this is one of the last events raised when exiting the game; it's raised after PluginFinalize is called.
///
///
///
@@ -71,6 +73,10 @@ public class OmsiHook
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.
+ ///
+ /// Note that while this event is raised when the map has finished loading; other systems may still be
+ /// loading (timetables, weather, humans, ai vehicles, and the map camera are loaded later). If you want to be sure
+ /// everything has loaded, the best bet would be to wait for an AccessVariable() call.
///
///
///
@@ -85,8 +91,8 @@ public class OmsiHook
///
/// Attaches the hooking application to OMSI.exe.
/// Always call this at some point before trying to read and write data.
- /// Try to initialise the connection to OmsiHookRPCPlugin, which is needed if you intend to call Omsi code or allocate memory.
///
+ /// Try to initialise the connection to OmsiHookRPCPlugin, which is needed if you intend to call Omsi code or allocate memory.
public async Task AttachToOMSI(bool initialiseRemoteMethods = true)
{
omsiMemory = new Memory();
@@ -113,7 +119,7 @@ public async Task AttachToOMSI(bool initialiseRemoteMethods = true)
if(initialiseRemoteMethods)
{
- await OmsiRemoteMethods.InitRemoteMethods(omsiMemory);
+ await OmsiRemoteMethods.InitRemoteMethods(omsiMemory, isLocalPlugin: Process.GetCurrentProcess().ProcessName == process.ProcessName);
}
stateMonitorTask = new(MonitorStateTask);
diff --git a/OmsiHook/OmsiHook.csproj b/OmsiHook/OmsiHook.csproj
index ae479e1..1450bda 100644
--- a/OmsiHook/OmsiHook.csproj
+++ b/OmsiHook/OmsiHook.csproj
@@ -10,9 +10,9 @@
OmsiHook is a simple library for hooking into Omsi's memory for modding.
true
true
- 2.3.1.1
- 2.3.1.1
- 2.3.1
+ 2.3.2.1
+ 2.3.2.1
+ 2.3.2
LGPL-3.0-only
False
README.md
diff --git a/OmsiHook/OmsiRemoteMethods.cs b/OmsiHook/OmsiRemoteMethods.cs
index 4f2827a..e943fc6 100644
--- a/OmsiHook/OmsiRemoteMethods.cs
+++ b/OmsiHook/OmsiRemoteMethods.cs
@@ -21,17 +21,21 @@ public static class OmsiRemoteMethods
private static ConcurrentDictionary> resultPromises;
private static Task resultReaderThread;
private static Memory memory;
+ private static bool localPlugin;
private static readonly ThreadLocal asyncWriteBuff = new(() => new byte[256]);
public static bool IsInitialised => (pipeRX?.IsConnected ?? false) && (pipeTX?.IsConnected ?? false);
// TODO: Okay maybe this shouldn't be static... Singleton?
- internal static async Task InitRemoteMethods(Memory omsiMemory, bool inifiniteTimeout = false)
+ internal static async Task InitRemoteMethods(Memory omsiMemory, bool inifiniteTimeout = false, bool isLocalPlugin = false)
{
memory = omsiMemory;
+ localPlugin = isLocalPlugin;
+
+ if (localPlugin)
+ return;
-#if !OMSI_PLUGIN
resultPromises = new();
// We swap rx and tx here so that it makes semantic sense (since the tx of the client goes to the rx of the server)
@@ -54,7 +58,6 @@ internal static async Task InitRemoteMethods(Memory omsiMemory, bool inifiniteTi
resultReaderThread = new Task(ResultReaderTask);
resultReaderThread.Start();
-#endif
}
///
@@ -102,7 +105,8 @@ public static int MakeVehicle()
public static void CloseRPCSession(bool killAllConnections)
{
-#if !OMSI_PLUGIN
+ if (!localPlugin)
+ return;
if (!IsInitialised)
throw new NotInitialisedException("OmsiHook RPC plugin is not connected! Did you make sure to call OmsiRemoteMethods.InitRemoteMethods() before this call?");
@@ -117,7 +121,6 @@ public static void CloseRPCSession(bool killAllConnections)
lock (pipeTX)
pipeTX.Write(writeBuffer);
// promise.Task.Wait();
-#endif
}
///
@@ -133,37 +136,40 @@ public static void CloseRPCSession(bool killAllConnections)
/// The index of the vehicle that was placed.
public static int PlaceRandomBus(int aiType = 0, int group = 1, int type = -1, bool scheduled = false, int tour = 0, int line = 0)
{
-#if OMSI_PLUGIN
- return TProgManPlaceRandomBus(memory.ReadMemory(0x00862f28), aiType, group, 0, false, true, type, scheduled, 0, tour, line);
-#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.TProgManPlaceRandomBus;
- Span writeBuffer = stackalloc byte[OmsiHookRPCMethods.RemoteMethodsArgsSizes[method] + 8];
- //Span readBuffer = stackalloc byte[4];
- (int resultPromise, TaskCompletionSource promise) = CreateResultPromise();
- BitConverter.TryWriteBytes(writeBuffer[(argPos)..], (int)method);
- BitConverter.TryWriteBytes(writeBuffer[(argPos += 4)..], resultPromise);
- BitConverter.TryWriteBytes(writeBuffer[(argPos += 4)..], aiType);
- BitConverter.TryWriteBytes(writeBuffer[(argPos += 4)..], group);
- BitConverter.TryWriteBytes(writeBuffer[(argPos += 4)..], 0);
- BitConverter.TryWriteBytes(writeBuffer[(argPos += 1)..], false);
- BitConverter.TryWriteBytes(writeBuffer[(argPos += 1)..], true);
- BitConverter.TryWriteBytes(writeBuffer[(argPos += 4)..], type);
- BitConverter.TryWriteBytes(writeBuffer[(argPos += 1)..], scheduled);
- BitConverter.TryWriteBytes(writeBuffer[(argPos += 4)..], 0);
- BitConverter.TryWriteBytes(writeBuffer[(argPos += 4)..], aiType);
- BitConverter.TryWriteBytes(writeBuffer[(argPos += 4)..], tour);
- BitConverter.TryWriteBytes(writeBuffer[(argPos += 4)..], line);
- lock (pipeTX)
- pipeTX.Write(writeBuffer);
- return promise.Task.Result;
- //lock (pipeRX)
- // pipeRX.Read(readBuffer);
- //return BitConverter.ToInt32(readBuffer);
-#endif
+ if (localPlugin)
+ {
+ return TProgManPlaceRandomBus(memory.ReadMemory(0x00862f28), aiType, group, 0, false, true, type, scheduled, 0, tour, line);
+ }
+ 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.TProgManPlaceRandomBus;
+ Span writeBuffer = stackalloc byte[OmsiHookRPCMethods.RemoteMethodsArgsSizes[method] + 8];
+ //Span readBuffer = stackalloc byte[4];
+ (int resultPromise, TaskCompletionSource promise) = CreateResultPromise();
+ BitConverter.TryWriteBytes(writeBuffer[(argPos)..], (int)method);
+ BitConverter.TryWriteBytes(writeBuffer[(argPos += 4)..], resultPromise);
+ BitConverter.TryWriteBytes(writeBuffer[(argPos += 4)..], aiType);
+ BitConverter.TryWriteBytes(writeBuffer[(argPos += 4)..], group);
+ BitConverter.TryWriteBytes(writeBuffer[(argPos += 4)..], 0);
+ BitConverter.TryWriteBytes(writeBuffer[(argPos += 1)..], false);
+ BitConverter.TryWriteBytes(writeBuffer[(argPos += 1)..], true);
+ BitConverter.TryWriteBytes(writeBuffer[(argPos += 4)..], type);
+ BitConverter.TryWriteBytes(writeBuffer[(argPos += 1)..], scheduled);
+ BitConverter.TryWriteBytes(writeBuffer[(argPos += 4)..], 0);
+ BitConverter.TryWriteBytes(writeBuffer[(argPos += 4)..], aiType);
+ BitConverter.TryWriteBytes(writeBuffer[(argPos += 4)..], tour);
+ BitConverter.TryWriteBytes(writeBuffer[(argPos += 4)..], line);
+ lock (pipeTX)
+ pipeTX.Write(writeBuffer);
+ return promise.Task.Result;
+ //lock (pipeRX)
+ // pipeRX.Read(readBuffer);
+ //return BitConverter.ToInt32(readBuffer);
+ }
}
///
@@ -175,28 +181,29 @@ public static int PlaceRandomBus(int aiType = 0, int group = 1, int type = -1, b
/// VirtualProtect it to access it).
public static async Task OmsiGetMem(int length)
{
-#if OMSI_PLUGIN
- return (uint)GetMem(length);
-#else
- if(!IsInitialised)
- return 0;
-
- int argPos = 0;
- var method = OmsiHookRPCMethods.RemoteMethod.GetMem;
- 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)..], length);
- lock (pipeTX)
- pipeTX.Write(writeBuffer.AsSpan()[..writeBufferSize]);
- return (uint)await promise.Task;
- /*lock (pipeRX)
- pipeRX.Read(readBuffer);
- return BitConverter.ToUInt32(readBuffer);*/
-#endif
+ if (localPlugin)
+ return (uint)GetMem(length);
+ else
+ {
+ if (!IsInitialised)
+ return 0;
+
+ int argPos = 0;
+ var method = OmsiHookRPCMethods.RemoteMethod.GetMem;
+ 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)..], length);
+ lock (pipeTX)
+ pipeTX.Write(writeBuffer.AsSpan()[..writeBufferSize]);
+ return (uint)await promise.Task;
+ /*lock (pipeRX)
+ pipeRX.Read(readBuffer);
+ return BitConverter.ToUInt32(readBuffer);*/
+ }
}
///
@@ -206,23 +213,24 @@ public static async Task OmsiGetMem(int length)
/// The pointer to the object to deallocate
public static void OmsiFreeMemAsync(int addr)
{
-#if OMSI_PLUGIN
- FreeMem(addr);
-#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.FreeMem;
- Span writeBuffer = stackalloc byte[OmsiHookRPCMethods.RemoteMethodsArgsSizes[method] + 8];
- (int resultPromise, TaskCompletionSource promise) = CreateResultPromise();
- BitConverter.TryWriteBytes(writeBuffer[(argPos)..], (int)method);
- BitConverter.TryWriteBytes(writeBuffer[(argPos += 4)..], resultPromise);
- BitConverter.TryWriteBytes(writeBuffer[(argPos += 4)..], addr);
- lock (pipeTX)
- pipeTX.Write(writeBuffer);
- //promise.AsTask().Wait();
-#endif
+ if (localPlugin)
+ FreeMem(addr);
+ 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.FreeMem;
+ Span writeBuffer = stackalloc byte[OmsiHookRPCMethods.RemoteMethodsArgsSizes[method] + 8];
+ (int resultPromise, TaskCompletionSource promise) = CreateResultPromise();
+ BitConverter.TryWriteBytes(writeBuffer[(argPos)..], (int)method);
+ BitConverter.TryWriteBytes(writeBuffer[(argPos += 4)..], resultPromise);
+ BitConverter.TryWriteBytes(writeBuffer[(argPos += 4)..], addr);
+ lock (pipeTX)
+ pipeTX.Write(writeBuffer);
+ //promise.AsTask().Wait();
+ }
}
///
@@ -230,22 +238,23 @@ public static void OmsiFreeMemAsync(int addr)
///
public static bool OmsiHookD3D()
{
-#if OMSI_PLUGIN
- return HookD3D() != 0;
-#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;
- Span writeBuffer = stackalloc byte[8];
- (int resultPromise, TaskCompletionSource promise) = CreateResultPromise();
- BitConverter.TryWriteBytes(writeBuffer[(argPos)..], (int)OmsiHookRPCMethods.RemoteMethod.HookD3D);
- BitConverter.TryWriteBytes(writeBuffer[(argPos+=4)..], resultPromise);
- lock (pipeTX)
- pipeTX.Write(writeBuffer);
- var res = promise.Task.Result;
- return res != 0;
-#endif
+ if (localPlugin)
+ return HookD3D() != 0;
+ 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;
+ Span writeBuffer = stackalloc byte[8];
+ (int resultPromise, TaskCompletionSource promise) = CreateResultPromise();
+ BitConverter.TryWriteBytes(writeBuffer[(argPos)..], (int)OmsiHookRPCMethods.RemoteMethod.HookD3D);
+ BitConverter.TryWriteBytes(writeBuffer[(argPos += 4)..], resultPromise);
+ lock (pipeTX)
+ pipeTX.Write(writeBuffer);
+ var res = promise.Task.Result;
+ return res != 0;
+ }
}
///
@@ -253,36 +262,39 @@ public static bool OmsiHookD3D()
///
public static async Task<(HRESULT hresult, uint pTexture)> OmsiCreateTextureAsync(uint width, uint height, D3DFORMAT format)
{
-#if OMSI_PLUGIN
- uint ppTexture = OmsiGetMem(4).Result;
- HRESULT hresult = (HRESULT)CreateTexture(width, height, (uint)format, ppTexture);
- return (hresult, ppTexture);
-#else
- if (!IsInitialised)
- throw new NotInitialisedException("OmsiHook RPC plugin is not connected! Did you make sure to call OmsiRemoteMethods.InitRemoteMethods() before this call?");
-
- // Allocate the pointers
- int ppTexture = memory.AllocRemoteMemory(4, true).Result;//OmsiGetMem(4).Result;
- memory.WriteMemory(ppTexture, 0);
-
- int argPos = 0;
- var method = OmsiHookRPCMethods.RemoteMethod.CreateTexture;
- // This should be thread safe as the asyncWriteBuff is thread local
- int writeBufferSize = OmsiHookRPCMethods.RemoteMethodsArgsSizes[method] + 8;
- 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)..], width);
- BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], height);
- BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], (uint)format);
- BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], ppTexture);
- lock (pipeTX)
- pipeTX.Write(writeBuffer.AsSpan()[..writeBufferSize]);
- HRESULT result = (HRESULT)await promise.Task;
- uint pTexture = memory.ReadMemory(ppTexture);
- return (result, pTexture);
-#endif
+ if (localPlugin)
+ {
+ uint ppTexture = OmsiGetMem(4).Result;
+ HRESULT hresult = (HRESULT)CreateTexture(width, height, (uint)format, ppTexture);
+ return (hresult, ppTexture);
+ }
+ else
+ {
+ if (!IsInitialised)
+ throw new NotInitialisedException("OmsiHook RPC plugin is not connected! Did you make sure to call OmsiRemoteMethods.InitRemoteMethods() before this call?");
+
+ // Allocate the pointers
+ int ppTexture = memory.AllocRemoteMemory(4, true).Result;//OmsiGetMem(4).Result;
+ memory.WriteMemory(ppTexture, 0);
+
+ int argPos = 0;
+ var method = OmsiHookRPCMethods.RemoteMethod.CreateTexture;
+ // This should be thread safe as the asyncWriteBuff is thread local
+ int writeBufferSize = OmsiHookRPCMethods.RemoteMethodsArgsSizes[method] + 8;
+ 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)..], width);
+ BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], height);
+ BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], (uint)format);
+ BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], ppTexture);
+ lock (pipeTX)
+ pipeTX.Write(writeBuffer.AsSpan()[..writeBufferSize]);
+ HRESULT result = (HRESULT)await promise.Task;
+ uint pTexture = memory.ReadMemory(ppTexture);
+ return (result, pTexture);
+ }
}
///
@@ -297,34 +309,37 @@ public static bool OmsiHookD3D()
///
public static async Task OmsiUpdateTextureAsync(uint texturePtr, uint textureDataPtr, uint width, uint height, Rectangle? updateRect = null)
{
-#if OMSI_PLUGIN
- return (HRESULT)UpdateSubresource(texturePtr, textureDataPtr, width, height,
- updateRect.HasValue ? 1 : 0, updateRect?.left??0, updateRect?.top??0, updateRect?.right??0, updateRect?.bottom??0);
-#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.UpdateSubresource;
- // This should be thread safe as the asyncWriteBuff is thread local
- int writeBufferSize = OmsiHookRPCMethods.RemoteMethodsArgsSizes[method] + 8;
- 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)..], texturePtr);
- BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], textureDataPtr);
- BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], width);
- BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], height);
- BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], updateRect.HasValue ? 1 : 0);
- BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], updateRect?.left ?? 0);
- BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], updateRect?.top ?? 0);
- BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], updateRect?.right ?? 0);
- BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], updateRect?.bottom ?? 0);
- lock (pipeTX)
- pipeTX.Write(writeBuffer.AsSpan()[..writeBufferSize]);
- return (HRESULT)await promise.Task;
-#endif
+ if (localPlugin)
+ {
+ return (HRESULT)UpdateSubresource(texturePtr, textureDataPtr, width, height,
+ updateRect.HasValue ? 1 : 0, updateRect?.left ?? 0, updateRect?.top ?? 0, updateRect?.right ?? 0, updateRect?.bottom ?? 0);
+ }
+ 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.UpdateSubresource;
+ // This should be thread safe as the asyncWriteBuff is thread local
+ int writeBufferSize = OmsiHookRPCMethods.RemoteMethodsArgsSizes[method] + 8;
+ 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)..], texturePtr);
+ BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], textureDataPtr);
+ BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], width);
+ BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], height);
+ BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], updateRect.HasValue ? 1 : 0);
+ BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], updateRect?.left ?? 0);
+ BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], updateRect?.top ?? 0);
+ BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], updateRect?.right ?? 0);
+ BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], updateRect?.bottom ?? 0);
+ lock (pipeTX)
+ pipeTX.Write(writeBuffer.AsSpan()[..writeBufferSize]);
+ return (HRESULT)await promise.Task;
+ }
}
///
@@ -335,25 +350,26 @@ public static async Task OmsiUpdateTextureAsync(uint texturePtr, uint t
///
public static async Task OmsiReleaseTextureAsync(uint texturePtr)
{
-#if OMSI_PLUGIN
- return (HRESULT)ReleaseTexture(texturePtr);
-#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.ReleaseTexture;
- // This should be thread safe as the asyncWriteBuff is thread local
- int writeBufferSize = OmsiHookRPCMethods.RemoteMethodsArgsSizes[method] + 8;
- 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)..], texturePtr);
- lock (pipeTX)
- pipeTX.Write(writeBuffer.AsSpan()[..writeBufferSize]);
- return (HRESULT)await promise.Task;
-#endif
+ if (localPlugin)
+ return (HRESULT)ReleaseTexture(texturePtr);
+ 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.ReleaseTexture;
+ // This should be thread safe as the asyncWriteBuff is thread local
+ int writeBufferSize = OmsiHookRPCMethods.RemoteMethodsArgsSizes[method] + 8;
+ 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)..], texturePtr);
+ lock (pipeTX)
+ pipeTX.Write(writeBuffer.AsSpan()[..writeBufferSize]);
+ return (HRESULT)await promise.Task;
+ }
}
///
@@ -365,42 +381,45 @@ public static async Task OmsiReleaseTextureAsync(uint texturePtr)
public static async Task<(HRESULT hresult, uint width, uint height, D3DFORMAT format)> OmsiGetTextureDescAsync(uint texturePtr)
{
uint descPtr = unchecked((uint)await memory.AllocRemoteMemory(4 * 3, true));
-#if OMSI_PLUGIN
- HRESULT res = (HRESULT)GetTextureDesc(texturePtr, descPtr, descPtr + 4, descPtr + 8);
-
- uint width = memory.ReadMemory(descPtr);
- uint height = memory.ReadMemory(descPtr+4);
- D3DFORMAT format = (D3DFORMAT)memory.ReadMemory(descPtr+8);
- memory.FreeRemoteMemory(descPtr, true);
-
- return (res, width, height, format);
-#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.GetTextureDesc;
- // This should be thread safe as the asyncWriteBuff is thread local
- int writeBufferSize = OmsiHookRPCMethods.RemoteMethodsArgsSizes[method] + 8;
- 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)..], texturePtr);
- BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], descPtr);
- BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], descPtr+4);
- BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], descPtr+8);
- lock (pipeTX)
- pipeTX.Write(writeBuffer.AsSpan()[..writeBufferSize]);
+ if (localPlugin)
+ {
+ HRESULT res = (HRESULT)GetTextureDesc(texturePtr, descPtr, descPtr + 4, descPtr + 8);
- HRESULT res = (HRESULT)await promise.Task;
- uint width = memory.ReadMemory(descPtr);
- uint height = memory.ReadMemory(descPtr + 4);
- D3DFORMAT format = (D3DFORMAT)memory.ReadMemory(descPtr + 8);
- memory.FreeRemoteMemory(descPtr, true);
+ uint width = memory.ReadMemory(descPtr);
+ uint height = memory.ReadMemory(descPtr + 4);
+ D3DFORMAT format = (D3DFORMAT)memory.ReadMemory(descPtr + 8);
+ memory.FreeRemoteMemory(descPtr, true);
- return (res, width, height, format);
-#endif
+ return (res, width, height, format);
+ }
+ 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.GetTextureDesc;
+ // This should be thread safe as the asyncWriteBuff is thread local
+ int writeBufferSize = OmsiHookRPCMethods.RemoteMethodsArgsSizes[method] + 8;
+ 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)..], texturePtr);
+ BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], descPtr);
+ BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], descPtr + 4);
+ BitConverter.TryWriteBytes(writeBuffer.AsSpan()[(argPos += 4)..], descPtr + 8);
+ lock (pipeTX)
+ pipeTX.Write(writeBuffer.AsSpan()[..writeBufferSize]);
+
+ HRESULT res = (HRESULT)await promise.Task;
+ uint width = memory.ReadMemory(descPtr);
+ uint height = memory.ReadMemory(descPtr + 4);
+ D3DFORMAT format = (D3DFORMAT)memory.ReadMemory(descPtr + 8);
+ memory.FreeRemoteMemory(descPtr, true);
+
+ return (res, width, height, format);
+ }
}
///
@@ -413,25 +432,26 @@ public static async Task OmsiReleaseTextureAsync(uint texturePtr)
///
public static async Task OmsiIsTextureAsync(uint texturePtr)
{
-#if OMSI_PLUGIN
- return !HRESULTFailed((HRESULT)IsTexture(texturePtr));
-#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.IsTexture;
- // This should be thread safe as the asyncWriteBuff is thread local
- int writeBufferSize = OmsiHookRPCMethods.RemoteMethodsArgsSizes[method] + 8;
- 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)..], texturePtr);
- lock (pipeTX)
- pipeTX.Write(writeBuffer.AsSpan()[..writeBufferSize]);
- return !HRESULTFailed((HRESULT)await promise.Task);
-#endif
+ if (localPlugin)
+ return !HRESULTFailed((HRESULT)IsTexture(texturePtr));
+ 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.IsTexture;
+ // This should be thread safe as the asyncWriteBuff is thread local
+ int writeBufferSize = OmsiHookRPCMethods.RemoteMethodsArgsSizes[method] + 8;
+ 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)..], texturePtr);
+ lock (pipeTX)
+ pipeTX.Write(writeBuffer.AsSpan()[..writeBufferSize]);
+ return !HRESULTFailed((HRESULT)await promise.Task);
+ }
}
[DllImport("OmsiHookInvoker.dll")]
diff --git a/OmsiHookInvoker/FunctionHooks.cpp b/OmsiHookInvoker/FunctionHooks.cpp
new file mode 100644
index 0000000..88b6545
--- /dev/null
+++ b/OmsiHookInvoker/FunctionHooks.cpp
@@ -0,0 +1,63 @@
+#include "pch.h"
+#include "FunctionHooks.h"
+
+FunctionHooks::FunctionHooks()
+{
+ DWORD oldProtect;
+ VirtualProtect(hookTrampolineFunc, sizeof(hookTrampolineFunc), PAGE_EXECUTE_READWRITE, &oldProtect);
+ ZeroMemory(hookTrampolineFunc, sizeof(hookTrampolineFunc));
+}
+
+FunctionHooks::~FunctionHooks()
+{
+
+}
+
+void FunctionHooks::InstallHook(UINT32 funcToHook)
+{
+ DWORD oldProtect;
+ VirtualProtect((LPVOID)funcToHook, 256, PAGE_EXECUTE_READWRITE, &oldProtect);
+ byte jmpInstruction[5] = { 0xE9, 0x0, 0x0, 0x0, 0x0 };
+
+ const UINT32 relAddr = (UINT32)hookTrampolineFunc - (funcToHook + sizeof(jmpInstruction));
+ memcpy(jmpInstruction + 1, &relAddr, 4);
+ //https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-flushinstructioncache
+ memcpy((LPVOID)funcToHook, jmpInstruction, sizeof(jmpInstruction));
+ VirtualProtect((LPVOID)funcToHook, 256, oldProtect, &oldProtect);
+}
+
+#define AsLEBytes(addr) ((addr>>3)&0xff), ((addr>>2)&0xff), ((addr>>1)&0xff), ((addr>>0)&0xff)
+
+void FunctionHooks::OnTrigger(void(*callback)(LPCSTR trigger, int value))
+{
+ // Bouncy bounce
+ UINT32 callbackRelAddr = (UINT32)callback - ((UINT32)hookTrampolineFunc + 11);
+ UINT32 returnRelAddr = (UINT32)0x007bae96 - ((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
+ 0x52, //push eax
+ 0x55, //push edx
+ 0x54, //push ecx
+
+ // Convert a borland fastcall to stdcall
+ 0x52, //push eax
+ 0x55, //push edx
+ 0x54, //push ecx
+ 0xe8, AsLEBytes(callbackRelAddr), //call callback
+
+ // Restore register args
+ 0x59, //pop ecx
+ 0x5a, //pop edx
+ 0x57, //pop eax
+
+ // Now execute the prolog of the function we overwrote and jump back
+ 0x55, //push ebp
+ 0x8b, 0xec, //mov ebp, esp
+ 0x83, 0xc4, 0xf0,//add esp, -0x10
+ 0xe9, AsLEBytes(returnRelAddr) //jmp 0x007bae96
+ };
+ memcpy(hookTrampolineFunc, hookTrampolineTemp, sizeof(hookTrampolineTemp));
+
+ InstallHook(0x007bae90);
+}
diff --git a/OmsiHookInvoker/FunctionHooks.h b/OmsiHookInvoker/FunctionHooks.h
new file mode 100644
index 0000000..ce4c485
--- /dev/null
+++ b/OmsiHookInvoker/FunctionHooks.h
@@ -0,0 +1,14 @@
+#pragma once
+class FunctionHooks
+{
+public:
+ FunctionHooks();
+ ~FunctionHooks();
+ void OnTrigger(void (*callback) (LPCSTR trigger, int value));
+
+private:
+ void InstallHook(UINT32 funcToHook);
+
+ byte hookTrampolineFunc[256];
+};
+
diff --git a/OmsiHookInvoker/OmsiHookInvoker.vcxproj b/OmsiHookInvoker/OmsiHookInvoker.vcxproj
index e0a204d..05d662f 100644
--- a/OmsiHookInvoker/OmsiHookInvoker.vcxproj
+++ b/OmsiHookInvoker/OmsiHookInvoker.vcxproj
@@ -1,4 +1,4 @@
-
+
@@ -92,12 +92,14 @@
+
+
Create
Create
diff --git a/OmsiHookInvoker/dllmain.cpp b/OmsiHookInvoker/dllmain.cpp
index 3e7f72a..e88dcb5 100644
--- a/OmsiHookInvoker/dllmain.cpp
+++ b/OmsiHookInvoker/dllmain.cpp
@@ -1,8 +1,10 @@
// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include "DXHook.h"
+#include "FunctionHooks.h"
DXHook* m_dxHook;
+FunctionHooks* m_functionHooks;
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
@@ -14,10 +16,13 @@ BOOL APIENTRY DllMain( HMODULE hModule,
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
+ m_functionHooks = new FunctionHooks();
break;
case DLL_PROCESS_DETACH:
if (m_dxHook)
delete m_dxHook;
+ if (m_functionHooks)
+ delete m_functionHooks;
break;
}
return TRUE;
@@ -206,3 +211,8 @@ extern "C" __declspec(dllexport) HRESULT IsTexture(IUnknown* Texture)
{
return DXHook::IsTexture(Texture);
}
+
+extern "C" __declspec(dllexport) void OnTrigger(void (*callback) (LPCSTR trigger, int value))
+{
+
+}
diff --git a/OmsiHookPlugin/OmsiHookPlugin.cs b/OmsiHookPlugin/OmsiHookPlugin.cs
index 51bd8c1..7d15fa0 100644
--- a/OmsiHookPlugin/OmsiHookPlugin.cs
+++ b/OmsiHookPlugin/OmsiHookPlugin.cs
@@ -4,27 +4,62 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using OmsiHook;
-using System.Security;
-using System.Diagnostics;
namespace OmsiHookPlugin
{
public class OmsiHookPlugin
{
private static OmsiHook.OmsiHook hook;
- private static bool spawned = false;
private static void Log(object msg) => File.AppendAllText("omsiHookPluginLog.txt", $"[{DateTime.Now:dd/MM/yy HH:mm:ss:ff}] {msg}\n");
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) }, EntryPoint = nameof(PluginStart))]
public static void PluginStart(IntPtr aOwner)
{
- File.Delete("omsiHookPluginLog.txt");
+ try
+ {
+ File.Delete("omsiHookPluginLog.txt");
+ } catch { }
Log("PluginStart()");
Log("Loading OmsiHook...");
hook = new();
- _ = hook.AttachToOMSI();
- Log("Didn't crash!");
+ try
+ {
+ hook.AttachToOMSI().Wait();
+ } catch (Exception e)
+ {
+ Log($"Failed to attach to Omsi:\n{e}");
+ }
+ hook.OnMapLoaded += Hook_OnMapLoaded;
+ hook.OnMapChange += Hook_OnMapChange;
+ hook.OnOmsiExited += Hook_OnOmsiExited;
+ hook.OnOmsiGotD3DContext += Hook_OnOmsiGotD3DContext;
+ hook.OnOmsiLostD3DContext += Hook_OnOmsiLostD3DContext;
+ }
+
+ private static void Hook_OnOmsiLostD3DContext(object sender, EventArgs e)
+ {
+ Log($"Lost D3D context!");
+ }
+
+ private static void Hook_OnOmsiGotD3DContext(object sender, EventArgs e)
+ {
+ Log($"Got D3D context!");
+ }
+
+ private static void Hook_OnOmsiExited(object sender, EventArgs e)
+ {
+ Log($"Omsi exited!");
+ }
+
+ private static void Hook_OnMapChange(object sender, EventArgs e)
+ {
+ Log($"Map changed!");
+ }
+
+ private static void Hook_OnMapLoaded(object sender, bool e)
+ {
+ Log($"Map loaded! {e}");
}
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) }, EntryPoint = nameof(PluginFinalize))]
@@ -36,27 +71,7 @@ public static void PluginFinalize()
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) }, EntryPoint = nameof(AccessVariable))]
public static void AccessVariable(ushort variableIndex, [C99Type("float*")] IntPtr value, [C99Type("__crt_bool*")] IntPtr writeValue)
{
- var val = Marshal.PtrToStructure(value);
- if (val > 0.9 && !spawned)
- {
- spawned = true;
- Log("Spawning bus!");
- try
- {
- //hook.Globals.RemoteMethods.PlaceRandomBus();
- } catch (Exception e)
- {
- Log("Uh oh:");
- Log(e.Message);
- Log(e.ToString());
- }
-
- Log("The bus might have spawned!");
- } else
- {
- if (val < 0.1)
- spawned = false;
- }
+
}
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) }, EntryPoint = nameof(AccessTrigger))]
diff --git a/OmsiHookPlugin/OmsiHookPlugin.opl b/OmsiHookPlugin/OmsiHookPlugin.opl
index 81721a9..e6a6f8f 100644
--- a/OmsiHookPlugin/OmsiHookPlugin.opl
+++ b/OmsiHookPlugin/OmsiHookPlugin.opl
@@ -3,4 +3,4 @@ OmsiHookPluginNE.dll
[varlist]
1
-door_0
+Throttle