WIP Prepend directive

This commit is contained in:
Christian Semmler 2025-08-19 16:05:25 -07:00
parent d10ac7e77c
commit 0960b1a593
4 changed files with 168 additions and 34 deletions

View File

@ -2,6 +2,7 @@
#include "compat.h" #include "compat.h"
#include "decomp.h" #include "decomp.h"
#include "extensions/siloader.h"
#include "mxautolock.h" #include "mxautolock.h"
#include "mxmisc.h" #include "mxmisc.h"
#include "mxnotificationparam.h" #include "mxnotificationparam.h"
@ -12,6 +13,8 @@
DECOMP_SIZE_ASSERT(MxNotification, 0x08); DECOMP_SIZE_ASSERT(MxNotification, 0x08);
DECOMP_SIZE_ASSERT(MxNotificationManager, 0x40); DECOMP_SIZE_ASSERT(MxNotificationManager, 0x40);
using namespace Extensions;
// FUNCTION: LEGO1 0x100ac220 // FUNCTION: LEGO1 0x100ac220
MxNotification::MxNotification(MxCore* p_target, const MxNotificationParam& p_param) MxNotification::MxNotification(MxCore* p_target, const MxNotificationParam& p_param)
{ {
@ -105,6 +108,11 @@ MxResult MxNotificationManager::Tickle()
while (m_sendList->size() != 0) { while (m_sendList->size() != 0) {
MxNotification* notif = m_sendList->front(); MxNotification* notif = m_sendList->front();
m_sendList->pop_front(); m_sendList->pop_front();
if (notif->GetParam()->GetNotification() == c_notificationEndAction) {
Extension<SiLoader>::Call(HandleEndAction, (MxEndActionNotificationParam&) *notif->GetParam());
}
notif->GetTarget()->Notify(*notif->GetParam()); notif->GetTarget()->Notify(*notif->GetParam());
delete notif; delete notif;
} }
@ -159,6 +167,11 @@ void MxNotificationManager::FlushPending(MxCore* p_listener)
while (pending.size() != 0) { while (pending.size() != 0) {
notif = pending.front(); notif = pending.front();
pending.pop_front(); pending.pop_front();
if (notif->GetParam()->GetNotification() == c_notificationEndAction) {
Extension<SiLoader>::Call(HandleEndAction, (MxEndActionNotificationParam&) *notif->GetParam());
}
notif->GetTarget()->Notify(*notif->GetParam()); notif->GetTarget()->Notify(*notif->GetParam());
delete notif; delete notif;
} }

View File

@ -66,7 +66,7 @@ MxStreamController* MxStreamer::Open(const char* p_name, MxU16 p_lookupType)
MxStreamController* stream = NULL; MxStreamController* stream = NULL;
if (GetOpenStream(p_name)) { if ((stream = GetOpenStream(p_name))) {
goto done; goto done;
} }

View File

@ -2,6 +2,7 @@
#include "extensions/extensions.h" #include "extensions/extensions.h"
#include "legoworld.h" #include "legoworld.h"
#include "mxactionnotificationparam.h"
#include "mxatom.h" #include "mxatom.h"
#include <map> #include <map>
@ -24,18 +25,23 @@ class SiLoader {
static std::optional<MxResult> HandleStart(MxDSAction& p_action); static std::optional<MxResult> HandleStart(MxDSAction& p_action);
static std::optional<MxBool> HandleRemove(StreamObject p_object, LegoWorld* world); static std::optional<MxBool> HandleRemove(StreamObject p_object, LegoWorld* world);
static std::optional<MxBool> HandleDelete(MxDSAction& p_action); static std::optional<MxBool> HandleDelete(MxDSAction& p_action);
static MxBool HandleEndAction(MxEndActionNotificationParam& p_param);
static std::map<std::string, std::string> options; static std::map<std::string, std::string> options;
static std::vector<std::string> files; static std::vector<std::string> files;
static std::vector<std::string> directives;
static bool enabled; static bool enabled;
private: private:
static std::vector<std::pair<StreamObject, StreamObject>> startWith; static std::vector<std::pair<StreamObject, StreamObject>> startWith;
static std::vector<std::pair<StreamObject, StreamObject>> removeWith; static std::vector<std::pair<StreamObject, StreamObject>> removeWith;
static std::vector<std::pair<StreamObject, StreamObject>> replace; static std::vector<std::pair<StreamObject, StreamObject>> replace;
static std::vector<std::pair<StreamObject, StreamObject>> prepend;
static bool LoadFile(const char* p_file); static bool LoadFile(const char* p_file);
static void ParseDirectives(const MxAtomId& p_atom, si::Core* p_core, MxAtomId p_parentReplacedAtom = MxAtomId()); static bool LoadDirective(const char* p_directive);
static MxStreamController* OpenStream(const char* p_file);
static void ParseExtra(const MxAtomId& p_atom, si::Core* p_core, MxAtomId p_parentReplacedAtom = MxAtomId());
}; };
#ifdef EXTENSIONS #ifdef EXTENSIONS
@ -44,11 +50,13 @@ constexpr auto HandleFind = &SiLoader::HandleFind;
constexpr auto HandleStart = &SiLoader::HandleStart; constexpr auto HandleStart = &SiLoader::HandleStart;
constexpr auto HandleRemove = &SiLoader::HandleRemove; constexpr auto HandleRemove = &SiLoader::HandleRemove;
constexpr auto HandleDelete = &SiLoader::HandleDelete; constexpr auto HandleDelete = &SiLoader::HandleDelete;
constexpr auto HandleEndAction = &SiLoader::HandleEndAction;
#else #else
constexpr decltype(&SiLoader::Load) Load = nullptr; constexpr decltype(&SiLoader::Load) Load = nullptr;
constexpr decltype(&SiLoader::HandleFind) HandleFind = nullptr; constexpr decltype(&SiLoader::HandleFind) HandleFind = nullptr;
constexpr decltype(&SiLoader::HandleStart) HandleStart = nullptr; constexpr decltype(&SiLoader::HandleStart) HandleStart = nullptr;
constexpr decltype(&SiLoader::HandleRemove) HandleRemove = nullptr; constexpr decltype(&SiLoader::HandleRemove) HandleRemove = nullptr;
constexpr decltype(&SiLoader::HandleDelete) HandleDelete = nullptr; constexpr decltype(&SiLoader::HandleDelete) HandleDelete = nullptr;
constexpr decltype(&SiLoader::HandleEndAction) HandleEndAction = nullptr;
#endif #endif
}; // namespace Extensions }; // namespace Extensions

