Skip to content

Commit

Permalink
Fixes negative numbers transfer (Papyrus => Scaleform) bug
Browse files Browse the repository at this point in the history
  • Loading branch information
Odie committed Nov 17, 2021
1 parent 5ff6271 commit 8f1e523
Show file tree
Hide file tree
Showing 6 changed files with 270 additions and 4 deletions.
7 changes: 7 additions & 0 deletions sksevr_plugin/plugin/Globals.h
@@ -0,0 +1,7 @@
#pragma once
#include "skse64/PluginAPI.h"
extern PluginHandle g_pluginHandle;
extern SKSEPapyrusInterface* g_papyrus;
extern SKSEScaleformInterface* g_scaleform;
extern SKSETaskInterface* g_SkseTaskInterface;
extern SKSEObjectInterface* g_SkseObjectInterface;
196 changes: 196 additions & 0 deletions sksevr_plugin/plugin/PapyrusUIFix.cpp
@@ -0,0 +1,196 @@
#include "PapyrusUIFix.h"

#include "skse64/GameMenus.h"
#include "skse64/ScaleformCallbacks.h"
#include "skse64/ScaleformMovie.h"
#include "skse64/PapyrusNativeFunctions.h"

#include "skse64/PapyrusUI.h"
#include "skse64/Hooks_UI.h"
#include "skse64/Serialization.h"

#include "Globals.h"

