SiLoader draft

This commit is contained in:
Christian Semmler 2025-08-10 11:45:52 -07:00
parent f2b6188d89
commit 602c3eafc8
No known key found for this signature in database
GPG Key ID: 086DAA1360BEEE5C
12 changed files with 272 additions and 1 deletions

3
.gitmodules vendored
View File

@ -7,3 +7,6 @@
[submodule "imgui"]
path = 3rdparty/imgui
url = https://github.com/ocornut/imgui
[submodule "3rdparty/libweaver"]
path = 3rdparty/libweaver
url = https://github.com/isledecomp/SIEdit

View File

@ -72,3 +72,23 @@ target_include_directories(imgui PUBLIC ${imgui_SOURCE_DIR})
target_link_libraries(imgui PUBLIC SDL3::Headers)
target_link_libraries(imgui PRIVATE SDL3::SDL3)
set_property(TARGET imgui PROPERTY CXX_CLANG_TIDY "")
if(DOWNLOAD_DEPENDENCIES)
include(FetchContent)
FetchContent_Populate(
libweaver
URL https://github.com/isledecomp/SIEdit/archive/6da93b2072c41c41d526b8b9df7d4292be1f0f55.tar.gz
URL_MD5 ae59007fcb9efadc06c67621e1e107cb
)
else()
set(libsmacker_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libweaver")
endif()
add_library(libweaver STATIC
${libweaver_SOURCE_DIR}/lib/core.cpp
${libweaver_SOURCE_DIR}/lib/file.cpp
${libweaver_SOURCE_DIR}/lib/interleaf.cpp
${libweaver_SOURCE_DIR}/lib/object.cpp
${libweaver_SOURCE_DIR}/lib/sitypes.cpp
)
target_include_directories(libweaver PUBLIC ${libweaver_SOURCE_DIR}/lib)

1
3rdparty/libweaver vendored Submodule

@ -0,0 +1 @@
Subproject commit 6da93b2072c41c41d526b8b9df7d4292be1f0f55

View File

@ -42,6 +42,7 @@ find_program(SDL_SHADERCROSS_BIN NAMES "shadercross")
find_package(Python3 3.12 COMPONENTS Interpreter)
option(ISLE_BUILD_APP "Build isle application" ON)
option(ISLE_BUILD_ASSETS "Build assets from the /assets directory" OFF)
option(ISLE_ASAN "Enable Address Sanitizer" OFF)
option(ISLE_UBSAN "Enable Undefined Behavior Sanitizer" OFF)
option(ISLE_WERROR "Treat warnings as errors" OFF)
@ -490,9 +491,11 @@ if (NOT ISLE_MINIWIN)
endif()
if (ISLE_EXTENSIONS)
target_link_libraries(lego1 PRIVATE libweaver)
target_compile_definitions(lego1 PUBLIC EXTENSIONS)
target_sources(lego1 PRIVATE
extensions/src/extensions.cpp
extensions/src/siloader.cpp
extensions/src/textureloader.cpp
)
endif()
@ -644,6 +647,36 @@ if (ISLE_BUILD_CONFIG)
endif()
endif()
if(ISLE_BUILD_ASSETS)
message(STATUS "Asset building is enabled")
set(GENERATED_ASSETS_DIR "${CMAKE_BINARY_DIR}/assets")
add_executable(asset_generator EXCLUDE_FROM_ALL
assets/main.cpp
)
target_link_libraries(asset_generator PRIVATE libweaver)
target_include_directories(asset_generator PRIVATE "${CMAKE_SOURCE_DIR}/util" "${CMAKE_SOURCE_DIR}/LEGO1/omni/include" "${CMAKE_SOURCE_DIR}/LEGO1" "${CMAKE_SOURCE_DIR}/LEGO1/lego/sources")
add_custom_command(
OUTPUT ${GENERATED_ASSETS_DIR}/.stamp
COMMAND ${CMAKE_COMMAND} -E make_directory ${GENERATED_ASSETS_DIR}
COMMAND $<TARGET_FILE:asset_generator> ${GENERATED_ASSETS_DIR}
COMMAND ${CMAKE_COMMAND} -E touch ${GENERATED_ASSETS_DIR}/.stamp
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/assets
DEPENDS asset_generator
COMMENT "Generating assets into ${GENERATED_ASSETS_DIR}/"
VERBATIM
)
add_custom_target(build_assets ALL
DEPENDS ${GENERATED_ASSETS_DIR}/.stamp
)
install(DIRECTORY ${GENERATED_ASSETS_DIR}/
DESTINATION assets
)
endif()
if (ISLE_MINIWIN)
set_property(TARGET ${isle_targets} APPEND PROPERTY LINK_LIBRARIES "miniwin")
endif()

View File

@ -2,6 +2,7 @@
#include "3dmanager/lego3dmanager.h"
#include "anim/legoanim.h"
#include "extensions/siloader.h"
#include "isle.h"
#include "isle_actions.h"
#include "islepathactor.h"
@ -37,6 +38,8 @@
#include <string.h>
#include <vec.h>
using namespace Extensions;
// FUNCTION: LEGO1 0x1003dd70
// FUNCTION: BETA10 0x100d3410
LegoROI* PickROI(MxLong p_x, MxLong p_y)
@ -515,6 +518,8 @@ MxBool RemoveFromCurrentWorld(const MxAtomId& p_atomId, MxS32 p_id)
}
((MxPresenter*) object)->EndAction();
Extension<SiLoader>::Call(RemoveWith, SiLoader::StreamObject{p_atomId, p_id}, world);
}
return TRUE;
@ -544,6 +549,8 @@ MxBool RemoveFromWorld(MxAtomId& p_entityAtom, MxS32 p_entityId, MxAtomId& p_wor
}
((MxPresenter*) object)->EndAction();
Extension<SiLoader>::Call(RemoveWith, SiLoader::StreamObject{p_entityAtom, p_entityId}, world);
}
return TRUE;

