Cogs.Core
AssetReader.cpp
1#include "AssetReader.h"
2
3#include "JsonParser.h"
4
5#include "EntityReader.h"
6#include "ResourceReader.h"
7#include "SceneReader.h"
8#include "VariableReader.h"
9
10#include "ExtensionRegistry.h"
11
12#include "Context.h"
13#include "Scene.h"
14
15#include "Resources/ResourceStore.h"
16
17#include "Foundation/Logging/Logger.h"
18#include "Foundation/Platform/FileContents.h"
19
20namespace
21{
22 const Cogs::Logging::Log logger = Cogs::Logging::getLogger("AssetReader");
23
24 bool loadSceneExtension(const std::string& name)
25 {
26#if !defined( EMSCRIPTEN )
28#else
30 return true;
31 }
32 LOG_WARNING_ONCE(logger, "Scene file in Cogs.js using extension Not Loaded: %s", name.c_str());
33 return true;
34#endif
35 }
36}
37
38namespace Cogs
39{
40 namespace Core
41 {
42 void readTemplates(Context * context, const Value & jsonTemplates, AssetLoadFlags /*flags*/)
43 {
44 if (jsonTemplates.IsObject()) {
45 for (const auto& t : jsonTemplates.GetObject()) {
46 readEntityDefinition(context->store, toKey(t.name), t.value);
47 }
48 }
49 else {
50 LOG_ERROR(logger, "Expected templates section as JSON object");
51 }
52 }
53
54 [[nodiscard]] bool readExtensions(Context * /*context*/, const Value & jsonExtensions, AssetLoadFlags /*flags*/)
55 {
56 bool ok = true;
57 if (jsonExtensions.IsString()) {
58 auto name = toString(jsonExtensions);
59 ok = loadSceneExtension(name) && ok;
60 } else if (jsonExtensions.IsArray()) {
61 for (const auto & element : jsonExtensions.GetArray()) {
62 if (element.IsString()) {
63 auto name = toString(element);
64 ok = loadSceneExtension(name) && ok;
65 } else {
66 LOG_ERROR(logger, "Extension element must be string.");
67 ok = false;
68 }
69 }
70 } else {
71 LOG_ERROR(logger, "Extensions may only be specified as a single string or array of strings.");
72 ok = false;
73 }
74
75 return ok;
76 }
77
78 [[nodiscard]] bool readImports(Context * context, const Value & jsonImports, AssetLoadFlags flags, ComponentModel::Entity* root)
79 {
82
83 bool ok = true;
84 if (jsonImports.IsString()) {
85 ok = readAsset(context, toKey(jsonImports), flags, root);
86 } else if (jsonImports.IsArray()) {
87 for (const auto & element : jsonImports.GetArray()) {
88 if (element.IsString()) {
89 ok = readAsset(context, toKey(element), flags, root) && ok;
90 } else {
91 LOG_ERROR(logger, "Import element must be string path.");
92 ok = false;
93 }
94 }
95 } else {
96 LOG_ERROR(logger, "Imports may only be specified as a single string or array of strings.");
97 ok = false;
98 }
99
100 return ok;
101 }
102 }
103
104 [[nodiscard]] bool loadAsset(Cogs::Core::Context* context, const rapidjson::Document & document, Cogs::Core::AssetLoadFlags flags, ComponentModel::Entity* root)
105 {
106 using namespace Cogs::Core;
107
108 bool setup = true && (flags & AssetLoadFlags::ClearScene) != 0;
109
110 if ((flags & AssetLoadFlags::NoDefault) != 0) {
111 setup = false;
112 }
113 else {
114 for (const auto& section : document.GetObject()) {
115 if (section.name == "meta") {
116 if (section.value.HasMember("flags")) {
117 setup = false;
118 }
119 }
120 }
121 }
122
123 if (setup) {
124 context->scene->setup(true);
125 }
126
127 bool ok = true;
128 for (const auto& section : document.GetObject()) {
129 const Cogs::StringView sectionName = toKey(section.name);
130 switch (sectionName.hash()) {
131 case Cogs::hash("extensions"):
132 if (!readExtensions(context, section.value, flags)) {
133 LOG_ERROR(logger, "Failed to load one or several 'extensions'. Scene loading aborted");
134 return false;
135 }
136 break;
137 case Cogs::hash("imports"):
138 if (!readImports(context, section.value, flags, root)) {
139 LOG_ERROR(logger, "Failed to read all 'imports'. Scene loading aborted");
140 return false;
141 }
142 break;
143 case Cogs::hash("templates"):
144 readTemplates(context, section.value, flags);
145 break;
146 case Cogs::hash("resources"):
147 readResources(context, section.value);
148 break;
149 case Cogs::hash("entities"): [[fallthrough]];
150 case Cogs::hash("scene"):
151 readScene(context, section.value, flags, root);
152 break;
153 case Cogs::hash("variables"): [[fallthrough]];
154 case Cogs::hash("settings"):
155 readVariables(*context->variables, section.value, {});
156 break;
157 case Cogs::hash("meta"):
158 break;
159 default:
160 LOG_WARNING(logger, "Unknown scene section: %.*s", StringViewFormat(sectionName));
161 break;
162 }
163 }
164
165 return ok;
166 }
167
168}
169
170bool Cogs::Core::readAsset(Context * context, StringView fileName, AssetLoadFlags flags, ComponentModel::Entity * root)
171{
172 if ((flags & AssetLoadFlags::ClearScene) == AssetLoadFlags::ClearScene) {
173 context->scene->clear();
174 }
175
176 rapidjson::Document document = parseJson(context, fileName, JsonParseFlags::NoCachedContent);
177
178 if (!document.IsObject()) {
179 LOG_ERROR(logger, "readAsset: JSon Parse Error '%.*s'", StringViewFormat(fileName));
180 if ((flags & AssetLoadFlags::ClearScene) == AssetLoadFlags::ClearScene) {
181 context->scene->setup(true);
182 }
183 return false;
184 }
185
186 bool ok = loadAsset(context, document, flags, root);
187 if ((flags & AssetLoadFlags::ClearScene) == AssetLoadFlags::ClearScene) {
188 context->scene->setup(false);
189 }
190
191 return ok;
192}
193
194
195bool Cogs::Core::readAssetFromString(Context* context, StringView contents, AssetLoadFlags flags, ComponentModel::Entity* root)
196{
197 if ((flags & AssetLoadFlags::ClearScene) == AssetLoadFlags::ClearScene) {
198 context->scene->clear();
199 }
200
201 rapidjson::Document document = parseJson(contents, JsonParseFlags::NoCachedContent);
202
203 if (!document.IsObject()) {
204 LOG_ERROR(logger, "readAssetFromString: JSon Parse Error: %.*s", StringViewFormat(contents.substr(0,80)));
205 if ((flags & AssetLoadFlags::ClearScene) == AssetLoadFlags::ClearScene) {
206 context->scene->setup(true);
207 }
208 return false;
209 }
210
211 return loadAsset(context, document, flags, root);
212}
213
214
215namespace {
216 using namespace Cogs::Core;
217
218 bool readAssetDefinitionFromDocument(Context* context, Document& document, Cogs::StringView origin, AssetDefinition& assetDefinition)
219 {
220 if (!document.IsObject()) {
221 LOG_ERROR(logger, "readAssetDefinitionFromDocument: JSon Parse Error '%.*s'", StringViewFormat(origin));
222 return false;
223 }
224
225 AssetLoadFlags flags = AssetLoadFlags::None;
226
227 bool ok = true;
228 for (const auto& section : document.GetObject()) {
229 const Cogs::StringView sectionName = toKey(section.name);
230 switch (sectionName.hash()) {
231 case Cogs::hash("extensions"):
232 if (!readExtensions(context, section.value, flags)) {
233 LOG_ERROR(logger, "Failed to load one or several 'extensions'. Scene loading aborted");
234 return false;
235 }
236 break;
237 case Cogs::hash("imports"):
238 if (!readImports(context, section.value, flags, nullptr)) {
239 LOG_ERROR(logger, "Failed to read all 'imports'. Scene loading aborted");
240 return false;
241 }
242 break;
243 case Cogs::hash("templates"):
244 readTemplates(context, section.value, flags);
245 break;
246 case Cogs::hash("resources"):
247 readResourceDefinitions(context, section.value, 0, assetDefinition);
248 break;
249 case Cogs::hash("entities"): [[fallthrough]];
250 case Cogs::hash("scene"):
251 readSceneDefinition(context, section.value, flags, assetDefinition);
252 break;
253 case Cogs::hash("variables"): [[fallthrough]];
254 case Cogs::hash("settings"):
255 readVariables(*context->variables, section.value, {});
256 break;
257 case Cogs::hash("meta"):
258 break;
259 default:
260 LOG_WARNING(logger, "Unknown scene section: %.*s", StringViewFormat(sectionName));
261 break;
262 }
263 }
264 return ok;
265 }
266
267 JsonParseFlags createJsonParseFlags(bool compressed) {
268 auto flags = JsonParseFlags::PreferUncachedContent;
269 if (compressed) {
270 flags |= JsonParseFlags::Compressed;
271 }
272 return flags;
273 }
274}
275
276bool Cogs::Core::readAssetDefinitionFromFile(Context * context, StringView fileName, AssetDefinition & assetDefinition, bool compressed /*= false*/)
277{
278 auto flags = createJsonParseFlags(compressed);
279 auto doc = parseJson(context, fileName, flags);
280 return readAssetDefinitionFromDocument(context, doc, fileName, assetDefinition);
281}
282
283bool Cogs::Core::readAssetDefinitionFromFileContents(class Context* context, std::unique_ptr<FileContents> contents, AssetDefinition & assetDefinition, bool compressed /*= false*/)
284{
285 auto flags = createJsonParseFlags(compressed);
286 std::string origin = contents->origin().to_string();
287 auto doc = parseJson(context, std::move(contents), flags);
288 return readAssetDefinitionFromDocument(context, doc, origin , assetDefinition);
289}
Container for components, providing composition of dynamic entities.
Definition: Entity.h:18
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Definition: Context.h:83
class EntityStore * store
Entity store.
Definition: Context.h:231
std::unique_ptr< class Scene > scene
Scene structure.
Definition: Context.h:225
static bool hasExtension(const StringView &key, bool silent=false)
Check if an extension with the given key is present in this build.
static const void * loadExtensionModule(const std::string &path, void **modulehandle=nullptr, ExtensionModuleLoadResult *result=nullptr)
Load the extension module with the given name.
Log implementation class.
Definition: LogManager.h:139
Provides a weakly referenced view over the contents of a string.
Definition: StringView.h:24
constexpr StringView substr(size_t offset, size_t count=NoPosition) const noexcept
Get the given sub string.
Definition: StringView.h:258
std::string to_string() const
String conversion method.
Definition: StringView.cpp:9
constexpr size_t hash() const noexcept
Get the hash code of the string.
Definition: StringView.h:200
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
void COGSCORE_DLL_API readSceneDefinition(class Context *context, const Value &jsonScene, AssetLoadFlags flags, AssetDefinition &asset)
Parse JSON description of Entities in Cogs Scene. Store contents in asset param.
void COGSCORE_DLL_API readScene(class Context *context, const Value &jsonScene, AssetLoadFlags flags, ComponentModel::Entity *root)
Parse JSON description of Entities in Cogs Scene file and create Entities defined in scene.
AssetLoadFlags
Asset and Scene loading flags. May be combined with resource loading flags.
@ NoDefault
Don't load the default scene. Highly recommended as not setting this flag cause extra scene parse.
@ ClearScene
Clear the scene before loading the asset. NOT allowed for Bridge: loadAsset and loadAssetFromString.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
Contains all Cogs related functionality.
Definition: FieldSetter.h:23
constexpr size_t hash() noexcept
Simple getter function that returns the initial value for fnv1a hashing.
Definition: HashFunctions.h:62