#pragma once #include #include struct BSScript { struct Object { uint64_t GetHandle(); }; struct Variable { Variable(); ~Variable() noexcept; void Reset() noexcept; void Clear() noexcept; Object* GetObject() const noexcept; template void Set(T aValue) noexcept { // static_assert(false); } template T* ExtractComplexType() noexcept; enum Type : uint64_t { kEmpty, kObject, kString, kInteger, kFloat, kBoolean, kMax = 16 }; union Data { int32_t i; const char* s; float f; bool b; Object* pObj; }; Type type; Data data; }; // https://github.com/Ryan-rsm-McKenzie/CommonLibSSE/blob/master/include/RE/I/IFunction.h enum class FunctionType { kNormal = 0, kGetter = 1, kSetter = 2 }; enum class CallResult { kCompleted = 0, kSetupForVM = 1, kInProgress = 2, kFailedRetry = 3, kFailedAbort = 4 }; struct StackFrame; struct Stack; struct IVirtualMachine; struct IFunction : BSIntrusiveRefCounted { virtual ~IFunction() = default; virtual BSFixedString& GetName() = 0; virtual BSFixedString& GetObjectTypeName() = 0; virtual BSFixedString& GetStateName() = 0; virtual Variable::Type& GetReturnType() = 0; virtual uint32_t GetParamCount() = 0; virtual void GetParam(uint32_t aIndex, BSFixedString& apNameOut, Variable::Type& apTypeOut) = 0; virtual uint32_t GetStackFrameSize() = 0; virtual bool GetIsNative() = 0; virtual bool GetIsStatic() = 0; virtual bool GetIsEmpty() = 0; virtual FunctionType GetFunctionType() = 0; virtual uint32_t GetUserFlags() = 0; virtual BSFixedString& GetDocString() = 0; virtual void InsertLocals(StackFrame* apFrame) = 0; // TODO: is actually GameVM virtual CallResult Call(Stack* apStack, void* apLogger, IVirtualMachine* apVm, bool aArg4) = 0; virtual BSFixedString& GetSourceFilename() = 0; virtual bool TranslateIPToLineNumber(uint32_t aIndexPtr, uint32_t& aLineNumberOut) = 0; virtual bool GetVarNameForStackIndex(uint32_t aIndex, BSFixedString& aNameOut) = 0; virtual bool CanBeCalledFromTasklets() = 0; virtual void SetCallableFromTasklets(bool aCallable) = 0; }; struct IFunctionArguments { struct Statement { void SetSize(uint32_t aCount) noexcept; uint8_t pad0[8]; Variable* vars; }; virtual ~IFunctionArguments() {} virtual void Prepare(Statement* apUnk) noexcept = 0; }; struct Stack { uint32_t GetPageForFrame(StackFrame* apFrame) { TP_THIS_FUNCTION(TGetPageForFrame, uint32_t, Stack, StackFrame*); POINTER_SKYRIMSE(TGetPageForFrame, getPageForFrame, 104483); return TiltedPhoques::ThisCall(getPageForFrame, this, apFrame); } Variable* GetStackFrameVariable(StackFrame* apFrame, uint32_t aIndex, uint32_t aPageHint) { TP_THIS_FUNCTION(TGetStackFrameVariable, Variable*, Stack, StackFrame*, uint32_t, uint32_t); POINTER_SKYRIMSE(TGetStackFrameVariable, getStackFrameVariable, 104484); return TiltedPhoques::ThisCall(getStackFrameVariable, this, apFrame, aIndex, aPageHint); } }; struct StackFrame { uint32_t GetPageForFrame() { return pParent->GetPageForFrame(this); } Variable* GetStackFrameVariable(uint32_t aIndex, uint32_t aPageHint) { return pParent->GetStackFrameVariable(this, aIndex, aPageHint); } Stack* pParent; }; struct IObjectHandlePolicy { static IObjectHandlePolicy* Get() noexcept; virtual ~IObjectHandlePolicy(); virtual bool HandleIsType(uint32_t aType, uint64_t aHandle); virtual bool IsHandleObjectAvailable(uint64_t aHandle); virtual void sub_03(); virtual void sub_04(); virtual void sub_05(); virtual void sub_06(); virtual void sub_07(); virtual void* GetObjectForHandle(uint32_t aType, uint64_t aHandle); template T* GetObjectForHandle(uint64_t aHandle) { return (T*)(BSScript::IObjectHandlePolicy::Get()->GetObjectForHandle((uint32_t)T::Type, aHandle)); } }; struct IVirtualMachine { virtual ~IVirtualMachine() = 0; virtual void sub_01(); virtual void sub_02(); virtual void sub_03(); virtual void sub_04(); virtual void sub_05(); virtual void sub_06(); virtual void sub_07(); virtual void sub_08(); virtual void GetScriptObjectType1(BSFixedString* apClassName, void** apOutTypeInfoPtr); virtual void sub_0A(); virtual void sub_0B(); virtual void sub_0C(); virtual void sub_0D(); virtual void sub_0E(); virtual void sub_0F(); virtual void sub_10(); virtual void sub_11(); virtual void sub_12(); virtual void sub_13(); virtual void sub_14(); virtual void sub_15(); virtual void sub_16(); virtual void sub_17(); virtual void BindNativeMethod(IFunction* apFunction); virtual void sub_19(); virtual void sub_1A(); virtual void sub_1B(); virtual void sub_1C(); virtual void sub_1D(); virtual void sub_1E(); virtual void sub_1F(); virtual void sub_20(); virtual void sub_21(); virtual void sub_22(); virtual void sub_23(); virtual void SendEvent(uint64_t aId, const BSFixedString& acEventName, IFunctionArguments* apArgs) const noexcept; virtual void sub_25(); virtual void sub_26(); virtual void sub_27(); virtual void sub_28(); virtual void sub_29(); virtual void sub_2A(); virtual void sub_2B(); virtual void sub_2C(); virtual IObjectHandlePolicy* GetObjectHandlePolicy(); }; struct NativeFunctionBase : IFunction { BSFixedString& GetName() override; BSFixedString& GetObjectTypeName() override; BSFixedString& GetStateName() override; Variable::Type& GetReturnType() override; std::uint32_t GetParamCount() override; void GetParam(uint32_t aIndex, BSFixedString& apNameOut, Variable::Type& a_typeOut) override; uint32_t GetStackFrameSize() override; bool GetIsNative() override; bool GetIsStatic() override; bool GetIsEmpty() override; FunctionType GetFunctionType() override; std::uint32_t GetUserFlags() override; BSFixedString& GetDocString() override; void InsertLocals(StackFrame* apFrame) override; CallResult Call(Stack* apStack, void* apLogger, IVirtualMachine* apVm, bool aArg4) override; BSFixedString& GetSourceFilename() override; bool TranslateIPToLineNumber(uint32_t aTaskletExecutionOffset, uint32_t& aLineNumberOut) override; bool GetVarNameForStackIndex(uint32_t aIndex, BSFixedString& aNameOut) override; bool CanBeCalledFromTasklets() override; void SetCallableFromTasklets(bool aCallable) override; virtual bool HasCallback() { return false; } virtual bool MarshallAndDispatch(Variable* apBaseVar, IVirtualMachine* apVm, uint32_t aStackID, Variable* apResult, StackFrame* apStackFrame) { return false; } struct Parameters { struct Entry { const char* name; union { Variable::Type type; void* pType; }; }; Entry* data; uint16_t size; uint16_t capacity; }; BSFixedString name; BSFixedString objectName; BSFixedString stateName; Variable::Type returnType; Parameters parameters; bool isStatic; bool isCallableFromTask; bool isLatent; uint8_t pad43; uint32_t flags; BSFixedString documentation; }; static_assert(sizeof(NativeFunctionBase) == 0x50); struct NativeFunction : NativeFunctionBase { virtual ~NativeFunction() { TP_THIS_FUNCTION(TNativeFunctionDtor, void, NativeFunction); // TODO: not sure about this address POINTER_SKYRIMSE(TNativeFunctionDtor, dtor, 104655); TiltedPhoques::ThisCall(dtor, this); } NativeFunction(const char* apFunctionName, const char* apClassName, bool aIsStatic, uint32_t aParameterCount) { TP_THIS_FUNCTION(TNativeFunctionCtor, void, NativeFunction, const char*, const char*, bool, uint32_t); POINTER_SKYRIMSE(TNativeFunctionCtor, ctor, 104653); TiltedPhoques::ThisCall(ctor, this, apFunctionName, apClassName, aIsStatic, aParameterCount); } bool HasCallback() override { return pFunction != nullptr; } void* pFunction; }; // TODO: template stuff for a cleaner implementation // https://github.com/Ryan-rsm-McKenzie/CommonLibSSE/blob/master/include/RE/N/NativeFunction.h struct IsRemotePlayerFunc : NativeFunction { using FunctionType = bool(Actor* pBase); IsRemotePlayerFunc(const char* apFunctionName, const char* apClassName, FunctionType aFunction, Variable::Type aType); bool MarshallAndDispatch(Variable* apBaseVar, IVirtualMachine* apVm, uint32_t aStackID, Variable* apResult, StackFrame* apStackFrame) override; }; struct IsPlayerFunc : NativeFunction { using FunctionType = bool(Actor* pBase); IsPlayerFunc(const char* apFunctionName, const char* apClassName, FunctionType aFunction, Variable::Type aType); bool MarshallAndDispatch(Variable* apBaseVar, IVirtualMachine* apVm, uint32_t aStackID, Variable* apResult, StackFrame* apStackFrame) override; }; struct DidLaunchSkyrimTogetherFunc : NativeFunction { using FunctionType = bool(); DidLaunchSkyrimTogetherFunc(const char* apFunctionName, const char* apClassName, FunctionType aFunction, Variable::Type aType); bool MarshallAndDispatch(Variable* apBaseVar, IVirtualMachine* apVm, uint32_t aStackID, Variable* apResult, StackFrame* apStackFrame) override; }; // Bad PoC code #if 0 template struct EventArguments : IFunctionArguments { using Tuple = std::tuple; EventArguments(T... args) : args(std::forward(args)...) { } virtual ~EventArguments(){}; virtual void Prepare(IFunctionArguments::Statement* apStatement) noexcept { apStatement->SetSize(std::tuple_size_v>); PrepareImplementation(apStatement, std::make_index_sequence>>{}); } private: template void PrepareImplementation(IFunctionArguments::Statement* apStatement, std::index_sequence) noexcept { ((apStatement->vars[Is].Set(std::get(args))), ...); } Tuple args; }; #endif }; template <> void BSScript::Variable::Set(int32_t aValue) noexcept; template <> void BSScript::Variable::Set(float aValue) noexcept; template <> void BSScript::Variable::Set(bool aValue) noexcept; template <> void BSScript::Variable::Set(const char* acpValue) noexcept;