Arma Reforger Explorer  1.1.0.42
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
SCR_DestructibleTreeV2.c
Go to the documentation of this file.
1 [EntityEditorProps(category: "GameScripted/TreeDestructionV2", description: "A tree entity that can be destroyed.", color: "0 0 255 255", visible: false, dynamicBox: true)]
2 class SCR_DestructibleTreeV2Class : TreeClass
3 {
4  [Attribute("200")]
5  float m_fDamageThreshold;
6 
7  [Attribute("30000")]
8  float m_fHealth;
9 
10  [Attribute("-1", desc: "Pick a prefab of the broken tree.")]
11  ref SCR_TreePartHierarchyV2 m_TreePartHierarchy;
12 
13  //------------------------------------------------------------------------------------------------
14  // constructor
16  void SCR_DestructibleTreeV2Class(BaseContainer prefab)
17  {
18 // Print("CreatePrefabData");
19 // Print(prefab.GetClassName());
20 // Print(prefab.GetName());
21 // Print(m_fDamageThreshold);
22 // Print(m_fHealth);
23  }
24 }
25 
26 class SCR_TreeTraceInfo
27 {
28  float impulse;
29  float distance;
30  vector position;
31  vector direction;
33 }
34 
36 {
37  int treePartIdx;
38  vector position;
39  float rotation[4];
40  bool isDynamic;
41  bool isParented;
42 }
43 
44 class SCR_ActiveTreeData
45 {
46  ref array<SCR_TreePartV2> m_aTreeParts = null;
47  ref array<ref SCR_TreeTraceInfo> m_aTreeTraceInfo = null;
48  ref array<ref SCR_DestroyedTreePartsData> m_aCachedTreePartsToDestroy = null;
49  ref array<int> m_aTreePartsToBreak = null;
50  float m_fDamage = 0;
52 }
53 
56 {
57 #ifdef ENABLE_DESTRUCTION
58  static const int INACTIVE_TREE_INDEX = -1;
59  static const int DESTROYED_TREE_INDEX = -2;
60 
61  static bool s_bPrintTreeDamage = 0;
62  static SCR_DestructibleTreesSynchManager synchManager = null;
63 
64  //THESE ARE RUNTIME
65  //private ref SCR_ActiveTreeData treeData = null;
66  private int m_iIndex = INACTIVE_TREE_INDEX;
67 
68  //------------------------------------------------------------------------------------------------
70  bool GetIsDestroyed()
71  {
72  return m_iIndex == DESTROYED_TREE_INDEX;
73  }
74 
75  //------------------------------------------------------------------------------------------------
77  void SetToDestroy(bool sentRPC = false)
78  {
79  SetEventMask(EntityEvent.FRAME);
80  SetFlags(EntityFlags.ACTIVE);
81 
82  if (RplSession.Mode() == RplMode.Client)
83  return;
84 
85  if (!sentRPC)
86  {
88  return;
89  EntityID id = GetID();
90  synchManager.SynchronizeSetToDestroy(id);
91  }
92  }
93 
94  //------------------------------------------------------------------------------------------------
97  private void Destroy()
98  {
99  //Print("Destroy");
100  if (!GetIsDestroyed())
101  {
102  Physics physics = GetPhysics();
103  if (physics)
104  physics.Destroy();
105  SetObject(null, "");
106 
107  //Store new the newly spawned prefab in child variable.
108  IEntity child = BuildHierarchy();
109 
110  if (!child)
111  child = GetChildren();
112  }
113 
114  if (m_iIndex < 0 || !synchManager)
115  return;
116 
117  SCR_ActiveTreeData treeData = synchManager.GetActiveTreeData(m_iIndex);
118 
119  if (treeData && treeData.m_aTreePartsToBreak)
120  {
121  foreach (int i : treeData.m_aTreePartsToBreak)
122  {
123  SetToBreak(i);
124  RemoveTreePartFromParent(i)
125  }
126 
127  treeData.m_aTreePartsToBreak.Clear();
128  treeData.m_aTreePartsToBreak = null;
129  }
130 
131  m_iIndex = DESTROYED_TREE_INDEX;
132 
133  // TODO: Hotfix calling update to ensure colliders are traceable in this frame, remove once engine handles this.
134  if (treeData && treeData.m_aTreeParts)
135  {
136  foreach (SCR_TreePartV2 treePart : treeData.m_aTreeParts)
137  {
138  treePart.Update();
139  }
140  }
141 
142  Trace();
143 
144  if (!treeData || !treeData.m_aCachedTreePartsToDestroy)
145  return;
146 
147  int cachedTreePartsCount = treeData.m_aCachedTreePartsToDestroy.Count();
148  for (int i = cachedTreePartsCount-1; i >= 0; i--)
149  {
150  SCR_TreePartV2 treePart = FindTreePart(treeData.m_aCachedTreePartsToDestroy[i].treePartIdx);
151  //Print(treePart);
152  if (treePart)
153  {
154  if (treeData.m_aCachedTreePartsToDestroy[i].isDynamic)
155  treePart.SetPhysics(true);
156  else
157  treePart.SetPhysics(false);
158  //Print(m_aCachedTreePartsToDestroy[i].isParented);
159  treePart.CachePosition(treeData.m_aCachedTreePartsToDestroy[i].position);
160  treePart.CacheRotation(treeData.m_aCachedTreePartsToDestroy[i].rotation);
161 // Print("Caching data rotation: ");
162 // Print(m_aCachedTreePartsToDestroy[i].rotation);
163  if (!treeData.m_aCachedTreePartsToDestroy[i].isParented)
164  treePart.ClientSetToBreakFromParent();
165  }
166  treeData.m_aCachedTreePartsToDestroy[i] = null;
167  treeData.m_aCachedTreePartsToDestroy.Remove(i);
168  }
169  treeData.m_aCachedTreePartsToDestroy.Clear();
170  treeData.m_aCachedTreePartsToDestroy = null;
171  }
172 
173  //------------------------------------------------------------------------------------------------
174  private IEntity BuildHierarchy()
175  {
177  if (!prefabData || !prefabData.m_TreePartHierarchy || prefabData.m_TreePartHierarchy.m_Prefab.GetPath() == "-1")
178  return null;
179 
180  if (m_iIndex < 0 || !synchManager)
181  return null;
182 
183  SCR_ActiveTreeData treeData = synchManager.GetActiveTreeData(m_iIndex);
184 
185  if (!treeData)
186  treeData = new SCR_ActiveTreeData();
187 
188  if (!treeData.m_aTreeParts)
189  treeData.m_aTreeParts = {};
190 
191  Resource resource = Resource.Load(prefabData.m_TreePartHierarchy.m_Prefab);
192  if (!resource.IsValid())
193  return null;
194 
195  vector mat[4];
196  GetTransform(mat);
197 
198  IEntity rootEnt = GetGame().SpawnEntityPrefab(resource);
199 
200  if (RplSession.Mode() == RplMode.Client)
201  AddChild(rootEnt, -1, EAddChildFlags.AUTO_TRANSFORM);
202  else
203  AddChild(rootEnt, -1, EAddChildFlags.NONE);
204 
205  rootEnt.SetTransform(mat);
206  SCR_TreePartV2 rootTreePart = SCR_TreePartV2.Cast(rootEnt);
207 
208  if (rootTreePart)
209  {
210  rootTreePart.m_vLockedOrigin = GetOrigin();
211  treeData.m_aTreeParts.Insert(rootTreePart);
212  }
213 
214  prefabData.m_TreePartHierarchy.SpawnAllChildren(rootEnt, treeData.m_aTreeParts);
215 
216  array<IEntity> children = {};
217  SCR_Global.GetHierarchyEntityList(rootEnt, children);
218 
219  foreach (SCR_TreePartV2 treePart : treeData.m_aTreeParts)
220  {
221  treePart.m_ParentTree = this;
222  }
223 
224  prefabData.m_TreePartHierarchy = null;
225 
226  return rootEnt;
227  }
228 
229  //------------------------------------------------------------------------------------------------
232  void SetRotationOfTreePart(int treePartIdx, float quat[4])
233  {
234  SCR_TreePartV2 foundTreePart = FindTreePart(treePartIdx);
235  if (!foundTreePart)
236  return;
237 
238  foundTreePart.SetRotation(quat);
239  }
240 
241  //------------------------------------------------------------------------------------------------
245  void CacheRotationOfTreePart(int treePartIdx, float quat[4])
246  {
247  SCR_TreePartV2 foundTreePart = FindTreePart(treePartIdx);
248 
249  if (!foundTreePart)
250  return;
251 
252  foundTreePart.CacheRotation(quat);
253  }
254 
255  //------------------------------------------------------------------------------------------------
259  void CacheSwitchTreePartPhysics(int treePartIdx, bool toDynamic)
260  {
261  SCR_TreePartV2 foundTreePart = FindTreePart(treePartIdx);
262 
263  if (!foundTreePart)
264  return;
265 
266  foundTreePart.SetPhysics(toDynamic);
267  }
268 
269  //------------------------------------------------------------------------------------------------
275  void ServerSetToBreak(int treePartIdx, vector positionVector, vector impulseVector, EDamageType damageType)
276  {
277  SCR_TreePartV2 foundTreePart = FindTreePart(treePartIdx);
278  if (!foundTreePart)
279  return;
280 
281  foundTreePart.SetToBreak(treePartIdx, positionVector, impulseVector, damageType);
282  }
283 
284  //------------------------------------------------------------------------------------------------
286  void SetToBreak(int treePartIdx)
287  {
288  SCR_TreePartV2 foundTreePart = FindTreePart(treePartIdx);
289 
290  if (!foundTreePart)
291  {
292  if (m_iIndex < 0 || !synchManager)
293  return;
294 
295  SCR_ActiveTreeData treeData = synchManager.GetActiveTreeData(m_iIndex);
296 
297  if (!treeData)
298  treeData = new SCR_ActiveTreeData();
299 
300  if (!treeData.m_aTreePartsToBreak)
301  treeData.m_aTreePartsToBreak = {};
302 
303  treeData.m_aTreePartsToBreak.Insert(treePartIdx);
304  return;
305  }
306 
307  foundTreePart.SetToBreak();
308  }
309 
310  //------------------------------------------------------------------------------------------------
313  void RemoveTreePartFromParent(int treePartIndex)
314  {
315  SCR_TreePartV2 foundTreePart = FindTreePart(treePartIndex);
316  if (!foundTreePart)
317  return;
318 
319  foundTreePart.RemoveFromParent();
320  }
321 
322  //------------------------------------------------------------------------------------------------
329  void CacheDestroyedTreePart(int treePartIdx, vector position, float quat[4], bool isDynamic, bool isParented)
330  {
332  data.treePartIdx = treePartIdx;
333  data.position[0] = position[0];
334  data.position[1] = position[1];
335  data.position[2] = position[2];
336  Math3D.QuatCopy(quat, data.rotation);
337  data.isDynamic = isDynamic;
338  data.isParented = isParented;
339 
340  if (m_iIndex < 0 || !synchManager)
341  return;
342 
343  SCR_ActiveTreeData treeData = synchManager.GetActiveTreeData(m_iIndex);
344 
345  if (!treeData)
346  treeData = new SCR_ActiveTreeData();
347 
348  if (!treeData.m_aCachedTreePartsToDestroy)
349  treeData.m_aCachedTreePartsToDestroy = {};
350 
351  treeData.m_aCachedTreePartsToDestroy.Insert(data);
352  }
353 
354  //------------------------------------------------------------------------------------------------
361  void UpdateTransformOfTreePart(int treePartIdx, vector pos, float quat[4], vector velocityLinear, vector velocityAngular)
362  {
363  SCR_TreePartV2 treePart = FindTreePart(treePartIdx);
364  if (!treePart)
365  return;
366 
367  treePart.UpdateTransform(pos, quat, velocityLinear, velocityAngular);
368  }
369 
370  //------------------------------------------------------------------------------------------------
373  void SetPositionOfTreePart(int treePartIdx, vector pos)
374  {
375  SCR_TreePartV2 foundTreePart = FindTreePart(treePartIdx);
376  if (!foundTreePart)
377  return;
378 
379  foundTreePart.SetPosition(pos);
380  }
381 
382  //------------------------------------------------------------------------------------------------
386  void CachePositionOfTreePart(int treePartIdx, vector pos)
387  {
388  SCR_TreePartV2 foundTreePart = FindTreePart(treePartIdx);
389  if (!foundTreePart)
390  return;
391 
392  foundTreePart.CachePosition(pos);
393  }
394 
395  //------------------------------------------------------------------------------------------------
399  void UpdateVelocityOfTreePart(int treePartIdx, vector velocity)
400  {
401  SCR_TreePartV2 foundTreePart = FindTreePart(treePartIdx);
402  if (!foundTreePart)
403  return;
404 
405  foundTreePart.SetVelocity(velocity);
406  }
407 
408  //------------------------------------------------------------------------------------------------
412  void UpdateAngularVelocityOfTreePart(int treePartIdx, vector angularVelocity)
413  {
414  SCR_TreePartV2 foundTreePart = FindTreePart(treePartIdx);
415  if (!foundTreePart)
416  return;
417 
418  foundTreePart.SetAngularVelocity(angularVelocity);
419  }
420 
421  //------------------------------------------------------------------------------------------------
424  void ClientSwitchTreePartToStatic(int treePartIdx)
425  {
426  SCR_TreePartV2 foundTreePart = FindTreePart(treePartIdx);
427  if (!foundTreePart)
428  return;
429 
430  foundTreePart.SetPhysics(false);
431  }
432 
433  //------------------------------------------------------------------------------------------------
440  void SetToTrace(vector position, vector direction, float impulse, float distance, EDamageType type, IEntity other)
441  {
442  SCR_TreeTraceInfo info = new SCR_TreeTraceInfo();
443  info.position = position;
444  info.direction = direction;
445  info.impulse = impulse;
446  info.distance = distance;
447  info.type = type;
448 
449  if (m_iIndex < 0 || !synchManager)
450  return;
451 
452  SCR_ActiveTreeData treeData = synchManager.GetActiveTreeData(m_iIndex);
453 
454  if (!treeData)
455  treeData = new SCR_ActiveTreeData();
456 
457  if (!treeData.m_aTreeTraceInfo)
458  treeData.m_aTreeTraceInfo = {};
459 
460  treeData.m_aTreeTraceInfo.Insert(info);
461  }
462 
463  //------------------------------------------------------------------------------------------------
465  void Trace()
466  {
467  if (m_iIndex < 0 || !synchManager)
468  return;
469 
470  SCR_ActiveTreeData treeData = synchManager.GetActiveTreeData(m_iIndex);
471 
472  if (!treeData || !treeData.m_aTreeTraceInfo)
473  return;
474 
475  int count = treeData.m_aTreeTraceInfo.Count();
476  for (int i = count - 1; i >= 0; i--)
477  {
478  SCR_TreeTraceInfo info = treeData.m_aTreeTraceInfo[i];
479 
480  if (info.type == EDamageType.EXPLOSIVE)
481  {
482  foreach (SCR_TreePartV2 treePart : treeData.m_aTreeParts)
483  {
484  if (treePart.m_bDebugDamage)
485  treePart.PrintDamageDebug(info.impulse, info.type);
486 
487  float reducedImpulse;
488  if (treePart.WouldBreak(info.impulse, info.type, reducedImpulse))
489  treePart.SetToBreak(positionVector: info.position, impulseVector: reducedImpulse * info.direction, damageType: info.type);
490  }
491  }
492  else
493  {
494  TraceSphere param = new TraceSphere();
495 
496  param.Radius = 0.1;
497  param.Start = info.position;
498  param.End = info.position + info.direction;
499  param.Flags = TraceFlags.WORLD | TraceFlags.ENTS;
500  param.LayerMask = EPhysicsLayerDefs.Camera; // is this a correct layer mask?
501 
502  SCR_Global.g_TraceFilterEnt = this;
503 
504  vector tracePos = GetWorld().TraceMove(param, SCR_Global.FilterCallback_IgnoreAllButEntityWithChildren) * (param.End - param.Start) + param.Start;
505 
506  IEntity traceEnt = param.TraceEnt;
507  if (traceEnt)
508  {
509  SCR_TreePartV2 tracedTreePart = SCR_TreePartV2.Cast(traceEnt);
510  if (tracedTreePart)
511  {
512  if (tracedTreePart.m_bDebugDamage)
513  tracedTreePart.PrintDamageDebug(info.impulse, info.type);
514 
515  float reducedImpulse;
516  if (tracedTreePart.WouldBreak(info.impulse, info.type, reducedImpulse))
517  tracedTreePart.SetToBreak(positionVector: info.position, impulseVector: reducedImpulse * info.direction, damageType: info.type);
518  }
519  }
520 
521  treeData.m_aTreeTraceInfo[i] = null;
522  }
523  }
524 
525  treeData.m_aTreeTraceInfo.Clear();
526  treeData.m_aTreeTraceInfo = null;
527  }
528 
529  //------------------------------------------------------------------------------------------------
530  void OnTreePartHitGround()
531  {
532  if (m_iIndex < 0 || !synchManager)
533  return;
534 
535  SCR_ActiveTreeData treeData = synchManager.GetActiveTreeData(m_iIndex);
536 
537  if (treeData.m_fTimeSinceLastSoundEvent < 0.5)
538  return;
539  treeData.m_fTimeSinceLastSoundEvent = 0;
540 
541  if (synchManager)
542  {
543  BaseSoundComponent soundComponent = synchManager.GetSoundComponent();
544  if (soundComponent)
545  soundComponent.PlayStr(SCR_SoundEvent.SOUND_HIT_GROUND);
546  }
547  }
548 
549  //------------------------------------------------------------------------------------------------
550  override void OnDamage(EDamageType type,
551  float damage,
552  HitZone pHitZone,
553  notnull Instigator instigator,
554  inout vector hitTransform[3],
555  float speed,
556  int colliderID,
557  int nodeID)
558  {
559  if (RplSession.Mode() == RplMode.Client)
560  return;
561 
562  if (s_bPrintTreeDamage)
563  Print(damage);
564 
566 
567  if (damage < prefabData.m_fDamageThreshold)
568  return;
569 
570  if (!synchManager)
571  return;
572 
573  if (m_iIndex < 0)
574  m_iIndex = synchManager.AddActiveTree();
575 
576  if (m_iIndex < 0)
577  return;
578 
579  SCR_ActiveTreeData treeData = synchManager.GetActiveTreeData(m_iIndex);
580 
581  treeData.m_fDamage += damage;
582  if (treeData.m_fDamage < prefabData.m_fHealth)
583  return;
584 
585  float distance = 0;
586  if (damageSource)
587  distance = (damageSource.GetOrigin() - GetOrigin()).Length() * 1.1;
588 
589  //Calculate impulse vector from direction vector and damage
590  vector positionVector = outMat[0];
591  vector direction = outMat[1];
592 
593  if (type == EDamageType.EXPLOSIVE)
594  {
595  positionVector = "0 0 0";
596  direction = (GetOrigin() - outMat[0]) * damage;
597  }
598 
599  vector position = outMat[0] + (-outMat[1] * 0.5); // Position of hit + normal of the hit
600 
601  direction.Normalize();
602 
603  Vehicle vehicle = Vehicle.Cast(damageSource);
604  if (vehicle)
605  SetToTrace(position, direction, damage, distance, type, vehicle);
606  else
607  SetToTrace(position, direction, damage, distance, type, null);
608 
609  SetToDestroy();
610  }
611 
612  //------------------------------------------------------------------------------------------------
613  private SCR_TreePartV2 FindTreePart(int treePartIdx)
614  {
615  if (m_iIndex < 0 || !synchManager)
616  return null;
617 
618  SCR_ActiveTreeData treeData = synchManager.GetActiveTreeData(m_iIndex);
619 
620  if (!treeData || !treeData.m_aTreeParts)
621  return null;
622 
623  foreach (SCR_TreePartV2 treePart : treeData.m_aTreeParts)
624  {
625  if (treePart.GetTreePartIndex() == treePartIdx)
626  return treePart;
627  }
628 
629  return null;
630  }
631 
632  //------------------------------------------------------------------------------------------------
633  override void EOnFrame(IEntity owner, float timeSlice)
634  {
635  if (m_iIndex < 0 || !synchManager)
636  return;
637 
638  SCR_ActiveTreeData treeData = synchManager.GetActiveTreeData(m_iIndex);
639 
640  if (!GetIsDestroyed())
641  {
642  Destroy();
643 
644  treeData.m_fTimeSinceLastSoundEvent = 0;
645  }
646 
647  treeData.m_fTimeSinceLastSoundEvent += timeSlice;
648 
649  if (treeData.m_fTimeSinceLastSoundEvent > 10)
650  {
651  treeData.m_fTimeSinceLastSoundEvent = 0;
652  ClearEventMask(EntityEvent.FRAME);
653  ClearFlags(EntityFlags.ACTIVE);
654  }
655  }
656 #endif
657 }
direction
vector direction
Definition: SCR_DestructibleTreeV2.c:31
GetPrefabData
SCR_VehicleDamageManagerComponentClass GetPrefabData()
Definition: SCR_VehicleDamageManagerComponent.c:260
EntityEditorProps
enum EQueryType EntityEditorProps(category:"GameScripted/Sound", description:"THIS IS THE SCRIPT DESCRIPTION.", color:"0 0 255 255")
Definition: SCR_AmbientSoundsComponent.c:12
SCR_DestructibleTreeV2Class
Definition: SCR_DestructibleTreeV2.c:2
HitZone
Definition: HitZone.c:12
OnDamage
override protected void OnDamage(notnull BaseDamageContext damageContext)
Definition: SCR_ArmorDamageManagerComponent.c:11
m_aTreePartsToBreak
ref array< int > m_aTreePartsToBreak
Definition: SCR_DestructibleTreeV2.c:49
Destroy
override bool Destroy()
Definition: SCR_EditableGroupComponent.c:460
GetGame
ArmaReforgerScripted GetGame()
Definition: game.c:1424
EOnFrame
override void EOnFrame(IEntity owner, float timeSlice)
Definition: SCR_PlayerProfileManagerComponent.c:199
SCR_SoundEvent
Definition: SCR_SoundEvent.c:1
desc
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
Definition: SCR_RespawnBriefingComponent.c:17
m_fTimeSinceLastSoundEvent
float m_fTimeSinceLastSoundEvent
Definition: SCR_DestructibleTreeV2.c:51
m_aCachedTreePartsToDestroy
ref array< ref SCR_DestroyedTreePartsData > m_aCachedTreePartsToDestroy
Definition: SCR_DestructibleTreeV2.c:48
Instigator
Definition: Instigator.c:6
if
if(!destructionManager) return
GetOrigin
vector GetOrigin()
Definition: SCR_AIUtilityComponent.c:279
impulse
SCR_DestructibleTreeV2Class impulse
SCR_TreePartV2
Definition: SCR_TreePartV2.c:8
m_fDamage
float m_fDamage
Definition: SCR_DestructibleTreeV2.c:50
Attribute
typedef Attribute
Post-process effect of scripted camera.
SCR_DestroyedTreePartsData
Definition: SCR_DestructibleTreeV2.c:35
distance
float distance
Definition: SCR_DestructibleTreeV2.c:29
GetID
int GetID()
Definition: SCR_AmbientPatrolSpawnPointComponent.c:65
EntityID
SCR_CompositionSlotManagerComponentClass EntityID
SCR_DestructibleTreeV2
Encapsulates the functionality of a destructible tree entity in the world.
Definition: SCR_DestructibleTreeV2.c:55
m_aTreeTraceInfo
ref array< ref SCR_TreeTraceInfo > m_aTreeTraceInfo
Definition: SCR_DestructibleTreeV2.c:47
SCR_TreePartHierarchyV2
Definition: SCR_TreePartHierarchyV2.c:3
SCR_DestructibleTreesSynchManager
Definition: SCR_DestructibleTreesSynchManager.c:6
m_aTreeParts
class SCR_DestroyedTreePartsData m_aTreeParts
m_iIndex
private int m_iIndex
Definition: SCR_StressTestGroupActivation.c:11
SCR_Global
Definition: Functions.c:6
type
EDamageType type
Definition: SCR_DestructibleTreeV2.c:32
EDamageType
EDamageType
Definition: EDamageType.c:12
GetChildren
void GetChildren(out array< SCR_ScenarioFrameworkLayerBase > children)
Definition: SCR_ScenarioFrameworkLayerBase.c:359
data
Get all prefabs that have the spawner data
Definition: SCR_EntityCatalogManagerComponent.c:305
position
vector position
Definition: SCR_DestructibleTreeV2.c:30
category
params category
Definition: SCR_VehicleDamageManagerComponent.c:180