diff --git a/src/jasper/modules/world/include/jasper/world/worldstatic.hpp b/src/jasper/modules/world/include/jasper/world/worldstatic.hpp index b4a44a6..b78b88b 100644 --- a/src/jasper/modules/world/include/jasper/world/worldstatic.hpp +++ b/src/jasper/modules/world/include/jasper/world/worldstatic.hpp @@ -110,13 +110,17 @@ void loadTile(ObjectCache const&objCache, TileStatic &dst, TileDoc const&src) no ox::Result loadWorldStatic(ObjectCache const&objCache, WorldDoc const&doc) noexcept; [[nodiscard]] -auto &tile(ox::CommonRefWith auto &ws, size_t lyr, ox::Integer_c auto col, ox::Integer_c auto row) noexcept { +auto &tile( + ox::CommonRefWith auto&ws, + size_t lyr, + ox::Integer_c auto col, + ox::Integer_c auto row) noexcept { auto const idx = static_cast(row) * static_cast(ws.columns) + static_cast(col); return ws.map[lyr].tiles[idx]; } [[nodiscard]] -auto &cbb(ox::CommonRefWith auto &ws, size_t lyr) noexcept { +auto &cbb(ox::CommonRefWith auto&ws, size_t lyr) noexcept { return ws.map[lyr].cbb; } diff --git a/src/jasper/modules/world/src/studio/studiomodule.cpp b/src/jasper/modules/world/src/studio/studiomodule.cpp index f9f5cdd..9bfaee2 100644 --- a/src/jasper/modules/world/src/studio/studiomodule.cpp +++ b/src/jasper/modules/world/src/studio/studiomodule.cpp @@ -11,7 +11,7 @@ namespace jasper::world { -class StudioModule: public studio::Module { +static class: public studio::Module { public: ox::Vector editors(studio::StudioContext &ctx) const noexcept override { return { @@ -21,13 +21,14 @@ class StudioModule: public studio::Module { } ox::Vector> itemMakers(studio::StudioContext&) const noexcept override { ox::Vector> out; - out.emplace_back(ox::make>("World Object Set", "WorldObjectSets", FileExt_jwob, ox::ClawFormat::Organic)); - out.emplace_back(ox::make>("World", "Worlds", FileExt_jwld, ox::ClawFormat::Organic)); + out.emplace_back(ox::make>( + "World Object Set", "WorldObjectSets", FileExt_jwob, ox::ClawFormat::Organic)); + out.emplace_back(ox::make>( + "World", "Worlds", FileExt_jwld, ox::ClawFormat::Organic)); return out; } -}; +} mod; -static StudioModule const mod; studio::Module const*studioModule() noexcept { return &mod; } diff --git a/src/jasper/modules/world/src/studio/worldeditor/commands/addrmobjectset.cpp b/src/jasper/modules/world/src/studio/worldeditor/commands/addrmobjectset.cpp index c5ce28a..e024c09 100644 --- a/src/jasper/modules/world/src/studio/worldeditor/commands/addrmobjectset.cpp +++ b/src/jasper/modules/world/src/studio/worldeditor/commands/addrmobjectset.cpp @@ -7,14 +7,14 @@ namespace jasper::world { -AddObjectSet::AddObjectSet(WorldDoc &doc, ox::StringView objSetPath): +AddObjectSet::AddObjectSet(WorldDoc &doc, ox::UUID const&objSetUuid): m_doc(doc), - m_path(ox::String(objSetPath)) { + m_path(ox::sfmt("uuid://{}", objSetUuid.toString())) { for (auto const&o : m_doc.objSets) { - if (o.path > objSetPath) { + if (o.path > m_path) { break; - } else if (o.path == objSetPath) { - throw ox::Exception(OxError(1, "Path already exists in doc")); + } else if (o.path == m_path) { + throw OxException(1, "Path already exists in doc"); } ++m_insertIdx; } diff --git a/src/jasper/modules/world/src/studio/worldeditor/commands/addrmobjectset.hpp b/src/jasper/modules/world/src/studio/worldeditor/commands/addrmobjectset.hpp index d9846cd..288716f 100644 --- a/src/jasper/modules/world/src/studio/worldeditor/commands/addrmobjectset.hpp +++ b/src/jasper/modules/world/src/studio/worldeditor/commands/addrmobjectset.hpp @@ -18,7 +18,7 @@ class AddObjectSet: public studio::UndoCommand { size_t m_insertIdx{}; ox::String m_path; public: - AddObjectSet(WorldDoc &doc, ox::StringView objSetPath); + AddObjectSet(WorldDoc &doc, ox::UUID const&objSetUuid); void redo() noexcept override; void undo() noexcept override; [[nodiscard]] diff --git a/src/jasper/modules/world/src/studio/worldeditor/commands/modifytiles.cpp b/src/jasper/modules/world/src/studio/worldeditor/commands/modifytiles.cpp index 91ee67a..257623c 100644 --- a/src/jasper/modules/world/src/studio/worldeditor/commands/modifytiles.cpp +++ b/src/jasper/modules/world/src/studio/worldeditor/commands/modifytiles.cpp @@ -7,7 +7,8 @@ namespace jasper::world { -ModifyTilesCommand::ModifyTilesCommand(WorldDoc &doc, +ModifyTilesCommand::ModifyTilesCommand( + WorldDoc &doc, WorldStatic &worldStatic, ObjectCache &objCache, ox::Vector mods): @@ -15,6 +16,17 @@ ModifyTilesCommand::ModifyTilesCommand(WorldDoc &doc, m_worldStatic(worldStatic), m_objCache(objCache), m_mods(std::move(mods)) { + bool noChanges = true; + for (auto const&mod : m_mods) { + auto const&docTile = tile(m_doc, mod.layer, mod.tileAddr.x, mod.tileAddr.y); + if (docTile.obj.worldObjectId != mod.objId || docTile.obj.worldObjectSetId != mod.setId) { + noChanges = false; + break; + } + } + if (noChanges) { + throw studio::NoChangesException(); + } } void ModifyTilesCommand::redo() noexcept { diff --git a/src/jasper/modules/world/src/studio/worldeditor/worldeditor-imgui.cpp b/src/jasper/modules/world/src/studio/worldeditor/worldeditor-imgui.cpp index 43a5b34..c38457e 100644 --- a/src/jasper/modules/world/src/studio/worldeditor/worldeditor-imgui.cpp +++ b/src/jasper/modules/world/src/studio/worldeditor/worldeditor-imgui.cpp @@ -47,6 +47,14 @@ static WorldDoc makeValid(WorldDoc doc) noexcept { } [[nodiscard]] +static ox::Vec2 dropPos(ox::Vec2 dropPos) noexcept { + auto const winPos = ImGui::GetWindowPos(); + dropPos.x -= winPos.x; + dropPos.y -= winPos.y; + return dropPos; +} + + [[nodiscard]] constexpr ox::Point fbPtToTileAddr( ox::Vec2 const&fbPt, ox::Vec2 const&mapSz) noexcept { @@ -98,7 +106,7 @@ void WorldEditorImGui::onActivated() noexcept { } ox::Error WorldEditorImGui::saveItem() noexcept { - return m_sctx.project->writeObj(itemPath(), m_doc, ox::ClawFormat::Organic); + return m_sctx.project->writeObj(itemPath(), m_doc, ox::ClawFormat::Metal); } void WorldEditorImGui::drawObjSetSelector() noexcept { @@ -111,14 +119,23 @@ void WorldEditorImGui::drawObjSetSelector() noexcept { rmObjSet(); } ig::ListBox("Object Sets", [this](size_t i) -> ox::CStringView { - return m_doc.objSets[i].path; + auto const&uuidUrl = m_doc.objSets[i].path; + auto [setName, err] = uuidUrlToPath(keelCtx(m_sctx.tctx), uuidUrl); + if (err) { + setName = uuidUrl; + } + return setName; }, m_doc.objSets.size(), m_palMgr.selectedIdx); } void WorldEditorImGui::drawObjSelector() noexcept { ig::IDStackItem const idStackItem("ObjSelector"); - for (auto const&[setName, setId, set] : m_objSets) { + for (auto const&[uuidUrl, setId, set] : m_objSets) { constexpr auto flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; + auto [setName, err] = uuidUrlToPath(keelCtx(m_sctx.tctx), uuidUrl); + if (err) { + setName = uuidUrl; + } if (ImGui::TreeNodeEx(setName.c_str(), flags)) { for (auto const&obj : set->objects) { if (ImGui::TreeNodeEx(obj.name.c_str(), ImGuiTreeNodeFlags_Leaf)) { @@ -155,14 +172,6 @@ void WorldEditorImGui::drawResources() noexcept { drawObjSelector(); } -[[nodiscard]] -static ox::Vec2 dropPos(ox::Vec2 dropPos) noexcept { - auto const winPos = ImGui::GetWindowPos(); - dropPos.x -= winPos.x; - dropPos.y -= winPos.y; - return dropPos; -} - void WorldEditorImGui::drawWorldView() noexcept { ig::IDStackItem const idStackItem("WorldView"); auto const paneSize = ImGui::GetContentRegionAvail(); @@ -221,7 +230,8 @@ void WorldEditorImGui::drawWorldView() noexcept { } ox::Error WorldEditorImGui::addObjSet(ox::StringView path) noexcept { - pushCommand(m_doc, path); + oxRequire(uuid, keel::pathToUuid(keelCtx(m_sctx.tctx), path)); + pushCommand(m_doc, uuid); return {}; } @@ -247,7 +257,7 @@ ox::Error WorldEditorImGui::loadObjectSets() noexcept { return {}; } -ox::Error WorldEditorImGui::undoStackChanged(const studio::UndoCommand *) { +ox::Error WorldEditorImGui::undoStackChanged(studio::UndoCommand const*) { oxReturnError(m_view.setupWorld()); return {}; } diff --git a/src/jasper/modules/world/src/studio/worldeditor/worldeditor-imgui.hpp b/src/jasper/modules/world/src/studio/worldeditor/worldeditor-imgui.hpp index c060fa4..501d955 100644 --- a/src/jasper/modules/world/src/studio/worldeditor/worldeditor-imgui.hpp +++ b/src/jasper/modules/world/src/studio/worldeditor/worldeditor-imgui.hpp @@ -19,6 +19,10 @@ namespace jasper::world { class WorldEditorImGui: public studio::Editor { private: + struct Selection { + ox::Point begin, end; + }; + ox::Optional m_selection; uint8_t m_activeLayer{}; studio::StudioContext &m_sctx; studio::ig::FilePicker m_objSetPicker{ diff --git a/src/jasper/modules/world/src/world.cpp b/src/jasper/modules/world/src/world.cpp index 8500aa5..07d7499 100644 --- a/src/jasper/modules/world/src/world.cpp +++ b/src/jasper/modules/world/src/world.cpp @@ -8,8 +8,6 @@ namespace jasper::world { -namespace ncore = nostalgia::core; - World::World(WorldStatic const&worldStatic) noexcept: m_worldStatic(worldStatic) { } @@ -37,9 +35,11 @@ void World::setupLayer( uint_t cbb) const noexcept { ncore::setBgStatus(ctx, lyr, true); ncore::setBgCbb(ctx, lyr, cbb); - for (auto y = 0; y < m_worldStatic.rows; ++y) { - for (auto x = 0; x < m_worldStatic.columns; ++x) { - auto &t = tile(m_worldStatic, lyr, static_cast(x), static_cast(y)); + auto const rows = ox::min(m_worldStatic.rows, ncore::tileRows(ctx) / 2); + auto const columns = ox::min(m_worldStatic.columns, ncore::tileColumns(ctx) / 2); + for (auto y = 0; y < rows; ++y) { + for (auto x = 0; x < columns; ++x) { + auto &t = tile(m_worldStatic, lyr, x, y); auto const tx = x * 2; auto const ty = y * 2; ncore::setBgTile(ctx, lyr, tx + 0, ty + 0, {