ext_02.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. #include "stdafx.h"
  2. #include <iostream>
  3. #include "gmThread.h"
  4. #include <vector>
  5. #include <string>
  6. #include <sstream>
  7. struct ScriptEntity;
  8. struct Entity;
  9. struct Entity
  10. {
  11. Entity() : Id(0), X(0), Y(0), ScriptObject(NULL) { }
  12. Entity(int id) : Id(id), X(0), Y(0), ScriptObject(NULL) { }
  13. int Id, X, Y;
  14. ScriptEntity *ScriptObject;
  15. };
  16. struct ScriptEntity
  17. {
  18. ScriptEntity(Entity &ent) : EntityObject(ent), ScriptProperties(NULL) { }
  19. Entity &EntityObject;
  20. gmTableObject *ScriptProperties;
  21. };
  22. class EntityManager
  23. {
  24. public:
  25. EntityManager() : _EntityIds(0) { }
  26. Entity &CreateEntity(int &a_entityid)
  27. {
  28. Entity e(++_EntityIds);
  29. a_entityid = e.Id;
  30. _Entities.push_back(e);
  31. return _Entities[a_entityid - 1];
  32. }
  33. Entity &GetEntity(int a_entityid)
  34. {
  35. return _Entities[a_entityid - 1];
  36. }
  37. protected:
  38. typedef std::vector<Entity> EntityList;
  39. typedef EntityList::iterator EntityListItr;
  40. EntityList _Entities;
  41. int _EntityIds;
  42. };
  43. //// Global entity manager
  44. static EntityManager s_EntityManager;
  45. namespace gmEntityLib
  46. {
  47. gmType s_entitytype = GM_NULL;
  48. gmStringObject *s_xprop = NULL;
  49. gmStringObject *s_yprop = NULL;
  50. gmStringObject *s_idprop = NULL;
  51. gmMemFixed s_scriptents( sizeof(ScriptEntity) );
  52. // The entity is passed as this
  53. int GM_CDECL gmEntityInfo(gmThread *a_thread)
  54. {
  55. ScriptEntity *sent = reinterpret_cast<ScriptEntity*>(a_thread->ThisUserCheckType(s_entitytype));
  56. if (sent == NULL)
  57. {
  58. a_thread->GetMachine()->GetLog().LogEntry("gmEntityInfo: Expected entity type as this");
  59. return GM_EXCEPTION;
  60. }
  61. std::stringstream infotext;
  62. infotext << "EntityId: ";
  63. infotext << sent->EntityObject.Id;
  64. infotext << " - Postition("; infotext << sent->EntityObject.X; infotext << ","; infotext << sent->EntityObject.Y; infotext << ") - Name: ";
  65. // Get name from table and pass to object
  66. gmVariable namevar = sent->ScriptProperties->Get(a_thread->GetMachine(), "name");
  67. if (namevar.IsNull() || namevar.m_type != GM_STRING)
  68. {
  69. infotext << " [No name]";
  70. }
  71. else
  72. {
  73. infotext << namevar.GetStringObjectSafe()->GetString();
  74. }
  75. std::cout << infotext.str() << std::endl;
  76. return GM_OK;
  77. }
  78. int GM_CDECL gmCreateEntity(gmThread *a_thread)
  79. {
  80. // Create an entity from the manager
  81. int entityId = 0;
  82. Entity &ent = s_EntityManager.CreateEntity(entityId);
  83. // Allocate a script entity & construct it
  84. ScriptEntity *sent = reinterpret_cast<ScriptEntity*>(s_scriptents.Alloc());
  85. GM_PLACEMENT_NEW( ScriptEntity(ent), sent );
  86. // Tie back to entity
  87. ent.ScriptObject = sent;
  88. // Create a property table
  89. sent->ScriptProperties = a_thread->GetMachine()->AllocTableObject();
  90. // Tell GM how much memory we're using
  91. int memadjust = sizeof(gmTableObject) + sizeof(Entity) + sizeof(ScriptEntity);
  92. a_thread->GetMachine()->AdjustKnownMemoryUsed(memadjust);
  93. // Bind an additional method to the entity's prop table
  94. sent->ScriptProperties->Set(a_thread->GetMachine(), "ShowInfo", gmVariable( a_thread->GetMachine()->AllocFunctionObject(gmEntityInfo) ) );
  95. // return to client
  96. a_thread->PushNewUser( sent, s_entitytype );
  97. return GM_OK;
  98. }
  99. //// Dot Operators
  100. void GM_CDECL gmOpGetDot(gmThread *a_thread, gmVariable *a_operands)
  101. {
  102. if (a_operands[0].m_type != s_entitytype)
  103. {
  104. a_thread->GetMachine()->GetLog().LogEntry( "gmEntity:OpSetDot invalid type passed" );
  105. a_operands[0] = gmVariable::s_null;
  106. return;
  107. }
  108. // Get scriptentity back
  109. ScriptEntity *sent = reinterpret_cast<ScriptEntity*>(a_operands[0].GetUserSafe(s_entitytype));
  110. gmStringObject *p = a_operands[1].GetStringObjectSafe();
  111. // Test for our known properties and return their values back immediately
  112. if (p == s_xprop)
  113. {
  114. a_operands[0] = gmVariable(sent->EntityObject.X);
  115. }
  116. else if(p == s_yprop)
  117. {
  118. a_operands[0] = gmVariable(sent->EntityObject.Y);
  119. }
  120. else if (p == s_idprop)
  121. {
  122. a_operands[0] = gmVariable(sent->EntityObject.Id);
  123. }
  124. else
  125. {
  126. // Otherwise, return the value from the table!
  127. a_operands[0] = sent->ScriptProperties->Get(gmVariable(p));
  128. }
  129. }
  130. void GM_CDECL gmOpSetDot(gmThread *a_thread, gmVariable *a_operands)
  131. {
  132. if (a_operands[0].m_type != s_entitytype)
  133. {
  134. a_thread->GetMachine()->GetLog().LogEntry( "gmEntity:OpSetDot invalid type passed" );
  135. a_operands[0] = gmVariable::s_null;
  136. return;
  137. }
  138. // Get scriptentity back
  139. ScriptEntity *sent = reinterpret_cast<ScriptEntity*>(a_operands[0].GetUserSafe(s_entitytype));
  140. // Get name of 'get' prop
  141. gmStringObject *p = a_operands[2].GetStringObjectSafe();
  142. if (p == NULL)
  143. {
  144. a_thread->GetMachine()->GetLog().LogEntry( "gmEntity:OpSetDot invalid property passed" );
  145. a_operands[0] = gmVariable::s_null;
  146. return;
  147. }
  148. // Test for our known properties and return their values back immediately
  149. if (p == s_xprop)
  150. {
  151. sent->EntityObject.X = a_operands[1].GetIntSafe();
  152. }
  153. else if (p == s_yprop)
  154. {
  155. sent->EntityObject.Y = a_operands[1].GetIntSafe();
  156. }
  157. else if (p == s_idprop)
  158. {
  159. a_thread->GetMachine()->GetLog().LogEntry( "gmEntity:OpSetDot cannot set Id" );
  160. a_operands[0] = gmVariable::s_null;
  161. }
  162. else
  163. {
  164. // Otherwise, store a value in the table
  165. sent->ScriptProperties->Set(a_thread->GetMachine(), gmVariable(p), a_operands[1]);
  166. }
  167. }
  168. ///////////////
  169. // GC operations
  170. void GM_CDECL gcDestruct(gmMachine *a_machine, gmUserObject *a_object)
  171. {
  172. GM_ASSERT( a_object->m_userType == s_entitytype );
  173. ScriptEntity *sent = reinterpret_cast<ScriptEntity *>(a_object->m_user);
  174. // Do we want to tell the entitymanager to destry the object here?
  175. // this will be implementation dependent, so let's not do anything for now as it's a sample
  176. // Free up the script entity
  177. s_scriptents.Free(sent);
  178. int memadjust = sizeof(gmTableObject) + sizeof(ScriptEntity); // Note, didn;t add Entity sizeof
  179. a_machine->AdjustKnownMemoryUsed(-memadjust);
  180. }
  181. bool GM_CDECL gcTrace(gmMachine *a_machine, gmUserObject *a_object, gmGarbageCollector *a_gc, const int a_workLeftToGo, int &a_workDone)
  182. {
  183. GM_ASSERT( a_object->m_userType == s_entitytype );
  184. ScriptEntity *sent = reinterpret_cast<ScriptEntity *>(a_object->m_user);
  185. a_workDone++;
  186. a_gc->GetNextObject(sent->ScriptProperties);
  187. a_workDone++;
  188. return true;
  189. }
  190. gmFunctionEntry s_lib[] = {
  191. { "createEntity", gmCreateEntity, NULL }
  192. };
  193. void Bind(gmMachine *a_machine)
  194. {
  195. s_entitytype = a_machine->CreateUserType("entity");
  196. // Register creation function
  197. a_machine->RegisterLibrary( s_lib, sizeof(s_lib) / sizeof(gmFunctionEntry) );
  198. a_machine->RegisterTypeOperator( s_entitytype, O_GETDOT, NULL, gmOpGetDot );
  199. a_machine->RegisterTypeOperator( s_entitytype, O_SETDOT, NULL, gmOpSetDot );
  200. // Register GC callbacks
  201. a_machine->RegisterUserCallbacks( s_entitytype, gcTrace, gcDestruct, NULL );
  202. // Allocate permanent strings
  203. s_xprop = a_machine->AllocPermanantStringObject("X");
  204. s_yprop = a_machine->AllocPermanantStringObject("Y");
  205. s_idprop = a_machine->AllocPermanantStringObject("Id");
  206. }
  207. };
  208. int main(int argc, char* argv[])
  209. {
  210. // Create gm virtual machine
  211. gmMachine gm;
  212. gmEntityLib::Bind(&gm);
  213. gm.ExecuteString(
  214. "ent = createEntity();"
  215. "ent.X = 100;"
  216. "print(ent.Id);"
  217. "ent.name = \"somebody\";"
  218. "ent.sayname = function() { print( \"My name is: \", .name ); };"
  219. "ent.sayname();"
  220. "ent.ShowInfo();"
  221. );
  222. return 0;
  223. }