TDME2  1.9.200
MiniScriptLogic.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <memory>
4 #include <span>
5 #include <string>
6 #include <unordered_map>
7 
8 #include <tdme/tdme.h>
9 
15 #include <tdme/engine/Engine.h>
16 #include <tdme/engine/Transform.h>
20 #include <tdme/utilities/Console.h>
22 
23 using std::make_unique;
24 using std::span;
25 using std::string;
26 using std::unique_ptr;
27 using std::unordered_map;
28 
30 
42 
43 /**
44  * Mini script logic
45  * @author Andreas Drewke
46  */
48 public:
49  // forbid class copy
51 
52  /**
53  * Public constructor
54  * @param context context
55  * @param id id
56  * @param handlingHIDInput handling hid input
57  * @param miniScript logic mini script
58  * @param prototype prototype
59  * @param runsInEditor runs in editor
60  * @param hierarchyId hierarchy id
61  * @param hierarchyParentId hierarchy parent id
62  */
63  inline MiniScriptLogic(Context* context, const string& id, bool handlingHIDInput, LogicMiniScript* miniScript, Prototype* prototype, bool runsInEditor, const string& hierarchyId = string(), const string& hierarchyParentId = string()):
65  //
66  enginePrototypes[id] = prototype;
67  logicPrototypes[id] = prototype;
68  //
69  miniScript->setContext(context);
70  miniScript->setLogic(this);
71  }
72 
73  /**
74  * @return is running in editor
75  */
76  inline bool isRunningInEditor() {
77  return runsInEditor;
78  }
79 
80  /**
81  * @return Returns mini script
82  */
84  return miniScript.get();
85  }
86 
87  /**
88  * @return hierarchy id
89  */
90  inline const string& getHierarchyId() {
91  return hierarchyId;
92  }
93 
94  /**
95  * @return hierarchy parent id
96  */
97  inline const string& getHierarchyParentId() {
98  return hierarchyParentId;
99  }
100 
101  // overridden methods
102  inline void handleHIDEvents(vector<GUIMouseEvent>& mouseEvents, vector<GUIKeyboardEvent>& keyEvents) {
103  miniScript->collectHIDEvents(mouseEvents, keyEvents);
104  }
105 
106  inline void updateEngine() override {
107  // add engine entities requested by EngineMiniScript
108  if (miniScript->enginePrototypesToAdd.empty() == false) {
109  miniScript->prototypesToAddMutex.lock();
110  for (const auto& prototypeToAdd: miniScript->enginePrototypesToAdd) {
111  //
112  Console::println("MiniScriptLogic::updateEngine(): adding prototype: id: " + prototypeToAdd.id + ", hierarchyId: " + prototypeToAdd.hierarchyId + ", hierarchy parent id: " + prototypeToAdd.hierarchyParentId);
113  //
114  EntityHierarchy* parentEntity = nullptr;
115  if (prototypeToAdd.hierarchyId.empty() == false) {
116  parentEntity = dynamic_cast<EntityHierarchy*>(context->getEngine()->getEntity(prototypeToAdd.hierarchyId));
117  }
118  auto transform = prototypeToAdd.transform;
119  if (prototypeToAdd.type == LogicMiniScript::PrototypeToAdd::TYPE_ATTACH &&
120  prototypeToAdd.attachNodeId.empty() == false) {
121  auto prototypeIt = enginePrototypes.find(prototypeToAdd.hierarchyParentId);
122  auto prototype = prototypeIt == enginePrototypes.end()?nullptr:prototypeIt->second;
123  Matrix4x4 attachNodeTransformMatrix;
124  if (prototype != nullptr &&
125  prototype->getModel() != nullptr &&
126  prototype->getModel()->computeTransformMatrix(
127  prototypeToAdd.attachNodeId,
128  prototype->getModel()->getImportTransformMatrix(),
129  attachNodeTransformMatrix
130  ) == true) {
131  //
132  Transform attachNodeTransform;
133  attachNodeTransform.fromMatrix(attachNodeTransformMatrix, RotationOrder::ZYX);
134  transform = attachNodeTransform * transform;
135  } else {
136  Console::println("MiniScriptLogic::updateEngine(): " + getId() + ": " + prototypeToAdd.attachNodeId + "@" + getId() + " not found");
137  }
138  /*
139  // TODO: we need to create structure of attachNodeId ... ROOT
140  // but our bots do not have a structure until now
141  auto node = prototype->getModel()->getNodeById(prototypeToAdd.attachNodeId);
142  while (node != nullptr) {
143  node = node->getParentNode();
144  }
145  */
146  }
147  //
148  auto id = prototypeToAdd.attachNodeId.empty() == false?prototypeToAdd.attachNodeId + "." + prototypeToAdd.id:prototypeToAdd.id;
149  //
150  auto entity =
152  prototypeToAdd.prototype,
153  prototypeToAdd.attachNodeId.empty() == false?prototypeToAdd.attachNodeId + "." + prototypeToAdd.id:prototypeToAdd.id,
154  transform,
155  1,
156  parentEntity != nullptr
157  );
158  if (parentEntity == nullptr) {
159  context->getEngine()->addEntity(entity);
160  } else {
161  parentEntity->addEntity(entity, prototypeToAdd.hierarchyParentId);
162  parentEntity->update();
163  }
164  //
165  if (prototypeToAdd.type == LogicMiniScript::PrototypeToAdd::TYPE_ATTACH) enginePrototypes[id] = prototypeToAdd.prototype;
166  //
167  SceneConnector::addSounds(context->getAudio(), prototypeToAdd.prototype, id);
168  }
169  miniScript->enginePrototypesToAdd.clear();
170  miniScript->prototypesToAddMutex.unlock();
171  }
172  //
173  if (engineInitialized == false) {
174  // load sounds
175  auto prototypeIt = enginePrototypes.find(id);
176  if (prototypeIt != enginePrototypes.end()) {
177  SceneConnector::addSounds(context->getAudio(), prototypeIt->second, id);
178  }
179  // execute initializeEngine() function
180  vector<EngineMiniScript::ScriptVariable> argumentValues(0);
181  EngineMiniScript::ScriptVariable returnValue;
182  span argumentValuesSpan(argumentValues);
183  if (miniScript->call("initializeEngine", argumentValuesSpan, returnValue) == false) {
184  // Console::println("MiniScriptLogic::updateEngine(): Failed to call initializeEngine() function");
185  }
186  //
187  engineInitialized = true;
188  }
189  // execute updateEngine() function
190  vector<EngineMiniScript::ScriptVariable> argumentValues(0);
191  EngineMiniScript::ScriptVariable returnValue;
192  span argumentValuesSpan(argumentValues);
193  if (miniScript->call("updateEngine", argumentValuesSpan, returnValue) == false) {
194  // Console::println("MiniScriptLogic::updateEngine(): Failed to call updateEngine() function");
195  }
196  }
197 
198  inline void updateLogic() override {
199  // add physics entities requested by EngineMiniScript and scripts
200  if (miniScript->physicsPrototypesToAdd.empty() == false) {
201  miniScript->prototypesToAddMutex.lock();
202  //
203  for (const auto& prototypeToAdd: miniScript->physicsPrototypesToAdd) {
204  //
205  Console::println("MiniScriptLogic::updateLogic(): adding prototype: id: " + prototypeToAdd.id + ", hierarchyId: " + prototypeToAdd.hierarchyId + ", hierarchy parent id: " + prototypeToAdd.hierarchyParentId);
206  //
207  // add to physics
208  auto transform = prototypeToAdd.transform;
209  if (prototypeToAdd.type == LogicMiniScript::PrototypeToAdd::TYPE_ATTACH &&
210  prototypeToAdd.attachNodeId.empty() == false) {
211  auto prototypeIt = logicPrototypes.find(prototypeToAdd.hierarchyParentId);
212  auto prototype = prototypeIt == logicPrototypes.end()?nullptr:prototypeIt->second;
213  Matrix4x4 attachNodeTransformMatrix;
214  if (prototype != nullptr &&
215  prototype->getModel() != nullptr &&
216  prototype->getModel()->computeTransformMatrix(
217  prototypeToAdd.attachNodeId,
218  prototype->getModel()->getImportTransformMatrix(),
219  attachNodeTransformMatrix
220  ) == true) {
221  //
222  Transform attachNodeTransform;
223  attachNodeTransform.fromMatrix(attachNodeTransformMatrix, RotationOrder::ZYX);
224  transform = attachNodeTransform * transform;
225  } else {
226  Console::println("MiniScriptLogic::updateLogic(): " + getId() + ": " + prototypeToAdd.attachNodeId + "@" + getId() + " not found");
227  }
228  /*
229  // TODO: we need to create structure of attachNodeId ... ROOT
230  // but our bots do not have a structure until now
231  auto node = prototype->getModel()->getNodeById(prototypeToAdd.attachNodeId);
232  while (node != nullptr) {
233  node = node->getParentNode();
234  }
235  */
236  }
237  //
238  auto id = prototypeToAdd.attachNodeId.empty() == false?prototypeToAdd.attachNodeId + "." + prototypeToAdd.id:prototypeToAdd.id;
239  //
240  if (prototypeToAdd.hierarchyId.empty() == false) {
242  context->getWorld(),
243  prototypeToAdd.prototype,
244  id,
245  transform,
246  prototypeToAdd.hierarchyId,
247  prototypeToAdd.hierarchyParentId
248  );
249  } else {
251  context->getWorld(),
252  prototypeToAdd.prototype,
253  id,
254  transform,
255  Body::COLLISION_TYPEID_DYNAMIC
256  );
257  }
258  //
259  if (prototypeToAdd.type == LogicMiniScript::PrototypeToAdd::TYPE_ATTACH) logicPrototypes[id] = prototypeToAdd.prototype;
260 
261  // add logic
262  if (prototypeToAdd.prototype->hasScript() == true) {
263  auto prototype = prototypeToAdd.prototype;
264  auto logicMiniScript = make_unique<LogicMiniScript>();
265  logicMiniScript->parseScript(
266  Tools::getPathName(prototype->getScript()),
267  Tools::getFileName(prototype->getScript())
268  );
269  miniScript->context->addLogic(
270  make_unique<MiniScriptLogic>(
271  miniScript->context,
272  prototypeToAdd.id,
273  prototype->isScriptHandlingHID(),
274  logicMiniScript.release(),
275  prototypeToAdd.prototype,
276  runsInEditor,
277  prototypeToAdd.hierarchyId,
278  prototypeToAdd.hierarchyParentId
279  ).release()
280  );
281  }
282  }
283  //
284  miniScript->physicsPrototypesToAdd.clear();
285  //
286  miniScript->prototypesToAddMutex.unlock();
287  }
288  //
289  if (logicInitialized == false) {
290  // execute initializeLogic() function
291  vector<EngineMiniScript::ScriptVariable> argumentValues(0);
292  EngineMiniScript::ScriptVariable returnValue;
293  span argumentValuesSpan(argumentValues);
294  if (miniScript->call("initializeLogic", argumentValuesSpan, returnValue) == false) {
295  // Console::println("MiniScriptLogic::updateLogic(): Failed to call initializeLogic() function");
296  }
297  //
298  logicInitialized = true;
299  }
300  // execute on: nothing and other event polling and execution
301  miniScript->execute();
302  // execute updateLogic() function
303  vector<EngineMiniScript::ScriptVariable> argumentValues(0);
304  EngineMiniScript::ScriptVariable returnValue;
305  span argumentValuesSpan(argumentValues);
306  if (miniScript->call("updateLogic", argumentValuesSpan, returnValue) == false) {
307  // Console::println("MiniScriptLogic::updateLogic(): Failed to call updateLogic() function");
308  }
309  }
310 
311  inline void onLogicAdded() override {
312  // execute onLogicAdded() function
313  vector<EngineMiniScript::ScriptVariable> argumentValues(0);
314  EngineMiniScript::ScriptVariable returnValue;
315  span argumentValuesSpan(argumentValues);
316  if (miniScript->call("onLogicAdded", argumentValuesSpan, returnValue) == false) {
317  // Console::println("MiniScriptLogic::onLogicAdded(): Failed to call onLogicAdded() function");
318  }
319  }
320 
321  inline void onLogicsProcessed() override {
322  // execute onLogicsProcessed() function
323  vector<EngineMiniScript::ScriptVariable> argumentValues(0);
324  EngineMiniScript::ScriptVariable returnValue;
325  span argumentValuesSpan(argumentValues);
326  if (miniScript->call("onLogicsProcessed", argumentValuesSpan, returnValue) == false) {
327  // Console::println("MiniScriptLogic::onLogicsProcessed(): Failed to call onLogicsProcessed() function");
328  }
329  }
330 
331 private:
332  unique_ptr<LogicMiniScript> miniScript;
333  unordered_map<string, Prototype*> enginePrototypes;
334  unordered_map<string, Prototype*> logicPrototypes;
336  string hierarchyId;
338  bool engineInitialized { false };
339  bool logicInitialized { false };
340 };
Engine main class.
Definition: Engine.h:131
void addEntity(Entity *entity)
Adds an entity by id.
Definition: Engine.cpp:357
Entity * getEntity(const string &id)
Returns a entity by given id.
Definition: Engine.h:1175
Entity hierarchy to be used with engine class.
void update() override
Update transform.
void addEntity(Entity *entity, const string &parentId=string())
Adds a entity to the hierarchy.
Scene engine/physics connector.
static BodyHierarchy * createSubBody(World *world, Prototype *prototype, const string &id, const Transform &transform, const string &bodyHierarchyId, const string &bodyHierarchyParentId)
Create sub body in body hierarchy.
static Entity * createEntity(Prototype *prototype, const string &id, const Transform &transform, int instances=1, bool noEntityHierarchy=false)
Create engine entity.
static Body * createBody(World *world, Prototype *prototype, const string &id, const Transform &transform, uint16_t collisionTypeId=BODY_TYPEID_STANDARD, bool hierarchy=false, int index=BOUNDINGVOLUME_INDEX_NONE, PrototypePhysics_BodyType *overrideType=nullptr)
Create body.
static void addSounds(Audio *audio, Prototype *prototype, const string &id, int poolSize=1)
Add scene entity sounds into given audio instance associated with given id.
Transform which contain scale, rotations and translation.
Definition: Transform.h:29
virtual void fromMatrix(const Matrix4x4 &matrix, RotationOrder *rotationOrder)
Set up this transform from given matrix and rotation order.
Definition: Transform.cpp:22
const string & getId()
Definition: Logic.h:96
unordered_map< string, Prototype * > logicPrototypes
void updateLogic() override
Update logic.
void onLogicAdded() override
On logic added.
void updateEngine() override
Update engine.
void onLogicsProcessed() override
On logics processed.
unique_ptr< LogicMiniScript > miniScript
void handleHIDEvents(vector< GUIMouseEvent > &mouseEvents, vector< GUIKeyboardEvent > &keyEvents)
Handle HID events.
unordered_map< string, Prototype * > enginePrototypes
Representation of a 3D model.
Definition: Model.h:35
Represents rotation orders of a model.
Definition: RotationOrder.h:23
Prototype definition.
Definition: Prototype.h:55
Matrix4x4 class representing matrix4x4 mathematical structure and operations for 3d space.
Definition: Matrix4x4.h:23
Console class.
Definition: Console.h:29
#define FORBID_CLASS_COPY(CLASS)
Definition: tdme.h:6