Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for rc_memrefs_t #1135

Merged
merged 4 commits into from
Jan 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/base.props
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
<PreprocessorDefinitions>_ARCH=$(PlatformArchitecture);RC_CLIENT_SUPPORTS_HASH;RA_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_ARCH=$(PlatformArchitecture);RC_CLIENT_SUPPORTS_HASH;RC_DISABLE_LUA;RA_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
</ClCompile>
Expand Down
35 changes: 24 additions & 11 deletions src/data/models/AchievementModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -415,25 +415,36 @@ void AchievementModel::SyncTrigger()
return;
}

const auto nSize = rc_trigger_size(sTrigger.c_str());
auto* pGame = pRuntime.GetClient()->game;
Expects(pGame != nullptr);

rc_preparse_state_t preparse;
rc_init_preparse_state(&preparse, nullptr, 0);
preparse.parse.existing_memrefs = pGame->runtime.memrefs;

rc_trigger_with_memrefs_t* trigger = RC_ALLOC(rc_trigger_with_memrefs_t, &preparse.parse);
const char* sMemaddr = sTrigger.c_str();
rc_parse_trigger_internal(&trigger->trigger, &sMemaddr, &preparse.parse);
rc_preparse_alloc_memrefs(nullptr, &preparse);

const auto nSize = preparse.parse.offset;
if (nSize > 0)
{
void* trigger_buffer = malloc(nSize);
if (trigger_buffer)
{
// populate the item, using the communal memrefs pool
auto* pGame = pRuntime.GetClient()->game;
rc_reset_parse_state(&preparse.parse, trigger_buffer, nullptr, 0);
trigger = RC_ALLOC(rc_trigger_with_memrefs_t, &preparse.parse);
rc_preparse_alloc_memrefs(&trigger->memrefs, &preparse);

rc_parse_state_t parse;
rc_init_parse_state(&parse, trigger_buffer, nullptr, 0);
parse.first_memref = &pGame->runtime.memrefs;
parse.variables = &pGame->runtime.variables;
preparse.parse.existing_memrefs = pGame->runtime.memrefs;
preparse.parse.memrefs = &trigger->memrefs;

const char* sMemaddr = sTrigger.c_str();
m_pAchievement->trigger = RC_ALLOC(rc_trigger_t, &parse);
rc_parse_trigger_internal(m_pAchievement->trigger, &sMemaddr, &parse);
rc_destroy_parse_state(&parse);
m_pAchievement->trigger->memrefs = nullptr;
sMemaddr = sTrigger.c_str();
m_pAchievement->trigger = &trigger->trigger;
rc_parse_trigger_internal(m_pAchievement->trigger, &sMemaddr, &preparse.parse);
trigger->trigger.has_memrefs = 1;

pRuntime.AttachMemory(m_pAchievement->trigger);

Expand All @@ -453,6 +464,8 @@ void AchievementModel::SyncTrigger()
}
}
}

rc_destroy_preparse_state(&preparse);
}
}

Expand Down
33 changes: 22 additions & 11 deletions src/data/models/LeaderboardModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -334,25 +334,34 @@ void LeaderboardModel::SyncDefinition()
return;
}

const auto nSize = rc_lboard_size(sMemAddr.c_str());
auto* pGame = pRuntime.GetClient()->game;
Expects(pGame != nullptr);

rc_preparse_state_t preparse;
rc_init_preparse_state(&preparse, nullptr, 0);
preparse.parse.existing_memrefs = pGame->runtime.memrefs;

rc_lboard_with_memrefs_t* lboard = RC_ALLOC(rc_lboard_with_memrefs_t, &preparse.parse);
rc_parse_lboard_internal(&lboard->lboard, sMemAddr.c_str(), &preparse.parse);
rc_preparse_alloc_memrefs(nullptr, &preparse);