namespace PapyrusUIFix
{
template <typename T> void SetGFxValue(GFxValue* val, T arg);
template <> void SetGFxValue<bool>(GFxValue* val, bool arg) { val->SetBool(arg); }
template <> void SetGFxValue<float>(GFxValue* val, float arg) { val->SetNumber(arg); }

// Disabled so we don't accidentally use this
//template <> void SetGFxValue<UInt32>(GFxValue* val, UInt32 arg) { val->SetNumber(arg); }

template <> void SetGFxValue<SInt32>(GFxValue* val, SInt32 arg) { val->SetNumber(arg); }
template <> void SetGFxValue<BSFixedString>(GFxValue* val, BSFixedString arg)
{
// lifetime of this string will not be managed by the scaleform runtime
val->SetString(arg.data);
}

class UIInvokeDelegate : public UIDelegate_v1, public ISKSEObject
{
public:
UIInvokeDelegate(const char* nameBuf, const char* targetBuf) :
menuName_(nameBuf),
target_(targetBuf)
{}

explicit UIInvokeDelegate(SerializationTag tag) {

}

virtual const char* ClassName() const { return "SkyUI-UIInvokeDelegate"; }
virtual UInt32 ClassVersion() const { return 1; }

virtual void Run() override
{
MenuManager* mm = MenuManager::GetSingleton();
if (!mm)
return;

BSFixedString t(menuName_.c_str());
GFxMovieView* view = mm->GetMovieView(&t);
if (!view)
return;

GFxValue* value = NULL;
if (args.size() > 0)
value = &args[0];

view->Invoke(target_.c_str(), NULL, value, args.size());
}
virtual void Dispose() override
{
delete this;
}

virtual bool Save(SKSESerializationInterface* intfc)
{
using namespace Serialization;

if (!WriteData(intfc, &menuName_))
return false;

if (!WriteData(intfc, &target_))
return false;

if (!WriteData(intfc, &type_))
return false;

if (!WriteData(intfc, &handle_))
return false;

return true;
}

virtual bool Load(SKSESerializationInterface* intfc, UInt32 version)
{
using namespace Serialization;

if (!ReadData(intfc, &menuName_))
return false;

if (!ReadData(intfc, &target_))
return false;

if (!ReadData(intfc, &type_))
return false;

if (!ReadData(intfc, &handle_))
return false;

UInt64 fixedHandle;
if (intfc->ResolveHandle(handle_, &fixedHandle))
handle_ = fixedHandle;

return true;
}


std::vector<GFxValue> args;

private:
std::string menuName_;
std::string target_;

UInt32 type_;
UInt64 handle_;
};

template <typename T>
void SetT(StaticFunctionTag* thisInput, BSFixedString menuName, BSFixedString targetStr, T value)
{
if (!menuName.data || !targetStr.data)
return;

MenuManager* mm = MenuManager::GetSingleton();
if (!mm)
return;

GFxMovieView* view = mm->GetMovieView(&menuName);
if (!view)
return;

GFxValue fxValue;
PapyrusUIFix::SetGFxValue<T>(&fxValue, value);

view->SetVariable(targetStr.data, &fxValue, 1);
}

template <typename T>
void InvokeArgT(StaticFunctionTag* thisInput, BSFixedString menuName, BSFixedString targetStr, T arg)
{
if (!menuName.data || !targetStr.data)
return;

if (!g_SkseTaskInterface)
return;

UIInvokeDelegate* cmd = new UIInvokeDelegate(menuName.data, targetStr.data);

cmd->args.resize(1);
PapyrusUIFix::SetGFxValue<T>(&cmd->args[0], arg);

g_SkseTaskInterface->AddUITask(cmd);
}

template <typename T>
void InvokeArrayT(StaticFunctionTag* thisInput, BSFixedString menuName, BSFixedString targetStr, VMArray<T> args)
{
if (!menuName.data || !targetStr.data)
return;

if (!g_SkseTaskInterface)
return;

UInt32 argCount = args.Length();

UIInvokeDelegate* cmd = new UIInvokeDelegate(menuName.data, targetStr.data);

cmd->args.resize(argCount);
for (UInt32 i = 0; i < argCount; i++)
{
T arg;
args.Get(&arg, i);
PapyrusUIFix::SetGFxValue<T>(&cmd->args[i], arg);
}

g_SkseTaskInterface->AddUITask(cmd);
}

bool RegisterPapyrusFuncs(VMClassRegistry* registry) {
SKSEObjectRegistry& objectRegistry = g_SkseObjectInterface->GetObjectRegistry();
objectRegistry.RegisterClass<UIInvokeDelegate>();

registry->RegisterFunction(
new NativeFunction3 <StaticFunctionTag, void, BSFixedString, BSFixedString, SInt32>("SetInt", "UI", SetT<SInt32>, registry));

registry->RegisterFunction(
new NativeFunction3 <StaticFunctionTag, void, BSFixedString, BSFixedString, SInt32>("InvokeInt", "UI", InvokeArgT<SInt32>, registry));

registry->RegisterFunction(
new NativeFunction3 <StaticFunctionTag, void, BSFixedString, BSFixedString, VMArray<SInt32>>("InvokeIntA", "UI", InvokeArrayT<SInt32>, registry));

return true;
}
}
8 changes: 8 additions & 0 deletions sksevr_plugin/plugin/PapyrusUIFix.h
@@ -0,0 +1,8 @@
#pragma once

#include "skse64/PapyrusObjects.h"

namespace PapyrusUIFix
{
bool RegisterPapyrusFuncs(VMClassRegistry* registry);
}
23 changes: 19 additions & 4 deletions sksevr_plugin/plugin/main.cpp
Expand Up @@ -3,14 +3,20 @@
#include <shlobj.h> // CSIDL_MYCODUMENTS

#include "FormDB.h"
#include "ScaleformExtendedDataFix.h"
#include "Keyboard.h"
#include "ControllerStateHook.h"
#include "Settings.h"

static PluginHandle g_pluginHandle = kPluginHandle_Invalid;
static SKSEPapyrusInterface* g_papyrus = nullptr;
static SKSEScaleformInterface* g_scaleform = nullptr;
// SKSE patches
#include "ScaleformExtendedDataFix.h"
#include "PapyrusUIFix.h"
#include "skse64/Hooks_UI.h"

