Skip to content

Commit

Permalink
Register stat types
Browse files Browse the repository at this point in the history
  • Loading branch information
psiberx committed Aug 4, 2023
1 parent a34758b commit c51ca7a
Show file tree
Hide file tree
Showing 10 changed files with 205 additions and 3 deletions.
2 changes: 2 additions & 0 deletions src/App/Application.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "Application.hpp"
#include "App/Environment.hpp"
#include "App/Stats/StatService.hpp"
#include "App/Tweaks/TweakService.hpp"
#include "Core/Foundation/RuntimeProvider.hpp"
#include "Support/MinHook/MinHookProvider.hpp"
Expand All @@ -15,4 +16,5 @@ App::Application::Application(HMODULE aHandle, const RED4ext::Sdk*)
Register<Support::RedLibProvider>();

Register<App::TweakService>(Env::GameDir(), Env::TweaksDir());
Register<App::StatService>();
}
97 changes: 97 additions & 0 deletions src/App/Stats/StatService.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#include "StatService.hpp"
#include "App/Tweaks/TweakService.hpp"
#include "Core/Facades/Container.hpp"

namespace
{
constexpr auto BaseStatPrefix = "BaseStats.";
constexpr auto BaseStatPrefixLength = std::char_traits<char>::length(BaseStatPrefix);
constexpr auto BaseStatCount = static_cast<uint32_t>(Red::game::data::StatType::Count);
constexpr auto InvalidStat = static_cast<uint32_t>(Red::game::data::StatType::Invalid);

bool s_statTypesModified = false;
}

void App::StatService::OnBootstrap()
{
HookAfter<Raw::StatsDataSystem::InitializeRecords>(&OnInitializeStats);
}

void App::StatService::OnInitializeStats(void* aSystem)
{
auto statRecords = Raw::StatsDataSystem::StatRecords::Get(aSystem);
auto statTypeEnum = Red::GetDescriptor<Red::game::data::StatType>();

auto& tweakManager = Core::Resolve<TweakService>()->GetManager();
auto& tweakChangelog = Core::Resolve<TweakService>()->GetChangelog();

for (const auto& recordId : tweakChangelog.GetAffectedRecords())
{
const auto& recordName = tweakManager.GetName(recordId);
if (recordName.starts_with(BaseStatPrefix))
{
auto enumName = tweakManager.GetFlat({recordId, ".enumName"}).As<Red::CString>().c_str();
if (!statTypeEnum->HasOption(enumName))
{
if (recordName.substr(BaseStatPrefixLength) != enumName)
{
LogError("{}: Enum name must match the record name.", recordName);
continue;
}

if (statRecords->size == BaseStatCount)
{
// Add dummy entries for "Count" and "Invalid"
statRecords->EmplaceBack();
statRecords->EmplaceBack();
}

statTypeEnum->AddOption(statRecords->size, enumName);
statRecords->PushBack(recordId);

if (!s_statTypesModified)
{
s_statTypesModified = true;
Hook<Raw::StatsDataSystem::GetStatFlags>(&OnGetStatFlags);
Hook<Raw::StatsDataSystem::GetStatRange>(&OnGetStatRange);
}
}
}
}
}

uint32_t App::StatService::OnGetStatFlags(void* aSystem, uint32_t aStat)
{
if (aStat != InvalidStat)
{
auto& statParams = Raw::StatsDataSystem::StatParams::Ref(aSystem);
auto& statLock = Raw::StatsDataSystem::StatLock::Ref(aSystem);

std::shared_lock _(statLock);
if (aStat < statParams.size)
{
return statParams[aStat].flags;
}
}

return 0;
}

uint64_t* App::StatService::OnGetStatRange(void* aSystem, uint64_t* aRange, uint32_t aStat)
{
if (aStat != InvalidStat)
{
auto& statParams = Raw::StatsDataSystem::StatParams::Ref(aSystem);
auto& statLock = Raw::StatsDataSystem::StatLock::Ref(aSystem);

std::shared_lock _(statLock);
if (aStat < statParams.size)
{
*aRange = statParams[aStat].range;
return aRange;
}
}

*aRange = 0;
return aRange;
}
22 changes: 22 additions & 0 deletions src/App/Stats/StatService.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#include "Core/Foundation/Feature.hpp"
#include "Core/Hooking/HookingAgent.hpp"
#include "Core/Logging/LoggingAgent.hpp"
#include "Red/StatsDataSystem.hpp"

