effectmanager.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875
  1. /**
  2. \brief Manager class for managing Effect (EffectParticle, EffectSound)
  3. \warning Keeps a ref to any Effect registered (Created/Played), make sure to perform the necessary cleanup
  4. */
  5. class SEffectManager
  6. {
  7. //! Static map of all registered effects <id, Effect>
  8. protected static ref map<int, ref Effect> m_EffectsMap;
  9. //! Static array of IDs that were previously used, but freed up by unregistering
  10. protected static ref array<int> m_FreeEffectIDs;
  11. //! Counter for quickly getting the next ID if FreeEffectIDs array is empty
  12. protected static int m_HighestFreeEffectID = 1;
  13. //! As the counter starts at 1, Effect ID can never be 0
  14. static const int INVALID_ID = 0;
  15. //! Bool to check whether Cleanup is happening, which means that the maps should no longer be accessed
  16. protected static bool m_IsCleanup;
  17. //! Bool to check whether Init was called
  18. protected static bool m_IsInitialized;
  19. //! Static map of cached sound params, to prevent having to recreate them
  20. protected static ref map<string, ref SoundParams> m_ParamsMap;
  21. //! Static invoker for the SEffectManager.Event_OnFrameUpdate called form MissionGameplay.OnUpdate
  22. static ref ScriptInvoker Event_OnFrameUpdate;
  23. protected static ref map<int, EffecterBase> m_EffectersMap;
  24. //! Static array of IDs that were previously used, but freed up by unregistering Effecters
  25. protected static ref array<int> m_FreeEffecterIDs;
  26. protected static int m_HighestFreeEffecterID = 1;
  27. /** \name Generic playback
  28. Methods for playing Effect
  29. \note Since 1.15, these should work on EffectSound as well
  30. */
  31. //@{
  32. /**
  33. *\brief Play an Effect
  34. * \warning As the Effect is automatically registered, it will not be freed automatically (because of the ref)
  35. * Unless 'SetAutodestroy(true)' is called on the created 'Effect', which will clean it up when the sound stop
  36. * Alternatively, SEffectManager.DestroyEffect can be called manually, which will also unregister and cleanup
  37. * \param eff \p Effect The Effect to play
  38. * \param pos \p vector The position to play the Effect
  39. * \return \p int The registered ID of the Effect
  40. */
  41. static int PlayInWorld(notnull Effect eff, vector pos)
  42. {
  43. // Stop the effect first, just in case
  44. eff.Stop();
  45. int id = EffectRegister(eff);
  46. eff.SetPosition( pos );
  47. eff.Start();
  48. return id;
  49. }
  50. /**
  51. *\brief Play an Effect
  52. * \warning Read PlayInWorld warning
  53. * \param eff \p Effect The Effect to play
  54. * \param obj \p Object The parent of the Effect
  55. * \param local_pos \p vector The local position to play the Effect in relation to the parent (Optional)
  56. * \param local_ori \p vector The local orientation to play the Effect in relation to the parent (Optional)
  57. * \param force_rotation_relative_to_world \p bool Whether to force the orientation to stay in WS (Optional)
  58. * \return \p int The registered ID of the Effect
  59. */
  60. static int PlayOnObject(notnull Effect eff, Object obj, vector local_pos = "0 0 0", vector local_ori = "0 0 0", bool force_rotation_relative_to_world = false)
  61. {
  62. // Stop the effect first, just in case
  63. eff.Stop();
  64. int id = EffectRegister(eff);
  65. if (!obj)
  66. {
  67. ErrorEx("Parent object is null.", ErrorExSeverity.WARNING);
  68. eff.SetPosition(local_pos);
  69. }
  70. else
  71. {
  72. eff.SetPosition(obj.GetPosition());
  73. }
  74. eff.SetParent(obj);
  75. eff.SetLocalPosition(local_pos);
  76. eff.SetAttachedLocalOri(local_ori);
  77. if (force_rotation_relative_to_world)
  78. {
  79. EffectParticle eff_particle = EffectParticle.Cast(eff);
  80. if (eff_particle)
  81. {
  82. eff_particle.ForceParticleRotationRelativeToWorld(force_rotation_relative_to_world);
  83. }
  84. }
  85. eff.Start();
  86. return id;
  87. }
  88. /**
  89. \brief Stops the Effect
  90. \param effect_id \p int The ID of the Effect to Stop
  91. */
  92. static void Stop(int effect_id)
  93. {
  94. Effect eff = m_EffectsMap.Get(effect_id);
  95. if (eff)
  96. {
  97. eff.Stop();
  98. }
  99. else
  100. {
  101. ErrorEx(string.Format("Failed to stop Effect with ID %1. The ID is not registered in m_EffectsMap!", effect_id));
  102. }
  103. }
  104. //@}
  105. /** \name Create/Play sound
  106. Methods for playing/creating sound
  107. */
  108. //@{
  109. /**
  110. *\brief Create an EffectSound
  111. * \warning Read PlayInWorld warning
  112. * \param sound_set \p string The sound set name of the sound
  113. * \param position \p vector The position to play the sound
  114. * \param play_fade_in \p float The fade in duration of the sound (Optional)
  115. * \param stop_fade_out \p float The fade out duration of the sound (Optional)
  116. * \param loop \p bool Whether the sound should loop (Optional)
  117. * \param enviroment \p bool Whether to set environment variables (Optional)
  118. * \return \p EffectSound The created EffectSound
  119. */
  120. static EffectSound CreateSound(string sound_set, vector position, float play_fade_in = 0, float stop_fade_out = 0, bool loop = false, bool enviroment = false)
  121. {
  122. EffectSound effect_sound = new EffectSound();
  123. effect_sound.SetSoundSet(sound_set);
  124. effect_sound.SetPosition(position);
  125. effect_sound.SetSoundFadeIn(play_fade_in);
  126. effect_sound.SetSoundFadeOut(stop_fade_out);
  127. effect_sound.SetSoundLoop(loop);
  128. effect_sound.SetEnviromentVariables(enviroment);
  129. EffectRegister( effect_sound );
  130. return effect_sound;
  131. }
  132. /**
  133. *\brief Create and play an EffectSound
  134. * \warning Calls CreateSound, read CreateSound warning
  135. * \param sound_set \p string The sound set name of the sound
  136. * \param position \p vector The position to play the sound
  137. * \param play_fade_in \p float The fade in duration of the sound (Optional)
  138. * \param stop_fade_out \p float The fade out duration of the sound (Optional)
  139. * \param loop \p bool Whether the sound should loop (Optional)
  140. * \return \p EffectSound The created EffectSound
  141. */
  142. static EffectSound PlaySound(string sound_set, vector position, float play_fade_in = 0, float stop_fade_out = 0, bool loop = false)
  143. {
  144. EffectSound effect_sound = CreateSound(sound_set, position, play_fade_in, stop_fade_out, loop, false);
  145. effect_sound.SoundPlay();
  146. return effect_sound;
  147. }
  148. /**
  149. *\brief Create and play an EffectSound
  150. * \warning Calls CreateSound, read CreateSound warning
  151. * \param params \p SoundParams Params to create the sound with
  152. * \param position \p vector The position to play the sound
  153. * \param play_fade_in \p float The fade in duration of the sound (Optional)
  154. * \param stop_fade_out \p float The fade out duration of the sound (Optional)
  155. * \param loop \p bool Whether the sound should loop (Optional)
  156. * \return \p EffectSound The created EffectSound
  157. */
  158. static EffectSound PlaySoundParams(notnull SoundParams params, vector position, float play_fade_in = 0, float stop_fade_out = 0, bool loop = false)
  159. {
  160. EffectSound effect_sound = CreateSound(params.GetName(), position, play_fade_in, stop_fade_out, loop, false);
  161. effect_sound.SoundPlayEx(params);
  162. return effect_sound;
  163. }
  164. /**
  165. *\brief Create and play an EffectSound, using or creating cached SoundParams
  166. * \warning Calls CreateSound, read CreateSound warning
  167. * \param sound_set \p string The sound set name of the sound
  168. * \param position \p vector The position to play the sound
  169. * \param play_fade_in \p float The fade in duration of the sound (Optional)
  170. * \param stop_fade_out \p float The fade out duration of the sound (Optional)
  171. * \param loop \p bool Whether the sound should loop (Optional)
  172. * \return \p EffectSound The created EffectSound
  173. */
  174. static EffectSound PlaySoundCachedParams(string sound_set, vector position, float play_fade_in = 0, float stop_fade_out = 0, bool loop = false)
  175. {
  176. SoundParams params = GetCachedSoundParam(sound_set);
  177. EffectSound effect_sound = CreateSound(params.GetName(), position, play_fade_in, stop_fade_out, loop, false);
  178. effect_sound.SoundPlayEx(params);
  179. return effect_sound;
  180. }
  181. /**
  182. *\brief Create and play an EffectSound, updating environment variables
  183. * \warning Calls CreateSound, read CreateSound warning
  184. * \param sound_set \p string The sound set name of the sound
  185. * \param position \p vector The position to play the sound
  186. * \param play_fade_in \p float The fade in duration of the sound (Optional)
  187. * \param stop_fade_out \p float The fade out duration of the sound (Optional)
  188. * \param loop \p bool Whether the sound should loop (Optional)
  189. * \return \p EffectSound The created EffectSound
  190. */
  191. static EffectSound PlaySoundEnviroment(string sound_set, vector position, float play_fade_in = 0, float stop_fade_out = 0, bool loop = false)
  192. {
  193. EffectSound effect_sound = CreateSound(sound_set, position, play_fade_in, stop_fade_out, loop, true);
  194. effect_sound.SoundPlay();
  195. return effect_sound;
  196. }
  197. /**
  198. *\brief Create and play an EffectSound
  199. * \warning Calls CreateSound, read CreateSound warning
  200. * \param sound_set \p string The sound set name of the sound
  201. * \param parent_object \p Object The parent Object for the sound to follow
  202. * \param play_fade_in \p float The fade in duration of the sound (Optional)
  203. * \param stop_fade_out \p float The fade out duration of the sound (Optional)
  204. * \param loop \p bool Whether the sound should loop (Optional)
  205. * \return \p EffectSound The created EffectSound
  206. */
  207. static EffectSound PlaySoundOnObject(string sound_set, Object parent_object, float play_fade_in = 0, float stop_fade_out = 0, bool loop = false)
  208. {
  209. EffectSound effect_sound = CreateSound(sound_set, parent_object.GetPosition(), play_fade_in, stop_fade_out, loop);
  210. effect_sound.SetParent( parent_object );
  211. effect_sound.SetLocalPosition( vector.Zero );
  212. effect_sound.SoundPlay();
  213. return effect_sound;
  214. }
  215. //@}
  216. /** \name Generic API
  217. General methods used for SEffectManager
  218. */
  219. //@{
  220. /**
  221. \brief Unregisters, stops and frees the Effect
  222. \param effect_sound \p EffectSound The EffectSound to free
  223. */
  224. static void DestroyEffect(Effect effect)
  225. {
  226. if (effect)
  227. {
  228. if (effect.CanDestroy())
  229. {
  230. // Functionality already happens in dtor of Effect to be safe
  231. delete effect;
  232. }
  233. else
  234. {
  235. // Make it clean up itself when done
  236. effect.SetAutodestroy(true);
  237. effect.Stop();
  238. }
  239. }
  240. }
  241. /**
  242. \brief Checks whether an Effect ID is registered in SEffectManager
  243. \param effect_id \p int The Effect ID to check
  244. \return \p bool Whether there is an Effect registered for this ID
  245. */
  246. static bool IsEffectExist( int effect_id )
  247. {
  248. if (!m_IsCleanup)
  249. return m_EffectsMap[effect_id] != null;
  250. else
  251. return false;
  252. }
  253. /**
  254. \brief Gets the Effect with the given registered Effect ID
  255. \param effect_id \p int The Effect ID
  256. \return \p Effect The Effect registered to the ID or null
  257. */
  258. static Effect GetEffectByID(int effect_id)
  259. {
  260. if (!m_IsCleanup)
  261. return m_EffectsMap[effect_id];
  262. else
  263. return null;
  264. }
  265. /**
  266. \brief Registers Effect in SEffectManager
  267. \note Already handled in SEffectManager Create/Play methods
  268. \note This will make SEffectManager hold a strong ref for the Effect
  269. \param effect \p Effect The Effect to register
  270. \return \p int The Effect ID
  271. */
  272. static int EffectRegister(Effect effect)
  273. {
  274. if (effect.IsRegistered())
  275. {
  276. ErrorEx(string.Format("Attempted to register Effect '%1' which was already registered.", effect.GetDebugName()), ErrorExSeverity.INFO);
  277. return effect.GetID();
  278. }
  279. int id;
  280. if (!m_IsCleanup)
  281. {
  282. id = GetFreeEffectID();
  283. m_EffectsMap.Insert(id, effect);
  284. effect.Event_OnRegistered(id);
  285. }
  286. else
  287. ErrorEx("Attempted to register Effect while SEffectManager is cleaning up, request ignored.", ErrorExSeverity.WARNING);
  288. return id;
  289. }
  290. protected static int GetFreeEffecterID()
  291. {
  292. int return_id;
  293. if (m_FreeEffecterIDs.Count() > 0)
  294. {
  295. return_id = m_FreeEffecterIDs.Get(0);
  296. m_FreeEffecterIDs.Remove(0);
  297. }
  298. else
  299. {
  300. return_id = m_HighestFreeEffecterID;
  301. ++m_HighestFreeEffecterID;
  302. }
  303. return return_id;
  304. }
  305. /**
  306. \brief Unregisters Effect in SEffectManager
  307. \note Will automatically occur on stop when the Effect is AutoDestroy
  308. \note ID can be gotten from the Effect by calling Effect.GetID
  309. \note Generic Play methods will also return the ID
  310. \param id \p int The ID of the Effect to unregister
  311. */
  312. static void EffectUnregister(int id)
  313. {
  314. if (m_IsCleanup)
  315. return; // No error needed, since it will have been unregistered anyways after cleanup is finished
  316. Effect effect;
  317. if ( m_EffectsMap.Find(id, effect) )
  318. {
  319. effect.Event_OnUnregistered();
  320. m_EffectsMap.Remove(id);
  321. }
  322. if ( m_FreeEffectIDs.Find(id) == -1 )
  323. {
  324. m_FreeEffectIDs.Insert(id);
  325. }
  326. }
  327. /**
  328. \brief Unregisters Effect in SEffectManager
  329. \param effect \p Effect The Effect to unregister
  330. */
  331. static void EffectUnregisterEx(Effect effect)
  332. {
  333. EffectUnregister(effect.GetID());
  334. }
  335. /**
  336. \brief Helper function for EffectRegister to decide an Effect ID
  337. \return \p int A currently unused Effect ID
  338. */
  339. protected static int GetFreeEffectID()
  340. {
  341. int return_id;
  342. if (m_FreeEffectIDs.Count() > 0)
  343. {
  344. return_id = m_FreeEffectIDs.Get(0);
  345. m_FreeEffectIDs.Remove(0);
  346. }
  347. else
  348. {
  349. return_id = m_HighestFreeEffectID;
  350. ++m_HighestFreeEffectID;
  351. }
  352. return return_id;
  353. }
  354. //@}
  355. /** \name Sound helpers
  356. Sound specific helper methods
  357. */
  358. //@{
  359. /**
  360. \brief Legacy, backwards compatibility
  361. \param sound_effect \p EffectSound The EffectSound to free
  362. \return \p bool A bool which is always true
  363. */
  364. static bool DestroySound(EffectSound sound_effect)
  365. {
  366. DestroyEffect(sound_effect);
  367. return true;
  368. }
  369. /**
  370. \brief Get or create a cached SoundParams object
  371. \param soundset \p string The sound set name of the sound
  372. \return \p SoundParams The cached SoundParams for the given soundset
  373. */
  374. static SoundParams GetCachedSoundParam(string soundset)
  375. {
  376. SoundParams params;
  377. if (!m_ParamsMap.Find(soundset, params))
  378. {
  379. params = new SoundParams(soundset);
  380. m_ParamsMap.Insert(soundset, params);
  381. }
  382. return params;
  383. }
  384. //@}
  385. /** \name Events
  386. Various events that can be overriden for custom behaviour
  387. */
  388. //@{
  389. /**
  390. \brief Event called from EffectSound.Event_OnSoundWaveEnded
  391. \note Every registered sound is registered to call this
  392. \param effect_sound \p EffectSound The EffectSound calling the event
  393. */
  394. static void Event_OnSoundWaveEnded(EffectSound effect_sound)
  395. {
  396. }
  397. /**
  398. \brief Event called on frame
  399. \note Called from MissionGameplay.OnUpdate
  400. \note Effects register themselves by Effect.SetEnableEventFrame(true)
  401. \note EffectSound is automatically registered
  402. \param time_delta \p float Time passed since the previous frame
  403. */
  404. static void Event_OnFrameUpdate(float time_delta)
  405. {
  406. Event_OnFrameUpdate.Invoke(time_delta);
  407. }
  408. //@}
  409. /** \name Lifetime
  410. Creation and cleanup
  411. */
  412. //@{
  413. /**
  414. \brief Initialize the containers
  415. \note This is done this way, to have these not exist on server
  416. */
  417. static void Init()
  418. {
  419. m_EffectsMap = new map<int, ref Effect>;
  420. m_FreeEffectIDs = new array<int>;
  421. m_ParamsMap = new map<string, ref SoundParams>;
  422. Event_OnFrameUpdate = new ScriptInvoker();
  423. m_IsInitialized = true;
  424. }
  425. static void InitServer()
  426. {
  427. m_EffectersMap = new map<int, EffecterBase>;
  428. m_FreeEffecterIDs = new array<int>;
  429. }
  430. /**
  431. \brief Cleanup method to properly clean up the static data
  432. \note Will be called when MissionBase is destroyed
  433. */
  434. static void Cleanup()
  435. {
  436. // Nothing to clean
  437. if (!m_IsInitialized)
  438. return;
  439. m_IsCleanup = true;
  440. // There should not be anything in here on server
  441. if (GetGame() && GetGame().IsDedicatedServer())
  442. {
  443. if (m_ParamsMap.Count() > 0)
  444. ErrorEx(string.Format("SEffectManager containing SoundParams on server."), ErrorExSeverity.WARNING);
  445. if (m_EffectsMap.Count() > 0)
  446. ErrorEx(string.Format("SEffectManager containing Effect on server."), ErrorExSeverity.WARNING);
  447. }
  448. // These are intentionally cached, just clear them
  449. m_ParamsMap.Clear();
  450. // These might not be intentionally still here, so log how many there are
  451. #ifdef DEVELOPER
  452. Print("--- SEffectManager Cleanup dump - Begin ------------------------");
  453. Print(string.Format("Effect count: %1", m_EffectsMap.Count()));
  454. #endif
  455. // Best to call the unregister event before clearing the map
  456. // In case some ref is still being held elsewhere and will still be kept alive
  457. foreach (int id, Effect eff : m_EffectsMap)
  458. {
  459. eff.Event_OnUnregistered();
  460. #ifdef SFXM_DUMP
  461. Print(string.Format( "%1 :: %2 :: %3", eff, typename.EnumToString(EffectType, eff.GetEffectType()), eff.GetDebugName() ));
  462. #endif
  463. }
  464. foreach (int i, EffecterBase effecter : m_EffectersMap)
  465. {
  466. effecter.Delete();
  467. }
  468. #ifdef DEVELOPER
  469. Print("--- SEffectManager Cleanup dump - End --------------------------");
  470. #endif
  471. // Now we can clear it
  472. m_EffectsMap.Clear();
  473. m_EffectersMap.Clear();
  474. // Reset the state
  475. m_HighestFreeEffectID = 1;
  476. Event_OnFrameUpdate.Clear();
  477. m_IsCleanup = false;
  478. }
  479. //@}
  480. //! returns unique effecter ID
  481. static int CreateParticleServer(vector pos, EffecterParameters parameters)
  482. {
  483. EffecterBase eff;
  484. eff = EffecterBase.Cast(GetGame().CreateObjectEx(parameters.m_EffecterType, pos, ECE_PLACE_ON_SURFACE));
  485. if (eff)
  486. {
  487. int id = GetFreeEffecterID();
  488. m_EffectersMap.Insert(id, eff);
  489. }
  490. eff.Init(id, parameters);
  491. return id;
  492. }
  493. //! allows re-initializing existing effecter with new parameters (extept m_EffecterType, obviously)
  494. static void ReinitParticleServer(int effecterID, EffecterParameters parameters)
  495. {
  496. EffecterBase eff = m_EffectersMap.Get(effecterID);
  497. if (eff)
  498. {
  499. eff.Init(effecterID,parameters);
  500. }
  501. }
  502. static void ReactivateParticleServer(int effecterID)
  503. {
  504. EffecterBase eff = m_EffectersMap.Get(effecterID);
  505. if (eff)
  506. {
  507. eff.Reactivate();
  508. }
  509. }
  510. static void StartParticleServer(int effecterID)
  511. {
  512. EffecterBase eff = m_EffectersMap.Get(effecterID);
  513. if (eff)
  514. {
  515. eff.Start();
  516. }
  517. }
  518. static void StopParticleServer(int effecterID)
  519. {
  520. EffecterBase eff = m_EffectersMap.Get(effecterID);
  521. if (eff)
  522. {
  523. eff.Stop();
  524. }
  525. }
  526. static void DestroyEffecterParticleServer(int effecterID)
  527. {
  528. EffecterBase eff = m_EffectersMap.Get(effecterID);
  529. if (eff)
  530. {
  531. m_EffectersMap.Remove(effecterID);
  532. eff.DeleteSafe();
  533. }
  534. }
  535. static void OnUpdate(float timeslice)
  536. {
  537. if (m_EffectersMap)
  538. {
  539. foreach (int i, EffecterBase effecter : m_EffectersMap)
  540. {
  541. effecter.DecreaseLifespan(timeslice);
  542. }
  543. }
  544. }
  545. }
  546. enum EffecterCommands
  547. {
  548. NONE = -1,
  549. START,
  550. STOP,
  551. REACTIVATE0,
  552. REACTIVATE1
  553. }
  554. class EffecterParameters
  555. {
  556. string m_EffecterType;
  557. float m_Lifespan;
  558. void EffecterParameters(string type, float lifespan)
  559. {
  560. m_EffecterType = type;
  561. m_Lifespan = lifespan;
  562. }
  563. }
  564. class ParticleEffecterParameters : EffecterParameters
  565. {
  566. int m_ParticleID;
  567. void ParticleEffecterParameters(string type, float lifespan, int particleID)
  568. {
  569. m_ParticleID = particleID;
  570. }
  571. }
  572. class EffecterBase : EntityAI
  573. {
  574. const float NOT_DEFINED_LIFESPAN = -1;
  575. protected float m_Lifespan;
  576. protected int m_ID;
  577. protected int m_Command = EffecterCommands.NONE;
  578. protected int m_CommandSync = EffecterCommands.NONE;
  579. void EffecterBase()
  580. {
  581. RegisterNetSyncVariableInt("m_CommandSync");
  582. }
  583. void Init(int id, EffecterParameters parameters)
  584. {
  585. m_ID = id;
  586. SetLifespan(parameters.m_Lifespan);
  587. }
  588. void DecreaseLifespan(float timeSlice)
  589. {
  590. if (m_Lifespan == NOT_DEFINED_LIFESPAN)
  591. return;
  592. m_Lifespan -= timeSlice;
  593. if (m_Lifespan < 0)
  594. {
  595. SEffectManager.DestroyEffecterParticleServer(m_ID);
  596. }
  597. }
  598. void SetLifespan(float lifespan)
  599. {
  600. m_Lifespan = lifespan;
  601. }
  602. void Start()
  603. {
  604. m_CommandSync = EffecterCommands.START;
  605. Process();
  606. }
  607. void Stop()
  608. {
  609. m_CommandSync = EffecterCommands.STOP;
  610. Process();
  611. }
  612. void Reactivate()
  613. {
  614. if (m_CommandSync == EffecterCommands.REACTIVATE0)
  615. {
  616. m_CommandSync = EffecterCommands.REACTIVATE1;
  617. }
  618. else
  619. {
  620. m_CommandSync = EffecterCommands.REACTIVATE0;
  621. }
  622. Process();
  623. }
  624. void Process()
  625. {
  626. if (GetGame().IsMultiplayer())
  627. {
  628. SetSynchDirty();
  629. }
  630. else
  631. {
  632. OnVariablesSynchronized();
  633. }
  634. }
  635. override int GetHideIconMask()
  636. {
  637. return EInventoryIconVisibility.HIDE_VICINITY;
  638. }
  639. }
  640. class ParticleEffecter : EffecterBase
  641. {
  642. protected int m_ParticleEffectID = -1;
  643. protected int m_ParticleEffectIDSync = -1;
  644. protected ref EffectParticleGeneral m_Effect = null;
  645. //protected int m_EffectID = -1;
  646. void ParticleEffecter(int lifespan)
  647. {
  648. RegisterNetSyncVariableInt("m_ParticleEffectIDSync");
  649. }
  650. override void Init(int id, EffecterParameters parameters)
  651. {
  652. super.Init(id, parameters);
  653. ParticleEffecterParameters par = ParticleEffecterParameters.Cast(parameters);
  654. SetParticle(par.m_ParticleID);
  655. }
  656. void SetParticle(int particleID)
  657. {
  658. m_ParticleEffectIDSync = particleID;
  659. Process();
  660. }
  661. override void OnVariablesSynchronized()
  662. {
  663. if (m_ParticleEffectIDSync != m_ParticleEffectID)
  664. {
  665. if (m_Effect)
  666. {
  667. m_Effect.SetParticle(m_ParticleEffectIDSync);
  668. }
  669. else
  670. {
  671. m_Effect = new EffectParticleGeneral();
  672. m_Effect.SetParticle(m_ParticleEffectIDSync);
  673. SEffectManager.PlayInWorld(m_Effect, GetWorldPosition());
  674. }
  675. m_ParticleEffectID = m_ParticleEffectIDSync;
  676. }
  677. if (m_CommandSync != m_Command)
  678. {
  679. switch (m_CommandSync)
  680. {
  681. case EffecterCommands.START:
  682. if (m_Effect && !m_Effect.IsPlaying())
  683. {
  684. m_Effect.SetParticle(m_ParticleEffectID);
  685. m_Effect.Start();
  686. }
  687. break;
  688. case EffecterCommands.STOP:
  689. if (m_Effect && m_Effect.IsPlaying())
  690. {
  691. m_Effect.Stop();
  692. }
  693. break;
  694. case EffecterCommands.REACTIVATE0:
  695. case EffecterCommands.REACTIVATE1:
  696. if (m_Effect)
  697. {
  698. m_Effect.SetParticle(m_ParticleEffectID);
  699. }
  700. if (!m_Effect.IsPlaying())
  701. {
  702. m_Effect.Start();
  703. }
  704. break;
  705. default:
  706. break;
  707. }
  708. m_Command = m_CommandSync;
  709. }
  710. }
  711. void ~ParticleEffecter()
  712. {
  713. SEffectManager.DestroyEffect(m_Effect);
  714. }
  715. }
  716. class EffectParticleGeneral : EffectParticle
  717. {
  718. int m_LastParticleID;
  719. void EffectParticleGeneral()
  720. {
  721. }
  722. void SetParticle( int particleID )
  723. {
  724. bool was_playing = IsPlaying();
  725. Stop();
  726. SetParticleID(particleID);
  727. if (was_playing)
  728. {
  729. Start();
  730. }
  731. }
  732. override void SetParticleID( int id )
  733. {
  734. super.SetParticleID(id);
  735. m_LastParticleID = id;
  736. }
  737. }