View File

@ -1,6 +1,7 @@
#include "legomain.h"
#include "3dmanager/lego3dmanager.h"
#include "extensions/siloader.h"
#include "islepathactor.h"
#include "legoanimationmanager.h"
#include "legobuildingmanager.h"
@ -40,6 +41,8 @@ DECOMP_SIZE_ASSERT(LegoOmni::WorldContainer, 0x1c)
DECOMP_SIZE_ASSERT(LegoWorldList, 0x18)
DECOMP_SIZE_ASSERT(LegoWorldListCursor, 0x10)
using namespace Extensions;
// GLOBAL: LEGO1 0x100f6718
// GLOBAL: BETA10 0x101ee748
// STRING: LEGO1 0x100f6710
@ -670,6 +673,14 @@ MxResult LegoOmni::Start(MxDSAction* p_dsAction)
this->m_action.SetObjectId(p_dsAction->GetObjectId());
this->m_action.SetUnknown24(p_dsAction->GetUnknown24());
#endif
if (result == SUCCESS) {
Extension<SiLoader>::Call(
StartWith,
SiLoader::StreamObject{p_dsAction->GetAtomId(), p_dsAction->GetObjectId()}
);
}
return result;
}

53
assets/main.cpp Normal file
View File

@ -0,0 +1,53 @@
#include "mxdsaction.h"
#include <file.h>
#include <interleaf.h>
#include <object.h>
si::Interleaf::Version version = si::Interleaf::Version2_2;
uint32_t bufferSize = 65535;
uint32_t bufferCount = 8;
std::string out;
si::MemoryBuffer mxHd;
void CreateWidescreen()
{
si::Interleaf si;
mxHd.seek(0, si::MemoryBuffer::SeekStart);
si.Read(&mxHd);
si::Object GaraDoor_Wide;
const char extra[] =
"World:current, StartWith:\\Lego\\Scripts\\Isle\\Isle;1160, RemoveWith:\\Lego\\Scripts\\Isle\\Isle;1161";
GaraDoor_Wide.type_ = si::MxOb::Bitmap;
GaraDoor_Wide.flags_ = MxDSAction::c_enabled | MxDSAction::c_bit4;
GaraDoor_Wide.duration_ = -1;
GaraDoor_Wide.loops_ = 1;
GaraDoor_Wide.extra_ = si::bytearray(extra, sizeof(extra));
GaraDoor_Wide.presenter_ = "MxStillPresenter";
GaraDoor_Wide.name_ = "GaraDoor_Wide";
GaraDoor_Wide.filetype_ = si::MxOb::STL;
GaraDoor_Wide.location_.x = -240.0;
GaraDoor_Wide.location_.z = -1.0;
GaraDoor_Wide.up_.y = 1.0;
GaraDoor_Wide.ReplaceWithFile("widescreen/garadoor.bmp");
si.AppendChild(&GaraDoor_Wide);
si.Write((out + "/widescreen.si").c_str());
}
int main(int argc, char* argv[])
{
out = argv[1];
mxHd.WriteU32(si::RIFF::MxHd);
mxHd.WriteU32(3 * sizeof(uint32_t));
mxHd.WriteU32(version);
mxHd.WriteU32(bufferSize);
mxHd.WriteU32(bufferCount);
CreateWidescreen();
return 0;
}

BIN
assets/widescreen/garadoor.bmp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 526 KiB

View File

