ScriptInstance.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2011 Lasse Öörni
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. #include "Precompiled.h"
  24. #include "Context.h"
  25. #include "Log.h"
  26. #include "MemoryBuffer.h"
  27. #include "PhysicsEvents.h"
  28. #include "PhysicsWorld.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 "StringUtils.h"
  37. #include "VectorBuffer.h"
  38. #include <angelscript.h>
  39. #include "DebugNew.h"
  40. static const std::string methodDeclarations[] = {
  41. "void Start()",
  42. "void Stop()",
  43. "void Update(float)",
  44. "void PostUpdate(float)",
  45. "void FixedUpdate(float)",
  46. "void FixedPostUpdate(float)",
  47. "void Load(Deserializer&)",
  48. "void Save(Serializer&)",
  49. "void PostLoad()"
  50. };
  51. OBJECTTYPESTATIC(ScriptInstance);
  52. ScriptInstance::ScriptInstance(Context* context) :
  53. Component(context),
  54. script_(GetSubsystem<Script>()),
  55. scriptObject_(0),
  56. active_(true),
  57. fixedUpdateFps_(0),
  58. fixedUpdateInterval_(0.0f),
  59. fixedUpdateAcc_(0.0f),
  60. fixedPostUpdateAcc_(0.0f)
  61. {
  62. ClearMethods();
  63. }
  64. ScriptInstance::~ScriptInstance()
  65. {
  66. ReleaseObject();
  67. }
  68. void ScriptInstance::RegisterObject(Context* context)
  69. {
  70. context->RegisterFactory<ScriptInstance>();
  71. ATTRIBUTE(ScriptInstance, VAR_RESOURCEREF, "Script File", scriptFile_, ResourceRef(ScriptFile::GetTypeStatic()));
  72. ATTRIBUTE(ScriptInstance, VAR_STRING, "Class Name", className_, std::string());
  73. ATTRIBUTE(ScriptInstance, VAR_BOOL, "Active", active_, true);
  74. ATTRIBUTE(ScriptInstance, VAR_INT, "Fixed Update FPS", fixedUpdateFps_, 0);
  75. ATTRIBUTE_MODE(ScriptInstance, VAR_FLOAT, "Time Accumulator", fixedUpdateAcc_, 0.0f, AM_SERIALIZATION);
  76. ATTRIBUTE_MODE(ScriptInstance, VAR_BUFFER, "Delayed Method Calls", delayedMethodCalls_, std::vector<unsigned char>(), AM_SERIALIZATION);
  77. ID_ATTRIBUTE(ScriptInstance, VAR_BUFFER, "Script Data", ATTR_SCRIPTDATA, std::vector<unsigned char>());
  78. }
  79. void ScriptInstance::OnSetAttribute(const AttributeInfo& attr, const Variant& value)
  80. {
  81. ResourceCache* cache = GetSubsystem<ResourceCache>();
  82. switch (attr.offset_)
  83. {
  84. case offsetof(ScriptInstance, scriptFile_):
  85. SetScriptFile(cache->GetResource<ScriptFile>(value.GetResourceRef().id_));
  86. break;
  87. case offsetof(ScriptInstance, className_):
  88. SetClassName(value.GetString());
  89. break;
  90. case offsetof(ScriptInstance, fixedUpdateFps_):
  91. SetFixedUpdateFps(value.GetInt());
  92. break;
  93. case offsetof(ScriptInstance, fixedUpdateAcc_):
  94. Serializable::OnSetAttribute(attr, value);
  95. fixedPostUpdateAcc_ = fixedUpdateAcc_;
  96. break;
  97. case offsetof(ScriptInstance, delayedMethodCalls_):
  98. {
  99. MemoryBuffer buf(value.GetBuffer());
  100. delayedMethodCalls_.resize(buf.ReadVLE());
  101. for (std::vector<DelayedMethodCall>::iterator i = delayedMethodCalls_.begin(); i != delayedMethodCalls_.end(); ++i)
  102. {
  103. i->delay_ = buf.ReadFloat();
  104. i->declaration_ = buf.ReadString();
  105. i->parameters_ = buf.ReadVariantVector();
  106. }
  107. }
  108. break;
  109. case ATTR_SCRIPTDATA:
  110. if ((scriptObject_) && (methods_[METHOD_LOAD]))
  111. {
  112. MemoryBuffer buf(value.GetBuffer());
  113. VariantVector parameters;
  114. parameters.push_back(Variant((void*)static_cast<Deserializer*>(&buf)));
  115. scriptFile_->Execute(scriptObject_, methods_[METHOD_LOAD], parameters);
  116. }
  117. break;
  118. default:
  119. Serializable::OnSetAttribute(attr, value);
  120. break;
  121. }
  122. }
  123. Variant ScriptInstance::OnGetAttribute(const AttributeInfo& attr)
  124. {
  125. switch (attr.offset_)
  126. {
  127. case offsetof(ScriptInstance, scriptFile_):
  128. return GetResourceRef(scriptFile_, ScriptFile::GetTypeStatic());
  129. case offsetof(ScriptInstance, delayedMethodCalls_):
  130. {
  131. VectorBuffer buf;
  132. buf.WriteVLE(delayedMethodCalls_.size());
  133. for (std::vector<DelayedMethodCall>::const_iterator i = delayedMethodCalls_.begin(); i != delayedMethodCalls_.end(); ++i)
  134. {
  135. buf.WriteFloat(i->delay_);
  136. buf.WriteString(i->declaration_);
  137. buf.WriteVariantVector(i->parameters_);
  138. }
  139. return buf.GetBuffer();
  140. }
  141. case ATTR_SCRIPTDATA:
  142. if ((!scriptObject_) || (!methods_[METHOD_SAVE]))
  143. return std::vector<unsigned char>();
  144. else
  145. {
  146. VectorBuffer buf;
  147. VariantVector parameters;
  148. parameters.push_back(Variant((void*)static_cast<Serializer*>(&buf)));
  149. scriptFile_->Execute(scriptObject_, methods_[METHOD_SAVE], parameters);
  150. return buf.GetBuffer();
  151. }
  152. default:
  153. return Serializable::OnGetAttribute(attr);
  154. }
  155. }
  156. void ScriptInstance::PostLoad()
  157. {
  158. if ((scriptObject_) && (methods_[METHOD_POSTLOAD]))
  159. scriptFile_->Execute(scriptObject_, methods_[METHOD_POSTLOAD]);
  160. }
  161. bool ScriptInstance::CreateObject(ScriptFile* scriptFile, const std::string& className)
  162. {
  163. className_ = std::string(); // Do not create object during SetScriptFile()
  164. SetScriptFile(scriptFile);
  165. SetClassName(className);
  166. return scriptObject_ != 0;
  167. }
  168. void ScriptInstance::SetScriptFile(ScriptFile* scriptFile)
  169. {
  170. if ((scriptFile == scriptFile_) && (scriptObject_))
  171. return;
  172. ReleaseObject();
  173. // Unsubscribe from the reload event of previous script file (if any), then subscribe to the new
  174. if (scriptFile_)
  175. {
  176. UnsubscribeFromEvent(scriptFile_, E_RELOADSTARTED);
  177. UnsubscribeFromEvent(scriptFile_, E_RELOADFINISHED);
  178. }
  179. if (scriptFile)
  180. {
  181. SubscribeToEvent(scriptFile, E_RELOADSTARTED, HANDLER(ScriptInstance, HandleScriptFileReload));
  182. SubscribeToEvent(scriptFile, E_RELOADFINISHED, HANDLER(ScriptInstance, HandleScriptFileReloadFinished));
  183. }
  184. scriptFile_ = scriptFile;
  185. CreateObject();
  186. }
  187. void ScriptInstance::SetClassName(const std::string& className)
  188. {
  189. if ((className == className_) && (scriptObject_))
  190. return;
  191. ReleaseObject();
  192. className_ = className;
  193. CreateObject();
  194. }
  195. void ScriptInstance::SetActive(bool active)
  196. {
  197. active_ = active;
  198. }
  199. void ScriptInstance::SetFixedUpdateFps(int fps)
  200. {
  201. fixedUpdateFps_ = Max(fps, 0);
  202. fixedUpdateInterval_ = fixedUpdateFps_ ? (1.0f / fixedUpdateFps_) : 0.0f;
  203. fixedUpdateAcc_ = 0.0f;
  204. fixedPostUpdateAcc_ = 0.0f;
  205. }
  206. bool ScriptInstance::Execute(const std::string& declaration, const VariantVector& parameters)
  207. {
  208. if (!scriptObject_)
  209. return false;
  210. asIScriptFunction* method = scriptFile_->GetMethod(scriptObject_, declaration);
  211. return scriptFile_->Execute(scriptObject_, method, parameters);
  212. }
  213. bool ScriptInstance::Execute(asIScriptFunction* method, const VariantVector& parameters)
  214. {
  215. if ((!method) || (!scriptObject_))
  216. return false;
  217. return scriptFile_->Execute(scriptObject_, method, parameters);
  218. }
  219. void ScriptInstance::DelayedExecute(float delay, const std::string& declaration, const VariantVector& parameters)
  220. {
  221. if (!scriptObject_)
  222. return;
  223. DelayedMethodCall call;
  224. call.delay_ = Max(delay, 0.0f);
  225. call.declaration_ = declaration;
  226. call.parameters_ = parameters;
  227. delayedMethodCalls_.push_back(call);
  228. // Make sure we are registered to the scene update event, because delayed calls are executed there
  229. if ((!methods_[METHOD_UPDATE]) && (!HasSubscribed(E_SCENEUPDATE)))
  230. {
  231. Node* node = GetNode();
  232. if (node)
  233. SubscribeToEvent(node->GetScene(), E_SCENEUPDATE, HANDLER(ScriptInstance, HandleSceneUpdate));
  234. }
  235. }
  236. void ScriptInstance::ClearDelayedExecute()
  237. {
  238. delayedMethodCalls_.clear();
  239. }
  240. void ScriptInstance::AddEventHandler(StringHash eventType, const std::string& handlerName)
  241. {
  242. if (!scriptObject_)
  243. return;
  244. std::string declaration = "void " + handlerName + "(StringHash, VariantMap&)";
  245. asIScriptFunction* method = scriptFile_->GetMethod(scriptObject_, declaration);
  246. if (!method)
  247. {
  248. declaration = "void " + handlerName + "()";
  249. method = scriptFile_->GetMethod(scriptObject_, declaration);
  250. if (!method)
  251. {
  252. LOGERROR("Event handler method " + handlerName + " not found in " + scriptFile_->GetName());
  253. return;
  254. }
  255. }
  256. SubscribeToEvent(eventType, HANDLER_USERDATA(ScriptInstance, HandleScriptEvent, (void*)method));
  257. }
  258. void ScriptInstance::AddEventHandler(Object* sender, StringHash eventType, const std::string& handlerName)
  259. {
  260. if (!scriptObject_)
  261. return;
  262. if (!sender)
  263. {
  264. LOGERROR("Null event sender for event " + ToString(eventType) + ", handler " + handlerName);
  265. return;
  266. }
  267. std::string declaration = "void " + handlerName + "(StringHash, VariantMap&)";
  268. asIScriptFunction* method = scriptFile_->GetMethod(scriptObject_, declaration);
  269. if (!method)
  270. {
  271. declaration = "void " + handlerName + "()";
  272. method = scriptFile_->GetMethod(scriptObject_, declaration);
  273. if (!method)
  274. {
  275. LOGERROR("Event handler method " + handlerName + " not found in " + scriptFile_->GetName());
  276. return;
  277. }
  278. }
  279. SubscribeToEvent(sender, eventType, HANDLER_USERDATA(ScriptInstance, HandleScriptEvent, (void*)method));
  280. }
  281. void ScriptInstance::CreateObject()
  282. {
  283. if ((!scriptFile_) || (className_.empty()))
  284. return;
  285. scriptObject_ = scriptFile_->CreateObject(className_);
  286. if (scriptObject_)
  287. {
  288. script_->GetObjectMap()[(void*)scriptObject_] = this;
  289. GetSupportedMethods();
  290. if (methods_[METHOD_START])
  291. scriptFile_->Execute(scriptObject_, methods_[METHOD_START]);
  292. }
  293. else
  294. LOGERROR("Failed to create object of class " + className_ + " from " + scriptFile_->GetName());
  295. }
  296. void ScriptInstance::ReleaseObject()
  297. {
  298. if (scriptObject_)
  299. {
  300. if (methods_[METHOD_STOP])
  301. scriptFile_->Execute(scriptObject_, methods_[METHOD_STOP]);
  302. UnsubscribeFromAllEvents();
  303. ClearMethods();
  304. ClearDelayedExecute();
  305. scriptObject_->Release();
  306. scriptObject_ = 0;
  307. script_->GetObjectMap().erase((void*)scriptObject_);
  308. }
  309. }
  310. void ScriptInstance::ClearMethods()
  311. {
  312. for (unsigned i = 0; i < MAX_SCRIPT_METHODS; ++i)
  313. methods_[i] = 0;
  314. delayedMethodCalls_.clear();
  315. }
  316. void ScriptInstance::GetSupportedMethods()
  317. {
  318. for (unsigned i = 0; i < MAX_SCRIPT_METHODS; ++i)
  319. methods_[i] = scriptFile_->GetMethod(scriptObject_, methodDeclarations[i]);
  320. // Subscribe to the update events as supported
  321. Node* node = GetNode();
  322. if (node)
  323. {
  324. Scene* scene = node->GetScene();
  325. if (scene)
  326. {
  327. if (methods_[METHOD_UPDATE])
  328. SubscribeToEvent(scene, E_SCENEUPDATE, HANDLER(ScriptInstance, HandleSceneUpdate));
  329. if (methods_[METHOD_POSTUPDATE])
  330. SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(ScriptInstance, HandleScenePostUpdate));
  331. PhysicsWorld* world = scene->GetComponent<PhysicsWorld>();
  332. if (world)
  333. {
  334. if (methods_[METHOD_FIXEDUPDATE])
  335. SubscribeToEvent(world, E_PHYSICSPRESTEP, HANDLER(ScriptInstance, HandlePhysicsPreStep));
  336. if (methods_[METHOD_FIXEDPOSTUPDATE])
  337. SubscribeToEvent(world, E_PHYSICSPOSTSTEP, HANDLER(ScriptInstance, HandlePhysicsPostStep));
  338. }
  339. }
  340. }
  341. }
  342. void ScriptInstance::HandleSceneUpdate(StringHash eventType, VariantMap& eventData)
  343. {
  344. if ((!active_) || (!scriptObject_))
  345. return;
  346. using namespace SceneUpdate;
  347. float timeStep = eventData[P_TIMESTEP].GetFloat();
  348. // Execute delayed method calls
  349. for (std::vector<DelayedMethodCall>::iterator i = delayedMethodCalls_.begin(); i != delayedMethodCalls_.end();)
  350. {
  351. i->delay_ -= timeStep;
  352. if (i->delay_ <= 0.0f)
  353. {
  354. Execute(i->declaration_, i->parameters_);
  355. i = delayedMethodCalls_.erase(i);
  356. }
  357. else
  358. ++i;
  359. }
  360. if (methods_[METHOD_UPDATE])
  361. {
  362. VariantVector parameters;
  363. parameters.push_back(timeStep);
  364. scriptFile_->Execute(scriptObject_, methods_[METHOD_UPDATE], parameters);
  365. }
  366. }
  367. void ScriptInstance::HandleScenePostUpdate(StringHash eventType, VariantMap& eventData)
  368. {
  369. if ((!active_) || (!scriptObject_))
  370. return;
  371. using namespace ScenePostUpdate;
  372. VariantVector parameters;
  373. parameters.push_back(eventData[P_TIMESTEP]);
  374. scriptFile_->Execute(scriptObject_, methods_[METHOD_POSTUPDATE], parameters);
  375. }
  376. void ScriptInstance::HandlePhysicsPreStep(StringHash eventType, VariantMap& eventData)
  377. {
  378. if ((!active_) || (!scriptObject_))
  379. return;
  380. using namespace PhysicsPreStep;
  381. if (!fixedUpdateFps_)
  382. {
  383. VariantVector parameters;
  384. parameters.push_back(eventData[P_TIMESTEP]);
  385. scriptFile_->Execute(scriptObject_, methods_[METHOD_FIXEDUPDATE], parameters);
  386. }
  387. else
  388. {
  389. float timeStep = eventData[P_TIMESTEP].GetFloat();
  390. fixedUpdateAcc_ += timeStep;
  391. if (fixedUpdateAcc_ >= fixedUpdateInterval_)
  392. {
  393. fixedUpdateAcc_ = fmodf(fixedUpdateAcc_, fixedUpdateInterval_);
  394. VariantVector parameters;
  395. parameters.push_back(fixedUpdateInterval_);
  396. scriptFile_->Execute(scriptObject_, methods_[METHOD_FIXEDUPDATE], parameters);
  397. }
  398. }
  399. }
  400. void ScriptInstance::HandlePhysicsPostStep(StringHash eventType, VariantMap& eventData)
  401. {
  402. if ((!active_) || (!scriptObject_))
  403. return;
  404. using namespace PhysicsPostStep;
  405. if (!fixedUpdateFps_)
  406. {
  407. VariantVector parameters;
  408. parameters.push_back(eventData[P_TIMESTEP]);
  409. scriptFile_->Execute(scriptObject_, methods_[METHOD_FIXEDPOSTUPDATE], parameters);
  410. }
  411. else
  412. {
  413. float timeStep = eventData[P_TIMESTEP].GetFloat();
  414. fixedPostUpdateAcc_ += timeStep;
  415. if (fixedPostUpdateAcc_ >= fixedUpdateInterval_)
  416. {
  417. fixedPostUpdateAcc_ = fmodf(fixedPostUpdateAcc_, fixedUpdateInterval_);
  418. VariantVector parameters;
  419. parameters.push_back(fixedUpdateInterval_);
  420. scriptFile_->Execute(scriptObject_, methods_[METHOD_FIXEDPOSTUPDATE], parameters);
  421. }
  422. }
  423. }
  424. void ScriptInstance::HandleScriptEvent(StringHash eventType, VariantMap& eventData)
  425. {
  426. if ((!active_) || (!scriptFile_) || (!scriptObject_))
  427. return;
  428. asIScriptFunction* method = static_cast<asIScriptFunction*>(context_->GetHandler()->GetUserData());
  429. VariantVector parameters;
  430. if (method->GetParamCount() > 0)
  431. {
  432. parameters.push_back(Variant((void*)&eventType));
  433. parameters.push_back(Variant((void*)&eventData));
  434. }
  435. scriptFile_->Execute(scriptObject_, method, parameters);
  436. }
  437. Context* GetScriptContext()
  438. {
  439. return static_cast<Script*>(asGetActiveContext()->GetEngine()->GetUserData())->GetContext();
  440. }
  441. ScriptInstance* GetScriptContextInstance()
  442. {
  443. asIScriptContext* context = asGetActiveContext();
  444. void* object = context->GetThisPointer();
  445. std::map<void*, ScriptInstance*>& objectMap = static_cast<Script*>(context->GetEngine()->GetUserData())->GetObjectMap();
  446. std::map<void*, ScriptInstance*>::const_iterator i = objectMap.find(object);
  447. if (i != objectMap.end())
  448. return i->second;
  449. else
  450. return 0;
  451. }
  452. Node* GetScriptContextNode()
  453. {
  454. ScriptInstance* instance = GetScriptContextInstance();
  455. return instance ? instance->GetNode() : 0;
  456. }
  457. Scene* GetScriptContextScene()
  458. {
  459. Scene* scene = 0;
  460. Node* node = GetScriptContextNode();
  461. if (node)
  462. scene = node->GetScene();
  463. // If null, try to get the default scene
  464. if (!scene)
  465. scene = GetScriptContext()->GetSubsystem<Script>()->GetDefaultScene();
  466. return scene;
  467. }
  468. ScriptEventListener* GetScriptContextEventListener()
  469. {
  470. // First try to get the script instance. If not found, get the script file for procedural event handling
  471. ScriptInstance* instance = GetScriptContextInstance();
  472. if (instance)
  473. return instance;
  474. ScriptFile* file = GetScriptContextFile();
  475. return file;
  476. }
  477. Object* GetScriptContextEventListenerObject()
  478. {
  479. ScriptInstance* instance = GetScriptContextInstance();
  480. if (instance)
  481. return instance;
  482. ScriptFile* file = GetScriptContextFile();
  483. return file;
  484. }
  485. void ScriptInstance::HandleScriptFileReload(StringHash eventType, VariantMap& eventData)
  486. {
  487. ReleaseObject();
  488. }
  489. void ScriptInstance::HandleScriptFileReloadFinished(StringHash eventType, VariantMap& eventData)
  490. {
  491. if (!className_.empty())
  492. CreateObject();
  493. }