From d6e8d35d712edfaf15e3eb1c0425e44359fbb546 Mon Sep 17 00:00:00 2001 From: jekky <11986158+jac3km4@users.noreply.github.com> Date: Wed, 13 Dec 2023 04:20:37 +0000 Subject: [PATCH] feat: add requirements for script validation --- include/RED4ext/Addresses.hpp | 4 + .../RED4ext/Scripting/ScriptReport-inl.hpp | 79 +++++++++++++++++++ include/RED4ext/Scripting/ScriptReport.hpp | 36 +++++++++ src/Scripting/ScriptReport.cpp | 5 ++ 4 files changed, 124 insertions(+) create mode 100644 include/RED4ext/Scripting/ScriptReport-inl.hpp create mode 100644 include/RED4ext/Scripting/ScriptReport.hpp create mode 100644 src/Scripting/ScriptReport.cpp diff --git a/include/RED4ext/Addresses.hpp b/include/RED4ext/Addresses.hpp index 5c51129c7..a254b1d6b 100644 --- a/include/RED4ext/Addresses.hpp +++ b/include/RED4ext/Addresses.hpp @@ -201,5 +201,9 @@ constexpr uintptr_t TweakDB_CreateRecord = 0x1401D50D0 - ImageBase; // 48 89 5C constexpr uintptr_t UpdateRegistrar_RegisterGroupUpdate = 0x1407FC05C - ImageBase; // 48 8B C4 48 89 58 08 48 89 70 10 48 89 78 18 55 41 56 41 57 48 8D 68 B1 48 81 EC D0 00 00 00 48 8B 7D 77 49 8B D9, expected: 1, index: 0 constexpr uintptr_t UpdateRegistrar_RegisterBucketUpdate = 0x1407FBF0C - ImageBase; // 48 8B C4 48 89 58 08 48 89 70 10 48 89 78 18 55 41 56 41 57 48 8D 68 B9 48 81 EC D0 00 00 00 48 8B 7D 77 49 8B D9, expected: 1, index: 0 #pragma endregion + +#pragma region ScriptValidator +constexpr uintptr_t ScriptValidator_Validate = 0x14060FC3C - ImageBase; // 48 89 5C 24 ? 48 89 4C 24 ? 55 56 57 41 54 41 55 41 56 41 57 48 8D 6C 24 ? 48 81 EC ? ? ? ? 48 8B C2, expected: 1, index: 0 +#pragma endregion } // namespace RED4ext::Addresses // clang-format on diff --git a/include/RED4ext/Scripting/ScriptReport-inl.hpp b/include/RED4ext/Scripting/ScriptReport-inl.hpp new file mode 100644 index 000000000..81d761f1e --- /dev/null +++ b/include/RED4ext/Scripting/ScriptReport-inl.hpp @@ -0,0 +1,79 @@ +#pragma once + +#ifdef RED4EXT_STATIC_LIB +#include +#endif + +#include + +RED4EXT_INLINE RED4ext::ScriptReport::ScriptReport() noexcept + : errors(&unk10) + , maxErrors(0) + , fillErrors(true) +{ +} + +RED4EXT_INLINE RED4ext::ScriptReport::ScriptReport(RED4ext::DynArray& aErrors, uint32_t aMaxErrors) noexcept + : errors(&aErrors) + , maxErrors(aMaxErrors) + , fillErrors(true) +{ +} + +RED4EXT_INLINE void RED4ext::ScriptReport::AddValidationError(const char* aFormat, ...) +{ + if (errors && fillErrors) + { + std::va_list args; + va_start(args, aFormat); + errors->PushBack(Format(aFormat, args)); + va_end(args); + } +} + +RED4EXT_INLINE void RED4ext::ScriptReport::AddBindingError(const char* aFormat, ...) +{ + if (errors && fillErrors) + { + std::va_list args; + va_start(args, aFormat); + errors->PushBack(Format(aFormat, args)); + va_end(args); + } +} + +RED4EXT_INLINE [[nodiscard]] bool RED4ext::ScriptReport::HasErrors() const noexcept +{ + return errors && errors->size > 0; +} + +RED4EXT_INLINE [[nodiscard]] RED4ext::CString RED4ext::ScriptReport::ToString() const noexcept +{ + if (!errors || errors->size == 0) + { + return {}; + } + + std::string str; + bool eol = false; + + for (const auto& error : *errors) + { + if (eol) + { + str.append("\n"); + } + + str.append(error.c_str()); + eol = true; + } + + return str.c_str(); +} + +RED4EXT_INLINE RED4ext::CString RED4ext::ScriptReport::Format(const char* aFormat, std::va_list aArgs) +{ + char buffer[4096]; + vsnprintf(buffer, sizeof(buffer), aFormat, aArgs); + return buffer; +} diff --git a/include/RED4ext/Scripting/ScriptReport.hpp b/include/RED4ext/Scripting/ScriptReport.hpp new file mode 100644 index 000000000..344713c09 --- /dev/null +++ b/include/RED4ext/Scripting/ScriptReport.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include + +namespace RED4ext +{ +struct ScriptReport +{ + ScriptReport() noexcept; + + ScriptReport(DynArray& aErrors, uint32_t aMaxErrors = 0) noexcept; + + virtual ~ScriptReport() = default; + + virtual void AddValidationError(const char* aFormat, ...); + + virtual void AddBindingError(const char* aFormat, ...); + + [[nodiscard]] bool HasErrors() const noexcept; + + [[nodiscard]] CString ToString() const noexcept; + + static CString Format(const char* aFormat, std::va_list aArgs); + + bool fillErrors; // 08 - Usually equals to CBaseEngine::scriptsSilentValidation + DynArray unk10; // 10 - Seems to be unused by the game + DynArray* errors; // 20 - Usually points to CBaseEngine::scriptsValidationErrors + uint32_t maxErrors; // 28 +}; +RED4EXT_ASSERT_SIZE(ScriptReport, 0x30); +RED4EXT_ASSERT_OFFSET(ScriptReport, fillErrors, 0x08); +RED4EXT_ASSERT_OFFSET(ScriptReport, errors, 0x20); +RED4EXT_ASSERT_OFFSET(ScriptReport, maxErrors, 0x28); +} // namespace RED4ext diff --git a/src/Scripting/ScriptReport.cpp b/src/Scripting/ScriptReport.cpp new file mode 100644 index 000000000..3c710ec9d --- /dev/null +++ b/src/Scripting/ScriptReport.cpp @@ -0,0 +1,5 @@ +#ifndef RED4EXT_STATIC_LIB +#error Please define 'RED4EXT_STATIC_LIB' to compile this file. +#endif + +#include