Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ComponentManager.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2013 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "precompiled.h"
19 
20 #include "ComponentManager.h"
21 
22 #include "IComponent.h"
23 #include "ParamNode.h"
24 #include "SimContext.h"
25 
28 
29 #include "lib/utf8.h"
30 #include "ps/CLogger.h"
31 #include "ps/Filesystem.h"
32 
33 /**
34  * Used for script-only message types.
35  */
36 class CMessageScripted : public CMessage
37 {
38 public:
39  virtual int GetType() const { return mtid; }
40  virtual const char* GetScriptHandlerName() const { return handlerName.c_str(); }
41  virtual const char* GetScriptGlobalHandlerName() const { return globalHandlerName.c_str(); }
42  virtual jsval ToJSVal(ScriptInterface& UNUSED(scriptInterface)) const { return msg.get(); }
43 
44  CMessageScripted(int mtid, const std::string& name, const CScriptValRooted& msg) :
45  mtid(mtid), handlerName("On" + name), globalHandlerName("OnGlobal" + name), msg(msg)
46  {
47  }
48 
49  int mtid;
50  std::string handlerName;
51  std::string globalHandlerName;
53 };
54 
55 CComponentManager::CComponentManager(CSimContext& context, bool skipScriptFunctions) :
56  m_NextScriptComponentTypeId(CID__LastNative),
57  m_ScriptInterface("Engine", "Simulation", ScriptInterface::CreateRuntime(128*MiB)),
58  m_SimContext(context), m_CurrentlyHotloading(false)
59 {
60  context.SetComponentManager(this);
61 
62  m_ScriptInterface.SetCallbackData(static_cast<void*> (this));
63 
64  // TODO: ought to seed the RNG (in a network-synchronised way) before we use it
67 
68  // For component script tests, the test system sets up its own scripted implementation of
69  // these functions, so we skip registering them here in those cases
70  if (!skipScriptFunctions)
71  {
72  m_ScriptInterface.RegisterFunction<void, int, std::string, CScriptVal, CComponentManager::Script_RegisterComponentType> ("RegisterComponentType");
73  m_ScriptInterface.RegisterFunction<void, std::string, CComponentManager::Script_RegisterInterface> ("RegisterInterface");
74  m_ScriptInterface.RegisterFunction<void, std::string, CComponentManager::Script_RegisterMessageType> ("RegisterMessageType");
75  m_ScriptInterface.RegisterFunction<void, std::string, CScriptVal, CComponentManager::Script_RegisterGlobal> ("RegisterGlobal");
76  m_ScriptInterface.RegisterFunction<IComponent*, int, int, CComponentManager::Script_QueryInterface> ("QueryInterface");
77  m_ScriptInterface.RegisterFunction<std::vector<int>, int, CComponentManager::Script_GetEntitiesWithInterface> ("GetEntitiesWithInterface");
78  m_ScriptInterface.RegisterFunction<std::vector<IComponent*>, int, CComponentManager::Script_GetComponentsWithInterface> ("GetComponentsWithInterface");
79  m_ScriptInterface.RegisterFunction<void, int, int, CScriptVal, CComponentManager::Script_PostMessage> ("PostMessage");
80  m_ScriptInterface.RegisterFunction<void, int, CScriptVal, CComponentManager::Script_BroadcastMessage> ("BroadcastMessage");
81  m_ScriptInterface.RegisterFunction<int, std::string, CComponentManager::Script_AddEntity> ("AddEntity");
82  m_ScriptInterface.RegisterFunction<int, std::string, CComponentManager::Script_AddLocalEntity> ("AddLocalEntity");
83  m_ScriptInterface.RegisterFunction<void, int, CComponentManager::Script_DestroyEntity> ("DestroyEntity");
84  m_ScriptInterface.RegisterFunction<CScriptVal, std::wstring, CComponentManager::Script_ReadJSONFile> ("ReadJSONFile");
85  m_ScriptInterface.RegisterFunction<CScriptVal, std::wstring, CComponentManager::Script_ReadCivJSONFile> ("ReadCivJSONFile");
86  m_ScriptInterface.RegisterFunction<std::vector<std::string>, std::wstring, bool, CComponentManager::Script_FindJSONFiles> ("FindJSONFiles");
87  }
88 
89  // Define MT_*, IID_* as script globals, and store their names
90 #define MESSAGE(name) m_ScriptInterface.SetGlobal("MT_" #name, (int)MT_##name);
91 #define INTERFACE(name) \
92  m_ScriptInterface.SetGlobal("IID_" #name, (int)IID_##name); \
93  m_InterfaceIdsByName[#name] = IID_##name;
94 #define COMPONENT(name)
95 #include "simulation2/TypeList.h"
96 #undef MESSAGE
97 #undef INTERFACE
98 #undef COMPONENT
99 
100  m_ScriptInterface.SetGlobal("INVALID_ENTITY", (int)INVALID_ENTITY);
101  m_ScriptInterface.SetGlobal("SYSTEM_ENTITY", (int)SYSTEM_ENTITY);
102 
104 
105  ResetState();
106 }
107 
109 {
110  ResetState();
111 }
112 
114 {
115 #define MESSAGE(name) \
116  RegisterMessageType(MT_##name, #name);
117 #define INTERFACE(name) \
118  extern void RegisterComponentInterface_##name(ScriptInterface&); \
119  RegisterComponentInterface_##name(m_ScriptInterface);
120 #define COMPONENT(name) \
121  extern void RegisterComponentType_##name(CComponentManager&); \
122  m_CurrentComponent = CID_##name; \
123  RegisterComponentType_##name(*this);
124 
125 #include "simulation2/TypeList.h"
126 
128 
129 #undef MESSAGE
130 #undef INTERFACE
131 #undef COMPONENT
132 }
133 
134 
135 bool CComponentManager::LoadScript(const VfsPath& filename, bool hotload)
136 {
137  m_CurrentlyHotloading = hotload;
138  CVFSFile file;
139  PSRETURN loadOk = file.Load(g_VFS, filename);
140  ENSURE(loadOk == PSRETURN_OK); // TODO
141  std::string content = file.DecodeUTF8(); // assume it's UTF-8
142  bool ok = m_ScriptInterface.LoadScript(filename, content);
143  return ok;
144 }
145 
146 void CComponentManager::Script_RegisterComponentType(void* cbdata, int iid, std::string cname, CScriptVal ctor)
147 {
148  CComponentManager* componentManager = static_cast<CComponentManager*> (cbdata);
149 
150  // Find the C++ component that wraps the interface
151  int cidWrapper = componentManager->GetScriptWrapper(iid);
152  if (cidWrapper == CID__Invalid)
153  {
154  componentManager->m_ScriptInterface.ReportError("Invalid interface id");
155  return;
156  }
157  const ComponentType& ctWrapper = componentManager->m_ComponentTypesById[cidWrapper];
158 
159  bool mustReloadComponents = false; // for hotloading
160 
161  ComponentTypeId cid = componentManager->LookupCID(cname);
162  if (cid == CID__Invalid)
163  {
164  // Allocate a new cid number
165  cid = componentManager->m_NextScriptComponentTypeId++;
166  componentManager->m_ComponentTypeIdsByName[cname] = cid;
167  }
168  else
169  {
170  // Component type is already loaded, so do hotloading:
171 
172  if (!componentManager->m_CurrentlyHotloading)
173  {
174  componentManager->m_ScriptInterface.ReportError("Registering component type with already-registered name"); // TODO: report the actual name
175  return;
176  }
177 
178  const ComponentType& ctPrevious = componentManager->m_ComponentTypesById[cid];
179 
180  // We can only replace scripted component types, not native ones
181  if (ctPrevious.type != CT_Script)
182  {
183  componentManager->m_ScriptInterface.ReportError("Hotloading script component type with same name as native component");
184  return;
185  }
186 
187  // We don't support changing the IID of a component type (it would require fiddling
188  // around with m_ComponentsByInterface and being careful to guarantee uniqueness per entity)
189  if (ctPrevious.iid != iid)
190  {
191  // ...though it only matters if any components exist with this type
192  if (!componentManager->m_ComponentsByTypeId[cid].empty())
193  {
194  componentManager->m_ScriptInterface.ReportError("Hotloading script component type mustn't change interface ID");
195  return;
196  }
197  }
198 
199  // Remove the old component type's message subscriptions
200  std::map<MessageTypeId, std::vector<ComponentTypeId> >::iterator it;
201  for (it = componentManager->m_LocalMessageSubscriptions.begin(); it != componentManager->m_LocalMessageSubscriptions.end(); ++it)
202  {
203  std::vector<ComponentTypeId>& types = it->second;
204  std::vector<ComponentTypeId>::iterator ctit = find(types.begin(), types.end(), cid);
205  if (ctit != types.end())
206  types.erase(ctit);
207  }
208  for (it = componentManager->m_GlobalMessageSubscriptions.begin(); it != componentManager->m_GlobalMessageSubscriptions.end(); ++it)
209  {
210  std::vector<ComponentTypeId>& types = it->second;
211  std::vector<ComponentTypeId>::iterator ctit = find(types.begin(), types.end(), cid);
212  if (ctit != types.end())
213  types.erase(ctit);
214  }
215 
216  mustReloadComponents = true;
217  }
218 
219  std::string schema = "<empty/>";
220  {
221  CScriptValRooted prototype;
222  if (componentManager->m_ScriptInterface.GetProperty(ctor.get(), "prototype", prototype) &&
223  componentManager->m_ScriptInterface.HasProperty(prototype.get(), "Schema"))
224  {
225  componentManager->m_ScriptInterface.GetProperty(prototype.get(), "Schema", schema);
226  }
227  }
228 
229  // Construct a new ComponentType, using the wrapper's alloc functions
230  ComponentType ct = {
231  CT_Script,
232  iid,
233  ctWrapper.alloc,
234  ctWrapper.dealloc,
235  cname,
236  schema,
237  CScriptValRooted(componentManager->m_ScriptInterface.GetContext(), ctor)
238  };
239  componentManager->m_ComponentTypesById[cid] = ct;
240 
241  componentManager->m_CurrentComponent = cid; // needed by Subscribe
242 
243 
244  // Find all the ctor prototype's On* methods, and subscribe to the appropriate messages:
245 
246  CScriptVal proto;
247  if (!componentManager->m_ScriptInterface.GetProperty(ctor.get(), "prototype", proto))
248  return; // error
249 
250  std::vector<std::string> methods;
251  if (!componentManager->m_ScriptInterface.EnumeratePropertyNamesWithPrefix(proto.get(), "On", methods))
252  return; // error
253 
254  for (std::vector<std::string>::const_iterator it = methods.begin(); it != methods.end(); ++it)
255  {
256  std::string name = (*it).substr(2); // strip the "On" prefix
257 
258  // Handle "OnGlobalFoo" functions specially
259  bool isGlobal = false;
260  if (name.substr(0, 6) == "Global")
261  {
262  isGlobal = true;
263  name = name.substr(6);
264  }
265 
266  std::map<std::string, MessageTypeId>::const_iterator mit = componentManager->m_MessageTypeIdsByName.find(name);
267  if (mit == componentManager->m_MessageTypeIdsByName.end())
268  {
269  std::string msg = "Registered component has unrecognised '" + *it + "' message handler method";
270  componentManager->m_ScriptInterface.ReportError(msg.c_str());
271  return;
272  }
273 
274  if (isGlobal)
275  componentManager->SubscribeGloballyToMessageType(mit->second);
276  else
277  componentManager->SubscribeToMessageType(mit->second);
278  }
279 
280  componentManager->m_CurrentComponent = CID__Invalid;
281 
282  if (mustReloadComponents)
283  {
284  // For every script component with this cid, we need to switch its
285  // prototype from the old constructor's prototype property to the new one's
286  const std::map<entity_id_t, IComponent*>& comps = componentManager->m_ComponentsByTypeId[cid];
287  std::map<entity_id_t, IComponent*>::const_iterator eit = comps.begin();
288  for (; eit != comps.end(); ++eit)
289  {
290  jsval instance = eit->second->GetJSInstance();
291  if (!JSVAL_IS_NULL(instance))
292  componentManager->m_ScriptInterface.SetPrototype(instance, proto.get());
293  }
294  }
295 }
296 
297 void CComponentManager::Script_RegisterInterface(void* cbdata, std::string name)
298 {
299  CComponentManager* componentManager = static_cast<CComponentManager*> (cbdata);
300 
301  std::map<std::string, InterfaceId>::iterator it = componentManager->m_InterfaceIdsByName.find(name);
302  if (it != componentManager->m_InterfaceIdsByName.end())
303  {
304  // Redefinitions are fine (and just get ignored) when hotloading; otherwise
305  // they're probably unintentional and should be reported
306  if (!componentManager->m_CurrentlyHotloading)
307  componentManager->m_ScriptInterface.ReportError("Registering interface with already-registered name"); // TODO: report the actual name
308  return;
309  }
310 
311  // IIDs start at 1, so size+1 is the next unused one
312  size_t id = componentManager->m_InterfaceIdsByName.size() + 1;
313  componentManager->m_InterfaceIdsByName[name] = (InterfaceId)id;
314  componentManager->m_ComponentsByInterface.resize(id+1); // add one so we can index by InterfaceId
315  componentManager->m_ScriptInterface.SetGlobal(("IID_" + name).c_str(), (int)id);
316 }
317 
318 void CComponentManager::Script_RegisterMessageType(void* cbdata, std::string name)
319 {
320  CComponentManager* componentManager = static_cast<CComponentManager*> (cbdata);
321 
322  std::map<std::string, MessageTypeId>::iterator it = componentManager->m_MessageTypeIdsByName.find(name);
323  if (it != componentManager->m_MessageTypeIdsByName.end())
324  {
325  // Redefinitions are fine (and just get ignored) when hotloading; otherwise
326  // they're probably unintentional and should be reported
327  if (!componentManager->m_CurrentlyHotloading)
328  componentManager->m_ScriptInterface.ReportError("Registering message type with already-registered name"); // TODO: report the actual name
329  return;
330  }
331 
332  // MTIDs start at 1, so size+1 is the next unused one
333  size_t id = componentManager->m_MessageTypeIdsByName.size() + 1;
334  componentManager->RegisterMessageType((MessageTypeId)id, name.c_str());
335  componentManager->m_ScriptInterface.SetGlobal(("MT_" + name).c_str(), (int)id);
336 }
337 
338 void CComponentManager::Script_RegisterGlobal(void* cbdata, std::string name, CScriptVal value)
339 {
340  CComponentManager* componentManager = static_cast<CComponentManager*> (cbdata);
341 
342  // Set the value, and accept duplicates only if hotloading (otherwise it's an error,
343  // in order to detect accidental duplicate definitions of globals)
344  componentManager->m_ScriptInterface.SetGlobal(name.c_str(), value, componentManager->m_CurrentlyHotloading);
345 }
346 
347 IComponent* CComponentManager::Script_QueryInterface(void* cbdata, int ent, int iid)
348 {
349  CComponentManager* componentManager = static_cast<CComponentManager*> (cbdata);
350  IComponent* component = componentManager->QueryInterface((entity_id_t)ent, iid);
351  return component;
352 }
353 
354 std::vector<int> CComponentManager::Script_GetEntitiesWithInterface(void* cbdata, int iid)
355 {
356  CComponentManager* componentManager = static_cast<CComponentManager*> (cbdata);
357 
358  std::vector<int> ret;
359  const InterfaceListUnordered& ents = componentManager->GetEntitiesWithInterfaceUnordered(iid);
360  for (InterfaceListUnordered::const_iterator it = ents.begin(); it != ents.end(); ++it)
361  if (!ENTITY_IS_LOCAL(it->first))
362  ret.push_back(it->first);
363  std::sort(ret.begin(), ret.end());
364  return ret;
365 }
366 
367 std::vector<IComponent*> CComponentManager::Script_GetComponentsWithInterface(void* cbdata, int iid)
368 {
369  CComponentManager* componentManager = static_cast<CComponentManager*> (cbdata);
370 
371  std::vector<IComponent*> ret;
372  InterfaceList ents = componentManager->GetEntitiesWithInterface(iid);
373  for (InterfaceList::const_iterator it = ents.begin(); it != ents.end(); ++it)
374  ret.push_back(it->second); // TODO: maybe we should exclude local entities
375  return ret;
376 }
377 
379 {
380  if (mtid == MT__Invalid || mtid > (int)m_MessageTypeIdsByName.size()) // (IDs start at 1 so use '>' here)
381  LOGERROR(L"PostMessage with invalid message type ID '%d'", mtid);
382 
383  if (mtid < MT__LastNative)
384  {
385  return CMessageFromJSVal(mtid, m_ScriptInterface, data.get());
386  }
387  else
388  {
389  return new CMessageScripted(mtid, m_MessageTypeNamesById[mtid],
391  }
392 }
393 
394 void CComponentManager::Script_PostMessage(void* cbdata, int ent, int mtid, CScriptVal data)
395 {
396  CComponentManager* componentManager = static_cast<CComponentManager*> (cbdata);
397 
398  CMessage* msg = componentManager->ConstructMessage(mtid, data);
399  if (!msg)
400  return; // error
401 
402  componentManager->PostMessage(ent, *msg);
403 
404  delete msg;
405 }
406 
407 void CComponentManager::Script_BroadcastMessage(void* cbdata, int mtid, CScriptVal data)
408 {
409  CComponentManager* componentManager = static_cast<CComponentManager*> (cbdata);
410 
411  CMessage* msg = componentManager->ConstructMessage(mtid, data);
412  if (!msg)
413  return; // error
414 
415  componentManager->BroadcastMessage(*msg);
416 
417  delete msg;
418 }
419 
420 int CComponentManager::Script_AddEntity(void* cbdata, std::string templateName)
421 {
422  CComponentManager* componentManager = static_cast<CComponentManager*> (cbdata);
423 
424  std::wstring name(templateName.begin(), templateName.end());
425  // TODO: should validate the string to make sure it doesn't contain scary characters
426  // that will let it access non-component-template files
427 
428  entity_id_t ent = componentManager->AddEntity(name, componentManager->AllocateNewEntity());
429  return (int)ent;
430 }
431 
432 int CComponentManager::Script_AddLocalEntity(void* cbdata, std::string templateName)
433 {
434  CComponentManager* componentManager = static_cast<CComponentManager*> (cbdata);
435 
436  std::wstring name(templateName.begin(), templateName.end());
437  // TODO: should validate the string to make sure it doesn't contain scary characters
438  // that will let it access non-component-template files
439 
440  entity_id_t ent = componentManager->AddEntity(name, componentManager->AllocateNewLocalEntity());
441  return (int)ent;
442 }
443 
444 void CComponentManager::Script_DestroyEntity(void* cbdata, int ent)
445 {
446  CComponentManager* componentManager = static_cast<CComponentManager*> (cbdata);
447 
448  componentManager->DestroyComponentsSoon(ent);
449 }
450 
452 {
453  // Delete all IComponents
454  std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> >::iterator iit = m_ComponentsByTypeId.begin();
455  for (; iit != m_ComponentsByTypeId.end(); ++iit)
456  {
457  std::map<entity_id_t, IComponent*>::iterator eit = iit->second.begin();
458  for (; eit != iit->second.end(); ++eit)
459  {
460  eit->second->Deinit();
461  m_ComponentTypesById[iit->first].dealloc(eit->second);
462  }
463  }
464 
465  std::vector<boost::unordered_map<entity_id_t, IComponent*> >::iterator ifcit = m_ComponentsByInterface.begin();
466  for (; ifcit != m_ComponentsByInterface.end(); ++ifcit)
467  ifcit->clear();
468 
469  m_ComponentsByTypeId.clear();
470 
471  // Delete all SEntityComponentCaches
472  std::map<entity_id_t, SEntityComponentCache*>::iterator ccit = m_ComponentCaches.begin();
473  for (; ccit != m_ComponentCaches.end(); ++ccit)
474  free(ccit->second);
475  m_ComponentCaches.clear();
477 
478  m_DestructionQueue.clear();
479 
480  // Reset IDs
483 }
484 
486  const char* name, const std::string& schema)
487 {
488  ComponentType c = { CT_Native, iid, alloc, dealloc, name, schema, CScriptValRooted() };
489  m_ComponentTypesById.insert(std::make_pair(cid, c));
490  m_ComponentTypeIdsByName[name] = cid;
491 }
492 
494  DeallocFunc dealloc, const char* name, const std::string& schema)
495 {
496  ComponentType c = { CT_ScriptWrapper, iid, alloc, dealloc, name, schema, CScriptValRooted() };
497  m_ComponentTypesById.insert(std::make_pair(cid, c));
498  m_ComponentTypeIdsByName[name] = cid;
499  // TODO: merge with RegisterComponentType
500 }
501 
503 {
504  m_MessageTypeIdsByName[name] = mtid;
505  m_MessageTypeNamesById[mtid] = name;
506 }
507 
509 {
510  // TODO: verify mtid
512  std::vector<ComponentTypeId>& types = m_LocalMessageSubscriptions[mtid];
513  types.push_back(m_CurrentComponent);
514  std::sort(types.begin(), types.end()); // TODO: just sort once at the end of LoadComponents
515 }
516 
518 {
519  // TODO: verify mtid
521  std::vector<ComponentTypeId>& types = m_GlobalMessageSubscriptions[mtid];
522  types.push_back(m_CurrentComponent);
523  std::sort(types.begin(), types.end()); // TODO: just sort once at the end of LoadComponents
524 }
525 
527 {
528  std::map<std::string, ComponentTypeId>::const_iterator it = m_ComponentTypeIdsByName.find(cname);
529  if (it == m_ComponentTypeIdsByName.end())
530  return CID__Invalid;
531  return it->second;
532 }
533 
535 {
536  std::map<ComponentTypeId, ComponentType>::const_iterator it = m_ComponentTypesById.find(cid);
537  if (it == m_ComponentTypesById.end())
538  return "";
539  return it->second.name;
540 }
541 
543 {
544  if (iid >= IID__LastNative && iid <= (int)m_InterfaceIdsByName.size()) // use <= since IDs start at 1
545  return CID_UnknownScript;
546 
547  std::map<ComponentTypeId, ComponentType>::const_iterator it = m_ComponentTypesById.begin();
548  for (; it != m_ComponentTypesById.end(); ++it)
549  if (it->second.iid == iid && it->second.type == CT_ScriptWrapper)
550  return it->first;
551  LOGERROR(L"No script wrapper found for interface id %d", iid); // TODO: report name (if iid is valid at all)
552  return CID__Invalid;
553 }
554 
556 {
558  // TODO: check for overflow
559  return id;
560 }
561 
563 {
565  // TODO: check for overflow
566  return id;
567 }
568 
570 {
571  // TODO: ensure this ID hasn't been allocated before
572  // (this might occur with broken map files)
573  entity_id_t id = preferredId;
574 
575  // Ensure this ID won't be allocated again
576  if (id >= m_NextEntityId)
577  m_NextEntityId = id+1;
578  // TODO: check for overflow
579 
580  return id;
581 }
582 
584 {
585  IComponent* component = ConstructComponent(ent, cid);
586  if (!component)
587  return false;
588 
589  component->Init(paramNode);
590  return true;
591 }
592 
594 {
595  std::map<ComponentTypeId, ComponentType>::const_iterator it = m_ComponentTypesById.find(cid);
596  if (it == m_ComponentTypesById.end())
597  {
598  LOGERROR(L"Invalid component id %d", cid);
599  return NULL;
600  }
601 
602  const ComponentType& ct = it->second;
603 
604  ENSURE((size_t)ct.iid < m_ComponentsByInterface.size());
605 
606  boost::unordered_map<entity_id_t, IComponent*>& emap1 = m_ComponentsByInterface[ct.iid];
607  if (emap1.find(ent.GetId()) != emap1.end())
608  {
609  LOGERROR(L"Multiple components for interface %d", ct.iid);
610  return NULL;
611  }
612 
613  std::map<entity_id_t, IComponent*>& emap2 = m_ComponentsByTypeId[cid];
614 
615  // If this is a scripted component, construct the appropriate JS object first
616  jsval obj = JSVAL_NULL;
617  if (ct.type == CT_Script)
618  {
619  obj = m_ScriptInterface.CallConstructor(ct.ctor.get(), JSVAL_VOID);
620  if (JSVAL_IS_VOID(obj))
621  {
622  LOGERROR(L"Script component constructor failed");
623  return NULL;
624  }
625  }
626 
627  // Construct the new component
628  IComponent* component = ct.alloc(m_ScriptInterface, obj);
629  ENSURE(component);
630 
631  component->SetEntityHandle(ent);
632  component->SetSimContext(m_SimContext);
633 
634  // Store a reference to the new component
635  emap1.insert(std::make_pair(ent.GetId(), component));
636  emap2.insert(std::make_pair(ent.GetId(), component));
637  // TODO: We need to more careful about this - if an entity is constructed by a component
638  // while we're iterating over all components, this will invalidate the iterators and everything
639  // will break.
640  // We probably need some kind of delayed addition, so they get pushed onto a queue and then
641  // inserted into the world later on. (Be careful about immediation deletion in that case, too.)
642 
644  ENSURE(cache != NULL && ct.iid < (int)cache->numInterfaces && cache->interfaces[ct.iid] == NULL);
645  cache->interfaces[ct.iid] = component;
646 
647  return component;
648 }
649 
651 {
652  // Just add it into the by-interface map, not the by-component-type map,
653  // so it won't be considered for messages or deletion etc
654 
655  boost::unordered_map<entity_id_t, IComponent*>& emap1 = m_ComponentsByInterface.at(iid);
656  if (emap1.find(ent.GetId()) != emap1.end())
657  debug_warn(L"Multiple components for interface");
658  emap1.insert(std::make_pair(ent.GetId(), &component));
659 
661  ENSURE(cache != NULL && iid < (int)cache->numInterfaces && cache->interfaces[iid] == NULL);
662  cache->interfaces[iid] = &component;
663 }
664 
666 {
667  // Interface IDs start at 1, and SEntityComponentCache is defined with a 1-sized array,
668  // so we need space for an extra m_InterfaceIdsByName.size() items
669  SEntityComponentCache* cache = (SEntityComponentCache*)calloc(1,
670  sizeof(SEntityComponentCache) + sizeof(IComponent*) * m_InterfaceIdsByName.size());
671  ENSURE(cache != NULL);
672  cache->numInterfaces = m_InterfaceIdsByName.size() + 1;
673 
674  ENSURE(m_ComponentCaches.find(ent) == m_ComponentCaches.end());
675  m_ComponentCaches[ent] = cache;
676 
677  return CEntityHandle(ent, cache);
678 }
679 
681 {
682  std::map<entity_id_t, SEntityComponentCache*>::iterator it;
683  it = m_ComponentCaches.find(ent);
684  if (it == m_ComponentCaches.end())
685  {
686  if (allowCreate)
687  return AllocateEntityHandle(ent);
688  else
689  return CEntityHandle(ent, NULL);
690  }
691  else
692  return CEntityHandle(ent, it->second);
693 }
694 
696 {
699  m_SimContext.SetSystemEntity(m_SystemEntity);
700 }
701 
702 entity_id_t CComponentManager::AddEntity(const std::wstring& templateName, entity_id_t ent)
703 {
705  if (!cmpTemplateManager)
706  {
707  debug_warn(L"No ICmpTemplateManager loaded");
708  return INVALID_ENTITY;
709  }
710 
711  // TODO: should assert that ent doesn't exist
712 
713  const CParamNode* tmpl = cmpTemplateManager->LoadTemplate(ent, utf8_from_wstring(templateName), -1);
714  if (!tmpl)
715  return INVALID_ENTITY; // LoadTemplate will have reported the error
716 
718 
719  // Construct a component for each child of the root element
720  const CParamNode::ChildrenMap& tmplChilds = tmpl->GetChildren();
721  for (CParamNode::ChildrenMap::const_iterator it = tmplChilds.begin(); it != tmplChilds.end(); ++it)
722  {
723  // Ignore attributes on the root element
724  if (it->first.length() && it->first[0] == '@')
725  continue;
726 
728  if (cid == CID__Invalid)
729  {
730  LOGERROR(L"Unrecognised component type name '%hs' in entity template '%ls'", it->first.c_str(), templateName.c_str());
731  return INVALID_ENTITY;
732  }
733 
734  if (!AddComponent(handle, cid, it->second))
735  {
736  LOGERROR(L"Failed to construct component type name '%hs' in entity template '%ls'", it->first.c_str(), templateName.c_str());
737  return INVALID_ENTITY;
738  }
739  // TODO: maybe we should delete already-constructed components if one of them fails?
740  }
741 
742  CMessageCreate msg(ent);
743  PostMessage(ent, msg);
744 
745  return ent;
746 }
747 
749 {
750  m_DestructionQueue.push_back(ent);
751 }
752 
754 {
755  while (!m_DestructionQueue.empty())
756  {
757  // Make a copy of the destruction queue, so that the iterators won't be invalidated if the
758  // CMessageDestroy handlers try to destroy more entities themselves
759  std::vector<entity_id_t> queue;
760  queue.swap(m_DestructionQueue);
761 
762  for (std::vector<entity_id_t>::iterator it = queue.begin(); it != queue.end(); ++it)
763  {
764  entity_id_t ent = *it;
766 
767  CMessageDestroy msg(ent);
768  PostMessage(ent, msg);
769 
770  // Destroy the components, and remove from m_ComponentsByTypeId:
771  std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> >::iterator iit = m_ComponentsByTypeId.begin();
772  for (; iit != m_ComponentsByTypeId.end(); ++iit)
773  {
774  std::map<entity_id_t, IComponent*>::iterator eit = iit->second.find(ent);
775  if (eit != iit->second.end())
776  {
777  eit->second->Deinit();
778  m_ComponentTypesById[iit->first].dealloc(eit->second);
779  iit->second.erase(ent);
780  handle.GetComponentCache()->interfaces[m_ComponentTypesById[iit->first].iid] = NULL;
781  }
782  }
783 
784  free(handle.GetComponentCache());
785  m_ComponentCaches.erase(ent);
786 
787  // Remove from m_ComponentsByInterface
788  std::vector<boost::unordered_map<entity_id_t, IComponent*> >::iterator ifcit = m_ComponentsByInterface.begin();
789  for (; ifcit != m_ComponentsByInterface.end(); ++ifcit)
790  {
791  ifcit->erase(ent);
792  }
793  }
794  }
795 }
796 
798 {
799  if ((size_t)iid >= m_ComponentsByInterface.size())
800  {
801  // Invalid iid
802  return NULL;
803  }
804 
805  boost::unordered_map<entity_id_t, IComponent*>::const_iterator eit = m_ComponentsByInterface[iid].find(ent);
806  if (eit == m_ComponentsByInterface[iid].end())
807  {
808  // This entity doesn't implement this interface
809  return NULL;
810  }
811 
812  return eit->second;
813 }
814 
816 {
817  std::vector<std::pair<entity_id_t, IComponent*> > ret;
818 
819  if ((size_t)iid >= m_ComponentsByInterface.size())
820  {
821  // Invalid iid
822  return ret;
823  }
824 
825  ret.reserve(m_ComponentsByInterface[iid].size());
826 
827  boost::unordered_map<entity_id_t, IComponent*>::const_iterator it = m_ComponentsByInterface[iid].begin();
828  for (; it != m_ComponentsByInterface[iid].end(); ++it)
829  ret.push_back(*it);
830 
831  std::sort(ret.begin(), ret.end()); // lexicographic pair comparison means this'll sort by entity ID
832 
833  return ret;
834 }
835 
838 {
839  if ((size_t)iid >= m_ComponentsByInterface.size())
840  {
841  // Invalid iid
842  return g_EmptyEntityMap;
843  }
844 
845  return m_ComponentsByInterface[iid];
846 }
847 
849 {
850  // Send the message to components of ent, that subscribed locally to this message
851  std::map<MessageTypeId, std::vector<ComponentTypeId> >::const_iterator it;
852  it = m_LocalMessageSubscriptions.find(msg.GetType());
853  if (it != m_LocalMessageSubscriptions.end())
854  {
855  std::vector<ComponentTypeId>::const_iterator ctit = it->second.begin();
856  for (; ctit != it->second.end(); ++ctit)
857  {
858  // Find the component instances of this type (if any)
859  std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> >::const_iterator emap = m_ComponentsByTypeId.find(*ctit);
860  if (emap == m_ComponentsByTypeId.end())
861  continue;
862 
863  // Send the message to all of them
864  std::map<entity_id_t, IComponent*>::const_iterator eit = emap->second.find(ent);
865  if (eit != emap->second.end())
866  eit->second->HandleMessage(msg, false);
867  }
868  }
869 
870  SendGlobalMessage(ent, msg);
871 }
872 
874 {
875  // Send the message to components of all entities that subscribed locally to this message
876  std::map<MessageTypeId, std::vector<ComponentTypeId> >::const_iterator it;
877  it = m_LocalMessageSubscriptions.find(msg.GetType());
878  if (it != m_LocalMessageSubscriptions.end())
879  {
880  std::vector<ComponentTypeId>::const_iterator ctit = it->second.begin();
881  for (; ctit != it->second.end(); ++ctit)
882  {
883  // Find the component instances of this type (if any)
884  std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> >::const_iterator emap = m_ComponentsByTypeId.find(*ctit);
885  if (emap == m_ComponentsByTypeId.end())
886  continue;
887 
888  // Send the message to all of them
889  std::map<entity_id_t, IComponent*>::const_iterator eit = emap->second.begin();
890  for (; eit != emap->second.end(); ++eit)
891  eit->second->HandleMessage(msg, false);
892  }
893  }
894 
896 }
897 
899 {
900  // (Common functionality for PostMessage and BroadcastMessage)
901 
902  // Send the message to components of all entities that subscribed globally to this message
903  std::map<MessageTypeId, std::vector<ComponentTypeId> >::const_iterator it;
904  it = m_GlobalMessageSubscriptions.find(msg.GetType());
905  if (it != m_GlobalMessageSubscriptions.end())
906  {
907  std::vector<ComponentTypeId>::const_iterator ctit = it->second.begin();
908  for (; ctit != it->second.end(); ++ctit)
909  {
910  // Special case: Messages for non-local entities shouldn't be sent to script
911  // components that subscribed globally, so that we don't have to worry about
912  // them accidentally picking up non-network-synchronised data.
913  if (ENTITY_IS_LOCAL(ent))
914  {
915  std::map<ComponentTypeId, ComponentType>::const_iterator it = m_ComponentTypesById.find(*ctit);
916  if (it != m_ComponentTypesById.end() && it->second.type == CT_Script)
917  continue;
918  }
919 
920  // Find the component instances of this type (if any)
921  std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> >::const_iterator emap = m_ComponentsByTypeId.find(*ctit);
922  if (emap == m_ComponentsByTypeId.end())
923  continue;
924 
925  // Send the message to all of them
926  std::map<entity_id_t, IComponent*>::const_iterator eit = emap->second.begin();
927  for (; eit != emap->second.end(); ++eit)
928  eit->second->HandleMessage(msg, true);
929  }
930  }
931 }
932 
933 
935 {
936  std::string schema =
937  "<grammar xmlns='http://relaxng.org/ns/structure/1.0' xmlns:a='http://ns.wildfiregames.com/entity' datatypeLibrary='http://www.w3.org/2001/XMLSchema-datatypes'>"
938  "<define name='nonNegativeDecimal'>"
939  "<data type='decimal'><param name='minInclusive'>0</param></data>"
940  "</define>"
941  "<define name='positiveDecimal'>"
942  "<data type='decimal'><param name='minExclusive'>0</param></data>"
943  "</define>"
944  "<define name='anything'>"
945  "<zeroOrMore>"
946  "<choice>"
947  "<attribute><anyName/></attribute>"
948  "<text/>"
949  "<element>"
950  "<anyName/>"
951  "<ref name='anything'/>"
952  "</element>"
953  "</choice>"
954  "</zeroOrMore>"
955  "</define>";
956 
957  std::map<InterfaceId, std::vector<std::string> > interfaceComponentTypes;
958 
959  std::vector<std::string> componentTypes;
960 
961  for (std::map<ComponentTypeId, ComponentType>::const_iterator it = m_ComponentTypesById.begin(); it != m_ComponentTypesById.end(); ++it)
962  {
963  schema +=
964  "<define name='component." + it->second.name + "'>"
965  "<element name='" + it->second.name + "'>"
966  "<interleave>" + it->second.schema + "</interleave>"
967  "</element>"
968  "</define>";
969 
970  interfaceComponentTypes[it->second.iid].push_back(it->second.name);
971  componentTypes.push_back(it->second.name);
972  }
973 
974  // Declare the implementation of each interface, for documentation
975  for (std::map<std::string, InterfaceId>::const_iterator it = m_InterfaceIdsByName.begin(); it != m_InterfaceIdsByName.end(); ++it)
976  {
977  schema += "<define name='interface." + it->first + "'><choice>";
978  std::vector<std::string>& cts = interfaceComponentTypes[it->second];
979  for (size_t i = 0; i < cts.size(); ++i)
980  schema += "<ref name='component." + cts[i] + "'/>";
981  schema += "</choice></define>";
982  }
983 
984  // List all the component types, in alphabetical order (to match the reordering performed by CParamNode).
985  // (We do it this way, rather than <interleave>ing all the interface definitions (which would additionally perform
986  // a check that we don't use multiple component types of the same interface in one file), because libxml2 gives
987  // useless error messages in the latter case; this way lets it report the real error.)
988  std::sort(componentTypes.begin(), componentTypes.end());
989  schema +=
990  "<start>"
991  "<element name='Entity'>"
992  "<optional><attribute name='parent'/></optional>";
993  for (std::vector<std::string>::const_iterator it = componentTypes.begin(); it != componentTypes.end(); ++it)
994  schema += "<optional><ref name='component." + *it + "'/></optional>";
995  schema +=
996  "</element>"
997  "</start>";
998 
999  schema += "</grammar>";
1000 
1001  return schema;
1002 }
1003 
1004 CScriptVal CComponentManager::Script_ReadJSONFile(void* cbdata, std::wstring fileName)
1005 {
1006  return ReadJSONFile(cbdata, L"simulation/data", fileName);
1007 }
1008 
1009 CScriptVal CComponentManager::Script_ReadCivJSONFile(void* cbdata, std::wstring fileName)
1010 {
1011  return ReadJSONFile(cbdata, L"civs", fileName);
1012 }
1013 
1014 CScriptVal CComponentManager::ReadJSONFile(void* cbdata, std::wstring filePath, std::wstring fileName)
1015 {
1016  CComponentManager* componentManager = static_cast<CComponentManager*> (cbdata);
1017 
1018  VfsPath path = VfsPath(filePath) / fileName;
1019 
1020  return componentManager->GetScriptInterface().ReadJSONFile(path).get();
1021 }
1022 
1023 Status CComponentManager::FindJSONFilesCallback(const VfsPath& pathname, const CFileInfo& UNUSED(fileInfo), const uintptr_t cbData)
1024 {
1026 
1027  VfsPath pathstem = pathname.ChangeExtension(L"");
1028  // Strip the root from the path
1029  std::wstring name = pathstem.string().substr(data->path.string().length());
1030 
1031  data->templates.push_back(std::string(name.begin(), name.end()));
1032 
1033  return INFO::OK;
1034 }
1035 
1036 std::vector<std::string> CComponentManager::Script_FindJSONFiles(void* UNUSED(cbdata), std::wstring subPath, bool recursive)
1037 {
1039  cbData.path = VfsPath(L"simulation/data/" + subPath + L"/");
1040 
1041  int dir_flags = 0;
1042  if (recursive) {
1043  dir_flags = vfs::DIR_RECURSIVE;
1044  }
1045 
1046  // Find all simulation/data/{subPath}/*.json recursively
1047  Status ret = vfs::ForEachFile(g_VFS, cbData.path, FindJSONFilesCallback, (uintptr_t)&cbData, L"*.json", dir_flags);
1048  if (ret != INFO::OK)
1049  {
1050  // Some error reading directory
1051  wchar_t error[200];
1052  LOGERROR(L"Error reading directory '%ls': %ls", cbData.path.string().c_str(), StatusDescription(ret, error, ARRAY_SIZE(error)));
1053  }
1054 
1055  return cbData.templates;
1056 }
bool SetPrototype(jsval obj, jsval proto)
An entity initialisation parameter node.
Definition: ParamNode.h:112
static CScriptVal Script_ReadCivJSONFile(void *cbdata, std::wstring fileName)
IComponent * interfaces[1]
Definition: Entity.h:66
void SubscribeToMessageType(MessageTypeId mtid)
Subscribe the current component type to the given message type.
size_t numInterfaces
Definition: Entity.h:65
CStr DecodeUTF8() const
Returns contents of a UTF-8 encoded file as a string with optional BOM removed.
Definition: Filesystem.cpp:153
bool ReplaceNondeterministicRNG(boost::rand48 &rng)
Replace the default JS random number geenrator with a seeded, network-sync&#39;d one. ...
void FlushDestroyedComponents()
Does the actual destruction of components from DestroyComponentsSoon.
std::map< MessageTypeId, std::vector< ComponentTypeId > > m_GlobalMessageSubscriptions
void ResetState()
Resets the dynamic simulation state (deletes all entities, resets entity ID counters; doesn&#39;t unload/...
This is sent immediately after a new entity&#39;s components have all been created and initialised...
Definition: MessageTypes.h:191
std::vector< std::pair< entity_id_t, IComponent * > > InterfaceList
#define UNUSED(param)
mark a function parameter as unused and avoid the corresponding compiler warning. ...
void AddMockComponent(CEntityHandle ent, InterfaceId iid, IComponent &component)
Adds an externally-created component, so that it is returned by QueryInterface but does not get destr...
Path VfsPath
VFS path of the form &quot;(dir/)*file?&quot;.
Definition: vfs_path.h:40
static CScriptVal ReadJSONFile(void *cbdata, std::wstring filePath, std::wstring fileName)
entity_id_t AddEntity(const std::wstring &templateName, entity_id_t ent)
Constructs an entity based on the given template, and adds it the world with entity ID ent...
const Status OK
Definition: status.h:386
#define LOGERROR
Definition: CLogger.h:35
std::vector< boost::unordered_map< entity_id_t, IComponent * > > m_ComponentsByInterface
bool HasProperty(jsval obj, const char *name)
Check the named property has been defined on the given object.
void SetCallbackData(void *cbdata)
std::string handlerName
void(* DeallocFunc)(IComponent *)
const PSRETURN PSRETURN_OK
Definition: Errors.h:103
#define ENTITY_IS_LOCAL(id)
Definition: Entity.h:60
static CComponentManager::InterfaceListUnordered g_EmptyEntityMap
Reads a file, then gives read-only access to the contents.
Definition: Filesystem.h:69
static void Script_PostMessage(void *cbdata, int ent, int mtid, CScriptVal data)
std::string utf8_from_wstring(const std::wstring &src, Status *err)
opposite of wstring_from_utf8
Definition: utf8.cpp:208
entity_id_t m_NextLocalEntityId
IComponent *(* AllocFunc)(ScriptInterface &scriptInterface, jsval ctor)
virtual void Init(const CParamNode &paramNode)=0
IComponent * QueryInterface(entity_id_t ent, InterfaceId iid) const
std::string globalHandlerName
Object wrapping an entity_id_t, with a SEntityComponentCache to support fast QueryInterface() / CmpPt...
Definition: Entity.h:80
ScriptInterface & GetScriptInterface()
const jsval & get() const
Returns the current value.
Definition: ScriptVal.h:38
CSimContext & m_SimContext
A trivial wrapper around a jsval.
Definition: ScriptVal.h:29
bool LoadScript(const VfsPath &filename, const std::string &code)
Load and execute the given script in a new function scope.
const ChildrenMap & GetChildren() const
Returns the names/nodes of the children of this node, ordered by name.
Definition: ParamNode.cpp:244
bool LoadGlobalScripts()
Load global scripts that most script contexts need, located in the /globalscripts directory...
Contains pointers to various &#39;global&#39; objects that are needed by the simulation code, to allow easy access without using real (evil) global variables.
Definition: SimContext.h:32
std::map< std::string, MessageTypeId > m_MessageTypeIdsByName
Used for script-only message types.
entity_id_t m_NextEntityId
const entity_id_t SYSTEM_ENTITY
Entity ID for singleton &#39;system&#39; components.
Definition: Entity.h:44
#define ARRAY_SIZE(name)
void RegisterMessageType(MessageTypeId mtid, const char *name)
const entity_id_t FIRST_LOCAL_ENTITY
Definition: Entity.h:61
CEntityHandle LookupEntityHandle(entity_id_t ent, bool allowCreate=false)
Returns a CEntityHandle with id ent.
boost::rand48 m_RNG
const InterfaceListUnordered & GetEntitiesWithInterfaceUnordered(InterfaceId iid) const
static std::vector< IComponent * > Script_GetComponentsWithInterface(void *cbdata, int iid)
#define ENSURE(expr)
ensure the expression &lt;expr&gt; evaluates to non-zero.
Definition: debug.h:282
std::map< std::string, ComponentTypeId > m_ComponentTypeIdsByName
CScriptValRooted msg
virtual int GetType() const =0
InterfaceList GetEntitiesWithInterface(InterfaceId iid) const
std::map< ComponentTypeId, std::map< entity_id_t, IComponent * > > m_ComponentsByTypeId
CMessage * ConstructMessage(int mtid, CScriptVal data)
static Status FindJSONFilesCallback(const VfsPath &, const CFileInfo &, const uintptr_t)
static void Script_RegisterComponentType(void *cbdata, int iid, std::string cname, CScriptVal ctor)
u32 PSRETURN
Definition: Errors.h:75
Definition: path.h:75
This is sent immediately before a destroyed entity is flushed and really destroyed.
Definition: MessageTypes.h:211
CScriptValRooted ReadJSONFile(const VfsPath &path)
Read a JSON file.
const String & string() const
Definition: path.h:123
std::map< std::string, InterfaceId > m_InterfaceIdsByName
CMessageScripted(int mtid, const std::string &name, const CScriptValRooted &msg)
static const size_t MiB
Definition: alignment.h:72
CEntityHandle AllocateEntityHandle(entity_id_t ent)
ScriptInterface m_ScriptInterface
void RegisterComponentType(InterfaceId, ComponentTypeId, AllocFunc, DeallocFunc, const char *, const std::string &schema)
std::map< MessageTypeId, std::string > m_MessageTypeNamesById
entity_id_t GetId() const
Definition: Entity.h:89
static std::vector< int > Script_GetEntitiesWithInterface(void *cbdata, int iid)
i64 Status
Error handling system.
Definition: status.h:171
CComponentManager(CSimContext &, bool skipScriptFunctions=false)
void SetEntityHandle(CEntityHandle ent)
Definition: IComponent.h:46
void InitSystemEntity()
Set up an empty SYSTEM_ENTITY.
void SubscribeGloballyToMessageType(MessageTypeId mtid)
Subscribe the current component type to all messages of the given message type.
entity_id_t AllocateNewLocalEntity()
Returns a new local entity ID that has never been used before.
static void Script_RegisterGlobal(void *cbdata, std::string name, CScriptVal value)
bool GetProperty(jsval obj, const char *name, T &out)
Get the named property on the given object.
std::string LookupComponentTypeName(ComponentTypeId cid) const
void PostMessage(entity_id_t ent, const CMessage &msg) const
Send a message, targeted at a particular entity.
CMessage * CMessageFromJSVal(int mtid, ScriptInterface &scriptingInterface, jsval val)
bool AddComponent(CEntityHandle ent, ComponentTypeId cid, const CParamNode &paramNode)
Constructs a component of type &#39;cid&#39;, initialised with data &#39;paramNode&#39;, and attaches it to entity &#39;e...
bool LoadScript(const VfsPath &filename, bool hotload=false)
Load a script and execute it in a new function scope.
virtual const char * GetScriptHandlerName() const
static CScriptVal Script_ReadJSONFile(void *cbdata, std::wstring fileName)
ComponentTypeId m_CurrentComponent
ComponentTypeId m_NextScriptComponentTypeId
std::map< MessageTypeId, std::vector< ComponentTypeId > > m_LocalMessageSubscriptions
IComponent * ConstructComponent(CEntityHandle ent, ComponentTypeId cid)
Allocates a component object of type &#39;cid&#39;, and attaches it to entity &#39;ent&#39;.
Path ChangeExtension(Path extension) const
Definition: path.h:185
Template manager: Handles the loading of entity template files for the initialisation and deserializa...
void SetSystemEntity(CEntityHandle ent)
Definition: SimContext.h:48
virtual const char * GetScriptGlobalHandlerName() const
void RegisterComponentTypeScriptWrapper(InterfaceId, ComponentTypeId, AllocFunc, DeallocFunc, const char *, const std::string &schema)
Status ForEachFile(const PIVFS &fs, const VfsPath &startPath, FileCallback cb, uintptr_t cbData, const wchar_t *pattern, size_t flags)
call back for each file in a directory tree
Definition: vfs_util.cpp:58
PSRETURN Load(const PIVFS &vfs, const VfsPath &filename)
Returns either PSRETURN_OK or PSRETURN_CVFSFile_LoadFailed.
Definition: Filesystem.cpp:117
std::vector< entity_id_t > m_DestructionQueue
wchar_t * StatusDescription(Status status, wchar_t *buf, size_t max_chars)
generate textual description of a Status.
Definition: status.cpp:79
jsval CallConstructor(jsval ctor, jsval arg)
Call a constructor function, equivalent to JS &quot;new ctor(arg)&quot;.
bool SetGlobal(const char *name, const T &value, bool replace=false)
Set the named property on the global object.
void BroadcastMessage(const CMessage &msg) const
Send a message, not targeted at any particular entity.
virtual jsval ToJSVal(ScriptInterface &scriptInterface) const
ComponentTypeId LookupCID(const std::string &cname) const
static std::vector< std::string > Script_FindJSONFiles(void *cbdata, std::wstring subPath, bool recursive)
virtual const CParamNode * LoadTemplate(entity_id_t ent, const std::string &templateName, int playerID)=0
Loads the template XML file identified by &#39;templateName&#39; (including inheritance from parent XML files...
JSBool error(JSContext *cx, uintN argc, jsval *vp)
std::map< entity_id_t, SEntityComponentCache * > m_ComponentCaches
std::string GenerateSchema()
std::map< ComponentTypeId, ComponentType > m_ComponentTypesById
jsval get() const
Returns the current value (or JSVAL_VOID if uninitialised).
Definition: ScriptVal.cpp:45
boost::unordered_map< entity_id_t, IComponent * > InterfaceListUnordered
static void Script_DestroyEntity(void *cbdata, int ent)
static Handle handle(size_t idx, u64 tag)
Definition: h_mgr.cpp:121
Abstraction around a SpiderMonkey JSContext.
#define debug_warn(expr)
display the error dialog with the given text.
Definition: debug.h:324
void DestroyComponentsSoon(entity_id_t ent)
Destroys all the components belonging to the specified entity when FlushDestroyedComponents is called...
void SetComponentManager(CComponentManager *man)
Definition: SimContext.cpp:57
static void Script_BroadcastMessage(void *cbdata, int mtid, CScriptVal data)
static void Script_RegisterMessageType(void *cbdata, std::string name)
const entity_id_t INVALID_ENTITY
Invalid entity ID.
Definition: Entity.h:36
PIVFS g_VFS
Definition: Filesystem.cpp:30
static IComponent * Script_QueryInterface(void *cbdata, int ent, int iid)
u32 entity_id_t
Entity ID type.
Definition: Entity.h:24
static int Script_AddLocalEntity(void *cbdata, std::string templateName)
static void Script_RegisterInterface(void *cbdata, std::string name)
bool EnumeratePropertyNamesWithPrefix(jsval obj, const char *prefix, std::vector< std::string > &out)
void SetSimContext(const CSimContext &context)
Definition: IComponent.h:53
std::map< std::string, CParamNode > ChildrenMap
Definition: ParamNode.h:115
JSContext * GetContext() const
CEntityHandle m_SystemEntity
static int Script_AddEntity(void *cbdata, std::string templateName)
void ReportError(const char *msg)
Report the given error message through the JS error reporting mechanism, and throw a JS exception...
void SendGlobalMessage(entity_id_t ent, const CMessage &msg) const
ComponentTypeId GetScriptWrapper(InterfaceId iid)
SEntityComponentCache * GetComponentCache() const
Definition: Entity.h:90
virtual int GetType() const
entity_id_t AllocateNewEntity()
Returns a new entity ID that has never been used before.