[jasper/world]/studio] Make World refer to obj sets with UUIDs
Some checks failed
Build / build (push) Failing after 30s

This commit is contained in:
Gary Talent 2024-05-22 00:37:03 -05:00
parent 8e9274a84b
commit 299a91fd66
8 changed files with 63 additions and 32 deletions

View File

@ -110,13 +110,17 @@ void loadTile(ObjectCache const&objCache, TileStatic &dst, TileDoc const&src) no
ox::Result<WorldStatic> loadWorldStatic(ObjectCache const&objCache, WorldDoc const&doc) noexcept; ox::Result<WorldStatic> loadWorldStatic(ObjectCache const&objCache, WorldDoc const&doc) noexcept;
[[nodiscard]] [[nodiscard]]
auto &tile(ox::CommonRefWith<WorldStatic> auto &ws, size_t lyr, ox::Integer_c auto col, ox::Integer_c auto row) noexcept { auto &tile(
ox::CommonRefWith<WorldStatic> auto&ws,
size_t lyr,
ox::Integer_c auto col,
ox::Integer_c auto row) noexcept {
auto const idx = static_cast<size_t>(row) * static_cast<size_t>(ws.columns) + static_cast<size_t>(col); auto const idx = static_cast<size_t>(row) * static_cast<size_t>(ws.columns) + static_cast<size_t>(col);
return ws.map[lyr].tiles[idx]; return ws.map[lyr].tiles[idx];
} }
[[nodiscard]] [[nodiscard]]
auto &cbb(ox::CommonRefWith<WorldStatic> auto &ws, size_t lyr) noexcept { auto &cbb(ox::CommonRefWith<WorldStatic> auto&ws, size_t lyr) noexcept {
return ws.map[lyr].cbb; return ws.map[lyr].cbb;
} }

View File

