diff --git a/src/dependency/minidef/src/CppGen.cpp b/src/dependency/minidef/src/CppGen.cpp index c2cde21..ad0a2bf 100644 --- a/src/dependency/minidef/src/CppGen.cpp +++ b/src/dependency/minidef/src/CppGen.cpp @@ -102,7 +102,7 @@ namespace Generated )END"; constexpr char LoadFuncBodyType3[] = R"END( isOk = Load(%sobj[i].%s, %u, serializer) && isOk; )END"; - constexpr char LoadFuncBodyEnum1[] = R"END( auto val = (%s)obj[i]; + constexpr char LoadFuncBodyEnum2[] = R"END( %s& val = (%s&)obj[i]; isOk = Load(&val, 1, serializer) && isOk; )END"; constexpr char LoadFuncBodyEnd[] = R"END( } @@ -262,7 +262,7 @@ void CppFileWriter::WriteSaveLoadMethods(const Def::DefinitionFile& definitions) WriteCpp(WriteTemplates::SaveFuncBodyEnd); WriteCpp(WriteTemplates::LoadFuncBodyStart1, nameBuf); - WriteCpp(WriteTemplates::LoadFuncBodyEnum1, fieldBuf); + WriteCpp(WriteTemplates::LoadFuncBodyEnum2, fieldBuf, fieldBuf); WriteCpp(WriteTemplates::LoadFuncBodyEnd); } for (int32_t typeIdx = 0; typeIdx < definitions.TypeCount; ++typeIdx) diff --git a/src/game/Instance.h b/src/game/Instance.h index c5fed09..9048ee8 100644 --- a/src/game/Instance.h +++ b/src/game/Instance.h @@ -43,6 +43,10 @@ namespace Game uint16_t SelectedDebugLevel = UINT16_MAX; uint64_t ImguiIniSize = 0; char ImguiIni[4096]{0}; + static constexpr uint32_t MaxAssets = 128; + uint32_t AssetCount = 0; + uint32_t AssetHandles[MaxAssets]{0}; + char AssetHandlePaths[MaxAssets][128]; }; struct GameInstance diff --git a/src/game/Level.cpp b/src/game/Level.cpp index 27898f0..962565f 100644 --- a/src/game/Level.cpp +++ b/src/game/Level.cpp @@ -74,7 +74,7 @@ namespace Game needReset |= PuzzleTiles.Setup(storagePtr, needReset); needReset |= UIQuads.Setup(storagePtr, needReset); - Generated::Setup(PuzzleData); + Generated::Setup(); bx::Error err; bx::DirectoryReader dirIter; diff --git a/src/game/Mesh.cpp b/src/game/Mesh.cpp index 551be21..d93998b 100644 --- a/src/game/Mesh.cpp +++ b/src/game/Mesh.cpp @@ -1,3 +1,4 @@ +#include "Global.h" #include "Log.h" #include "Mesh.h" #include "bx/bx.h" @@ -8,6 +9,8 @@ #include "bx/string.h" #include "rendering/Rendering.h" +#include "Instance.h" + #define TINYGLTF_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_WRITE_IMPLEMENTATION @@ -139,6 +142,15 @@ namespace Game if (LoadMesh(mod, fullPath.getCPtr(), modelFileIsBinary[i])) { mod.AssetHandle = CrcPath(fullPath.getCPtr()); + auto& inst = GetInstance(); + if (inst.DebugData.AssetCount < inst.DebugData.MaxAssets) + { + inst.DebugData.AssetHandles[inst.DebugData.AssetCount] = mod.AssetHandle; + bx::strCopy(inst.DebugData.AssetHandlePaths[inst.DebugData.AssetCount], + sizeof(inst.DebugData.AssetHandlePaths[inst.DebugData.AssetCount]), + fullPath.getCPtr()); + ++inst.DebugData.AssetCount; + } ++writeI; } else diff --git a/src/game/Puzzle.cpp b/src/game/Puzzle.cpp index 8e7c838..0426eb3 100644 --- a/src/game/Puzzle.cpp +++ b/src/game/Puzzle.cpp @@ -1,10 +1,9 @@ #include "Log.h" #include "Puzzle.h" #include "bx/string.h" -#include "imgui.h" -#include "rendering/Rendering.h" #include "bx/bx.h" +#include "imgui.h" #include namespace @@ -16,25 +15,43 @@ namespace {1, 0}, }; - Generated::StaticPuzzleData* StaticDataInstance = nullptr; + Generated::StaticPuzzleData StaticData; } // namespace namespace Generated { - void Setup(StaticPuzzleData& data) + void Setup() { - StaticDataInstance = &data; LOG("Setting up static puzzle data"); - for (int32_t i = 0; i < BX_COUNTOF(data.Cards); ++i) - { - data.Cards[i].ModelHandle = Game::GameRendering::Get().GetModelHandleFromPath("models/w straight.glb"); - } + LoadStaticPuzzleData(); } StaticPuzzleData& GetStaticPuzzleData() { - assert(StaticDataInstance != nullptr); - return *StaticDataInstance; + return StaticData; + } + + void LoadStaticPuzzleData() + { + Deserializer ser; + ser.Init("game/data/static/puzzle.dat"); + if (ser.ReadT("SPUZ", StaticData)) + { + LOG("Successfully loaded static puzzle data!"); + } + ser.Finish(); + } + + void SaveStaticPuzzleData() + { + auto& data = GetStaticPuzzleData(); + Serializer ser; + ser.Init("game/data/static/puzzle.dat"); + if (ser.WriteT("SPUZ", GetStaticPuzzleData())) + { + LOG("Successfully saved static puzzle data!"); + } + ser.Finish(); } const StaticPuzzleCard& GetCard(const StaticPuzzleData& data, StaticPuzzleCardHandle H) { @@ -167,6 +184,18 @@ namespace Generated namespace Generated { + constexpr float UIPuzBoxSize = 26; + + const char* GetShortNodeName(const PuzzleNode& node) + { + PuzzleElementType::Enum elemMax = PuzzleElementType::None; + for (int32_t i = 0; i < BX_COUNTOF(node.PlacedTypes); ++i) + { + if (node.PlacedTypes[i] > elemMax) elemMax = node.PlacedTypes[i]; + } + return PuzzleElementType::ShortName[elemMax]; + } + bool RenderDebugUI(PuzzleData& obj) { bool dataChanged = false; @@ -197,6 +226,47 @@ namespace Generated dataChanged = true; } ImGui::PopID(); + + ImVec2 puzCursorStart = ImGui::GetCursorScreenPos(); + auto& drawList = *ImGui::GetWindowDrawList(); + + for (int32_t y = 0; y < obj.HeightTiles; ++y) + { + for (int32_t x = 0; x < obj.WidthTiles; ++x) + { + PuzzleNode& node = obj.PlacedNodes[Puzzle::Config::MaxPuzzleSizeTiles * y + x]; + ImVec2 pos = ImVec2{puzCursorStart.x + x * UIPuzBoxSize + 5, puzCursorStart.y + y * UIPuzBoxSize}; + ImGui::SetCursorScreenPos(pos); + ImGui::Text("%s", GetShortNodeName(node)); + } + } + + for (int32_t y = 0; y <= obj.HeightTiles; ++y) + { + ImVec2 linePos = {puzCursorStart.x, puzCursorStart.y + y * UIPuzBoxSize}; + drawList.AddLine(linePos, + {linePos.x + obj.WidthTiles * UIPuzBoxSize, linePos.y}, + y % Puzzle::Config::CardSize == 0 ? 0xFFFFFFFF : 0x11FFFFFF); + } + for (int32_t x = 0; x <= obj.WidthTiles; ++x) + { + ImVec2 linePos = {puzCursorStart.x + x * UIPuzBoxSize, puzCursorStart.y}; + drawList.AddLine(linePos, + {linePos.x, linePos.y + obj.HeightTiles * UIPuzBoxSize}, + x % Puzzle::Config::CardSize == 0 ? 0xFFFFFFFF : 0x11FFFFFF); + } + + ImGui::Spacing(); + ImGui::Spacing(); + + if (ImGui::TreeNodeEx("Available Cards", ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Framed)) + { + for (int32_t i = 0; i < obj.AvailableCardCount; ++i) + { + ImGui::Text("Card"); + } + ImGui::TreePop(); + } } ImGui::End(); diff --git a/src/game/Puzzle.h b/src/game/Puzzle.h index 9c730b1..d1d6d26 100644 --- a/src/game/Puzzle.h +++ b/src/game/Puzzle.h @@ -18,112 +18,6 @@ namespace Puzzle static constexpr uint32_t MaxAvailableStacks = 16; static constexpr uint32_t MaxGoalPositions = 16; }; - - // struct PuzPos - // { - // int8_t X = 0; - // int8_t Y = 0; - - // PuzPos& operator+=(const PuzPos& rhs) - // { - // X += rhs.X; - // Y += rhs.Y; - // return *this; - // } - - // friend PuzPos operator+(PuzPos lhs, const PuzPos& rhs) - // { - // lhs += rhs; - // return lhs; - // } - // }; - - // struct ElemPos - // { - // PuzPos Position; - // uint8_t ElemIdx = 0; - // }; - - // enum class PuzzleElementType : uint8_t - // { - // None, - // WaterIn, - // WaterGoal, - // WaterChannel, - // ElectricIn, - // ElectricGoal, - // Blocked, - // Bridge, - // }; - - // struct PuzzleNode - // { - // PuzzleElementType PlacedTypes[Config::MaxElementsPerTile]{PuzzleElementType::None}; - - // bool HasElement(PuzzleElementType search) const; - // bool IsEmpty() const; - // }; - - // struct StaticPuzzleCard - // { - // PuzzleNode Nodes[Config::NodesPerCard]; - // uint16_t ModelHandle = 0; - // }; - - // struct StaticPuzzleCardHandle - // { - // uint16_t Idx = UINT16_MAX; - // bool IsValid() - // { - // return Idx != UINT16_MAX; - // } - // }; - - // struct StaticPuzzleData - // { - // StaticPuzzleCard Cards[64]; - - // void Setup(); - // static StaticPuzzleData& Get(); - // const StaticPuzzleCard& GetCard(StaticPuzzleCardHandle H) const; - // }; - - // struct PlacedPuzzleCard - // { - // StaticPuzzleCardHandle RefCard; - // PuzPos Position; - // uint8_t Rotation = 0; - // bool IsLocked = false; - // }; - - // struct PuzzleCardStack - // { - // StaticPuzzleCardHandle RefCard; - // uint8_t MaxAvailableCount = 0; - // uint8_t UsedCount = 0; - - // uint8_t GetRemainingCount(); - // }; - - // struct PuzzleData - // { - // uint32_t AvailableCardCount = 0; - // PuzzleCardStack AvailableCards[Config::MaxAvailableStacks]; - // uint32_t PlacedCardCount = 0; - // PlacedPuzzleCard PlacedCards[Config::MaxCardsInPuzzle]; - - // // Indexed by board position - // PuzzleNode PlacedNodes[Config::MaxTilesInPuzzle]; - - // uint32_t GoalPositionCount = 0; - // ElemPos GoalPositions[Config::MaxGoalPositions]; - - // const PuzzleNode& GetNodeAt(PuzPos pos) const; - // PuzzleElementType GetElementAt(ElemPos pos) const; - - // char PuzzleName[32]{"Unnamed"}; - // bool RenderDebugUI(); - // }; } // namespace Puzzle namespace Generated @@ -131,8 +25,10 @@ namespace Generated PuzPos operator+=(PuzPos lhs, const PuzPos& rhs); PuzPos operator+(PuzPos lhs, const PuzPos& rhs); - void Setup(StaticPuzzleData& data); + void Setup(); StaticPuzzleData& GetStaticPuzzleData(); + void LoadStaticPuzzleData(); + void SaveStaticPuzzleData(); const StaticPuzzleCard& GetCard(const StaticPuzzleData& data, StaticPuzzleCardHandle H); bool HasElement(const PuzzleNode& node, PuzzleElementType::Enum search); bool IsEmpty(const PuzzleNode& node); diff --git a/src/game/Setup.cpp b/src/game/Setup.cpp index b2bae47..6629110 100644 --- a/src/game/Setup.cpp +++ b/src/game/Setup.cpp @@ -48,6 +48,7 @@ namespace Game instance.UsedScratchAmount = 0; SetShared(shared); SetInstance(instance); + Generated::LoadStaticPuzzleData(); SetupInstance.Rendering.Setup(); instance.GameLevel.Setup(shared.Game); instance.IsInitialized = true; diff --git a/src/game/Tools.cpp b/src/game/Tools.cpp new file mode 100644 index 0000000..9e4d681 --- /dev/null +++ b/src/game/Tools.cpp @@ -0,0 +1,39 @@ +#include "Global.h" +#include "Instance.h" +#include "Tools.h" +#include "rendering/Rendering.h" + +#include + +namespace Tools +{ + const char* GetAssetPath(uint32_t assetHandle) + { + const auto& inst = Game::GetInstance(); + for (int32_t j = 0; j < inst.DebugData.AssetCount; ++j) + { + if (inst.DebugData.AssetHandles[j] == assetHandle) + { + return inst.DebugData.AssetHandlePaths[j]; + } + } + return "---"; + } + + void ModelDropdown(uint16_t& modelHandle) + { + auto& R = Game::GameRendering::Get(); + const char* name = GetAssetPath(R.Models[modelHandle].AssetHandle); + if (ImGui::BeginCombo("Models", name)) + { + for (int32_t i = 0; i < R.ModelCount; ++i) + { + if (ImGui::Selectable(GetAssetPath(R.Models[i].AssetHandle), i == modelHandle)) + { + modelHandle = i; + } + } + ImGui::EndCombo(); + } + } +} // namespace Tools diff --git a/src/game/Tools.h b/src/game/Tools.h new file mode 100644 index 0000000..b910873 --- /dev/null +++ b/src/game/Tools.h @@ -0,0 +1,7 @@ +#pragma once +#include + +namespace Tools +{ + void ModelDropdown(uint16_t& modelHandle); +} // namespace Tools diff --git a/src/game/data/puzzles/hell yea.pzl b/src/game/data/puzzles/hell yea.pzl index 09030ea..aed0f8d 100644 --- a/src/game/data/puzzles/hell yea.pzl +++ b/src/game/data/puzzles/hell yea.pzl @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fadb13f56deb93ae832808dc82bec034707f017f6cd70b18bb3c8f9d86d5fb00 +oid sha256:8b9208edea8425a4f88b27a2c4d5efee5ba64fd8732a24fbada5ef0e89aa6073 size 18110 diff --git a/src/game/data/puzzles/test.pzl b/src/game/data/puzzles/test.pzl index 4e1c001..b983ed5 100644 --- a/src/game/data/puzzles/test.pzl +++ b/src/game/data/puzzles/test.pzl @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ca5a0230894fad40db294317c016d4002833aa72573a20a80584ff661fc633d4 +oid sha256:de5ca966c746712655f85e1333f1c7666bc6ceed22dd63d44830f01e96515836 size 18110 diff --git a/src/game/data/static/puzzle.dat b/src/game/data/static/puzzle.dat new file mode 100644 index 0000000..5ca1242 Binary files /dev/null and b/src/game/data/static/puzzle.dat differ diff --git a/src/game/mini.def b/src/game/mini.def index d9c51bb..01d9fa9 100644 --- a/src/game/mini.def +++ b/src/game/mini.def @@ -12,14 +12,14 @@ type ElemPos enum PuzzleElementType(u8) { - None GameName("Empty") - WaterIn GameName("Water Source") - WaterGoal GameName("Water Goal") - WaterChannel GameName("Water Channel") - ElectricIn GameName("Electricity Source") - ElectricGoal GameName("Electricity Goal") - Blocked GameName("Blocked") - Bridge GameName("Bridge") + None GameName("Empty") ShortName(" ") + WaterIn GameName("Water Source") ShortName("~+") + WaterGoal GameName("Water Goal") ShortName("~-") + WaterChannel GameName("Water Channel") ShortName("~") + ElectricIn GameName("Electricity Source") ShortName("e+") + ElectricGoal GameName("Electricity Goal") ShortName("e-") + Blocked GameName("Blocked") ShortName("B") + Bridge GameName("Bridge") ShortName("#") } type PuzzleNode diff --git a/src/game/rendering/Rendering.cpp b/src/game/rendering/Rendering.cpp index 5ff25da..a978ff3 100644 --- a/src/game/rendering/Rendering.cpp +++ b/src/game/rendering/Rendering.cpp @@ -3,6 +3,7 @@ #include "../Instance.h" #include "../Log.h" #include "../Mesh.h" +#include "../Tools.h" #include "Rendering.h" #include "SDL3/SDL_events.h" @@ -515,6 +516,8 @@ namespace Game for (int32_t i = 0; i < BX_COUNTOF(level.Puzzles); ++i) { auto& puzzleData = level.Puzzles[i].Data; + if (puzzleData.PuzzleName[0] == 0) continue; + bool isSelected = debug.SelectedDebugLevel == i; ImGui::PushID("selectable"); if (ImGui::Selectable(puzzleData.PuzzleName, isSelected)) @@ -525,6 +528,7 @@ namespace Game if (isSelected) { ImGui::PushID("edit field"); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::InputText("", puzzleData.PuzzleName, sizeof(Generated::PuzzleData::PuzzleName)); ImGui::PopID(); @@ -536,6 +540,53 @@ namespace Game } } ImGui::End(); + if (ImGui::Begin("Cards")) + { + Generated::StaticPuzzleData& staticData = Generated::GetStaticPuzzleData(); + if (ImGui::Button("Save")) + { + Generated::SaveStaticPuzzleData(); + } + ImGui::SameLine(); + if (ImGui::Button("Reload")) + { + Generated::LoadStaticPuzzleData(); + } + + for (int32_t i = 0; i < BX_COUNTOF(staticData.Cards); ++i) + { + ImGui::Separator(); + + Generated::StaticPuzzleCard& card = staticData.Cards[i]; + ImGui::PushID(i); + ImGui::Text("%i", i); + + Tools::ModelDropdown(card.ModelHandle); + for (int32_t y = 0; y < Puzzle::Config::CardSize; ++y) + { + ImGui::PushID(y); + for (int32_t x = 0; x < Puzzle::Config::CardSize; ++x) + { + if (x > 0) ImGui::SameLine(); + ImGui::PushID(x); + auto& node = card.Nodes[y * Puzzle::Config::CardSize + x]; + if (ImGui::Button(Generated::PuzzleElementType::ShortName[node.PlacedTypes[0]], {26, 24})) + { + int32_t newVal = int32_t(node.PlacedTypes[0]) + 1; + if (newVal >= Generated::PuzzleElementType::EntryCount) + { + newVal = 0; + } + node.PlacedTypes[0] = Generated::PuzzleElementType::Enum(newVal); + } + ImGui::PopID(); + } + ImGui::PopID(); + } + ImGui::PopID(); + } + } + ImGui::End(); } GetInstance().GameLevel.Update(); diff --git a/src/game/rendering/Rendering.h b/src/game/rendering/Rendering.h index 3f5bed5..a8c1b93 100644 --- a/src/game/rendering/Rendering.h +++ b/src/game/rendering/Rendering.h @@ -96,7 +96,7 @@ namespace Game UIVisibilityState UIVisible = UIVisibilityState::Game; DitherData DitherTextures; - private: + public: bgfx::UniformHandle DefaultSampler; Texture Textures[8]; Material Materials[8]; diff --git a/src/gen/Def.h b/src/gen/Def.h index fdc9ed0..bd13676 100644 --- a/src/gen/Def.h +++ b/src/gen/Def.h @@ -1,4 +1,7 @@ #pragma once +#include "../game/Log.h" + +#include "bx/string.h" #include #include @@ -19,18 +22,21 @@ namespace Generated template bool WriteT(const char* _4cc, const T& data) { - Writer.write(_4cc, 4, &Err); - if (!Err.isOk()) return false; + if (!Write(_4cc, 4)) return false; + uint32_t hash = data.Hash; - Writer.write(&hash, sizeof(hash), &Err); + if (!Write(&hash, sizeof(hash))) return false; + uint32_t size = sizeof(T); - Writer.write(&size, sizeof(size), &Err); - return Err.isOk() && Save(&data, 1, *this); + if (!Write(&size, sizeof(size))) return false; + + return Save(&data, 1, *this); } bool Write(const void* data, uint32_t size) { Writer.write(data, size, &Err); + if (!Err.isOk()) LOG_ERROR("Write error: %s", Err.getMessage().getCPtr()); return Err.isOk(); } @@ -56,9 +62,47 @@ namespace Generated bool Read(void* data, uint32_t size) { Reader.read(data, size, &Err); + if (!Err.isOk()) LOG_ERROR("Read error: %s", Err.getMessage().getCPtr()); return Err.isOk(); } + template bool ReadT(const char* _4cc, T& data) + { + char magic[5]{0}; + if (!Read(magic, 4)) return false; + + bx::StringView given{_4cc, 4}; + bx::StringView loaded{magic, 4}; + if (bx::strCmp(given, loaded) != 0) + { + LOG_ERROR("Magic mismatch! %s != %s", _4cc, magic); + return false; + } + + uint32_t hash = 0; + if (!Read(&hash, sizeof(hash))) return false; + if (data.Hash != hash) + { + LOG_ERROR("Hash mismatch! %u != %u", data.Hash, hash); + return false; + } + + uint32_t size = 0; + if (!Read(&size, sizeof(size))) return false; + if (sizeof(T) != size) + { + LOG_ERROR("Size mismatch! %u != %u", sizeof(T), size); + return false; + } + + if (!Load(&data, 1, *this)) + { + LOG_ERROR("Failed to load: %s", Err.getMessage().getCPtr()); + return false; + } + return true; + } + void Finish() { Reader.close(); diff --git a/src/gen/Generated.cpp b/src/gen/Generated.cpp index 6596b48..332ef61 100644 --- a/src/gen/Generated.cpp +++ b/src/gen/Generated.cpp @@ -17,7 +17,7 @@ namespace Generated bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - auto val = (int32_t)obj[i]; + int32_t& val = (int32_t&)obj[i]; isOk = Load(&val, 1, serializer) && isOk; } return isOk; @@ -123,7 +123,6 @@ namespace Generated bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = Save(&obj[i].CardCount, 1, serializer) && isOk; isOk = Save(obj[i].Cards, 64, serializer) && isOk; } return isOk; @@ -133,7 +132,6 @@ namespace Generated bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = Load(&obj[i].CardCount, 1, serializer) && isOk; isOk = Load(obj[i].Cards, 64, serializer) && isOk; } return isOk; diff --git a/src/gen/Generated.h b/src/gen/Generated.h index ece5f7f..fc0a6ed 100644 --- a/src/gen/Generated.h +++ b/src/gen/Generated.h @@ -48,7 +48,7 @@ namespace Generated "~", "e+", "e-", - "█", + "B", "#", }; }; @@ -82,8 +82,7 @@ namespace Generated }; struct StaticPuzzleData { - static constexpr uint32_t Hash = 2220151575; - uint16_t CardCount = {}; + static constexpr uint32_t Hash = 1881743597; StaticPuzzleCard Cards[64] = {}; }; struct PuzzleCardStack