namespace App
{
class StatService
: public Core::Feature
, public Core::HookingAgent
, public Core::LoggingAgent
{
protected:
void OnBootstrap() override;

static void OnInitializeStats(void* aSystem);
static uint32_t OnGetStatFlags(void* aSystem, uint32_t aStat);
static uint64_t* OnGetStatRange(void* aSystem, uint64_t* aRange, uint32_t aStat);
};
}
15 changes: 15 additions & 0 deletions src/App/Tweaks/TweakService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,18 @@ bool App::TweakService::RegisterDirectory(std::filesystem::path aPath)
m_importPaths.emplace_back(std::move(aPath));
return true;
}

Red::TweakDBManager& App::TweakService::GetManager()
{
return *m_manager;
}

Red::TweakDBReflection& App::TweakService::GetReflection()
{
return *m_reflection;
}

App::TweakChangelog& App::TweakService::GetChangelog()
{
return *m_changelog;
}
4 changes: 4 additions & 0 deletions src/App/Tweaks/TweakService.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ class TweakService
void ExecuteTweaks();
void ExecuteTweak(Red::CName aName);

Red::TweakDBManager& GetManager();
Red::TweakDBReflection& GetReflection();
App::TweakChangelog& GetChangelog();

protected:
void OnBootstrap() override;
void CreateTweaksDir();
Expand Down
4 changes: 2 additions & 2 deletions src/App/Version.rc
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#define VER_PRODUCTVERSION 1,2,0,0
#define VER_FILEVERSION 1,2,0,2308010056
#define VER_FILEVERSION 1,2,0,2308041748

#define VER_PRODUCTNAME_STR "TweakXL\0"
#define VER_PRODUCTVERSION_STR "1.2.0\0"
#define VER_FILEVERSION_STR "1.2.0.2308010056\0"
#define VER_FILEVERSION_STR "1.2.0.2308041748\0"

1 VERSIONINFO
FILEVERSION VER_FILEVERSION
Expand Down
7 changes: 6 additions & 1 deletion src/Red/Addresses.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#pragma once

// Generated by cp77ida.py on 2023-06-26 for Cyberpunk 2077 v.1.63
// Generated by cp77ida.py on 2023-08-04 for Cyberpunk 2077 v.1.63
// DO NOT MODIFY. USE tools\ida\scan.py TO GENERATE THIS FILE.

#include <cstdint>
Expand All @@ -11,6 +11,11 @@ constexpr uintptr_t ImageBase = 0x140000000;

constexpr uintptr_t Main = 0x1401A0550 - ImageBase; // 40 53 48 81 EC ? ? ? ? FF 15 ? ? ? ? E8 ? ? ? ? E8 ? ? ? ?, expected: 1, index: 0

constexpr uintptr_t StatsDataSystem_InitializeRecords = 0x141A26120 - ImageBase; // 48 89 5C 24 ? 55 56 57 41 54 41 55 41 56 41 57 48 83 EC ? 48 8B F9 E8 ? ? ? ? 48 BA, expected: 1, index: 0
constexpr uintptr_t StatsDataSystem_InitializeParams = 0x141A262C0 - ImageBase; // 48 8B C4 41 54 41 56 48 81 EC ? ? ? ? 8B 91 ? ? ? ? 4C 8D B1 ? ? ? ? 45 33 E4 48 89 58 ? 48 89 78, expected: 1, index: 0
constexpr uintptr_t StatsDataSystem_GetStatFlags = 0x141A24810 - ImageBase; // 48 89 74 24 ? 57 48 83 EC ? 8B FA 48 8B F1 81 FA ? ? ? ? 73 ? 48 81 C1 ? ? ? ? 48 89 5C 24, expected: 1, index: 0
constexpr uintptr_t StatsDataSystem_GetStatRange = 0x141A24880 - ImageBase; // 48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC ? 41 8B F0 48 8B FA 48 8B E9 41 81 F8 ? ? ? ? 73, expected: 1, index: 0

