particlemanager.c 18 KB

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