Skip to content

Conversation

@RunnerScrab
Copy link
Contributor

This will fix native method binding in Starfield v1.15.222. GetStackFrameVariable and GetPageForFrame had relocated in memory, and GetStackFrameVariable now only takes 3 arguments.

To call IVirtualMachine::BindNativeMethod(), you must still obtain a valid pointer to IVirtualMachine, which cannot be done using Game::GetVM() as that function does not work. To get a valid IVirtualMachine*, you can use a hook like this:

RE::BSScript::IVirtualMachine* g_pvm = 0;

void GetBindEverythingToScriptArg(RE::BSScript::IVirtualMachine** a_vm)
{
	REX::INFO("GetBindEverythingToScriptArg called!");
	if (a_vm && *a_vm)
	{
		REX::INFO("Storing intercepted IVirtualMachine pointer.");
		g_pvm = *a_vm;
		g_pvm->IncRef();
	}
	else
		REX::INFO("No valid pointer to IVirtualMachine?");

	using func_t = decltype(&GetBindEverythingToScriptArg);
	static REL::Relocation<func_t> func{ RE::ID::GameVM::BindEverythingToScript };
	return func(a_vm);
}

inline static REL::Hook Hook0{ REL::ID(116472), 0x802, GetBindEverythingToScriptArg };

@qudix
Copy link
Contributor

qudix commented Oct 25, 2025

I think I see what happened here, this address id you found is actually for BSScript::StackFrame::GetVariable:

[[nodiscard]] Variable& GetStackFrameVariable(std::uint32_t a_index, std::uint32_t a_pageHint) const

The Stack version of the function was indeed inlined, so that needs to be removed and we should rename the StackFrame version to GetVariable and change it to use the id you found:

[[nodiscard]] Variable& GetVariable(std::uint32_t a_index, std::uint32_t a_pageHint) const
{
	using func_t = decltype(&StackFrame::GetVariable);
	static REL::Relocation<func_t> func{ ID::BSScript::StackFrame::GetVariable };
	return func(this, a_index, a_pageHint);
}

@RunnerScrab
Copy link
Contributor Author

RunnerScrab commented Oct 26, 2025

Updated so that the actual relocation is for StackFrame::GetVariable() instead of Stack::GetStackFrameVariable(), and also to use StackFrame::GetVariable() instead in BSScriptUtil::Detail::DispatchHelper. Bound functions still seem to work!

(Sorry for the 5 commits + squashing. My git is a little rusty)

Remove extraneous newlines
Fix native method binding
Make the relocation for StackFrame::GetVariable instead
Remove unused function readded by stash/checkout
@RunnerScrab RunnerScrab force-pushed the RunnerScrab_FixNativeMethodBinding branch from b7f7ecc to c61624b Compare October 26, 2025 00:35
@qudix
Copy link
Contributor

qudix commented Oct 26, 2025

I know why ci is failing, so ignore that. As for GetVM, I think that is failing because the GameVM class likely had member variables added or removed, causing this:

BSTSmartPointer<BSScript::IVirtualMachine> impl; // 00D8

to be pointing to the wrong memory.

I'll merge this and we can look at that next.

@qudix qudix merged commit c5ca4d1 into libxse:main Oct 26, 2025
0 of 2 checks passed
@RunnerScrab RunnerScrab deleted the RunnerScrab_FixNativeMethodBinding branch October 26, 2025 05:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants