diff options
author | rtk0c <[email protected]> | 2022-05-22 23:05:03 -0700 |
---|---|---|
committer | rtk0c <[email protected]> | 2022-05-22 23:05:03 -0700 |
commit | 123f741e3f5374b93ac39887b62bfa0d66762ae2 (patch) | |
tree | cedbc4b2dd87e2caadfde48a0c12a0336672bdd3 /source/Level.cpp | |
parent | c568f0a8c9f0aef00c770b494ee1ff3a89ab48de (diff) |
Changeset: 36 Add basic machinery for levels (no saving/loading yet)
Diffstat (limited to 'source/Level.cpp')
-rw-r--r-- | source/Level.cpp | 165 |
1 files changed, 164 insertions, 1 deletions
diff --git a/source/Level.cpp b/source/Level.cpp index eec7b85..ea3e9a9 100644 --- a/source/Level.cpp +++ b/source/Level.cpp @@ -1,12 +1,175 @@ #include "Level.hpp" +#include "AppConfig.hpp" +#include "PodVector.hpp" +#include "RapidJsonHelper.hpp" +#include "ScopeGuard.hpp" +#include "Utils.hpp" + +#include <rapidjson/document.h> +#include <rapidjson/filereadstream.h> +#include <rapidjson/filewritestream.h> +#include <rapidjson/writer.h> +#include <cstdio> +#include <filesystem> + +using namespace std::literals; +namespace fs = std::filesystem; + +constexpr auto kInvalidEntryId = std::numeric_limits<size_t>::max(); + +struct Level::InstanciationEntry { + // If set to std::numeric_limits<size_t>::max(), this object is parented to the "root" provided when instanciating + size_t parentId; + rapidjson::Document data; +}; + +Level::Level() = default; + +Level::~Level() = default; + +void Level::Instanciate(GameObject* relRoot) const { +} + +void LevelManager::DiscoverFilesDesignatedLocation() { + auto path = AppConfig::assetDirPath / "Levels"; + DiscoverFiles(path); +} + +void LevelManager::DiscoverFiles(const std::filesystem::path& dir) { + for (auto& item : fs::directory_iterator(dir)) { + auto& path = item.path(); + if (!item.is_regular_file()) { + continue; + } + if (path.extension() != ".json") { + continue; + } + + // Parse uid from filename, map key + Uid uid; + uid.ReadString(path.filename().string()); + + // Map value + LoadableObject obj; + obj.filePath = path; + + mObjByUid.try_emplace(uid, std::move(obj)); + } +} + +Level* LevelManager::FindLevel(const Uid& uid) const { + auto iter = mObjByUid.find(uid); + if (iter != mObjByUid.end()) { + return iter->second.level.Get(); + } else { + return nullptr; + } +} + +#define BRUSSEL_DEF_LEVEL_NAME "New Level" +#define BRUSSEl_DEF_LEVEL_DESC "No description." + +Level* LevelManager::LoadLevel(const Uid& uid) { + auto iter = mObjByUid.find(uid); + if (iter != mObjByUid.end()) { + auto& ldObj = iter->second; + if (ldObj.level != nullptr) { + auto file = Utils::OpenCstdioFile(ldObj.filePath, Utils::Read, false); + if (!file) { + fprintf(stderr, "Cannot open file level file %s that was discovered on game startup.", ldObj.filePath.string().c_str()); + return nullptr; + } + DEFER { fclose(file); }; + + char readerBuffer[65536]; + rapidjson::FileReadStream stream(file, readerBuffer, sizeof(readerBuffer)); + + rapidjson::Document root; + root.ParseStream(stream); + + Level* level; + ldObj.level.Attach(level = new Level()); + + level->mMan = this; + +#if defined(BRUSSEL_DEV_ENV) + BRUSSEL_JSON_GET_DEFAULT(root, "Name", std::string, ldObj.name, BRUSSEL_DEF_LEVEL_NAME); + BRUSSEL_JSON_GET_DEFAULT(root, "Description", std::string, ldObj.description, BRUSSEl_DEF_LEVEL_DESC) +#endif + + auto rvEntries = rapidjson::GetProperty(root, rapidjson::kArrayType, "DataEntries"sv); + if (!rvEntries) return nullptr; + for (auto iter = rvEntries->Begin(); iter != rvEntries->End(); ++iter) { + Level::InstanciationEntry entry; + + BRUSSEL_JSON_GET_DEFAULT(*iter, "ParentId", int, entry.parentId, kInvalidEntryId); + + auto rvDataEntry = rapidjson::GetProperty(*iter, "Data"sv); + if (!rvDataEntry) return nullptr; + entry.data.CopyFrom(*iter, entry.data.GetAllocator()); + + level->mEntries.push_back(std::move(entry)); + } + } + return ldObj.level.Get(); + } else { + return nullptr; + } +} + +void LevelManager::PrepareLevel(const Uid& uid) { + // TODO +} + +LevelManager::LoadableObject& LevelManager::AddLevel(const Uid& uid) { + auto&& [iter, inserted] = mObjByUid.try_emplace(uid, LoadableObject{}); + auto& ldObj = iter->second; +#if defined(BRUSSEL_DEV_ENV) + ldObj.name = BRUSSEL_DEF_LEVEL_NAME; + ldObj.description = BRUSSEl_DEF_LEVEL_DESC; +#endif + return ldObj; +} + LevelWrapperObject::LevelWrapperObject(GameWorld* world) - : GameObject(KD_LevelWrapper, world) { + : GameObject(KD_LevelWrapper, world) // +{ mStopFreePropagation = true; } LevelWrapperObject::~LevelWrapperObject() { + // Destruction/freeing of this object is handled by our parent for (auto child : GetChildren()) { FreeRecursive(child); } } + +void LevelWrapperObject::SetBoundLevel(Level* level) { + if (mLevel != level) { + mLevel.Attach(level); + + // Cleanup old children + // TODO needs to Resleep()? + auto children = RemoveAllChildren(); + for (auto child : children) { + FreeRecursive(child); + } + } + + level->Instanciate(this); + + PodVector<GameObject*> stack; + stack.push_back(this); + + while (!stack.empty()) { + auto obj = stack.back(); + stack.pop_back(); + + for (auto child : obj->GetChildren()) { + stack.push_back(child); + } + + obj->Awaken(); + } +} |