const auto nSize = preparse.parse.offset;
if (nSize > 0)
{
void* lboard_buffer = malloc(nSize);
if (lboard_buffer)
{
// populate the item, using the communal memrefs pool
auto* pGame = pRuntime.GetClient()->game;

rc_parse_state_t parse;
rc_init_parse_state(&parse, lboard_buffer, nullptr, 0);
parse.first_memref = &pGame->runtime.memrefs;
parse.variables = &pGame->runtime.variables;
rc_reset_parse_state(&preparse.parse, lboard_buffer, nullptr, 0);
lboard = RC_ALLOC(rc_lboard_with_memrefs_t, &preparse.parse);
rc_preparse_alloc_memrefs(&lboard->memrefs, &preparse);

m_pLeaderboard->lboard = RC_ALLOC(rc_lboard_t, &parse);
rc_parse_lboard_internal(m_pLeaderboard->lboard, sMemAddr.c_str(), &parse);
rc_destroy_parse_state(&parse);
preparse.parse.existing_memrefs = pGame->runtime.memrefs;
preparse.parse.memrefs = &lboard->memrefs;

m_pLeaderboard->lboard->memrefs = nullptr;
m_pLeaderboard->lboard = &lboard->lboard;
rc_parse_lboard_internal(m_pLeaderboard->lboard, sMemAddr.c_str(), &preparse.parse);
lboard->lboard.has_memrefs = 1;

pRuntime.AttachMemory(m_pLeaderboard->lboard);

Expand Down Expand Up @@ -383,6 +392,8 @@ void LeaderboardModel::SyncDefinition()
// parse error - discard old tracker
pRuntime.ReleaseLeaderboardTracker(m_pLeaderboard->public_.id);
}

rc_destroy_preparse_state(&preparse);
}
}

Expand Down
68 changes: 10 additions & 58 deletions src/services/AchievementRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -447,8 +447,6 @@ class AchievementRuntime::ClientSynchronizer
private:
rc_client_subset_info_t* m_pPublishedSubset = nullptr;
rc_client_t* m_pClient = nullptr;
rc_memref_t** m_pNextMemref = nullptr;
rc_value_t** m_pNextVariable = nullptr;

typedef struct rc_client_subset_wrapper_t
{
Expand All @@ -475,37 +473,6 @@ class AchievementRuntime::ClientSynchronizer
return false;
}

bool AllocatedMemrefs() noexcept
{
bool bAllocatedMemref = false;

/* if at least one memref was allocated within the object, we can't free the buffer when the object is
* deactivated */
if (*m_pNextMemref != nullptr)
{
bAllocatedMemref = true;
/* advance through the new memrefs so we're ready for the next allocation */
do
{
m_pNextMemref = &(*m_pNextMemref)->next;
} while (*m_pNextMemref != nullptr);
}

/* if at least one variable was allocated within the object, we can't free the buffer when the object is
* deactivated */
if (*m_pNextVariable != nullptr)
{
bAllocatedMemref = true;
/* advance through the new variables so we're ready for the next allocation */
do
{
m_pNextVariable = &(*m_pNextVariable)->next;
} while (*m_pNextVariable != nullptr);
}

return bAllocatedMemref;
}

