particlemanager.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. //! Flags for ParticleManagerSettings
  2. enum ParticleManagerSettingsFlags
  3. {
  4. NONE,
  5. //! Particles will be locked to the index and not reused
  6. FIXED_INDEX,
  7. //! Allocation blocks the game until it is done
  8. BLOCKING,
  9. //! Disable the creation of virtual particles when the pool is still allocating
  10. DISABLE_VIRTUAL,
  11. //! Reuse stopped particles even if they are owned by something
  12. REUSE_OWNED,
  13. };
  14. //! Class simply to have easily modded constants
  15. class ParticleManagerConstants
  16. {
  17. /** \name Global ParticleManager settings
  18. Settings applied to the global ParticleManager
  19. */
  20. //@{
  21. static const int POOL_SIZE = 10000;
  22. static const int FLAGS = ParticleManagerSettingsFlags.NONE;
  23. //@}
  24. }
  25. //! Settings given to ParticleManager on creation (in ctor)
  26. class ParticleManagerSettings
  27. {
  28. /**
  29. \brief Constructor (ctor)
  30. \param poolSize \p int Size of pool (amount of created and reserved particles)
  31. \param flags \p int ParticleManagerSettingsFlags
  32. */
  33. void ParticleManagerSettings(int poolSize, int flags = ParticleManagerSettingsFlags.NONE)
  34. {
  35. }
  36. //! dtor
  37. void ~ParticleManagerSettings()
  38. {
  39. }
  40. }
  41. //! Invokers for ParticleManager events
  42. class ParticleManagerEvents
  43. {
  44. ref ScriptInvoker Event_OnAllocation = new ScriptInvoker();
  45. ref ScriptInvoker Event_OnAllocationEnd = new ScriptInvoker();
  46. }
  47. //! Has a fixed pool of precreated and reserved particles
  48. class ParticleManager : Managed
  49. {
  50. //! Static ParticleManager
  51. private static ref ParticleManager g_ParticleManager;
  52. //! Access to the static ParticleManager
  53. static ParticleManager GetInstance()
  54. {
  55. if (!g_ParticleManager && !GetGame().IsDedicatedServer())
  56. {
  57. g_ParticleManager = new ParticleManager(
  58. new ParticleManagerSettings(
  59. ParticleManagerConstants.POOL_SIZE,
  60. ParticleManagerConstants.FLAGS));
  61. g_ParticleManager.SetName("GlobalParticleManager");
  62. }
  63. return g_ParticleManager;
  64. }
  65. //! To clean it up properly before game closes
  66. static void CleanupInstance()
  67. {
  68. if (g_ParticleManager)
  69. delete g_ParticleManager;
  70. }
  71. /**
  72. \brief Constructor (ctor)
  73. \param settings \p ParticleManagerSettings Settings for the ParticleManager
  74. */
  75. void ParticleManager(ParticleManagerSettings settings)
  76. {
  77. }
  78. //! dtor
  79. void ~ParticleManager()
  80. {
  81. }
  82. /** \name API for compatibility with Particle/ParticleSource create/play
  83. Mimics the static Create and Play methods from Particle/ParticleSource
  84. */
  85. //@{
  86. /**
  87. \brief Create function
  88. \param id \p int Particle ID registered in ParticleList
  89. \param pos \p vector Position of ParticleSource in LS (WS when no parent)
  90. \param playOnCreation \p bool Whether to play immediately after creation (Optional)
  91. \param parent \p Object Parent Object which will child the ParticleSource (Optional)
  92. \param ori \p vector Orientation of ParticleSource in LS (WS when no parent) (Pitch, Yaw, Roll in degrees) (Optional)
  93. \param forceWorldRotation \p bool Forces orientation to rotate relative to the world and not with the parent (Optional)
  94. \param owner \p Class The owning instance for this particle (Optional)
  95. \return \p ParticleSource Created particle instance when successful
  96. */
  97. ParticleSource CreateParticle( int id, vector pos, bool playOnCreation = false, Object parent = null, vector ori = vector.Zero, bool forceWorldRotation = false, Class owner = null )
  98. {
  99. int flags = ParticlePropertiesFlags.NONE;
  100. if (playOnCreation)
  101. {
  102. flags = flags | ParticlePropertiesFlags.PLAY_ON_CREATION;
  103. }
  104. if (forceWorldRotation)
  105. {
  106. flags = flags | ParticlePropertiesFlags.FORCE_WORLD_ROT;
  107. }
  108. return CreateParticleEx(id, pos, flags, parent, ori, owner);
  109. }
  110. /**
  111. \brief Master create function
  112. \param id \p int Particle ID registered in ParticleList
  113. \param pos \p vector Position of ParticleSource in LS (WS when no parent)
  114. \param flags \p int See ParticlePropertiesFlags (Optional)
  115. \param parent \p Object Parent Object which will child the ParticleSource (Optional)
  116. \param ori \p vector Orientation of ParticleSource in LS (WS when no parent) (Pitch, Yaw, Roll in degrees) (Optional)
  117. \param owner \p Class The owning instance for this particle (Optional)
  118. \return \p ParticleSource Created particle instance when successful
  119. */
  120. ParticleSource CreateParticleEx( int id, vector pos, int flags = ParticlePropertiesFlags.NONE, Object parent = null, vector ori = vector.Zero, Class owner = null )
  121. {
  122. string particlePath = ParticleList.GetParticleFullPath(id);
  123. if (particlePath == "") // There is already an error inside of ParticleList signaling this
  124. {
  125. ErrorEx(string.Format("Could not create ParticleSource as particle id %1 is invalid.", id));
  126. return null;
  127. }
  128. ParticleProperties props = new ParticleProperties(pos, flags, parent, ori, owner);
  129. ParticleSource p = CreateParticleByPath(particlePath, props);
  130. return p;
  131. }
  132. /**
  133. \brief Creates a particle emitter and attaches it on the given object
  134. \param particle_id \p int Particle ID registered in ParticleList
  135. \param parent_obj \p Object Instance on which this particle will be attached
  136. \param local_pos \p vector Attachment position local to the parent (Optional)
  137. \param local_ori \p vector Orientation local to the parent (Pitch, Yaw, Roll in degrees) (Optional)
  138. \param force_world_rotation \p bool Forces particle's orientation to rotate relative to the world and not with the object (Optional)
  139. \return \p ParticleSource Created particle instance
  140. */
  141. ParticleSource CreateOnObject(
  142. int particle_id,
  143. Object parent_obj,
  144. vector local_pos = "0 0 0",
  145. vector local_ori = "0 0 0",
  146. bool force_world_rotation = false )
  147. {
  148. return CreateParticle(particle_id, local_pos, false, parent_obj, local_ori, force_world_rotation);
  149. }
  150. /**
  151. \brief Legacy function for backwards compatibility
  152. */
  153. ParticleSource Create( int particle_id, Object parent_obj, vector local_pos = "0 0 0", vector local_ori = "0 0 0" )
  154. {
  155. return CreateOnObject( particle_id, parent_obj, local_pos, local_ori);
  156. }
  157. /**
  158. \brief Creates a particle emitter on the given position
  159. \param particle_id \p int Particle ID registered in ParticleList
  160. \param global_pos \p Vector Position where the particel will be created
  161. \param global_ori \p vector Orientation (Pitch, Yawn, Roll in degrees) (Optional)
  162. \param force_world_rotation \p bool Has absolutely no effect here as there is no parent
  163. \return \p ParticleSource Created particle instance
  164. */
  165. ParticleSource CreateInWorld( int particle_id, vector global_pos, vector global_ori = "0 0 0", bool force_world_rotation = false )
  166. {
  167. return CreateParticle(particle_id, global_pos, false, null, global_ori, force_world_rotation);
  168. }
  169. /**
  170. \brief Legacy function for backwards compatibility with 1.01 and below
  171. */
  172. ParticleSource Create( int particle_id, vector global_pos, vector global_ori = "0 0 0" )
  173. {
  174. return CreateInWorld( particle_id, global_pos, global_ori );
  175. }
  176. //@}
  177. /** \name Static play on creation
  178. You can use the following Play(...) functions to create and activate a particle in 1 line of your script.
  179. */
  180. //@{
  181. /**
  182. \brief Creates a particle emitter, attaches it on the given object and activates it
  183. \param particle_id \p int Particle ID registered in ParticleList
  184. \param parent_obj \p Object Instance on which this particle will be attached
  185. \param local_pos \p vector Attachment position local to the parent (Optional)
  186. \param local_ori \p vector Orientation local to the parent (Pitch, Yaw, Roll in degrees) (Optional)
  187. \param force_world_rotation \p bool Forces particle's orientation to rotate relative to the world and not with the object (Optional)
  188. \return \p ParticleSource Created particle instance
  189. */
  190. ParticleSource PlayOnObject(int particle_id, Object parent_obj, vector local_pos = "0 0 0", vector local_ori = "0 0 0", bool force_world_rotation = false )
  191. {
  192. return CreateParticle(particle_id, local_pos, true, parent_obj, local_ori, force_world_rotation);
  193. }
  194. /**
  195. \brief Legacy function for backwards compatibility with 1.01 and below
  196. */
  197. ParticleSource Play( int particle_id, Object parent_obj, vector local_pos = "0 0 0", vector local_ori = "0 0 0" )
  198. {
  199. return PlayOnObject( particle_id, parent_obj, local_pos, local_ori);
  200. }
  201. /**
  202. \brief Creates a particle emitter on the given position and activates it
  203. \param particle_id \p int Particle ID registered in ParticleList
  204. \param global_pos \p Vector Position where the particel will be created
  205. \return \p ParticleSource Created particle instance
  206. */
  207. ParticleSource PlayInWorld(int particle_id, vector global_pos)
  208. {
  209. return PlayInWorldEx(particle_id, null, global_pos);
  210. }
  211. ParticleSource PlayInWorldEx(int particle_id, Object parent_obj, vector global_pos, vector global_ori = "0 0 0", bool force_world_rotation = false)
  212. {
  213. return CreateParticle(particle_id, global_pos, true, parent_obj, global_ori, force_world_rotation);
  214. }
  215. /**
  216. \brief Legacy function for backwards compatibility with 1.01 and below
  217. */
  218. ParticleSource Play( int particle_id, vector global_pos)
  219. {
  220. return PlayInWorld( particle_id, global_pos);
  221. }
  222. //@}
  223. /** \name Get Particles
  224. API for creating, playing or obtaining particles from the pool
  225. */
  226. //@{
  227. /**
  228. \brief Creates an amount of particles with the properties given
  229. \param particles \p array<ParticleSource> The resulting particles if an array is given
  230. \param path \p string Path of particle effect
  231. \param properties \p ParticleProperties Properties of the particles created
  232. \param count \p int Amount of particles to create with these properties
  233. \return \p int Amount of particles created in this frame, if the ParticleManager is still allocating while this is called and virtual particles are enabled, the overflow particles will be virtual instead and not given in the out array
  234. */
  235. proto native int CreateParticles(array<ParticleSource> particles, string path, notnull ParticlePropertiesArray properties, int count = 1);
  236. /**
  237. \brief Create a particle
  238. \param path \p string Path of particle effect
  239. \param properties \p ParticleProperties Properties of the particles created
  240. \return \p ParticleSource The resulting particle
  241. */
  242. ParticleSource CreateParticleByPath(string path, notnull ParticleProperties properties)
  243. {
  244. array<ParticleSource> tempArr = new array<ParticleSource>;
  245. CreateParticles(tempArr, path, {properties}, 1);
  246. if (tempArr.Count() > 0)
  247. return tempArr[0];
  248. else
  249. return null;
  250. }
  251. /**
  252. \brief QoL function using script ParticleList, strongly recommend to read comments for CreateParticles as well
  253. \param id \p int ID of particle registered in ParticleList
  254. \param properties \p ParticleProperties Properties of the particles created
  255. \param count \p int Amount of particles to create with these properties
  256. \return \p int Amount of particles created in this frame, if the ParticleManager is still allocating while this is called and virtual particles are enabled, the overflow particles will be virtual instead
  257. */
  258. int CreateParticlesById(int id, notnull ParticlePropertiesArray properties, int count)
  259. {
  260. return CreateParticles(null, ParticleList.GetParticleFullPath(id), properties, count);
  261. }
  262. /**
  263. \brief QoL function using script ParticleList, strongly recommend to read comments for CreateParticles as well
  264. \param id \p int ID of particle registered in ParticleList
  265. \param properties \p ParticleProperties Properties of the particles created
  266. \param count \p int Amount of particles to create with these properties
  267. \return \p array<ParticleSource> The resulting particles - Read particles param of CreateParticles
  268. */
  269. array<ParticleSource> CreateParticlesByIdArr(int id, notnull ParticlePropertiesArray properties, int count)
  270. {
  271. array<ParticleSource> outArr = new array<ParticleSource>;
  272. CreateParticles(outArr, ParticleList.GetParticleFullPath(id), properties, count);
  273. return outArr;
  274. }
  275. /**
  276. \brief QoL function for when only one particle is needed using script ParticleList, strongly recommend to read comments for CreateParticles as well
  277. \param id \p int ID of particle registered in ParticleList
  278. \param properties \p ParticleProperties Properties of the particles created
  279. \return \p ParticleSource The resulting particle
  280. */
  281. ParticleSource CreateParticleById(int id, ParticleProperties properties)
  282. {
  283. array<ParticleSource> tempArr = new array<ParticleSource>;
  284. CreateParticles(tempArr, ParticleList.GetParticleFullPath(id), {properties}, 1);
  285. if (tempArr.Count() > 0)
  286. return tempArr[0];
  287. else
  288. return null;
  289. }
  290. /**
  291. \brief QoL function for when wanting to play a particle at a position right away
  292. \param particles \p array<ParticleSource> The resulting particles if an array is given
  293. \param path \p string Path of particle effect
  294. \param positions \p array<vector> Positions of particles
  295. \param count \p int Amount of particles to create at this position
  296. \return \p int Amount of particles created in this frame, if the ParticleManager is still allocating while this is called and virtual particles are enabled, the overflow particles will be virtual instead and not given in the out array
  297. */
  298. proto native int PlayParticles(out array<ParticleSource> particles, string path, notnull array<vector> positions, int count = 1);
  299. /**
  300. \brief QoL function using script ParticleList, strongly recommend to read comments for PlayParticles as well
  301. \param id \p int ID of particle registered in ParticleList
  302. \param positions \p array<vector> Positions of particles
  303. \param count \p int Amount of particles to create at this position
  304. \return \p array<ParticleSource> The resulting particles - Read particles param of PlayParticles
  305. */
  306. array<ParticleSource> PlayParticlesById(int id, array<vector> positions, int count)
  307. {
  308. array<ParticleSource> outArr = new array<ParticleSource>;
  309. PlayParticles(outArr, ParticleList.GetParticleFullPath(id), positions, count);
  310. return outArr;
  311. }
  312. /**
  313. \brief QoL function for when only one particle is needed using script ParticleList, strongly recommend to read comments for PlayParticles as well
  314. \param id \p int ID of particle registered in ParticleList
  315. \param positions \p array<vector> Positions of particles
  316. \return \p ParticleSource The resulting particle
  317. */
  318. ParticleSource PlayParticleById(int id, array<vector> position)
  319. {
  320. array<ParticleSource> tempArr = new array<ParticleSource>;
  321. PlayParticles(tempArr, ParticleList.GetParticleFullPath(id), position, 1);
  322. if (tempArr.Count() > 0)
  323. return tempArr[0];
  324. else
  325. return null;
  326. }
  327. /**
  328. \brief Manually get the particle at index
  329. \param index \p int Index of particle
  330. \return \p ParticleSource ParticleSource at given index
  331. */
  332. proto native ParticleSource GetParticle(int index);
  333. /**
  334. \brief Manually get a portion of the particles in the pool
  335. \param particles \p array<ParticleSource> The resulting particles
  336. \param startIndex \p int Starting index
  337. \param count \p int Amount of particles to get
  338. \return \p int Amount of particles in outArray
  339. */
  340. proto native int GetParticles(out array<ParticleSource> outArray, int startIndex, int count);
  341. /**
  342. \brief Manually get a portion of the particles in the pool
  343. \param startIndex \p int Starting index
  344. \param count \p int Amount of particles to get
  345. \return \p array<ParticleSource> The resulting particles
  346. */
  347. array<ParticleSource> GetParticlesEx(int startIndex, int count)
  348. {
  349. array<ParticleSource> outArr = new array<ParticleSource>;
  350. GetParticles(outArr, startIndex, count);
  351. return outArr;
  352. }
  353. //@}
  354. /** \name Identification
  355. Identification functionality
  356. */
  357. //@{
  358. /**
  359. \brief Set a name for the ParticleManager to identify it more easily
  360. \param name \p string Name for ParticleManager
  361. */
  362. proto native void SetName(string name);
  363. /**
  364. \brief Gets the name which is set for the ParticleManager, default is "ParticleSourceManager"
  365. \param name \p string Name of ParticleManager
  366. */
  367. proto string GetName();
  368. /**
  369. \brief Gets the debug name for the ParticleManager
  370. \param dbgName \p string "name:id"
  371. */
  372. proto string GetDebugNameNative();
  373. /**
  374. \brief Gets the debug name for the ParticleManager
  375. \return \p string "name:id"
  376. */
  377. override string GetDebugName()
  378. {
  379. return GetDebugNameNative();
  380. }
  381. /**
  382. \brief Gets the ID for the ParticleManager
  383. \return \p int ID for the ParticleManager (different every restart, as it is the nth instance created since the start of the program)
  384. */
  385. proto int GetCountID();
  386. /**
  387. \brief Gets the amount of ParticleManager that have been created since the start of the program
  388. \return \p int Amount of ParticleManager that have been created since the start of the program
  389. */
  390. proto native static int GetStaticCount();
  391. /**
  392. \brief Gets the amount of ParticleManager that are currently existing
  393. \return \p int Amount of ParticleManager that are currently existing
  394. */
  395. proto native static int GetStaticActiveCount();
  396. //@}
  397. /** \name Properties and state
  398. Obtain information about the state of the ParticleManager
  399. */
  400. //@{
  401. /**
  402. \brief Gets the fixed maximum size of the pool
  403. \return \p int The fixed maximum size of the pool
  404. */
  405. proto native int GetPoolSize();
  406. /**
  407. \brief Gets the amount of particles currently allocated
  408. \return \p int Amount of particles currently allocated
  409. */
  410. proto native int GetAllocatedCount();
  411. /**
  412. \brief Gets the amount of virtual particles
  413. \return \p int Amount of virtual particles currently waiting to be turned into real particles
  414. */
  415. proto native int GetVirtualCount();
  416. /**
  417. \brief Gets the amount of playing particles
  418. \return \p int Amount of currently playing particles
  419. */
  420. proto native int GetPlayingCount();
  421. /**
  422. \brief Checks if the ParticleManager has allocated all slots in the pool
  423. \return \p bool True when the number of allocated particles is the same as the pool size
  424. */
  425. proto native bool IsFinishedAllocating();
  426. //@}
  427. /** \name Script Events API
  428. Setting and getting of ScriptEvents
  429. */
  430. //@{
  431. /**
  432. \brief Set the events
  433. \param events \p Managed The events to set
  434. */
  435. private proto void SetScriptEvents(Managed events);
  436. /**
  437. \brief Get the events
  438. \return \p Managed If there is any events set, this will return them
  439. */
  440. private proto Managed GetScriptEvents();
  441. /**
  442. \brief Get the events
  443. \return \p ParticleManagerEvents If there is any events set, this will return them so that additional functionality can be bound to them
  444. */
  445. ParticleManagerEvents GetEvents()
  446. {
  447. return ParticleManagerEvents.Cast(GetScriptEvents());
  448. }
  449. //@}
  450. /** \name Events
  451. Events called from C++
  452. */
  453. //@{
  454. void OnAllocation(array<ParticleSource> allocatedParticles)
  455. {
  456. GetEvents().Event_OnAllocation.Invoke(this, allocatedParticles);
  457. }
  458. void OnAllocationEnd()
  459. {
  460. GetEvents().Event_OnAllocationEnd.Invoke(this);
  461. }
  462. //@}
  463. }