mirror of https://github.com/AxioDL/metaforce.git
Integrate URDEVersionInfo
This commit is contained in:
parent
e553a9022f
commit
52b4db2f00
|
@ -2,6 +2,7 @@
|
||||||
BasedOnStyle: LLVM
|
BasedOnStyle: LLVM
|
||||||
ColumnLimit: 120
|
ColumnLimit: 120
|
||||||
UseTab: Never
|
UseTab: Never
|
||||||
|
TabWidth: 4
|
||||||
---
|
---
|
||||||
Language: Cpp
|
Language: Cpp
|
||||||
DerivePointerAlignment: false
|
DerivePointerAlignment: false
|
||||||
|
|
|
@ -9,6 +9,7 @@ make_dnalist(CMDL
|
||||||
EGMC
|
EGMC
|
||||||
SAVWCommon
|
SAVWCommon
|
||||||
ParticleCommon
|
ParticleCommon
|
||||||
|
URDEVersionInfo
|
||||||
Tweaks/ITweakPlayerGun)
|
Tweaks/ITweakPlayerGun)
|
||||||
|
|
||||||
set(DNACOMMON_SOURCES
|
set(DNACOMMON_SOURCES
|
||||||
|
@ -40,6 +41,7 @@ set(DNACOMMON_SOURCES
|
||||||
RigInverter.hpp RigInverter.cpp
|
RigInverter.hpp RigInverter.cpp
|
||||||
AROTBuilder.hpp AROTBuilder.cpp
|
AROTBuilder.hpp AROTBuilder.cpp
|
||||||
OBBTreeBuilder.hpp OBBTreeBuilder.cpp
|
OBBTreeBuilder.hpp OBBTreeBuilder.cpp
|
||||||
|
URDEVersionInfo.hpp
|
||||||
Tweaks/ITweak.hpp
|
Tweaks/ITweak.hpp
|
||||||
Tweaks/TweakWriter.hpp
|
Tweaks/TweakWriter.hpp
|
||||||
Tweaks/ITweakGame.hpp
|
Tweaks/ITweakGame.hpp
|
||||||
|
|
|
@ -3,11 +3,12 @@
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "SpecBase.hpp"
|
#include "DataSpec/SpecBase.hpp"
|
||||||
#include "Blender/BlenderSupport.hpp"
|
#include "DataSpec/Blender/BlenderSupport.hpp"
|
||||||
#include "DNACommon/DNACommon.hpp"
|
#include "DataSpec/DNACommon/DNACommon.hpp"
|
||||||
#include "DNACommon/TXTR.hpp"
|
#include "DataSpec/DNACommon/TXTR.hpp"
|
||||||
#include "AssetNameMap.hpp"
|
#include "DataSpec/AssetNameMap.hpp"
|
||||||
|
#include "DataSpec/DNACommon/URDEVersionInfo.hpp"
|
||||||
#include "hecl/ClientProcess.hpp"
|
#include "hecl/ClientProcess.hpp"
|
||||||
#include "nod/DiscBase.hpp"
|
#include "nod/DiscBase.hpp"
|
||||||
#include "nod/nod.hpp"
|
#include "nod/nod.hpp"
|
||||||
|
@ -42,7 +43,9 @@ SpecBase::SpecBase(const hecl::Database::DataSpecEntry* specEntry, hecl::Databas
|
||||||
: hecl::Database::IDataSpec(specEntry)
|
: hecl::Database::IDataSpec(specEntry)
|
||||||
, m_project(project)
|
, m_project(project)
|
||||||
, m_pc(pc)
|
, m_pc(pc)
|
||||||
, m_masterShader(project.getProjectWorkingPath(), ".hecl/RetroMasterShader.blend") {
|
, m_masterShader(project.getProjectWorkingPath(), ".hecl/RetroMasterShader.blend")
|
||||||
|
, m_region(ERegion::Invalid)
|
||||||
|
, m_game(EGame::Invalid) {
|
||||||
AssetNameMap::InitAssetNameMap();
|
AssetNameMap::InitAssetNameMap();
|
||||||
SpecBase::setThreadProject();
|
SpecBase::setThreadProject();
|
||||||
}
|
}
|
||||||
|
@ -128,8 +131,7 @@ bool IsPathAudioGroup(const hecl::ProjectPath& path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsPathSong(const hecl::ProjectPath& path) {
|
static bool IsPathSong(const hecl::ProjectPath& path) {
|
||||||
if (path.getPathType() != hecl::ProjectPath::Type::Glob ||
|
if (path.getPathType() != hecl::ProjectPath::Type::Glob || !path.getWithExtension(_SYS_STR(".mid"), true).isFile() ||
|
||||||
!path.getWithExtension(_SYS_STR(".mid"), true).isFile() ||
|
|
||||||
!path.getWithExtension(_SYS_STR(".yaml"), true).isFile()) {
|
!path.getWithExtension(_SYS_STR(".yaml"), true).isFile()) {
|
||||||
return path.isFile() && path.getLastComponentExt() == _SYS_STR("mid") &&
|
return path.isFile() && path.getLastComponentExt() == _SYS_STR("mid") &&
|
||||||
path.getWithExtension(_SYS_STR(".yaml"), true).isFile();
|
path.getWithExtension(_SYS_STR(".yaml"), true).isFile();
|
||||||
|
@ -311,7 +313,8 @@ void SpecBase::flattenDependenciesBlend(const hecl::ProjectPath& in, std::vector
|
||||||
hecl::SystemStringConv chSysName(sub.name);
|
hecl::SystemStringConv chSysName(sub.name);
|
||||||
if (!sub.cskrId.empty()) {
|
if (!sub.cskrId.empty()) {
|
||||||
hecl::SystemStringConv cskrSysName(sub.cskrId);
|
hecl::SystemStringConv cskrSysName(sub.cskrId);
|
||||||
pathsOut.push_back(asGlob.ensureAuxInfo(fmt::format(FMT_STRING(_SYS_STR("{}_{}.CSKR")), chSysName, cskrSysName)));
|
pathsOut.push_back(
|
||||||
|
asGlob.ensureAuxInfo(fmt::format(FMT_STRING(_SYS_STR("{}_{}.CSKR")), chSysName, cskrSysName)));
|
||||||
} else {
|
} else {
|
||||||
pathsOut.push_back(asGlob.ensureAuxInfo(fmt::format(FMT_STRING(_SYS_STR("{}.CSKR")), chSysName)));
|
pathsOut.push_back(asGlob.ensureAuxInfo(fmt::format(FMT_STRING(_SYS_STR("{}.CSKR")), chSysName)));
|
||||||
}
|
}
|
||||||
|
@ -327,7 +330,8 @@ void SpecBase::flattenDependenciesBlend(const hecl::ProjectPath& in, std::vector
|
||||||
flattenDependenciesBlend(overlay.mesh, pathsOut, btok);
|
flattenDependenciesBlend(overlay.mesh, pathsOut, btok);
|
||||||
pathsOut.push_back(overlay.mesh);
|
pathsOut.push_back(overlay.mesh);
|
||||||
}
|
}
|
||||||
pathsOut.push_back(asGlob.ensureAuxInfo(fmt::format(FMT_STRING(_SYS_STR("{}.{}_{}.CSKR")), chSysName, overlaySys, overlayCskrId)));
|
pathsOut.push_back(asGlob.ensureAuxInfo(
|
||||||
|
fmt::format(FMT_STRING(_SYS_STR("{}.{}_{}.CSKR")), chSysName, overlaySys, overlayCskrId)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -345,7 +349,8 @@ void SpecBase::flattenDependenciesBlend(const hecl::ProjectPath& in, std::vector
|
||||||
|
|
||||||
hecl::SystemStringConv chSysName(att.name);
|
hecl::SystemStringConv chSysName(att.name);
|
||||||
hecl::SystemStringConv sysCskrId(att.cskrId);
|
hecl::SystemStringConv sysCskrId(att.cskrId);
|
||||||
pathsOut.push_back(asGlob.ensureAuxInfo(fmt::format(FMT_STRING(_SYS_STR("ATTACH.{}_{}.CSKR")), chSysName, sysCskrId)));
|
pathsOut.push_back(
|
||||||
|
asGlob.ensureAuxInfo(fmt::format(FMT_STRING(_SYS_STR("ATTACH.{}_{}.CSKR")), chSysName, sysCskrId)));
|
||||||
|
|
||||||
if (att.armature >= 0) {
|
if (att.armature >= 0) {
|
||||||
const auto& arm = actor.armatures[att.armature];
|
const auto& arm = actor.armatures[att.armature];
|
||||||
|
@ -358,8 +363,9 @@ void SpecBase::flattenDependenciesBlend(const hecl::ProjectPath& in, std::vector
|
||||||
hecl::SystemStringConv actSysName(act.first);
|
hecl::SystemStringConv actSysName(act.first);
|
||||||
hecl::SystemStringConv actAnimId(act.second);
|
hecl::SystemStringConv actAnimId(act.second);
|
||||||
pathsOut.push_back(asGlob.ensureAuxInfo(fmt::format(FMT_STRING(_SYS_STR("{}_{}.ANIM")), actSysName, actAnimId)));
|
pathsOut.push_back(asGlob.ensureAuxInfo(fmt::format(FMT_STRING(_SYS_STR("{}_{}.ANIM")), actSysName, actAnimId)));
|
||||||
hecl::SystemString searchPrefix(asGlob.getWithExtension(
|
hecl::SystemString searchPrefix(
|
||||||
fmt::format(FMT_STRING(_SYS_STR(".{}_")), actSysName).c_str(), true).getLastComponent());
|
asGlob.getWithExtension(fmt::format(FMT_STRING(_SYS_STR(".{}_")), actSysName).c_str(), true)
|
||||||
|
.getLastComponent());
|
||||||
hecl::ProjectPath evntPath;
|
hecl::ProjectPath evntPath;
|
||||||
for (const auto& ent : dEnum) {
|
for (const auto& ent : dEnum) {
|
||||||
if (hecl::StringUtils::BeginsWith(ent.m_name, searchPrefix.c_str()) &&
|
if (hecl::StringUtils::BeginsWith(ent.m_name, searchPrefix.c_str()) &&
|
||||||
|
@ -628,8 +634,7 @@ void SpecBase::doPackage(const hecl::ProjectPath& path, const hecl::Database::Da
|
||||||
std::unordered_set<urde::SObjectTag> addedTags;
|
std::unordered_set<urde::SObjectTag> addedTags;
|
||||||
addedTags.reserve(buildList.size());
|
addedTags.reserve(buildList.size());
|
||||||
for (auto& tag : buildList) {
|
for (auto& tag : buildList) {
|
||||||
if ((i == 0 && tag.type == FOURCC('CMDL')) ||
|
if ((i == 0 && tag.type == FOURCC('CMDL')) || (i == 1 && tag.type != FOURCC('CMDL'))) {
|
||||||
(i == 1 && tag.type != FOURCC('CMDL'))) {
|
|
||||||
if (addedTags.find(tag) != addedTags.end())
|
if (addedTags.find(tag) != addedTags.end())
|
||||||
continue;
|
continue;
|
||||||
addedTags.insert(tag);
|
addedTags.insert(tag);
|
||||||
|
@ -1010,11 +1015,10 @@ bool SpecBase::addFileToIndex(const hecl::ProjectPath& path, athena::io::YAMLDoc
|
||||||
hecl::SystemStringConv overlaySys(overlay.first);
|
hecl::SystemStringConv overlaySys(overlay.first);
|
||||||
hecl::SystemStringConv overlayCskrId(overlay.second);
|
hecl::SystemStringConv overlayCskrId(overlay.second);
|
||||||
if (!overlay.second.empty()) {
|
if (!overlay.second.empty()) {
|
||||||
subPath =
|
subPath = asGlob.ensureAuxInfo(
|
||||||
asGlob.ensureAuxInfo(fmt::format(FMT_STRING(_SYS_STR("{}.{}_{}.CSKR")), subName, overlaySys, overlayCskrId));
|
fmt::format(FMT_STRING(_SYS_STR("{}.{}_{}.CSKR")), subName, overlaySys, overlayCskrId));
|
||||||
} else {
|
} else {
|
||||||
subPath =
|
subPath = asGlob.ensureAuxInfo(fmt::format(FMT_STRING(_SYS_STR("{}.{}.CSKR")), subName, overlaySys));
|
||||||
asGlob.ensureAuxInfo(fmt::format(FMT_STRING(_SYS_STR("{}.{}.CSKR")), subName, overlaySys));
|
|
||||||
}
|
}
|
||||||
insertPathTag(cacheWriter, buildTagFromPath(subPath), subPath);
|
insertPathTag(cacheWriter, buildTagFromPath(subPath), subPath);
|
||||||
}
|
}
|
||||||
|
@ -1026,11 +1030,10 @@ bool SpecBase::addFileToIndex(const hecl::ProjectPath& path, athena::io::YAMLDoc
|
||||||
hecl::SystemStringConv attachmentCskrId(attachment.second);
|
hecl::SystemStringConv attachmentCskrId(attachment.second);
|
||||||
hecl::ProjectPath subPath;
|
hecl::ProjectPath subPath;
|
||||||
if (!attachment.second.empty()) {
|
if (!attachment.second.empty()) {
|
||||||
subPath =
|
subPath = asGlob.ensureAuxInfo(
|
||||||
asGlob.ensureAuxInfo(fmt::format(FMT_STRING(_SYS_STR("ATTACH.{}_{}.CSKR")), attachmentSys, attachmentCskrId));
|
fmt::format(FMT_STRING(_SYS_STR("ATTACH.{}_{}.CSKR")), attachmentSys, attachmentCskrId));
|
||||||
} else {
|
} else {
|
||||||
subPath =
|
subPath = asGlob.ensureAuxInfo(fmt::format(FMT_STRING(_SYS_STR("ATTACH.{}.CSKR")), attachmentSys));
|
||||||
asGlob.ensureAuxInfo(fmt::format(FMT_STRING(_SYS_STR("ATTACH.{}.CSKR")), attachmentSys));
|
|
||||||
}
|
}
|
||||||
insertPathTag(cacheWriter, buildTagFromPath(subPath), subPath);
|
insertPathTag(cacheWriter, buildTagFromPath(subPath), subPath);
|
||||||
}
|
}
|
||||||
|
@ -1164,8 +1167,8 @@ void SpecBase::backgroundIndexProc() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Log.report(logvisor::Info, FMT_STRING(_SYS_STR("Name index of '{}' loaded; {} names")), getOriginalSpec().m_name,
|
Log.report(logvisor::Info, FMT_STRING(_SYS_STR("Name index of '{}' loaded; {} names")),
|
||||||
m_catalogNameToTag.size());
|
getOriginalSpec().m_name, m_catalogNameToTag.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1208,15 +1211,16 @@ void SpecBase::waitForIndexComplete() const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpecBase::WriteVersionInfo(hecl::Database::Project &project, const hecl::ProjectPath &pakPath) {
|
void SpecBase::WriteVersionInfo(hecl::Database::Project& project, const hecl::ProjectPath& pakPath) {
|
||||||
hecl::ProjectPath versionPath(pakPath, _SYS_STR("version.yaml"));
|
hecl::ProjectPath versionPath(pakPath, _SYS_STR("version.yaml"));
|
||||||
versionPath.makeDirChain(false);
|
versionPath.makeDirChain(false);
|
||||||
|
|
||||||
athena::io::YAMLDocWriter yamlW("URDEVersionData");
|
URDEVersionInfo info;
|
||||||
yamlW.writeString("version", m_version);
|
info.version = m_version;
|
||||||
yamlW.writeByte("region", atUint8(m_region));
|
info.region = m_region;
|
||||||
yamlW.writeBool("is_trilogy", !m_standalone);
|
info.game = m_game;
|
||||||
athena::io::FileWriter fileW(versionPath.getAbsolutePath());
|
info.isTrilogy = !m_standalone;
|
||||||
yamlW.finish(&fileW);
|
athena::io::FileWriter writer(versionPath.getAbsolutePath());
|
||||||
|
athena::io::ToYAMLStream(info, writer);
|
||||||
}
|
}
|
||||||
} // namespace DataSpec
|
} // namespace DataSpec
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "hecl/Blender/Token.hpp"
|
#include "hecl/Blender/Token.hpp"
|
||||||
#include "Runtime/RetroTypes.hpp"
|
#include "Runtime/RetroTypes.hpp"
|
||||||
|
|
||||||
|
|
||||||
namespace nod {
|
namespace nod {
|
||||||
class DiscBase;
|
class DiscBase;
|
||||||
class Node;
|
class Node;
|
||||||
|
@ -23,13 +24,8 @@ class YAMLDocWriter;
|
||||||
} // namespace athena::io
|
} // namespace athena::io
|
||||||
|
|
||||||
namespace DataSpec {
|
namespace DataSpec {
|
||||||
enum class ERegion {
|
enum class ERegion;
|
||||||
Invalid = 0,
|
enum class EGame;
|
||||||
NTSC_U = 'E',
|
|
||||||
PAL = 'P',
|
|
||||||
NTSC_J = 'J'
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SpecBase : hecl::Database::IDataSpec {
|
struct SpecBase : hecl::Database::IDataSpec {
|
||||||
/* HECL Adaptors */
|
/* HECL Adaptors */
|
||||||
void setThreadProject() override;
|
void setThreadProject() override;
|
||||||
|
@ -203,9 +199,10 @@ protected:
|
||||||
const std::unordered_map<urde::CAssetId, std::vector<uint8_t>>& mlvlData);
|
const std::unordered_map<urde::CAssetId, std::vector<uint8_t>>& mlvlData);
|
||||||
|
|
||||||
std::unique_ptr<nod::DiscBase> m_disc;
|
std::unique_ptr<nod::DiscBase> m_disc;
|
||||||
bool m_isWii;
|
bool m_isWii{};
|
||||||
bool m_standalone;
|
bool m_standalone{};
|
||||||
ERegion m_region = ERegion::Invalid;
|
ERegion m_region;
|
||||||
|
EGame m_game;
|
||||||
std::string m_version;
|
std::string m_version;
|
||||||
|
|
||||||
void WriteVersionInfo(hecl::Database::Project& project, const hecl::ProjectPath& pakPath);
|
void WriteVersionInfo(hecl::Database::Project& project, const hecl::ProjectPath& pakPath);
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "DNACommon/DPSC.hpp"
|
#include "DNACommon/DPSC.hpp"
|
||||||
#include "DNACommon/DGRP.hpp"
|
#include "DNACommon/DGRP.hpp"
|
||||||
#include "DNACommon/MAPU.hpp"
|
#include "DNACommon/MAPU.hpp"
|
||||||
|
#include "DNACommon/URDEVersionInfo.hpp"
|
||||||
#include "DNACommon/Tweaks/TweakWriter.hpp"
|
#include "DNACommon/Tweaks/TweakWriter.hpp"
|
||||||
#include "DNAMP1/Tweaks/CTweakPlayerRes.hpp"
|
#include "DNAMP1/Tweaks/CTweakPlayerRes.hpp"
|
||||||
#include "DNAMP1/Tweaks/CTweakGunRes.hpp"
|
#include "DNAMP1/Tweaks/CTweakGunRes.hpp"
|
||||||
|
@ -46,7 +47,6 @@
|
||||||
#include "DNAMP1/Tweaks/CTweakPlayerGun.hpp"
|
#include "DNAMP1/Tweaks/CTweakPlayerGun.hpp"
|
||||||
#include "DNAMP1/MazeSeeds.hpp"
|
#include "DNAMP1/MazeSeeds.hpp"
|
||||||
#include "DNAMP1/SnowForces.hpp"
|
#include "DNAMP1/SnowForces.hpp"
|
||||||
|
|
||||||
#include "hecl/ClientProcess.hpp"
|
#include "hecl/ClientProcess.hpp"
|
||||||
#include "hecl/MultiProgressPrinter.hpp"
|
#include "hecl/MultiProgressPrinter.hpp"
|
||||||
#include "hecl/Blender/Connection.hpp"
|
#include "hecl/Blender/Connection.hpp"
|
||||||
|
@ -145,7 +145,8 @@ struct SpecMP1 : SpecBase {
|
||||||
, m_workPath(project.getProjectWorkingPath(), _SYS_STR("MP1"))
|
, m_workPath(project.getProjectWorkingPath(), _SYS_STR("MP1"))
|
||||||
, m_cookPath(project.getProjectCookedPath(SpecEntMP1), _SYS_STR("MP1"))
|
, m_cookPath(project.getProjectCookedPath(SpecEntMP1), _SYS_STR("MP1"))
|
||||||
, m_pakRouter(*this, m_workPath, m_cookPath) {
|
, m_pakRouter(*this, m_workPath, m_cookPath) {
|
||||||
setThreadProject();
|
m_game = EGame::MetroidPrime1;
|
||||||
|
SpecBase::setThreadProject();
|
||||||
}
|
}
|
||||||
|
|
||||||
void buildPaks(nod::Node& root, const std::vector<hecl::SystemString>& args, ExtractReport& rep) {
|
void buildPaks(nod::Node& root, const std::vector<hecl::SystemString>& args, ExtractReport& rep) {
|
||||||
|
@ -197,8 +198,9 @@ struct SpecMP1 : SpecBase {
|
||||||
|
|
||||||
/* Sort PAKs alphabetically */
|
/* Sort PAKs alphabetically */
|
||||||
m_orderedPaks.clear();
|
m_orderedPaks.clear();
|
||||||
for (DNAMP1::PAKBridge& dpak : m_paks)
|
for (DNAMP1::PAKBridge& dpak : m_paks) {
|
||||||
m_orderedPaks[std::string(dpak.getName())] = &dpak;
|
m_orderedPaks[std::string(dpak.getName())] = &dpak;
|
||||||
|
}
|
||||||
|
|
||||||
/* Assemble extract report */
|
/* Assemble extract report */
|
||||||
rep.childOpts.reserve(m_orderedPaks.size());
|
rep.childOpts.reserve(m_orderedPaks.size());
|
||||||
|
@ -218,9 +220,10 @@ struct SpecMP1 : SpecBase {
|
||||||
const std::vector<hecl::SystemString>& args, std::vector<ExtractReport>& reps) override {
|
const std::vector<hecl::SystemString>& args, std::vector<ExtractReport>& reps) override {
|
||||||
nod::IPartition* partition = disc.getDataPartition();
|
nod::IPartition* partition = disc.getDataPartition();
|
||||||
m_dolBuf = partition->getDOLBuf();
|
m_dolBuf = partition->getDOLBuf();
|
||||||
const char* buildInfo = (char*)memmem(m_dolBuf.get(), partition->getDOLSize(), "MetroidBuildInfo", 16) + 19;
|
const char* buildInfo =
|
||||||
|
static_cast<char*>(memmem(m_dolBuf.get(), partition->getDOLSize(), "MetroidBuildInfo", 16)) + 19;
|
||||||
|
|
||||||
if (!buildInfo)
|
if (buildInfo == nullptr)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
m_version = std::string(buildInfo);
|
m_version = std::string(buildInfo);
|
||||||
|
@ -275,15 +278,15 @@ struct SpecMP1 : SpecBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
m_dolBuf = dolIt->getBuf();
|
m_dolBuf = dolIt->getBuf();
|
||||||
const char* buildInfo = (char*)memmem(m_dolBuf.get(), dolIt->size(), "MetroidBuildInfo", 16) + 19;
|
const char* buildInfo = static_cast<char*>(memmem(m_dolBuf.get(), dolIt->size(), "MetroidBuildInfo", 16)) + 19;
|
||||||
|
|
||||||
/* Root Report */
|
/* Root Report */
|
||||||
ExtractReport& rep = reps.emplace_back();
|
ExtractReport& rep = reps.emplace_back();
|
||||||
rep.name = _SYS_STR("MP1");
|
rep.name = _SYS_STR("MP1");
|
||||||
rep.desc = _SYS_STR("Metroid Prime ") + regstr;
|
rep.desc = _SYS_STR("Metroid Prime ") + regstr;
|
||||||
if (buildInfo) {
|
if (buildInfo != nullptr) {
|
||||||
std::string buildStr(buildInfo);
|
m_version = std::string(buildInfo);
|
||||||
hecl::SystemStringConv buildView(buildStr);
|
hecl::SystemStringConv buildView(m_version);
|
||||||
rep.desc += _SYS_STR(" (") + buildView + _SYS_STR(")");
|
rep.desc += _SYS_STR(" (") + buildView + _SYS_STR(")");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "DNACommon/MAPU.hpp"
|
#include "DNACommon/MAPU.hpp"
|
||||||
#include "DNACommon/PATH.hpp"
|
#include "DNACommon/PATH.hpp"
|
||||||
#include "DNACommon/TXTR.hpp"
|
#include "DNACommon/TXTR.hpp"
|
||||||
|
#include "DNACommon/URDEVersionInfo.hpp"
|
||||||
|
|
||||||
#include "hecl/ClientProcess.hpp"
|
#include "hecl/ClientProcess.hpp"
|
||||||
#include "hecl/Blender/Connection.hpp"
|
#include "hecl/Blender/Connection.hpp"
|
||||||
|
@ -111,7 +112,8 @@ struct SpecMP2 : SpecBase {
|
||||||
, m_workPath(project.getProjectWorkingPath(), _SYS_STR("MP2"))
|
, m_workPath(project.getProjectWorkingPath(), _SYS_STR("MP2"))
|
||||||
, m_cookPath(project.getProjectCookedPath(SpecEntMP2), _SYS_STR("MP2"))
|
, m_cookPath(project.getProjectCookedPath(SpecEntMP2), _SYS_STR("MP2"))
|
||||||
, m_pakRouter(*this, m_workPath, m_cookPath) {
|
, m_pakRouter(*this, m_workPath, m_cookPath) {
|
||||||
setThreadProject();
|
m_game = EGame::MetroidPrime2;
|
||||||
|
SpecBase::setThreadProject();
|
||||||
}
|
}
|
||||||
|
|
||||||
void buildPaks(nod::Node& root, const std::vector<hecl::SystemString>& args, ExtractReport& rep) {
|
void buildPaks(nod::Node& root, const std::vector<hecl::SystemString>& args, ExtractReport& rep) {
|
||||||
|
@ -183,9 +185,10 @@ struct SpecMP2 : SpecBase {
|
||||||
const std::vector<hecl::SystemString>& args, std::vector<ExtractReport>& reps) override {
|
const std::vector<hecl::SystemString>& args, std::vector<ExtractReport>& reps) override {
|
||||||
nod::IPartition* partition = disc.getDataPartition();
|
nod::IPartition* partition = disc.getDataPartition();
|
||||||
std::unique_ptr<uint8_t[]> dolBuf = partition->getDOLBuf();
|
std::unique_ptr<uint8_t[]> dolBuf = partition->getDOLBuf();
|
||||||
const char* buildInfo = (char*)memmem(dolBuf.get(), partition->getDOLSize(), "MetroidBuildInfo", 16) + 19;
|
const char* buildInfo = static_cast<char*>(memmem(dolBuf.get(), partition->getDOLSize(), "MetroidBuildInfo", 16)) + 19;
|
||||||
if (!buildInfo)
|
if (buildInfo == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
m_version = std::string(buildInfo);
|
m_version = std::string(buildInfo);
|
||||||
/* Root Report */
|
/* Root Report */
|
||||||
|
@ -206,7 +209,7 @@ struct SpecMP2 : SpecBase {
|
||||||
const std::vector<hecl::SystemString>& args, std::vector<ExtractReport>& reps) override {
|
const std::vector<hecl::SystemString>& args, std::vector<ExtractReport>& reps) override {
|
||||||
std::vector<hecl::SystemString> mp2args;
|
std::vector<hecl::SystemString> mp2args;
|
||||||
bool doExtract = false;
|
bool doExtract = false;
|
||||||
if (args.size()) {
|
if (!args.empty()) {
|
||||||
/* Needs filter */
|
/* Needs filter */
|
||||||
for (const hecl::SystemString& arg : args) {
|
for (const hecl::SystemString& arg : args) {
|
||||||
hecl::SystemString lowerArg = arg;
|
hecl::SystemString lowerArg = arg;
|
||||||
|
@ -237,15 +240,15 @@ struct SpecMP2 : SpecBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<uint8_t[]> dolBuf = dolIt->getBuf();
|
std::unique_ptr<uint8_t[]> dolBuf = dolIt->getBuf();
|
||||||
const char* buildInfo = (char*)memmem(dolBuf.get(), dolIt->size(), "MetroidBuildInfo", 16) + 19;
|
const char* buildInfo = static_cast<char*>(memmem(dolBuf.get(), dolIt->size(), "MetroidBuildInfo", 16)) + 19;
|
||||||
|
|
||||||
/* Root Report */
|
/* Root Report */
|
||||||
ExtractReport& rep = reps.emplace_back();
|
ExtractReport& rep = reps.emplace_back();
|
||||||
rep.name = _SYS_STR("MP2");
|
rep.name = _SYS_STR("MP2");
|
||||||
rep.desc = _SYS_STR("Metroid Prime 2 ") + regstr;
|
rep.desc = _SYS_STR("Metroid Prime 2 ") + regstr;
|
||||||
if (buildInfo) {
|
if (buildInfo != nullptr) {
|
||||||
std::string buildStr(buildInfo);
|
m_version = std::string(buildInfo);
|
||||||
hecl::SystemStringConv buildView(buildStr);
|
hecl::SystemStringConv buildView(m_version);
|
||||||
rep.desc += _SYS_STR(" (") + buildView + _SYS_STR(")");
|
rep.desc += _SYS_STR(" (") + buildView + _SYS_STR(")");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "DataSpec/DNAMP3/MAPA.hpp"
|
#include "DataSpec/DNAMP3/MAPA.hpp"
|
||||||
#include "DataSpec/DNAMP2/STRG.hpp"
|
#include "DataSpec/DNAMP2/STRG.hpp"
|
||||||
#include "DataSpec/DNACommon/TXTR.hpp"
|
#include "DataSpec/DNACommon/TXTR.hpp"
|
||||||
|
#include "DataSpec/DNACommon/URDEVersionInfo.hpp"
|
||||||
|
|
||||||
#include "hecl/ClientProcess.hpp"
|
#include "hecl/ClientProcess.hpp"
|
||||||
#include "hecl/Blender/Connection.hpp"
|
#include "hecl/Blender/Connection.hpp"
|
||||||
|
@ -89,11 +90,7 @@ struct TextureCache {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SpecMP3 : SpecBase {
|
struct SpecMP3 : SpecBase {
|
||||||
bool checkStandaloneID(const char* id) const override {
|
bool checkStandaloneID(const char* id) const override { return memcmp(id, "RM3", 3) == 0; }
|
||||||
if (!memcmp(id, "RM3", 3))
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool doMP3 = false;
|
bool doMP3 = false;
|
||||||
std::vector<const nod::Node*> m_nonPaks;
|
std::vector<const nod::Node*> m_nonPaks;
|
||||||
|
@ -122,7 +119,8 @@ struct SpecMP3 : SpecBase {
|
||||||
, m_feWorkPath(project.getProjectWorkingPath(), _SYS_STR("fe"))
|
, m_feWorkPath(project.getProjectWorkingPath(), _SYS_STR("fe"))
|
||||||
, m_feCookPath(project.getProjectCookedPath(SpecEntMP3), _SYS_STR("fe"))
|
, m_feCookPath(project.getProjectCookedPath(SpecEntMP3), _SYS_STR("fe"))
|
||||||
, m_fePakRouter(*this, m_feWorkPath, m_feCookPath) {
|
, m_fePakRouter(*this, m_feWorkPath, m_feCookPath) {
|
||||||
setThreadProject();
|
m_game = EGame::MetroidPrime3;
|
||||||
|
SpecBase::setThreadProject();
|
||||||
}
|
}
|
||||||
|
|
||||||
void buildPaks(nod::Node& root, const std::vector<hecl::SystemString>& args, ExtractReport& rep, bool fe) {
|
void buildPaks(nod::Node& root, const std::vector<hecl::SystemString>& args, ExtractReport& rep, bool fe) {
|
||||||
|
@ -223,13 +221,15 @@ struct SpecMP3 : SpecBase {
|
||||||
doMP3 = true;
|
doMP3 = true;
|
||||||
nod::IPartition* partition = disc.getDataPartition();
|
nod::IPartition* partition = disc.getDataPartition();
|
||||||
std::unique_ptr<uint8_t[]> dolBuf = partition->getDOLBuf();
|
std::unique_ptr<uint8_t[]> dolBuf = partition->getDOLBuf();
|
||||||
const char* buildInfo = (char*)memmem(dolBuf.get(), partition->getDOLSize(), "MetroidBuildInfo", 16) + 19;
|
const char* buildInfo = static_cast<char*>(memmem(dolBuf.get(), partition->getDOLSize(), "MetroidBuildInfo", 16)) + 19;
|
||||||
if (!buildInfo)
|
if (buildInfo == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* We don't want no stinking demo dammit */
|
/* We don't want no stinking demo dammit */
|
||||||
if (!strcmp(buildInfo, "Build v3.068 3/2/2006 14:55:13"))
|
if (strcmp(buildInfo, "Build v3.068 3/2/2006 14:55:13") == 0) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
m_version = std::string(buildInfo);
|
m_version = std::string(buildInfo);
|
||||||
/* Root Report */
|
/* Root Report */
|
||||||
|
@ -317,8 +317,8 @@ struct SpecMP3 : SpecBase {
|
||||||
rep.name = _SYS_STR("MP3");
|
rep.name = _SYS_STR("MP3");
|
||||||
rep.desc = _SYS_STR("Metroid Prime 3 ") + regstr;
|
rep.desc = _SYS_STR("Metroid Prime 3 ") + regstr;
|
||||||
|
|
||||||
std::string buildStr(buildInfo);
|
m_version = std::string(buildInfo);
|
||||||
hecl::SystemStringConv buildView(buildStr);
|
hecl::SystemStringConv buildView(m_version);
|
||||||
rep.desc += _SYS_STR(" (") + buildView + _SYS_STR(")");
|
rep.desc += _SYS_STR(" (") + buildView + _SYS_STR(")");
|
||||||
|
|
||||||
/* Iterate PAKs and build level options */
|
/* Iterate PAKs and build level options */
|
||||||
|
|
|
@ -19,7 +19,7 @@ class CFileDvdRequest : public IDvdRequest {
|
||||||
std::function<void(u32)> m_callback;
|
std::function<void(u32)> m_callback;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~CFileDvdRequest() override { PostCancelRequest(); }
|
~CFileDvdRequest() override { CFileDvdRequest::PostCancelRequest(); }
|
||||||
|
|
||||||
void WaitUntilComplete() override {
|
void WaitUntilComplete() override {
|
||||||
while (!m_complete.load() && !m_cancel.load()) {
|
while (!m_complete.load() && !m_cancel.load()) {
|
||||||
|
@ -32,14 +32,15 @@ public:
|
||||||
m_cancel.store(true);
|
m_cancel.store(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMediaType GetMediaType() const override { return EMediaType::File; }
|
[[nodiscard]] EMediaType GetMediaType() const override { return EMediaType::File; }
|
||||||
|
|
||||||
CFileDvdRequest(CDvdFile& file, void* buf, u32 len, ESeekOrigin whence, int off, std::function<void(u32)>&& cb)
|
CFileDvdRequest(CDvdFile& file, void* buf, u32 len, ESeekOrigin whence, int off, std::function<void(u32)>&& cb)
|
||||||
: m_reader(file.m_reader), m_buf(buf), m_len(len), m_whence(whence), m_offset(off), m_callback(std::move(cb)) {}
|
: m_reader(file.m_reader), m_buf(buf), m_len(len), m_whence(whence), m_offset(off), m_callback(std::move(cb)) {}
|
||||||
|
|
||||||
void DoRequest() {
|
void DoRequest() {
|
||||||
if (m_cancel.load())
|
if (m_cancel.load()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
u32 readLen;
|
u32 readLen;
|
||||||
if (m_whence == ESeekOrigin::Cur && m_offset == 0) {
|
if (m_whence == ESeekOrigin::Cur && m_offset == 0) {
|
||||||
readLen = m_reader->readBytesToBuf(m_buf, m_len);
|
readLen = m_reader->readBytesToBuf(m_buf, m_len);
|
||||||
|
@ -47,8 +48,9 @@ public:
|
||||||
m_reader->seek(m_offset, athena::SeekOrigin(m_whence));
|
m_reader->seek(m_offset, athena::SeekOrigin(m_whence));
|
||||||
readLen = m_reader->readBytesToBuf(m_buf, m_len);
|
readLen = m_reader->readBytesToBuf(m_buf, m_len);
|
||||||
}
|
}
|
||||||
if (m_callback)
|
if (m_callback) {
|
||||||
m_callback(readLen);
|
m_callback(readLen);
|
||||||
|
}
|
||||||
m_complete.store(true);
|
m_complete.store(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -63,21 +65,22 @@ void CDvdFile::WorkerProc() {
|
||||||
logvisor::RegisterThreadName("CDvdFile");
|
logvisor::RegisterThreadName("CDvdFile");
|
||||||
while (m_WorkerRun.load()) {
|
while (m_WorkerRun.load()) {
|
||||||
std::unique_lock<std::mutex> lk(CDvdFile::m_WorkerMutex);
|
std::unique_lock<std::mutex> lk(CDvdFile::m_WorkerMutex);
|
||||||
while (CDvdFile::m_RequestQueue.size()) {
|
while (!CDvdFile::m_RequestQueue.empty()) {
|
||||||
std::vector<std::shared_ptr<IDvdRequest>> swapQueue;
|
std::vector<std::shared_ptr<IDvdRequest>> swapQueue;
|
||||||
swapQueue.swap(CDvdFile::m_RequestQueue);
|
swapQueue.swap(CDvdFile::m_RequestQueue);
|
||||||
lk.unlock();
|
lk.unlock();
|
||||||
std::unique_lock<std::mutex> waitlk(CDvdFile::m_WaitMutex);
|
std::unique_lock<std::mutex> waitlk(CDvdFile::m_WaitMutex);
|
||||||
for (std::shared_ptr<IDvdRequest>& req : swapQueue) {
|
for (std::shared_ptr<IDvdRequest>& req : swapQueue) {
|
||||||
CFileDvdRequest& concreteReq = static_cast<CFileDvdRequest&>(*req);
|
auto& concreteReq = static_cast<CFileDvdRequest&>(*req);
|
||||||
concreteReq.DoRequest();
|
concreteReq.DoRequest();
|
||||||
}
|
}
|
||||||
waitlk.unlock();
|
waitlk.unlock();
|
||||||
swapQueue.clear();
|
swapQueue.clear();
|
||||||
lk.lock();
|
lk.lock();
|
||||||
}
|
}
|
||||||
if (!m_WorkerRun.load())
|
if (!m_WorkerRun.load()) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
m_WorkerCV.wait(lk);
|
m_WorkerCV.wait(lk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,13 +96,16 @@ std::shared_ptr<IDvdRequest> CDvdFile::AsyncSeekRead(void* buf, u32 len, ESeekOr
|
||||||
}
|
}
|
||||||
|
|
||||||
hecl::ProjectPath CDvdFile::ResolvePath(std::string_view path) {
|
hecl::ProjectPath CDvdFile::ResolvePath(std::string_view path) {
|
||||||
auto start = path.begin();
|
const char* start = path.begin();
|
||||||
while (*start == '/') ++start;
|
while (*start == '/') {
|
||||||
|
++start;
|
||||||
|
}
|
||||||
std::string lowerChStr(start, path.end());
|
std::string lowerChStr(start, path.end());
|
||||||
std::transform(lowerChStr.begin(), lowerChStr.end(), lowerChStr.begin(), ::tolower);
|
std::transform(lowerChStr.begin(), lowerChStr.end(), lowerChStr.begin(), ::tolower);
|
||||||
auto search = m_caseInsensitiveMap.find(lowerChStr);
|
auto search = m_caseInsensitiveMap.find(lowerChStr);
|
||||||
if (search == m_caseInsensitiveMap.end())
|
if (search == m_caseInsensitiveMap.end()) {
|
||||||
return {};
|
return {};
|
||||||
|
}
|
||||||
return hecl::ProjectPath(m_DvdRoot, search->second);
|
return hecl::ProjectPath(m_DvdRoot, search->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,19 +126,22 @@ void CDvdFile::RecursiveBuildCaseInsensitiveMap(const hecl::ProjectPath& path, s
|
||||||
void CDvdFile::Initialize(const hecl::ProjectPath& path) {
|
void CDvdFile::Initialize(const hecl::ProjectPath& path) {
|
||||||
m_DvdRoot = path;
|
m_DvdRoot = path;
|
||||||
RecursiveBuildCaseInsensitiveMap(path, path.getAbsolutePathUTF8().length() + 1);
|
RecursiveBuildCaseInsensitiveMap(path, path.getAbsolutePathUTF8().length() + 1);
|
||||||
if (m_WorkerRun.load())
|
if (m_WorkerRun.load()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
m_WorkerRun.store(true);
|
m_WorkerRun.store(true);
|
||||||
m_WorkerThread = std::thread(WorkerProc);
|
m_WorkerThread = std::thread(WorkerProc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDvdFile::Shutdown() {
|
void CDvdFile::Shutdown() {
|
||||||
if (!m_WorkerRun.load())
|
if (!m_WorkerRun.load()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
m_WorkerRun.store(false);
|
m_WorkerRun.store(false);
|
||||||
m_WorkerCV.notify_one();
|
m_WorkerCV.notify_one();
|
||||||
if (m_WorkerThread.joinable())
|
if (m_WorkerThread.joinable()) {
|
||||||
m_WorkerThread.join();
|
m_WorkerThread.join();
|
||||||
|
}
|
||||||
m_RequestQueue.clear();
|
m_RequestQueue.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -664,6 +664,7 @@ void CMain::RefreshGameState() {
|
||||||
}
|
}
|
||||||
|
|
||||||
static logvisor::Module DiscordLog("Discord");
|
static logvisor::Module DiscordLog("Discord");
|
||||||
|
static logvisor::Module MainLog("MP1::CMain");
|
||||||
static const char* DISCORD_APPLICATION_ID = "402571593815031819";
|
static const char* DISCORD_APPLICATION_ID = "402571593815031819";
|
||||||
static int64_t DiscordStartTime;
|
static int64_t DiscordStartTime;
|
||||||
static CAssetId DiscordWorldSTRG;
|
static CAssetId DiscordWorldSTRG;
|
||||||
|
@ -775,6 +776,32 @@ void CMain::Init(const hecl::Runtime::FileStoreManager& storeMgr, hecl::CVarMana
|
||||||
x70_tweaks.RegisterResourceTweaks(m_cvarMgr);
|
x70_tweaks.RegisterResourceTweaks(m_cvarMgr);
|
||||||
AddWorldPaks();
|
AddWorldPaks();
|
||||||
|
|
||||||
|
bool loadedVersion = false;
|
||||||
|
if (CDvdFile::FileExists("version.yaml")) {
|
||||||
|
CDvdFile file("version.yaml");
|
||||||
|
if (file) {
|
||||||
|
std::unique_ptr<u8[]> buf = std::make_unique<u8[]>(file.Length());
|
||||||
|
u32 readLen = file.SyncRead(buf.get(), file.Length());
|
||||||
|
if (readLen == file.Length()) {
|
||||||
|
CMemoryInStream memoryInStream(buf.get(), file.Length());
|
||||||
|
athena::io::FromYAMLStream(m_version, memoryInStream);
|
||||||
|
loadedVersion = true;
|
||||||
|
MainLog.report(logvisor::Level::Info, FMT_STRING("Loaded version info"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (loadedVersion) {
|
||||||
|
if (GetGame() != EGame::MetroidPrime1) {
|
||||||
|
MainLog.report(logvisor::Level::Fatal,
|
||||||
|
FMT_STRING("Attempted to initialize URDE in MP1 mode with non-MP1 data!!!!"));
|
||||||
|
}
|
||||||
|
boo::SystemStringView versionView(GetVersionString());
|
||||||
|
MainLog.report(logvisor::Level::Info, FMT_STRING("Loading data from Metroid Prime version {} from region {}{}"),
|
||||||
|
versionView, char(GetRegion()), IsTrilogy() ? _SYS_STR(" from trilogy") : _SYS_STR(""));
|
||||||
|
} else {
|
||||||
|
MainLog.report(logvisor::Level::Fatal, FMT_STRING("Unable to load version info"));
|
||||||
|
}
|
||||||
|
|
||||||
const auto& args = boo::APP->getArgs();
|
const auto& args = boo::APP->getArgs();
|
||||||
for (auto it = args.begin(); it != args.end(); ++it) {
|
for (auto it = args.begin(); it != args.end(); ++it) {
|
||||||
if (*it == _SYS_STR("--warp") && args.end() - it >= 3) {
|
if (*it == _SYS_STR("--warp") && args.end() - it >= 3) {
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include "Runtime/GuiSys/CTextExecuteBuffer.hpp"
|
#include "Runtime/GuiSys/CTextExecuteBuffer.hpp"
|
||||||
#include "DataSpec/DNAMP1/Tweaks/CTweakPlayer.hpp"
|
#include "DataSpec/DNAMP1/Tweaks/CTweakPlayer.hpp"
|
||||||
#include "DataSpec/DNAMP1/Tweaks/CTweakGame.hpp"
|
#include "DataSpec/DNAMP1/Tweaks/CTweakGame.hpp"
|
||||||
|
#include "DataSpec/DNACommon/URDEVersionInfo.hpp"
|
||||||
#include "hecl/Console.hpp"
|
#include "hecl/Console.hpp"
|
||||||
#include "hecl/CVarCommons.hpp"
|
#include "hecl/CVarCommons.hpp"
|
||||||
|
|
||||||
|
@ -48,6 +49,8 @@ class IObjectStore;
|
||||||
|
|
||||||
namespace MP1 {
|
namespace MP1 {
|
||||||
class CMain;
|
class CMain;
|
||||||
|
using ERegion = DataSpec::ERegion;
|
||||||
|
using EGame = DataSpec::EGame;
|
||||||
|
|
||||||
class CGameGlobalObjects {
|
class CGameGlobalObjects {
|
||||||
friend class CMain;
|
friend class CMain;
|
||||||
|
@ -244,6 +247,7 @@ private:
|
||||||
bool m_firstFrame = true;
|
bool m_firstFrame = true;
|
||||||
using delta_clock = std::chrono::high_resolution_clock;
|
using delta_clock = std::chrono::high_resolution_clock;
|
||||||
std::chrono::time_point<delta_clock> m_prevFrameTime;
|
std::chrono::time_point<delta_clock> m_prevFrameTime;
|
||||||
|
DataSpec::URDEVersionInfo m_version;
|
||||||
|
|
||||||
void InitializeSubsystems();
|
void InitializeSubsystems();
|
||||||
static void InitializeDiscord();
|
static void InitializeDiscord();
|
||||||
|
@ -311,6 +315,13 @@ public:
|
||||||
void ListWorlds(hecl::Console*, const std::vector<std::string>&);
|
void ListWorlds(hecl::Console*, const std::vector<std::string>&);
|
||||||
void Warp(hecl::Console*, const std::vector<std::string>&);
|
void Warp(hecl::Console*, const std::vector<std::string>&);
|
||||||
hecl::Console* Console() const override { return m_console.get(); }
|
hecl::Console* Console() const override { return m_console.get(); }
|
||||||
|
bool IsPAL() const { return m_version.region == ERegion::PAL; }
|
||||||
|
bool IsJapanese() const { return m_version.region == ERegion::NTSC_J; }
|
||||||
|
bool IsUSA() const { return m_version.region == ERegion::NTSC_U; }
|
||||||
|
bool IsTrilogy() const { return m_version.isTrilogy; }
|
||||||
|
ERegion GetRegion() const { return m_version.region; }
|
||||||
|
EGame GetGame() const { return m_version.game; }
|
||||||
|
std::string_view GetVersionString() const { return m_version.version; }
|
||||||
|
|
||||||
int m_warpWorldIdx = -1;
|
int m_warpWorldIdx = -1;
|
||||||
TAreaId m_warpAreaId = 0;
|
TAreaId m_warpAreaId = 0;
|
||||||
|
|
2
hecl
2
hecl
|
@ -1 +1 @@
|
||||||
Subproject commit d208592b2825188940064e462038e2ce90164101
|
Subproject commit a52732d1dea9e8e61a35fc262d46bc0730026ce9
|
Loading…
Reference in New Issue