Improved prefab loading a bit.

This commit is contained in:
2024-12-05 19:27:37 -06:00
parent 223bbed232
commit a4774e6189
10 changed files with 113 additions and 71 deletions

View File

@ -20,8 +20,7 @@
"type": "RPGEntity"
},
"player": {
"type": "RPGPlayer",
"camera": "camera"
"type": "RPGPlayer"
}
}
}

View File

@ -23,7 +23,12 @@
"rosa": {
"prefab": "rosa",
"position": [ 0, 0, 0 ]
"position": [ 0, 0, 0 ],
"components": {
"player": {
"camera": "camera"
}
}
},
"npc": {

View File

@ -32,5 +32,8 @@ namespace Dawn {
);
~LoaderForSceneItems();
friend class SceneLoader;
friend class PrefabLoader;
};
}

View File

@ -10,6 +10,7 @@
#include "asset/loader/TextureLoader.hpp"
#include "scene/Scene.hpp"
#include "component/SceneComponentRegistry.hpp"
#include "util/JSON.hpp"
using namespace Dawn;
@ -35,6 +36,7 @@ void PrefabLoader::updateSync() {
assertNotNull(this->jsonLoader, "JSON Loader is NULL?");
if(!this->jsonLoader->loaded) return;
this->state = PrefabLoaderState::LOADING_DEPENDENCIES;
this->ctx->data = this->jsonLoader->data;
this->setupDependencies();
break;
@ -62,37 +64,6 @@ std::string PrefabLoader::getAssetType() const {
return PrefabLoader::ASSET_TYPE;
}
void PrefabLoader::stagePrefab(std::shared_ptr<SceneItem> item) {
assertTrue(this->loaded, "Prefab not loaded");
// Force-set new context values
ctx->data = this->jsonLoader->data;
// Load the scene item.
item->load(ctx);
auto &itemData = this->jsonLoader->data;
if(itemData.contains("components")) {
for(auto &cmpItem : itemData["components"].items()) {
auto &cmpName = cmpItem.key();
auto &cmpData = cmpItem.value();
assertTrue(
cmpData.contains("type"),
"Component missing type in %s",
cmpName.c_str()
);
auto cmpType = cmpData["type"].get<std::string>();
auto cmp = SceneComponentRegistry::createComponent(
cmpType, item
);
ctx->data = cmpData;
ctx->components[cmpName] = cmp;
cmp->load(ctx);
}
}
}
PrefabLoader::~PrefabLoader() {
}

View File

@ -34,13 +34,6 @@ namespace Dawn {
void updateAsync() override;
std::string getAssetType() const override;
/**
* Stages this prefab onto a scene item.
*
* @param item The scene item to stage.
*/
void stagePrefab(std::shared_ptr<SceneItem> item);
~PrefabLoader();
};
}

View File

@ -42,7 +42,7 @@ namespace Dawn {
auto it = assets.find(j);
if(it == assets.end()) {
auto parent = this->parent.lock();
assertNotNull(parent, "Couldn't find asset.");
assertNotNull(parent, "Couldn't find asset %s", j.c_str());
return parent->getAsset<T>(j);
}
auto asset = std::dynamic_pointer_cast<T>(it->second);
@ -80,5 +80,6 @@ namespace Dawn {
friend class PrefabLoader;
friend class LoaderForSceneItems;
friend class SceneLoader;
friend class SceneItem;
};
}

View File

