Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
DebrisSmallEntity.c
Go to the documentation of this file.
1[EntityEditorProps(category: "GameScripted/Debris", description: "Entity used to represent small chunks of debris. Automatically managed.", dynamicBox: true)]
5
10class SCR_DebrisSmallEntity : SCR_BaseDebrisSmallEntity
11{
12#ifdef ENABLE_BASE_DESTRUCTION
14 private static int s_iDebrisMaximumCount = 1000;
15
17 private static ref array<SCR_DebrisSmallEntity> s_aDebrisSmallList = null;
18
20 private int m_iPriority;
21
23 private float m_fMaxDistance;
24
26 protected vector m_vSoundPositionLast;
27
29 protected float m_fSoundThreshold;
30
32 protected AudioHandle m_AudioHandle = AudioHandle.Invalid;
33
35 protected SCR_EMaterialSoundTypeDebris m_eMaterialSoundType;
36
38 protected bool m_bExteriorSource;
39
41 static private int s_iSpawnedThisFrame;
42
44 static private int s_iDebrisPerFrameLimit = 128;
45
46 //------------------------------------------------------------------------------------------------
48 protected void RegisterDebris()
49 {
50 if (!IsGamePlaying())
51 return;
52
53 // If array is not created, create it
54 if (!s_aDebrisSmallList)
55 s_aDebrisSmallList = {};
56
57 // Insert element into the list
58 if (s_aDebrisSmallList)
59 {
60 s_aDebrisSmallList.Insert(this);
61 }
62 }
63
64 //------------------------------------------------------------------------------------------------
66 private void UnregisterDebris()
67 {
68 if (!IsGamePlaying())
69 return;
70
71 // If the array exists only
72 if (s_aDebrisSmallList)
73 {
74 // Remove the element, resize the array
75 // If no debris is left in the list, delete it
76 int idx = s_aDebrisSmallList.Find(this);
77 int count = s_aDebrisSmallList.Count();
78 if (idx >= 0)
79 {
80 s_aDebrisSmallList.Remove(idx);
81 s_aDebrisSmallList.Resize(count-1);
82
83 if (s_aDebrisSmallList.Count() <= 0)
84 {
85 s_aDebrisSmallList = null;
86 }
87 }
88 }
89 }
90
91 //------------------------------------------------------------------------------------------------
92 override void EOnContact(IEntity owner, IEntity other, Contact contact)
93 {
94 if (m_bDelete)
95 return;
96
97 float spdDiff = contact.GetRelativeNormalVelocityAfter() - contact.GetRelativeNormalVelocityBefore();
98
99 // Play sound
100 if (spdDiff > m_fSoundThreshold && vector.DistanceSq(m_vSoundPositionLast, contact.Position) >= MINIMAL_DISTANCE_SQ && m_eMaterialSoundType != 0 && m_fAgeTime > MINIMAL_AGE)
101 PlaySound(contact.Position, spdDiff);
102
103 // Sound debug
104#ifdef ENABLE_DIAG
105 m_fdVelocity = spdDiff;
106#endif // ENABLE_DIAG
107
108 if (spdDiff < 20)
109 return;
110
111 DeleteDebris();
112 }
113
114 //------------------------------------------------------------------------------------------------
115 void PlaySound(vector pos, float dVelocity)
116 {
117 SCR_SoundManagerModule soundManager = SCR_SoundManagerModule.GetInstance(GetWorld());
118 if (!soundManager)
119 return;
120
121 SCR_MPDestructionManager destructionManager = SCR_MPDestructionManager.GetInstance();
122 if (!destructionManager)
123 return;
124
125 SCR_AudioSourceConfiguration audioSourceConfiguration = destructionManager.GetAudioSourceConfiguration();
126 if (!audioSourceConfiguration)
127 return;
128
129 // Override InteriorSignal flag
130 if (m_bExteriorSource)
131 audioSourceConfiguration.m_eFlags = SCR_Enum.SetFlag(audioSourceConfiguration.m_eFlags, EAudioSourceConfigurationFlag.ExteriorSource);
132 else
133 audioSourceConfiguration.m_eFlags = SCR_Enum.RemoveFlag(audioSourceConfiguration.m_eFlags, EAudioSourceConfigurationFlag.ExteriorSource);
134
135
136 audioSourceConfiguration.m_sSoundEventName = SCR_SoundEvent.SOUND_MPD_ + typename.EnumToString(SCR_EMaterialSoundTypeDebris, m_eMaterialSoundType);
137
138 SCR_AudioSource audioSource = soundManager.CreateAudioSource(this, audioSourceConfiguration, pos);
139 if (!audioSource)
140 return;
141
142 // Stop previous sound
143 AudioSystem.TerminateSound(m_AudioHandle);
144
145 // Set signals
146 audioSource.SetSignalValue(SCR_AudioSource.COLLISION_D_V_SIGNAL_NAME, dVelocity - m_fSoundThreshold);
147 audioSource.SetSignalValue(SCR_AudioSource.ENTITY_SIZE_SIGNAL_NAME, GetPhysics().GetMass());
148
149 // Play sound
150 soundManager.PlayAudioSource(audioSource);
151 m_AudioHandle = audioSource.m_AudioHandle;
152
153 // Store position of the last played sound
154 m_vSoundPositionLast = pos;
155
156 // Sound Debug
157#ifdef ENABLE_DIAG
158 SoundDebugPlaySound(m_fSoundThreshold, dVelocity, pos);
159#endif // ENABLE_DIAG
160 }
161
162 //------------------------------------------------------------------------------------------------
163 override void EOnFrame(IEntity owner, float timeSlice)
164 {
165 super.EOnFrame(owner, timeSlice);
166
167 // Check if within camera range, set to delete if not.
168 if (!m_bDelete)
169 {
170 const float distance = GetDistanceToCamera(owner.GetWorld(), owner.GetOrigin());
171 if (distance >= m_fMaxDistance)
172 DeleteDebris();
173 }
174
175 // Sound debug
176#ifdef ENABLE_DIAG
177 SoundDebugOnFrame(m_fSoundThreshold);
178#endif // ENABLE_DIAG
179 }
180
181 //------------------------------------------------------------------------------------------------
191 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, bool exteriorSource = false)
192 {
193 if (s_iSpawnedThisFrame >= s_iDebrisPerFrameLimit)
194 return null;
195
196 // Check if model is valid
197 if (model == string.Empty)
198 return null;
199
200 // Check if model is not being spawned out of its range
201 if (GetDistanceToCamera(world, mat[3]) > maxDistance)
202 return null;
203
204 SCR_DebrisSmallEntity entity = null;
205
206 // See if this is first entity or not, if so, create the list
207 if (!s_aDebrisSmallList)
208 s_aDebrisSmallList = {};
209
210 // If the list exists, check count. If over limit, replate debris with lower priority by this one.
211 if (s_aDebrisSmallList)
212 {
213 int count = s_aDebrisSmallList.Count();
214 // Over the limit
215 if (count >= s_iDebrisMaximumCount)
216 {
217 foreach(SCR_DebrisSmallEntity debrisSmallEntity : s_aDebrisSmallList)
218 {
219 if (debrisSmallEntity)
220 {
221 if (debrisSmallEntity.m_iPriority < priority)
222 {
223 entity = debrisSmallEntity;
224 break;
225 }
226 }
227 }
228 // TODO: Try out if this impacts performance or not (or how heavily)
229 if (entity)
230 {
231 Physics entityPhysics = entity.GetPhysics();
232 if (entityPhysics)
233 entityPhysics.Destroy();
234 }
235 }
236 // Below the limit, spawn new one.
237 else
238 {
239 entity = SCR_DebrisSmallEntity.Cast(GetGame().SpawnEntity(SCR_DebrisSmallEntity));
240 }
241 }
242
243 // Spawning has failed? There was no possible replacement?
244 if (!entity)
245 return null;
246
247 s_iSpawnedThisFrame++;
248 // Set newly spawned entity (or the one being reused)'s data to the new
249 entity.SetTransform(mat);
250 Resource resource = Resource.Load(model);
251 if (!resource)
252 return null;
253
254 BaseResourceObject baseRes = resource.GetResource();
255 if (!baseRes)
256 return null;
257
258 VObject obj = baseRes.ToVObject();
259 entity.SetObject(obj, remap);
260
261 entity.m_fLifeTime = lifeTime;
262 entity.m_iPriority = priority;
263 entity.m_fMaxDistance = maxDistance;
264 entity.m_eMaterialSoundType = materialSoundType;
265
266 // Store sound parameters
267 entity.m_fSoundThreshold = Math.Sqrt(2 * KINETIC_ENERGY_THRESHOLD / mass);
268
269 vector mins, maxs;
270 entity.GetWorldBounds(mins, maxs);
271 entity.m_vSoundPositionLast = vector.Lerp(mins, maxs, 0.5);
272
273 entity.m_bExteriorSource = exteriorSource;
274
275 // Set physics
276 Physics entityPhysics = entity.GetPhysics();
277 if (!entityPhysics)
278 {
279 if (isStatic)
280 {
281 entityPhysics = Physics.CreateStatic(entity, -1);
282 }
283 else
284 {
285 entityPhysics = Physics.CreateDynamic(entity, mass, -1);
286 if (entityPhysics)
287 {
288 //hotfix for debris getting stuck in terrain causing low fps
289 vector entityOrigin = entity.GetOrigin();
290 float terrainYMins = GetGame().GetWorld().GetSurfaceY(mins[0], mins[2]);
291 float terrainYMaxs = GetGame().GetWorld().GetSurfaceY(maxs[0], maxs[2]);
292
293 if ((mins[1] < terrainYMins || mins[1] < terrainYMaxs) && (maxs[1] > terrainYMins || maxs[1] > terrainYMaxs))
294 {
295 float highestTerrainY;
296 if (terrainYMaxs > terrainYMins)
297 highestTerrainY = terrainYMaxs;
298 else
299 highestTerrainY = terrainYMins;
300
301 float newHeight = highestTerrainY - mins[1] + entityOrigin[1] + 0.1;
302 entity.SetOrigin({entityOrigin[0], newHeight, entityOrigin[2]});
303 }
304
305 entityPhysics.SetVelocity(linearVelocity);
306 entityPhysics.SetAngularVelocity(angularVelocity * Math.DEG2RAD);
307 }
308 }
309
310 if (entityPhysics)
311 entityPhysics.SetInteractionLayer(EPhysicsLayerDefs.Debris);
312 }
313
314 return entity;
315 }
316
317 //------------------------------------------------------------------------------------------------
319 //1 \param count The amount of debris to delete.
320 static void DeleteRandomDebris(int count = 1)
321 {
322 for (int i = 0; i < count; i++)
323 {
324 if (s_aDebrisSmallList)
325 {
326 if (s_aDebrisSmallList.Count() > 0)
327 {
328 SCR_DebrisSmallEntity ent = s_aDebrisSmallList.GetRandomElement();
329 if (ent)
330 {
331 ent.DeleteDebris();
332 }
333 }
334 }
335 }
336 }
337
338 //------------------------------------------------------------------------------------------------
340 override void DeleteDebris()
341 {
342 UnregisterDebris();
343 super.DeleteDebris();
344 }
345
346 //------------------------------------------------------------------------------------------------
347 override void EOnPostFrame(IEntity owner, float timeSlice)
348 {
349 s_iSpawnedThisFrame = 0;
350 }
351
352 //------------------------------------------------------------------------------------------------
354 override void EOnInit(IEntity owner)
355 {
356 RegisterDebris();
357 }
358
359 //------------------------------------------------------------------------------------------------
360 void SCR_DebrisSmallEntity(IEntitySource src, IEntity parent)
361 {
362 SetEventMask(EntityEvent.INIT | EntityEvent.POSTFRAME | EntityEvent.CONTACT);
363 }
364
365 //------------------------------------------------------------------------------------------------
366 void ~SCR_DebrisSmallEntity()
367 {
368 UnregisterDebris();
369 }
370#endif // ENABLE_BASE_DESTRUCTION
371}
bool IsGamePlaying()
SCR_BaseDebrisSmallEntityClass m_bDelete
Whether this debris has reached end of its lifetime and should be deleted.
void SCR_BaseDebrisSmallEntity(IEntitySource src, IEntity parent)
float m_fAgeTime
Entity age in seconds. After this time is bigger thatn m_fLifeTime, debris will despawn.
void DeleteDebris()
Delete debris - unregisters it from the list and makes it scale down and delete.
ArmaReforgerScripted GetGame()
Definition game.c:1398
int m_iPriority
enum EAudioSourceFlag m_AudioHandle
Stores valid Audio handle.
void SCR_AudioSource(SCR_AudioSourceConfiguration audioSourceConfiguration, vector mat[4])
IEntity SpawnEntity(ResourceName entityResourceName, notnull IEntity slotOwner)
enum SCR_ECompassType EntityEditorProps(category:"GameScripted/Gadgets", description:"Compass", color:"0 0 255 255")
Prefab data class for compass component.
float distance
void PlaySound(string soundName)
override void EOnContact(IEntity owner, IEntity other, Contact contact)
override void EOnFrame(IEntity owner, float timeSlice)
enum EVehicleType IEntity
proto external vector GetOrigin()
proto external BaseWorld GetWorld()
SCR_AudioSourceConfiguration GetAudioSourceConfiguration()
override void EOnInit(IEntity owner)
EntityEvent
Various entity events.
Definition EntityEvent.c:14