aboutsummaryrefslogtreecommitdiff
path: root/source/Level.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Level.cpp')
-rw-r--r--source/Level.cpp165
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();
+ }
+}