Arma Reforger Explorer  1.1.0.42
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
DebrisSmallEntity.c
Go to the documentation of this file.
1 #define DEBUG
2 #define ENABLE_BASE_DESTRUCTION
3 //------------------------------------------------------------------------------------------------
4 [EntityEditorProps(category: "GameScripted/Debris", description: "Entity used to represent small chunks of debris. Automatically managed.", dynamicBox: true)]
5 class SCR_DebrisSmallEntityClass: GenericEntityClass
6 {
7 };
8 
9 //------------------------------------------------------------------------------------------------
15 {
16 #ifdef ENABLE_BASE_DESTRUCTION
17  private static int s_iDebrisMaximumCount = 1000;
20  private static ref array<SCR_DebrisSmallEntity> s_aDebrisSmallList = null;
21 
23  private bool m_bDelete = false;
25  private int m_iPriority = 0;
27  private float m_fLifeTime = 0.0;
29  private float m_fAgeTime = 0.0;
31  private float m_fMaxDistance = 0.0;
33  private Physics m_RigidBody = null;
37  private vector m_vSoundPositionLast;
39  private static const float MINIMAL_DISTANCE_SQ = 0.25;
41  private static const float MINIMAL_AGE = 0.25;
43  private AudioHandle m_AudioHandle = AudioHandle.Invalid;
45  private float m_fSoundThreshold;
47  private static const int KINETIC_ENERGY_THRESHOLD = 12;
48  #ifdef ENABLE_DIAG
49  private float m_fdVelocity;
52  private ref DebugTextWorldSpace m_Text;
54  private float m_fTextMax;
56  private float m_fTextAgeTime;
57  #endif
58 
60  static private int m_iSpawnedThisFrame = 0;
62  static private int m_iDebrisPerFrameLimit = 128;
63 
64  //------------------------------------------------------------------------------------------------
67  private bool IsGamePlaying()
68  {
69  if (GetGame().GetWorldEntity())
70  return true;
71  return false;
72  }
73 
74  //------------------------------------------------------------------------------------------------
76  private void RegisterDebris()
77  {
78  if (!IsGamePlaying())
79  return;
80 
81  // If array is not created, create it
82  if (!s_aDebrisSmallList)
83  {
84  s_aDebrisSmallList = new array<SCR_DebrisSmallEntity>();
85  }
86  // Insert element into the list
87  if (s_aDebrisSmallList)
88  {
89  s_aDebrisSmallList.Insert(this);
90  }
91  }
92 
93  //------------------------------------------------------------------------------------------------
95  private void UnregisterDebris()
96  {
97  if (!IsGamePlaying())
98  return;
99 
100  // If the array exists only
101  if (s_aDebrisSmallList)
102  {
103  // Remove the element, resize the array
104  // If no debris is left in the list, delete it
105  int idx = s_aDebrisSmallList.Find(this);
106  int count = s_aDebrisSmallList.Count();
107  if (idx >= 0)
108  {
109  s_aDebrisSmallList.Remove(idx);
110  s_aDebrisSmallList.Resize(count-1);
111 
112  if (s_aDebrisSmallList.Count() <= 0)
113  {
114  s_aDebrisSmallList = null;
115  }
116  }
117  }
118  }
119 
120  //------------------------------------------------------------------------------------------------
121  private static float GetDistanceToCamera(BaseWorld world, vector position)
122  {
123  vector cameraMat[4];
124  world.GetCurrentCamera(cameraMat);
125  return vector.Distance(cameraMat[3], position);
126  }
127 
128  //------------------------------------------------------------------------------------------------
129  override void EOnContact(IEntity owner, IEntity other, Contact contact)
130  {
131  if (m_bDelete)
132  return;
133 
134  float spdDiff = contact.GetRelativeNormalVelocityAfter() - contact.GetRelativeNormalVelocityBefore();
135 
136  // Play sound
137  if (spdDiff > m_fSoundThreshold && vector.DistanceSq(m_vSoundPositionLast, contact.Position) >= MINIMAL_DISTANCE_SQ && m_eMaterialSoundType != 0 && m_fAgeTime > MINIMAL_AGE)
138  PlaySound(contact.Position, spdDiff);
139 
140  // Sound debug
141  #ifdef ENABLE_DIAG
142  m_fdVelocity = spdDiff;
143  #endif
144 
145  if (spdDiff < 20)
146  return;
147 
148 
149  DeleteDebris();
150  }
151 
152  //------------------------------------------------------------------------------------------------
153  private void PlaySound(vector pos, float dVelocity)
154  {
155  SCR_SoundManagerEntity soundManagerEntity = GetGame().GetSoundManagerEntity();
156  if (!soundManagerEntity)
157  return;
158 
159  SCR_MPDestructionManager destructionManager = SCR_MPDestructionManager.GetInstance();
160  if (!destructionManager)
161  return;
162 
163  SCR_AudioSourceConfiguration audioSourceConfiguration = destructionManager.GetAudioSourceConfiguration();
164  if (!audioSourceConfiguration)
165  return;
166 
167  audioSourceConfiguration.m_sSoundEventName = SCR_SoundEvent.SOUND_MPD_ + typename.EnumToString(SCR_EMaterialSoundTypeDebris, m_eMaterialSoundType);
168  SCR_AudioSource audioSource = soundManagerEntity.CreateAudioSource(this, audioSourceConfiguration);
169  if (!audioSource)
170  return;
171 
172  // Stop previous sound
173  AudioSystem.TerminateSound(m_AudioHandle);
174 
175  // Set signals
176  audioSource.SetSignalValue(SCR_AudioSource.COLLISION_D_V_SIGNAL_NAME, dVelocity - m_fSoundThreshold);
177  audioSource.SetSignalValue(SCR_AudioSource.ENTITY_SIZE_SIGNAL_NAME, m_RigidBody.GetMass());
178 
179  // Get sound position
180  vector mat[4];
181  GetTransform(mat);
182  mat[3] = pos;
183 
184  // Play sound
185  soundManagerEntity.PlayAudioSource(audioSource, mat);
186  m_AudioHandle = audioSource.m_AudioHandle;
187 
188  // Store position of the last played sound
189  m_vSoundPositionLast = pos;
190 
191  // Sound Debug
192  #ifdef ENABLE_DIAG
193  if (DiagMenu.GetBool(SCR_DebugMenuID.DEBUGUI_SOUNDS_MPDESTRUCTION_SHOW_IMPULSEVALUES))
194  {
195  m_Text = DebugTextWorldSpace.Create(GetWorld(), dVelocity.ToString(1, 2) + "/" + m_fSoundThreshold.ToString(1, 2) + "/" + m_RigidBody.GetMass().ToString(), DebugTextFlags.FACE_CAMERA, pos[0], pos[1], pos[2], 20, COLOR_BLUE);
196  m_fTextAgeTime = m_fAgeTime + 1;
197  }
198  #endif
199  }
200 
201  //------------------------------------------------------------------------------------------------
202  override void EOnFrame(IEntity owner, float timeSlice)
203  {
204  // Get debris age
205  m_fAgeTime += timeSlice;
206 
207  // Delete this debris. (automatically unregisters)
208  if (m_fAgeTime >= m_fLifeTime)
209  {
210  DeleteDebris();
211  }
212 
213  // Check if within camera range, set to delete if not.
214  if (!m_bDelete)
215  {
216  float distance = GetDistanceToCamera(owner.GetWorld(), owner.GetOrigin());
217  if (distance >= m_fMaxDistance)
218  DeleteDebris();
219  }
220 
221  // If debris should be deleted then delete it.
222  if (m_bDelete)
223  {
224  if (m_RigidBody)
225  {
226  m_RigidBody.Destroy();
227  m_RigidBody = null;
228  }
229 
230  delete this;
231  }
232 
233  //Sound debug
234  #ifdef ENABLE_DIAG
235  if (DiagMenu.GetBool(SCR_DebugMenuID.DEBUGUI_SOUNDS_MPDESTRUCTION_SHOW_IMPULSEVALUES))
236  {
237  // Get center of entity
238  vector minsDebug;
239  vector maxsDebug;
240  owner.GetWorldBounds(minsDebug, maxsDebug);
241  vector centerDebug;
242  for (int i = 0; i < 3; i++)
243  {
244  centerDebug[i] = minsDebug[i] + Math.AbsFloat(((maxsDebug[i] - minsDebug[i]) * 0.5));
245  }
246 
247  // Hold peak velue for 1s
248  if (m_fAgeTime - m_fTextAgeTime > 1 || m_fdVelocity > m_fTextMax)
249  {
250  m_Text = DebugTextWorldSpace.Create(GetWorld(), m_fdVelocity.ToString(1, 2) + "/" + m_fSoundThreshold.ToString(1, 2) + "/" + m_RigidBody.GetMass().ToString(), DebugTextFlags.FACE_CAMERA, centerDebug[0], centerDebug[1], centerDebug[2], 20);
251  m_fTextMax = m_fdVelocity;
252  m_fTextAgeTime = m_fAgeTime;
253  }
254  }
255  #endif
256  }
257 
258  //------------------------------------------------------------------------------------------------
268  static SCR_DebrisSmallEntity SpawnDebris(BaseWorld world, vector mat[4], ResourceName model, float mass = 10, float lifeTime = 10.0, float maxDistance = 256.0, int priority = 1, vector linearVelocity = "0 0 0", vector angularVelocity = "0 0 0", string remap = "", bool isStatic = false, SCR_EMaterialSoundTypeDebris materialSoundType = 0)
269  {
270  if (m_iSpawnedThisFrame >= m_iDebrisPerFrameLimit)
271  return null;
272 
273  // Check if model is valid
274  if (model == string.Empty)
275  return null;
276 
277  // Check if model is not being spawned out of its range
278  if (GetDistanceToCamera(world, mat[3]) > maxDistance)
279  return null;
280 
281  SCR_DebrisSmallEntity entity = null;
282 
283  // See if this is first entity or not, if so, create the list
284  if (!s_aDebrisSmallList)
285  s_aDebrisSmallList = new array<SCR_DebrisSmallEntity>();
286 
287  // If the list exists, check count. If over limit, replate debris with lower priority by this one.
288  if (s_aDebrisSmallList)
289  {
290  int count = s_aDebrisSmallList.Count();
291  // Over the limit
292  if (count >= s_iDebrisMaximumCount)
293  {
294  for (int i = 0; i < s_aDebrisSmallList.Count(); i++)
295  {
296  if (s_aDebrisSmallList[i])
297  {
298  if (s_aDebrisSmallList[i].m_iPriority < priority)
299  {
300  entity = s_aDebrisSmallList[i];
301  break;
302  }
303  }
304  }
305  // TODO: Try out if this impacts performance or not (or how heavily)
306  if (entity)
307  {
308  if (entity.m_RigidBody)
309  {
310  entity.m_RigidBody.Destroy();
311  entity.m_RigidBody = null;
312  }
313  }
314  }
315  // Below the limit, spawn new one.
316  else
317  {
319  }
320  }
321 
322  // Spawning has failed? There was no possible replacement?
323  if (!entity)
324  return null;
325 
326  m_iSpawnedThisFrame++;
327  // Set newly spawned entity (or the one being reused)'s data to the new
328  entity.SetTransform(mat);
329  Resource resource = Resource.Load(model);
330  if (!resource)
331  return null;
332 
333  BaseResourceObject baseRes = resource.GetResource();
334  if (!baseRes)
335  return null;
336 
337  VObject obj = baseRes.ToVObject();
338  entity.SetObject(obj, remap);
339 
340  entity.m_fLifeTime = lifeTime;
341  entity.m_iPriority = priority;
342  entity.m_fMaxDistance = maxDistance;
343  entity.m_eMaterialSoundType = materialSoundType;
344 
345  // Get sound threshold
346  entity.m_fSoundThreshold = Math.Sqrt(2 * KINETIC_ENERGY_THRESHOLD / mass);
347 
348  // Set debris init position for sound
349  vector mins;
350  vector maxs;
351  entity.GetWorldBounds(mins, maxs);
352 
353  entity.m_vSoundPositionLast = vector.Lerp(mins, maxs, 0.5);
354 
355  // Set physics
356  if (!entity.m_RigidBody)
357  {
358  if (isStatic)
359  entity.m_RigidBody = Physics.CreateStatic(entity, -1);
360  else
361  {
362  entity.m_RigidBody = Physics.CreateDynamic(entity, mass, -1);
363  if (entity.m_RigidBody)
364  {
365  entity.m_RigidBody.SetVelocity(linearVelocity);
366  entity.m_RigidBody.SetAngularVelocity(angularVelocity * Math.DEG2RAD);
367  }
368 
369  //hotfix for debris getting stuck in terrain causing low fps
370  vector entityOrigin = entity.GetOrigin();
371  float terrainY = GetGame().GetWorld().GetSurfaceY(entityOrigin[0], entityOrigin[2]);
372  if (mins[1] < terrainY && maxs[1] > terrainY)
373  {
374  float newHeight = terrainY - mins[1] + entityOrigin[1] + 0.001;
375  entity.SetOrigin({entityOrigin[0], newHeight, entityOrigin[2]});
376  }
377  }
378 
379  if (entity.m_RigidBody)
380  entity.m_RigidBody.SetInteractionLayer(EPhysicsLayerDefs.Debris);
381  }
382 
383  return entity;
384  }
385 
386  //------------------------------------------------------------------------------------------------
388  //1 \param count The amount of debris to delete.
389  static void DeleteRandomDebris(int count = 1)
390  {
391  for (int i = 0; i < count; i++)
392  {
393  if (s_aDebrisSmallList)
394  {
395  if (s_aDebrisSmallList.Count() > 0)
396  {
397  SCR_DebrisSmallEntity ent = s_aDebrisSmallList.GetRandomElement();
398  if (ent)
399  {
400  ent.DeleteDebris();
401  }
402  }
403  }
404  }
405  }
406 
407  //------------------------------------------------------------------------------------------------
409  void DeleteDebris()
410  {
411  UnregisterDebris();
412  m_bDelete = true;
413  ClearEventMask(EntityEvent.CONTACT);
414  }
415 
416  //------------------------------------------------------------------------------------------------
417  override void EOnPostFrame(IEntity owner, float timeSlice)
418  {
419  m_iSpawnedThisFrame = 0;
420  }
421 
422  //------------------------------------------------------------------------------------------------
424  override void EOnInit(IEntity owner)
425  {
426  RegisterDebris();
427  }
428 
429  //------------------------------------------------------------------------------------------------
430  void SCR_DebrisSmallEntity(IEntitySource src, IEntity parent)
431  {
432  SetEventMask(EntityEvent.INIT | EntityEvent.FRAME | EntityEvent.POSTFRAME | EntityEvent.CONTACT);
433  SetFlags(EntityFlags.ACTIVE, true);
434  }
435 
436  //------------------------------------------------------------------------------------------------
437  void ~SCR_DebrisSmallEntity()
438  {
439  UnregisterDebris();
440  }
441 #endif
442 };
SCR_AudioSource
Definition: SCR_AudioSource.c:1
SpawnEntity
protected IEntity SpawnEntity(ResourceName entityResourceName, notnull IEntity slotOwner)
Definition: SCR_CatalogEntitySpawnerComponent.c:1008
EntityEditorProps
enum EQueryType EntityEditorProps(category:"GameScripted/Sound", description:"THIS IS THE SCRIPT DESCRIPTION.", color:"0 0 255 255")
Definition: SCR_AmbientSoundsComponent.c:12
GetGame
ArmaReforgerScripted GetGame()
Definition: game.c:1424
SCR_EMaterialSoundTypeDebris
SCR_EMaterialSoundTypeDebris
Definition: SCR_DestructionMultiPhaseComponent.c:3
SCR_SoundEvent
Definition: SCR_SoundEvent.c:1
GenericEntity
SCR_GenericBoxEntityClass GenericEntity
SCR_SoundManagerEntity
Definition: SCR_SoundManagerEntity.c:17
distance
float distance
Definition: SCR_DestructibleTreeV2.c:29
SCR_MPDestructionManager
Definition: SCR_MPDestructionManager.c:103
SCR_DebrisSmallEntity
Definition: DebrisSmallEntity.c:14
SCR_DebrisSmallEntityClass
Definition: DebrisSmallEntity.c:5
m_iPriority
int m_iPriority
Definition: SCR_AITalkRequest.c:28
SCR_DebugMenuID
SCR_DebugMenuID
This enum contains all IDs for DiagMenu entries added in script.
Definition: DebugMenuID.c:3
position
vector position
Definition: SCR_DestructibleTreeV2.c:30
m_eMaterialSoundType
SCR_EMaterialSoundTypeDebris m_eMaterialSoundType
Definition: SCR_DestructionBaseComponent.c:728
category
params category
Definition: SCR_VehicleDamageManagerComponent.c:180