View File

@ -11,9 +11,11 @@ using namespace Extensions;
std::map<std::string, std::string> SiLoader::options; std::map<std::string, std::string> SiLoader::options;
std::vector<std::string> SiLoader::files; std::vector<std::string> SiLoader::files;
std::vector<std::string> SiLoader::directives;
std::vector<std::pair<SiLoader::StreamObject, SiLoader::StreamObject>> SiLoader::startWith; std::vector<std::pair<SiLoader::StreamObject, SiLoader::StreamObject>> SiLoader::startWith;
std::vector<std::pair<SiLoader::StreamObject, SiLoader::StreamObject>> SiLoader::removeWith; std::vector<std::pair<SiLoader::StreamObject, SiLoader::StreamObject>> SiLoader::removeWith;
std::vector<std::pair<SiLoader::StreamObject, SiLoader::StreamObject>> SiLoader::replace; std::vector<std::pair<SiLoader::StreamObject, SiLoader::StreamObject>> SiLoader::replace;
std::vector<std::pair<SiLoader::StreamObject, SiLoader::StreamObject>> SiLoader::prepend;
bool SiLoader::enabled = false; bool SiLoader::enabled = false;
void SiLoader::Initialize() void SiLoader::Initialize()
@ -21,11 +23,19 @@ void SiLoader::Initialize()
char* files = SDL_strdup(options["si loader:files"].c_str()); char* files = SDL_strdup(options["si loader:files"].c_str());
char* saveptr; char* saveptr;
for (char* file = SDL_strtok_r(files, ",\n", &saveptr); file; file = SDL_strtok_r(NULL, ",\n", &saveptr)) { for (char* file = SDL_strtok_r(files, ",\n\r", &saveptr); file; file = SDL_strtok_r(NULL, ",\n\r", &saveptr)) {
SiLoader::files.emplace_back(file); SiLoader::files.emplace_back(file);
} }
char* directives = SDL_strdup(options["si loader:directives"].c_str());
for (char* directive = SDL_strtok_r(directives, ",\n\r", &saveptr); directive;
directive = SDL_strtok_r(NULL, ",\n\r", &saveptr)) {
SiLoader::directives.emplace_back(directive);
}
SDL_free(files); SDL_free(files);
SDL_free(directives);
} }
bool SiLoader::Load() bool SiLoader::Load()
@ -34,6 +44,10 @@ bool SiLoader::Load()
LoadFile(file.c_str()); LoadFile(file.c_str());
} }
for (const auto& directive : directives) {
LoadDirective(directive.c_str());
}
return true; return true;
} }
@ -51,30 +65,48 @@ std::optional<MxCore*> SiLoader::HandleFind(StreamObject p_object, LegoWorld* wo
std::optional<MxResult> SiLoader::HandleStart(MxDSAction& p_action) std::optional<MxResult> SiLoader::HandleStart(MxDSAction& p_action)
{ {
StreamObject object{p_action.GetAtomId(), p_action.GetObjectId()}; StreamObject object{p_action.GetAtomId(), p_action.GetObjectId()};
auto start = [](const StreamObject& p_object, MxDSAction& p_in, MxDSAction& p_out) -> MxResult {
if (!OpenStream(p_object.first.GetInternal())) {
return FAILURE;
}
p_out.SetAtomId(p_object.first);
p_out.SetObjectId(p_object.second);
p_out.SetUnknown24(p_in.GetUnknown24());
p_out.SetNotificationObject(p_in.GetNotificationObject());
p_out.SetOrigin(p_in.GetOrigin());
return Start(&p_out);
};
for (const auto& key : startWith) { for (const auto& key : startWith) {
if (key.first == object) { if (key.first == object) {
MxDSAction action; MxDSAction action;
action.SetAtomId(key.second.first); start(key.second, p_action, action);
action.SetObjectId(key.second.second);
action.SetUnknown24(p_action.GetUnknown24());
action.SetNotificationObject(p_action.GetNotificationObject());
action.SetOrigin(p_action.GetOrigin());
Start(&action);
} }
} }
for (const auto& key : replace) { for (const auto& key : replace) {
if (key.first == object) { if (key.first == object) {
MxDSAction action; MxDSAction action;
action.SetAtomId(key.second.first); MxResult result = start(key.second, p_action, action);
action.SetObjectId(key.second.second);
action.SetUnknown24(p_action.GetUnknown24()); if (result == SUCCESS) {
action.SetNotificationObject(p_action.GetNotificationObject()); p_action.SetUnknown24(action.GetUnknown24());
action.SetOrigin(p_action.GetOrigin()); }
return result;
}
}
for (const auto& key : prepend) {
if (key.first == object) {
MxDSAction action;
MxResult result = start(key.second, p_action, action);
if (result == SUCCESS) {
p_action.SetUnknown24(action.GetUnknown24());
}
MxResult result = Start(&action);
p_action.SetUnknown24(action.GetUnknown24());
return result; return result;
} }
} }
@ -102,29 +134,26 @@ std::optional<MxBool> SiLoader::HandleRemove(StreamObject p_object, LegoWorld* w
std::optional<MxBool> SiLoader::HandleDelete(MxDSAction& p_action) std::optional<MxBool> SiLoader::HandleDelete(MxDSAction& p_action)
{ {
StreamObject object{p_action.GetAtomId(), p_action.GetObjectId()}; StreamObject object{p_action.GetAtomId(), p_action.GetObjectId()};
auto deleteObject = [](const StreamObject& p_object, MxDSAction& p_in, MxDSAction& p_out) {
p_out.SetAtomId(p_object.first);
p_out.SetObjectId(p_object.second);
p_out.SetUnknown24(p_in.GetUnknown24());
p_out.SetNotificationObject(p_in.GetNotificationObject());
p_out.SetOrigin(p_in.GetOrigin());
DeleteObject(p_out);
};
for (const auto& key : removeWith) { for (const auto& key : removeWith) {
if (key.first == object) { if (key.first == object) {
MxDSAction action; MxDSAction action;
action.SetAtomId(key.second.first); deleteObject(key.second, p_action, action);
action.SetObjectId(key.second.second);
action.SetUnknown24(p_action.GetUnknown24());
action.SetNotificationObject(p_action.GetNotificationObject());
action.SetOrigin(p_action.GetOrigin());
DeleteObject(action);
} }
} }
for (const auto& key : replace) { for (const auto& key : replace) {
if (key.first == object) { if (key.first == object) {
MxDSAction action; MxDSAction action;
action.SetAtomId(key.second.first); deleteObject(key.second, p_action, action);
action.SetObjectId(key.second.second);
action.SetUnknown24(p_action.GetUnknown24());
action.SetNotificationObject(p_action.GetNotificationObject());
action.SetOrigin(p_action.GetOrigin());
DeleteObject(action);
p_action.SetUnknown24(action.GetUnknown24()); p_action.SetUnknown24(action.GetUnknown24());
return TRUE; return TRUE;
} }
@ -133,6 +162,32 @@ std::optional<MxBool> SiLoader::HandleDelete(MxDSAction& p_action)
return std::nullopt; return std::nullopt;
} }
MxBool SiLoader::HandleEndAction(MxEndActionNotificationParam& p_param)
{
StreamObject object{p_param.GetAction()->GetAtomId(), p_param.GetAction()->GetObjectId()};
auto start = [](const StreamObject& p_object, MxDSAction& p_in, MxDSAction& p_out) {
if (!OpenStream(p_object.first.GetInternal())) {
return;
}
p_out.SetAtomId(p_object.first);
p_out.SetObjectId(p_object.second);
p_out.SetUnknown24(-1);
p_out.SetNotificationObject(p_in.GetNotificationObject());
p_out.SetOrigin(p_in.GetOrigin());
Start(&p_out);
};
for (const auto& key : prepend) {
if (key.second == object) {
MxDSAction action;
start(key.second, *p_param.GetAction(), action);
}
}
return TRUE;
}
bool SiLoader::LoadFile(const char* p_file) bool SiLoader::LoadFile(const char* p_file)
{ {
si::Interleaf si; si::Interleaf si;
@ -150,16 +205,65 @@ bool SiLoader::LoadFile(const char* p_file)
} }
} }
if (!(controller = Streamer()->Open(p_file, MxStreamer::e_diskStream))) { if (!(controller = OpenStream(p_file))) {
SDL_Log("Could not load SI file %s", p_file);
return false; return false;
} }
ParseDirectives(controller->GetAtom(), &si); ParseExtra(controller->GetAtom(), &si);
return true; return true;
} }
void SiLoader::ParseDirectives(const MxAtomId& p_atom, si::Core* p_core, MxAtomId p_parentReplacedAtom) bool SiLoader::LoadDirective(const char* p_directive)
{
char originAtom[256], targetAtom[256];
uint32_t originId, targetId;
if (SDL_sscanf(p_directive, "StartWith:%255[^;];%d;%255[^;];%d", originAtom, &originId, targetAtom, &targetId) ==
4) {
startWith.emplace_back(
StreamObject{MxAtomId{originAtom, e_lowerCase2}, originId},
StreamObject{MxAtomId{targetAtom, e_lowerCase2}, targetId}
);
}
if (SDL_sscanf(p_directive, "RemoveWith:%255[^;];%d;%255[^;];%d", originAtom, &originId, targetAtom, &targetId) ==
4) {
removeWith.emplace_back(
StreamObject{MxAtomId{originAtom, e_lowerCase2}, originId},
StreamObject{MxAtomId{targetAtom, e_lowerCase2}, targetId}
);
}
if (SDL_sscanf(p_directive, "Replace:%255[^;];%d;%255[^;];%d", originAtom, &originId, targetAtom, &targetId) == 4) {
replace.emplace_back(
StreamObject{MxAtomId{originAtom, e_lowerCase2}, originId},
StreamObject{MxAtomId{targetAtom, e_lowerCase2}, targetId}
);
}
if (SDL_sscanf(p_directive, "Prepend:%255[^;];%d;%255[^;];%d", originAtom, &originId, targetAtom, &targetId) == 4) {
prepend.emplace_back(
StreamObject{MxAtomId{originAtom, e_lowerCase2}, originId},
StreamObject{MxAtomId{targetAtom, e_lowerCase2}, targetId}
);
}
return true;
}
MxStreamController* SiLoader::OpenStream(const char* p_file)
{
MxStreamController* controller;
if (!(controller = Streamer()->Open(p_file, MxStreamer::e_diskStream))) {
SDL_Log("Could not load SI file %s", p_file);
return nullptr;
}
return controller;
}
void SiLoader::ParseExtra(const MxAtomId& p_atom, si::Core* p_core, MxAtomId p_parentReplacedAtom)
{ {
for (si::Core* child : p_core->GetChildren()) { for (si::Core* child : p_core->GetChildren()) {
MxAtomId replacedAtom = p_parentReplacedAtom; MxAtomId replacedAtom = p_parentReplacedAtom;
@ -206,9 +310,18 @@ void SiLoader::ParseDirectives(const MxAtomId& p_atom, si::Core* p_core, MxAtomI
} }
} }
} }
if ((directive = SDL_strstr(extra.c_str(), "Prepend:"))) {
if (SDL_sscanf(directive, "Prepend:%255[^;];%d", atom, &id) == 2) {
prepend.emplace_back(
StreamObject{MxAtomId{atom, e_lowerCase2}, id},
StreamObject{p_atom, object->id_}
);
}
}
} }
} }
ParseDirectives(p_atom, child, replacedAtom); ParseExtra(p_atom, child, replacedAtom);
} }
} }