private static void OnActorComponentBeginPlay(IntPtr address) { UObject obj = GCHelper.Find(address); IntPtr original = actorComponentBeginPlay.GetOriginal(obj); Native_VTableHacks.CallOriginal_ActorComponentBeginPlay(original, address); obj.BeginPlayInternal(); }
private static void OnActorEndPlay(IntPtr address, byte endPlayReason) { UObject obj = GCHelper.Find(address); IntPtr original = actorEndPlay.GetOriginal(obj); Native_VTableHacks.CallOriginal_ActorEndPlay(original, address, endPlayReason); obj.EndPlayInternal(endPlayReason); }
private static void OnSetupPlayerInputComponent(IntPtr address, IntPtr inputComponentAddress) { UObject obj = GCHelper.Find(address); IntPtr original = setupPlayerInput.GetOriginal(obj); Native_VTableHacks.CallOriginal_SetupPlayerInputComponent(original, address, inputComponentAddress); obj.SetupPlayerInputComponent(inputComponentAddress); }
private static FunctionRedirect AddVTableRedirect(IntPtr unrealClass, string dummyName, Delegate callback) { using (FStringUnsafe dummyNameUnsafe = new FStringUnsafe(dummyName)) { Native_VTableHacks.Set_VTableCallback(ref dummyNameUnsafe.Array, Marshal.GetFunctionPointerForDelegate(callback)); } FunctionRedirect redirect = new FunctionRedirect(unrealClass, dummyName, callback); vtableRedirects.Add(redirect); return(redirect); }
private static void OnGetLifetimeReplicatedProps(IntPtr address, IntPtr arrayAddress) { UObject obj = GCHelper.Find(address); IntPtr original = repProps.GetOriginal(obj); Native_VTableHacks.CallOriginal_GetLifetimeReplicatedProps(original, address, arrayAddress); using (TArrayUnsafeRef <FLifetimeProperty> lifetimePropsUnsafe = new TArrayUnsafeRef <FLifetimeProperty>(arrayAddress)) { FLifetimePropertyCollection lifetimeProps = new FLifetimePropertyCollection(address, lifetimePropsUnsafe); obj.GetLifetimeReplicatedProps(lifetimeProps); } }
public static unsafe void Unload() { foreach (FunctionRedirect redirect in vtableRedirects) { using (FStringUnsafe dummyNameUnsafe = new FStringUnsafe(redirect.DummyName)) { Native_VTableHacks.Set_VTableCallback(ref dummyNameUnsafe.Array, IntPtr.Zero); } } // Restore the old vtable entry on hotreload. This is important as otherwise we would lose the original function address // which is stored in the managed UClass (which gets destroyed on hotreload) foreach (IntPtr objAddress in new NativeReflection.NativeObjectIterator(Runtime.Classes.UObject, EObjectFlags.NoFlags)) { foreach (FunctionRedirect redirect in vtableRedirects) { if (!Native_UObjectBaseUtility.IsA(objAddress, redirect.Class)) { continue; } IntPtr *vtable = *(IntPtr **)objAddress; if (vtable[redirect.VTableIndex] == redirect.NativeCallback) { UObject obj = GCHelper.Find(objAddress); Debug.Assert(obj != null); UClass unrealClass = obj.GetClass(); Debug.Assert(unrealClass != null); UClass.VTableOriginalFunc originalFunc; if (unrealClass.VTableOriginalFunctions != null && unrealClass.VTableOriginalFunctions.TryGetValue(redirect.VTableIndex, out originalFunc)) { IntPtr pageAlignedPtr = FMemory.PageAlignPointer((IntPtr)(&vtable[redirect.VTableIndex])); FMemory.PageProtect(pageAlignedPtr, (IntPtr)IntPtr.Size, true, true); *(&vtable[redirect.VTableIndex]) = originalFunc.FuncAddress; } } } } }