2
0
mirror of https://github.com/AxioDL/metaforce.git synced 2025-05-31 16:01:20 +00:00
Lioncash 7f7a18a708 DataSpec/DNACommon: Resolve indirect includes where applicable
Avoids indirect inclusions where applicable and includes the necessary
headers as used by the interface. This way, it prevents code from
failing to compile due to changes in other header inclusions.
2019-08-23 22:03:03 -04:00

679 lines
25 KiB
C++

#include "DataSpec/DNACommon/PAK.hpp"
#include "DataSpec/DNAMP1/DNAMP1.hpp"
#include "DataSpec/DNAMP2/DNAMP2.hpp"
#include "DataSpec/DNAMP3/DNAMP3.hpp"
namespace DataSpec {
template <class PAKBRIDGE>
void UniqueResult::checkEntry(const PAKBRIDGE& pakBridge, const typename PAKBRIDGE::PAKType::Entry& entry) {
UniqueResult::Type resultType = UniqueResult::Type::NotFound;
bool foundOneLayer = false;
const hecl::SystemString* levelName = nullptr;
typename PAKBRIDGE::PAKType::IDType levelId;
typename PAKBRIDGE::PAKType::IDType areaId;
unsigned layerIdx;
for (const auto& lpair : pakBridge.m_levelDeps) {
if (entry.id == lpair.first) {
levelName = &lpair.second.name;
resultType = UniqueResult::Type::Level;
break;
}
for (const auto& pair : lpair.second.areas) {
unsigned l = 0;
for (const auto& layer : pair.second.layers) {
if (layer.resources.find(entry.id) != layer.resources.end()) {
if (foundOneLayer) {
if (areaId == pair.first) {
resultType = UniqueResult::Type::Area;
} else if (levelId == lpair.first) {
resultType = UniqueResult::Type::Level;
break;
} else {
m_type = UniqueResult::Type::Pak;
return;
}
continue;
} else
resultType = UniqueResult::Type::Layer;
levelName = &lpair.second.name;
levelId = lpair.first;
areaId = pair.first;
layerIdx = l;
foundOneLayer = true;
}
++l;
}
if (pair.second.resources.find(entry.id) != pair.second.resources.end()) {
if (foundOneLayer) {
if (areaId == pair.first) {
resultType = UniqueResult::Type::Area;
} else if (levelId == lpair.first) {
resultType = UniqueResult::Type::Level;
break;
} else {
m_type = UniqueResult::Type::Pak;
return;
}
continue;
} else
resultType = UniqueResult::Type::Area;
levelName = &lpair.second.name;
levelId = lpair.first;
areaId = pair.first;
foundOneLayer = true;
}
}
}
m_type = resultType;
m_levelName = levelName;
if (resultType == UniqueResult::Type::Layer || resultType == UniqueResult::Type::Area) {
const typename PAKBRIDGE::Level::Area& area = pakBridge.m_levelDeps.at(levelId).areas.at(areaId);
m_areaName = &area.name;
if (resultType == UniqueResult::Type::Layer) {
const typename PAKBRIDGE::Level::Area::Layer& layer = area.layers[layerIdx];
m_layerName = &layer.name;
}
}
}
template void UniqueResult::checkEntry(const DNAMP1::PAKBridge& pakBridge,
const DNAMP1::PAKBridge::PAKType::Entry& entry);
template void UniqueResult::checkEntry(const DNAMP2::PAKBridge& pakBridge,
const DNAMP2::PAKBridge::PAKType::Entry& entry);
template void UniqueResult::checkEntry(const DNAMP3::PAKBridge& pakBridge,
const DNAMP3::PAKBridge::PAKType::Entry& entry);
hecl::ProjectPath UniqueResult::uniquePath(const hecl::ProjectPath& pakPath) const {
if (m_type == Type::Pak)
return pakPath;
hecl::ProjectPath levelDir;
if (m_levelName)
levelDir.assign(pakPath, *m_levelName);
else
levelDir = pakPath;
if (m_type == Type::Area) {
hecl::ProjectPath areaDir(levelDir, *m_areaName);
return areaDir;
} else if (m_type == Type::Layer) {
hecl::ProjectPath areaDir(levelDir, *m_areaName);
hecl::ProjectPath layerDir(areaDir, *m_layerName);
return layerDir;
}
return levelDir;
}
template <class BRIDGETYPE>
void PAKRouter<BRIDGETYPE>::build(std::vector<BRIDGETYPE>& bridges, std::function<void(float)> progress) {
m_bridges = &bridges;
m_bridgePaths.clear();
m_uniqueEntries.clear();
m_sharedEntries.clear();
m_charAssoc.m_cmdlRigs.clear();
size_t count = 0;
float bridgesSz = bridges.size();
/* Route entries unique/shared per-pak */
size_t bridgeIdx = 0;
for (BRIDGETYPE& bridge : bridges) {
const auto& name = bridge.getName();
hecl::SystemStringConv sysName(name);
hecl::SystemStringView::const_iterator extit = sysName.sys_str().end() - 4;
hecl::SystemString baseName(sysName.sys_str().begin(), extit);
m_bridgePaths.emplace_back(
std::make_pair(hecl::ProjectPath(m_gameWorking, baseName), hecl::ProjectPath(m_gameCooked, baseName)));
/* Index this PAK */
bridge.build();
/* Add to global entry lookup */
const typename BRIDGETYPE::PAKType& pak = bridge.getPAK();
for (const auto& entry : pak.m_entries) {
if (!pak.m_noShare) {
auto sSearch = m_sharedEntries.find(entry.first);
if (sSearch != m_sharedEntries.end())
continue;
auto uSearch = m_uniqueEntries.find(entry.first);
if (uSearch != m_uniqueEntries.end()) {
m_uniqueEntries.erase(uSearch);
m_sharedEntries[entry.first] = std::make_pair(bridgeIdx, &entry.second);
} else
m_uniqueEntries[entry.first] = std::make_pair(bridgeIdx, &entry.second);
} else
m_uniqueEntries[entry.first] = std::make_pair(bridgeIdx, &entry.second);
}
/* Add RigPairs to global map */
bridge.addCMDLRigPairs(*this, m_charAssoc);
progress(++count / bridgesSz);
++bridgeIdx;
}
/* Add named resources to catalog YAML files */
for (BRIDGETYPE& bridge : bridges) {
athena::io::YAMLDocWriter catalogWriter(nullptr);
enterPAKBridge(bridge);
/* Add MAPA transforms to global map */
bridge.addMAPATransforms(*this, m_mapaTransforms, m_overrideEntries);
const typename BRIDGETYPE::PAKType& pak = bridge.getPAK();
for (const auto& namedEntry : pak.m_nameEntries) {
if (namedEntry.name == "holo_cinf")
continue; /* Problematic corner case */
if (auto rec = catalogWriter.enterSubRecord(namedEntry.name.c_str())) {
hecl::ProjectPath working = getWorking(namedEntry.id);
if (working.getAuxInfoUTF8().size()) {
if (auto v = catalogWriter.enterSubVector(nullptr)) {
catalogWriter.writeString(nullptr, working.getRelativePathUTF8());
catalogWriter.writeString(nullptr, working.getAuxInfoUTF8());
}
} else
catalogWriter.writeString(nullptr, working.getRelativePathUTF8());
}
}
/* Write catalog */
intptr_t curBridgeIdx = reinterpret_cast<intptr_t>(m_curBridgeIdx.get());
const hecl::ProjectPath& pakPath = m_bridgePaths[curBridgeIdx].first;
pakPath.makeDirChain(true);
athena::io::FileWriter writer(hecl::ProjectPath(pakPath, "!catalog.yaml").getAbsolutePath());
catalogWriter.finish(&writer);
}
}
template <class BRIDGETYPE>
void PAKRouter<BRIDGETYPE>::enterPAKBridge(const BRIDGETYPE& pakBridge) {
g_PakRouter.reset(this);
auto pit = m_bridgePaths.begin();
size_t bridgeIdx = 0;
for (const BRIDGETYPE& bridge : *m_bridges) {
if (&bridge == &pakBridge) {
m_pak.reset(&pakBridge.getPAK());
m_node.reset(&pakBridge.getNode());
m_curBridgeIdx.reset(reinterpret_cast<void*>(bridgeIdx));
return;
}
++pit;
++bridgeIdx;
}
LogDNACommon.report(logvisor::Fatal, fmt("PAKBridge provided to PAKRouter::enterPAKBridge() was not part of build()"));
}
template <class BRIDGETYPE>
hecl::ProjectPath PAKRouter<BRIDGETYPE>::getCharacterWorking(const EntryType* entry) const {
auto characterSearch = m_charAssoc.m_cskrCinfToCharacter.find(entry->id);
if (characterSearch != m_charAssoc.m_cskrCinfToCharacter.cend()) {
hecl::ProjectPath characterPath = getWorking(characterSearch->second.first);
if (entry->type == FOURCC('EVNT')) {
hecl::SystemStringConv wideStr(characterSearch->second.second);
return characterPath.getWithExtension((hecl::SystemString(_SYS_STR(".")) + wideStr.c_str()).c_str(), true);
}
return characterPath.ensureAuxInfo(characterSearch->second.second);
}
return {};
}
template <class BRIDGETYPE>
hecl::ProjectPath PAKRouter<BRIDGETYPE>::getWorking(const EntryType* entry,
const ResExtractor<BRIDGETYPE>& extractor) const {
if (!entry)
return hecl::ProjectPath();
auto overrideSearch = m_overrideEntries.find(entry->id);
if (overrideSearch != m_overrideEntries.end())
return overrideSearch->second;
const PAKType* pak = m_pak.get();
intptr_t curBridgeIdx = reinterpret_cast<intptr_t>(m_curBridgeIdx.get());
if (pak && pak->m_noShare) {
const EntryType* singleSearch = pak->lookupEntry(entry->id);
if (singleSearch) {
const hecl::ProjectPath& pakPath = m_bridgePaths[curBridgeIdx].first;
#if HECL_UCS2
hecl::SystemString entName = hecl::UTF8ToWide(getBestEntryName(*entry));
#else
hecl::SystemString entName = getBestEntryName(*entry);
#endif
hecl::SystemString auxInfo;
if (extractor.fileExts[0] && !extractor.fileExts[1])
entName += extractor.fileExts[0];
else if (extractor.fileExts[0])
entName += _SYS_STR(".*");
else if (hecl::ProjectPath chWork = getCharacterWorking(entry))
return chWork;
return hecl::ProjectPath(pakPath, entName).ensureAuxInfo(auxInfo);
}
}
auto uniqueSearch = m_uniqueEntries.find(entry->id);
if (uniqueSearch != m_uniqueEntries.end()) {
const BRIDGETYPE& bridge = m_bridges->at(uniqueSearch->second.first);
const hecl::ProjectPath& pakPath = m_bridgePaths[uniqueSearch->second.first].first;
#if HECL_UCS2
hecl::SystemString entName = hecl::UTF8ToWide(getBestEntryName(*entry));
#else
hecl::SystemString entName = getBestEntryName(*entry);
#endif
hecl::SystemString auxInfo;
if (extractor.fileExts[0] && !extractor.fileExts[1])
entName += extractor.fileExts[0];
else if (extractor.fileExts[0])
entName += _SYS_STR(".*");
else if (hecl::ProjectPath chWork = getCharacterWorking(entry))
return chWork;
if (bridge.getPAK().m_noShare) {
return hecl::ProjectPath(pakPath, entName).ensureAuxInfo(auxInfo);
} else {
hecl::ProjectPath uniquePath = entry->unique.uniquePath(pakPath);
return hecl::ProjectPath(uniquePath, entName).ensureAuxInfo(auxInfo);
}
}
auto sharedSearch = m_sharedEntries.find(entry->id);
if (sharedSearch != m_sharedEntries.end()) {
#if HECL_UCS2
hecl::SystemString entBase = hecl::UTF8ToWide(getBestEntryName(*entry));
#else
hecl::SystemString entBase = getBestEntryName(*entry);
#endif
hecl::SystemString auxInfo;
hecl::SystemString entName = entBase;
if (extractor.fileExts[0] && !extractor.fileExts[1])
entName += extractor.fileExts[0];
else if (extractor.fileExts[0])
entName += _SYS_STR(".*");
else if (hecl::ProjectPath chWork = getCharacterWorking(entry))
return chWork;
hecl::ProjectPath sharedPath(m_sharedWorking, entName);
return sharedPath.ensureAuxInfo(auxInfo);
}
LogDNACommon.report(logvisor::Fatal, fmt("Unable to find entry {}"), entry->id);
return hecl::ProjectPath();
}
template <class BRIDGETYPE>
hecl::ProjectPath PAKRouter<BRIDGETYPE>::getWorking(const EntryType* entry) const {
if (!entry)
return hecl::ProjectPath();
return getWorking(entry, BRIDGETYPE::LookupExtractor(*m_node.get(), *m_pak.get(), *entry));
}
template <class BRIDGETYPE>
hecl::ProjectPath PAKRouter<BRIDGETYPE>::getWorking(const IDType& id, bool silenceWarnings) const {
return getWorking(lookupEntry(id, nullptr, silenceWarnings, false));
}
template <class BRIDGETYPE>
hecl::ProjectPath PAKRouter<BRIDGETYPE>::getCooked(const EntryType* entry) const {
if (!entry)
return hecl::ProjectPath();
auto overrideSearch = m_overrideEntries.find(entry->id);
if (overrideSearch != m_overrideEntries.end()) {
return overrideSearch->second.getCookedPath(*m_dataSpec.overrideDataSpec(
overrideSearch->second, m_dataSpec.getDataSpecEntry()));
}
const PAKType* pak = m_pak.get();
intptr_t curBridgeIdx = reinterpret_cast<intptr_t>(m_curBridgeIdx.get());
if (pak && pak->m_noShare) {
const EntryType* singleSearch = pak->lookupEntry(entry->id);
if (singleSearch) {
const hecl::ProjectPath& pakPath = m_bridgePaths[curBridgeIdx].second;
return hecl::ProjectPath(pakPath, getBestEntryName(*entry));
}
}
auto uniqueSearch = m_uniqueEntries.find(entry->id);
if (uniqueSearch != m_uniqueEntries.end()) {
const BRIDGETYPE& bridge = m_bridges->at(uniqueSearch->second.first);
const hecl::ProjectPath& pakPath = m_bridgePaths[uniqueSearch->second.first].second;
if (bridge.getPAK().m_noShare) {
return hecl::ProjectPath(pakPath, getBestEntryName(*entry));
} else {
hecl::ProjectPath uniquePath = entry->unique.uniquePath(pakPath);
return hecl::ProjectPath(uniquePath, getBestEntryName(*entry));
}
}
auto sharedSearch = m_sharedEntries.find(entry->id);
if (sharedSearch != m_sharedEntries.end()) {
return hecl::ProjectPath(m_sharedCooked, getBestEntryName(*entry));
}
LogDNACommon.report(logvisor::Fatal, fmt("Unable to find entry {}"), entry->id);
return hecl::ProjectPath();
}
template <class BRIDGETYPE>
hecl::ProjectPath PAKRouter<BRIDGETYPE>::getCooked(const IDType& id, bool silenceWarnings) const {
return getCooked(lookupEntry(id, nullptr, silenceWarnings, false));
}
template <class BRIDGETYPE>
hecl::SystemString PAKRouter<BRIDGETYPE>::getResourceRelativePath(const EntryType& a, const IDType& b) const {
const nod::Node* node = m_node.get();
const PAKType* pak = m_pak.get();
if (!pak)
LogDNACommon.report(logvisor::Fatal,
fmt("PAKRouter::enterPAKBridge() must be called before PAKRouter::getResourceRelativePath()"));
const typename BRIDGETYPE::PAKType::Entry* be = lookupEntry(b);
if (!be)
return hecl::SystemString();
hecl::ProjectPath aPath = getWorking(&a, BRIDGETYPE::LookupExtractor(*node, *pak, a));
hecl::SystemString ret;
for (size_t i = 0; i < aPath.levelCount(); ++i)
ret += _SYS_STR("../");
hecl::ProjectPath bPath = getWorking(be, BRIDGETYPE::LookupExtractor(*node, *pak, *be));
ret += bPath.getRelativePath();
return ret;
}
template <class BRIDGETYPE>
std::string PAKRouter<BRIDGETYPE>::getBestEntryName(const EntryType& entry, bool stdOverride) const {
std::string name;
for (const BRIDGETYPE& bridge : *m_bridges) {
const typename BRIDGETYPE::PAKType& pak = bridge.getPAK();
const typename BRIDGETYPE::PAKType::Entry* e = pak.lookupEntry(entry.id);
if (!e)
continue;
if (stdOverride && !pak.m_noShare) {
if (entry.type == FOURCC('MLVL'))
return "!world";
else if (entry.type == FOURCC('MREA'))
return "!area";
else if (entry.type == FOURCC('MAPA'))
return "!map";
else if (entry.type == FOURCC('PATH'))
return "!path";
}
bool named;
name = pak.bestEntryName(bridge.getNode(), entry, named);
if (named)
return name;
}
return name;
}
template <class BRIDGETYPE>
std::string PAKRouter<BRIDGETYPE>::getBestEntryName(const IDType& entry, bool stdOverride) const {
std::string name;
for (const BRIDGETYPE& bridge : *m_bridges) {
const typename BRIDGETYPE::PAKType& pak = bridge.getPAK();
const typename BRIDGETYPE::PAKType::Entry* e = pak.lookupEntry(entry);
if (!e)
continue;
if (stdOverride && !pak.m_noShare) {
if (e->type == FOURCC('MLVL'))
return "!world";
else if (e->type == FOURCC('MREA'))
return "!area";
else if (e->type == FOURCC('MAPA'))
return "!map";
else if (e->type == FOURCC('PATH'))
return "!path";
}
bool named;
name = pak.bestEntryName(bridge.getNode(), *e, named);
if (named)
return name;
}
return name;
}
template <class BRIDGETYPE>
bool PAKRouter<BRIDGETYPE>::extractResources(const BRIDGETYPE& pakBridge, bool force, hecl::blender::Token& btok,
std::function<void(const hecl::SystemChar*, float)> progress) {
enterPAKBridge(pakBridge);
size_t count = 0;
size_t sz = m_pak->m_entries.size();
float fsz = sz;
for (unsigned w = 0; count < sz; ++w) {
for (const auto& item : m_pak->m_firstEntries) {
const auto* entryPtr = m_pak->lookupEntry(item);
ResExtractor<BRIDGETYPE> extractor = BRIDGETYPE::LookupExtractor(*m_node.get(), *m_pak.get(), *entryPtr);
if (extractor.weight != w)
continue;
std::string bestName = getBestEntryName(*entryPtr, false);
hecl::SystemStringConv bestNameView(bestName);
float thisFac = ++count / fsz;
progress(bestNameView.c_str(), thisFac);
const nod::Node* node = m_node.get();
hecl::ProjectPath working = getWorking(entryPtr, extractor);
working.makeDirChain(false);
hecl::ResourceLock resLk(working);
if (!resLk)
continue;
/* Extract to unmodified directory */
hecl::ProjectPath cooked = working.getCookedPath(m_dataSpec.getUnmodifiedSpec());
if (force || cooked.isNone()) {
cooked.makeDirChain(false);
PAKEntryReadStream s = entryPtr->beginReadStream(*node);
FILE* fout = hecl::Fopen(cooked.getAbsolutePath().data(), _SYS_STR("wb"));
fwrite(s.data(), 1, s.length(), fout);
fclose(fout);
}
if (extractor.func_a) /* Doesn't need PAKRouter access */
{
if (force || !extractor.IsFullyExtracted(working)) {
PAKEntryReadStream s = entryPtr->beginReadStream(*node);
extractor.func_a(s, working);
}
} else if (extractor.func_b) /* Needs PAKRouter access */
{
if (force || !extractor.IsFullyExtracted(working)) {
PAKEntryReadStream s = entryPtr->beginReadStream(*node);
extractor.func_b(m_dataSpec, s, working, *this, *entryPtr, force, btok,
[&progress, thisFac](const hecl::SystemChar* update) { progress(update, thisFac); });
}
}
}
}
return true;
}
template <class BRIDGETYPE>
const typename BRIDGETYPE::PAKType::Entry* PAKRouter<BRIDGETYPE>::lookupEntry(const IDType& entry,
const nod::Node** nodeOut,
bool silenceWarnings,
bool currentPAK) const {
if (!entry.isValid())
return nullptr;
if (!m_bridges)
LogDNACommon.report(logvisor::Fatal, fmt("PAKRouter::build() must be called before PAKRouter::lookupEntry()"));
const PAKType* pak = m_pak.get();
const nod::Node* node = m_node.get();
if (pak) {
const EntryType* ent = pak->lookupEntry(entry);
if (ent) {
if (nodeOut)
*nodeOut = node;
return ent;
}
}
if (currentPAK) {
#ifndef NDEBUG
if (!silenceWarnings)
LogDNACommon.report(logvisor::Warning, fmt("unable to find PAK entry {} in current PAK"), entry);
#endif
return nullptr;
}
for (const BRIDGETYPE& bridge : *m_bridges) {
const PAKType& pak = bridge.getPAK();
const EntryType* ent = pak.lookupEntry(entry);
if (ent) {
if (nodeOut)
*nodeOut = &bridge.getNode();
return ent;
}
}
#ifndef NDEBUG
if (!silenceWarnings)
LogDNACommon.report(logvisor::Warning, fmt("unable to find PAK entry {}"), entry);
#endif
if (nodeOut)
*nodeOut = nullptr;
return nullptr;
}
template <class BRIDGETYPE>
const typename CharacterAssociations<typename PAKRouter<BRIDGETYPE>::IDType>::RigPair*
PAKRouter<BRIDGETYPE>::lookupCMDLRigPair(const IDType& id) const {
auto search = m_charAssoc.m_cmdlRigs.find(id);
if (search == m_charAssoc.m_cmdlRigs.end())
return nullptr;
return &search->second;
}
template <class BRIDGETYPE>
const typename CharacterAssociations<typename PAKRouter<BRIDGETYPE>::IDType>::MultimapIteratorPair
PAKRouter<BRIDGETYPE>::lookupCharacterAttachmentRigs(const IDType& id) const {
return m_charAssoc.m_characterToAttachmentRigs.equal_range(id);
}
template <class BRIDGETYPE>
const zeus::CMatrix4f* PAKRouter<BRIDGETYPE>::lookupMAPATransform(const IDType& id) const {
auto search = m_mapaTransforms.find(id);
if (search == m_mapaTransforms.end())
return nullptr;
return &search->second;
}
template <class BRIDGETYPE>
hecl::ProjectPath PAKRouter<BRIDGETYPE>::getAreaLayerWorking(const IDType& areaId, int layerIdx) const {
if (!m_bridges)
LogDNACommon.report(logvisor::Fatal, fmt("PAKRouter::build() must be called before PAKRouter::getAreaLayerWorking()"));
auto bridgePathIt = m_bridgePaths.cbegin();
for (const BRIDGETYPE& bridge : *m_bridges) {
for (const auto& level : bridge.m_levelDeps)
for (const auto& area : level.second.areas)
if (area.first == areaId) {
hecl::ProjectPath levelPath(bridgePathIt->first, level.second.name);
hecl::ProjectPath areaPath(levelPath, area.second.name);
if (layerIdx < 0)
return areaPath;
return hecl::ProjectPath(areaPath, area.second.layers.at(layerIdx).name);
}
++bridgePathIt;
}
return hecl::ProjectPath();
}
template <class BRIDGETYPE>
hecl::ProjectPath PAKRouter<BRIDGETYPE>::getAreaLayerWorking(const IDType& areaId, int layerIdx,
bool& activeOut) const {
activeOut = false;
if (!m_bridges)
LogDNACommon.report(logvisor::Fatal, fmt("PAKRouter::build() must be called before PAKRouter::getAreaLayerWorking()"));
auto bridgePathIt = m_bridgePaths.cbegin();
for (const BRIDGETYPE& bridge : *m_bridges) {
for (const auto& level : bridge.m_levelDeps)
for (const auto& area : level.second.areas)
if (area.first == areaId) {
hecl::ProjectPath levelPath(bridgePathIt->first, level.second.name);
hecl::ProjectPath areaPath(levelPath, area.second.name);
if (layerIdx < 0)
return areaPath;
const typename Level<IDType>::Area::Layer& layer = area.second.layers.at(layerIdx);
activeOut = layer.active;
return hecl::ProjectPath(areaPath, layer.name);
}
++bridgePathIt;
}
return hecl::ProjectPath();
}
template <class BRIDGETYPE>
hecl::ProjectPath PAKRouter<BRIDGETYPE>::getAreaLayerCooked(const IDType& areaId, int layerIdx) const {
if (!m_bridges)
LogDNACommon.report(logvisor::Fatal, fmt("PAKRouter::build() must be called before PAKRouter::getAreaLayerCooked()"));
auto bridgePathIt = m_bridgePaths.cbegin();
for (const BRIDGETYPE& bridge : *m_bridges) {
for (const auto& level : bridge.m_levelDeps)
for (const auto& area : level.second.areas)
if (area.first == areaId) {
hecl::ProjectPath levelPath(bridgePathIt->second, level.second.name);
hecl::ProjectPath areaPath(levelPath, area.second.name);
if (layerIdx < 0)
return areaPath;
return hecl::ProjectPath(areaPath, area.second.layers.at(layerIdx).name);
}
++bridgePathIt;
}
return hecl::ProjectPath();
}
template <class BRIDGETYPE>
hecl::ProjectPath PAKRouter<BRIDGETYPE>::getAreaLayerCooked(const IDType& areaId, int layerIdx, bool& activeOut) const {
activeOut = false;
if (!m_bridges)
LogDNACommon.report(logvisor::Fatal, fmt("PAKRouter::build() must be called before PAKRouter::getAreaLayerCooked()"));
auto bridgePathIt = m_bridgePaths.cbegin();
for (const BRIDGETYPE& bridge : *m_bridges) {
for (const auto& level : bridge.m_levelDeps)
for (const auto& area : level.second.areas)
if (area.first == areaId) {
hecl::ProjectPath levelPath(bridgePathIt->second, level.second.name);
hecl::ProjectPath areaPath(levelPath, area.second.name);
if (layerIdx < 0)
return areaPath;
const typename Level<IDType>::Area::Layer& layer = area.second.layers.at(layerIdx);
activeOut = layer.active;
return hecl::ProjectPath(areaPath, layer.name);
}
++bridgePathIt;
}
return hecl::ProjectPath();
}
template <class BRIDGETYPE>
void PAKRouter<BRIDGETYPE>::enumerateResources(const std::function<bool(const EntryType*)>& func) {
if (!m_bridges)
LogDNACommon.report(logvisor::Fatal, fmt("PAKRouter::build() must be called before PAKRouter::enumerateResources()"));
for (const auto& entryPair : m_uniqueEntries)
if (!func(entryPair.second.second))
return;
for (const auto& entryPair : m_sharedEntries)
if (!func(entryPair.second.second))
return;
}
template <class BRIDGETYPE>
bool PAKRouter<BRIDGETYPE>::mreaHasDupeResources(const IDType& id) const {
const PAKType* pak = m_pak.get();
if (!pak)
LogDNACommon.report(logvisor::Fatal,
fmt("PAKRouter::enterPAKBridge() must be called before PAKRouter::mreaHasDupeResources()"));
return pak->mreaHasDupeResources(id);
}
template class PAKRouter<DNAMP1::PAKBridge>;
template class PAKRouter<DNAMP2::PAKBridge>;
template class PAKRouter<DNAMP3::PAKBridge>;
} // namespace DataSpec