@ -7,7 +7,8 @@
#include "game/Game.hpp"
#include "assert/assert.hpp"
#include "scene/Scene.hpp"
#include "component/SceneComponentRegistry.hpp"
#include "util/JSON.hpp"
#include "PrefabLoader.hpp"
using namespace Dawn;
@ -76,29 +77,33 @@ void SceneLoader::updateSync() {
auto &itemName = item.key();
auto &itemData = item.value();
auto sceneItem = ctx->items[itemName];
sceneItem->name = itemName;
ctx->data = itemData;
sceneItem->load(ctx);
if(itemData.contains("components")) {
for(auto &cmpItem : itemData["components"].items()) {
auto &cmpName = cmpItem.key();
auto &cmpData = cmpItem.value();
std::shared_ptr<SceneLoadContext> itemCtx;
if(itemData.contains("prefab")) {
auto prefabLoader = ctx->getAsset<PrefabLoader>(
itemData["prefab"].get<std::string>()
);
assertNotNull(prefabLoader, "Prefab loader not found");
assertTrue(prefabLoader->loaded, "Prefab loader not loaded");
assertNotNull(
prefabLoader->jsonLoader,
"Prefab JSON loader not found"
);
assertTrue(
cmpData.contains("type"),
"Component missing type in %s",
cmpName.c_str()
prefabLoader->jsonLoader->loaded,
"Prefab JSON loader not loaded"
);
itemCtx = prefabLoader->ctx;
itemCtx->data = json(prefabLoader->jsonLoader->data);
itemCtx->parent = this->ctx;
JSON::mergeObjectsRecursive(itemCtx->data, itemData);
} else {
itemCtx = this->ctx;
itemCtx->data = json(itemData);
}
auto cmpType = cmpData["type"].get<std::string>();
auto cmp = SceneComponentRegistry::createComponent(
cmpType, sceneItem
);
ctx->data = cmpData;
ctx->components[cmpName] = cmp;
cmp->load(ctx);
}
}
sceneItem->load(itemCtx);
}
}

View File

@ -8,6 +8,7 @@
#include "util/JSON.hpp"
#include "assert/assert.hpp"
#include "asset/loader/scene/PrefabLoader.hpp"
#include "component/SceneComponentRegistry.hpp"
using namespace Dawn;
@ -77,13 +78,6 @@ void SceneItem::deinit() {
}
void SceneItem::load(std::shared_ptr<SceneLoadContext> ctx) {
// Load prefab first, it can be overriden by other properties.
if(ctx->data.contains("prefab")) {
this->name = ctx->data["prefab"].get<std::string>();
auto prefabLoader = ctx->getAsset<PrefabLoader>(this->name);
prefabLoader->stagePrefab(shared_from_this());
}
if(ctx->data.contains("name")) {
this->name = ctx->data["name"].get<std::string>();
}
@ -108,6 +102,39 @@ void SceneItem::load(std::shared_ptr<SceneLoadContext> ctx) {
if(ctx->data.contains("scale")) {
this->setLocalScale(JSON::vec3(ctx->data["scale"]));
}
if(ctx->data.contains("components")) {
assertTrue(
ctx->data["components"].is_object(),
"Components must be an object in %s",
this->name.c_str()
);
auto components = json(ctx->data["components"]);
for(auto &cmpItem : components.items()) {
auto &cmpName = cmpItem.key();
auto &cmpData = cmpItem.value();
assertTrue(
cmpData.is_object(),
"Component data must be an object in %s",
cmpName.c_str()
);
assertTrue(
cmpData.contains("type"),
"Component missing type in %s",
cmpName.c_str()
);
auto cmpType = cmpData["type"].get<std::string>();
auto component = SceneComponentRegistry::createComponent(
cmpType, shared_from_this()
);
assertNotNull(component, "Component %s not found", cmpType.c_str());
ctx->data = json(cmpData);
ctx->components[cmpName] = component;
component->load(ctx);
}
}
}
void SceneItem::remove() {

View File

@ -77,3 +77,26 @@ struct Color JSON::color(const json &j) {
assertUnreachable("Invalid JSON type for color");
return COLOR_WHITE;
}
void JSON::mergeObjectsRecursive(json &a, const json &b) {
assertTrue(a.type() == json::value_t::object, "a is not an object");
assertTrue(b.type() == json::value_t::object, "b is not an object");
for(auto &item : b.items()) {
auto &key = item.key();
auto &value = item.value();
if(a.contains(key)) {
if(
a[key].type() == json::value_t::object &&
value.type() == json::value_t::object
) {
mergeObjectsRecursive(a[key], value);
} else {
a[key] = json(value);
}
} else {
a[key] = json(value);
}
}
}

View File

@ -25,5 +25,20 @@ namespace Dawn {
* @return Parsed color.
*/
static struct Color color(const json &j);
/**
* Merges all objects in the given JSON object into the first object,
* recursively.
*
* e.g. if; &a is { a: { b: 1, c: 2 }, d: 3 }
* &b is { a: { b: 4, d: 5 }, e: 4 }
*
* The output will become;
* { a: { b: 4, c: 2, d: 5 }, e: 4 }
*
* @param a JSON object to merge into.
* @param b JSON object to merge from.
*/
static void mergeObjectsRecursive(json &a, const json &b);
};
}