From e66286ebe30afc9acc4531fc2bea29b7fb924f93 Mon Sep 17 00:00:00 2001 From: rtk0c Date: Mon, 30 May 2022 17:03:20 -0700 Subject: Changeset: 56 Buildsystem cleanup: change to layered structure for different targets --- source/30-game/Level.cpp | 175 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 source/30-game/Level.cpp (limited to 'source/30-game/Level.cpp') diff --git a/source/30-game/Level.cpp b/source/30-game/Level.cpp new file mode 100644 index 0000000..5881084 --- /dev/null +++ b/source/30-game/Level.cpp @@ -0,0 +1,175 @@ +#include "Level.hpp" + +#include "AppConfig.hpp" +#include "PodVector.hpp" +#include "RapidJsonHelper.hpp" +#include "ScopeGuard.hpp" +#include "Utils.hpp" + +#include +#include +#include +#include +#include +#include + +using namespace std::literals; +namespace fs = std::filesystem; + +constexpr auto kInvalidEntryId = std::numeric_limits::max(); + +struct Level::InstanciationEntry { + // If set to std::numeric_limits::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) // +{ + 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 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(); + } +} -- cgit v1.2.3-70-g09d2