@ -11,7 +11,7 @@
namespace jasper::world { namespace jasper::world {
class StudioModule: public studio::Module { static class: public studio::Module {
public: public:
ox::Vector<studio::EditorMaker> editors(studio::StudioContext &ctx) const noexcept override { ox::Vector<studio::EditorMaker> editors(studio::StudioContext &ctx) const noexcept override {
return { return {
@ -21,13 +21,14 @@ class StudioModule: public studio::Module {
} }
ox::Vector<ox::UPtr<studio::ItemMaker>> itemMakers(studio::StudioContext&) const noexcept override { ox::Vector<ox::UPtr<studio::ItemMaker>> itemMakers(studio::StudioContext&) const noexcept override {
ox::Vector<ox::UPtr<studio::ItemMaker>> out; ox::Vector<ox::UPtr<studio::ItemMaker>> out;
out.emplace_back(ox::make<studio::ItemMakerT<WorldObjectSet>>("World Object Set", "WorldObjectSets", FileExt_jwob, ox::ClawFormat::Organic)); out.emplace_back(ox::make<studio::ItemMakerT<WorldObjectSet>>(
out.emplace_back(ox::make<studio::ItemMakerT<WorldDoc>>("World", "Worlds", FileExt_jwld, ox::ClawFormat::Organic)); "World Object Set", "WorldObjectSets", FileExt_jwob, ox::ClawFormat::Organic));
out.emplace_back(ox::make<studio::ItemMakerT<WorldDoc>>(
"World", "Worlds", FileExt_jwld, ox::ClawFormat::Organic));
return out; return out;
} }
}; } mod;
static StudioModule const mod;
studio::Module const*studioModule() noexcept { studio::Module const*studioModule() noexcept {
return &mod; return &mod;
} }

View File

@ -7,14 +7,14 @@
namespace jasper::world { namespace jasper::world {
AddObjectSet::AddObjectSet(WorldDoc &doc, ox::StringView objSetPath): AddObjectSet::AddObjectSet(WorldDoc &doc, ox::UUID const&objSetUuid):
m_doc(doc), m_doc(doc),
m_path(ox::String(objSetPath)) { m_path(ox::sfmt("uuid://{}", objSetUuid.toString())) {
for (auto const&o : m_doc.objSets) { for (auto const&o : m_doc.objSets) {
if (o.path > objSetPath) { if (o.path > m_path) {
break; break;
} else if (o.path == objSetPath) { } else if (o.path == m_path) {
throw ox::Exception(OxError(1, "Path already exists in doc")); throw OxException(1, "Path already exists in doc");
} }
++m_insertIdx; ++m_insertIdx;
} }

View File

@ -18,7 +18,7 @@ class AddObjectSet: public studio::UndoCommand {
size_t m_insertIdx{}; size_t m_insertIdx{};
ox::String m_path; ox::String m_path;
public: public:
AddObjectSet(WorldDoc &doc, ox::StringView objSetPath); AddObjectSet(WorldDoc &doc, ox::UUID const&objSetUuid);
void redo() noexcept override; void redo() noexcept override;
void undo() noexcept override; void undo() noexcept override;
[[nodiscard]] [[nodiscard]]

View File

@ -7,7 +7,8 @@
namespace jasper::world { namespace jasper::world {
ModifyTilesCommand::ModifyTilesCommand(WorldDoc &doc, ModifyTilesCommand::ModifyTilesCommand(
WorldDoc &doc,
WorldStatic &worldStatic, WorldStatic &worldStatic,
ObjectCache &objCache, ObjectCache &objCache,
ox::Vector<Mod> mods): ox::Vector<Mod> mods):
@ -15,6 +16,17 @@ ModifyTilesCommand::ModifyTilesCommand(WorldDoc &doc,
m_worldStatic(worldStatic), m_worldStatic(worldStatic),
m_objCache(objCache), m_objCache(objCache),
m_mods(std::move(mods)) { 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 { void ModifyTilesCommand::redo() noexcept {

View File

@ -47,6 +47,14 @@ static WorldDoc makeValid(WorldDoc doc) noexcept {
} }
[[nodiscard]] [[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( constexpr ox::Point fbPtToTileAddr(
ox::Vec2 const&fbPt, ox::Vec2 const&fbPt,
ox::Vec2 const&mapSz) noexcept { ox::Vec2 const&mapSz) noexcept {
@ -98,7 +106,7 @@ void WorldEditorImGui::onActivated() noexcept {
} }
ox::Error WorldEditorImGui::saveItem() 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 { void WorldEditorImGui::drawObjSetSelector() noexcept {
@ -111,14 +119,23 @@ void WorldEditorImGui::drawObjSetSelector() noexcept {
rmObjSet(); rmObjSet();
} }
ig::ListBox("Object Sets", [this](size_t i) -> ox::CStringView { 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); }, m_doc.objSets.size(), m_palMgr.selectedIdx);
} }
void WorldEditorImGui::drawObjSelector() noexcept { void WorldEditorImGui::drawObjSelector() noexcept {
ig::IDStackItem const idStackItem("ObjSelector"); 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; 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)) { if (ImGui::TreeNodeEx(setName.c_str(), flags)) {
for (auto const&obj : set->objects) { for (auto const&obj : set->objects) {
if (ImGui::TreeNodeEx(obj.name.c_str(), ImGuiTreeNodeFlags_Leaf)) { if (ImGui::TreeNodeEx(obj.name.c_str(), ImGuiTreeNodeFlags_Leaf)) {
@ -155,14 +172,6 @@ void WorldEditorImGui::drawResources() noexcept {
drawObjSelector(); 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 { void WorldEditorImGui::drawWorldView() noexcept {
ig::IDStackItem const idStackItem("WorldView"); ig::IDStackItem const idStackItem("WorldView");
auto const paneSize = ImGui::GetContentRegionAvail(); auto const paneSize = ImGui::GetContentRegionAvail();
@ -221,7 +230,8 @@ void WorldEditorImGui::drawWorldView() noexcept {
} }
ox::Error WorldEditorImGui::addObjSet(ox::StringView path) noexcept { ox::Error WorldEditorImGui::addObjSet(ox::StringView path) noexcept {
pushCommand<AddObjectSet>(m_doc, path); oxRequire(uuid, keel::pathToUuid(keelCtx(m_sctx.tctx), path));
pushCommand<AddObjectSet>(m_doc, uuid);
return {}; return {};
} }
@ -247,7 +257,7 @@ ox::Error WorldEditorImGui::loadObjectSets() noexcept {
return {}; return {};
} }
ox::Error WorldEditorImGui::undoStackChanged(const studio::UndoCommand *) { ox::Error WorldEditorImGui::undoStackChanged(studio::UndoCommand const*) {
oxReturnError(m_view.setupWorld()); oxReturnError(m_view.setupWorld());
return {}; return {};
} }

View File

@ -19,6 +19,10 @@ namespace jasper::world {
class WorldEditorImGui: public studio::Editor { class WorldEditorImGui: public studio::Editor {
private: private:
struct Selection {
ox::Point begin, end;
};
ox::Optional<Selection> m_selection;
uint8_t m_activeLayer{}; uint8_t m_activeLayer{};
studio::StudioContext &m_sctx; studio::StudioContext &m_sctx;
studio::ig::FilePicker m_objSetPicker{ studio::ig::FilePicker m_objSetPicker{

View File

@ -8,8 +8,6 @@
namespace jasper::world { namespace jasper::world {
namespace ncore = nostalgia::core;
World::World(WorldStatic const&worldStatic) noexcept: World::World(WorldStatic const&worldStatic) noexcept:
m_worldStatic(worldStatic) { m_worldStatic(worldStatic) {
} }
@ -37,9 +35,11 @@ void World::setupLayer(
uint_t cbb) const noexcept { uint_t cbb) const noexcept {
ncore::setBgStatus(ctx, lyr, true); ncore::setBgStatus(ctx, lyr, true);
ncore::setBgCbb(ctx, lyr, cbb); ncore::setBgCbb(ctx, lyr, cbb);
for (auto y = 0; y < m_worldStatic.rows; ++y) { auto const rows = ox::min<int>(m_worldStatic.rows, ncore::tileRows(ctx) / 2);
for (auto x = 0; x < m_worldStatic.columns; ++x) { auto const columns = ox::min<int>(m_worldStatic.columns, ncore::tileColumns(ctx) / 2);
auto &t = tile(m_worldStatic, lyr, static_cast<size_t>(x), static_cast<size_t>(y)); 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 tx = x * 2;
auto const ty = y * 2; auto const ty = y * 2;
ncore::setBgTile(ctx, lyr, tx + 0, ty + 0, { ncore::setBgTile(ctx, lyr, tx + 0, ty + 0, {