ScriptInstance.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851
  1. //
  2. // Copyright (c) 2008-2013 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "Precompiled.h"
  23. #include "Context.h"
  24. #include "Log.h"
  25. #include "MemoryBuffer.h"
  26. #include "PhysicsEvents.h"
  27. #include "PhysicsWorld.h"
  28. #include "Profiler.h"
  29. #include "ResourceCache.h"
  30. #include "ResourceEvents.h"
  31. #include "Scene.h"
  32. #include "SceneEvents.h"
  33. #include "Script.h"
  34. #include "ScriptFile.h"
  35. #include "ScriptInstance.h"
  36. #include <angelscript.h>
  37. #include "DebugNew.h"
  38. namespace Urho3D
  39. {
  40. static const char* methodDeclarations[] = {
  41. "void Start()",
  42. "void Stop()",
  43. "void DelayedStart()",
  44. "void Update(float)",
  45. "void PostUpdate(float)",
  46. "void FixedUpdate(float)",
  47. "void FixedPostUpdate(float)",
  48. "void Load(Deserializer&)",
  49. "void Save(Serializer&)",
  50. "void ReadNetworkUpdate(Deserializer&)",
  51. "void WriteNetworkUpdate(Serializer&)",
  52. "void ApplyAttributes()"
  53. };
  54. extern const char* UI_CATEGORY;
  55. ScriptInstance::ScriptInstance(Context* context) :
  56. Component(context),
  57. script_(GetSubsystem<Script>()),
  58. scriptObject_(0),
  59. fixedUpdateFps_(0),
  60. fixedUpdateInterval_(0.0f),
  61. fixedUpdateAcc_(0.0f),
  62. fixedPostUpdateAcc_(0.0f),
  63. subscribed_(false),
  64. subscribedPostFixed_(false)
  65. {
  66. ClearScriptMethods();
  67. ClearScriptAttributes();
  68. }
  69. ScriptInstance::~ScriptInstance()
  70. {
  71. ReleaseObject();
  72. }
  73. void ScriptInstance::RegisterObject(Context* context)
  74. {
  75. context->RegisterFactory<ScriptInstance>(LOGIC_CATEGORY);
  76. ACCESSOR_ATTRIBUTE(ScriptInstance, VAR_BOOL, "Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
  77. ACCESSOR_ATTRIBUTE(ScriptInstance, VAR_RESOURCEREF, "Script File", GetScriptFileAttr, SetScriptFileAttr, ResourceRef, ResourceRef(ScriptFile::GetTypeStatic()), AM_DEFAULT);
  78. REF_ACCESSOR_ATTRIBUTE(ScriptInstance, VAR_STRING, "Class Name", GetClassName, SetClassName, String, String::EMPTY, AM_DEFAULT);
  79. ACCESSOR_ATTRIBUTE(ScriptInstance, VAR_INT, "Fixed Update FPS", GetFixedUpdateFps, SetFixedUpdateFps, int, 0, AM_DEFAULT);
  80. ACCESSOR_ATTRIBUTE(ScriptInstance, VAR_FLOAT, "Time Accumulator", GetFixedUpdateAccAttr, SetFixedUpdateAccAttr, float, 0.0f, AM_FILE | AM_NOEDIT);
  81. ACCESSOR_ATTRIBUTE(ScriptInstance, VAR_BUFFER, "Delayed Method Calls", GetDelayedMethodCallsAttr, SetDelayedMethodCallsAttr, PODVector<unsigned char>, Variant::emptyBuffer, AM_FILE | AM_NOEDIT);
  82. ACCESSOR_ATTRIBUTE(ScriptInstance, VAR_BUFFER, "Script Data", GetScriptDataAttr, SetScriptDataAttr, PODVector<unsigned char>, Variant::emptyBuffer, AM_FILE | AM_NOEDIT);
  83. ACCESSOR_ATTRIBUTE(ScriptInstance, VAR_BUFFER, "Script Network Data", GetScriptNetworkDataAttr, SetScriptNetworkDataAttr, PODVector<unsigned char>, Variant::emptyBuffer, AM_NET | AM_NOEDIT);
  84. }
  85. void ScriptInstance::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
  86. {
  87. if (attr.mode_ & (AM_NODEID | AM_COMPONENTID))
  88. {
  89. // The component / node to which the ID refers to may not be in scene yet. Delay searching for it to ApplyAttributes
  90. idAttributes_[const_cast<AttributeInfo*>(&attr)] = src.GetUInt();
  91. }
  92. else
  93. Serializable::OnSetAttribute(attr, src);
  94. }
  95. void ScriptInstance::OnGetAttribute(const AttributeInfo& attr, Variant& dest) const
  96. {
  97. // Get ID's of node / component handle attributes
  98. if (attr.mode_ & AM_NODEID)
  99. {
  100. Node* node = *(reinterpret_cast<Node**>(attr.ptr_));
  101. unsigned nodeID = node ? node->GetID() : 0;
  102. dest = Variant(nodeID);
  103. }
  104. else if (attr.mode_ & AM_COMPONENTID)
  105. {
  106. Component* component = *(reinterpret_cast<Component**>(attr.ptr_));
  107. unsigned componentID = component ? component->GetID() : 0;
  108. dest = Variant(componentID);
  109. }
  110. else
  111. Serializable::OnGetAttribute(attr, dest);
  112. }
  113. void ScriptInstance::ApplyAttributes()
  114. {
  115. // Apply node / component ID's now
  116. for (HashMap<AttributeInfo*, unsigned>::Iterator i = idAttributes_.Begin(); i != idAttributes_.End(); ++i)
  117. {
  118. AttributeInfo& attr = *i->first_;
  119. if (attr.mode_ & AM_NODEID)
  120. {
  121. Node*& nodePtr = *(reinterpret_cast<Node**>(attr.ptr_));
  122. // Decrease reference count of the old object, then increment the new
  123. if (nodePtr)
  124. nodePtr->ReleaseRef();
  125. nodePtr = GetScene()->GetNode(i->second_);
  126. if (nodePtr)
  127. nodePtr->AddRef();
  128. }
  129. else if (attr.mode_ & AM_COMPONENTID)
  130. {
  131. Component*& componentPtr = *(reinterpret_cast<Component**>(attr.ptr_));
  132. if (componentPtr)
  133. componentPtr->ReleaseRef();
  134. componentPtr = GetScene()->GetComponent(i->second_);
  135. if (componentPtr)
  136. componentPtr->AddRef();
  137. }
  138. }
  139. idAttributes_.Clear();
  140. if (scriptObject_ && methods_[METHOD_APPLYATTRIBUTES])
  141. scriptFile_->Execute(scriptObject_, methods_[METHOD_APPLYATTRIBUTES]);
  142. }
  143. void ScriptInstance::OnSetEnabled()
  144. {
  145. UpdateEventSubscription();
  146. }
  147. bool ScriptInstance::CreateObject(ScriptFile* scriptFile, const String& className)
  148. {
  149. className_ = String::EMPTY; // Do not create object during SetScriptFile()
  150. SetScriptFile(scriptFile);
  151. SetClassName(className);
  152. return scriptObject_ != 0;
  153. }
  154. void ScriptInstance::SetScriptFile(ScriptFile* scriptFile)
  155. {
  156. if (scriptFile == scriptFile_ && scriptObject_)
  157. return;
  158. ReleaseObject();
  159. // Unsubscribe from the reload event of previous script file (if any), then subscribe to the new
  160. if (scriptFile_)
  161. {
  162. UnsubscribeFromEvent(scriptFile_, E_RELOADSTARTED);
  163. UnsubscribeFromEvent(scriptFile_, E_RELOADFINISHED);
  164. }
  165. if (scriptFile)
  166. {
  167. SubscribeToEvent(scriptFile, E_RELOADSTARTED, HANDLER(ScriptInstance, HandleScriptFileReload));
  168. SubscribeToEvent(scriptFile, E_RELOADFINISHED, HANDLER(ScriptInstance, HandleScriptFileReloadFinished));
  169. }
  170. scriptFile_ = scriptFile;
  171. CreateObject();
  172. MarkNetworkUpdate();
  173. }
  174. void ScriptInstance::SetClassName(const String& className)
  175. {
  176. if (className == className_ && scriptObject_)
  177. return;
  178. ReleaseObject();
  179. className_ = className;
  180. CreateObject();
  181. MarkNetworkUpdate();
  182. }
  183. void ScriptInstance::SetFixedUpdateFps(int fps)
  184. {
  185. fixedUpdateFps_ = Max(fps, 0);
  186. fixedUpdateInterval_ = fixedUpdateFps_ ? (1.0f / fixedUpdateFps_) : 0.0f;
  187. fixedUpdateAcc_ = 0.0f;
  188. fixedPostUpdateAcc_ = 0.0f;
  189. MarkNetworkUpdate();
  190. }
  191. bool ScriptInstance::Execute(const String& declaration, const VariantVector& parameters)
  192. {
  193. if (!scriptObject_)
  194. return false;
  195. asIScriptFunction* method = scriptFile_->GetMethod(scriptObject_, declaration);
  196. return scriptFile_->Execute(scriptObject_, method, parameters);
  197. }
  198. bool ScriptInstance::Execute(asIScriptFunction* method, const VariantVector& parameters)
  199. {
  200. if (!method || !scriptObject_)
  201. return false;
  202. return scriptFile_->Execute(scriptObject_, method, parameters);
  203. }
  204. void ScriptInstance::DelayedExecute(float delay, bool repeat, const String& declaration, const VariantVector& parameters)
  205. {
  206. if (!scriptObject_)
  207. return;
  208. DelayedMethodCall call;
  209. call.period_ = call.delay_ = Max(delay, 0.0f);
  210. call.repeat_ = repeat;
  211. call.declaration_ = declaration;
  212. call.parameters_ = parameters;
  213. delayedMethodCalls_.Push(call);
  214. // Make sure we are registered to the scene update event, because delayed calls are executed there
  215. if (!subscribed_)
  216. UpdateEventSubscription();
  217. }
  218. void ScriptInstance::ClearDelayedExecute(const String& declaration)
  219. {
  220. if (declaration.Empty())
  221. delayedMethodCalls_.Clear();
  222. else
  223. {
  224. for (Vector<DelayedMethodCall>::Iterator i = delayedMethodCalls_.Begin(); i != delayedMethodCalls_.End();)
  225. {
  226. if (declaration == i->declaration_)
  227. i = delayedMethodCalls_.Erase(i);
  228. else
  229. ++i;
  230. }
  231. }
  232. }
  233. void ScriptInstance::AddEventHandler(StringHash eventType, const String& handlerName)
  234. {
  235. if (!scriptObject_)
  236. return;
  237. String declaration = "void " + handlerName + "(StringHash, VariantMap&)";
  238. asIScriptFunction* method = scriptFile_->GetMethod(scriptObject_, declaration);
  239. if (!method)
  240. {
  241. declaration = "void " + handlerName + "()";
  242. method = scriptFile_->GetMethod(scriptObject_, declaration);
  243. if (!method)
  244. {
  245. LOGERROR("Event handler method " + handlerName + " not found in " + scriptFile_->GetName());
  246. return;
  247. }
  248. }
  249. SubscribeToEvent(eventType, HANDLER_USERDATA(ScriptInstance, HandleScriptEvent, (void*)method));
  250. }
  251. void ScriptInstance::AddEventHandler(Object* sender, StringHash eventType, const String& handlerName)
  252. {
  253. if (!scriptObject_)
  254. return;
  255. if (!sender)
  256. {
  257. LOGERROR("Null event sender for event " + String(eventType) + ", handler " + handlerName);
  258. return;
  259. }
  260. String declaration = "void " + handlerName + "(StringHash, VariantMap&)";
  261. asIScriptFunction* method = scriptFile_->GetMethod(scriptObject_, declaration);
  262. if (!method)
  263. {
  264. declaration = "void " + handlerName + "()";
  265. method = scriptFile_->GetMethod(scriptObject_, declaration);
  266. if (!method)
  267. {
  268. LOGERROR("Event handler method " + handlerName + " not found in " + scriptFile_->GetName());
  269. return;
  270. }
  271. }
  272. SubscribeToEvent(sender, eventType, HANDLER_USERDATA(ScriptInstance, HandleScriptEvent, (void*)method));
  273. }
  274. void ScriptInstance::SetScriptFileAttr(ResourceRef value)
  275. {
  276. ResourceCache* cache = GetSubsystem<ResourceCache>();
  277. SetScriptFile(cache->GetResource<ScriptFile>(value.id_));
  278. }
  279. void ScriptInstance::SetDelayedMethodCallsAttr(PODVector<unsigned char> value)
  280. {
  281. MemoryBuffer buf(value);
  282. delayedMethodCalls_.Resize(buf.ReadVLE());
  283. for (Vector<DelayedMethodCall>::Iterator i = delayedMethodCalls_.Begin(); i != delayedMethodCalls_.End(); ++i)
  284. {
  285. i->period_ = buf.ReadFloat();
  286. i->delay_ = buf.ReadFloat();
  287. i->repeat_ = buf.ReadBool();
  288. i->declaration_ = buf.ReadString();
  289. i->parameters_ = buf.ReadVariantVector();
  290. }
  291. if (delayedMethodCalls_.Size() && !subscribed_)
  292. UpdateEventSubscription();
  293. }
  294. void ScriptInstance::SetFixedUpdateAccAttr(float value)
  295. {
  296. fixedUpdateAcc_ = value;
  297. fixedPostUpdateAcc_ = value;
  298. }
  299. void ScriptInstance::SetScriptDataAttr(PODVector<unsigned char> data)
  300. {
  301. if (scriptObject_ && methods_[METHOD_LOAD])
  302. {
  303. MemoryBuffer buf(data);
  304. VariantVector parameters;
  305. parameters.Push(Variant((void*)static_cast<Deserializer*>(&buf)));
  306. scriptFile_->Execute(scriptObject_, methods_[METHOD_LOAD], parameters);
  307. }
  308. }
  309. void ScriptInstance::SetScriptNetworkDataAttr(PODVector<unsigned char> data)
  310. {
  311. if (scriptObject_ && methods_[METHOD_READNETWORKUPDATE])
  312. {
  313. MemoryBuffer buf(data);
  314. VariantVector parameters;
  315. parameters.Push(Variant((void*)static_cast<Deserializer*>(&buf)));
  316. scriptFile_->Execute(scriptObject_, methods_[METHOD_READNETWORKUPDATE], parameters);
  317. }
  318. }
  319. ResourceRef ScriptInstance::GetScriptFileAttr() const
  320. {
  321. return GetResourceRef(scriptFile_, ScriptFile::GetTypeStatic());
  322. }
  323. PODVector<unsigned char> ScriptInstance::GetDelayedMethodCallsAttr() const
  324. {
  325. VectorBuffer buf;
  326. buf.WriteVLE(delayedMethodCalls_.Size());
  327. for (Vector<DelayedMethodCall>::ConstIterator i = delayedMethodCalls_.Begin(); i != delayedMethodCalls_.End(); ++i)
  328. {
  329. buf.WriteFloat(i->period_);
  330. buf.WriteFloat(i->delay_);
  331. buf.WriteBool(i->repeat_);
  332. buf.WriteString(i->declaration_);
  333. buf.WriteVariantVector(i->parameters_);
  334. }
  335. return buf.GetBuffer();
  336. }
  337. float ScriptInstance::GetFixedUpdateAccAttr() const
  338. {
  339. return fixedUpdateAcc_;
  340. }
  341. PODVector<unsigned char> ScriptInstance::GetScriptDataAttr() const
  342. {
  343. if (!scriptObject_ || !methods_[METHOD_SAVE])
  344. return PODVector<unsigned char>();
  345. else
  346. {
  347. VectorBuffer buf;
  348. VariantVector parameters;
  349. parameters.Push(Variant((void*)static_cast<Serializer*>(&buf)));
  350. scriptFile_->Execute(scriptObject_, methods_[METHOD_SAVE], parameters);
  351. return buf.GetBuffer();
  352. }
  353. }
  354. PODVector<unsigned char> ScriptInstance::GetScriptNetworkDataAttr() const
  355. {
  356. if (!scriptObject_ || !methods_[METHOD_WRITENETWORKUPDATE])
  357. return PODVector<unsigned char>();
  358. else
  359. {
  360. VectorBuffer buf;
  361. VariantVector parameters;
  362. parameters.Push(Variant((void*)static_cast<Serializer*>(&buf)));
  363. scriptFile_->Execute(scriptObject_, methods_[METHOD_WRITENETWORKUPDATE], parameters);
  364. return buf.GetBuffer();
  365. }
  366. }
  367. void ScriptInstance::CreateObject()
  368. {
  369. if (!scriptFile_ || className_.Empty())
  370. return;
  371. PROFILE(CreateScriptObject);
  372. scriptObject_ = scriptFile_->CreateObject(className_);
  373. if (scriptObject_)
  374. {
  375. // Map script object to script instance with userdata
  376. scriptObject_->SetUserData(this);
  377. ClearDelayedExecute();
  378. GetScriptMethods();
  379. GetScriptAttributes();
  380. UpdateEventSubscription();
  381. if (methods_[METHOD_START])
  382. scriptFile_->Execute(scriptObject_, methods_[METHOD_START]);
  383. }
  384. else
  385. LOGERROR("Failed to create object of class " + className_ + " from " + scriptFile_->GetName());
  386. }
  387. void ScriptInstance::ReleaseObject()
  388. {
  389. if (scriptObject_)
  390. {
  391. if (methods_[METHOD_STOP])
  392. scriptFile_->Execute(scriptObject_, methods_[METHOD_STOP]);
  393. PODVector<StringHash> exceptions;
  394. exceptions.Push(E_RELOADSTARTED);
  395. exceptions.Push(E_RELOADFINISHED);
  396. UnsubscribeFromAllEventsExcept(exceptions, false);
  397. subscribed_ = false;
  398. subscribedPostFixed_ = false;
  399. ClearScriptMethods();
  400. ClearScriptAttributes();
  401. scriptObject_->SetUserData(0);
  402. scriptObject_->Release();
  403. scriptObject_ = 0;
  404. }
  405. }
  406. void ScriptInstance::ClearScriptMethods()
  407. {
  408. for (unsigned i = 0; i < MAX_SCRIPT_METHODS; ++i)
  409. methods_[i] = 0;
  410. delayedMethodCalls_.Clear();
  411. }
  412. void ScriptInstance::ClearScriptAttributes()
  413. {
  414. attributeInfos_ = *context_->GetAttributes(GetTypeStatic());
  415. }
  416. void ScriptInstance::GetScriptMethods()
  417. {
  418. for (unsigned i = 0; i < MAX_SCRIPT_METHODS; ++i)
  419. methods_[i] = scriptFile_->GetMethod(scriptObject_, methodDeclarations[i]);
  420. }
  421. void ScriptInstance::GetScriptAttributes()
  422. {
  423. asIScriptEngine* engine = GetSubsystem<Script>()->GetScriptEngine();
  424. attributeInfos_ = *context_->GetAttributes(GetTypeStatic());
  425. unsigned numProperties = scriptObject_->GetPropertyCount();
  426. for (unsigned i = 0; i < numProperties; ++i)
  427. {
  428. const char* name;
  429. int typeId;
  430. bool isPrivate, isHandle;
  431. scriptObject_->GetObjectType()->GetProperty(i, &name, &typeId, &isPrivate);
  432. // Hide private variables or ones that begin with an underscore
  433. if (isPrivate || name[0] == '_')
  434. continue;
  435. String typeName = engine->GetTypeDeclaration(typeId);
  436. isHandle = typeName.EndsWith("@");
  437. if (isHandle)
  438. typeName = typeName.Substring(0, typeName.Length() - 1);
  439. AttributeInfo info;
  440. info.name_ = name;
  441. info.ptr_ = scriptObject_->GetAddressOfProperty(i);
  442. if (!isHandle)
  443. {
  444. switch (typeId)
  445. {
  446. case asTYPEID_BOOL:
  447. info.type_ = VAR_BOOL;
  448. break;
  449. case asTYPEID_INT32:
  450. case asTYPEID_UINT32:
  451. info.type_ = VAR_INT;
  452. break;
  453. case asTYPEID_FLOAT:
  454. info.type_ = VAR_FLOAT;
  455. break;
  456. default:
  457. info.type_ = Variant::GetTypeFromName(typeName);
  458. break;
  459. }
  460. }
  461. else
  462. {
  463. // For a handle type, check if it's an Object subclass with a registered factory
  464. ShortStringHash typeHash(typeName);
  465. if (context_->GetObjectFactories().Find(typeHash) != context_->GetObjectFactories().End())
  466. {
  467. // There are three possibilities: the handle is for a Node, a Component or UIElement subclass
  468. // We want to identify nodes and components so that we can store their ID's for serialization
  469. const HashMap<String, Vector<ShortStringHash> >& categories = context_->GetObjectCategories();
  470. if (categories.Contains(UI_CATEGORY))
  471. {
  472. const Vector<ShortStringHash>& uiCategory = categories.Find(UI_CATEGORY)->second_;
  473. if (uiCategory.Contains(typeHash))
  474. continue; // Is handle to a UIElement; can not handle those
  475. }
  476. if (typeHash == Node::GetTypeStatic() || typeHash == Scene::GetTypeStatic())
  477. {
  478. info.mode_ |= AM_NODEID;
  479. info.type_ = VAR_INT;
  480. }
  481. else
  482. {
  483. bool foundComponent = false;
  484. // If is found in one of the component categories, must be a component
  485. for (HashMap<String, Vector<ShortStringHash> >::ConstIterator i = categories.Begin(); i != categories.End();
  486. ++i)
  487. {
  488. if (i->second_.Contains(typeHash))
  489. {
  490. foundComponent = true;
  491. break;
  492. }
  493. }
  494. if (foundComponent)
  495. {
  496. info.mode_ |= AM_COMPONENTID;
  497. info.type_ = VAR_INT;
  498. }
  499. }
  500. }
  501. }
  502. if (info.type_ != VAR_NONE)
  503. attributeInfos_.Push(info);
  504. }
  505. }
  506. void ScriptInstance::UpdateEventSubscription()
  507. {
  508. Scene* scene = GetScene();
  509. if (!scene)
  510. {
  511. LOGERROR("Node is detached from scene, can not subscribe script object to update events");
  512. return;
  513. }
  514. bool enabled = scriptObject_ && IsEnabledEffective();
  515. if (enabled)
  516. {
  517. if (!subscribed_ && (methods_[METHOD_UPDATE] || methods_[METHOD_DELAYEDSTART] || delayedMethodCalls_.Size()))
  518. {
  519. SubscribeToEvent(scene, E_SCENEUPDATE, HANDLER(ScriptInstance, HandleSceneUpdate));
  520. subscribed_ = true;
  521. }
  522. if (!subscribedPostFixed_)
  523. {
  524. if (methods_[METHOD_POSTUPDATE])
  525. SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(ScriptInstance, HandleScenePostUpdate));
  526. PhysicsWorld* world = scene->GetComponent<PhysicsWorld>();
  527. if (world)
  528. {
  529. if (methods_[METHOD_FIXEDUPDATE])
  530. SubscribeToEvent(world, E_PHYSICSPRESTEP, HANDLER(ScriptInstance, HandlePhysicsPreStep));
  531. if (methods_[METHOD_FIXEDPOSTUPDATE])
  532. SubscribeToEvent(world, E_PHYSICSPOSTSTEP, HANDLER(ScriptInstance, HandlePhysicsPostStep));
  533. }
  534. else
  535. {
  536. if (methods_[METHOD_FIXEDUPDATE] || methods_[METHOD_FIXEDPOSTUPDATE])
  537. LOGERROR("No physics world, can not subscribe script object to fixed update events");
  538. }
  539. subscribedPostFixed_ = true;
  540. }
  541. }
  542. else
  543. {
  544. if (subscribed_)
  545. {
  546. UnsubscribeFromEvent(scene, E_SCENEUPDATE);
  547. subscribed_ = false;
  548. }
  549. if (subscribedPostFixed_)
  550. {
  551. UnsubscribeFromEvent(scene, E_SCENEPOSTUPDATE);
  552. PhysicsWorld* world = scene->GetComponent<PhysicsWorld>();
  553. if (world)
  554. {
  555. UnsubscribeFromEvent(world, E_PHYSICSPRESTEP);
  556. UnsubscribeFromEvent(world, E_PHYSICSPOSTSTEP);
  557. }
  558. subscribedPostFixed_ = false;
  559. }
  560. }
  561. }
  562. void ScriptInstance::HandleSceneUpdate(StringHash eventType, VariantMap& eventData)
  563. {
  564. if (!scriptObject_)
  565. return;
  566. using namespace SceneUpdate;
  567. float timeStep = eventData[P_TIMESTEP].GetFloat();
  568. // Execute delayed method calls
  569. for (unsigned i = 0; i < delayedMethodCalls_.Size();)
  570. {
  571. DelayedMethodCall& call = delayedMethodCalls_[i];
  572. bool remove = false;
  573. call.delay_ -= timeStep;
  574. if (call.delay_ <= 0.0f)
  575. {
  576. if (!call.repeat_)
  577. remove = true;
  578. else
  579. call.delay_ += call.period_;
  580. Execute(call.declaration_, call.parameters_);
  581. }
  582. if (remove)
  583. delayedMethodCalls_.Erase(i);
  584. else
  585. ++i;
  586. }
  587. // Execute delayed start before first update
  588. if (methods_[METHOD_DELAYEDSTART])
  589. {
  590. scriptFile_->Execute(scriptObject_, methods_[METHOD_DELAYEDSTART]);
  591. methods_[METHOD_DELAYEDSTART] = 0; // Only execute once
  592. }
  593. if (methods_[METHOD_UPDATE])
  594. {
  595. VariantVector parameters;
  596. parameters.Push(timeStep);
  597. scriptFile_->Execute(scriptObject_, methods_[METHOD_UPDATE], parameters);
  598. }
  599. }
  600. void ScriptInstance::HandleScenePostUpdate(StringHash eventType, VariantMap& eventData)
  601. {
  602. if (!scriptObject_)
  603. return;
  604. using namespace ScenePostUpdate;
  605. VariantVector parameters;
  606. parameters.Push(eventData[P_TIMESTEP]);
  607. scriptFile_->Execute(scriptObject_, methods_[METHOD_POSTUPDATE], parameters);
  608. }
  609. void ScriptInstance::HandlePhysicsPreStep(StringHash eventType, VariantMap& eventData)
  610. {
  611. if (!scriptObject_)
  612. return;
  613. using namespace PhysicsPreStep;
  614. if (!fixedUpdateFps_)
  615. {
  616. VariantVector parameters;
  617. parameters.Push(eventData[P_TIMESTEP]);
  618. scriptFile_->Execute(scriptObject_, methods_[METHOD_FIXEDUPDATE], parameters);
  619. }
  620. else
  621. {
  622. float timeStep = eventData[P_TIMESTEP].GetFloat();
  623. fixedUpdateAcc_ += timeStep;
  624. if (fixedUpdateAcc_ >= fixedUpdateInterval_)
  625. {
  626. fixedUpdateAcc_ = fmodf(fixedUpdateAcc_, fixedUpdateInterval_);
  627. VariantVector parameters;
  628. parameters.Push(fixedUpdateInterval_);
  629. scriptFile_->Execute(scriptObject_, methods_[METHOD_FIXEDUPDATE], parameters);
  630. }
  631. }
  632. }
  633. void ScriptInstance::HandlePhysicsPostStep(StringHash eventType, VariantMap& eventData)
  634. {
  635. if (!scriptObject_)
  636. return;
  637. using namespace PhysicsPostStep;
  638. if (!fixedUpdateFps_)
  639. {
  640. VariantVector parameters;
  641. parameters.Push(eventData[P_TIMESTEP]);
  642. scriptFile_->Execute(scriptObject_, methods_[METHOD_FIXEDPOSTUPDATE], parameters);
  643. }
  644. else
  645. {
  646. float timeStep = eventData[P_TIMESTEP].GetFloat();
  647. fixedPostUpdateAcc_ += timeStep;
  648. if (fixedPostUpdateAcc_ >= fixedUpdateInterval_)
  649. {
  650. fixedPostUpdateAcc_ = fmodf(fixedPostUpdateAcc_, fixedUpdateInterval_);
  651. VariantVector parameters;
  652. parameters.Push(fixedUpdateInterval_);
  653. scriptFile_->Execute(scriptObject_, methods_[METHOD_FIXEDPOSTUPDATE], parameters);
  654. }
  655. }
  656. }
  657. void ScriptInstance::HandleScriptEvent(StringHash eventType, VariantMap& eventData)
  658. {
  659. if (!IsEnabledEffective() || !scriptFile_ || !scriptObject_)
  660. return;
  661. asIScriptFunction* method = static_cast<asIScriptFunction*>(GetEventHandler()->GetUserData());
  662. VariantVector parameters;
  663. if (method->GetParamCount() > 0)
  664. {
  665. parameters.Push(Variant((void*)&eventType));
  666. parameters.Push(Variant((void*)&eventData));
  667. }
  668. scriptFile_->Execute(scriptObject_, method, parameters);
  669. }
  670. void ScriptInstance::HandleScriptFileReload(StringHash eventType, VariantMap& eventData)
  671. {
  672. ReleaseObject();
  673. }
  674. void ScriptInstance::HandleScriptFileReloadFinished(StringHash eventType, VariantMap& eventData)
  675. {
  676. if (!className_.Empty())
  677. CreateObject();
  678. }
  679. Context* GetScriptContext()
  680. {
  681. return static_cast<Script*>(asGetActiveContext()->GetEngine()->GetUserData())->GetContext();
  682. }
  683. ScriptInstance* GetScriptContextInstance()
  684. {
  685. asIScriptContext* context = asGetActiveContext();
  686. asIScriptObject* object = context ? static_cast<asIScriptObject*>(context->GetThisPointer()) : 0;
  687. if (object)
  688. return static_cast<ScriptInstance*>(object->GetUserData());
  689. else
  690. return 0;
  691. }
  692. Node* GetScriptContextNode()
  693. {
  694. ScriptInstance* instance = GetScriptContextInstance();
  695. return instance ? instance->GetNode() : 0;
  696. }
  697. Scene* GetScriptContextScene()
  698. {
  699. Scene* scene = 0;
  700. Node* node = GetScriptContextNode();
  701. if (node)
  702. scene = node->GetScene();
  703. // If null, try to get the default scene
  704. if (!scene)
  705. scene = GetScriptContext()->GetSubsystem<Script>()->GetDefaultScene();
  706. return scene;
  707. }
  708. ScriptEventListener* GetScriptContextEventListener()
  709. {
  710. // If context's this pointer is non-null, try to get the script instance. Else get the script file for procedural
  711. // event handling
  712. asIScriptContext* context = asGetActiveContext();
  713. if (context)
  714. {
  715. if (context->GetThisPointer())
  716. return GetScriptContextInstance();
  717. else
  718. return GetScriptContextFile();
  719. }
  720. else
  721. return 0;
  722. }
  723. Object* GetScriptContextEventListenerObject()
  724. {
  725. return dynamic_cast<Object*>(GetScriptContextEventListener());
  726. }
  727. }