mirror of
https://github.com/isledecomp/isle-portable.git
synced 2026-01-11 10:31:16 +00:00
Add new directives to SiLoader, allow specifying directives in .ini (#688)
* WIP Prepend directive * WIP * Add new directives
This commit is contained in:
parent
3017cd24e0
commit
e709400dc6
@ -2,6 +2,7 @@
|
||||
|
||||
#include "compat.h"
|
||||
#include "decomp.h"
|
||||
#include "extensions/siloader.h"
|
||||
#include "mxautolock.h"
|
||||
#include "mxmisc.h"
|
||||
#include "mxnotificationparam.h"
|
||||
@ -12,6 +13,8 @@
|
||||
DECOMP_SIZE_ASSERT(MxNotification, 0x08);
|
||||
DECOMP_SIZE_ASSERT(MxNotificationManager, 0x40);
|
||||
|
||||
using namespace Extensions;
|
||||
|
||||
// FUNCTION: LEGO1 0x100ac220
|
||||
MxNotification::MxNotification(MxCore* p_target, const MxNotificationParam& p_param)
|
||||
{
|
||||
@ -105,6 +108,11 @@ MxResult MxNotificationManager::Tickle()
|
||||
while (m_sendList->size() != 0) {
|
||||
MxNotification* notif = m_sendList->front();
|
||||
m_sendList->pop_front();
|
||||
|
||||
if (notif->GetParam()->GetNotification() == c_notificationEndAction) {
|
||||
Extension<SiLoader>::Call(HandleEndAction, (MxEndActionNotificationParam&) *notif->GetParam());
|
||||
}
|
||||
|
||||
notif->GetTarget()->Notify(*notif->GetParam());
|
||||
delete notif;
|
||||
}
|
||||
@ -159,6 +167,11 @@ void MxNotificationManager::FlushPending(MxCore* p_listener)
|
||||
while (pending.size() != 0) {
|
||||
notif = pending.front();
|
||||
pending.pop_front();
|
||||
|
||||
if (notif->GetParam()->GetNotification() == c_notificationEndAction) {
|
||||
Extension<SiLoader>::Call(HandleEndAction, (MxEndActionNotificationParam&) *notif->GetParam());
|
||||
}
|
||||
|
||||
notif->GetTarget()->Notify(*notif->GetParam());
|
||||
delete notif;
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@ MxStreamController* MxStreamer::Open(const char* p_name, MxU16 p_lookupType)
|
||||
|
||||
MxStreamController* stream = NULL;
|
||||
|
||||
if (GetOpenStream(p_name)) {
|
||||
if ((stream = GetOpenStream(p_name))) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
#include "extensions/extensions.h"
|
||||
#include "legoworld.h"
|
||||
#include "mxactionnotificationparam.h"
|
||||
#include "mxatom.h"
|
||||
|
||||
#include <map>
|
||||
@ -24,18 +25,25 @@ class SiLoader {
|
||||
static std::optional<MxResult> HandleStart(MxDSAction& p_action);
|
||||
static std::optional<MxBool> HandleRemove(StreamObject p_object, LegoWorld* world);
|
||||
static std::optional<MxBool> HandleDelete(MxDSAction& p_action);
|
||||
static MxBool HandleEndAction(MxEndActionNotificationParam& p_param);
|
||||
|
||||
static std::map<std::string, std::string> options;
|
||||
static std::vector<std::string> files;
|
||||
static std::vector<std::string> directives;
|
||||
static bool enabled;
|
||||
|
||||
private:
|
||||
static std::vector<std::pair<StreamObject, StreamObject>> startWith;
|
||||
static std::vector<std::pair<StreamObject, StreamObject>> removeWith;
|
||||
static std::vector<std::pair<StreamObject, StreamObject>> replace;
|
||||
static std::vector<std::pair<StreamObject, StreamObject>> prepend;
|
||||
static std::vector<StreamObject> fullScreenMovie;
|
||||
static std::vector<StreamObject> disable3d;
|
||||
|
||||
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
|
||||
@ -44,11 +52,13 @@ constexpr auto HandleFind = &SiLoader::HandleFind;
|
||||
constexpr auto HandleStart = &SiLoader::HandleStart;
|
||||
constexpr auto HandleRemove = &SiLoader::HandleRemove;
|
||||
constexpr auto HandleDelete = &SiLoader::HandleDelete;
|
||||
constexpr auto HandleEndAction = &SiLoader::HandleEndAction;
|
||||
#else
|
||||
constexpr decltype(&SiLoader::Load) Load = nullptr;
|
||||
constexpr decltype(&SiLoader::HandleFind) HandleFind = nullptr;
|
||||
constexpr decltype(&SiLoader::HandleStart) HandleStart = nullptr;
|
||||
constexpr decltype(&SiLoader::HandleRemove) HandleRemove = nullptr;
|
||||
constexpr decltype(&SiLoader::HandleDelete) HandleDelete = nullptr;
|
||||
constexpr decltype(&SiLoader::HandleEndAction) HandleEndAction = nullptr;
|
||||
#endif
|
||||
}; // namespace Extensions
|
||||
|
||||
@ -9,11 +9,17 @@
|
||||
|
||||
using namespace Extensions;
|
||||
|
||||
const char prependedMarker[] = ";;prepended;;";
|
||||
|
||||
std::map<std::string, std::string> SiLoader::options;
|
||||
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::removeWith;
|
||||
std::vector<std::pair<SiLoader::StreamObject, SiLoader::StreamObject>> SiLoader::replace;
|
||||
std::vector<std::pair<SiLoader::StreamObject, SiLoader::StreamObject>> SiLoader::prepend;
|
||||
std::vector<SiLoader::StreamObject> SiLoader::fullScreenMovie;
|
||||
std::vector<SiLoader::StreamObject> SiLoader::disable3d;
|
||||
bool SiLoader::enabled = false;
|
||||
|
||||
void SiLoader::Initialize()
|
||||
@ -21,11 +27,19 @@ void SiLoader::Initialize()
|
||||
char* files = SDL_strdup(options["si loader:files"].c_str());
|
||||
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);
|
||||
}
|
||||
|
||||
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(directives);
|
||||
}
|
||||
|
||||
bool SiLoader::Load()
|
||||
@ -34,6 +48,10 @@ bool SiLoader::Load()
|
||||
LoadFile(file.c_str());
|
||||
}
|
||||
|
||||
for (const auto& directive : directives) {
|
||||
LoadDirective(directive.c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -51,34 +69,62 @@ std::optional<MxCore*> SiLoader::HandleFind(StreamObject p_object, LegoWorld* wo
|
||||
std::optional<MxResult> SiLoader::HandleStart(MxDSAction& p_action)
|
||||
{
|
||||
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) {
|
||||
if (key.first == object) {
|
||||
MxDSAction action;
|
||||
action.SetAtomId(key.second.first);
|
||||
action.SetObjectId(key.second.second);
|
||||
action.SetUnknown24(p_action.GetUnknown24());
|
||||
action.SetNotificationObject(p_action.GetNotificationObject());
|
||||
action.SetOrigin(p_action.GetOrigin());
|
||||
Start(&action);
|
||||
start(key.second, p_action, action);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& key : replace) {
|
||||
if (key.first == object) {
|
||||
MxDSAction action;
|
||||
action.SetAtomId(key.second.first);
|
||||
action.SetObjectId(key.second.second);
|
||||
action.SetUnknown24(p_action.GetUnknown24());
|
||||
action.SetNotificationObject(p_action.GetNotificationObject());
|
||||
action.SetOrigin(p_action.GetOrigin());
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_action.GetExtraLength() == 0 || !SDL_strstr(p_action.GetExtraData(), prependedMarker)) {
|
||||
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());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (std::find(fullScreenMovie.begin(), fullScreenMovie.end(), object) != fullScreenMovie.end()) {
|
||||
VideoManager()->EnableFullScreenMovie(TRUE);
|
||||
}
|
||||
|
||||
if (std::find(disable3d.begin(), disable3d.end(), object) != disable3d.end()) {
|
||||
VideoManager()->FUN_1007c520();
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@ -102,29 +148,26 @@ std::optional<MxBool> SiLoader::HandleRemove(StreamObject p_object, LegoWorld* w
|
||||
std::optional<MxBool> SiLoader::HandleDelete(MxDSAction& p_action)
|
||||
{
|
||||
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) {
|
||||
if (key.first == object) {
|
||||
MxDSAction action;
|
||||
action.SetAtomId(key.second.first);
|
||||
action.SetObjectId(key.second.second);
|
||||
action.SetUnknown24(p_action.GetUnknown24());
|
||||
action.SetNotificationObject(p_action.GetNotificationObject());
|
||||
action.SetOrigin(p_action.GetOrigin());
|
||||
DeleteObject(action);
|
||||
deleteObject(key.second, p_action, action);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& key : replace) {
|
||||
if (key.first == object) {
|
||||
MxDSAction action;
|
||||
action.SetAtomId(key.second.first);
|
||||
action.SetObjectId(key.second.second);
|
||||
action.SetUnknown24(p_action.GetUnknown24());
|
||||
action.SetNotificationObject(p_action.GetNotificationObject());
|
||||
action.SetOrigin(p_action.GetOrigin());
|
||||
|
||||
DeleteObject(action);
|
||||
deleteObject(key.second, p_action, action);
|
||||
p_action.SetUnknown24(action.GetUnknown24());
|
||||
return TRUE;
|
||||
}
|
||||
@ -133,6 +176,39 @@ std::optional<MxBool> SiLoader::HandleDelete(MxDSAction& p_action)
|
||||
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) -> MxResult {
|
||||
if (!OpenStream(p_object.first.GetInternal())) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
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());
|
||||
p_out.AppendExtra(sizeof(prependedMarker), prependedMarker);
|
||||
return Start(&p_out);
|
||||
};
|
||||
|
||||
if (std::find(fullScreenMovie.begin(), fullScreenMovie.end(), object) != fullScreenMovie.end()) {
|
||||
VideoManager()->EnableFullScreenMovie(FALSE);
|
||||
}
|
||||
|
||||
if (!p_param.GetSender() || !p_param.GetSender()->IsA("MxCompositePresenter")) {
|
||||
for (const auto& key : prepend) {
|
||||
if (key.second == object) {
|
||||
MxDSAction action;
|
||||
start(key.first, *p_param.GetAction(), action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool SiLoader::LoadFile(const char* p_file)
|
||||
{
|
||||
si::Interleaf si;
|
||||
@ -150,16 +226,73 @@ bool SiLoader::LoadFile(const char* p_file)
|
||||
}
|
||||
}
|
||||
|
||||
if (!(controller = Streamer()->Open(p_file, MxStreamer::e_diskStream))) {
|
||||
SDL_Log("Could not load SI file %s", p_file);
|
||||
if (!(controller = OpenStream(p_file))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ParseDirectives(controller->GetAtom(), &si);
|
||||
ParseExtra(controller->GetAtom(), &si);
|
||||
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[^:;]%*[:;]%u%*[:;]%255[^:;]%*[:;]%u",
|
||||
originAtom,
|
||||
&originId,
|
||||
targetAtom,
|
||||
&targetId
|
||||
) == 4) {
|
||||
startWith.emplace_back(
|
||||
StreamObject{MxAtomId{originAtom, e_lowerCase2}, originId},
|
||||
StreamObject{MxAtomId{targetAtom, e_lowerCase2}, targetId}
|
||||
);
|
||||
}
|
||||
else if (SDL_sscanf(p_directive, "RemoveWith:%255[^:;]%*[:;]%u%*[:;]%255[^:;]%*[:;]%u", originAtom, &originId, targetAtom, &targetId) == 4) {
|
||||
removeWith.emplace_back(
|
||||
StreamObject{MxAtomId{originAtom, e_lowerCase2}, originId},
|
||||
StreamObject{MxAtomId{targetAtom, e_lowerCase2}, targetId}
|
||||
);
|
||||
}
|
||||
else if (SDL_sscanf(p_directive, "Replace:%255[^:;]%*[:;]%u%*[:;]%255[^:;]%*[:;]%u", originAtom, &originId, targetAtom, &targetId) == 4) {
|
||||
replace.emplace_back(
|
||||
StreamObject{MxAtomId{originAtom, e_lowerCase2}, originId},
|
||||
StreamObject{MxAtomId{targetAtom, e_lowerCase2}, targetId}
|
||||
);
|
||||
}
|
||||
else if (SDL_sscanf(p_directive, "Prepend:%255[^:;]%*[:;]%u%*[:;]%255[^:;]%*[:;]%u", originAtom, &originId, targetAtom, &targetId) == 4) {
|
||||
prepend.emplace_back(
|
||||
StreamObject{MxAtomId{targetAtom, e_lowerCase2}, targetId},
|
||||
StreamObject{MxAtomId{originAtom, e_lowerCase2}, originId}
|
||||
);
|
||||
}
|
||||
else if (SDL_sscanf(p_directive, "FullScreenMovie:%255[^:;]%*[:;]%u", originAtom, &originId) == 2) {
|
||||
fullScreenMovie.emplace_back(StreamObject{MxAtomId{originAtom, e_lowerCase2}, originId});
|
||||
}
|
||||
else if (SDL_sscanf(p_directive, "Disable3d:%255[^:;]%*[:;]%u", originAtom, &originId) == 2) {
|
||||
disable3d.emplace_back(StreamObject{MxAtomId{originAtom, e_lowerCase2}, originId});
|
||||
}
|
||||
|
||||
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()) {
|
||||
MxAtomId replacedAtom = p_parentReplacedAtom;
|
||||
@ -172,7 +305,7 @@ void SiLoader::ParseDirectives(const MxAtomId& p_atom, si::Core* p_core, MxAtomI
|
||||
uint32_t id;
|
||||
|
||||
if ((directive = SDL_strstr(extra.c_str(), "StartWith:"))) {
|
||||
if (SDL_sscanf(directive, "StartWith:%255[^;];%d", atom, &id) == 2) {
|
||||
if (SDL_sscanf(directive, "StartWith:%255[^:;]%*[:;]%u", atom, &id) == 2) {
|
||||
startWith.emplace_back(
|
||||
StreamObject{MxAtomId{atom, e_lowerCase2}, id},
|
||||
StreamObject{p_atom, object->id_}
|
||||
@ -181,7 +314,7 @@ void SiLoader::ParseDirectives(const MxAtomId& p_atom, si::Core* p_core, MxAtomI
|
||||
}
|
||||
|
||||
if ((directive = SDL_strstr(extra.c_str(), "RemoveWith:"))) {
|
||||
if (SDL_sscanf(directive, "RemoveWith:%255[^;];%d", atom, &id) == 2) {
|
||||
if (SDL_sscanf(directive, "RemoveWith:%255[^:;]%*[:;]%u", atom, &id) == 2) {
|
||||
removeWith.emplace_back(
|
||||
StreamObject{MxAtomId{atom, e_lowerCase2}, id},
|
||||
StreamObject{p_atom, object->id_}
|
||||
@ -197,7 +330,7 @@ void SiLoader::ParseDirectives(const MxAtomId& p_atom, si::Core* p_core, MxAtomI
|
||||
}
|
||||
else {
|
||||
if ((directive = SDL_strstr(extra.c_str(), "Replace:"))) {
|
||||
if (SDL_sscanf(directive, "Replace:%255[^;];%d", atom, &id) == 2) {
|
||||
if (SDL_sscanf(directive, "Replace:%255[^:;]%*[:;]%u", atom, &id) == 2) {
|
||||
replace.emplace_back(
|
||||
StreamObject{MxAtomId{atom, e_lowerCase2}, id},
|
||||
StreamObject{p_atom, object->id_}
|
||||
@ -206,9 +339,26 @@ 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[^:;]%*[:;]%u", atom, &id) == 2) {
|
||||
prepend.emplace_back(
|
||||
StreamObject{p_atom, object->id_},
|
||||
StreamObject{MxAtomId{atom, e_lowerCase2}, id}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ((directive = SDL_strstr(extra.c_str(), "FullScreenMovie"))) {
|
||||
fullScreenMovie.emplace_back(StreamObject{MxAtomId{atom, e_lowerCase2}, id});
|
||||
}
|
||||
|
||||
if ((directive = SDL_strstr(extra.c_str(), "Disable3d"))) {
|
||||
disable3d.emplace_back(StreamObject{MxAtomId{atom, e_lowerCase2}, id});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ParseDirectives(p_atom, child, replacedAtom);
|
||||
ParseExtra(p_atom, child, replacedAtom);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user