Access Violations

I started using SUBSCRIBE_UOBJECT_METHOD() as per Mircea/Rex advice, but I still get an access violation. Starting a test world with nothing in it / no other mods besides SML, everything works OK until I place a sign. The build animation plays and then there's about 1 frame where the sign tries to display something and then the game crashes.
#include "MoreLightingOptionsModule.h"
#include "Buildables/FGBuildableWidgetSign.h"
#include "Patching/NativeHookManager.h"

class HFGBuildableWidgetSign
{
public:
static void Hook_GetAdjustedEmissiveValue(TCallScope<float(__cdecl*)(const AFGBuildableWidgetSign*, int32)>& scope, const AFGBuildableWidgetSign* self, int32 Level)
{
if (!self) {
return;
}

float BaseEmissiveValue = scope(self, Level);
float NewEmissiveValue = BaseEmissiveValue * 10.0f;
if (NewEmissiveValue >= 0.0f) {
scope.Override(NewEmissiveValue);
}
}

static void RegisterHooks()
{
SUBSCRIBE_UOBJECT_METHOD(AFGBuildableWidgetSign, GetAdjustedEmissiveValue, &HFGBuildableWidgetSign::Hook_GetAdjustedEmissiveValue);
}
};

// Startup Module for MoreLightingOptions
void FMoreLightingOptionsModule::StartupModule()
{
if (!WITH_EDITOR)
{
HFGBuildableWidgetSign::RegisterHooks();
}
}

void FMoreLightingOptionsModule::ShutdownModule()
{
}

IMPLEMENT_GAME_MODULE(FMoreLightingOptionsModule, MoreLightingOptions);
#include "MoreLightingOptionsModule.h"
#include "Buildables/FGBuildableWidgetSign.h"
#include "Patching/NativeHookManager.h"

class HFGBuildableWidgetSign
{
public:
static void Hook_GetAdjustedEmissiveValue(TCallScope<float(__cdecl*)(const AFGBuildableWidgetSign*, int32)>& scope, const AFGBuildableWidgetSign* self, int32 Level)
{
if (!self) {
return;
}

float BaseEmissiveValue = scope(self, Level);
float NewEmissiveValue = BaseEmissiveValue * 10.0f;
if (NewEmissiveValue >= 0.0f) {
scope.Override(NewEmissiveValue);
}
}

static void RegisterHooks()
{
SUBSCRIBE_UOBJECT_METHOD(AFGBuildableWidgetSign, GetAdjustedEmissiveValue, &HFGBuildableWidgetSign::Hook_GetAdjustedEmissiveValue);
}
};

// Startup Module for MoreLightingOptions
void FMoreLightingOptionsModule::StartupModule()
{
if (!WITH_EDITOR)
{
HFGBuildableWidgetSign::RegisterHooks();
}
}

void FMoreLightingOptionsModule::ShutdownModule()
{
}