@ -9,7 +9,7 @@
namespace Extensions
{
constexpr const char* availableExtensions[] = {"extensions:texture loader"};
constexpr const char* availableExtensions[] = {"extensions:texture loader", "extensions:si loader"};
LEGO1_EXPORT void Enable(const char* p_key, std::map<std::string, std::string> p_options);

View File

@ -0,0 +1,38 @@
#pragma once
#include "extensions/extensions.h"
#include "legoworld.h"
#include "mxatom.h"
#include <map>
#include <vector>
namespace Extensions
{
class SiLoader {
public:
typedef std::pair<MxAtomId, MxU32> StreamObject;
static void Initialize();
static bool StartWith(StreamObject p_object);
static bool RemoveWith(StreamObject p_object, LegoWorld* world);
static std::map<std::string, std::string> options;
static bool enabled;
private:
static std::vector<std::string> files;
static std::vector<std::pair<StreamObject, StreamObject>> startWith;
static std::vector<std::pair<StreamObject, StreamObject>> removeWith;
static bool LoadFile(const char* p_file);
};
#ifdef EXTENSIONS
constexpr auto StartWith = &SiLoader::StartWith;
constexpr auto RemoveWith = &SiLoader::RemoveWith;
#else
constexpr decltype(&SiLoader::StartWith) StartWith = nullptr;
constexpr decltype(&SiLoader::RemoveWith) RemoveWith = nullptr;
#endif
}; // namespace Extensions

View File

@ -1,5 +1,6 @@
#include "extensions/extensions.h"
#include "extensions/siloader.h"
#include "extensions/textureloader.h"
#include <SDL3/SDL_log.h>
@ -13,6 +14,11 @@ void Extensions::Enable(const char* p_key, std::map<std::string, std::string> p_
TextureLoader::enabled = true;
TextureLoader::Initialize();
}
else if (!SDL_strcasecmp(p_key, "extensions:si loader")) {
SiLoader::options = std::move(p_options);
SiLoader::enabled = true;
SiLoader::Initialize();
}
SDL_Log("Enabled extension: %s", p_key);
break;

View File

@ -0,0 +1,99 @@
#include "extensions/siloader.h"
#include "mxdsaction.h"
#include "mxmisc.h"
#include "mxstreamer.h"
#include <SDL3/SDL.h>
#include <interleaf.h>
using namespace Extensions;
std::map<std::string, std::string> SiLoader::options;
std::vector<std::pair<SiLoader::StreamObject, SiLoader::StreamObject>> SiLoader::startWith;
std::vector<std::pair<SiLoader::StreamObject, SiLoader::StreamObject>> SiLoader::removeWith;
bool SiLoader::enabled = false;
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)) {
LoadFile(file);
}
SDL_free(files);
}
bool SiLoader::StartWith(StreamObject p_object)
{
for (const auto& key : startWith) {
if (key.first == p_object) {
MxDSAction action;
action.SetAtomId(key.second.first);
action.SetObjectId(key.second.second);
Start(&action);
}
}
return true;
}
bool SiLoader::RemoveWith(StreamObject p_object, LegoWorld* world)
{
for (auto& key : startWith) {
if (key.first == p_object) {
RemoveFromWorld(key.second.first, key.second.second, world->GetAtomId(), world->GetEntityId());
}
}
return true;
}
bool SiLoader::LoadFile(const char* p_file)
{
si::Interleaf si;
MxStreamController* controller;
if (si.Read(p_file) != si::Interleaf::ERROR_SUCCESS) {
SDL_Log("Could not parse SI file %s", p_file);
return false;
}
if ((controller = Streamer()->Open(p_file, MxStreamer::e_diskStream)) != SUCCESS) {
SDL_Log("Could not load SI file %s", p_file);
return false;
}
for (si::Core* child : si.GetChildren()) {
if (si::Object* object = dynamic_cast<si::Object*>(child)) {
if (object->type() != si::MxOb::Null) {
std::string extra(object->extra_.data(), object->extra_.size());
const char* directive;
char atom[256];
uint32_t id;
if ((directive = SDL_strstr(extra.c_str(), "StartWith:"))) {
if (SDL_sscanf(extra.c_str(), "StartWith:%255[^;];%d", atom, &id) == 2) {
startWith.emplace_back(
StreamObject{MxAtomId{atom, e_lowerCase2}, id},
StreamObject{controller->GetAtom(), object->id_}
);
}
}
if ((directive = SDL_strstr(extra.c_str(), "RemoveWith:"))) {
if (SDL_sscanf(extra.c_str(), "RemoveWith:%255[^;];%d", atom, &id) == 2) {
removeWith.emplace_back(
StreamObject{MxAtomId{atom, e_lowerCase2}, id},
StreamObject{controller->GetAtom(), object->id_}
);
}
}
}
}
}
return true;
}