static rc_client_leaderboard_info_t* FindLeaderboard(rc_client_subset_info_t* pSubset, uint32_t nId)
{
Expects(pSubset != nullptr);
Expand Down Expand Up @@ -703,10 +670,7 @@ class AchievementRuntime::ClientSynchronizer
if (m_pClient == nullptr)
{
m_pClient = pClient;
m_pNextMemref = &pClient->game->runtime.memrefs;
m_pNextVariable = &pClient->game->runtime.variables;
m_pPublishedSubset = pClient->game->subsets;
AllocatedMemrefs(); // advance pointers
}

std::vector<ra::data::models::AchievementModel*> vCoreAchievements;
Expand Down Expand Up @@ -784,15 +748,10 @@ class AchievementRuntime::ClientSynchronizer

void AttachMemory(void* pMemory)
{
if (AllocatedMemrefs())
{
// if memrefs were allocated, we can't release this memory until the game is unloaded
m_vAllocatedMemory.push_back(pMemory);
}
else
{
if (m_pSubsetWrapper)
m_pSubsetWrapper->vAllocatedMemory.push_back(pMemory);
}
else
m_vAllocatedMemory.push_back(pMemory);
}

bool DetachMemory(void* pMemory) noexcept
Expand Down Expand Up @@ -2378,6 +2337,9 @@ _NODISCARD static char ComparisonSizeFromPrefix(_In_ char cPrefix) noexcept
static bool LoadProgressV2(rc_client_t* pClient, ra::services::TextReader& pFile)
{
auto& pRuntime = pClient->game->runtime;
rc_preparse_state_t pParseState;
rc_init_preparse_state(&pParseState, nullptr, 0);
pParseState.parse.existing_memrefs = pRuntime.memrefs;

std::string sLine;
while (pFile.GetLine(sLine))
Expand Down Expand Up @@ -2433,20 +2395,10 @@ static bool LoadProgressV2(rc_client_t* pClient, ra::services::TextReader& pFile
if (tokenizer.PeekChar() == sLineMD5.at(31))
{
// match! attempt to store it
rc_memref_t* pMemoryReference = pRuntime.memrefs;
while (pMemoryReference)
{
if (pMemoryReference->address == pMemRef.address &&
pMemoryReference->value.size == pMemRef.value.size)
{
pMemoryReference->value.value = pMemRef.value.value;
pMemoryReference->value.changed = pMemRef.value.changed;
pMemoryReference->value.prior = pMemRef.value.prior;
break;
}

pMemoryReference = pMemoryReference->next;
}
rc_memref_t* pMemoryReference = rc_alloc_memref(&pParseState.parse, pMemRef.address, pMemRef.value.size);
pMemoryReference->value.value = pMemRef.value.value;
pMemoryReference->value.changed = pMemRef.value.changed;
pMemoryReference->value.prior = pMemRef.value.prior;
}
}
}
Expand Down
6 changes: 4 additions & 2 deletions src/ui/viewmodels/TriggerConditionViewModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -753,11 +753,13 @@ ra::ByteAddress TriggerConditionViewModel::GetIndirectAddress(ra::ByteAddress nA

rc_condition_t* pFirstCondition = nullptr;

const auto* pTrigger = pTriggerViewModel->GetTriggerFromString();
auto* pTrigger = pTriggerViewModel->GetTriggerFromString();
if (pTrigger != nullptr)
{
// if the trigger is managed by the viewmodel (not the runtime) then we need to update the memrefs
rc_update_memref_values(pTrigger->memrefs, rc_peek_callback, nullptr);
auto* memrefs = rc_trigger_get_memrefs(pTrigger);
if (memrefs)
rc_update_memref_values(memrefs, rc_peek_callback, nullptr);

// find the condset associated to the selected group
if (nIndex == 0)
Expand Down
52 changes: 35 additions & 17 deletions src/ui/viewmodels/TriggerViewModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <rcheevos.h>
#include <rcheevos/src/rcheevos/rc_internal.h>
#include <rcheevos/src/rc_client_internal.h>

#include "RA_StringUtils.h"

Expand Down Expand Up @@ -241,17 +242,15 @@ void TriggerViewModel::PasteFromClipboard()

// have to use internal parsing functions to decode conditions without full trigger/value
// restriction validation (full validation will occur after new conditions are added)
rc_parse_state_t parse;
rc_init_parse_state(&parse, nullptr, nullptr, 0);
rc_memref_t* first_memref;
rc_init_parse_state_memrefs(&parse, &first_memref);
parse.is_value = IsValue();
rc_preparse_state_t preparse;
rc_init_preparse_state(&preparse, nullptr, 0);
preparse.parse.is_value = IsValue();
std::string sTrigger = ra::Narrow(sClipboardText);
const char* memaddr = sTrigger.c_str();
Expects(memaddr != nullptr);
rc_parse_condset(&memaddr, &parse);
rc_parse_condset(&memaddr, &preparse.parse);

const auto nSize = parse.offset;
const auto nSize = preparse.parse.offset;
if (nSize > 0 && *memaddr == 'S')
{
ra::ui::viewmodels::MessageBoxViewModel::ShowErrorMessage(
Expand All @@ -268,11 +267,21 @@ void TriggerViewModel::PasteFromClipboard()

std::string sTriggerBuffer;
sTriggerBuffer.resize(nSize);
rc_init_parse_state(&parse, sTriggerBuffer.data(), nullptr, 0);
rc_init_parse_state_memrefs(&parse, &first_memref);
parse.is_value = IsValue();
rc_reset_parse_state(&preparse.parse, sTriggerBuffer.data(), nullptr, 0);
preparse.parse.is_value = IsValue();

if (ra::services::ServiceLocator::Exists<ra::services::AchievementRuntime>())
{
auto& pRuntime = ra::services::ServiceLocator::GetMutable<ra::services::AchievementRuntime>().GetClient()->game->runtime;
preparse.parse.memrefs = pRuntime.memrefs;
}
else
{
preparse.parse.memrefs = &preparse.memrefs;
}

memaddr = sTrigger.c_str();
const rc_condset_t* pCondSet = rc_parse_condset(&memaddr, &parse);
const rc_condset_t* pCondSet = rc_parse_condset(&memaddr, &preparse.parse);
Expects(pCondSet != nullptr);

m_vConditions.BeginUpdate();
Expand Down Expand Up @@ -489,14 +498,24 @@ rc_trigger_t* TriggerViewModel::ParseTrigger(const std::string& sTrigger)
const auto nSize = rc_value_size(sTrigger.c_str());
if (nSize > 0)
{
m_sTriggerBuffer.resize(nSize + sizeof(rc_trigger_t));
m_sTriggerBuffer.resize(nSize + sizeof(rc_trigger_with_memrefs_t));
rc_value_t* pValue = rc_parse_value(m_sTriggerBuffer.data(), sTrigger.c_str(), nullptr, 0);
rc_trigger_t* pTrigger;
GSL_SUPPRESS_TYPE1 pTrigger = reinterpret_cast<rc_trigger_t*>(m_sTriggerBuffer.data() + nSize);
memset(pTrigger, 0, sizeof(rc_trigger_t));
rc_trigger_with_memrefs_t* pTriggerWithMemrefs;
GSL_SUPPRESS_TYPE1 pTriggerWithMemrefs = reinterpret_cast<rc_trigger_with_memrefs_t*>(m_sTriggerBuffer.data() + nSize);
memset(pTriggerWithMemrefs, 0, sizeof(rc_trigger_with_memrefs_t));
auto* pTrigger = &pTriggerWithMemrefs->trigger;
pTrigger->requirement = pValue->conditions;
pTrigger->alternative = pValue->conditions->next;
pTrigger->memrefs = pValue->memrefs;

if (pValue->has_memrefs)
{
rc_value_with_memrefs_t* pValueWithMemrefs;
GSL_SUPPRESS_TYPE1 pValueWithMemrefs = reinterpret_cast<rc_value_with_memrefs_t*>(pValue);
memcpy(&pTriggerWithMemrefs->memrefs, &pValueWithMemrefs->memrefs,
sizeof(pTriggerWithMemrefs->memrefs));
pTrigger->has_memrefs = 1;
}

return pTrigger;
}
}
Expand Down Expand Up @@ -543,7 +562,6 @@ void TriggerViewModel::InitializeFrom(const rc_value_t& pValue)
memset(m_pTrigger, 0, sizeof(rc_trigger_t));
m_pTrigger->requirement = pValue.conditions;
m_pTrigger->alternative = (pValue.conditions) ? pValue.conditions->next : nullptr;
m_pTrigger->memrefs = pValue.memrefs;
InitializeGroups(*m_pTrigger);
}

Expand Down
2 changes: 1 addition & 1 deletion tests/base.props
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
<CompileAs>CompileAsCpp</CompileAs>
<AdditionalIncludeDirectories>$(RA_IncludePath)</AdditionalIncludeDirectories>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<PreprocessorDefinitions>RA_UTEST;RA_EXPORTS;RC_CLIENT_SUPPORTS_HASH;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>RA_UTEST;RA_EXPORTS;RC_CLIENT_SUPPORTS_HASH;RC_DISABLE_LUA;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
Expand Down
Loading
Loading