1 [
EntityEditorProps(
category:
"GameScripted/TreeDestructionV2", description:
"A part of tree that reacts to damage.", color:
"0 0 255 255", visible:
false, dynamicBox:
true)]
13 [
Attribute(
"1", UIWidgets.EditBox,
"Enter the mass of this tree part.",
category:
"Physics settings")]
14 private float m_fMass;
15 [
Attribute(
"9", UIWidgets.EditBox,
"Enter the max linear acceleration of this tree part for each local axis.",
category:
"Physics settings")]
16 private float m_fMaxAccelerationLinear;
17 [
Attribute(
"5 5 5", UIWidgets.EditBox,
"Enter the max angular acceleration of this tree part.",
category:
"Physics settings")]
18 private vector m_vMaxAccelerationAngular;
19 [
Attribute(
"0.05", UIWidgets.EditBox,
"Enter the max speed of rotation around local Y axis of this tree part.",
category:
"Physics settings")]
20 private float m_fMaxYRotationVelocity;
21 [
Attribute(
"1", UIWidgets.CheckBox,
"Allow linear movement of this object?",
category:
"Physics settings")]
22 private bool m_bAllowLinearMovement;
23 [
Attribute(
"1", UIWidgets.CheckBox,
"Allow rotation around global Y axis of this object?",
category:
"Physics settings")]
24 private bool m_bAllowGlobalYRotation;
25 [
Attribute(
"200", UIWidgets.EditBox,
"Enter the max joint load.",
category:
"Physics settings")]
26 private float m_fMaxJointLoad;
31 [
Attribute(
"1", UIWidgets.EditBox,
"Enter the minimum impact that should be able to move with this object. Impact = reduced impulse.",
category:
"Damage settings")]
32 private float m_fMinImpact;
35 [
Attribute(
"1", UIWidgets.EditBox,
"Enter explosion resistance of this tree part. Every explosive impulse on this tree part will be divided by this number.",
category:
"Damage settings")]
36 private float m_fExplosionResistance;
37 [
Attribute(
"1", UIWidgets.EditBox,
"Enter kinetic resistance of this tree part. Every kinetic (projectile) impulse on this tree part will be divided by this number.",
category:
"Damage settings")]
38 private float m_fKineticResistance;
39 [
Attribute(
"1", UIWidgets.EditBox,
"Enter collision resistance of this tree part. Every collision (vehicle) impulse on this tree part will be divided by this number.",
category:
"Damage settings")]
40 private float m_fCollisionResistance;
41 [
Attribute(
"1", UIWidgets.EditBox,
"Enter melee resistance of this tree part. Every melee impulse on this tree part will be divided by this number.",
category:
"Damage settings")]
42 private float m_fMeleeResistance;
44 [
Attribute(
"0", UIWidgets.CheckBox,
"Allows you to debug values that are damage related.",
category:
"Damage settings")]
50 [
Attribute(
"0", UIWidgets.EditBox,
"Enter the index of this tree part.",
category:
"Recognition settings")]
51 private int m_iTreePartIndex;
52 [
Attribute(
"-1", UIWidgets.ResourceNamePicker,
"Pick the root dirt prefab.",
category:
"Root dirt settings")]
53 private ResourceName m_RootDirt;
54 [
Attribute(
"0 0 0", UIWidgets.Auto,
"The offset of the root dirt object.",
category:
"Root dirt settings")]
55 private vector m_vRootDirtOffset;
57 #ifdef ENABLE_DESTRUCTION
64 static const float GO_TO_STATIC_THRESHOLD = 0.2;
65 static const float GO_TO_STATIC_ANGULAR_THRESHOLD = 0.2;
66 static const int GO_TO_STATIC_TIME_THRESHOLD = 2;
67 static const int GO_TO_STATIC_TIME_THRESHOLD_MAX = 20;
72 static const int TARGET_RPC_COUNT = 4;
73 static const float NET_TELEPORT_DISTANCE = 10;
74 static const float NET_TELEPORT_ANGLE = 5;
85 private vector m_vCenterOfMass;
86 private float m_fLastSpeedLinear = 0;
87 private vector m_vLastSpeedAngular =
"0 0 0";
88 private bool m_bSpawnedRootBall =
false;
89 private IEntity m_RootsEntity =
null;
90 private Physics m_RootsPhysics =
null;
91 private vector m_vBBOXMin;
92 private vector m_vBBOXMax;
93 private vector m_vSynchVelocity;
94 private vector m_vLerpStartVector;
95 private vector m_vLerpTargetPosition;
96 private float m_fLerpStartQuat[4];
97 private float m_fLerpTargetQuat[4];
98 private float m_fLerpAmountPos = -1;
99 private float m_fLerpAmountRot = -1;
100 private ref array<IEntity> m_aQuerriedEnts =
new array<IEntity>();
101 private float m_fSynchTime = 0;
102 vector m_vLockedOrigin;
105 private vector m_vNetPosition;
106 private vector m_vNetVelocityLinear;
107 private vector m_vNetVelocityAngular;
108 private float m_fTimeSinceLastTick;
109 private float m_fNetRotation[4];
110 private bool m_bExtrapolate =
false;
115 private bool m_bApplyCachedRotation =
false;
116 private float m_fCachedRotation[4];
117 private bool m_bApplyCachedPosition =
false;
118 private vector m_vCachedPosition;
119 private bool m_bBreak =
false;
120 private vector m_vImpulseVector =
"0 0 0";
121 private vector m_vPositionVector =
"0 0 0";
127 private float m_fThresholdTime = 0;
128 private float m_fThresholdMaxTime = 0;
133 private bool m_bWakeUp =
false;
134 private bool m_bSwitchToDynamic;
135 private bool m_bSwitchToStatic;
136 private ref SCR_HybridPhysicsInfo m_HybridPhysicsInfo =
null;
137 private int m_iContactsCount = 0;
138 private bool m_bBreakFromParent =
false;
143 private bool m_bCreatedJoints =
false;
144 private ref array<PhysicsJoint> m_aChildrenJoints =
new array<PhysicsJoint>();
145 private PhysicsJoint m_ParentJoint;
150 private bool m_bSynchronizeHasParent =
true;
151 private static float m_fTargetSynchTime = -1;
156 private bool m_bSoundHitGroundPlayed =
false;
160 private void ClearPhysicsInfo()
162 if (!m_HybridPhysicsInfo)
165 delete m_HybridPhysicsInfo;
166 m_HybridPhysicsInfo =
null;
171 private void StorePhysicsInfo(IEntity owner)
178 m_HybridPhysicsInfo =
new SCR_HybridPhysicsInfo;
179 m_HybridPhysicsInfo.m_fMass =
m_Physics.GetMass();
182 for (
int i = 0; i < numGeoms; i++)
184 m_HybridPhysicsInfo.m_aLayerMasks.Insert(
m_Physics.GetGeomInteractionLayer(i));
188 m_Physics = Physics.CreateStatic(owner, -1);
190 int numStoredGeoms = m_HybridPhysicsInfo.m_aLayerMasks.Count();
192 for (
int i = 0; i < numStoredGeoms; i++)
197 m_Physics.SetGeomInteractionLayer(i, m_HybridPhysicsInfo.m_aLayerMasks.Get(i));
203 private void ApplyPhysicsInfo(IEntity owner)
210 if (!owner || !m_HybridPhysicsInfo)
214 m_Physics = Physics.CreateDynamic(owner, m_HybridPhysicsInfo.m_fMass, -1);
216 int numStoredGeoms = m_HybridPhysicsInfo.m_aLayerMasks.Count();
218 for (
int i = 0; i < numStoredGeoms; i++)
223 m_Physics.SetGeomInteractionLayer(i, m_HybridPhysicsInfo.m_aLayerMasks.Get(i));
230 void SetToBreak(
int treePartIdx = -1, vector positionVector =
"0 0 0", vector impulseVector =
"0 0 0",
EDamageType damageType =
EDamageType.MELEE)
234 if (RplSession.Mode() == RplMode.Client || !synchManager)
237 if (treePartIdx == -1)
238 treePartIdx = m_iTreePartIndex;
243 synchManager.SynchronizeSetToBreak(treePartIdx, positionVector, impulseVector, damageType, m_ParentTree.GetID());
245 m_ParentTree.SetFlags(EntityFlags.ACTIVE);
247 SetEventMask(EntityEvent.FRAME);
248 m_vImpulseVector = impulseVector * 50;
249 m_vPositionVector = positionVector;
250 ResetThresholdTime();
251 m_eDamageType = damageType;
263 if (!m_bSpawnedRootBall && m_iTreePartIndex == 0)
268 if (m_vPositionVector ==
"0 0 0")
269 m_vPositionVector = (m_vCenterOfMass +
GetOrigin());
274 m_Physics.ApplyImpulseAt(m_vPositionVector, m_vImpulseVector);
278 if (!m_bAllowLinearMovement)
280 SetOrigin(m_vLockedOrigin);
288 if (!m_bSoundHitGroundPlayed)
292 BaseSoundComponent soundComponent = synchManager.GetSoundComponent();
296 Math3D.MatrixIdentity3(mat);
297 mat[3] = m_vPositionVector;
298 soundComponent.SetTransformation(mat);
309 private void SpawnRootDirt()
311 if (m_RootDirt.GetPath() ==
"-1")
314 Resource resource = Resource.Load(m_RootDirt);
316 if (!resource.IsValid())
323 TraceParam traceParam =
new TraceParam();
324 traceParam.Start = worldPos + vector.Up;
325 traceParam.End = worldPos - vector.Up;
326 traceParam.Flags = TraceFlags.WORLD;
327 GetWorld().TraceMove(traceParam,
null);
330 if (traceParam.TraceNorm != vector.Zero)
332 vector newUp = traceParam.TraceNorm;
338 vector newRight = newUp * mat[2];
339 newRight.Normalize();
342 vector newForward = newRight * newUp;
343 newForward.Normalize();
351 mat[3] = m_vRootDirtOffset;
354 EntitySpawnParams param =
new EntitySpawnParams();
355 param.TransformMode = ETransformMode.LOCAL;
356 param.Transform = mat;
359 ArmaReforgerScripted game =
GetGame();
364 m_RootsEntity = game.SpawnEntityPrefab(resource, GetWorld(), param);
369 m_bSpawnedRootBall =
true;
374 void RemoveFromParent()
376 IEntity parent = GetParent();
382 parent.RemoveChild(
this);
383 parent.GetTransform(parentMat);
387 BreakJoint(m_ParentJoint,
this, parentTreePart);
388 m_bSynchronizeHasParent =
false;
390 if (RplSession.Mode() == RplMode.Client)
393 if (m_ParentTree && synchManager)
394 synchManager.SynchronizeRemoveFromParent(m_iTreePartIndex, m_ParentTree.GetID());
399 PhysicsJoint GetParentJoint()
401 return m_ParentJoint;
406 void RemoveJoint(PhysicsJoint physicsJoint)
411 if (physicsJoint == m_ParentJoint)
413 m_ParentJoint =
null;
417 int count = m_aChildrenJoints.Count();
418 for (
int i = 0; i < count; i++)
420 if (physicsJoint == m_aChildrenJoints.Get(i))
422 m_aChildrenJoints.Remove(i);
430 void DestroyAllJoints()
432 array<IEntity> children =
new array<IEntity>();
433 GetAllChildren(
this, children);
434 int count = children.Count();
436 for (
int i = 0; i < count; i++)
441 PhysicsJoint physicsJoint = treePart.GetParentJoint();
443 BreakJoint(physicsJoint,
this, treePart);
444 treePart.DestroyAllJoints();
451 private void SwitchPhysicsToStatic(
bool switchChildrenPhysics)
458 StorePhysicsInfo(
this);
463 m_bSwitchToStatic =
false;
468 IEntity parent = GetParent();
472 parent.GetTransform(mat);
476 m_bSwitchToStatic =
false;
477 m_bCreatedJoints =
false;
480 ResetThresholdTime();
483 m_Physics = Physics.CreateStatic(
this, -1);
484 if (m_RootsEntity && !m_RootsPhysics)
486 m_RootsPhysics = Physics.CreateStatic(m_RootsEntity, -1);
490 if (switchChildrenPhysics)
493 m_bCreatedJoints =
false;
494 array<IEntity> children =
new array<IEntity>();
495 SCR_Global.GetHierarchyEntityList(
this, children);
498 int count = children.Count();
499 for (
int i = 0; i < count; i++)
503 treePart.SwitchPhysicsToStatic(
false);
508 ClearEventMask(EntityEvent.SIMULATE | EntityEvent.POSTSIMULATE);
510 if (RplSession.Mode() == RplMode.Client)
517 Math3D.MatrixToQuat(mat, q);
519 if (m_ParentTree && synchManager)
521 synchManager.SynchronizeStaticRotation(m_iTreePartIndex, q, m_ParentTree.GetID());
522 synchManager.SynchronizeStaticPosition(m_iTreePartIndex, mat[3], m_ParentTree.GetID());
528 private void SwitchPhysicsToDynamic()
534 array<IEntity> children =
new array<IEntity>();
535 SCR_Global.GetHierarchyEntityList(
this, children);
538 int count = children.Count();
539 for (
int i = 0; i < count; i++)
543 treePart.SwitchPhysicsToDynamic();
550 m_bSwitchToDynamic =
false;
551 ResetThresholdTime();
555 m_RootsPhysics.Destroy();
556 m_RootsPhysics =
null;
566 m_bSwitchToDynamic =
false;
576 ApplyPhysicsInfo(
this);
577 m_vCenterOfMass =
m_Physics.GetCenterOfMass();
585 SetEventMask(EntityEvent.SIMULATE | EntityEvent.POSTSIMULATE);
590 private void DestroyPhysics()
601 private void LimitAcceleration()
606 vector velocity =
m_Physics.GetVelocity();
607 float currentSpeed = velocity.Length();
610 if (currentSpeed != 0)
614 float targetSpeed = Math.Clamp(currentSpeed, 0, m_fLastSpeedLinear + m_fMaxAccelerationLinear);
615 float multiplier = targetSpeed / currentSpeed;
618 velocity *= multiplier;
620 m_fLastSpeedLinear = velocity.Length();
623 vector velocityAngular =
m_Physics.GetAngularVelocity();
626 vector localVelocityAngular = velocityAngular.InvMultiply3(mat);
627 for (
int i = 0; i < 3; i++)
629 float targetVelocityAngular = Math.Clamp(localVelocityAngular[i], 0, m_vLastSpeedAngular[i] + m_vMaxAccelerationAngular[i]);
630 localVelocityAngular[i] = targetVelocityAngular;
633 velocityAngular = localVelocityAngular.Multiply3(mat);
634 m_Physics.SetAngularVelocity(velocityAngular);
639 private void LimitYRotation()
646 vector angularVelocity =
m_Physics.GetAngularVelocity();
648 if (Math.AbsFloat(angularVelocity[0]) > m_fMaxYRotationVelocity ||
649 Math.AbsFloat(angularVelocity[1]) > m_fMaxYRotationVelocity ||
650 Math.AbsFloat(angularVelocity[2]) > m_fMaxYRotationVelocity)
654 float scale = GetScale();
655 float matMultiplier = 1;
657 matMultiplier /= GetScale();
659 mat[0] = mat[0] * matMultiplier;
660 mat[1] = mat[1] * matMultiplier;
661 mat[2] = mat[2] * matMultiplier;
664 vector localAngularVelocity = angularVelocity.InvMultiply3(mat);
665 float velocity = localAngularVelocity[1];
668 velocity = Math.Clamp(velocity, -m_fMaxYRotationVelocity, m_fMaxYRotationVelocity);
669 localAngularVelocity[1] = velocity;
672 angularVelocity = localAngularVelocity.Multiply3(mat);
676 if (!m_bAllowGlobalYRotation)
677 angularVelocity[1] = 0;
679 m_Physics.SetAngularVelocity(angularVelocity);
686 if (!joint || !ent1 || !ent2)
689 ent1.RemoveJoint(joint);
690 ent2.RemoveJoint(joint);
696 private void CreateJoints()
702 array<IEntity> children =
new array<IEntity>();
703 GetAllChildren(
this, children);
704 int count = children.Count();
706 for (
int i = 0; i < count; i++)
709 if (treePart && !treePart.m_ParentJoint)
711 PhysicsJoint physicsJoint = treePart.CreateLowerJoint(
this);
713 m_aChildrenJoints.Insert(physicsJoint);
714 treePart.CreateJoints();
717 m_bCreatedJoints =
true;
723 private void GetAllChildren(IEntity parent, notnull inout array<IEntity> allChildren)
728 IEntity child = parent.GetChildren();
732 allChildren.Insert(child);
733 child = child.GetSibling();
739 private void StopSelf()
747 if (!m_bAllowLinearMovement)
749 SetOrigin(m_vLockedOrigin);
757 private void CheckThreshold(
float timeSlice)
762 m_fThresholdMaxTime += timeSlice;
763 if (m_fThresholdMaxTime > GO_TO_STATIC_TIME_THRESHOLD_MAX)
765 if (m_ParentTree && synchManager)
766 synchManager.SynchronizeSwitchTreePartToStatic(m_iTreePartIndex, m_ParentTree.GetID());
767 m_bSwitchToStatic =
true;
770 if (m_iContactsCount <= 0)
772 m_bSoundHitGroundPlayed =
false;
773 m_fThresholdTime = 0;
777 if (!
m_Physics || m_bSynchronizeHasParent)
782 float velocity =
m_Physics.GetVelocity().Length();
783 float angularVelocity =
m_Physics.GetAngularVelocity().Length();
784 if (velocity < GO_TO_STATIC_THRESHOLD && angularVelocity < GO_TO_STATIC_ANGULAR_THRESHOLD)
786 m_fThresholdTime += timeSlice;
787 if (m_fThresholdTime > GO_TO_STATIC_TIME_THRESHOLD)
789 if (m_ParentTree && synchManager)
790 synchManager.SynchronizeSwitchTreePartToStatic(m_iTreePartIndex, m_ParentTree.GetID());
791 m_bSwitchToStatic =
true;
800 if (!parent || !
m_Physics || m_ParentJoint)
803 m_ParentJoint = PhysicsJoint.CreateFixed(parent,
this, m_vCenterOfMass * GetScale(), parent.m_vCenterOfMass * parent.GetScale(),
true, m_fMaxJointLoad);
805 return m_ParentJoint;
811 IEntity parent = GetParent();
818 treePart.WakeUpParent();
822 private bool AddEnt(IEntity ent)
824 m_aQuerriedEnts.Insert(ent);
829 private bool FilterEnt(IEntity ent)
831 if (IsInHierarchy(ent) || ent ==
this)
837 private bool IsInHierarchy(IEntity ent)
842 array<IEntity> children =
new array<IEntity>();
843 SCR_Global.GetHierarchyEntityList(
this, children);
844 int count = children.Count();
845 for (
int i = 0; i < count; i++)
847 if (ent == children[i])
857 m_aQuerriedEnts.Clear();
861 GetWorld().QueryEntitiesByOBB(m_vBBOXMin, m_vBBOXMax, mat, AddEnt, FilterEnt);
863 int count = m_aQuerriedEnts.Count();
864 for (
int i = 0; i < count; i++)
866 if (m_aQuerriedEnts[i])
870 treePart.WakeUp(
true);
877 void WakeUp(
bool wakeUpParent)
892 void WakeUpHierarchy()
894 SwitchPhysicsToDynamic();
903 int GetTreePartIndex()
905 return m_iTreePartIndex;
909 void UpdateTransform(vector
position,
float quat[4], vector velocityLinear, vector velocityAngular)
911 m_bExtrapolate =
true;
914 m_vNetVelocityLinear = velocityLinear;
915 m_vNetVelocityAngular = velocityAngular;
916 Math3D.QuatCopy(quat, m_fNetRotation);
923 m_Physics.SetAngularVelocity(velocityAngular * Math.DEG2RAD);
928 Math3D.QuatToMatrix(quat, mat);
937 m_fTimeSinceLastTick = 0;
941 void CacheRotation(
float quat[4])
945 m_bApplyCachedRotation =
true;
946 Math3D.QuatCopy(quat, m_fCachedRotation);
950 void CachePosition(vector pos)
953 m_bApplyCachedPosition =
true;
954 m_vCachedPosition[0] = pos[0];
955 m_vCachedPosition[1] = pos[1];
956 m_vCachedPosition[2] = pos[2];
960 void SetRotation(
float quat[4])
963 Math3D.QuatToMatrix(quat, mat);
971 void SetPosition(vector pos)
978 void SetVelocity(vector velocity)
981 if (velocity.Length() < 0.02)
989 void SetAngularVelocity(vector angularVelocity)
992 if (angularVelocity.Length() < 0.02)
996 m_Physics.SetAngularVelocity(angularVelocity);
1000 void SetPhysics(
bool dynamic)
1003 m_bSwitchToDynamic =
true;
1005 m_bSwitchToStatic =
true;
1009 void ClientSetToBreakFromParent()
1011 m_bBreakFromParent =
true;
1015 IEntity parent = GetParent();
1020 parent.RemoveChild(
this);
1025 if (m_vCachedPosition && m_bApplyCachedPosition)
1028 SetPosition(m_vCachedPosition);
1029 m_bApplyCachedPosition =
false;
1034 if (m_fCachedRotation && m_bApplyCachedRotation)
1037 SetRotation(m_fCachedRotation);
1038 m_bApplyCachedRotation =
false;
1041 m_bBreakFromParent =
false;
1046 float GetQuatDiff(
float quat1[4],
float quat2[4])
1048 float diff0 = Math.AbsFloat(quat1[0] - quat2[0]);
1049 float diff1 = Math.AbsFloat(quat1[1] - quat2[1]);
1050 float diff2 = Math.AbsFloat(quat1[2] - quat2[2]);
1051 float diff3 = Math.AbsFloat(quat1[3] - quat2[3]);
1052 float diffSum = diff0 + diff1 + diff2 + diff3;
1060 float reducedDamage = -1;
1066 if (m_fMeleeResistance != 0)
1067 reducedDamage =
impulse / m_fMeleeResistance;
1072 if (m_fKineticResistance != 0)
1073 reducedDamage =
impulse / m_fKineticResistance;
1077 Print(
"Incendiary");
1082 if (m_fExplosionResistance != 0)
1083 reducedDamage =
impulse / m_fExplosionResistance;
1088 Print(
"Damage after reduction: " +
"NOT IMPLEMENTED YET");
1093 if (m_fCollisionResistance != 0)
1094 reducedDamage =
impulse / m_fCollisionResistance;
1099 Print(
"Damage before reduction: " +
impulse);
1100 if (reducedDamage != -1)
1101 Print(
"Damage after reduction: " + reducedDamage);
1102 else Print(
"Damage after reduction: NOT IMPLEMENTED YET");
1106 void ResetThresholdTime()
1108 m_fThresholdTime = 0;
1109 m_fThresholdMaxTime = 0;
1113 IEntity FindSuperParent()
1115 IEntity current =
this;
1116 while (current.GetParent())
1118 current = current.GetParent();
1130 if (m_fMeleeResistance != 0)
1131 impulse /= m_fMeleeResistance;
1134 if (m_fKineticResistance != 0)
1135 impulse /= m_fKineticResistance;
1140 if (m_fExplosionResistance != 0)
1141 impulse /= m_fExplosionResistance;
1146 if (m_fCollisionResistance != 0)
1147 impulse /= m_fCollisionResistance;
1151 if (
impulse > (m_fMinImpact * GetScale()))
1165 if (m_fMeleeResistance != 0)
1166 reducedImpulse /= m_fMeleeResistance;
1169 if (m_fKineticResistance != 0)
1170 reducedImpulse /= m_fKineticResistance;
1175 if (m_fExplosionResistance != 0)
1176 reducedImpulse /= m_fExplosionResistance;
1181 if (m_fCollisionResistance != 0)
1182 reducedImpulse /= m_fCollisionResistance;
1186 if (reducedImpulse > (m_fMinImpact * GetScale()))
1193 override void OnDamage(
float damage,
1196 inout vector outMat[3],
1197 IEntity damageSource,
1202 if (RplSession.Mode() == RplMode.Client)
1206 vector directionVector = -outMat[2];
1207 directionVector.Normalize();
1210 PrintDamageDebug(damage,
type);
1212 if (damage > m_fMinImpact)
1215 vector positionVector = outMat[0];
1219 positionVector =
"0 0 0";
1220 directionVector = (
GetOrigin() - outMat[0]);
1223 directionVector.Normalize();
1224 vector impulseVector = directionVector * (damage / 10);
1226 if (WouldBreak(damage,
type))
1227 SetToBreak(positionVector: positionVector, impulseVector: impulseVector, damageType:
type);
1233 override void EOnFrame(IEntity owner,
float timeSlice)
1237 if (m_bWakeUp && !owner.GetParent())
1239 if (m_bSwitchToDynamic)
1240 SwitchPhysicsToDynamic();
1241 if (m_bSwitchToStatic)
1243 SwitchPhysicsToStatic(
true);
1259 static void Extrapolate(
GenericEntity entity, Physics physics, vector netPosition, vector netVelocityLinear,
float netTeleportDistance,
float netRotation[4], vector netVelocityAngular,
float netTeleportAng,
float timeSinceLastTick,
float timeSlice,
float tickTime)
1261 float scale = entity.GetScale();
1262 vector currentMatrix[4];
1263 entity.GetWorldTransform(currentMatrix);
1266 vector
position = currentMatrix[3];
1268 Math3D.MatrixToQuat(currentMatrix,
rotation);
1271 if (!physics || !physics.IsDynamic())
1274 Math3D.QuatToMatrix(netRotation, currentMatrix);
1278 currentMatrix[3] = netPosition;
1280 entity.SetWorldTransform(currentMatrix);
1281 entity.SetScale(scale);
1286 vector projectedPos = netPosition + netVelocityLinear * timeSinceLastTick;
1288 netVelocityAngular = netVelocityAngular * timeSinceLastTick;
1289 vector netVelocityAngularFlipped = GetFixedAxisVector(netVelocityAngular);
1290 float projectedRotation[4];
1291 float netVelocityAngularQuat[4];
1292 netVelocityAngularFlipped.QuatFromAngles(netVelocityAngularQuat);
1293 Math3D.QuatMultiply(projectedRotation, netRotation, netVelocityAngularQuat);
1296 float posError = vector.Distance(projectedPos,
position);
1297 float rotError = Math3D.QuatAngle(projectedRotation,
rotation);
1301 if (posError > netTeleportDistance)
1303 entity.SetOrigin(netPosition);
1309 if (rotError > netTeleportAng)
1311 Math3D.QuatToMatrix(netRotation, currentMatrix);
1313 currentMatrix[3] = entity.GetOrigin();
1314 entity.SetWorldTransform(currentMatrix);
1318 float timeStep = Math.Clamp(timeSlice * 2, 0, 1);
1319 float timeStepTick = Math.Clamp(timeSlice / tickTime, 0, 1);
1322 if (posError > 0.01)
1324 entity.SetOrigin(MoveTowards(
position, projectedPos, posError * timeStep));
1325 physics.SetVelocity(physics.GetVelocity() + (projectedPos -
position) * timeStepTick);
1328 if (rotError > 0.01)
1331 Math3D.QuatRotateTowards(outRot,
rotation, projectedRotation, (rotError * timeStep) * Math.RAD2DEG);
1332 Math3D.QuatToMatrix(outRot, currentMatrix);
1334 currentMatrix[3] = entity.GetOrigin();
1336 entity.SetWorldTransform(currentMatrix);
1340 Math3D.QuatInverse(rotInv,
rotation);
1341 Math3D.QuatMultiply(rotDiff, projectedRotation, rotInv);
1342 vector angularVelocity = Math3D.QuatToAngles(rotDiff);
1343 angularVelocity = FixEulerVector180(angularVelocity) * Math.DEG2RAD * timeStepTick;
1344 angularVelocity += physics.GetAngularVelocity() * Math.DEG2RAD;
1345 physics.SetAngularVelocity(angularVelocity);
1348 entity.SetScale(scale);
1353 static vector GetFixedAxisVector(vector toFlip)
1356 flipped[0] = toFlip[1];
1357 flipped[1] = toFlip[0];
1358 flipped[2] = toFlip[2];
1363 static void RotateTowards(out
float result[4],
float from[4],
float to[4],
float maxDegreesDelta)
1365 float num = Math3D.QuatAngle(from, to);
1366 if (
float.AlmostEqual(num, 0.0))
1368 Math3D.QuatCopy(to, result);
1371 float t = Math.Min(1, maxDegreesDelta / num);
1372 Math3D.QuatLerp(result, from, to, t);
1377 static vector MoveTowards(vector start, vector target,
float maxDistanceDelta)
1379 vector diff = target - start;
1380 float magnitude = diff.Length();
1381 if (magnitude <= maxDistanceDelta ||
float.AlmostEqual(magnitude, 0.0))
1383 return start + diff / magnitude * maxDistanceDelta;
1388 static vector FixEulerVector180(vector angles)
1391 for (
int a = 0; a < 3; a++)
1393 while (angles[a] < -180)
1394 angles[a] = angles[a] + 360;
1395 while (angles[a] > 180)
1396 angles[a] = angles[a] - 360;
1407 SetEventMask(EntityEvent.FRAME);
1408 m_bSwitchToStatic =
true;
1413 override void EOnInit(IEntity owner)
1416 m_bSynchronizeHasParent =
true;
1418 GetBounds(m_vBBOXMin, m_vBBOXMax);
1420 SwitchPhysicsToStatic(
false);
1421 SetEventMask(EntityEvent.FRAME | EntityEvent.PHYSICSACTIVE);
1426 override void EOnSimulate(IEntity owner,
float timeSlice)
1432 if (m_bBreakFromParent)
1434 IEntity parent = GetParent();
1438 if (treePart && m_ParentJoint)
1439 BreakJoint(m_ParentJoint,
this, treePart);
1441 parent.RemoveChild(
this);
1444 if (m_vCachedPosition && m_bApplyCachedPosition)
1446 SetPosition(m_vCachedPosition);
1447 m_bApplyCachedPosition =
false;
1450 if (m_fCachedRotation && m_bApplyCachedRotation)
1452 SetRotation(m_fCachedRotation);
1453 m_bApplyCachedRotation =
false;
1456 m_bBreakFromParent =
false;
1462 if (
m_Physics.IsDynamic() && RplSession.Mode() == RplMode.Client)
1469 CheckThreshold(timeSlice);
1471 m_iContactsCount = 0;
1475 override void EOnPostSimulate(IEntity owner,
float timeSlice)
1477 if (RplSession.Mode() == RplMode.Client)
1481 m_fTimeSinceLastTick += timeSlice;
1482 Extrapolate(
this,
m_Physics, m_vNetPosition, m_vNetVelocityLinear, NET_TELEPORT_DISTANCE, m_fNetRotation, m_vNetVelocityAngular, NET_TELEPORT_ANGLE, m_fTimeSinceLastTick, timeSlice, m_fTargetSynchTime);
1506 m_fSynchTime += timeSlice;
1507 if (m_fSynchTime > m_fTargetSynchTime)
1509 if (!this.GetParent() && synchManager)
1514 GetWorldTransform(mat);
1515 Math3D.MatrixToQuat(mat, q);
1519 vector parentOrigin = m_ParentTree.GetOrigin();
1523 synchManager.SynchronizeTreePartTransform(m_iTreePartIndex, q,
GetOrigin(),
m_Physics.GetVelocity(),
m_Physics.GetAngularVelocity(), m_ParentTree.GetID());
1532 override void EOnContact(IEntity owner, IEntity other, Contact contact)
1534 if (RplSession.Mode() == RplMode.Client)
1538 if (m_bSoundHitGroundPlayed)
1541 if (GenericTerrainEntity.Cast(other))
1543 float vNormBefore = contact.GetRelativeNormalVelocityBefore();
1544 float vNormAfter = contact.GetRelativeNormalVelocityAfter();
1545 float dV = vNormAfter - vNormBefore;
1546 float impulse = contact.Impulse;
1548 if (dV > 2.5 &&
impulse > 100)
1552 m_ParentTree.OnTreePartHitGround();
1554 m_bSoundHitGroundPlayed =
true;
1558 if (Vehicle.Cast(other))
1562 superParent.ResetThresholdTime();
1571 if (TARGET_RPC_COUNT > 0 && m_fTargetSynchTime == -1)
1573 m_fTargetSynchTime = 1 / TARGET_RPC_COUNT;
1575 SetEventMask(EntityEvent.INIT);
1582 m_ParentJoint =
null;
1583 m_HybridPhysicsInfo =
null;
1584 m_aChildrenJoints =
null;
1585 m_aQuerriedEnts =
null;