PluginHandle g_pluginHandle = kPluginHandle_Invalid;
SKSEPapyrusInterface* g_papyrus = nullptr;
SKSEScaleformInterface* g_scaleform = nullptr;
SKSETaskInterface* g_SkseTaskInterface = nullptr;
SKSEObjectInterface* g_SkseObjectInterface = nullptr;

void WaitForDebugger(bool should_break = false) {
while (!IsDebuggerPresent())
Expand Down Expand Up @@ -61,9 +67,15 @@ extern "C" {
// We're storing all our data in lua
FormDB::InitGlobalLuaVM();

// Setup pointers to various SKSE interfaces
// Parts of the program may need to access these sparatically.
g_SkseTaskInterface = (SKSETaskInterface*)skse->QueryInterface(kInterface_Task);
g_SkseObjectInterface = (SKSEObjectInterface*)skse->QueryInterface(kInterface_Object);

// Register additional Papyrus functions
g_papyrus = (SKSEPapyrusInterface *)skse->QueryInterface(kInterface_Papyrus);
g_papyrus->Register(FormDB::RegisterPapyrusFuncs); // Expose FormDB lua functions to Papyrus
g_papyrus->Register(PapyrusUIFix::RegisterPapyrusFuncs); // Fix Papyrus=>SKSE=>Scaleform SInt32 conversion bug

// Register Inventory item hooks
g_scaleform = (SKSEScaleformInterface*)skse->QueryInterface(kInterface_Scaleform);
Expand All @@ -82,6 +94,9 @@ extern "C" {
// Start receiving constroller state updates
ControllerStateHook::Init();




_MESSAGE("Plugin loaded");

return true;
Expand Down
3 changes: 3 additions & 0 deletions sksevr_plugin/plugin/plugin.vcxproj
Expand Up @@ -144,8 +144,10 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="ControllerStateHook.h" />
<ClInclude Include="Globals.h" />
<ClInclude Include="Keyboard.h" />
<ClInclude Include="FormDB.h" />
<ClInclude Include="PapyrusUIFix.h" />
<ClInclude Include="ScaleformExtendedDataFix.h" />
<ClInclude Include="Settings.h" />
</ItemGroup>
Expand All @@ -154,6 +156,7 @@
<ClCompile Include="Keyboard.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="FormDB.cpp" />
<ClCompile Include="PapyrusUIFix.cpp" />
<ClCompile Include="ScaleformExtendedDataFix.cpp" />
<ClCompile Include="Settings.cpp" />
</ItemGroup>
Expand Down
37 changes: 37 additions & 0 deletions sksevr_plugin/plugin/plugin.vcxproj.filters
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="main.cpp" />
<ClCompile Include="ScaleformExtendedDataFix.cpp">
<Filter>SKSE Patches</Filter>
</ClCompile>
<ClCompile Include="ControllerStateHook.cpp" />
<ClCompile Include="Keyboard.cpp" />
<ClCompile Include="FormDB.cpp" />
<ClCompile Include="Settings.cpp" />
<ClCompile Include="PapyrusUIFix.cpp">
<Filter>SKSE Patches</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ScaleformExtendedDataFix.h">
<Filter>SKSE Patches</Filter>
</ClInclude>
<ClInclude Include="ControllerStateHook.h" />
<ClInclude Include="Keyboard.h" />
<ClInclude Include="FormDB.h" />
<ClInclude Include="Settings.h" />
<ClInclude Include="PapyrusUIFix.h">
<Filter>SKSE Patches</Filter>
</ClInclude>
<ClInclude Include="Globals.h" />
</ItemGroup>
<ItemGroup>
<None Include="exports.def" />
</ItemGroup>
<ItemGroup>
<Filter Include="SKSE Patches">
<UniqueIdentifier>{6d3ec361-f98a-4172-b913-8e3f183dad14}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>

0 comments on commit 8f1e523

Please sign in to comment.