mirror of
https://github.com/cemu-project/Cemu.git
synced 2026-04-29 07:23:18 -06:00
GraphicPack: Support wildcard titleId and RPX hash + entrypoint callbacks (#1805)
This commit is contained in:
parent
5bc60b9452
commit
2c03ac3217
@ -328,7 +328,7 @@ GraphicPack2::GraphicPack2(fs::path rulesPath, IniParser& rules)
|
||||
}
|
||||
|
||||
m_title_ids = ParseTitleIds(rules, "titleIds");
|
||||
if(m_title_ids.empty())
|
||||
if(m_title_ids.empty() && !m_universal)
|
||||
throw std::exception();
|
||||
|
||||
auto option_fsPriority = rules.FindOption("fsPriority");
|
||||
@ -532,6 +532,9 @@ std::string GraphicPack2::GetNormalizedPathString() const
|
||||
|
||||
bool GraphicPack2::ContainsTitleId(uint64_t title_id) const
|
||||
{
|
||||
if (m_universal)
|
||||
return true;
|
||||
|
||||
const auto it = std::find_if(m_title_ids.begin(), m_title_ids.end(), [title_id](uint64 id) { return id == title_id; });
|
||||
return it != m_title_ids.end();
|
||||
}
|
||||
@ -1188,7 +1191,7 @@ std::vector<GraphicPack2::PresetPtr> GraphicPack2::GetActivePresets() const
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<uint64> GraphicPack2::ParseTitleIds(IniParser& rules, const char* option_name) const
|
||||
std::vector<uint64> GraphicPack2::ParseTitleIds(IniParser& rules, const char* option_name)
|
||||
{
|
||||
std::vector<uint64> result;
|
||||
|
||||
@ -1196,6 +1199,12 @@ std::vector<uint64> GraphicPack2::ParseTitleIds(IniParser& rules, const char* op
|
||||
if (!option_text)
|
||||
return result;
|
||||
|
||||
if (*option_text == "*")
|
||||
{
|
||||
m_universal = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
for (auto& token : TokenizeView(*option_text, ','))
|
||||
{
|
||||
try
|
||||
|
||||
@ -109,6 +109,7 @@ public:
|
||||
bool Reload();
|
||||
|
||||
bool HasName() const { return !m_name.empty(); }
|
||||
bool IsUniversal() const { return m_universal; }
|
||||
|
||||
const std::string& GetName() const { return m_name.empty() ? m_virtualPath : m_name; }
|
||||
const std::string& GetVirtualPath() const { return m_virtualPath; } // returns the path in the gfx tree hierarchy
|
||||
@ -122,6 +123,8 @@ public:
|
||||
const std::vector<uint64_t>& GetTitleIds() const { return m_title_ids; }
|
||||
bool HasCustomVSyncFrequency() const { return m_vsync_frequency >= 1; }
|
||||
sint32 GetCustomVSyncFrequency() const { return m_vsync_frequency; }
|
||||
|
||||
const std::vector<std::pair<MPTR, GPCallbackType>>& GetCallbacks() const { return m_callbacks; }
|
||||
|
||||
// texture rules
|
||||
const std::vector<TextureRule>& GetTextureRules() const { return m_texture_rules; }
|
||||
@ -229,6 +232,7 @@ private:
|
||||
bool m_activated = false; // set if the graphic pack is currently used by the running game
|
||||
std::vector<uint64_t> m_title_ids;
|
||||
bool m_patchedFilesLoaded = false; // set to true once patched files are loaded
|
||||
bool m_universal = false; // set if this pack applies to every title id
|
||||
|
||||
sint32 m_vsync_frequency = -1;
|
||||
sint32 m_fs_priority = 100;
|
||||
@ -256,7 +260,7 @@ private:
|
||||
|
||||
std::unordered_map<std::string, PresetVar> ParsePresetVars(IniParser& rules) const;
|
||||
|
||||
std::vector<uint64> ParseTitleIds(IniParser& rules, const char* option_name) const;
|
||||
std::vector<uint64> ParseTitleIds(IniParser& rules, const char* option_name);
|
||||
|
||||
CustomShader LoadShader(const fs::path& path, uint64 shader_base_hash, uint64 shader_aux_hash, GP_SHADER_TYPE shader_type, bool isMetalShader) const;
|
||||
void ApplyShaderPresets(std::string& shader_source) const;
|
||||
@ -282,6 +286,8 @@ private:
|
||||
void LogPatchesSyntaxError(sint32 lineNumber, std::string_view errorMsg);
|
||||
|
||||
std::vector<PatchGroup*> list_patchGroups;
|
||||
|
||||
std::vector<std::pair<MPTR, GPCallbackType>> m_callbacks;
|
||||
|
||||
static std::recursive_mutex mtx_patches;
|
||||
static std::vector<const RPLModule*> list_modules;
|
||||
|
||||
@ -172,7 +172,7 @@ void GraphicPack2::ApplyPatchesForModule(const RPLModule* rpl)
|
||||
std::vector<PatchGroup*> list_groups;
|
||||
for (auto itr : list_patchGroups)
|
||||
{
|
||||
if (itr->matchesCRC(rpl->patchCRC))
|
||||
if (itr->matchesCRC(rpl->patchCRC) || (itr->m_isRpxOnlyTarget && rpl->IsRPX()))
|
||||
list_groups.emplace_back(itr);
|
||||
}
|
||||
// apply all groups at once
|
||||
@ -188,7 +188,7 @@ void GraphicPack2::RevertPatchesForModule(const RPLModule* rpl)
|
||||
std::vector<PatchGroup*> list_groups;
|
||||
for (auto itr : list_patchGroups)
|
||||
{
|
||||
if (itr->matchesCRC(rpl->patchCRC))
|
||||
if (itr->matchesCRC(rpl->patchCRC) || (itr->m_isRpxOnlyTarget && rpl->IsRPX()))
|
||||
list_groups.emplace_back(itr);
|
||||
}
|
||||
// undo all groups at once
|
||||
|
||||
@ -212,6 +212,10 @@ private:
|
||||
bool m_addrRelocated{};
|
||||
};
|
||||
|
||||
enum class GPCallbackType {
|
||||
Entry
|
||||
};
|
||||
|
||||
class PatchGroup
|
||||
{
|
||||
friend class GraphicPack2;
|
||||
@ -256,7 +260,9 @@ private:
|
||||
std::string name;
|
||||
std::vector<uint32> list_moduleMatches;
|
||||
std::vector<PatchEntry*> list_patches;
|
||||
std::vector<std::pair<std::string, GPCallbackType>> list_callbacks;
|
||||
uint32 codeCaveSize;
|
||||
MEMPTR<void> codeCaveMem;
|
||||
bool m_isApplied{};
|
||||
bool m_isRpxOnlyTarget{};
|
||||
};
|
||||
@ -710,6 +710,21 @@ void GraphicPack2::ApplyPatchGroups(std::vector<PatchGroup*>& groups, const RPLM
|
||||
continue;
|
||||
patchInstruction->applyPatch();
|
||||
}
|
||||
|
||||
for (const auto& [name, type] : patchGroup->list_callbacks)
|
||||
{
|
||||
auto it = patchContext.map_values.find(name);
|
||||
if (it != patchContext.map_values.end())
|
||||
{
|
||||
m_callbacks.push_back(std::make_pair(it->second, type));
|
||||
}
|
||||
else
|
||||
{
|
||||
patchContext.errorHandler.printError(patchGroup, -1, fmt::format("Failed to resolve .callback symbol: {}", name));
|
||||
patchContext.errorHandler.showStageErrorMessageBox();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// mark groups as applied
|
||||
for (auto patchGroup : groups)
|
||||
|
||||
@ -41,7 +41,7 @@ void GraphicPack2::CancelParsingPatches()
|
||||
|
||||
void GraphicPack2::AddPatchGroup(PatchGroup* group)
|
||||
{
|
||||
if (group->list_moduleMatches.empty())
|
||||
if (group->list_moduleMatches.empty() && !group->m_isRpxOnlyTarget)
|
||||
{
|
||||
LogPatchesSyntaxError(-1, fmt::format("Group \"{}\" has no moduleMatches definition", group->name));
|
||||
CancelParsingPatches();
|
||||
@ -347,6 +347,12 @@ bool GraphicPack2::ParseCemuPatchesTxtInternal(MemStreamReader& patchesStream)
|
||||
// read the checksums
|
||||
while (true)
|
||||
{
|
||||
if (parser.matchWordI("rpx"))
|
||||
{
|
||||
currentGroup->m_isRpxOnlyTarget = true;
|
||||
break;
|
||||
}
|
||||
|
||||
uint32 checksum = 0;
|
||||
if (parser.parseU32(checksum) == false)
|
||||
{
|
||||
@ -425,7 +431,32 @@ bool GraphicPack2::ParseCemuPatchesTxtInternal(MemStreamReader& patchesStream)
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
else if (parser.matchWordI(".callback"))
|
||||
{
|
||||
if (parser.matchWordI("entry"))
|
||||
{
|
||||
const char* symbolStr;
|
||||
sint32 symbolLen;
|
||||
if (parser.parseSymbolName(symbolStr, symbolLen))
|
||||
{
|
||||
currentGroup->list_callbacks.push_back(std::make_pair(std::string(symbolStr, static_cast<size_t>(symbolLen)), GPCallbackType::Entry));
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPatchesSyntaxError(lineNumber, "'.callback' must reference a symbol after the type");
|
||||
CancelParsingPatches();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPatchesSyntaxError(lineNumber, "Unrecognized type for '.callback'");
|
||||
CancelParsingPatches();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// next we attempt to parse symbol assignment
|
||||
// symbols can be labels or variables. The type is determined by what comes after the symbol name
|
||||
// <symbolName> = <expression> defines a variable
|
||||
|
||||
@ -267,6 +267,7 @@ bool RPLLoader_ProcessHeaders(std::string_view moduleName, uint8* rplData, uint3
|
||||
rplLoaderContext->fileInfo.tlsModuleIndex = fileInfoPtr->tlsModuleIndex;
|
||||
rplLoaderContext->fileInfo.sdataBase1 = fileInfoPtr->sdataBase1;
|
||||
rplLoaderContext->fileInfo.sdataBase2 = fileInfoPtr->sdataBase2;
|
||||
rplLoaderContext->fileInfo.flags = fileInfoPtr->flags;
|
||||
|
||||
// init section address table
|
||||
rplLoaderContext->sectionAddressTable2.resize(sectionCount);
|
||||
|
||||
@ -113,7 +113,7 @@ typedef struct
|
||||
/* +0x28 */ uint32be sdataBase2;
|
||||
/* +0x2C */ uint32be ukn2C;
|
||||
/* +0x30 */ uint32be ukn30;
|
||||
/* +0x34 */ uint32be ukn34;
|
||||
/* +0x34 */ uint32be flags;
|
||||
/* +0x38 */ uint32be ukn38;
|
||||
/* +0x3C */ uint32be ukn3C;
|
||||
/* +0x40 */ uint32be minimumToolkitVersion;
|
||||
@ -198,6 +198,8 @@ struct RPLModule
|
||||
|
||||
uint32 sdataBase1;
|
||||
uint32 sdataBase2;
|
||||
|
||||
uint32 flags;
|
||||
}fileInfo;
|
||||
// parsed CRC
|
||||
std::vector<uint32> crcTable;
|
||||
@ -208,6 +210,11 @@ struct RPLModule
|
||||
return 0;
|
||||
return crcTable[sectionIndex];
|
||||
}
|
||||
|
||||
bool IsRPX() const
|
||||
{
|
||||
return fileInfo.flags & 2;
|
||||
}
|
||||
|
||||
// state
|
||||
bool isLinked; // set to true if _linkModule was called on this module
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_MEM.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_FG.h"
|
||||
#include "Cafe/CafeSystem.h"
|
||||
#include "Cafe/GraphicPack/GraphicPack2.h"
|
||||
|
||||
extern MPTR _entryPoint;
|
||||
extern RPLModule* applicationRPX;
|
||||
@ -211,6 +212,18 @@ void coreinit_start(PPCInterpreter_t* hCPU)
|
||||
padscore::start();
|
||||
vpad::start();
|
||||
|
||||
// call entry-type callbacks in graphic packs
|
||||
for (const auto gp : GraphicPack2::GetActiveGraphicPacks())
|
||||
{
|
||||
for (const auto [callback, type] : gp->GetCallbacks())
|
||||
{
|
||||
if (type == GPCallbackType::Entry)
|
||||
{
|
||||
PPCCoreCallback(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// continue at main executable entrypoint
|
||||
hCPU->gpr[4] = memory_getVirtualOffsetFromPointer(_coreinitInfo->argv);
|
||||
hCPU->gpr[3] = _coreinitInfo->argc;
|
||||
|
||||
@ -43,44 +43,47 @@ void GraphicPacksWindow2::FillGraphicPackList() const
|
||||
|
||||
for(auto& p : graphic_packs)
|
||||
{
|
||||
// filter graphic packs by given title id
|
||||
if (m_filter_installed_games && !m_installed_games.empty())
|
||||
if (!p->IsUniversal())
|
||||
{
|
||||
bool found = false;
|
||||
for (uint64 titleId : p->GetTitleIds())
|
||||
{
|
||||
if (std::find(m_installed_games.cbegin(), m_installed_games.cend(), titleId) != m_installed_games.cend())
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
continue;
|
||||
}
|
||||
|
||||
// filter graphic packs by given title id
|
||||
if(has_filter)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
if (boost::icontains(p->GetVirtualPath(), m_filter))
|
||||
found = true;
|
||||
else
|
||||
// filter graphic packs by given title id
|
||||
if (m_filter_installed_games && !m_installed_games.empty())
|
||||
{
|
||||
bool found = false;
|
||||
for (uint64 titleId : p->GetTitleIds())
|
||||
{
|
||||
if (boost::icontains(fmt::format("{:x}", titleId), m_filter))
|
||||
if (std::find(m_installed_games.cbegin(), m_installed_games.cend(), titleId) != m_installed_games.cend())
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
continue;
|
||||
}
|
||||
|
||||
// filter graphic packs by given title id
|
||||
if(has_filter)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
if (boost::icontains(p->GetVirtualPath(), m_filter))
|
||||
found = true;
|
||||
else
|
||||
{
|
||||
for (uint64 titleId : p->GetTitleIds())
|
||||
{
|
||||
if (boost::icontains(fmt::format("{:x}", titleId), m_filter))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& path = p->GetVirtualPath();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user