IMPLEMENT_GAME_MODULE(FMoreLightingOptionsModule, MoreLightingOptions);
Solution:
```cpp float NewEmissiveValue = 0.0f; switch (Level) { case 0:...
Jump to solution
26 Replies
Beef
BeefOP•3mo ago
[2024.10.23-18.13.09:059][153]LogWindows: Error: === Critical error: ===
[2024.10.23-18.13.09:059][153]LogWindows: Error:
[2024.10.23-18.13.09:059][153]LogWindows: Error: Fatal error!
[2024.10.23-18.13.09:059][153]LogWindows: Error:
[2024.10.23-18.13.09:059][153]LogWindows: Error: Unhandled Exception: EXCEPTION_ACCESS_VIOLATION reading address 0xffffffffffffffff
[2024.10.23-18.13.09:059][153]LogWindows: Error:
[2024.10.23-18.13.09:059][153]LogWindows: Error: [Callstack] 0x00007ff97eb1105c UnknownFunction []
[2024.10.23-18.13.09:059][153]LogWindows: Error: [Callstack] 0x00007ff974da2a21 FactoryGameSteam-MoreLightingOptions-Win64-Shipping.dll!HFGBuildableWidgetSign::Hook_GetAdjustedEmissiveValue() [C:\SatisfactoryModding\SatisfactoryModLoader\Mods\MoreLightingOptions\Source\MoreLightingOptions\MoreLightingOptionsModule.cpp:15]
[2024.10.23-18.13.09:059][153]LogWindows: Error: === Critical error: ===
[2024.10.23-18.13.09:059][153]LogWindows: Error:
[2024.10.23-18.13.09:059][153]LogWindows: Error: Fatal error!
[2024.10.23-18.13.09:059][153]LogWindows: Error:
[2024.10.23-18.13.09:059][153]LogWindows: Error: Unhandled Exception: EXCEPTION_ACCESS_VIOLATION reading address 0xffffffffffffffff
[2024.10.23-18.13.09:059][153]LogWindows: Error:
[2024.10.23-18.13.09:059][153]LogWindows: Error: [Callstack] 0x00007ff97eb1105c UnknownFunction []
[2024.10.23-18.13.09:059][153]LogWindows: Error: [Callstack] 0x00007ff974da2a21 FactoryGameSteam-MoreLightingOptions-Win64-Shipping.dll!HFGBuildableWidgetSign::Hook_GetAdjustedEmissiveValue() [C:\SatisfactoryModding\SatisfactoryModLoader\Mods\MoreLightingOptions\Source\MoreLightingOptions\MoreLightingOptionsModule.cpp:15]
Originally was following the pattern of Linear Override, but since virtual float GetAdjustedEmissiveValue(int32 Level) const; is well, virtual that makes sense. I then used https://github.com/Th3Fanbus/Th3SwiftSwim/blob/master/Source/Th3SwiftSwim/Private/Th3SwiftSwim.cpp as suggested as the overall framework for the mod so far
Rex
Rex•3mo ago
You didn't need the helper class (I used that for AccessTransformers), but it still shouldn't crash like this Line 15 is float NewEmissiveValue = BaseEmissiveValue * 10.0f; I'm guessing something got inlined
Beef
BeefOP•3mo ago
I may want to hook in somewhere else, this just "seemed" easy ... but learning a new modding framework for a new game always is like this 😅
Rex
Rex•3mo ago
That's the thing, though. This should work Let me check...
Beef
BeefOP•3mo ago
OK, perhaps I've messed something up in .h or build.cs MoreLightingOptionsModule.h
#pragma once

#include "Modules/ModuleManager.h"
#include "CoreMinimal.h"

class FMoreLightingOptionsModule : public IModuleInterface {
public:
virtual void StartupModule() override;
virtual void ShutdownModule() override;
};
#pragma once

#include "Modules/ModuleManager.h"
#include "CoreMinimal.h"

class FMoreLightingOptionsModule : public IModuleInterface {
public:
virtual void StartupModule() override;
virtual void ShutdownModule() override;
};
Rex
Rex•3mo ago
.h looks fine
Beef
BeefOP•3mo ago
MoreLightingOptions.Build.cs
using UnrealBuildTool;

public class MoreLightingOptions : ModuleRules
{
public MoreLightingOptions(ReadOnlyTargetRules Target) : base(Target)
{
DefaultBuildSettings = BuildSettingsVersion.Latest;
ShadowVariableWarningLevel = WarningLevel.Error;
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
bLegacyParentIncludePaths = false;
CppStandard = CppStandardVersion.Cpp20;
bUseUnity = false;

PublicDependencyModuleNames.AddRange(new string[] {
"Core", "CoreUObject", "Engine",
"DeveloperSettings", "PhysicsCore", "InputCore",
"AssetRegistry", "RenderCore", "RHI",
"SlateCore", "Slate", "UMG", "GameplayTags",
"DummyHeaders", "FactoryGame", "SML",
});
}
}
using UnrealBuildTool;

public class MoreLightingOptions : ModuleRules
{
public MoreLightingOptions(ReadOnlyTargetRules Target) : base(Target)
{
DefaultBuildSettings = BuildSettingsVersion.Latest;
ShadowVariableWarningLevel = WarningLevel.Error;
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
bLegacyParentIncludePaths = false;
CppStandard = CppStandardVersion.Cpp20;
bUseUnity = false;

PublicDependencyModuleNames.AddRange(new string[] {
"Core", "CoreUObject", "Engine",
"DeveloperSettings", "PhysicsCore", "InputCore",
"AssetRegistry", "RenderCore", "RHI",
"SlateCore", "Slate", "UMG", "GameplayTags",
"DummyHeaders", "FactoryGame", "SML",
});
}
}
it's a pretty barebones mod for now while I wrap my head around everything, I feel there isn't much that can go wrong
Rex
Rex•3mo ago
That looks like it's based on Th3SwiftSwim?
Beef
BeefOP•3mo ago
That's correct, I restructured it to mirror that general construction
Rex
Rex•3mo ago
I think pretty much no one else sets bUseUnity = false;
Beef
BeefOP•3mo ago
the one thing that's missing is a proper state check, but there isn't much exposed in that header file
Rex
Rex•3mo ago
That's why I knew Okay, I can reproduce
Beef
BeefOP•3mo ago
Oh wow I didn't realize the cpp file was available in SML, that may help some - i thought I only had access to the header files
Rex
Rex•3mo ago
Which CPP file?
Beef
BeefOP•3mo ago
FGBuildableWidgetSign.cpp
Rex
Rex•3mo ago
That's just stubs
Beef
BeefOP•3mo ago
I think its just function definitions, but it at least has returns
Rex
Rex•3mo ago
Courtesy of Ghidra:
float __thiscall AFGBuildableWidgetSign::GetAdjustedEmissiveValue(AFGBuildableWidgetSign *this, int Level)
{
/* 0x489fd0 16593 ?GetAdjustedEmissiveValue@AFGBuildableWidgetSign@@UEBAMH@Z */
if (Level != 0) {
if (Level == 1) {
return 1.0;
}
if (Level == 2) {
return 5.0;
}
if (Level == 3) {
return 10.0;
}
}
return 0.0;
}
float __thiscall AFGBuildableWidgetSign::GetAdjustedEmissiveValue(AFGBuildableWidgetSign *this, int Level)
{
/* 0x489fd0 16593 ?GetAdjustedEmissiveValue@AFGBuildableWidgetSign@@UEBAMH@Z */
if (Level != 0) {
if (Level == 1) {
return 1.0;
}
if (Level == 2) {
return 5.0;
}
if (Level == 3) {
return 10.0;
}
}
return 0.0;
}
Beef
BeefOP•3mo ago
setting up a case system rather than a multiplier seems to function
Rex
Rex•3mo ago
I did something
class HFGBuildableWidgetSign
{
public:
static float GetAdjustedEmissiveValue_Orig(int32 Level)
{
switch (Level) {
case 3:
return 10.0;
case 2:
return 5.0;
case 1:
return 1.0;
case 0:
default:
return 0.0;
}
}

static void Hook_GetAdjustedEmissiveValue(TCallScope<float(__cdecl*)(const AFGBuildableWidgetSign*, int32)>& scope, const AFGBuildableWidgetSign* self, int32 Level)
{
scope.Override(GetAdjustedEmissiveValue_Orig(Level) * 10);
}

static void RegisterHooks()
{
SUBSCRIBE_UOBJECT_METHOD(AFGBuildableWidgetSign, GetAdjustedEmissiveValue, &HFGBuildableWidgetSign::Hook_GetAdjustedEmissiveValue);
}
};
class HFGBuildableWidgetSign
{
public:
static float GetAdjustedEmissiveValue_Orig(int32 Level)
{
switch (Level) {
case 3:
return 10.0;
case 2:
return 5.0;
case 1:
return 1.0;
case 0:
default:
return 0.0;
}
}

static void Hook_GetAdjustedEmissiveValue(TCallScope<float(__cdecl*)(const AFGBuildableWidgetSign*, int32)>& scope, const AFGBuildableWidgetSign* self, int32 Level)
{
scope.Override(GetAdjustedEmissiveValue_Orig(Level) * 10);
}

static void RegisterHooks()
{
SUBSCRIBE_UOBJECT_METHOD(AFGBuildableWidgetSign, GetAdjustedEmissiveValue, &HFGBuildableWidgetSign::Hook_GetAdjustedEmissiveValue);
}
};
Problem is that calling the original function didn't seem to work
Solution
Beef
Beef•3mo ago
float NewEmissiveValue = 0.0f;
switch (Level)
{
case 0:
NewEmissiveValue = 0.0f;
break;
case 1:
NewEmissiveValue = 5.0f;
break;
case 2:
NewEmissiveValue = 50.0f;
break;
case 3:
NewEmissiveValue = 500.0f;
break;
}
scope.Override(NewEmissiveValue);
float NewEmissiveValue = 0.0f;
switch (Level)
{
case 0:
NewEmissiveValue = 0.0f;
break;
case 1:
NewEmissiveValue = 5.0f;
break;
case 2:
NewEmissiveValue = 50.0f;
break;
case 3:
NewEmissiveValue = 500.0f;
break;
}
scope.Override(NewEmissiveValue);
is what I did, so basically the same
Rex
Rex•3mo ago
I like not using mutable variables 😄 cc @Mircea (Area Actions) any idea why hooking AFGBuildableWidgetSign::GetAdjustedEmissiveValue and trying to call the original would fail?
Beef
BeefOP•3mo ago
it's bright
No description
Beef
BeefOP•3mo ago
thanks for your help 🙂 Now I'm off to add some mod options, which I think will be easier on the blueprint side. I just have to figure out how to access those from cpp
Rex
Rex•3mo ago
Be warned: accessing options from hooks is a pain
Beef
BeefOP•3mo ago
Where there's a will there's a way ... eventually

Did you find this page helpful?