mirror of https://github.com/AxioDL/metaforce.git
shared resource routing
This commit is contained in:
parent
80cc3cc277
commit
28985165ff
|
@ -202,6 +202,125 @@ typedef struct
|
||||||
const char* fileExt;
|
const char* fileExt;
|
||||||
} ResExtractor;
|
} ResExtractor;
|
||||||
|
|
||||||
|
/* PAKRouter (for detecting shared entry locations) */
|
||||||
|
template <class BRIDGETYPE>
|
||||||
|
class PAKRouter
|
||||||
|
{
|
||||||
|
const HECL::ProjectPath& m_gameWorking;
|
||||||
|
const HECL::ProjectPath& m_gameCooked;
|
||||||
|
HECL::ProjectPath m_sharedWorking;
|
||||||
|
HECL::ProjectPath m_sharedCooked;
|
||||||
|
const BRIDGETYPE* m_pak = nullptr;
|
||||||
|
HECL::ProjectPath m_pakWorking;
|
||||||
|
HECL::ProjectPath m_pakCooked;
|
||||||
|
std::unordered_map<typename BRIDGETYPE::PAKType::IDType, typename BRIDGETYPE::PAKType::Entry*> m_uniqueEntries;
|
||||||
|
std::unordered_map<typename BRIDGETYPE::PAKType::IDType, typename BRIDGETYPE::PAKType::Entry*> m_sharedEntries;
|
||||||
|
public:
|
||||||
|
PAKRouter(const HECL::ProjectPath& working, const HECL::ProjectPath& cooked)
|
||||||
|
: m_gameWorking(working), m_gameCooked(cooked),
|
||||||
|
m_sharedWorking(working, "Shared"), m_sharedCooked(cooked, "Shared") {}
|
||||||
|
void build(const std::vector<BRIDGETYPE>& bridges, std::function<void(float)> progress)
|
||||||
|
{
|
||||||
|
m_uniqueEntries.clear();
|
||||||
|
m_sharedEntries.clear();
|
||||||
|
size_t count = 0;
|
||||||
|
float bridgesSz = bridges.size();
|
||||||
|
for (const BRIDGETYPE& bridge : bridges)
|
||||||
|
{
|
||||||
|
const typename BRIDGETYPE::PAKType& pak = bridge.getPAK();
|
||||||
|
for (const auto& entry : pak.m_idMap)
|
||||||
|
{
|
||||||
|
auto search = m_uniqueEntries.find(entry.first);
|
||||||
|
if (search != m_uniqueEntries.end())
|
||||||
|
{
|
||||||
|
m_uniqueEntries.erase(search);
|
||||||
|
m_sharedEntries.insert(entry);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_uniqueEntries.insert(entry);
|
||||||
|
}
|
||||||
|
progress(++count / bridgesSz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void enterPAKBridge(const BRIDGETYPE& pakBridge)
|
||||||
|
{
|
||||||
|
const std::string& name = pakBridge.getName();
|
||||||
|
HECL::SystemStringView sysName(name);
|
||||||
|
|
||||||
|
HECL::SystemString::const_iterator extit = sysName.sys_str().end() - 4;
|
||||||
|
HECL::SystemString baseName(sysName.sys_str().begin(), extit);
|
||||||
|
|
||||||
|
m_pakWorking.assign(m_gameWorking, baseName);
|
||||||
|
m_pakWorking.makeDir();
|
||||||
|
m_pakCooked.assign(m_gameCooked, baseName);
|
||||||
|
m_pakCooked.makeDir();
|
||||||
|
|
||||||
|
m_pak = &pakBridge;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<HECL::ProjectPath, ResExtractor> getWorking(const typename BRIDGETYPE::PAKType::IDType& id) const
|
||||||
|
{
|
||||||
|
if (!m_pak)
|
||||||
|
LogDNACommon.report(LogVisor::FatalError,
|
||||||
|
"PAKRouter::enterPAKBridge() must be called before PAKRouter::getWorkingPath()");
|
||||||
|
const typename BRIDGETYPE::PAKType& pak = m_pak->getPAK();
|
||||||
|
auto uniqueSearch = m_uniqueEntries.find(id);
|
||||||
|
if (uniqueSearch != m_uniqueEntries.end())
|
||||||
|
{
|
||||||
|
typename BRIDGETYPE::PAKType::Entry* ent = uniqueSearch->second;
|
||||||
|
ResExtractor extractor = BRIDGETYPE::LookupExtractor(*ent);
|
||||||
|
HECL::SystemString entName = pak.bestEntryName(*ent);
|
||||||
|
if (extractor.fileExt)
|
||||||
|
entName += extractor.fileExt;
|
||||||
|
return std::make_pair(HECL::ProjectPath(m_pakWorking, entName),
|
||||||
|
std::move(extractor));
|
||||||
|
}
|
||||||
|
auto sharedSearch = m_sharedEntries.find(id);
|
||||||
|
if (sharedSearch != m_sharedEntries.end())
|
||||||
|
{
|
||||||
|
typename BRIDGETYPE::PAKType::Entry* ent = sharedSearch->second;
|
||||||
|
ResExtractor extractor = BRIDGETYPE::LookupExtractor(*ent);
|
||||||
|
HECL::SystemString entName = pak.bestEntryName(*ent);
|
||||||
|
if (extractor.fileExt)
|
||||||
|
entName += extractor.fileExt;
|
||||||
|
HECL::ProjectPath sharedPath(m_sharedWorking, entName);
|
||||||
|
HECL::ProjectPath uniquePath(m_pakWorking, entName);
|
||||||
|
if (extractor.func)
|
||||||
|
uniquePath.makeLinkTo(sharedPath);
|
||||||
|
m_sharedWorking.makeDir();
|
||||||
|
return std::make_pair(std::move(sharedPath), std::move(extractor));
|
||||||
|
}
|
||||||
|
LogDNACommon.report(LogVisor::FatalError, "Unable to find entry %s", id.toString().c_str());
|
||||||
|
return std::make_pair(HECL::ProjectPath(), ResExtractor());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<HECL::ProjectPath, ResExtractor> getCooked(const typename BRIDGETYPE::PAKType::IDType& id) const
|
||||||
|
{
|
||||||
|
if (!m_pak)
|
||||||
|
LogDNACommon.report(LogVisor::FatalError,
|
||||||
|
"PAKRouter::enterPAKBridge() must be called before PAKRouter::getCookedPath()");
|
||||||
|
const typename BRIDGETYPE::PAKType& pak = m_pak->getPAK();
|
||||||
|
auto uniqueSearch = m_uniqueEntries.find(id);
|
||||||
|
if (uniqueSearch != m_uniqueEntries.end())
|
||||||
|
{
|
||||||
|
typename BRIDGETYPE::PAKType::Entry* ent = uniqueSearch->second;
|
||||||
|
return std::make_pair(HECL::ProjectPath(m_pakCooked, pak.bestEntryName(*ent)),
|
||||||
|
BRIDGETYPE::LookupExtractor(*ent));
|
||||||
|
}
|
||||||
|
auto sharedSearch = m_sharedEntries.find(id);
|
||||||
|
if (sharedSearch != m_sharedEntries.end())
|
||||||
|
{
|
||||||
|
m_sharedCooked.makeDir();
|
||||||
|
typename BRIDGETYPE::PAKType::Entry* ent = sharedSearch->second;
|
||||||
|
return std::make_pair(HECL::ProjectPath(m_sharedCooked, pak.bestEntryName(*ent)),
|
||||||
|
BRIDGETYPE::LookupExtractor(*ent));
|
||||||
|
}
|
||||||
|
LogDNACommon.report(LogVisor::FatalError, "Unable to find entry %s", id.toString().c_str());
|
||||||
|
return std::make_pair(HECL::ProjectPath(), ResExtractor());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/* Resource cooker function */
|
/* Resource cooker function */
|
||||||
typedef std::function<bool(const HECL::ProjectPath&, const HECL::ProjectPath&)> ResCooker;
|
typedef std::function<bool(const HECL::ProjectPath&, const HECL::ProjectPath&)> ResCooker;
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,8 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn, Athena::io::IStreamReade
|
||||||
|
|
||||||
/* Open Py Stream */
|
/* Open Py Stream */
|
||||||
HECL::BlenderConnection::PyOutStream os = conn.beginPythonOut();
|
HECL::BlenderConnection::PyOutStream os = conn.beginPythonOut();
|
||||||
os << "bm = bmesh.new();\n";
|
os << "import bmesh\n";
|
||||||
|
os << "bm = bmesh.new()\n";
|
||||||
|
|
||||||
for (size_t s=0 ; s<head.secCount ; ++s)
|
for (size_t s=0 ; s<head.secCount ; ++s)
|
||||||
{
|
{
|
||||||
|
@ -132,6 +133,7 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn, Athena::io::IStreamReade
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (s < head.secCount - 1)
|
||||||
reader.seek(secStart + head.secSizes[s], Athena::Begin);
|
reader.seek(secStart + head.secSizes[s], Athena::Begin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ struct CMDL
|
||||||
DECL_DNA
|
DECL_DNA
|
||||||
Value<atUint32> magic;
|
Value<atUint32> magic;
|
||||||
Value<atUint32> version;
|
Value<atUint32> version;
|
||||||
struct Flags
|
struct Flags : BigDNA
|
||||||
{
|
{
|
||||||
DECL_DNA
|
DECL_DNA
|
||||||
Value<atUint32> flags;
|
Value<atUint32> flags;
|
||||||
|
@ -31,6 +31,7 @@ struct CMDL
|
||||||
Value<atUint32> secCount;
|
Value<atUint32> secCount;
|
||||||
Value<atUint32> matSetCount;
|
Value<atUint32> matSetCount;
|
||||||
Vector<atUint32, DNA_COUNT(secCount)> secSizes;
|
Vector<atUint32, DNA_COUNT(secCount)> secSizes;
|
||||||
|
Align<32> align;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SurfaceHeader : BigDNA
|
struct SurfaceHeader : BigDNA
|
||||||
|
|
|
@ -18,7 +18,7 @@ struct MaterialSet : BigDNA
|
||||||
Value<atUint32> textureCount;
|
Value<atUint32> textureCount;
|
||||||
Vector<UniqueID32, DNA_COUNT(textureCount)> textureIDs;
|
Vector<UniqueID32, DNA_COUNT(textureCount)> textureIDs;
|
||||||
Value<atUint32> materialCount;
|
Value<atUint32> materialCount;
|
||||||
Vector<UniqueID32, DNA_COUNT(materialCount)> materialEndOffs;
|
Vector<atUint32, DNA_COUNT(materialCount)> materialEndOffs;
|
||||||
} head;
|
} head;
|
||||||
|
|
||||||
struct Material : BigDNA
|
struct Material : BigDNA
|
||||||
|
@ -53,7 +53,7 @@ struct MaterialSet : BigDNA
|
||||||
} flags;
|
} flags;
|
||||||
|
|
||||||
Value<atUint32> textureCount;
|
Value<atUint32> textureCount;
|
||||||
Vector<UniqueID32, DNA_COUNT(textureCount)> texureIdxs;
|
Vector<atUint32, DNA_COUNT(textureCount)> texureIdxs;
|
||||||
struct VAFlags : BigDNA
|
struct VAFlags : BigDNA
|
||||||
{
|
{
|
||||||
DECL_DNA
|
DECL_DNA
|
||||||
|
@ -83,8 +83,8 @@ struct MaterialSet : BigDNA
|
||||||
} vaFlags;
|
} vaFlags;
|
||||||
Value<atUint32> groupIdx;
|
Value<atUint32> groupIdx;
|
||||||
|
|
||||||
Value<atUint32> konstCount;
|
Vector<atUint32, DNA_COUNT(flags.konstValuesEnabled())> konstCount;
|
||||||
Vector<GX::Color, DNA_COUNT(konstCount)> konstColors;
|
Vector<GX::Color, DNA_COUNT(flags.konstValuesEnabled() ? konstCount[0] : 0)> konstColors;
|
||||||
|
|
||||||
/** Slightly modified blend enums in Retro's implementation */
|
/** Slightly modified blend enums in Retro's implementation */
|
||||||
enum BlendFactor
|
enum BlendFactor
|
||||||
|
|
|
@ -59,8 +59,7 @@ ResExtractor PAKBridge::LookupExtractor(const PAK::Entry& entry)
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PAKBridge::extractResources(const HECL::ProjectPath& workingOut,
|
bool PAKBridge::extractResources(const PAKRouter<PAKBridge>& router,
|
||||||
const HECL::ProjectPath& cookedOut,
|
|
||||||
bool force,
|
bool force,
|
||||||
std::function<void(float)> progress)
|
std::function<void(float)> progress)
|
||||||
{
|
{
|
||||||
|
@ -68,26 +67,27 @@ bool PAKBridge::extractResources(const HECL::ProjectPath& workingOut,
|
||||||
for (const std::pair<UniqueID32, PAK::Entry*>& item : m_pak.m_idMap)
|
for (const std::pair<UniqueID32, PAK::Entry*>& item : m_pak.m_idMap)
|
||||||
{
|
{
|
||||||
PAKEntryReadStream s;
|
PAKEntryReadStream s;
|
||||||
ResExtractor extractor = LookupExtractor(*item.second);
|
|
||||||
if (extractor.func)
|
auto cooked = router.getCooked(item.first);
|
||||||
{
|
if (force || cooked.first.getPathType() == HECL::ProjectPath::PT_NONE)
|
||||||
HECL::ProjectPath workPath(workingOut, m_pak.bestEntryName(*item.second) + extractor.fileExt);
|
|
||||||
if (force || workPath.getPathType() == HECL::ProjectPath::PT_NONE)
|
|
||||||
{
|
|
||||||
s = item.second->beginReadStream(m_node);
|
|
||||||
extractor.func(s, workPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
HECL::ProjectPath cookPath(cookedOut, m_pak.bestEntryName(*item.second));
|
|
||||||
if (force || cookPath.getPathType() == HECL::ProjectPath::PT_NONE)
|
|
||||||
{
|
{
|
||||||
if (!s)
|
if (!s)
|
||||||
s = item.second->beginReadStream(m_node);
|
s = item.second->beginReadStream(m_node);
|
||||||
FILE* fout = HECL::Fopen(cookPath.getAbsolutePath().c_str(), _S("wb"));
|
FILE* fout = HECL::Fopen(cooked.first.getAbsolutePath().c_str(), _S("wb"));
|
||||||
fwrite(s.data(), 1, s.length(), fout);
|
fwrite(s.data(), 1, s.length(), fout);
|
||||||
fclose(fout);
|
fclose(fout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto working = router.getWorking(item.first);
|
||||||
|
if (working.second.func)
|
||||||
|
{
|
||||||
|
if (force || working.first.getPathType() == HECL::ProjectPath::PT_NONE)
|
||||||
|
{
|
||||||
|
s = item.second->beginReadStream(m_node);
|
||||||
|
working.second.func(s, working.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
++count;
|
++count;
|
||||||
progress(count / (float)m_pak.m_idMap.size());
|
progress(count / (float)m_pak.m_idMap.size());
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,15 +17,17 @@ class PAKBridge
|
||||||
HECL::Database::Project& m_project;
|
HECL::Database::Project& m_project;
|
||||||
const NOD::DiscBase::IPartition::Node& m_node;
|
const NOD::DiscBase::IPartition::Node& m_node;
|
||||||
PAK m_pak;
|
PAK m_pak;
|
||||||
static ResExtractor LookupExtractor(const PAK::Entry& entry);
|
|
||||||
public:
|
public:
|
||||||
PAKBridge(HECL::Database::Project& project, const NOD::DiscBase::IPartition::Node& node);
|
PAKBridge(HECL::Database::Project& project, const NOD::DiscBase::IPartition::Node& node);
|
||||||
|
static ResExtractor LookupExtractor(const PAK::Entry& entry);
|
||||||
const std::string& getName() const {return m_node.getName();}
|
const std::string& getName() const {return m_node.getName();}
|
||||||
HECL::SystemString getLevelString() const;
|
HECL::SystemString getLevelString() const;
|
||||||
bool extractResources(const HECL::ProjectPath& dirOut,
|
bool extractResources(const PAKRouter<PAKBridge>& router,
|
||||||
const HECL::ProjectPath& cookedOut,
|
|
||||||
bool force,
|
bool force,
|
||||||
std::function<void(float)> progress);
|
std::function<void(float)> progress);
|
||||||
|
|
||||||
|
typedef PAK PAKType;
|
||||||
|
const PAKType& getPAK() const {return m_pak;}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,6 +75,8 @@ struct PAK : BigDNA
|
||||||
/* Otherwise return ID format string */
|
/* Otherwise return ID format string */
|
||||||
return entry.type.toString() + '_' + entry.id.toString();
|
return entry.type.toString() + '_' + entry.id.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef UniqueID32 IDType;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,8 +55,7 @@ ResExtractor PAKBridge::LookupExtractor(const DNAMP1::PAK::Entry& entry)
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PAKBridge::extractResources(const HECL::ProjectPath& workingOut,
|
bool PAKBridge::extractResources(const PAKRouter<PAKBridge>& router,
|
||||||
const HECL::ProjectPath& cookedOut,
|
|
||||||
bool force,
|
bool force,
|
||||||
std::function<void(float)> progress)
|
std::function<void(float)> progress)
|
||||||
{
|
{
|
||||||
|
@ -64,26 +63,27 @@ bool PAKBridge::extractResources(const HECL::ProjectPath& workingOut,
|
||||||
for (const std::pair<UniqueID32, DNAMP1::PAK::Entry*>& item : m_pak.m_idMap)
|
for (const std::pair<UniqueID32, DNAMP1::PAK::Entry*>& item : m_pak.m_idMap)
|
||||||
{
|
{
|
||||||
PAKEntryReadStream s;
|
PAKEntryReadStream s;
|
||||||
ResExtractor extractor = LookupExtractor(*item.second);
|
|
||||||
if (extractor.func)
|
auto cooked = router.getCooked(item.first);
|
||||||
{
|
if (force || cooked.first.getPathType() == HECL::ProjectPath::PT_NONE)
|
||||||
HECL::ProjectPath workPath(workingOut, m_pak.bestEntryName(*item.second) + extractor.fileExt);
|
|
||||||
if (force || workPath.getPathType() == HECL::ProjectPath::PT_NONE)
|
|
||||||
{
|
|
||||||
s = item.second->beginReadStream(m_node);
|
|
||||||
extractor.func(s, workPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
HECL::ProjectPath cookPath(cookedOut, m_pak.bestEntryName(*item.second));
|
|
||||||
if (force || cookPath.getPathType() == HECL::ProjectPath::PT_NONE)
|
|
||||||
{
|
{
|
||||||
if (!s)
|
if (!s)
|
||||||
s = item.second->beginReadStream(m_node);
|
s = item.second->beginReadStream(m_node);
|
||||||
FILE* fout = HECL::Fopen(cookPath.getAbsolutePath().c_str(), _S("wb"));
|
FILE* fout = HECL::Fopen(cooked.first.getAbsolutePath().c_str(), _S("wb"));
|
||||||
fwrite(s.data(), 1, s.length(), fout);
|
fwrite(s.data(), 1, s.length(), fout);
|
||||||
fclose(fout);
|
fclose(fout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto working = router.getWorking(item.first);
|
||||||
|
if (working.second.func)
|
||||||
|
{
|
||||||
|
if (force || working.first.getPathType() == HECL::ProjectPath::PT_NONE)
|
||||||
|
{
|
||||||
|
s = item.second->beginReadStream(m_node);
|
||||||
|
working.second.func(s, working.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
++count;
|
++count;
|
||||||
progress(count / (float)m_pak.m_idMap.size());
|
progress(count / (float)m_pak.m_idMap.size());
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,15 +17,17 @@ class PAKBridge
|
||||||
HECL::Database::Project& m_project;
|
HECL::Database::Project& m_project;
|
||||||
const NOD::DiscBase::IPartition::Node& m_node;
|
const NOD::DiscBase::IPartition::Node& m_node;
|
||||||
DNAMP1::PAK m_pak;
|
DNAMP1::PAK m_pak;
|
||||||
static ResExtractor LookupExtractor(const DNAMP1::PAK::Entry& entry);
|
|
||||||
public:
|
public:
|
||||||
PAKBridge(HECL::Database::Project& project, const NOD::DiscBase::IPartition::Node& node);
|
PAKBridge(HECL::Database::Project& project, const NOD::DiscBase::IPartition::Node& node);
|
||||||
|
static ResExtractor LookupExtractor(const DNAMP1::PAK::Entry& entry);
|
||||||
const std::string& getName() const {return m_node.getName();}
|
const std::string& getName() const {return m_node.getName();}
|
||||||
HECL::SystemString getLevelString() const;
|
HECL::SystemString getLevelString() const;
|
||||||
bool extractResources(const HECL::ProjectPath& dirOut,
|
bool extractResources(const PAKRouter<PAKBridge>& router,
|
||||||
const HECL::ProjectPath& cookedOut,
|
|
||||||
bool force,
|
bool force,
|
||||||
std::function<void(float)> progress);
|
std::function<void(float)> progress);
|
||||||
|
|
||||||
|
typedef DNAMP1::PAK PAKType;
|
||||||
|
const PAKType& getPAK() const {return m_pak;}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,8 +64,7 @@ ResExtractor PAKBridge::LookupExtractor(const PAK::Entry& entry)
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PAKBridge::extractResources(const HECL::ProjectPath& workingOut,
|
bool PAKBridge::extractResources(const PAKRouter<PAKBridge>& router,
|
||||||
const HECL::ProjectPath& cookedOut,
|
|
||||||
bool force,
|
bool force,
|
||||||
std::function<void(float)> progress)
|
std::function<void(float)> progress)
|
||||||
{
|
{
|
||||||
|
@ -73,26 +72,27 @@ bool PAKBridge::extractResources(const HECL::ProjectPath& workingOut,
|
||||||
for (const std::pair<UniqueID64, PAK::Entry*>& item : m_pak.m_idMap)
|
for (const std::pair<UniqueID64, PAK::Entry*>& item : m_pak.m_idMap)
|
||||||
{
|
{
|
||||||
PAKEntryReadStream s;
|
PAKEntryReadStream s;
|
||||||
ResExtractor extractor = LookupExtractor(*item.second);
|
|
||||||
if (extractor.func)
|
auto cooked = router.getCooked(item.first);
|
||||||
{
|
if (force || cooked.first.getPathType() == HECL::ProjectPath::PT_NONE)
|
||||||
HECL::ProjectPath workPath(workingOut, m_pak.bestEntryName(*item.second) + extractor.fileExt);
|
|
||||||
if (force || workPath.getPathType() == HECL::ProjectPath::PT_NONE)
|
|
||||||
{
|
|
||||||
s = item.second->beginReadStream(m_node);
|
|
||||||
extractor.func(s, workPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
HECL::ProjectPath cookPath(cookedOut, m_pak.bestEntryName(*item.second));
|
|
||||||
if (force || cookPath.getPathType() == HECL::ProjectPath::PT_NONE)
|
|
||||||
{
|
{
|
||||||
if (!s)
|
if (!s)
|
||||||
s = item.second->beginReadStream(m_node);
|
s = item.second->beginReadStream(m_node);
|
||||||
FILE* fout = HECL::Fopen(cookPath.getAbsolutePath().c_str(), _S("wb"));
|
FILE* fout = HECL::Fopen(cooked.first.getAbsolutePath().c_str(), _S("wb"));
|
||||||
fwrite(s.data(), 1, s.length(), fout);
|
fwrite(s.data(), 1, s.length(), fout);
|
||||||
fclose(fout);
|
fclose(fout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto working = router.getWorking(item.first);
|
||||||
|
if (working.second.func)
|
||||||
|
{
|
||||||
|
if (force || working.first.getPathType() == HECL::ProjectPath::PT_NONE)
|
||||||
|
{
|
||||||
|
s = item.second->beginReadStream(m_node);
|
||||||
|
working.second.func(s, working.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
++count;
|
++count;
|
||||||
progress(count / (float)m_pak.m_idMap.size());
|
progress(count / (float)m_pak.m_idMap.size());
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,15 +17,17 @@ class PAKBridge
|
||||||
HECL::Database::Project& m_project;
|
HECL::Database::Project& m_project;
|
||||||
const NOD::DiscBase::IPartition::Node& m_node;
|
const NOD::DiscBase::IPartition::Node& m_node;
|
||||||
PAK m_pak;
|
PAK m_pak;
|
||||||
static ResExtractor LookupExtractor(const PAK::Entry& entry);
|
|
||||||
public:
|
public:
|
||||||
PAKBridge(HECL::Database::Project& project, const NOD::DiscBase::IPartition::Node& node);
|
PAKBridge(HECL::Database::Project& project, const NOD::DiscBase::IPartition::Node& node);
|
||||||
|
static ResExtractor LookupExtractor(const PAK::Entry& entry);
|
||||||
const std::string& getName() const {return m_node.getName();}
|
const std::string& getName() const {return m_node.getName();}
|
||||||
HECL::SystemString getLevelString() const;
|
HECL::SystemString getLevelString() const;
|
||||||
bool extractResources(const HECL::ProjectPath& dirOut,
|
bool extractResources(const PAKRouter<PAKBridge>& router,
|
||||||
const HECL::ProjectPath& cookedOut,
|
|
||||||
bool force,
|
bool force,
|
||||||
std::function<void(float)> progress);
|
std::function<void(float)> progress);
|
||||||
|
|
||||||
|
typedef PAK PAKType;
|
||||||
|
const PAKType& getPAK() const {return m_pak;}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,6 +84,8 @@ struct PAK : BigDNA
|
||||||
/* Otherwise return ID format string */
|
/* Otherwise return ID format string */
|
||||||
return entry.type.toString() + '_' + entry.id.toString();
|
return entry.type.toString() + '_' + entry.id.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef UniqueID64 IDType;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,15 @@ struct SpecMP1 : SpecBase
|
||||||
std::vector<DNAMP1::PAKBridge> m_paks;
|
std::vector<DNAMP1::PAKBridge> m_paks;
|
||||||
std::map<std::string, DNAMP1::PAKBridge*, CaseInsensitiveCompare> m_orderedPaks;
|
std::map<std::string, DNAMP1::PAKBridge*, CaseInsensitiveCompare> m_orderedPaks;
|
||||||
|
|
||||||
|
HECL::ProjectPath m_workPath;
|
||||||
|
HECL::ProjectPath m_cookPath;
|
||||||
|
PAKRouter<DNAMP1::PAKBridge> m_pakRouter;
|
||||||
|
|
||||||
|
SpecMP1(HECL::Database::Project& project)
|
||||||
|
: m_workPath(project.getProjectRootPath(), _S("MP1")),
|
||||||
|
m_cookPath(project.getProjectCookedPath(SpecEntMP1), _S("MP1")),
|
||||||
|
m_pakRouter(m_workPath, m_cookPath) {}
|
||||||
|
|
||||||
void buildPaks(HECL::Database::Project& project,
|
void buildPaks(HECL::Database::Project& project,
|
||||||
NOD::DiscBase::IPartition::Node& root,
|
NOD::DiscBase::IPartition::Node& root,
|
||||||
const std::vector<HECL::SystemString>& args,
|
const std::vector<HECL::SystemString>& args,
|
||||||
|
@ -204,39 +213,38 @@ struct SpecMP1 : SpecBase
|
||||||
if (!doMP1)
|
if (!doMP1)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
HECL::ProjectPath mp1WorkPath(project.getProjectRootPath(), "MP1");
|
progress(_S("Indexing PAKs"), 2, 0.0);
|
||||||
mp1WorkPath.makeDir();
|
m_pakRouter.build(m_paks, [&progress](float factor)
|
||||||
progress(_S("MP1 Root"), 2, 0.0);
|
{
|
||||||
|
progress(_S("Indexing PAKs"), 2, factor);
|
||||||
|
});
|
||||||
|
progress(_S("Indexing PAKs"), 2, 1.0);
|
||||||
|
|
||||||
|
m_workPath.makeDir();
|
||||||
|
progress(_S("MP1 Root"), 3, 0.0);
|
||||||
int prog = 0;
|
int prog = 0;
|
||||||
for (const NOD::DiscBase::IPartition::Node* node : m_nonPaks)
|
for (const NOD::DiscBase::IPartition::Node* node : m_nonPaks)
|
||||||
{
|
{
|
||||||
node->extractToDirectory(mp1WorkPath.getAbsolutePath(), force);
|
node->extractToDirectory(m_workPath.getAbsolutePath(), force);
|
||||||
progress(_S("MP1 Root"), 2, prog++ / (float)m_nonPaks.size());
|
progress(_S("MP1 Root"), 3, prog++ / (float)m_nonPaks.size());
|
||||||
}
|
}
|
||||||
progress(_S("MP1 Root"), 2, 1.0);
|
progress(_S("MP1 Root"), 3, 1.0);
|
||||||
|
|
||||||
const HECL::ProjectPath& cookPath = project.getProjectCookedPath(SpecEntMP1);
|
const HECL::ProjectPath& cookPath = project.getProjectCookedPath(SpecEntMP1);
|
||||||
cookPath.makeDir();
|
cookPath.makeDir();
|
||||||
HECL::ProjectPath mp1CookPath(cookPath, "MP1");
|
m_cookPath.makeDir();
|
||||||
mp1CookPath.makeDir();
|
|
||||||
|
|
||||||
int compIdx = 3;
|
int compIdx = 4;
|
||||||
prog = 0;
|
prog = 0;
|
||||||
for (DNAMP1::PAKBridge& pak : m_paks)
|
for (DNAMP1::PAKBridge& pak : m_paks)
|
||||||
{
|
{
|
||||||
|
m_pakRouter.enterPAKBridge(pak);
|
||||||
|
|
||||||
const std::string& name = pak.getName();
|
const std::string& name = pak.getName();
|
||||||
HECL::SystemStringView sysName(name);
|
HECL::SystemStringView sysName(name);
|
||||||
|
|
||||||
std::string::const_iterator extit = name.end() - 4;
|
|
||||||
std::string baseName(name.begin(), extit);
|
|
||||||
|
|
||||||
HECL::ProjectPath pakWorkPath(mp1WorkPath, baseName);
|
|
||||||
pakWorkPath.makeDir();
|
|
||||||
HECL::ProjectPath pakCookPath(mp1CookPath, baseName);
|
|
||||||
pakCookPath.makeDir();
|
|
||||||
|
|
||||||
progress(sysName.sys_str().c_str(), compIdx, 0.0);
|
progress(sysName.sys_str().c_str(), compIdx, 0.0);
|
||||||
pak.extractResources(pakWorkPath, pakCookPath, force,
|
pak.extractResources(m_pakRouter, force,
|
||||||
[&progress, &sysName, &compIdx](float factor)
|
[&progress, &sysName, &compIdx](float factor)
|
||||||
{
|
{
|
||||||
progress(sysName.sys_str().c_str(), compIdx, factor);
|
progress(sysName.sys_str().c_str(), compIdx, factor);
|
||||||
|
@ -288,7 +296,8 @@ HECL::Database::DataSpecEntry SpecEntMP1 =
|
||||||
{
|
{
|
||||||
_S("MP1"),
|
_S("MP1"),
|
||||||
_S("Data specification for original Metroid Prime engine"),
|
_S("Data specification for original Metroid Prime engine"),
|
||||||
[](HECL::Database::DataSpecTool) -> HECL::Database::IDataSpec* {return new struct SpecMP1;}
|
[](HECL::Database::Project& project, HECL::Database::DataSpecTool)
|
||||||
|
-> HECL::Database::IDataSpec* {return new struct SpecMP1(project);}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,15 @@ struct SpecMP2 : SpecBase
|
||||||
std::vector<DNAMP2::PAKBridge> m_paks;
|
std::vector<DNAMP2::PAKBridge> m_paks;
|
||||||
std::map<std::string, DNAMP2::PAKBridge*, CaseInsensitiveCompare> m_orderedPaks;
|
std::map<std::string, DNAMP2::PAKBridge*, CaseInsensitiveCompare> m_orderedPaks;
|
||||||
|
|
||||||
|
HECL::ProjectPath m_workPath;
|
||||||
|
HECL::ProjectPath m_cookPath;
|
||||||
|
PAKRouter<DNAMP2::PAKBridge> m_pakRouter;
|
||||||
|
|
||||||
|
SpecMP2(HECL::Database::Project& project)
|
||||||
|
: m_workPath(project.getProjectRootPath(), _S("MP2")),
|
||||||
|
m_cookPath(project.getProjectCookedPath(SpecEntMP2), _S("MP2")),
|
||||||
|
m_pakRouter(m_workPath, m_cookPath) {}
|
||||||
|
|
||||||
void buildPaks(HECL::Database::Project& project,
|
void buildPaks(HECL::Database::Project& project,
|
||||||
NOD::DiscBase::IPartition::Node& root,
|
NOD::DiscBase::IPartition::Node& root,
|
||||||
const std::vector<HECL::SystemString>& args,
|
const std::vector<HECL::SystemString>& args,
|
||||||
|
@ -201,39 +210,38 @@ struct SpecMP2 : SpecBase
|
||||||
if (!doMP2)
|
if (!doMP2)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
HECL::ProjectPath mp2WorkPath(project.getProjectRootPath(), "MP2");
|
progress(_S("Indexing PAKs"), 2, 0.0);
|
||||||
mp2WorkPath.makeDir();
|
m_pakRouter.build(m_paks, [&progress](float factor)
|
||||||
progress(_S("MP2 Root"), 2, 0.0);
|
{
|
||||||
|
progress(_S("Indexing PAKs"), 2, factor);
|
||||||
|
});
|
||||||
|
progress(_S("Indexing PAKs"), 2, 1.0);
|
||||||
|
|
||||||
|
m_workPath.makeDir();
|
||||||
|
progress(_S("MP2 Root"), 3, 0.0);
|
||||||
int prog = 0;
|
int prog = 0;
|
||||||
for (const NOD::DiscBase::IPartition::Node* node : m_nonPaks)
|
for (const NOD::DiscBase::IPartition::Node* node : m_nonPaks)
|
||||||
{
|
{
|
||||||
node->extractToDirectory(mp2WorkPath.getAbsolutePath(), force);
|
node->extractToDirectory(m_workPath.getAbsolutePath(), force);
|
||||||
progress(_S("MP2 Root"), 2, prog++ / (float)m_nonPaks.size());
|
progress(_S("MP2 Root"), 3, prog++ / (float)m_nonPaks.size());
|
||||||
}
|
}
|
||||||
progress(_S("MP2 Root"), 2, 1.0);
|
progress(_S("MP2 Root"), 3, 1.0);
|
||||||
|
|
||||||
const HECL::ProjectPath& cookPath = project.getProjectCookedPath(SpecEntMP2);
|
const HECL::ProjectPath& cookPath = project.getProjectCookedPath(SpecEntMP2);
|
||||||
cookPath.makeDir();
|
cookPath.makeDir();
|
||||||
HECL::ProjectPath mp2CookPath(cookPath, "MP2");
|
m_cookPath.makeDir();
|
||||||
mp2CookPath.makeDir();
|
|
||||||
|
|
||||||
int compIdx = 3;
|
int compIdx = 4;
|
||||||
prog = 0;
|
prog = 0;
|
||||||
for (DNAMP2::PAKBridge& pak : m_paks)
|
for (DNAMP2::PAKBridge& pak : m_paks)
|
||||||
{
|
{
|
||||||
|
m_pakRouter.enterPAKBridge(pak);
|
||||||
|
|
||||||
const std::string& name = pak.getName();
|
const std::string& name = pak.getName();
|
||||||
HECL::SystemStringView sysName(name);
|
HECL::SystemStringView sysName(name);
|
||||||
|
|
||||||
std::string::const_iterator extit = name.end() - 4;
|
|
||||||
std::string baseName(name.begin(), extit);
|
|
||||||
|
|
||||||
HECL::ProjectPath pakWorkPath(mp2WorkPath, baseName);
|
|
||||||
pakWorkPath.makeDir();
|
|
||||||
HECL::ProjectPath pakCookPath(mp2CookPath, baseName);
|
|
||||||
pakCookPath.makeDir();
|
|
||||||
|
|
||||||
progress(sysName.sys_str().c_str(), compIdx, 0.0);
|
progress(sysName.sys_str().c_str(), compIdx, 0.0);
|
||||||
pak.extractResources(pakWorkPath, pakCookPath, force,
|
pak.extractResources(m_pakRouter, force,
|
||||||
[&progress, &sysName, &compIdx](float factor)
|
[&progress, &sysName, &compIdx](float factor)
|
||||||
{
|
{
|
||||||
progress(sysName.sys_str().c_str(), compIdx, factor);
|
progress(sysName.sys_str().c_str(), compIdx, factor);
|
||||||
|
@ -285,7 +293,8 @@ HECL::Database::DataSpecEntry SpecEntMP2
|
||||||
(
|
(
|
||||||
_S("MP2"),
|
_S("MP2"),
|
||||||
_S("Data specification for original Metroid Prime 2 engine"),
|
_S("Data specification for original Metroid Prime 2 engine"),
|
||||||
[](HECL::Database::DataSpecTool tool) -> HECL::Database::IDataSpec* {return new struct SpecMP2;}
|
[](HECL::Database::Project& project, HECL::Database::DataSpecTool)
|
||||||
|
-> HECL::Database::IDataSpec* {return new struct SpecMP2(project);}
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,12 +24,28 @@ struct SpecMP3 : SpecBase
|
||||||
std::vector<DNAMP3::PAKBridge> m_paks;
|
std::vector<DNAMP3::PAKBridge> m_paks;
|
||||||
std::map<std::string, DNAMP3::PAKBridge*, CaseInsensitiveCompare> m_orderedPaks;
|
std::map<std::string, DNAMP3::PAKBridge*, CaseInsensitiveCompare> m_orderedPaks;
|
||||||
|
|
||||||
|
HECL::ProjectPath m_workPath;
|
||||||
|
HECL::ProjectPath m_cookPath;
|
||||||
|
PAKRouter<DNAMP3::PAKBridge> m_pakRouter;
|
||||||
|
|
||||||
/* These are populated when extracting MPT's frontend (uses MP3's DataSpec) */
|
/* These are populated when extracting MPT's frontend (uses MP3's DataSpec) */
|
||||||
bool doMPTFE = false;
|
bool doMPTFE = false;
|
||||||
std::vector<const NOD::DiscBase::IPartition::Node*> m_feNonPaks;
|
std::vector<const NOD::DiscBase::IPartition::Node*> m_feNonPaks;
|
||||||
std::vector<DNAMP3::PAKBridge> m_fePaks;
|
std::vector<DNAMP3::PAKBridge> m_fePaks;
|
||||||
std::map<std::string, DNAMP3::PAKBridge*, CaseInsensitiveCompare> m_feOrderedPaks;
|
std::map<std::string, DNAMP3::PAKBridge*, CaseInsensitiveCompare> m_feOrderedPaks;
|
||||||
|
|
||||||
|
HECL::ProjectPath m_feWorkPath;
|
||||||
|
HECL::ProjectPath m_feCookPath;
|
||||||
|
PAKRouter<DNAMP3::PAKBridge> m_fePakRouter;
|
||||||
|
|
||||||
|
SpecMP3(HECL::Database::Project& project)
|
||||||
|
: m_workPath(project.getProjectRootPath(), _S("MP3")),
|
||||||
|
m_cookPath(project.getProjectCookedPath(SpecEntMP3), _S("MP3")),
|
||||||
|
m_pakRouter(m_workPath, m_cookPath),
|
||||||
|
m_feWorkPath(project.getProjectRootPath(), _S("fe")),
|
||||||
|
m_feCookPath(project.getProjectCookedPath(SpecEntMP3), _S("fe")),
|
||||||
|
m_fePakRouter(m_feWorkPath, m_feCookPath) {}
|
||||||
|
|
||||||
void buildPaks(HECL::Database::Project& project,
|
void buildPaks(HECL::Database::Project& project,
|
||||||
NOD::DiscBase::IPartition::Node& root,
|
NOD::DiscBase::IPartition::Node& root,
|
||||||
const std::vector<HECL::SystemString>& args,
|
const std::vector<HECL::SystemString>& args,
|
||||||
|
@ -295,6 +311,13 @@ struct SpecMP3 : SpecBase
|
||||||
int prog;
|
int prog;
|
||||||
if (doMP3)
|
if (doMP3)
|
||||||
{
|
{
|
||||||
|
progress(_S("Indexing PAKs"), compIdx, 0.0);
|
||||||
|
m_pakRouter.build(m_paks, [&progress, &compIdx](float factor)
|
||||||
|
{
|
||||||
|
progress(_S("Indexing PAKs"), compIdx, factor);
|
||||||
|
});
|
||||||
|
progress(_S("Indexing PAKs"), compIdx++, 1.0);
|
||||||
|
|
||||||
HECL::ProjectPath mp3WorkPath(project.getProjectRootPath(), "MP3");
|
HECL::ProjectPath mp3WorkPath(project.getProjectRootPath(), "MP3");
|
||||||
mp3WorkPath.makeDir();
|
mp3WorkPath.makeDir();
|
||||||
progress(_S("MP3 Root"), compIdx, 0.0);
|
progress(_S("MP3 Root"), compIdx, 0.0);
|
||||||
|
@ -314,19 +337,13 @@ struct SpecMP3 : SpecBase
|
||||||
prog = 0;
|
prog = 0;
|
||||||
for (DNAMP3::PAKBridge& pak : m_paks)
|
for (DNAMP3::PAKBridge& pak : m_paks)
|
||||||
{
|
{
|
||||||
|
m_pakRouter.enterPAKBridge(pak);
|
||||||
|
|
||||||
const std::string& name = pak.getName();
|
const std::string& name = pak.getName();
|
||||||
HECL::SystemStringView sysName(name);
|
HECL::SystemStringView sysName(name);
|
||||||
|
|
||||||
std::string::const_iterator extit = name.end() - 4;
|
|
||||||
std::string baseName(name.begin(), extit);
|
|
||||||
|
|
||||||
HECL::ProjectPath pakWorkPath(mp3WorkPath, baseName);
|
|
||||||
pakWorkPath.makeDir();
|
|
||||||
HECL::ProjectPath pakCookPath(mp3CookPath, baseName);
|
|
||||||
pakCookPath.makeDir();
|
|
||||||
|
|
||||||
progress(sysName.sys_str().c_str(), compIdx, 0.0);
|
progress(sysName.sys_str().c_str(), compIdx, 0.0);
|
||||||
pak.extractResources(pakWorkPath, pakCookPath, force,
|
pak.extractResources(m_pakRouter, force,
|
||||||
[&progress, &sysName, &compIdx](float factor)
|
[&progress, &sysName, &compIdx](float factor)
|
||||||
{
|
{
|
||||||
progress(sysName.sys_str().c_str(), compIdx, factor);
|
progress(sysName.sys_str().c_str(), compIdx, factor);
|
||||||
|
@ -337,38 +354,37 @@ struct SpecMP3 : SpecBase
|
||||||
|
|
||||||
if (doMPTFE)
|
if (doMPTFE)
|
||||||
{
|
{
|
||||||
HECL::ProjectPath feWorkPath(project.getProjectRootPath(), "fe");
|
progress(_S("Indexing PAKs"), compIdx, 0.0);
|
||||||
feWorkPath.makeDir();
|
m_fePakRouter.build(m_fePaks, [&progress, &compIdx](float factor)
|
||||||
|
{
|
||||||
|
progress(_S("Indexing PAKs"), compIdx, factor);
|
||||||
|
});
|
||||||
|
progress(_S("Indexing PAKs"), compIdx++, 1.0);
|
||||||
|
|
||||||
|
m_feWorkPath.makeDir();
|
||||||
progress(_S("fe Root"), compIdx, 0.0);
|
progress(_S("fe Root"), compIdx, 0.0);
|
||||||
int prog = 0;
|
int prog = 0;
|
||||||
for (const NOD::DiscBase::IPartition::Node* node : m_nonPaks)
|
for (const NOD::DiscBase::IPartition::Node* node : m_feNonPaks)
|
||||||
{
|
{
|
||||||
node->extractToDirectory(feWorkPath.getAbsolutePath(), force);
|
node->extractToDirectory(m_feWorkPath.getAbsolutePath(), force);
|
||||||
progress(_S("fe Root"), compIdx, prog++ / (float)m_nonPaks.size());
|
progress(_S("fe Root"), compIdx, prog++ / (float)m_feNonPaks.size());
|
||||||
}
|
}
|
||||||
progress(_S("fe Root"), compIdx++, 1.0);
|
progress(_S("fe Root"), compIdx++, 1.0);
|
||||||
|
|
||||||
const HECL::ProjectPath& cookPath = project.getProjectCookedPath(SpecEntMP3);
|
const HECL::ProjectPath& cookPath = project.getProjectCookedPath(SpecEntMP3);
|
||||||
cookPath.makeDir();
|
cookPath.makeDir();
|
||||||
HECL::ProjectPath feCookPath(cookPath, "fe");
|
m_feCookPath.makeDir();
|
||||||
feCookPath.makeDir();
|
|
||||||
|
|
||||||
prog = 0;
|
prog = 0;
|
||||||
for (DNAMP3::PAKBridge& pak : m_fePaks)
|
for (DNAMP3::PAKBridge& pak : m_fePaks)
|
||||||
{
|
{
|
||||||
|
m_fePakRouter.enterPAKBridge(pak);
|
||||||
|
|
||||||
const std::string& name = pak.getName();
|
const std::string& name = pak.getName();
|
||||||
HECL::SystemStringView sysName(name);
|
HECL::SystemStringView sysName(name);
|
||||||
|
|
||||||
std::string::const_iterator extit = name.end() - 4;
|
|
||||||
std::string baseName(name.begin(), extit);
|
|
||||||
|
|
||||||
HECL::ProjectPath pakWorkPath(feWorkPath, baseName);
|
|
||||||
pakWorkPath.makeDir();
|
|
||||||
HECL::ProjectPath pakCookPath(feCookPath, baseName);
|
|
||||||
pakCookPath.makeDir();
|
|
||||||
|
|
||||||
progress(sysName.sys_str().c_str(), compIdx, 0.0);
|
progress(sysName.sys_str().c_str(), compIdx, 0.0);
|
||||||
pak.extractResources(pakWorkPath, pakCookPath, force,
|
pak.extractResources(m_fePakRouter, force,
|
||||||
[&progress, &sysName, &compIdx](float factor)
|
[&progress, &sysName, &compIdx](float factor)
|
||||||
{
|
{
|
||||||
progress(sysName.sys_str().c_str(), compIdx, factor);
|
progress(sysName.sys_str().c_str(), compIdx, factor);
|
||||||
|
@ -421,7 +437,8 @@ HECL::Database::DataSpecEntry SpecEntMP3
|
||||||
(
|
(
|
||||||
_S("MP3"),
|
_S("MP3"),
|
||||||
_S("Data specification for original Metroid Prime 3 engine"),
|
_S("Data specification for original Metroid Prime 3 engine"),
|
||||||
[](HECL::Database::DataSpecTool tool) -> HECL::Database::IDataSpec* {return new struct SpecMP3;}
|
[](HECL::Database::Project& project, HECL::Database::DataSpecTool)
|
||||||
|
-> HECL::Database::IDataSpec* {return new struct SpecMP3(project);}
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1,7 @@
|
||||||
#include "CRandom16.hpp"
|
#include "CRandom16.hpp"
|
||||||
|
|
||||||
|
namespace Retro
|
||||||
|
{
|
||||||
|
CRandom16* GLOBAL_RANDOM = nullptr;
|
||||||
|
CGlobalRandom* GLOBAL_RANDOM_TOKEN = nullptr;
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
#define RETRO_CRANDOM16_HPP
|
#define RETRO_CRANDOM16_HPP
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "CRandom16.hpp"
|
|
||||||
|
|
||||||
namespace Retro
|
namespace Retro
|
||||||
{
|
{
|
||||||
|
@ -44,10 +43,10 @@ public:
|
||||||
|
|
||||||
inline int32_t Range(int32_t min, int32_t max)
|
inline int32_t Range(int32_t min, int32_t max)
|
||||||
{
|
{
|
||||||
uint32_t diff = max - min;
|
int64_t diff = max - min;
|
||||||
uint32_t rand = 0xffffffff;
|
int64_t rand = -1;
|
||||||
while (rand == 0xffffffff)
|
while (rand < 0)
|
||||||
rand = (Next() << 16) | Next();
|
rand = int32_t((Next() << 16) | Next());
|
||||||
return rand % diff + min;
|
return rand % diff + min;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue