private void ApplyVolumetriDamageToGrid(MyDamageInfo damageInfo, long attackerId) { var damagedBlocks = damageInfo.ExplosionDamage.DamagedBlocks; var explodedBlocks = damageInfo.AffectedCubeBlocks; var explodedGrids = damageInfo.AffectedCubeGrids; VRageRender.MyRenderProxy.GetRenderProfiler().StartProfilingBlock("foreach (var damagedBlock in damagedBlocks)"); if (MyDebugDrawSettings.DEBUG_DRAW_VOLUMETRIC_EXPLOSION_COLORING) { foreach (var explodedBlock in explodedBlocks) { explodedBlock.CubeGrid.ChangeColor(explodedBlock, new Vector3(0.66f, 1f, 1f)); } foreach (var damagedBlock in damagedBlocks) { float hue = 1f - damagedBlock.Value / damageInfo.ExplosionDamage.Damage; damagedBlock.Key.CubeGrid.ChangeColor(damagedBlock.Key, new Vector3(hue / 3f, 1.0f, 0.5f)); } } else { foreach (var damagedBlock in damagedBlocks) { var cubeBlock = damagedBlock.Key; if (cubeBlock.FatBlock != null && cubeBlock.FatBlock.MarkedForClose) continue; if (!cubeBlock.CubeGrid.BlocksDestructionEnabled) continue; // Allow mods to modify damage. This will cause a double call. Once here and once in the DoDamage, but only real way to do a check here MyDamageInformation checkInfo = new MyDamageInformation(false, damagedBlock.Value, MyDamageType.Explosion, attackerId); if (cubeBlock.UseDamageSystem) MyDamageSystem.Static.RaiseBeforeDamageApplied(cubeBlock, ref checkInfo); if (cubeBlock.FatBlock == null && cubeBlock.Integrity / cubeBlock.DeformationRatio < checkInfo.Amount) { VRageRender.MyRenderProxy.GetRenderProfiler().StartProfilingBlock("RemoveBlock"); cubeBlock.CubeGrid.RemoveDestroyedBlock(cubeBlock); VRageRender.MyRenderProxy.GetRenderProfiler().EndProfilingBlock(); } else { VRageRender.MyRenderProxy.GetRenderProfiler().StartProfilingBlock("ApplyDestructionDeformation"); float damage = damagedBlock.Value; if (cubeBlock.FatBlock != null) { damage *= 7f; } (cubeBlock as IMyDestroyableObject).DoDamage(damage, MyDamageType.Explosion, true); if (!cubeBlock.IsDestroyed) { cubeBlock.CubeGrid.ApplyDestructionDeformation(cubeBlock); } VRageRender.MyRenderProxy.GetRenderProfiler().EndProfilingBlock(); } foreach (var neighbour in cubeBlock.Neighbours) { neighbour.CubeGrid.Physics.AddDirtyBlock(neighbour); } cubeBlock.CubeGrid.Physics.AddDirtyBlock(cubeBlock); } } VRageRender.MyRenderProxy.GetRenderProfiler().EndProfilingBlock(); var sphere = damageInfo.Sphere; if (!MyDebugDrawSettings.DEBUG_DRAW_VOLUMETRIC_EXPLOSION_COLORING) { foreach (var grid in explodedGrids) { /*VRageRender.MyRenderProxy.GetRenderProfiler().StartProfilingBlock("UpdateDirty"); grid.UpdateDirty(); VRageRender.MyRenderProxy.GetRenderProfiler().EndProfilingBlock();*/ VRageRender.MyRenderProxy.GetRenderProfiler().StartProfilingBlock("CreateExplosionDebris"); if (m_explosionInfo.HitEntity == grid) { BoundingBoxD aabb = BoundingBoxD.CreateFromSphere(new BoundingSphereD(sphere.Center, sphere.Radius * 1.5f)); MyDebris.Static.CreateExplosionDebris(ref sphere, grid, ref aabb, 0.5f, false); } VRageRender.MyRenderProxy.GetRenderProfiler().EndProfilingBlock(); } } }
private void ApplyVolumetricExplosionOnEntities(ref MyExplosionInfo m_explosionInfo, List<MyEntity> entities, MyDamageInfo explosionDamageInfo) { Debug.Assert(Sync.IsServer); foreach (var entity in entities) { //Special case for characters in cockpits var character = entity as MyCharacter; if (character != null) { var cockpit = character.IsUsing as MyCockpit; if (cockpit != null) { if (explosionDamageInfo.ExplosionDamage.DamagedBlocks.ContainsKey(cockpit.SlimBlock)) { float damageRemaining = explosionDamageInfo.ExplosionDamage.DamageRemaining[cockpit.SlimBlock].DamageRemaining; character.DoDamage(damageRemaining, MyDamageType.Explosion, true, attackerId: m_explosionInfo.OwnerEntity != null ? m_explosionInfo.OwnerEntity.EntityId : 0); } continue; } } var raycastDamageInfo = explosionDamageInfo.ExplosionDamage.ComputeDamageForEntity(entity.PositionComp.WorldAABB.Center); float damage = raycastDamageInfo.DamageRemaining; float entityDistanceToExplosion = (float)(entity.PositionComp.WorldAABB.Center - explosionDamageInfo.Sphere.Center).Length(); damage *= (float)(1 - (entityDistanceToExplosion - raycastDamageInfo.DistanceToExplosion) / (explosionDamageInfo.Sphere.Radius - raycastDamageInfo.DistanceToExplosion)); if (damage <= 0f) continue; if (entity.Physics != null && entity.Physics.Enabled) { var ammoBase = entity as MyAmmoBase; if (ammoBase != null) { if (Vector3.DistanceSquared(m_explosionSphere.Center, ammoBase.PositionComp.GetPosition()) < 4 * m_explosionSphere.Radius * m_explosionSphere.Radius) { ammoBase.MarkedToDestroy = true; } ammoBase.Explode(); } float forceMultiplier = damage / 50000f; // Throws surrounding objects away from centre of the explosion. if (m_explosionInfo.ApplyForceAndDamage) { m_explosionInfo.StrengthImpulse = MyExplosionsConstants.EXPLOSION_STRENGTH_IMPULSE * (float)m_explosionSphere.Radius; m_explosionInfo.StrengthAngularImpulse = MyExplosionsConstants.EXPLOSION_STRENGTH_ANGULAR_IMPULSE; m_explosionInfo.HitEntity = m_explosionInfo.HitEntity != null ? m_explosionInfo.HitEntity.GetBaseEntity() : null; VRageRender.MyRenderProxy.GetRenderProfiler().StartProfilingBlock("ApplyExplosionForceAndDamage"); if (entity.PositionComp.WorldAABB.Center != m_explosionSphere.Center) { entity.Physics.AddForce( MyPhysicsForceType.APPLY_WORLD_IMPULSE_AND_WORLD_ANGULAR_IMPULSE, forceMultiplier * m_explosionInfo.StrengthImpulse * Vector3.Normalize(entity.PositionComp.WorldAABB.Center - m_explosionSphere.Center), entity.PositionComp.WorldAABB.Center, null); } VRageRender.MyRenderProxy.GetRenderProfiler().EndProfilingBlock(); } } if (!(entity is IMyDestroyableObject)) continue; var destroyableObj = entity as IMyDestroyableObject; destroyableObj.DoDamage(damage, MyDamageType.Explosion, true, attackerId: m_explosionInfo.OwnerEntity != null ? m_explosionInfo.OwnerEntity.EntityId : 0); } }
MyDamageInfo ApplyVolumetricExplosionOnGrid(ref MyExplosionInfo explosionInfo, ref BoundingSphereD sphere, List<MyEntity> entities) { Debug.Assert(Sandbox.Game.Multiplayer.Sync.IsServer, "This is supposed to be only server method"); VRageRender.MyRenderProxy.GetRenderProfiler().StartProfilingBlock("ApplyExplosionOnGrid"); bool gridWasHit = false; HashSet<MySlimBlock> explodedBlocks = new HashSet<MySlimBlock>(); Dictionary<MySlimBlock, float> damagedBlocks = new Dictionary<MySlimBlock, float>(); HashSet<MyCubeGrid> explodedGrids = new HashSet<MyCubeGrid>(); foreach (var entity in entities) { MyCubeGrid grid = entity as MyCubeGrid; if (grid != null && grid.CreatePhysics) { explodedGrids.Add(grid); var detectionHalfSize = grid.GridSize / 2 / 1.25f; var invWorldGrid = MatrixD.Invert(grid.WorldMatrix); VRageRender.MyRenderProxy.GetRenderProfiler().StartProfilingBlock("GetBlocksInsideSpheres"); BoundingSphereD innerSphere = new BoundingSphereD(sphere.Center, (float)Math.Max(0.1f, sphere.Radius - grid.GridSize)); BoundingSphereD exactSphere = new BoundingSphereD(sphere.Center, sphere.Radius); BoundingSphereD outerSphere = new BoundingSphereD(sphere.Center, sphere.Radius + grid.GridSize * 0.5f * (float)Math.Sqrt(3)); grid.GetBlocksInsideSpheres( ref innerSphere, ref exactSphere, ref outerSphere, m_explodedBlocksInner, m_explodedBlocksExact, m_explodedBlocksOuter, false, detectionHalfSize, ref invWorldGrid); VRageRender.MyRenderProxy.GetRenderProfiler().EndProfilingBlock(); m_explodedBlocksInner.UnionWith(m_explodedBlocksExact); explodedBlocks.UnionWith(m_explodedBlocksInner); VRageRender.MyRenderProxy.GetRenderProfiler().StartProfilingBlock("outerSphere2"); foreach (var cubeBlock in m_explodedBlocksOuter) { grid.Physics.AddDirtyBlock(cubeBlock); } VRageRender.MyRenderProxy.GetRenderProfiler().EndProfilingBlock(); m_explodedBlocksInner.Clear(); m_explodedBlocksExact.Clear(); m_explodedBlocksOuter.Clear(); gridWasHit = true; } } VRageRender.MyRenderProxy.GetRenderProfiler().EndProfilingBlock(); var damage = new MyExplosionDamage(explodedBlocks, sphere, explosionInfo.Damage); var damageInfo = new MyDamageInfo { GridWasHit = gridWasHit, ExplosionDamage = damage, AffectedCubeBlocks = explodedBlocks, AffectedCubeGrids = explodedGrids, Sphere = sphere }; return damageInfo; }
private void ApplyVolumetriDamageToGrid(MyDamageInfo damageInfo) { var damagedBlocks = damageInfo.ExplosionDamage.DamagedBlocks; var explodedBlocks = damageInfo.AffectedCubeBlocks; var explodedGrids = damageInfo.AffectedCubeGrids; VRageRender.MyRenderProxy.GetRenderProfiler().StartProfilingBlock("foreach (var damagedBlock in damagedBlocks)"); if (MyDebugDrawSettings.DEBUG_DRAW_VOLUMETRIC_EXPLOSION_COLORING) { foreach (var explodedBlock in explodedBlocks) { explodedBlock.CubeGrid.ChangeColor(explodedBlock, new Vector3(0.66f, 1f, 1f)); } foreach (var damagedBlock in damagedBlocks) { float hue = 1f - damagedBlock.Value / damageInfo.ExplosionDamage.Damage; damagedBlock.Key.CubeGrid.ChangeColor(damagedBlock.Key, new Vector3(hue / 3f, 1.0f, 0.5f)); } } else { foreach (var damagedBlock in damagedBlocks) { var cubeBlock = damagedBlock.Key; if (cubeBlock.FatBlock != null && cubeBlock.FatBlock.MarkedForClose) continue; if (cubeBlock.FatBlock == null && cubeBlock.Integrity / cubeBlock.DeformationRatio < damagedBlock.Value) { VRageRender.MyRenderProxy.GetRenderProfiler().StartProfilingBlock("RemoveBlock"); cubeBlock.CubeGrid.RemoveDestroyedBlock(cubeBlock); VRageRender.MyRenderProxy.GetRenderProfiler().EndProfilingBlock(); } else { VRageRender.MyRenderProxy.GetRenderProfiler().StartProfilingBlock("ApplyDestructionDeformation"); float damage = damagedBlock.Value; if (cubeBlock.FatBlock != null) { damage *= 7f; } (cubeBlock as IMyDestroyableObject).DoDamage(damage, MyDamageType.Explosion, true); if (!cubeBlock.IsDestroyed) { cubeBlock.CubeGrid.ApplyDestructionDeformation(cubeBlock); } VRageRender.MyRenderProxy.GetRenderProfiler().EndProfilingBlock(); } foreach (var neighbour in cubeBlock.Neighbours) { neighbour.CubeGrid.Physics.AddDirtyBlock(neighbour); } cubeBlock.CubeGrid.Physics.AddDirtyBlock(cubeBlock); } } VRageRender.MyRenderProxy.GetRenderProfiler().EndProfilingBlock(); var sphere = damageInfo.Sphere; if (!MyDebugDrawSettings.DEBUG_DRAW_VOLUMETRIC_EXPLOSION_COLORING) { foreach (var grid in explodedGrids) { VRageRender.MyRenderProxy.GetRenderProfiler().StartProfilingBlock("UpdateDirty"); grid.UpdateDirty(); VRageRender.MyRenderProxy.GetRenderProfiler().EndProfilingBlock(); VRageRender.MyRenderProxy.GetRenderProfiler().StartProfilingBlock("CreateExplosionDebris"); if (m_explosionInfo.HitEntity == grid) { BoundingBoxD aabb = BoundingBoxD.CreateFromSphere(new BoundingSphereD(sphere.Center, sphere.Radius * 1.5f)); MyDebris.Static.CreateExplosionDebris(ref sphere, grid, ref aabb, 0.5f, false); } VRageRender.MyRenderProxy.GetRenderProfiler().EndProfilingBlock(); } } }