constexpr uintptr_t TweakDB_Load = 0x140BE6B50 - ImageBase; // 48 89 5C 24 18 55 57 41 56 48 8B EC 48 83 EC 70 48 8B D9 45 33 F6 48 8D, expected: 1, index: 0
constexpr uintptr_t TweakDB_CreateRecord = 0x140FD4930 - ImageBase; // 48 89 5C 24 08 ? 89 ? 24 18 57 48 83 EC 30 8B C2, expected: 1, index: 0

Expand Down
45 changes: 45 additions & 0 deletions src/Red/StatsDataSystem.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#pragma once

#include "Red/Addresses.hpp"

namespace Red
{
struct StatParams
{
#pragma pack(push, 1)
union
{
uint64_t range;
struct
{
float min;
float max;
};
};
#pragma pack(pop)
uint32_t flags;
};
}

namespace Raw::StatsDataSystem
{
using StatRecords = Core::OffsetPtr<0xD8, Red::DynArray<Red::TweakDBID>>;
using StatParams = Core::OffsetPtr<0xE8, Red::DynArray<Red::StatParams>>;
using StatLock = Core::OffsetPtr<0xFC, Red::SharedMutex>;

constexpr auto InitializeRecords = Core::RawFunc<
/* addr = */ Red::Addresses::StatsDataSystem_InitializeRecords,
/* type = */ void (*)(void* aSystem)>();

constexpr auto InitializeParams = Core::RawFunc<
/* addr = */ Red::Addresses::StatsDataSystem_InitializeParams,
/* type = */ void (*)(void* aSystem)>();

constexpr auto GetStatFlags = Core::RawFunc<
/* addr = */ Red::Addresses::StatsDataSystem_GetStatFlags,
/* type = */ uint32_t (*)(void* aSystem, uint32_t aStat)>();

constexpr auto GetStatRange = Core::RawFunc<
/* addr = */ Red::Addresses::StatsDataSystem_GetStatRange,
/* type = */ uint64_t* (*)(void* aSystem, uint64_t*, uint32_t aStat)>();
}
2 changes: 2 additions & 0 deletions src/pch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include <RED4ext/RED4ext.hpp>

#include <RED4ext/ResourceDepot.hpp>
#include <RED4ext/Scripting/Natives/ScriptGameInstance.hpp>
#include <RED4ext/Scripting/Natives/Generated/Color.hpp>
#include <RED4ext/Scripting/Natives/Generated/EulerAngles.hpp>
Expand All @@ -27,6 +28,7 @@
#include <RED4ext/Scripting/Natives/Generated/game/data/TweakDBInterface.hpp>
#include <RED4ext/Scripting/Natives/Generated/game/IGameSystem.hpp>
#include <RED4ext/Scripting/Natives/Generated/game/ScriptableSystem.hpp>
#include <RED4ext/Scripting/Natives/Generated/game/data/StatType.hpp>

#include <nameof.hpp>
#include <semver.hpp>
Expand Down
10 changes: 10 additions & 0 deletions tools/ida/scan.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ def patterns():
Item(name="Derive",
pattern="40 53 48 83 EC 30 33 C0 4C 89 44 24 20 48 8B DA"),
]),
Group(name="StatsDataSystem", functions=[
Item(name="InitializeRecords",
pattern="48 89 5C 24 ? 55 56 57 41 54 41 55 41 56 41 57 48 83 EC ? 48 8B F9 E8 ? ? ? ? 48 BA"),
Item(name="InitializeParams",
pattern="48 8B C4 41 54 41 56 48 81 EC ? ? ? ? 8B 91 ? ? ? ? 4C 8D B1 ? ? ? ? 45 33 E4 48 89 58 ? 48 89 78"),
Item(name="GetStatFlags",
pattern="48 89 74 24 ? 57 48 83 EC ? 8B FA 48 8B F1 81 FA ? ? ? ? 73 ? 48 81 C1 ? ? ? ? 48 89 5C 24"),
Item(name="GetStatRange",
pattern="48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC ? 41 8B F0 48 8B FA 48 8B E9 41 81 F8 ? ? ? ? 73"),
]),
]),
]

Expand Down

0 comments on commit c51ca7a

Please sign in to comment.