public static bool FindRandomFracturedTreeInPlaceArea(Vector3D fromPosition, long entityId, out EntityInfo result) { result = default(EntityInfo); MyPlaceArea area = MyPlaceArea.FromEntity(entityId); if (area == null) { return(false); } var areaBB = area.WorldAABB; BoundingSphereD searchSphere = new BoundingSphereD(areaBB.Center, (double)areaBB.HalfExtents.Length()); m_tmpFracturePieceList.Clear(); FindFracturedTreesInternal(fromPosition, area, searchSphere); if (m_tmpFracturePieceList.Count == 0) { m_tmpFracturePieceList.Clear(); return(false); } int fractureIndex = (int)Math.Round(MyRandom.Instance.NextFloat() * (m_tmpFracturePieceList.Count - 1)); MyFracturedPiece selectedTarget = m_tmpFracturePieceList[fractureIndex]; m_tmpFracturePieceList.Clear(); result.EntityId = selectedTarget.EntityId; result.Target = selectedTarget.PositionComp.GetPosition(); return(true); }
private static bool FindClosestFracturedTreeInternal(Vector3D fromPosition, Vector3D searchCenter, double searchRadius, MyPlaceArea area, out EntityInfo result) { result = default(EntityInfo); double closestDistanceSq = double.MaxValue; MyFracturedPiece closestTarget = null; Vector3D closestPoint = default(Vector3D); BoundingSphereD searchSphere = new BoundingSphereD(searchCenter, searchRadius); m_tmpFracturePieceList.Clear(); MyFracturedPiecesManager.Static.GetFracturesInSphere(ref searchSphere, ref m_tmpFracturePieceList); for (int i = 0; i < m_tmpFracturePieceList.Count; ++i) { var fracture = m_tmpFracturePieceList[i]; // Skip non-tree fractures if (!MyTrees.IsEntityFracturedTree(fracture)) { continue; } if (IsFracturedTreeStump(fracture)) { continue; } Vector3D positionInTrunkLocal = Vector3D.Transform(fromPosition, fracture.PositionComp.WorldMatrixNormalizedInv); Vector3D closestPointOnTrunk; if (!FindClosestPointOnFracturedTree(positionInTrunkLocal, fracture, out closestPointOnTrunk)) { continue; } if (area == null || area.TestPoint(closestPointOnTrunk)) { double distanceSq = Vector3D.DistanceSquared(closestPointOnTrunk, fromPosition); if (distanceSq < closestDistanceSq) { closestDistanceSq = distanceSq; closestTarget = fracture; closestPoint = closestPointOnTrunk; } } } m_tmpFracturePieceList.Clear(); if (closestTarget == null) { return(false); } result.EntityId = closestTarget.EntityId; result.Target = closestPoint; return(true); }
private MyFracturedPiece AllocatePiece() { ProfilerShort.Begin("AllocCounter"); m_allocatedThisFrame++; var fp = new MyFracturedPiece(); fp.Physics = new MyPhysicsBody(fp, RigidBodyFlag.RBF_DEBRIS); ProfilerShort.End(); return fp; }
private static bool IsFracturedTreeStump(MyFracturedPiece fracture) { Vector4 minFour, maxFour; fracture.Shape.GetShape().GetLocalAABB(0, out minFour, out maxFour); if (maxFour.Y - minFour.Y < 3.5 * (maxFour.X - minFour.X)) // HACK: find stumps { return(true); } return(false); }
private static void FindFracturedTreesInternal(Vector3D fromPosition, MyPlaceArea area, BoundingSphereD sphere) { Debug.Assert(m_tmpFracturePieceList.Count == 0, "m_tmpFracturePieceList was not cleared after last use!"); MyFracturedPiecesManager.Static.GetFracturesInSphere(ref sphere, ref m_tmpFracturePieceList); for (int i = m_tmpFracturePieceList.Count - 1; i >= 0; i--) { MyFracturedPiece fracture = m_tmpFracturePieceList[i]; if (!MyTrees.IsEntityFracturedTree(fracture)) { m_tmpFracturePieceList.RemoveAtFast(i); continue; } if (IsFracturedTreeStump(fracture)) { m_tmpFracturePieceList.RemoveAtFast(i); continue; } Vector3D positionInTrunkLocal = Vector3D.Transform(fromPosition, fracture.PositionComp.WorldMatrixNormalizedInv); Vector3D closestPointOnTrunk; if (!FindClosestPointOnFracturedTree(positionInTrunkLocal, fracture, out closestPointOnTrunk)) { m_tmpFracturePieceList.RemoveAtFast(i); continue; } if (!area.TestPoint(closestPointOnTrunk)) { m_tmpFracturePieceList.RemoveAtFast(i); continue; } } }
MyTimeSpan GetPieceAgeLength(MyFracturedPiece piece) { if (piece.Physics == null || piece.Physics.BreakableBody == null) return MyTimeSpan.Zero; if (piece.Physics.RigidBody.Layer == FakePieceLayer) return MyTimeSpan.FromSeconds(8 + MyRandom.Instance.NextFloat(0, 4)); float volume = piece.Physics.BreakableBody.BreakableShape.Volume; float proposedAgeInSecs = volume * LIFE_OF_CUBIC_PIECE; return MyTimeSpan.FromSeconds(proposedAgeInSecs); }
public MyFracturedPieceDebugDraw(MyFracturedPiece piece) { m_piece = piece; }
public static void ApplyImpulseToTreeFracture(ref MatrixD worldMatrix, ref Vector3 hitNormal, List<HkdShapeInstanceInfo> shapeList, ref HkdBreakableShape compound, MyFracturedPiece fp, float forceMultiplier = 1.0f) { float mass = compound.GetMass(); Vector3 coMMaxY = Vector3.MinValue; shapeList.ForEach(s => coMMaxY = (s.CoM.Y > coMMaxY.Y) ? s.CoM : coMMaxY); Vector3 forceVector = hitNormal; forceVector.Y = 0; forceVector.Normalize(); Vector3 force = 0.3f * forceMultiplier * mass * forceVector; fp.Physics.Enabled = true;//so we get the body in world Vector3 worldForcePoint = fp.Physics.WorldToCluster(Vector3D.Transform(coMMaxY, worldMatrix)); fp.Physics.RigidBody.AngularDamping = MyPerGameSettings.DefaultAngularDamping; fp.Physics.RigidBody.LinearDamping = MyPerGameSettings.DefaultLinearDamping; fp.Physics.RigidBody.ApplyPointImpulse(force, worldForcePoint); }
public static void PlayDestructionSound(MyFracturedPiece fp) { var bDef = MyDefinitionManager.Static.GetCubeBlockDefinition(fp.OriginalBlocks[0]); if (bDef == null) return; MyPhysicalMaterialDefinition def = bDef.PhysicalMaterial; MySoundPair destructionCue; if (def.GeneralSounds.TryGetValue(m_destructionSound, out destructionCue) && !destructionCue.SoundId.IsNull) { var emmiter = MyAudioComponent.TryGetSoundEmitter(); if (emmiter == null) return; Vector3D pos = fp.PositionComp.GetPosition(); emmiter.SetPosition(pos); emmiter.PlaySound(destructionCue); } }
public void RemoveFracturePiece(MyFracturedPiece piece, float blendTimeSeconds, bool fromServer = false, bool sync = true) { System.Diagnostics.Debug.Assert(Sync.IsServer || fromServer, "Clients cannot remove pieces by themselves"); System.Diagnostics.Debug.Assert((sync && Sync.IsServer) ^ (fromServer && !sync), "Sync must be called on server."); if (blendTimeSeconds == 0) { Debug.Assert((Sync.IsServer && sync) || fromServer, "Server must sync Fracture Piece removal!"); if (sync) { Debug.Assert(m_piecesTimesOfDeath.ContainsKey(piece), "Double removing Fracture Piece!"); MySyncDestructions.RemoveFracturePiece(piece.EntityId, blendTimeSeconds); } RemoveInternal(piece); return; } MyTimeSpan newDeath = MySandboxGame.Static.UpdateTime + MyTimeSpan.FromSeconds(blendTimeSeconds); if (m_blendingPieces.Add(piece)) { if (sync) MySyncDestructions.RemoveFracturePiece(piece.EntityId, blendTimeSeconds); if (!m_piecesTimesOfDeath.ContainsKey(piece)) { Debug.Assert(fromServer, "Fracture piece missing time of death on server!"); m_piecesTimesOfDeath.Add(piece, newDeath); } MyTimeSpan currentDeath; if (m_piecesTimesOfDeath.TryGetValue(piece, out currentDeath)) { if (currentDeath > newDeath) { m_piecesTimesOfDeath[piece] = newDeath; } } else Debug.Fail("Fracture Piece missing time of death!"); } else { MyTimeSpan currentDeath; if (m_piecesTimesOfDeath.TryGetValue(piece, out currentDeath)) { if (currentDeath > newDeath) { m_piecesTimesOfDeath[piece] = newDeath; if (sync) MySyncDestructions.RemoveFracturePiece(piece.EntityId, blendTimeSeconds); } } else { Debug.Assert(false, "Shouldnt get here"); } } }
public MyFracturedPieceDebugDraw(MyFracturedPiece piece) { m_piece = piece; }
private static bool FindClosestPointOnFracturedTree(Vector3D fromPositionFractureLocal, MyFracturedPiece fracture, out Vector3D closestPoint) { // Marko: HACK: skip stumps closestPoint = default(Vector3D); if (fracture == null) return false; Vector4 minFour, maxFour; fracture.Shape.GetShape().GetLocalAABB(0, out minFour, out maxFour); var min = new Vector3D(minFour); var max = new Vector3D(maxFour); closestPoint = Vector3D.Clamp(fromPositionFractureLocal, min, max); closestPoint.X = (closestPoint.X + 2 * (max.X + min.X) / 2) / 3; closestPoint.Y = MathHelper.Clamp(closestPoint.Y + 0.25f * (closestPoint.Y - min.Y < max.Y - closestPoint.Y ? 1 : -1), min.Y, max.Y); closestPoint.Z = (closestPoint.Z + 2 * (max.Z + min.Z) / 2) / 3; closestPoint = Vector3D.Transform(closestPoint, fracture.PositionComp.WorldMatrix); return true; }
private static bool IsFracturedTreeStump(MyFracturedPiece fracture) { Vector4 minFour, maxFour; fracture.Shape.GetShape().GetLocalAABB(0, out minFour, out maxFour); if (maxFour.Y - minFour.Y < 3.5 * (maxFour.X - minFour.X)) // HACK: find stumps return true; return false; }
private static bool FindClosestPointOnFracturedTree(Vector3D fromPositionFractureLocal, MyFracturedPiece fracture, out Vector3D closestPoint) { // Marko: HACK: skip stumps closestPoint = default(Vector3D); if (fracture == null) { return(false); } Vector4 minFour, maxFour; fracture.Shape.GetShape().GetLocalAABB(0, out minFour, out maxFour); var min = new Vector3D(minFour); var max = new Vector3D(maxFour); closestPoint = Vector3D.Clamp(fromPositionFractureLocal, min, max); closestPoint.X = (closestPoint.X + 2 * (max.X + min.X) / 2) / 3; closestPoint.Y = MathHelper.Clamp(closestPoint.Y + 0.25f * (closestPoint.Y - min.Y < max.Y - closestPoint.Y ? 1 : -1), min.Y, max.Y); closestPoint.Z = (closestPoint.Z + 2 * (max.Z + min.Z) / 2) / 3; closestPoint = Vector3D.Transform(closestPoint, fracture.PositionComp.WorldMatrix); return(true); }
private void RemoveInternal(MyFracturedPiece fp) { if (fp.Physics != null && fp.Physics.RigidBody != null) { Debug.Assert(!fp.Physics.RigidBody.IsDisposed, "Disposed piece rigid body!!"); if (fp.Physics.RigidBody.IsDisposed) { var rb = fp.Physics.BreakableBody.GetRigidBody(); fp.Physics.BreakableBody = fp.Physics.BreakableBody; } } bool a = m_piecesTimesOfDeath.Remove(fp); bool b = m_blendingPieces.Remove(fp); bool c = m_inactivePieces.Remove(fp); if (fp.Physics == null || fp.Physics.RigidBody == null || fp.Physics.RigidBody.IsDisposed) { Debug.Fail("Should not get here!"); MyEntities.Remove(fp); return; } fp.Physics.RigidBody.Activated -= RigidBody_Activated; fp.Physics.RigidBody.Deactivated -= RigidBody_Deactivated; //Let objects staying on this fp to fall if (!fp.Physics.RigidBody.IsActive) fp.Physics.RigidBody.Activate(); MyPhysics.RemoveDestructions(fp.Physics.RigidBody); var bb = fp.Physics.BreakableBody; bb.AfterReplaceBody -= fp.Physics.FracturedBody_AfterReplaceBody; MyEntities.Remove(fp); fp.Physics.Enabled = false; fp.Physics.BreakableBody = null; //fp.Shape.RemoveReference(); //System.Diagnostics.Debug.Assert(bb.ReferenceCount == 1);//not true anymore, since FP can be removed from callback immediately MyFracturedPiecesManager.Static.ReturnToPool(bb); fp.Render.ClearModels(); fp.OriginalBlocks.Clear(); if (Sync.IsServer) Debug.Assert(m_dbgRemoved.Add(fp.EntityId)); else MySyncDestructions.FPManagerDbgMessage(0, fp.EntityId); fp.EntityId = 0; m_piecesPool.Enqueue(fp); }
public bool TryGetFractureById(long entityId, out MyFracturedPiece outFracture) { outFracture = null; var activeFractures = m_piecesTimesOfDeath.Keys; foreach(var fracture in activeFractures) { if (fracture.EntityId == entityId) { outFracture = fracture; return true; } } return false; }
private void RemoveInternal(MyFracturedPiece fp,bool fromServer = false) { if (fp.Physics != null && fp.Physics.RigidBody != null) { Debug.Assert(!fp.Physics.RigidBody.IsDisposed, "Disposed piece rigid body!!"); if (fp.Physics.RigidBody.IsDisposed) { fp.Physics.BreakableBody = fp.Physics.BreakableBody; } } if (fp.Physics == null || fp.Physics.RigidBody == null || fp.Physics.RigidBody.IsDisposed) { Debug.Fail("Should not get here!"); MyEntities.Remove(fp); return; } //Let objects staying on this fp to fall if (!fp.Physics.RigidBody.IsActive) fp.Physics.RigidBody.Activate(); MyPhysics.RemoveDestructions(fp.Physics.RigidBody); var bb = fp.Physics.BreakableBody; bb.AfterReplaceBody -= fp.Physics.FracturedBody_AfterReplaceBody; this.ReturnToPool(bb); fp.Physics.Enabled = false; MyEntities.Remove(fp); fp.Physics.BreakableBody = null; fp.Render.ClearModels(); fp.OriginalBlocks.Clear(); if (Sync.IsServer) Debug.Assert(m_dbgRemoved.Add(fp.EntityId)); else MySyncDestructions.FPManagerDbgMessage(0, fp.EntityId); fp.EntityId = 0; fp.Physics.BreakableBody = null; m_piecesPool.Enqueue(fp); }
public static void FixPosition(MyFracturedPiece fp) { //return; ProfilerShort.Begin("FixPosition"); var shape = fp.Physics.BreakableBody.BreakableShape; if (shape.GetChildrenCount() == 0) { ProfilerShort.End(); return; } shape.GetChildren(m_tmpInfos); var offset = m_tmpInfos[0].GetTransform().Translation; if (offset.LengthSquared() < 1) { m_tmpInfos.Clear(); ProfilerShort.End(); return; } var lst = new List<HkdConnection>(); var set = new HashSet<HkdBreakableShape>(); var set2 = new HashSet<HkdBreakableShape>(); set.Add(shape); shape.GetConnectionList(lst); fp.PositionComp.SetPosition(Vector3D.Transform(offset, fp.PositionComp.WorldMatrix)); foreach (var child in m_tmpInfos) { var m = child.GetTransform(); m.Translation -= offset; child.SetTransform(ref m); m_tmpInfos2.Add(child); HkdBreakableShape par = child.Shape; par.GetConnectionList(lst); while (par.HasParent) { par = par.GetParent(); if (set.Add(par)) par.GetConnectionList(lst); else { } } set2.Add(child.Shape); } m_tmpInfos.Clear(); HkdBreakableShape compound = new HkdCompoundBreakableShape(shape, m_tmpInfos2); //HkMassProperties mp = new HkMassProperties(); ((HkdCompoundBreakableShape)compound).RecalcMassPropsFromChildren(); compound.SetChildrenParent(compound); foreach (var c in lst) { HkBaseSystem.EnableAssert(390435339, true); if (!set2.Contains(c.ShapeA) || !set2.Contains(c.ShapeB)) continue; var cref = c; compound.AddConnection(ref cref); } fp.Physics.BreakableBody.BreakableShape = compound; m_tmpInfos2.Clear(); ((HkdCompoundBreakableShape)compound).RecalcMassPropsFromChildren(); ProfilerShort.End(); }
public void RemoveFracturePiece(MyFracturedPiece piece, float blendTimeSeconds, bool fromServer = false, bool sync = true) { System.Diagnostics.Debug.Assert(Sync.IsServer || fromServer, "Clients cannot remove pieces by themselves"); System.Diagnostics.Debug.Assert((sync && Sync.IsServer) ^ (fromServer && !sync), "Sync must be called on server."); if (blendTimeSeconds == 0) { Debug.Assert((Sync.IsServer && sync) || fromServer, "Server must sync Fracture Piece removal!"); RemoveInternal(piece, fromServer); return; } }