Externally track MemoryRelays

This commit is contained in:
Phillip Stephens 2017-01-31 03:21:45 -08:00
parent 0ed44f1cdc
commit 5b5f3318b0
10 changed files with 471 additions and 379 deletions

View File

@ -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);

View File

@ -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;
}
}
}

View File

@ -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);
}
};
}
}

View File

@ -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"; }
}
}

View File

@ -84,6 +84,7 @@ struct STRG : ISTRG
return true;
}
void gatherDependencies(std::vector<hecl::ProjectPath> &pathsOut) const;
};
}

View File

@ -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"), {}};
}

View File

@ -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)

View File

@ -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));
}
}

View File

@ -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__

View File

@ -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]));
}
}
}