mirror of https://github.com/AxioDL/metaforce.git
Externally track MemoryRelays
This commit is contained in:
parent
0ed44f1cdc
commit
5b5f3318b0
|
@ -20,7 +20,7 @@ struct ISTRG : BigYAML
|
|||
virtual hecl::SystemString getSystemString(const FourCC& lang, size_t idx) const=0;
|
||||
virtual int32_t lookupIdx(const std::string& name) const=0;
|
||||
|
||||
void gatherDependencies(std::vector<hecl::ProjectPath>& pathsOut) const;
|
||||
virtual void gatherDependencies(std::vector<hecl::ProjectPath>& pathsOut) const;
|
||||
};
|
||||
std::unique_ptr<ISTRG> LoadSTRG(athena::io::IStreamReader& reader);
|
||||
|
||||
|
|
|
@ -13,36 +13,59 @@ namespace DataSpec
|
|||
namespace DNAMP1
|
||||
{
|
||||
|
||||
bool MLVL::Extract(const SpecBase& dataSpec,
|
||||
PAKEntryReadStream& rs,
|
||||
const hecl::ProjectPath& outPath,
|
||||
PAKRouter<PAKBridge>& pakRouter,
|
||||
const PAK::Entry& entry,
|
||||
bool force,
|
||||
hecl::BlenderToken& btok,
|
||||
bool MLVL::Extract(const SpecBase& dataSpec, PAKEntryReadStream& rs, const hecl::ProjectPath& outPath,
|
||||
PAKRouter<PAKBridge>& pakRouter, const PAK::Entry& entry, bool force, hecl::BlenderToken& btok,
|
||||
std::function<void(const hecl::SystemChar*)> fileChanged)
|
||||
{
|
||||
MLVL mlvl;
|
||||
mlvl.read(rs);
|
||||
const nod::Node* node;
|
||||
const typename PAKRouter<PAKBridge>::EntryType* texEntry = pakRouter.lookupEntry(mlvl.saveWorldId, &node);
|
||||
hecl::ProjectPath savwPath = pakRouter.getWorking(texEntry);
|
||||
SAVW savw;
|
||||
if (!savwPath.isNone())
|
||||
{
|
||||
savwPath.makeDirChain(false);
|
||||
PAKEntryReadStream rs = texEntry->beginReadStream(*node);
|
||||
savw.read(rs);
|
||||
}
|
||||
|
||||
atUint32 areaIdx = 0;
|
||||
for (const MLVL::Area& area : mlvl.areas)
|
||||
{
|
||||
hecl::ProjectPath areaDir = pakRouter.getWorking(area.areaMREAId).getParentPath();
|
||||
athena::io::FileWriter fw(hecl::ProjectPath(areaDir, _S("!memoryid.yaml")).getAbsolutePath());
|
||||
athena::io::YAMLDocWriter w(nullptr);
|
||||
w.writeUint32("memoryid", area.areaId);
|
||||
w.finish(&fw);
|
||||
{
|
||||
athena::io::FileWriter fw(hecl::ProjectPath(areaDir, _S("!memoryid.yaml")).getAbsolutePath());
|
||||
athena::io::YAMLDocWriter w(nullptr);
|
||||
w.writeUint32("memoryid", area.areaId);
|
||||
w.finish(&fw);
|
||||
}
|
||||
{
|
||||
athena::io::FileWriter fw(hecl::ProjectPath(areaDir, _S("!memoryrelays.yaml")).getAbsolutePath());
|
||||
athena::io::YAMLDocWriter w(nullptr);
|
||||
|
||||
std::vector<atUint32> relayIds;
|
||||
for (const atUint32& relay : savw.relays)
|
||||
{
|
||||
atUint16 aIdx = ((relay >> 16) & 0x3ff);
|
||||
if (aIdx == areaIdx && std::find(relayIds.begin(), relayIds.end(), relay) == relayIds.end())
|
||||
relayIds.push_back(relay);
|
||||
}
|
||||
|
||||
w.enumerate<atUint32>("memrelays", relayIds);
|
||||
w.finish(&fw);
|
||||
}
|
||||
areaIdx++;
|
||||
}
|
||||
|
||||
athena::io::FileWriter writer(outPath.getWithExtension(_S(".yaml"), true).getAbsolutePath());
|
||||
mlvl.toYAMLStream(writer, static_cast<YAMLWriteMemberFn>(&MLVL::writeMeta));
|
||||
hecl::BlenderConnection& conn = btok.getBlenderConnection();
|
||||
return DNAMLVL::ReadMLVLToBlender(conn, mlvl, outPath, pakRouter,
|
||||
entry, force, fileChanged);
|
||||
return DNAMLVL::ReadMLVLToBlender(conn, mlvl, outPath, pakRouter, entry, force, fileChanged);
|
||||
}
|
||||
|
||||
bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath,
|
||||
const World& wld, hecl::BlenderToken& btok)
|
||||
bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const World& wld,
|
||||
hecl::BlenderToken& btok)
|
||||
{
|
||||
MLVL mlvl = {};
|
||||
athena::io::FileReader reader(inPath.getWithExtension(_S(".yaml"), true).getAbsolutePath());
|
||||
|
@ -77,8 +100,24 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
|
|||
if (!areaPath.isFile())
|
||||
continue;
|
||||
|
||||
hecl::DirectoryEnumerator dEnum(area.path.getAbsolutePath(),
|
||||
hecl::DirectoryEnumerator::Mode::DirsSorted);
|
||||
hecl::ProjectPath memRelayPath(area.path, _S("/!memoryrelays.yaml"));
|
||||
|
||||
std::vector<atUint32> memRelays;
|
||||
|
||||
if (memRelayPath.isFile())
|
||||
{
|
||||
athena::io::FileReader fr(memRelayPath.getAbsolutePath());
|
||||
athena::io::YAMLDocReader r;
|
||||
if (r.parse(&fr))
|
||||
r.enumerate<atUint32>("memrelays", memRelays);
|
||||
}
|
||||
|
||||
savw.relays.insert(savw.relays.end(), memRelays.begin(), memRelays.end());
|
||||
|
||||
/* Bare minimum we'll need exactly the same number of links as relays */
|
||||
std::vector<MemRelayLink> memRelayLinks(memRelays.size());
|
||||
|
||||
hecl::DirectoryEnumerator dEnum(area.path.getAbsolutePath(), hecl::DirectoryEnumerator::Mode::DirsSorted);
|
||||
bool areaInit = false;
|
||||
|
||||
size_t layerIdx = 0;
|
||||
|
@ -201,6 +240,7 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
|
|||
MLVL::Area& areaOut = mlvl.areas.back();
|
||||
areaOut.depLayers.push_back(areaOut.deps.size());
|
||||
|
||||
|
||||
/* Gather memory relays, scans, and dependencies */
|
||||
{
|
||||
g_ThreadBlenderToken.reset(&btok);
|
||||
|
@ -213,14 +253,28 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
|
|||
MemoryRelay& memRelay = static_cast<MemoryRelay&>(*obj);
|
||||
for (IScriptObject::Connection& conn : memRelay.connections)
|
||||
{
|
||||
mlvl.memRelayLinks.emplace_back();
|
||||
MemRelayLink& linkOut = mlvl.memRelayLinks.back();
|
||||
MemRelayLink linkOut;
|
||||
linkOut.memRelayId = memRelay.id;
|
||||
linkOut.targetId = conn.target;
|
||||
linkOut.msg = conn.msg;
|
||||
linkOut.active = memRelay.active;
|
||||
auto iter = std::find(memRelays.begin(), memRelays.end(), linkOut.memRelayId);
|
||||
if (iter == memRelays.end())
|
||||
{
|
||||
/* We must have a new relay, let's track it */
|
||||
memRelayLinks.push_back(linkOut);
|
||||
savw.relays.push_back(memRelay.id);
|
||||
memRelays.push_back(memRelay.id);
|
||||
}
|
||||
else /* Lets insert this in it's appropriate location, target order doesn't matter */
|
||||
{
|
||||
atUint32 idx = iter - memRelays.begin();
|
||||
if (idx >= memRelayLinks.size())
|
||||
memRelayLinks.push_back(linkOut);
|
||||
else
|
||||
memRelayLinks.insert(memRelayLinks.begin() + idx, linkOut);
|
||||
}
|
||||
}
|
||||
savw.relays.push_back(memRelay.id);
|
||||
}
|
||||
else if (obj->type == int(urde::EScriptObjectType::SpecialFunction))
|
||||
{
|
||||
|
@ -286,6 +340,9 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
|
|||
++layerIdx;
|
||||
}
|
||||
|
||||
/* Append Memory Relays */
|
||||
mlvl.memRelayLinks.insert(mlvl.memRelayLinks.end(), memRelayLinks.begin(), memRelayLinks.end());
|
||||
|
||||
/* Cull duplicate area paths and add typed hash to list */
|
||||
auto& conn = btok.getBlenderConnection();
|
||||
if (conn.openBlend(areaPath))
|
||||
|
@ -332,8 +389,7 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
|
|||
|
||||
/* Write out MAPW */
|
||||
{
|
||||
hecl::ProjectPath mapwCooked =
|
||||
mapwPath.getCookedPath(*g_curSpec->overrideDataSpec(mapwPath, nullptr, btok));
|
||||
hecl::ProjectPath mapwCooked = mapwPath.getCookedPath(*g_curSpec->overrideDataSpec(mapwPath, nullptr, btok));
|
||||
mapwCooked.makeDirChain(false);
|
||||
athena::io::FileWriter fo(mapwCooked.getAbsolutePath());
|
||||
fo.writeUint32Big(0xDEADF00D);
|
||||
|
@ -352,8 +408,7 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
|
|||
savw.doorCount = savw.doors.size();
|
||||
savw.scanCount = savw.scans.size();
|
||||
|
||||
hecl::ProjectPath savwCooked =
|
||||
savwPath.getCookedPath(*g_curSpec->overrideDataSpec(savwPath, nullptr, btok));
|
||||
hecl::ProjectPath savwCooked = savwPath.getCookedPath(*g_curSpec->overrideDataSpec(savwPath, nullptr, btok));
|
||||
savwCooked.makeDirChain(false);
|
||||
athena::io::FileWriter fo(savwCooked.getAbsolutePath());
|
||||
savw.write(fo);
|
||||
|
@ -361,6 +416,5 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -161,11 +161,8 @@ struct SCAN : BigYAML
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool Cook(const hecl::ProjectPath& inPath, const hecl::ProjectPath& outPath)
|
||||
static bool Cook(const SCAN& scan, const hecl::ProjectPath& outPath)
|
||||
{
|
||||
SCAN scan;
|
||||
athena::io::FileReader reader(inPath.getAbsolutePath());
|
||||
scan.fromYAMLStream(reader);
|
||||
athena::io::FileWriter ws(outPath.getAbsolutePath());
|
||||
scan.write(ws);
|
||||
return true;
|
||||
|
@ -204,6 +201,12 @@ struct SCAN : BigYAML
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gatherDependencies(std::vector<hecl::ProjectPath>& pathsOut)
|
||||
{
|
||||
for (int i = 0; i < 4; ++i)
|
||||
g_curSpec->flattenDependencies(textures[i].texture, pathsOut);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,22 +6,14 @@ namespace DataSpec
|
|||
namespace DNAMP1
|
||||
{
|
||||
|
||||
const std::vector<FourCC> skLanguages =
|
||||
{
|
||||
FOURCC('ENGL'),
|
||||
FOURCC('FREN'),
|
||||
FOURCC('GERM'),
|
||||
FOURCC('SPAN'),
|
||||
FOURCC('ITAL'),
|
||||
FOURCC('DUTC'),
|
||||
FOURCC('JAPN')
|
||||
};
|
||||
const std::vector<FourCC> skLanguages = {FOURCC('ENGL'), FOURCC('FREN'), FOURCC('GERM'), FOURCC('SPAN'),
|
||||
FOURCC('ITAL'), FOURCC('DUTC'), FOURCC('JAPN')};
|
||||
|
||||
static float u16stof(char16_t* str)
|
||||
{
|
||||
char cstr[16];
|
||||
int i;
|
||||
for (i=0 ; i<15 && str[i] != u'\0' ; ++i)
|
||||
for (i = 0; i < 15 && str[i] != u'\0'; ++i)
|
||||
cstr[i] = str[i];
|
||||
cstr[i] = '\0';
|
||||
return strtof(cstr, nullptr);
|
||||
|
@ -31,18 +23,16 @@ static uint32_t ParseTag(const char16_t* str)
|
|||
{
|
||||
char parseStr[9];
|
||||
int i;
|
||||
for (i=0 ; i<8 && str[i] ; ++i)
|
||||
for (i = 0; i < 8 && str[i]; ++i)
|
||||
parseStr[i] = str[i];
|
||||
parseStr[i] = '\0';
|
||||
return strtoul(parseStr, nullptr, 16);
|
||||
}
|
||||
|
||||
static std::u16string::const_iterator SkipCommas(std::u16string& ret,
|
||||
const std::u16string& str,
|
||||
std::u16string::const_iterator it,
|
||||
size_t count)
|
||||
static std::u16string::const_iterator SkipCommas(std::u16string& ret, const std::u16string& str,
|
||||
std::u16string::const_iterator it, size_t count)
|
||||
{
|
||||
for (size_t i=0 ; i<count ; ++i)
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
auto cpos = str.find(u',', it - str.begin());
|
||||
if (cpos == std::u16string::npos)
|
||||
|
@ -54,8 +44,7 @@ static std::u16string::const_iterator SkipCommas(std::u16string& ret,
|
|||
return it;
|
||||
}
|
||||
|
||||
static std::u16string::const_iterator UncookTextureList(std::u16string& ret,
|
||||
const std::u16string& str,
|
||||
static std::u16string::const_iterator UncookTextureList(std::u16string& ret, const std::u16string& str,
|
||||
std::u16string::const_iterator it)
|
||||
{
|
||||
while (true)
|
||||
|
@ -87,20 +76,17 @@ static std::u16string::const_iterator UncookTextureList(std::u16string& ret,
|
|||
return str.begin() + scpos + 1;
|
||||
}
|
||||
|
||||
static std::u16string::const_iterator CookTextureList(std::u16string& ret,
|
||||
const std::u16string& str,
|
||||
static std::u16string::const_iterator CookTextureList(std::u16string& ret, const std::u16string& str,
|
||||
std::u16string::const_iterator it)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
auto end = str.find_first_of(u",;", it - str.begin());
|
||||
if (end == std::u16string::npos)
|
||||
Log.report(logvisor::Fatal,
|
||||
"Missing comma/semicolon token while pasing font tag");
|
||||
Log.report(logvisor::Fatal, "Missing comma/semicolon token while pasing font tag");
|
||||
auto endIt = str.begin() + end;
|
||||
hecl::ProjectPath path =
|
||||
UniqueIDBridge::MakePathFromString<UniqueID32>(
|
||||
hecl::Char16ToUTF8(std::u16string(it, endIt)));
|
||||
UniqueIDBridge::MakePathFromString<UniqueID32>(hecl::Char16ToUTF8(std::u16string(it, endIt)));
|
||||
ret.append(hecl::UTF8ToChar16(UniqueID32(path).toString()));
|
||||
it = endIt;
|
||||
if (*it == u';')
|
||||
|
@ -126,11 +112,47 @@ static std::u16string::const_iterator CookTextureList(std::u16string& ret,
|
|||
return str.begin() + scpos + 1;
|
||||
}
|
||||
|
||||
static std::u16string::const_iterator GatherTextureList(std::vector<hecl::ProjectPath>& pathsOut,
|
||||
const std::u16string& str, std::u16string::const_iterator it)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
auto end = str.find_first_of(u",;", it - str.begin());
|
||||
if (end == std::u16string::npos)
|
||||
Log.report(logvisor::Fatal, "Missing comma/semicolon token while pasing font tag");
|
||||
auto endIt = str.begin() + end;
|
||||
hecl::ProjectPath path =
|
||||
UniqueIDBridge::MakePathFromString<UniqueID32>(hecl::Char16ToUTF8(std::u16string(it, endIt)));
|
||||
if (path)
|
||||
pathsOut.push_back(path);
|
||||
|
||||
it = endIt;
|
||||
if (*it == u';')
|
||||
{
|
||||
return it + 1;
|
||||
}
|
||||
else if (*it == u',')
|
||||
{
|
||||
++it;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Failsafe */
|
||||
auto scpos = str.find(u';', it - str.begin());
|
||||
if (scpos == std::u16string::npos)
|
||||
return str.end();
|
||||
return str.begin() + scpos + 1;
|
||||
}
|
||||
|
||||
static std::u16string UncookString(const std::u16string& str)
|
||||
{
|
||||
std::u16string ret;
|
||||
ret.reserve(str.size());
|
||||
for (auto it = str.begin() ; it != str.end() ;)
|
||||
for (auto it = str.begin(); it != str.end();)
|
||||
{
|
||||
if (*it == u'&')
|
||||
{
|
||||
|
@ -202,7 +224,7 @@ static std::u16string CookString(const std::u16string& str)
|
|||
{
|
||||
std::u16string ret;
|
||||
ret.reserve(str.size());
|
||||
for (auto it = str.begin() ; it != str.end() ;)
|
||||
for (auto it = str.begin(); it != str.end();)
|
||||
{
|
||||
if (*it == u'&')
|
||||
{
|
||||
|
@ -238,9 +260,8 @@ static std::u16string CookString(const std::u16string& str)
|
|||
auto scpos = str.find(u';', it - str.begin());
|
||||
if (scpos == std::u16string::npos)
|
||||
Log.report(logvisor::Fatal, "Missing semicolon token while pasing font tag");
|
||||
hecl::ProjectPath path =
|
||||
UniqueIDBridge::MakePathFromString<UniqueID32>(
|
||||
hecl::Char16ToUTF8(std::u16string(it, str.begin() + scpos)));
|
||||
hecl::ProjectPath path = UniqueIDBridge::MakePathFromString<UniqueID32>(
|
||||
hecl::Char16ToUTF8(std::u16string(it, str.begin() + scpos)));
|
||||
ret.append(hecl::UTF8ToChar16(UniqueID32(path).toString()));
|
||||
ret.push_back(u';');
|
||||
it = str.begin() + scpos + 1;
|
||||
|
@ -269,6 +290,68 @@ static std::u16string CookString(const std::u16string& str)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void STRG::gatherDependencies(std::vector<hecl::ProjectPath>& pathsOut) const
|
||||
{
|
||||
std::u16string skip;
|
||||
for (const auto& lang : langs)
|
||||
{
|
||||
for (const std::u16string& str : lang.second)
|
||||
{
|
||||
for (auto it = str.begin(); it != str.end();)
|
||||
{
|
||||
if (*it == u'&')
|
||||
{
|
||||
++it;
|
||||
if (!str.compare(it - str.begin(), 5, u"image"))
|
||||
{
|
||||
it += 6;
|
||||
if (!str.compare(it - str.begin(), 1, u"A"))
|
||||
{
|
||||
it = SkipCommas(skip, str, it, 2);
|
||||
it = GatherTextureList(pathsOut, str, it);
|
||||
continue;
|
||||
}
|
||||
else if (!str.compare(it - str.begin(), 2, u"SA"))
|
||||
{
|
||||
it = SkipCommas(skip, str, it, 4);
|
||||
it = GatherTextureList(pathsOut, str, it);
|
||||
continue;
|
||||
}
|
||||
else if (!str.compare(it - str.begin(), 2, u"SI"))
|
||||
{
|
||||
it = SkipCommas(skip, str, it, 3);
|
||||
it = GatherTextureList(pathsOut, str, it);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (!str.compare(it - str.begin(), 4, u"font"))
|
||||
{
|
||||
it += 5;
|
||||
auto scpos = str.find(u';', it - str.begin());
|
||||
if (scpos == std::u16string::npos)
|
||||
Log.report(logvisor::Fatal, "Missing semicolon token while pasing font tag");
|
||||
hecl::ProjectPath path = UniqueIDBridge::MakePathFromString<UniqueID32>(
|
||||
hecl::Char16ToUTF8(std::u16string(it, str.begin() + scpos)));
|
||||
if (path)
|
||||
pathsOut.push_back(path);
|
||||
it = str.begin() + scpos + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto scpos = str.find(u';', it - str.begin());
|
||||
if (scpos == std::u16string::npos)
|
||||
it = str.end();
|
||||
else
|
||||
it = str.begin() + scpos + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void STRG::_read(athena::io::IStreamReader& reader)
|
||||
{
|
||||
atUint32 langCount = reader.readUint32Big();
|
||||
|
@ -277,7 +360,7 @@ void STRG::_read(athena::io::IStreamReader& reader)
|
|||
std::vector<std::pair<FourCC, atUint32>> readLangs;
|
||||
|
||||
readLangs.reserve(langCount);
|
||||
for (atUint32 l=0 ; l<langCount ; ++l)
|
||||
for (atUint32 l = 0; l < langCount; ++l)
|
||||
{
|
||||
DNAFourCC lang;
|
||||
lang.read(reader);
|
||||
|
@ -294,7 +377,7 @@ void STRG::_read(athena::io::IStreamReader& reader)
|
|||
reader.seek(tablesStart + lang.second, athena::SeekOrigin::Begin);
|
||||
reader.readUint32Big(); // table size
|
||||
atUint32 langStart = reader.position();
|
||||
for (atUint32 s=0 ; s<strCount ; ++s)
|
||||
for (atUint32 s = 0; s < strCount; ++s)
|
||||
{
|
||||
atUint32 strOffset = reader.readUint32Big();
|
||||
atUint32 tmpOffset = reader.position();
|
||||
|
@ -342,7 +425,7 @@ void STRG::write(athena::io::IStreamWriter& writer) const
|
|||
writer.writeUint32Big(offset);
|
||||
offset += strCount * 4 + 4;
|
||||
atUint32 langStrCount = lang.second.size();
|
||||
for (atUint32 s=0 ; s<strCount ; ++s)
|
||||
for (atUint32 s = 0; s < strCount; ++s)
|
||||
{
|
||||
std::u16string str = CookString(lang.second[s]);
|
||||
atUint32 chCount = str.size();
|
||||
|
@ -360,7 +443,7 @@ void STRG::write(athena::io::IStreamWriter& writer) const
|
|||
atUint32 langStrCount = lang.second.size();
|
||||
atUint32 tableSz = strCount * 4;
|
||||
auto strIt = langIt;
|
||||
for (atUint32 s=0 ; s<strCount ; ++s)
|
||||
for (atUint32 s = 0; s < strCount; ++s)
|
||||
{
|
||||
if (s < langStrCount)
|
||||
tableSz += ((strIt++)->size() + 1) * 2;
|
||||
|
@ -371,7 +454,7 @@ void STRG::write(athena::io::IStreamWriter& writer) const
|
|||
|
||||
offset = strCount * 4;
|
||||
strIt = langIt;
|
||||
for (atUint32 s=0 ; s<strCount ; ++s)
|
||||
for (atUint32 s = 0; s < strCount; ++s)
|
||||
{
|
||||
writer.writeUint32Big(offset);
|
||||
if (s < langStrCount)
|
||||
|
@ -381,7 +464,7 @@ void STRG::write(athena::io::IStreamWriter& writer) const
|
|||
}
|
||||
|
||||
strIt = langIt;
|
||||
for (atUint32 s=0 ; s<strCount ; ++s)
|
||||
for (atUint32 s = 0; s < strCount; ++s)
|
||||
{
|
||||
if (s < langStrCount)
|
||||
writer.writeU16StringBig(*strIt++);
|
||||
|
@ -403,7 +486,7 @@ size_t STRG::binarySize(size_t __isz) const
|
|||
for (const std::pair<FourCC, std::vector<std::u16string>>& lang : langs)
|
||||
{
|
||||
atUint32 langStrCount = lang.second.size();
|
||||
for (atUint32 s=0 ; s<strCount ; ++s)
|
||||
for (atUint32 s = 0; s < strCount; ++s)
|
||||
{
|
||||
if (s < langStrCount)
|
||||
__isz += (CookString(lang.second[s]).size() + 1) * 2;
|
||||
|
@ -429,19 +512,22 @@ void STRG::read(athena::io::YAMLDocReader& reader)
|
|||
|
||||
if (lang.first.size() != 4)
|
||||
{
|
||||
Log.report(logvisor::Warning, "STRG language string '%s' must be exactly 4 characters; skipping", lang.first.c_str());
|
||||
Log.report(logvisor::Warning, "STRG language string '%s' must be exactly 4 characters; skipping",
|
||||
lang.first.c_str());
|
||||
return;
|
||||
}
|
||||
if (lang.second->m_type != YAML_SEQUENCE_NODE)
|
||||
{
|
||||
Log.report(logvisor::Warning, "STRG language string '%s' must contain a sequence; skipping", lang.first.c_str());
|
||||
Log.report(logvisor::Warning, "STRG language string '%s' must contain a sequence; skipping",
|
||||
lang.first.c_str());
|
||||
return;
|
||||
}
|
||||
for (const auto& str : lang.second->m_seqChildren)
|
||||
{
|
||||
if (str->m_type != YAML_SCALAR_NODE)
|
||||
{
|
||||
Log.report(logvisor::Warning, "STRG language '%s' must contain all scalars; skipping", lang.first.c_str());
|
||||
Log.report(logvisor::Warning, "STRG language '%s' must contain all scalars; skipping",
|
||||
lang.first.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -483,10 +569,6 @@ void STRG::write(athena::io::YAMLDocWriter& writer) const
|
|||
}
|
||||
}
|
||||
|
||||
const char* STRG::DNAType()
|
||||
{
|
||||
return "urde::DNAMP1::STRG";
|
||||
}
|
||||
|
||||
const char* STRG::DNAType() { return "urde::DNAMP1::STRG"; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,6 +84,7 @@ struct STRG : ISTRG
|
|||
return true;
|
||||
}
|
||||
|
||||
void gatherDependencies(std::vector<hecl::ProjectPath> &pathsOut) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "DNAMP1/HINT.hpp"
|
||||
#include "DNAMP1/MLVL.hpp"
|
||||
#include "DNAMP1/STRG.hpp"
|
||||
#include "DNAMP1/SCAN.hpp"
|
||||
#include "DNAMP1/CMDL.hpp"
|
||||
#include "DNAMP1/MREA.hpp"
|
||||
#include "DNAMP1/ANCS.hpp"
|
||||
|
@ -50,12 +51,10 @@ extern hecl::Database::DataSpecEntry SpecEntMP1ORIG;
|
|||
|
||||
struct OriginalIDs
|
||||
{
|
||||
static void Generate(PAKRouter<DNAMP1::PAKBridge>& pakRouter,
|
||||
hecl::Database::Project& project)
|
||||
static void Generate(PAKRouter<DNAMP1::PAKBridge>& pakRouter, hecl::Database::Project& project)
|
||||
{
|
||||
std::vector<UniqueID32> originalIDs;
|
||||
pakRouter.enumerateResources([&](const DNAMP1::PAK::Entry* ent) -> bool
|
||||
{
|
||||
pakRouter.enumerateResources([&](const DNAMP1::PAK::Entry* ent) -> bool {
|
||||
if (ent->type == FOURCC('MLVL') || ent->type == FOURCC('SCAN'))
|
||||
originalIDs.push_back(ent->id);
|
||||
return true;
|
||||
|
@ -91,16 +90,13 @@ struct OriginalIDs
|
|||
if (end != node.first.c_str() + 8)
|
||||
continue;
|
||||
|
||||
hecl::ProjectPath path(project.getProjectWorkingPath(),
|
||||
node.second->m_scalarString.c_str());
|
||||
hecl::ProjectPath path(project.getProjectWorkingPath(), node.second->m_scalarString.c_str());
|
||||
originalIDs.push_back(std::make_pair(id, path.hash().val32()));
|
||||
}
|
||||
std::sort(originalIDs.begin(), originalIDs.end(),
|
||||
[](const std::pair<UniqueID32, UniqueID32>& a,
|
||||
const std::pair<UniqueID32, UniqueID32>& b) -> bool
|
||||
{
|
||||
return a.first < b.first;
|
||||
});
|
||||
[](const std::pair<UniqueID32, UniqueID32>& a, const std::pair<UniqueID32, UniqueID32>& b) -> bool {
|
||||
return a.first < b.first;
|
||||
});
|
||||
|
||||
athena::io::FileWriter w(outPath.getAbsolutePath());
|
||||
w.writeUint32Big(originalIDs.size());
|
||||
|
@ -111,11 +107,9 @@ struct OriginalIDs
|
|||
}
|
||||
|
||||
std::sort(originalIDs.begin(), originalIDs.end(),
|
||||
[](const std::pair<UniqueID32, UniqueID32>& a,
|
||||
const std::pair<UniqueID32, UniqueID32>& b) -> bool
|
||||
{
|
||||
return a.second < b.second;
|
||||
});
|
||||
[](const std::pair<UniqueID32, UniqueID32>& a, const std::pair<UniqueID32, UniqueID32>& b) -> bool {
|
||||
return a.second < b.second;
|
||||
});
|
||||
for (const auto& idPair : originalIDs)
|
||||
{
|
||||
idPair.second.write(w);
|
||||
|
@ -142,14 +136,14 @@ struct SpecMP1 : SpecBase
|
|||
PAKRouter<DNAMP1::PAKBridge> m_pakRouter;
|
||||
|
||||
SpecMP1(const hecl::Database::DataSpecEntry* specEntry, hecl::Database::Project& project, bool pc)
|
||||
: SpecBase(specEntry, project, pc),
|
||||
m_workPath(project.getProjectWorkingPath(), _S("MP1")),
|
||||
m_cookPath(project.getProjectCookedPath(SpecEntMP1), _S("MP1")),
|
||||
m_pakRouter(*this, m_workPath, m_cookPath) {}
|
||||
: SpecBase(specEntry, project, pc)
|
||||
, m_workPath(project.getProjectWorkingPath(), _S("MP1"))
|
||||
, m_cookPath(project.getProjectCookedPath(SpecEntMP1), _S("MP1"))
|
||||
, m_pakRouter(*this, m_workPath, m_cookPath)
|
||||
{
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
m_nonPaks.clear();
|
||||
m_paks.clear();
|
||||
|
@ -199,7 +193,6 @@ struct SpecMP1 : SpecBase
|
|||
}
|
||||
|
||||
m_paks.emplace_back(m_project, child, good);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -226,10 +219,8 @@ struct SpecMP1 : SpecBase
|
|||
}
|
||||
}
|
||||
|
||||
bool checkFromStandaloneDisc(nod::DiscBase& disc,
|
||||
const hecl::SystemString& regstr,
|
||||
const std::vector<hecl::SystemString>& args,
|
||||
std::vector<ExtractReport>& reps)
|
||||
bool checkFromStandaloneDisc(nod::DiscBase& disc, const hecl::SystemString& regstr,
|
||||
const std::vector<hecl::SystemString>& args, std::vector<ExtractReport>& reps)
|
||||
{
|
||||
nod::Partition* partition = disc.getDataPartition();
|
||||
std::unique_ptr<uint8_t[]> dolBuf = partition->getDOLBuf();
|
||||
|
@ -257,10 +248,8 @@ struct SpecMP1 : SpecBase
|
|||
return true;
|
||||
}
|
||||
|
||||
bool checkFromTrilogyDisc(nod::DiscBase& disc,
|
||||
const hecl::SystemString& regstr,
|
||||
const std::vector<hecl::SystemString>& args,
|
||||
std::vector<ExtractReport>& reps)
|
||||
bool checkFromTrilogyDisc(nod::DiscBase& disc, const hecl::SystemString& regstr,
|
||||
const std::vector<hecl::SystemString>& args, std::vector<ExtractReport>& reps)
|
||||
{
|
||||
std::vector<hecl::SystemString> mp1args;
|
||||
bool doExtract = false;
|
||||
|
@ -328,10 +317,7 @@ struct SpecMP1 : SpecBase
|
|||
m_workPath.makeDir();
|
||||
|
||||
progress(_S("Indexing PAKs"), _S(""), 2, 0.0);
|
||||
m_pakRouter.build(m_paks, [&progress](float factor)
|
||||
{
|
||||
progress(_S("Indexing PAKs"), _S(""), 2, factor);
|
||||
});
|
||||
m_pakRouter.build(m_paks, [&progress](float factor) { progress(_S("Indexing PAKs"), _S(""), 2, factor); });
|
||||
progress(_S("Indexing PAKs"), _S(""), 2, 1.0);
|
||||
|
||||
hecl::ProjectPath outPath(m_project.getProjectWorkingPath(), _S("out"));
|
||||
|
@ -388,11 +374,8 @@ struct SpecMP1 : SpecBase
|
|||
progress(sysName.c_str(), _S(""), compIdx, 0.0);
|
||||
}
|
||||
hecl::SystemString pakName = sysName.sys_str();
|
||||
process.addLambdaTransaction([&, pakName](hecl::BlenderToken& btok)
|
||||
{
|
||||
m_pakRouter.extractResources(pak, force, btok,
|
||||
[&](const hecl::SystemChar* substr, float factor)
|
||||
{
|
||||
process.addLambdaTransaction([&, pakName](hecl::BlenderToken& btok) {
|
||||
m_pakRouter.extractResources(pak, force, btok, [&](const hecl::SystemChar* substr, float factor) {
|
||||
std::unique_lock<std::mutex> lk(msgLock);
|
||||
progress(pakName.c_str(), substr, compIdx, factor);
|
||||
});
|
||||
|
@ -404,20 +387,11 @@ struct SpecMP1 : SpecBase
|
|||
return true;
|
||||
}
|
||||
|
||||
const hecl::Database::DataSpecEntry& getOriginalSpec() const
|
||||
{
|
||||
return SpecEntMP1;
|
||||
}
|
||||
const hecl::Database::DataSpecEntry& getOriginalSpec() const { return SpecEntMP1; }
|
||||
|
||||
const hecl::Database::DataSpecEntry& getUnmodifiedSpec() const
|
||||
{
|
||||
return SpecEntMP1ORIG;
|
||||
}
|
||||
const hecl::Database::DataSpecEntry& getUnmodifiedSpec() const { return SpecEntMP1ORIG; }
|
||||
|
||||
hecl::ProjectPath getWorking(class UniqueID32& id)
|
||||
{
|
||||
return m_pakRouter.getWorking(id);
|
||||
}
|
||||
hecl::ProjectPath getWorking(class UniqueID32& id) { return m_pakRouter.getWorking(id); }
|
||||
|
||||
bool checkPathPrefix(const hecl::ProjectPath& path) const
|
||||
{
|
||||
|
@ -428,12 +402,13 @@ struct SpecMP1 : SpecBase
|
|||
{
|
||||
athena::io::YAMLDocReader reader;
|
||||
yaml_parser_set_input(reader.getParser(), (yaml_read_handler_t*)athena::io::YAMLAthenaReader, &fp);
|
||||
return reader.ClassTypeOperation([](const char* classType)
|
||||
{
|
||||
return reader.ClassTypeOperation([](const char* classType) {
|
||||
if (!strcmp(classType, DNAMP1::MLVL::DNAType()))
|
||||
return true;
|
||||
else if (!strcmp(classType, DNAMP1::STRG::DNAType()))
|
||||
return true;
|
||||
else if (!strcmp(classType, DNAMP1::SCAN::DNAType()))
|
||||
return true;
|
||||
else if (!strcmp(classType, DNAParticle::GPSM<UniqueID32>::DNAType()))
|
||||
return true;
|
||||
else if (!strcmp(classType, DNAParticle::SWSH<UniqueID32>::DNAType()))
|
||||
|
@ -575,94 +550,98 @@ struct SpecMP1 : SpecBase
|
|||
yaml_parser_set_input_file(reader.getParser(), fp);
|
||||
|
||||
urde::SObjectTag resTag;
|
||||
if (reader.ClassTypeOperation([&](const char* className) -> bool
|
||||
{
|
||||
if (!strcmp(className, "GPSM"))
|
||||
{
|
||||
resTag.type = SBIG('PART');
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(className, "SWSH"))
|
||||
{
|
||||
resTag.type = SBIG('SWHC');
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(className, "ELSM"))
|
||||
{
|
||||
resTag.type = SBIG('ELSC');
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(className, "WPSM"))
|
||||
{
|
||||
resTag.type = SBIG('WPSC');
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(className, "CRSM"))
|
||||
{
|
||||
resTag.type = SBIG('CRSC');
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(className, "DPSM"))
|
||||
{
|
||||
resTag.type = SBIG('DPSC');
|
||||
return true;
|
||||
}
|
||||
else if (!strcmp(className, "FONT"))
|
||||
{
|
||||
resTag.type = SBIG('FONT');
|
||||
return true;
|
||||
}
|
||||
else if (!strcmp(className, "urde::DNAMP1::EVNT"))
|
||||
{
|
||||
resTag.type = SBIG('EVNT');
|
||||
return true;
|
||||
}
|
||||
else if (!strcmp(className, "urde::DGRP"))
|
||||
{
|
||||
resTag.type = SBIG('DGRP');
|
||||
return true;
|
||||
}
|
||||
else if (!strcmp(className, "urde::DNAMP1::STRG"))
|
||||
{
|
||||
resTag.type = SBIG('STRG');
|
||||
return true;
|
||||
}
|
||||
else if (!strcmp(className, "DataSpec::DNAMP1::CTweakPlayerRes") ||
|
||||
!strcmp(className, "DataSpec::DNAMP1::CTweakGunRes") ||
|
||||
!strcmp(className, "DataSpec::DNAMP1::CTweakSlideShow") ||
|
||||
!strcmp(className, "DataSpec::DNAMP1::CTweakPlayer") ||
|
||||
!strcmp(className, "DataSpec::DNAMP1::CTweakCameraBob") ||
|
||||
!strcmp(className, "DataSpec::DNAMP1::CTweakGame") ||
|
||||
!strcmp(className, "DataSpec::DNAMP1::CTweakTargeting") ||
|
||||
!strcmp(className, "DataSpec::DNAMP1::CTweakAutoMapper") ||
|
||||
!strcmp(className, "DataSpec::DNAMP1::CTweakGui") ||
|
||||
!strcmp(className, "DataSpec::DNAMP1::CTweakPlayerControl") ||
|
||||
!strcmp(className, "DataSpec::DNAMP1::CTweakBall") ||
|
||||
!strcmp(className, "DataSpec::DNAMP1::CTweakParticle") ||
|
||||
!strcmp(className, "DataSpec::DNAMP1::CTweakGuiColors") ||
|
||||
!strcmp(className, "DataSpec::DNAMP1::CTweakPlayerGun"))
|
||||
{
|
||||
resTag.type = SBIG('CTWK');
|
||||
return true;
|
||||
}
|
||||
else if (!strcmp(className, "DataSpec::DNAMP1::HINT"))
|
||||
{
|
||||
resTag.type = SBIG('HINT');
|
||||
return true;
|
||||
}
|
||||
else if (!strcmp(className, "ATBL"))
|
||||
{
|
||||
resTag.type = SBIG('ATBL');
|
||||
return true;
|
||||
}
|
||||
else if (!strcmp(className, "MP1OriginalIDs"))
|
||||
{
|
||||
resTag.type = SBIG('OIDS');
|
||||
return true;
|
||||
}
|
||||
if (reader.ClassTypeOperation([&](const char* className) -> bool {
|
||||
if (!strcmp(className, "GPSM"))
|
||||
{
|
||||
resTag.type = SBIG('PART');
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(className, "SWSH"))
|
||||
{
|
||||
resTag.type = SBIG('SWHC');
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(className, "ELSM"))
|
||||
{
|
||||
resTag.type = SBIG('ELSC');
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(className, "WPSM"))
|
||||
{
|
||||
resTag.type = SBIG('WPSC');
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(className, "CRSM"))
|
||||
{
|
||||
resTag.type = SBIG('CRSC');
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(className, "DPSM"))
|
||||
{
|
||||
resTag.type = SBIG('DPSC');
|
||||
return true;
|
||||
}
|
||||
else if (!strcmp(className, "FONT"))
|
||||
{
|
||||
resTag.type = SBIG('FONT');
|
||||
return true;
|
||||
}
|
||||
else if (!strcmp(className, "urde::DNAMP1::EVNT"))
|
||||
{
|
||||
resTag.type = SBIG('EVNT');
|
||||
return true;
|
||||
}
|
||||
else if (!strcmp(className, "urde::DGRP"))
|
||||
{
|
||||
resTag.type = SBIG('DGRP');
|
||||
return true;
|
||||
}
|
||||
else if (!strcmp(className, "urde::DNAMP1::STRG"))
|
||||
{
|
||||
resTag.type = SBIG('STRG');
|
||||
return true;
|
||||
}
|
||||
else if (!strcmp(className, "urde::DNAMP1::SCAN"))
|
||||
{
|
||||
resTag.type = SBIG('SCAN');
|
||||
return true;
|
||||
}
|
||||
else if (!strcmp(className, "DataSpec::DNAMP1::CTweakPlayerRes") ||
|
||||
!strcmp(className, "DataSpec::DNAMP1::CTweakGunRes") ||
|
||||
!strcmp(className, "DataSpec::DNAMP1::CTweakSlideShow") ||
|
||||
!strcmp(className, "DataSpec::DNAMP1::CTweakPlayer") ||
|
||||
!strcmp(className, "DataSpec::DNAMP1::CTweakCameraBob") ||
|
||||
!strcmp(className, "DataSpec::DNAMP1::CTweakGame") ||
|
||||
!strcmp(className, "DataSpec::DNAMP1::CTweakTargeting") ||
|
||||
!strcmp(className, "DataSpec::DNAMP1::CTweakAutoMapper") ||
|
||||
!strcmp(className, "DataSpec::DNAMP1::CTweakGui") ||
|
||||
!strcmp(className, "DataSpec::DNAMP1::CTweakPlayerControl") ||
|
||||
!strcmp(className, "DataSpec::DNAMP1::CTweakBall") ||
|
||||
!strcmp(className, "DataSpec::DNAMP1::CTweakParticle") ||
|
||||
!strcmp(className, "DataSpec::DNAMP1::CTweakGuiColors") ||
|
||||
!strcmp(className, "DataSpec::DNAMP1::CTweakPlayerGun"))
|
||||
{
|
||||
resTag.type = SBIG('CTWK');
|
||||
return true;
|
||||
}
|
||||
else if (!strcmp(className, "DataSpec::DNAMP1::HINT"))
|
||||
{
|
||||
resTag.type = SBIG('HINT');
|
||||
return true;
|
||||
}
|
||||
else if (!strcmp(className, "ATBL"))
|
||||
{
|
||||
resTag.type = SBIG('ATBL');
|
||||
return true;
|
||||
}
|
||||
else if (!strcmp(className, "MP1OriginalIDs"))
|
||||
{
|
||||
resTag.type = SBIG('OIDS');
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}))
|
||||
return false;
|
||||
}))
|
||||
{
|
||||
resTag.id = path.hash().val32();
|
||||
fclose(fp);
|
||||
|
@ -673,15 +652,12 @@ struct SpecMP1 : SpecBase
|
|||
return {};
|
||||
}
|
||||
|
||||
void cookMesh(const hecl::ProjectPath& out, const hecl::ProjectPath& in,
|
||||
BlendStream& ds, bool fast, hecl::BlenderToken& btok,
|
||||
FCookProgress progress)
|
||||
void cookMesh(const hecl::ProjectPath& out, const hecl::ProjectPath& in, BlendStream& ds, bool fast,
|
||||
hecl::BlenderToken& btok, FCookProgress progress)
|
||||
{
|
||||
Mesh mesh = ds.compileMesh(fast ? hecl::HMDLTopology::Triangles : hecl::HMDLTopology::TriStrips, m_pc ? 16 : -1,
|
||||
[&progress](int surfCount)
|
||||
{
|
||||
progress(hecl::SysFormat(_S("%d"), surfCount).c_str());
|
||||
});
|
||||
Mesh mesh =
|
||||
ds.compileMesh(fast ? hecl::HMDLTopology::Triangles : hecl::HMDLTopology::TriStrips, m_pc ? 16 : -1,
|
||||
[&progress](int surfCount) { progress(hecl::SysFormat(_S("%d"), surfCount).c_str()); });
|
||||
|
||||
if (m_pc)
|
||||
DNAMP1::CMDL::HMDLCook(out, in, mesh);
|
||||
|
@ -689,14 +665,11 @@ struct SpecMP1 : SpecBase
|
|||
DNAMP1::CMDL::Cook(out, in, mesh);
|
||||
}
|
||||
|
||||
void cookActor(const hecl::ProjectPath& out, const hecl::ProjectPath& in,
|
||||
BlendStream& ds, bool fast, hecl::BlenderToken& btok,
|
||||
FCookProgress progress)
|
||||
void cookActor(const hecl::ProjectPath& out, const hecl::ProjectPath& in, BlendStream& ds, bool fast,
|
||||
hecl::BlenderToken& btok, FCookProgress progress)
|
||||
{
|
||||
Actor actor = ds.compileActor();
|
||||
DNAMP1::ANCS::Cook(out, in, actor, ds, m_pc,
|
||||
[&](const hecl::ProjectPath& modelPath) -> bool
|
||||
{
|
||||
DNAMP1::ANCS::Cook(out, in, actor, ds, m_pc, [&](const hecl::ProjectPath& modelPath) -> bool {
|
||||
hecl::ProjectPath cooked;
|
||||
if (m_pc)
|
||||
cooked = modelPath.getCookedPath(SpecEntMP1PC);
|
||||
|
@ -707,9 +680,8 @@ struct SpecMP1 : SpecBase
|
|||
});
|
||||
}
|
||||
|
||||
void cookArea(const hecl::ProjectPath& out, const hecl::ProjectPath& in,
|
||||
BlendStream& ds, bool fast, hecl::BlenderToken& btok,
|
||||
FCookProgress progress)
|
||||
void cookArea(const hecl::ProjectPath& out, const hecl::ProjectPath& in, BlendStream& ds, bool fast,
|
||||
hecl::BlenderToken& btok, FCookProgress progress)
|
||||
{
|
||||
std::vector<std::string> meshes = ds.getMeshList();
|
||||
std::vector<Mesh> meshCompiles;
|
||||
|
@ -726,11 +698,9 @@ struct SpecMP1 : SpecBase
|
|||
progress(_S("Collision Mesh"));
|
||||
continue;
|
||||
}
|
||||
meshCompiles.push_back(ds.compileMesh(mesh, fast ? hecl::HMDLTopology::Triangles : hecl::HMDLTopology::TriStrips, -1,
|
||||
[&](int surfCount)
|
||||
{
|
||||
progress(hecl::SysFormat(_S("%s %d"), meshSys.c_str(), surfCount).c_str());
|
||||
}));
|
||||
meshCompiles.push_back(ds.compileMesh(
|
||||
mesh, fast ? hecl::HMDLTopology::Triangles : hecl::HMDLTopology::TriStrips, -1,
|
||||
[&](int surfCount) { progress(hecl::SysFormat(_S("%s %d"), meshSys.c_str(), surfCount).c_str()); }));
|
||||
}
|
||||
|
||||
if (!colMesh)
|
||||
|
@ -744,24 +714,22 @@ struct SpecMP1 : SpecBase
|
|||
DNAMP1::MREA::Cook(out, in, meshCompiles, *colMesh, lights);
|
||||
}
|
||||
|
||||
void cookWorld(const hecl::ProjectPath& out, const hecl::ProjectPath& in,
|
||||
BlendStream& ds, bool fast, hecl::BlenderToken& btok,
|
||||
FCookProgress progress)
|
||||
void cookWorld(const hecl::ProjectPath& out, const hecl::ProjectPath& in, BlendStream& ds, bool fast,
|
||||
hecl::BlenderToken& btok, FCookProgress progress)
|
||||
{
|
||||
BlendStream::World world = ds.compileWorld();
|
||||
ds.close();
|
||||
DNAMP1::MLVL::Cook(out, in, world, btok);
|
||||
}
|
||||
|
||||
void cookGuiFrame(const hecl::ProjectPath& out, const hecl::ProjectPath& in,
|
||||
BlendStream& ds, hecl::BlenderToken& btok,
|
||||
FCookProgress progress)
|
||||
void cookGuiFrame(const hecl::ProjectPath& out, const hecl::ProjectPath& in, BlendStream& ds,
|
||||
hecl::BlenderToken& btok, FCookProgress progress)
|
||||
{
|
||||
ds.compileGuiFrame(out.getAbsolutePathUTF8(), 0);
|
||||
}
|
||||
|
||||
void cookYAML(const hecl::ProjectPath& out, const hecl::ProjectPath& in,
|
||||
athena::io::IStreamReader& fin, FCookProgress progress)
|
||||
void cookYAML(const hecl::ProjectPath& out, const hecl::ProjectPath& in, athena::io::IStreamReader& fin,
|
||||
FCookProgress progress)
|
||||
{
|
||||
athena::io::YAMLDocReader reader;
|
||||
if (reader.parse(&fin))
|
||||
|
@ -776,6 +744,12 @@ struct SpecMP1 : SpecBase
|
|||
strg.read(reader);
|
||||
DNAMP1::STRG::Cook(strg, out);
|
||||
}
|
||||
else if (!classStr.compare(DNAMP1::SCAN::DNAType()))
|
||||
{
|
||||
DNAMP1::SCAN scan;
|
||||
scan.read(reader);
|
||||
DNAMP1::SCAN::Cook(scan, out);
|
||||
}
|
||||
else if (!classStr.compare(DNAParticle::GPSM<UniqueID32>::DNAType()))
|
||||
{
|
||||
DNAParticle::GPSM<UniqueID32> gpsm;
|
||||
|
@ -945,6 +919,12 @@ struct SpecMP1 : SpecBase
|
|||
strg.read(reader);
|
||||
strg.gatherDependencies(pathsOut);
|
||||
}
|
||||
if (!classStr.compare(DNAMP1::SCAN::DNAType()))
|
||||
{
|
||||
DNAMP1::SCAN scan;
|
||||
scan.read(reader);
|
||||
scan.gatherDependencies(pathsOut);
|
||||
}
|
||||
else if (!classStr.compare(DNAParticle::GPSM<UniqueID32>::DNAType()))
|
||||
{
|
||||
DNAParticle::GPSM<UniqueID32> gpsm;
|
||||
|
@ -990,49 +970,33 @@ struct SpecMP1 : SpecBase
|
|||
}
|
||||
}
|
||||
|
||||
void cookAudioGroup(const hecl::ProjectPath& out, const hecl::ProjectPath& in,
|
||||
FCookProgress progress)
|
||||
void cookAudioGroup(const hecl::ProjectPath& out, const hecl::ProjectPath& in, FCookProgress progress)
|
||||
{
|
||||
DNAMP1::AGSC::Cook(in, out);
|
||||
progress(_S("Done"));
|
||||
}
|
||||
|
||||
void cookSong(const hecl::ProjectPath& out, const hecl::ProjectPath& in,
|
||||
FCookProgress progress)
|
||||
void cookSong(const hecl::ProjectPath& out, const hecl::ProjectPath& in, FCookProgress progress)
|
||||
{
|
||||
DNAMP1::CSNG::Cook(in, out);
|
||||
progress(_S("Done"));
|
||||
}
|
||||
};
|
||||
|
||||
hecl::Database::DataSpecEntry SpecEntMP1 =
|
||||
{
|
||||
_S("MP1"),
|
||||
_S("Data specification for original Metroid Prime engine"),
|
||||
[](hecl::Database::Project& project, hecl::Database::DataSpecTool)
|
||||
-> hecl::Database::IDataSpec* {return new struct SpecMP1(&SpecEntMP1, project, false);}
|
||||
};
|
||||
hecl::Database::DataSpecEntry SpecEntMP1 = {
|
||||
_S("MP1"), _S("Data specification for original Metroid Prime engine"),
|
||||
[](hecl::Database::Project& project, hecl::Database::DataSpecTool) -> hecl::Database::IDataSpec* {
|
||||
return new struct SpecMP1(&SpecEntMP1, project, false);
|
||||
}};
|
||||
|
||||
hecl::Database::DataSpecEntry SpecEntMP1PC =
|
||||
{
|
||||
_S("MP1-PC"),
|
||||
_S("Data specification for PC-optimized Metroid Prime engine"),
|
||||
[](hecl::Database::Project& project, hecl::Database::DataSpecTool tool)
|
||||
-> hecl::Database::IDataSpec*
|
||||
{
|
||||
hecl::Database::DataSpecEntry SpecEntMP1PC = {
|
||||
_S("MP1-PC"), _S("Data specification for PC-optimized Metroid Prime engine"),
|
||||
[](hecl::Database::Project& project, hecl::Database::DataSpecTool tool) -> hecl::Database::IDataSpec* {
|
||||
if (tool != hecl::Database::DataSpecTool::Extract)
|
||||
return new struct SpecMP1(&SpecEntMP1PC, project, true);
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
hecl::Database::DataSpecEntry SpecEntMP1ORIG =
|
||||
{
|
||||
_S("MP1-ORIG"),
|
||||
_S("Data specification for unmodified Metroid Prime resources"),
|
||||
{}
|
||||
};
|
||||
}};
|
||||
|
||||
hecl::Database::DataSpecEntry SpecEntMP1ORIG = {
|
||||
_S("MP1-ORIG"), _S("Data specification for unmodified Metroid Prime resources"), {}};
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "Runtime/Collision/CCollidableOBBTreeGroup.hpp"
|
||||
#include "Runtime/CSaveWorld.hpp"
|
||||
#include "Runtime/AutoMapper/CMapWorld.hpp"
|
||||
#include "Runtime/CScannableObjectInfo.hpp"
|
||||
#include "Audio/CAudioGroupSet.hpp"
|
||||
#include "Audio/CSfxManager.hpp"
|
||||
#include "Runtime/CDependencyGroup.hpp"
|
||||
|
@ -108,6 +109,7 @@ ProjectResourceFactoryMP1::ProjectResourceFactoryMP1(hecl::ClientProcess& client
|
|||
m_factoryMgr.AddFactory(FOURCC('SAVW'), FFactoryFunc(FSaveWorldFactory));
|
||||
m_factoryMgr.AddFactory(FOURCC('MAPW'), FFactoryFunc(FMapWorldFactory));
|
||||
m_factoryMgr.AddFactory(FOURCC('OIDS'), FFactoryFunc(FMP1OriginalIDsFactory));
|
||||
m_factoryMgr.AddFactory(FOURCC('SCAN'), FFactoryFunc(FScannableObjectInfoFactory));
|
||||
}
|
||||
|
||||
void ProjectResourceFactoryMP1::IndexMP1Resources(hecl::Database::Project& proj, CSimplePool& sp)
|
||||
|
|
|
@ -3,32 +3,19 @@
|
|||
|
||||
namespace urde
|
||||
{
|
||||
CScannableObjectInfo::CScannableObjectInfo(CInputStream& in, ResId resId)
|
||||
: x0_scannableObjectId(resId)
|
||||
CScannableObjectInfo::CScannableObjectInfo(CInputStream& in, ResId resId) : x0_scannableObjectId(resId)
|
||||
{
|
||||
u32 version = in.readUint32Big();
|
||||
Load(in, version);
|
||||
}
|
||||
|
||||
ResId CScannableObjectInfo::GetScannableObjectId() const
|
||||
{
|
||||
return x0_scannableObjectId;
|
||||
}
|
||||
ResId CScannableObjectInfo::GetScannableObjectId() const { return x0_scannableObjectId; }
|
||||
|
||||
ResId CScannableObjectInfo::GetStringTableId() const
|
||||
{
|
||||
return x4_stringId;
|
||||
}
|
||||
ResId CScannableObjectInfo::GetStringTableId() const { return x4_stringId; }
|
||||
|
||||
float CScannableObjectInfo::GetTotalDownloadTime() const
|
||||
{
|
||||
return x8_totalDownloadTime;
|
||||
}
|
||||
float CScannableObjectInfo::GetTotalDownloadTime() const { return x8_totalDownloadTime; }
|
||||
|
||||
const CScannableObjectInfo::SBucket& CScannableObjectInfo::GetBucket(s32 idx) const
|
||||
{
|
||||
return x14_buckets[idx];
|
||||
}
|
||||
const CScannableObjectInfo::SBucket& CScannableObjectInfo::GetBucket(s32 idx) const { return x14_buckets[idx]; }
|
||||
|
||||
void CScannableObjectInfo::Load(CInputStream& in, u32 version)
|
||||
{
|
||||
|
@ -46,7 +33,7 @@ void CScannableObjectInfo::Load(CInputStream& in, u32 version)
|
|||
if (version > 4)
|
||||
x10_important = in.readBool();
|
||||
|
||||
for (u32 i = 0 ; i<4 ; i++)
|
||||
for (u32 i = 0; i < 4; i++)
|
||||
x14_buckets.emplace_back(in, version);
|
||||
}
|
||||
|
||||
|
@ -65,9 +52,9 @@ CScannableObjectInfo::SBucket::SBucket(CInputStream& in, u32 version)
|
|||
}
|
||||
}
|
||||
|
||||
CFactoryFnReturn FScannableObjectInfoFactory(const SObjectTag& tag, CInputStream& in, const CVParamTransfer &)
|
||||
CFactoryFnReturn FScannableObjectInfoFactory(const SObjectTag& tag, CInputStream& in, const CVParamTransfer&,
|
||||
CObjectReference* selfRef)
|
||||
{
|
||||
return TToken<CScannableObjectInfo>::GetIObjObjectFor(std::make_unique<CScannableObjectInfo>(in, tag.id));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ private:
|
|||
u32 xc_category = 0;
|
||||
bool x10_important = false;
|
||||
rstl::reserved_vector<SBucket, 4> x14_buckets;
|
||||
|
||||
public:
|
||||
CScannableObjectInfo(CInputStream&, ResId);
|
||||
ResId GetStringTableId() const;
|
||||
|
@ -43,6 +44,7 @@ public:
|
|||
bool IsImportant() const;
|
||||
};
|
||||
|
||||
CFactoryFnReturn FScannableObjectInfoFactory(const SObjectTag&, CInputStream&, const CVParamTransfer&);
|
||||
CFactoryFnReturn FScannableObjectInfoFactory(const SObjectTag&, CInputStream&, const CVParamTransfer&,
|
||||
CObjectReference* selfRef);
|
||||
}
|
||||
#endif // __URDE_CSCANNABLEOBJECTINFO_HPP__
|
||||
|
|
|
@ -23,71 +23,85 @@ void CScriptGenerator::Accept(IVisitor& visitor) { visitor.Visit(this); }
|
|||
|
||||
void CScriptGenerator::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId objId, CStateManager& stateMgr)
|
||||
{
|
||||
if (msg == EScriptObjectMessage::SetToZero && GetActive())
|
||||
if (msg == EScriptObjectMessage::SetToZero && GetActive() && !x20_conns.empty())
|
||||
{
|
||||
if (!x20_conns.empty())
|
||||
std::vector<TUniqueId> follows;
|
||||
follows.reserve(x20_conns.size());
|
||||
for (const SConnection& conn : x20_conns)
|
||||
{
|
||||
std::vector<TUniqueId> follows;
|
||||
follows.reserve(x20_conns.size());
|
||||
for (const SConnection& conn : x20_conns)
|
||||
{
|
||||
if (conn.x0_state != EScriptObjectState::Zero || conn.x4_msg != EScriptObjectMessage::Follow)
|
||||
continue;
|
||||
if (conn.x0_state != EScriptObjectState::Zero || conn.x4_msg != EScriptObjectMessage::Follow)
|
||||
continue;
|
||||
|
||||
TUniqueId uid = stateMgr.GetIdForScript(conn.x8_objId);
|
||||
if (stateMgr.GetObjectById(uid) != nullptr)
|
||||
follows.push_back(uid);
|
||||
TUniqueId uid = stateMgr.GetIdForScript(conn.x8_objId);
|
||||
if (stateMgr.GetObjectById(uid) != nullptr)
|
||||
follows.push_back(uid);
|
||||
}
|
||||
|
||||
std::vector<std::pair<TUniqueId, TEditorId>> activates;
|
||||
activates.reserve(x20_conns.size());
|
||||
|
||||
for (const SConnection& conn : x20_conns)
|
||||
{
|
||||
if (conn.x0_state != EScriptObjectState::Zero)
|
||||
continue;
|
||||
|
||||
TUniqueId uid = stateMgr.GetIdForScript(conn.x8_objId);
|
||||
|
||||
if (conn.x4_msg != EScriptObjectMessage::Activate)
|
||||
{
|
||||
stateMgr.SendScriptMsgAlways(GetUniqueId(), uid, conn.x4_msg);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<std::pair<TUniqueId, TEditorId>> activates;
|
||||
activates.reserve(x20_conns.size());
|
||||
if (stateMgr.GetObjectById(uid) != nullptr)
|
||||
activates.emplace_back(uid, conn.x8_objId);
|
||||
}
|
||||
|
||||
for (const SConnection& conn : x20_conns)
|
||||
for (u32 i = 0; i < x34_spawnCount; ++i)
|
||||
{
|
||||
if (activates.size() == 0 || follows.size() == 0)
|
||||
return;
|
||||
|
||||
u32 activatesRand = 0.99f * (stateMgr.GetActiveRandom()->Float() * activates.size());
|
||||
u32 followsRand = 0.99f * (stateMgr.GetActiveRandom()->Float() * follows.size());
|
||||
|
||||
for (u32 j = 0; j < activates.size(); ++j)
|
||||
if (TCastToConstPtr<CScriptSound>(stateMgr.GetObjectById(activates[j].first)))
|
||||
activatesRand = j;
|
||||
|
||||
std::pair<TUniqueId, TEditorId> idPair = activates[activatesRand];
|
||||
CEntity* activate = stateMgr.ObjectById(idPair.first);
|
||||
CEntity* follow = stateMgr.ObjectById(follows[followsRand]);
|
||||
|
||||
if (!activate || !follow)
|
||||
break;
|
||||
|
||||
bool oldGeneratingObject = stateMgr.GetIsGeneratingObject();
|
||||
stateMgr.SetIsGeneratingObject(true);
|
||||
std::pair<TEditorId, TUniqueId> objId = stateMgr.GenerateObject(idPair.second);
|
||||
stateMgr.SetIsGeneratingObject(oldGeneratingObject);
|
||||
|
||||
if (objId.second != kInvalidUniqueId)
|
||||
{
|
||||
if (conn.x0_state != EScriptObjectState::Zero)
|
||||
continue;
|
||||
TCastToPtr<CActor> activateActor(stateMgr.ObjectById(idPair.first));
|
||||
TCastToPtr<CActor> followActor(follow);
|
||||
TCastToPtr<CWallCrawlerSwarm> wallCrawlerSwarm(follow);
|
||||
|
||||
TUniqueId uid = stateMgr.GetIdForScript(conn.x8_objId);
|
||||
|
||||
if (conn.x4_msg != EScriptObjectMessage::Activate)
|
||||
if (activateActor && wallCrawlerSwarm)
|
||||
{
|
||||
stateMgr.SendScriptMsgAlways(GetUniqueId(), uid, conn.x4_msg);
|
||||
continue;
|
||||
if (x38_25_inheritTransform)
|
||||
activateActor->SetTransform(wallCrawlerSwarm->GetTransform());
|
||||
activateActor->SetTranslation(wallCrawlerSwarm->GetLastKilledOffset() + x3c_offset);
|
||||
}
|
||||
|
||||
if (stateMgr.GetObjectById(uid) != nullptr)
|
||||
activates.emplace_back(uid, conn.x8_objId);
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < x34_spawnCount; ++i)
|
||||
{
|
||||
if (activates.size() == 0 || follows.size() == 0)
|
||||
return;
|
||||
|
||||
u32 activatesRand = 0.99f * (stateMgr.GetActiveRandom()->Float() * activates.size());
|
||||
u32 followsRand = 0.99f * (stateMgr.GetActiveRandom()->Float() * follows.size());
|
||||
|
||||
for (u32 j = 0; j < activates.size(); ++j)
|
||||
if (TCastToConstPtr<CScriptSound>(stateMgr.GetObjectById(activates[j].first)))
|
||||
activatesRand = j;
|
||||
|
||||
std::pair<TUniqueId, TEditorId> idPair = activates[activatesRand];
|
||||
CEntity* activate = stateMgr.ObjectById(idPair.first);
|
||||
CEntity* follow = stateMgr.ObjectById(follows[followsRand]);
|
||||
|
||||
if (!activate || !follow)
|
||||
break;
|
||||
|
||||
bool oldGeneratingObject = stateMgr.GetIsGeneratingObject();
|
||||
stateMgr.SetIsGeneratingObject(true);
|
||||
std::pair<TEditorId, TUniqueId> objId = stateMgr.GenerateObject(idPair.second);
|
||||
stateMgr.SetIsGeneratingObject(oldGeneratingObject);
|
||||
|
||||
if (objId.second != kInvalidUniqueId)
|
||||
else if (activateActor && followActor)
|
||||
{
|
||||
TCastToPtr<CActor> activateActor(stateMgr.ObjectById(idPair.first));
|
||||
TCastToPtr<CActor> followActor(follow);
|
||||
TCastToPtr<CWallCrawlerSwarm> wallCrawlerSwarm(follow);
|
||||
if (x38_25_inheritTransform)
|
||||
activateActor->SetTransform(followActor->GetTransform());
|
||||
activateActor->SetTranslation(followActor->GetTranslation() + x3c_offset);
|
||||
}
|
||||
else if (follow != nullptr)
|
||||
{
|
||||
TCastToPtr<CActor> activateActor(stateMgr.ObjectById(objId.second));
|
||||
|
||||
if (activateActor && wallCrawlerSwarm)
|
||||
{
|
||||
|
@ -101,35 +115,18 @@ void CScriptGenerator::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId objId
|
|||
activateActor->SetTransform(followActor->GetTransform());
|
||||
activateActor->SetTranslation(followActor->GetTranslation() + x3c_offset);
|
||||
}
|
||||
else if (follow != nullptr)
|
||||
{
|
||||
TCastToPtr<CActor> activateActor(stateMgr.ObjectById(objId.second));
|
||||
|
||||
if (activateActor && wallCrawlerSwarm)
|
||||
{
|
||||
if (x38_25_inheritTransform)
|
||||
activateActor->SetTransform(wallCrawlerSwarm->GetTransform());
|
||||
activateActor->SetTranslation(wallCrawlerSwarm->GetLastKilledOffset() + x3c_offset);
|
||||
}
|
||||
else if (activateActor && followActor)
|
||||
{
|
||||
if (x38_25_inheritTransform)
|
||||
activateActor->SetTransform(followActor->GetTransform());
|
||||
activateActor->SetTranslation(followActor->GetTranslation() + x3c_offset);
|
||||
}
|
||||
|
||||
float rnd = stateMgr.GetActiveRandom()->Range(x48_minScale, x4c_maxScale);
|
||||
CModelData* mData = followActor->ModelData();
|
||||
if (mData && (mData->AnimationData() || mData->GetNormalModel()))
|
||||
mData->SetScale(rnd * mData->GetScale());
|
||||
}
|
||||
|
||||
stateMgr.SendScriptMsg(activate, GetUniqueId(), EScriptObjectMessage::Activate);
|
||||
|
||||
activates.erase(std::find(activates.begin(), activates.end(), idPair));
|
||||
if (!x38_24_reuseFollowers)
|
||||
follows.erase(std::find(follows.begin(), follows.end(), follows[followsRand]));
|
||||
float rnd = stateMgr.GetActiveRandom()->Range(x48_minScale, x4c_maxScale);
|
||||
CModelData* mData = followActor->ModelData();
|
||||
if (mData && (mData->AnimationData() || mData->GetNormalModel()))
|
||||
mData->SetScale(rnd * mData->GetScale());
|
||||
}
|
||||
|
||||
stateMgr.SendScriptMsg(activate, GetUniqueId(), EScriptObjectMessage::Activate);
|
||||
|
||||
activates.erase(std::find(activates.begin(), activates.end(), idPair));
|
||||
if (!x38_24_reuseFollowers)
|
||||
follows.erase(std::find(follows.begin(), follows.end(), follows[followsRand]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue