diff --git a/Managed/UnrealEngine.Runtime/UnrealEngine.Runtime/CoreUObject/UObject.cs b/Managed/UnrealEngine.Runtime/UnrealEngine.Runtime/CoreUObject/UObject.cs
index 5606e22..f99b208 100644
--- a/Managed/UnrealEngine.Runtime/UnrealEngine.Runtime/CoreUObject/UObject.cs
+++ b/Managed/UnrealEngine.Runtime/UnrealEngine.Runtime/CoreUObject/UObject.cs
@@ -697,6 +697,11 @@ internal virtual void GetActorEyesViewPointInternal(out FVector OutLocation, out
OutRotation = default(FRotator);
}
+ internal virtual void InitInternal()
+ {
+ // This is eventually implemented in injected classes
+ }
+
///
/// Looks for a given function name
///
diff --git a/Managed/UnrealEngine.Runtime/UnrealEngine.Runtime/Internal/InjectedClasses/Engine/GameInstance_Injected.cs b/Managed/UnrealEngine.Runtime/UnrealEngine.Runtime/Internal/InjectedClasses/Engine/GameInstance_Injected.cs
new file mode 100644
index 0000000..2a2fc68
--- /dev/null
+++ b/Managed/UnrealEngine.Runtime/UnrealEngine.Runtime/Internal/InjectedClasses/Engine/GameInstance_Injected.cs
@@ -0,0 +1,26 @@
+using System;
+using UnrealEngine.Engine;
+using UnrealEngine.Runtime;
+using UnrealEngine.Runtime.Native;
+
+namespace UnrealEngine.Engine
+{
+ public partial class UGameInstance : UObject
+ {
+ private VTableHacks.CachedFunctionRedirect initializeRedirect;
+ internal override void InitInternal()
+ {
+ Init();
+ }
+
+ ///
+ /// Allow custom GameInstances an opportunity to set up what it needs.
+ ///
+ public virtual void Init()
+ {
+ initializeRedirect
+ .Resolve(VTableHacks.GameInstanceInit, this)
+ .Invoke(Address);
+ }
+ }
+}
diff --git a/Managed/UnrealEngine.Runtime/UnrealEngine.Runtime/Internal/VTableHacks.cs b/Managed/UnrealEngine.Runtime/UnrealEngine.Runtime/Internal/VTableHacks.cs
index 9417fe3..246b8e0 100644
--- a/Managed/UnrealEngine.Runtime/UnrealEngine.Runtime/Internal/VTableHacks.cs
+++ b/Managed/UnrealEngine.Runtime/UnrealEngine.Runtime/Internal/VTableHacks.cs
@@ -19,6 +19,7 @@ private static void AddVTableRedirects()
IntPtr actorClass = Runtime.Classes.AActor;
IntPtr actorComponentClass = Runtime.Classes.UActorComponent;
IntPtr playerControllerClass = Runtime.Classes.APlayerController;
+ IntPtr gameInstanceClass = Runtime.Classes.UGameInstance;
GetLifetimeReplicatedProps = AddVTableRedirect(objectClass, "DummyRepProps", new GetLifetimeReplicatedPropsDel(OnGetLifetimeReplicatedProps));
PawnSetupPlayerInputComponent = AddVTableRedirect(pawnClass, "DummySetupPlayerInput", new PawnSetupPlayerInputComponentDel(OnPawnSetupPlayerInputComponent));
@@ -29,6 +30,7 @@ private static void AddVTableRedirects()
ActorComponentEndPlay = AddVTableRedirect(actorComponentClass, "DummyActorComponentEndPlay", new EndPlayDel(OnActorComponentEndPlay));
PlayerControllerSetupInputComponent = AddVTableRedirect(playerControllerClass, "DummyPlayerControllerSetupInputComponent", new PlayerControllerSetupInputComponentDel(OnPlayerControllerSetupInputComponent));
PlayerControllerUpdateRotation = AddVTableRedirect(playerControllerClass, "DummyPlayerControllerUpdateRotation", new PlayerControllerUpdateRotationDel(OnPlayerControllerUpdateRotation));
+ GameInstanceInit = AddVTableRedirect(gameInstanceClass, "DummyGameInstanceInit", new GameInstanceInitDel(OnGameInstanceInit));
}
private static void LogCallbackException(string functionName, Exception e)
@@ -186,6 +188,23 @@ private static void OnPlayerControllerUpdateRotation(IntPtr address, float delta
}
}
+ public static FunctionRedirect GameInstanceInit { get; private set; }
+ delegate void GameInstanceInitDel(IntPtr address);
+ [UnmanagedFunctionPointer(CallingConvention.ThisCall)]
+ public delegate void GameInstanceInitDel_ThisCall(IntPtr address);
+ private static void OnGameInstanceInit(IntPtr address)
+ {
+ try
+ {
+ UObject obj = GCHelper.Find(address);
+ obj.InitInternal();
+ }
+ catch (Exception e)
+ {
+ LogCallbackException(nameof(OnGameInstanceInit), e);
+ }
+ }
+
////////////////////////////////////////////////////////////////////////////////////////
// Add vtable redirects above this line
////////////////////////////////////////////////////////////////////////////////////////
diff --git a/Source/USharp/Private/ExportedFunctions/Internal/Export_VTableHacks.h b/Source/USharp/Private/ExportedFunctions/Internal/Export_VTableHacks.h
index b23db70..8a3d736 100644
--- a/Source/USharp/Private/ExportedFunctions/Internal/Export_VTableHacks.h
+++ b/Source/USharp/Private/ExportedFunctions/Internal/Export_VTableHacks.h
@@ -9,6 +9,7 @@ ActorComponentBeginPlayCallbackSig ActorComponentBeginPlayCallback = nullptr;
ActorComponentEndPlayCallbackSig ActorComponentEndPlayCallback = nullptr;
PlayerControllerSetupInputComponentCallbackSig PlayerControllerSetupInputComponentCallback = nullptr;
PlayerControllerUpdateRotationCallbackSig PlayerControllerUpdateRotationCallback = nullptr;
+GameInstanceInitCallbackSig GameInstanceInitCallback = nullptr;
TMap DummyNames;
CSEXPORT void CSCONV Export_VTableHacks_Set_VTableCallback(const FString& DummyName, void* Callback)
@@ -25,6 +26,7 @@ CSEXPORT void CSCONV Export_VTableHacks_Set_VTableCallback(const FString& DummyN
DummyNames.Add(TEXT("DummyActorComponentEndPlay"), (void**)&ActorComponentEndPlayCallback);
DummyNames.Add(TEXT("DummyPlayerControllerSetupInputComponent"), (void**)&PlayerControllerSetupInputComponentCallback);
DummyNames.Add(TEXT("DummyPlayerControllerUpdateRotation"), (void**)&PlayerControllerUpdateRotationCallback);
+ DummyNames.Add(TEXT("DummyGameInstanceInit"), (void**)&GameInstanceInitCallback);
}
void*** Element = DummyNames.Find(DummyName);
diff --git a/Source/USharp/Private/VTableHacks.h b/Source/USharp/Private/VTableHacks.h
index 2b3af28..61272f7 100644
--- a/Source/USharp/Private/VTableHacks.h
+++ b/Source/USharp/Private/VTableHacks.h
@@ -428,4 +428,44 @@ class USHARP_API ADummyPlayerControllerUpdateRotation3 : public ADummyPlayerCont
{
FMsg::Logf("", 0, FName(TEXT("USharp")), ELogVerbosity::Log, TEXT("ADummyPlayerControllerUpdateRotation3-UpdateRotation"));
}
+};
+
+/////////////////////////////////////////////////////////////////////////////
+// UGameInstance::Init
+/////////////////////////////////////////////////////////////////////////////
+
+typedef void(CSCONV *GameInstanceInitCallbackSig)(UGameInstance* Obj);
+extern GameInstanceInitCallbackSig GameInstanceInitCallback;
+
+UCLASS(NotBlueprintable, NotBlueprintType)
+class USHARP_API UDummyGameInstanceInit1 : public UGameInstance
+{
+ GENERATED_BODY()
+
+public:
+ virtual void Init() override
+ {
+ if (GameInstanceInitCallback != nullptr)
+ {
+ GameInstanceInitCallback(this);
+ }
+ }
+};
+
+UCLASS(NotBlueprintable, NotBlueprintType)
+class USHARP_API UDummyGameInstanceInit2 : public UDummyGameInstanceInit1
+{
+ GENERATED_BODY()
+};
+
+UCLASS(NotBlueprintable, NotBlueprintType)
+class USHARP_API UDummyGameInstanceInit3 : public UDummyGameInstanceInit2
+{
+ GENERATED_BODY()
+
+public:
+ virtual void Init() override
+ {
+ FMsg::Logf("", 0, FName(TEXT("USharp")), ELogVerbosity::Log, TEXT("UDummyGameInstanceInit3-Init"));
+ }
};
\ No newline at end of file