Cogs.Core
EntityCreator.cpp
1#include "EntityCreator.h"
2
3#include "Foundation/Logging/Logger.h"
4
5#include "EntityStore.h"
6
7#include "Systems/Core/TransformSystem.h"
8#include "Systems/Core/PropertiesSystem.h"
9#include "Systems/Core/AssetSystem.h"
10
11#include "Components/Core/RenderComponent.h"
12
13#include "Resources/AssetManager.h"
14
15namespace
16{
17 Cogs::Logging::Log logger = Cogs::Logging::getLogger("EntityCreator");
18
19 void logFail(bool lookupExisting, Cogs::StringView type, Cogs::StringView name)
20 {
21 if (lookupExisting) {
22 LOG_ERROR(logger, "Could not find entity name:'%.*s'.", StringViewFormat(name));
23 }
24 else {
25 LOG_ERROR(logger, "Could not create entity type:'%.*s'.", StringViewFormat(type));
26 }
27 }
28}
29
30Cogs::Core::EntityPtr Cogs::Core::createEntity(EntityCreationContext & entityContext, const SceneEntityDefinition & definition)
31{
32 auto context = entityContext.context;
33 auto & scene = *entityContext.scene;
34
35 if (definition.isSequence()) return nullptr;
36
37 const auto name = scene.properties.getString(definition.nameIndex);
38
39 StringView type{};
40 if (definition.isModel()) {
41 type = entityContext.skipModel ? "Group" : "Model";
42 }
43 else if (definition.isAsset()) {
44 type = "Asset";
45 }
46 else if (definition.isModel() || definition.isLodGroup()) {
47 }
48 else {
49 type = Strings::get(definition.type);
50 }
51
52 const bool lookupExisting = !name.empty() && name[0] == '$';
53
54 EntityPtr entity{};
55
56 if (lookupExisting) {
57 entity = context->store->findEntity(name.substr(1));
58 } else {
59 switch (entityContext.parentMode) {
60 case EntityParentMode::None:
61 entity = context->store->createEntity(name, type);
62 break;
63 case EntityParentMode::Default:
64 entity = context->store->createChildEntity(type, entityContext.parent, name);
65 break;
66 case EntityParentMode::TransformOnly:
67 entity = context->store->createEntity(name, type, false);
68
69 {
70 auto parentTransform = entityContext.parent->getComponentHandle<TransformComponent>();
71
72 auto transform = entity->getComponent<TransformComponent>();
73
74 if (transform) {
75 transform->parent = parentTransform;
76 }
77 }
78
79 break;
80 default:
81 break;
82 }
83 }
84
85 if (!entity) {
86 logFail(lookupExisting, type, name);
87 return {};
88 }
89
90 if (definition.objectId < ~0u) {
91 auto renderComponent = entity->getComponent<RenderComponent>();
92
93 if (renderComponent) {
94 renderComponent->objectId = definition.objectId;
95 } else {
96 LOG_ERROR(logger, "objectId property set but no target RenderComponent defined.");
97 }
98 }
99
100 if (definition.numFields) {
101 std::span<FieldValue> fields = std::span(scene.fieldValues).subspan(definition.firstField, definition.numFields);
102 applyFieldValues(context, fields, entity.get());
103 }
104
105 if (definition.numProperties > 0) {
106 auto propertiesComponent = entity->getComponent<PropertiesComponent>();
107
108 if (!propertiesComponent) {
109 propertiesComponent = context->store->addComponent<PropertiesComponent>(entity.get());
110 }
111
112 propertiesComponent->properties.copyProperties(scene.properties, definition.firstProperty, definition.numProperties);
113 }
114
115 if (definition.isParentedByName()) {
116 auto parentName = scene.properties.getString(definition.parentIndex);
117
118 auto p = context->store->findEntity(parentName.substr(1));
119 context->store->addChild(p.get(), entity);
120 }
121
122 if (definition.isAsset()) {
123 auto path = scene.properties.getString(definition.asset.index);
124
125 auto assetComponent = entity->getComponent<AssetComponent>();
126
127 if (!assetComponent) {
128 assetComponent = context->store->addComponent<AssetComponent>(entity.get());
129 }
130
131 assetComponent->asset = context->assetManager->loadAsset(path, NoResourceId, AssetLoadFlags::None);
132 assetComponent->flags = (AssetFlags)definition.asset.flags;
133 }
134
135 return entity;
136}
137
138Cogs::ComponentModel::Entity * Cogs::Core::createEntity(Context * context, SceneDefinition & scene, const SceneEntityDefinition & definition, Cogs::ComponentModel::Entity * parent)
139{
140 if (definition.isSequence()) {
141 return nullptr;
142 }
143
144 const StringView name = scene.properties.getString(definition.nameIndex);
145 StringView type;
146 if (definition.isAsset()) {
147 type = "Asset";
148 }
149 else if (definition.isModel() || definition.isLodGroup()) {
150 }
151 else {
152 type = Strings::get(definition.type);
153 }
154
155 const bool lookupExisting = !name.empty() && name[0] == '$';
156 EntityPtr entity;
157 if (lookupExisting) {
158 entity = context->store->findEntity(name.substr(1));
159 }
160 else if (parent) {
161 entity = context->store->createChildEntity(type, parent, name);
162 } else {
163 entity = context->store->createEntity(name, type);
164 }
165
166 if (!entity) {
167 logFail(lookupExisting, type, name);
168 return nullptr;
169 }
170
171 if (definition.objectId < ~0u) {
172 auto renderComponent = entity->getComponent<RenderComponent>();
173
174 if (renderComponent) {
175 renderComponent->objectId = definition.objectId;
176 } else {
177 LOG_ERROR(logger, "objectId property set but no target RenderComponent defined.");
178 }
179 }
180
181 if (definition.numFields) {
182 auto fields = std::span(scene.fieldValues).subspan(definition.firstField, definition.numFields);
183 applyFieldValues(context, fields, entity.get());
184 }
185
186 if (definition.numProperties > 0) {
187 auto propertiesComponent = entity->getComponent<PropertiesComponent>();
188
189 if (!propertiesComponent) {
190 propertiesComponent = context->store->addComponent<PropertiesComponent>(entity.get());
191 }
192
193 propertiesComponent->properties.copyProperties(scene.properties, definition.firstProperty, definition.numProperties);
194 }
195
196 if (definition.isParentedByName()) {
197 auto parentName = scene.properties.getString(definition.parentIndex);
198
199 auto p = context->store->findEntity(parentName.substr(1));
200 context->store->addChild(p.get(), entity);
201 }
202
203 if (definition.isAsset()) {
204 auto path = scene.properties.getString(definition.asset.index);
205
206 auto assetComponent = entity->getComponent<AssetComponent>();
207
208 if (!assetComponent) {
209 assetComponent = context->store->addComponent<AssetComponent>(entity.get());
210 }
211
212 assetComponent->asset = context->assetManager->loadAsset(path, NoResourceId, AssetLoadFlags::None);
213 assetComponent->flags = (AssetFlags)definition.asset.flags;
214 }
215
216 return entity.get();
217}
Container for components, providing composition of dynamic entities.
Definition: Entity.h:18
Log implementation class.
Definition: LogManager.h:139
Provides a weakly referenced view over the contents of a string.
Definition: StringView.h:24
constexpr bool empty() const noexcept
Check if the string is empty.
Definition: StringView.h:122
constexpr StringView substr(size_t offset, size_t count=NoPosition) const noexcept
Get the given sub string.
Definition: StringView.h:258
std::shared_ptr< ComponentModel::Entity > EntityPtr
Smart pointer for Entity access.
Definition: EntityPtr.h:12
void applyFieldValues(class Context *context, std::span< FieldValue > entityDefinition, ComponentModel::Entity *entity)
Apply defaults from the given entityDefinition to the given entity.
AssetFlags
Controls asset system's model instance behaviour.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180