/// <param name="damage">Not used for now but could be used as a multiplier instead of random decal size</param> public static void HandleAddDecal(IMyEntity entity, MyHitInfo hitInfo, MyStringHash source = default(MyStringHash), float damage = -1) { if (entity == null) DebugNullEntity(); IMyDecalProxy proxy = entity as IMyDecalProxy; if (proxy != null) { AddDecal(proxy, ref hitInfo, damage, source); return; } MyCubeGrid grid = entity.GetTopMostParent() as MyCubeGrid; if (grid != null) { var block = grid.GetTargetedBlock(hitInfo.Position); if (block != null) { var compoundBlock = block.FatBlock as MyCompoundCubeBlock; if (compoundBlock == null) proxy = block; else proxy = compoundBlock; } } if (proxy != null) AddDecal(proxy, ref hitInfo, damage, source); }
/// <param name="damage">Not used for now but could be used as a multiplier instead of random decal size</param> public static void HandleAddDecal(IMyEntity entity, MyHitInfo hitInfo, MyStringHash source = default(MyStringHash), object customdata = null, float damage = -1) { IMyDecalProxy proxy = entity as IMyDecalProxy; if (proxy != null) { AddDecal(proxy, ref hitInfo, damage, source, customdata); return; } MyCubeGrid grid = entity as MyCubeGrid; if (grid != null) { var block = grid.GetTargetedBlock(hitInfo.Position); if (block != null) { var compoundBlock = block.FatBlock as MyCompoundCubeBlock; if (compoundBlock == null) proxy = block; else proxy = compoundBlock; } } if (proxy == null) return; AddDecal(proxy, ref hitInfo, damage, source, customdata); }
private static void AddDecal(IMyDecalProxy proxy, ref MyHitInfo hitInfo, float damage, MyStringHash source, object customdata) { bool skip = DefaultFilterProxy(proxy); if (skip) return; m_handler.Source = source; m_handler.Enabled = true; proxy.AddDecals(hitInfo, source, customdata, m_handler); m_handler.Enabled = false; m_handler.Source = MyStringHash.NullOrEmpty; }
private static void AddDecal(IMyDecalProxy proxy, ref MyHitInfo hitInfo, float damage, MyStringHash source) { bool skip = DefaultFilterProxy(proxy); if (skip) return; MyDecalRenderData data; proxy.GetDecalRenderData(hitInfo, out data); if (data.Skip) return; MyDecalMaterial material; bool found = MyDecalMaterials.TryGetDecalMaterial(data.Material.String, source.String, out material); if (!found) { if (MyFakes.ENABLE_USE_DEFAULT_DAMAGE_DECAL) found = MyDecalMaterials.TryGetDecalMaterial(DEFAULT, DEFAULT, out material); if (!found) return; } var perp = Vector3.CalculatePerpendicularVector(data.Normal); float rotation = material.Rotation; if (material.Rotation == float.PositiveInfinity) rotation = MyRandom.Instance.NextFloat() * MathHelper.TwoPi; if (rotation != 0) { // Rotate around normal Quaternion q = Quaternion.CreateFromAxisAngle(data.Normal, rotation); perp = new Vector3((new Quaternion(perp, 0) * q).ToVector4()); } var pos = MatrixD.CreateWorld(data.Position, data.Normal, perp); var size = material.MinSize; if (material.MaxSize > material.MinSize) size += MyRandom.Instance.NextFloat() * (material.MaxSize - material.MinSize); pos = Matrix.CreateScale(new Vector3(size, size, material.Depth)) * pos; var decalId = MyRenderProxy.CreateDecal(data.RenderObjectId, pos, material.GetStringId()); proxy.OnAddDecal(decalId, ref data); }
/// <param name="damage">Not used for now but could be used as a multiplier instead of random decal size</param> public static void HandleAddDecal(IMyEntity entity, MyHitInfo hitInfo, MyStringHash source = default(MyStringHash), object customdata = null, float damage = -1) { IMyDecalProxy proxy = entity as IMyDecalProxy; if (proxy != null) { AddDecal(proxy, ref hitInfo, damage, source, customdata); return; } MyCubeGrid grid = entity as MyCubeGrid; if (grid != null) { MyCubeGridHitInfo info = customdata as MyCubeGridHitInfo; MySlimBlock block; if (info == null) { block = grid.GetTargetedBlock(hitInfo.Position); } else { // If info is provided, lookup for the cube using provided position MyCube cube; bool found = grid.TryGetCube(info.Position, out cube); if (!found) return; block = cube.CubeBlock; } var compoundBlock = block != null ? block.FatBlock as MyCompoundCubeBlock : null; if (compoundBlock == null) proxy = block; else proxy = compoundBlock; } if (proxy == null) return; AddDecal(proxy, ref hitInfo, damage, source, customdata); }
void IMyDecalProxy.GetDecalRenderData(MyHitInfo hitInfo, out MyDecalRenderData renderable) { // TODO renderable = new MyDecalRenderData(); renderable.Skip = true; }
void IMyDecalProxy.AddDecals(MyHitInfo hitInfo, MyStringHash source, object customdata, IMyDecalHandler decalHandler) { MyCharacterHitInfo charHitInfo = customdata as MyCharacterHitInfo; if (charHitInfo == null || charHitInfo.BoneIndex == -1) return; MyDecalRenderInfo renderable = new MyDecalRenderInfo(); renderable.Position = charHitInfo.Triangle.IntersectionPointInObjectSpace; renderable.Normal = charHitInfo.Triangle.NormalInObjectSpace; renderable.RenderObjectId = Render.GetRenderObjectID(); renderable.Material = MyStringHash.GetOrCompute(m_characterDefinition.PhysicalMaterial); var decalId = decalHandler.AddDecal(ref renderable); if (decalId == null) return; AddBoneDecal(decalId.Value, charHitInfo.HitPositionBindingPose, charHitInfo.HitNormalBindingPose, charHitInfo.BoneIndex); }
void IMyDecalProxy.AddDecals(MyHitInfo hitInfo, MyStringHash source, object customdata, IMyDecalHandler decalHandler) { MyDecalRenderInfo renderable = new MyDecalRenderInfo(); MyCubeGridHitInfo gridHitInfo = customdata as MyCubeGridHitInfo; renderable.Flags = BlockDefinition.PhysicalMaterial.Transparent ? MyDecalFlags.Transparent : MyDecalFlags.None; if (FatBlock == null) { renderable.Position = Vector3D.Transform(hitInfo.Position, CubeGrid.PositionComp.WorldMatrixInvScaled); renderable.Normal = Vector3D.TransformNormal(hitInfo.Normal, CubeGrid.PositionComp.WorldMatrixInvScaled); renderable.RenderObjectId = CubeGrid.Render.GetRenderObjectID(); } else { renderable.Position = Vector3D.Transform(hitInfo.Position, FatBlock.PositionComp.WorldMatrixInvScaled); renderable.Normal = Vector3D.TransformNormal(hitInfo.Normal, FatBlock.PositionComp.WorldMatrixInvScaled); renderable.RenderObjectId = FatBlock.Render.GetRenderObjectID(); } renderable.Material = MyStringHash.GetOrCompute(BlockDefinition.PhysicalMaterial.Id.SubtypeName); if (gridHitInfo != null) { VertexBoneIndicesWeights? boneIndicesWeights = gridHitInfo.Triangle.GetAffectingBoneIndicesWeights(ref m_boneIndexWeightTmp); if (boneIndicesWeights.HasValue) { renderable.BoneIndices = boneIndicesWeights.Value.Indices; renderable.BoneWeights = boneIndicesWeights.Value.Weights; var decalId = decalHandler.AddDecal(ref renderable); if (decalId != null) CubeGrid.RenderData.AddDecal(Position, gridHitInfo, decalId.Value); return; } } decalHandler.AddDecal(ref renderable); }
public void DoDamage(float damage, MyStringHash damageType, MyHitInfo? hitInfo = null, bool addDirtyParts = true, long attackerId = 0) { if (!CubeGrid.BlocksDestructionEnabled && !ForceBlockDestructible) return; var compoundBlock = FatBlock as MyCompoundCubeBlock; if (compoundBlock != null) //jn: TODO think of something better { compoundBlock.DoDamage(damage, damageType, hitInfo, attackerId); return; } if (IsMultiBlockPart) { var multiBlockInfo = CubeGrid.GetMultiBlockInfo(MultiBlockId); Debug.Assert(multiBlockInfo != null); if (multiBlockInfo != null) { Debug.Assert(m_tmpMultiBlocks.Count == 0); m_tmpMultiBlocks.AddRange(multiBlockInfo.Blocks); float totalMaxIntegrity = multiBlockInfo.GetTotalMaxIntegrity(); foreach (var multiBlockPart in m_tmpMultiBlocks) multiBlockPart.DoDamageInternal(damage * (multiBlockPart.MaxIntegrity / totalMaxIntegrity), damageType, addDirtyParts: addDirtyParts, hitInfo: hitInfo, attackerId: attackerId); m_tmpMultiBlocks.Clear(); } } else { DoDamageInternal(damage, damageType, addDirtyParts: addDirtyParts, hitInfo: hitInfo, attackerId: attackerId); } }
bool IMyDestroyableObject.DoDamage(float damage, MyStringHash damageType, bool sync, MyHitInfo? hitInfo, long attackerId) { if (MarkedToExplode || (!MySession.Static.DestructibleBlocks)) return false; //if (!IsFunctional) // return false; if (sync) { if (Sync.IsServer) MySyncDamage.DoDamageSynced(this, damage, damageType, attackerId); } else { MyDamageInformation damageInfo = new MyDamageInformation(false, damage, damageType, attackerId); if (UseDamageSystem) MyDamageSystem.Static.RaiseBeforeDamageApplied(this, ref damageInfo); m_damageType = damageType; if (damageInfo.Amount > 0) { if (UseDamageSystem) MyDamageSystem.Static.RaiseAfterDamageApplied(this, damageInfo); OnDestroy(); if (UseDamageSystem) MyDamageSystem.Static.RaiseDestroyed(this, damageInfo); } } return true; }
private void DoDamage(float damage, MyHitInfo hitInfo, object customdata, IMyEntity damagedEntity) { //damage tracking MyEntity ent = (MyEntity)MySession.Static.ControlledEntity; if (this.OwnerEntityAbsolute != null && this.OwnerEntityAbsolute.Equals(MySession.Static.ControlledEntity) && (damagedEntity is IMyDestroyableObject || damagedEntity is MyCubeGrid)) { MySession.Static.TotalDamageDealt += (uint)damage; } MyDecals.HandleAddDecal(damagedEntity, hitInfo, m_projectileAmmoDefinition.PhysicalMaterial, customdata, damage); if (!Sync.IsServer) return; if (m_projectileAmmoDefinition.PhysicalMaterial == m_hashBolt) { IMyDestroyableObject destroyable = damagedEntity as IMyDestroyableObject; if (destroyable != null && damagedEntity is MyCharacter) destroyable.DoDamage(damage, MyDamageType.Bolt, true, hitInfo, m_weapon != null ? GetSubpartOwner(m_weapon).EntityId : 0); } else { var grid = damagedEntity as MyCubeGrid; IMyDestroyableObject destroyable; if (grid != null) { if (grid.Physics != null && grid.Physics.Enabled && (grid.BlocksDestructionEnabled || MyFakes.ENABLE_VR_FORCE_BLOCK_DESTRUCTIBLE)) { bool causeDeformation = false; var block = grid.GetTargetedBlock(hitInfo.Position); if (block != null && (grid.BlocksDestructionEnabled || block.ForceBlockDestructible)) { block.DoDamage(damage, MyDamageType.Bullet, true, hitInfo, m_weapon != null ? GetSubpartOwner(m_weapon).EntityId : 0); if (block.FatBlock == null) causeDeformation = true; } if (grid.BlocksDestructionEnabled && causeDeformation) ApllyDeformationCubeGrid(hitInfo.Position, grid); } } //By Gregory: When MyEntitySubpart (e.g. extended parts of pistons and doors) damage the whole parent component //Temporary fix! Maybe other solution? MyEntitySubpart cannot implement IMyDestroyableObject cause is on dependent namespace else if (damagedEntity is MyEntitySubpart) { if (damagedEntity.Parent != null && damagedEntity.Parent.Parent is MyCubeGrid) { hitInfo.Position = damagedEntity.Parent.WorldAABB.Center; DoDamage(damage, hitInfo, customdata, damagedEntity.Parent.Parent); } } else if ((destroyable = damagedEntity as IMyDestroyableObject) != null) destroyable.DoDamage(damage, MyDamageType.Bullet, true, hitInfo, m_weapon != null ? GetSubpartOwner(m_weapon).EntityId : 0); } //Handle damage ?? some WIP code by Ondrej //MyEntity damagedObject = entity; //damagedObject.DoDamage(m_ammoProperties.HealthDamage, m_ammoProperties.ShipDamage, m_ammoProperties.EMPDamage, m_ammoProperties.DamageType, m_ammoProperties.AmmoType, m_ignorePhysObject); //if (MyMultiplayerGameplay.IsRunning) // MyMultiplayerGameplay.Static.ProjectileHit(damagedObject, intersectionValue.IntersectionPointInWorldSpace, this.m_directionNormalized, MyAmmoConstants.FindAmmo(m_ammoProperties), this.OwnerEntity); }
// Update position, check collisions, etc. // Return false if projectile dies/timeouts in this tick. public bool Update() { // Projectile was killed , but still not last time drawn, so we don't need to do update (we are waiting for last draw) if (m_state == MyProjectileStateEnum.KILLED) return true; // Projectile was killed and last time drawn, so we can finally remove it from buffer if (m_state == MyProjectileStateEnum.KILLED_AND_DRAWN) { StopEffect(); return false; } Vector3D position = m_position; m_position += m_velocity * VRage.Game.MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS * MyFakes.SIMULATION_SPEED; // Distance timeout Vector3 positionDelta = m_position - m_origin; if (Vector3.Dot(positionDelta, positionDelta) >= m_maxTrajectory * m_maxTrajectory) { StopEffect(); m_state = MyProjectileStateEnum.KILLED; return true; } m_checkIntersectionIndex = ++m_checkIntersectionIndex % CHECK_INTERSECTION_INTERVAL; if (m_checkIntersectionIndex != 0 && m_positionChecked) //check only each n-th intersection return true; // Calculate hit point, create decal and throw debris particles Vector3D lineEndPosition = position + CHECK_INTERSECTION_INTERVAL * (m_velocity * VRage.Game.MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS * MyFakes.SIMULATION_SPEED); LineD line = new LineD(m_positionChecked ? position : m_origin, lineEndPosition); m_positionChecked = true; IMyEntity entity; Vector3D hitPosition; Vector3 hitNormal; MyCharacterHitInfo charHitInfo; GetHitEntityAndPosition(line, out entity, out hitPosition, out hitNormal, out charHitInfo); if (entity == null || entity == m_ignoreEntity || entity.Physics == null) return true; if (IsIgnoredEntity(entity)) { return true; // prevent player shooting himself } ProfilerShort.Begin("Projectile.Update"); bool headShot = false; MyCharacter hitCharacter = entity as MyCharacter; if (hitCharacter != null) { IStoppableAttackingTool stoppableTool = hitCharacter.CurrentWeapon as IStoppableAttackingTool; if (stoppableTool != null) stoppableTool.StopShooting(OwnerEntity); headShot = charHitInfo.HitHead && m_projectileAmmoDefinition.HeadShot; // allow head shots only for ammo supporting it in definition } m_position = hitPosition; bool isProjectileGroupKilled = false; if (!isProjectileGroupKilled) { MySurfaceImpactEnum surfaceImpact; MyStringHash materialType; GetSurfaceAndMaterial(entity, ref hitPosition, out surfaceImpact, out materialType); PlayHitSound(materialType, entity, hitPosition, m_projectileAmmoDefinition.PhysicalMaterial); MyHitInfo hitInfo = new MyHitInfo(); hitInfo.Normal = hitNormal; hitInfo.Position = hitPosition; hitInfo.Velocity = m_velocity; float damage = headShot ? m_projectileAmmoDefinition.ProjectileHeadShotDamage : m_projectileAmmoDefinition.ProjectileMassDamage; DoDamage(damage, hitInfo, charHitInfo, entity); //particle effect defined in materialProperties.sbc Vector3D particleHitPosition = hitPosition + line.Direction * -0.2; if (MyMaterialPropertiesHelper.Static.TryCreateCollisionEffect(MyMaterialPropertiesHelper.CollisionType.Hit, particleHitPosition, hitNormal, m_projectileAmmoDefinition.PhysicalMaterial, materialType) == false) { //default effect when none other was found if (surfaceImpact != MySurfaceImpactEnum.CHARACTER) MyParticleEffects.CreateBasicHitParticles(m_projectileAmmoDefinition.ProjectileOnHitEffectName, ref hitPosition, ref hitNormal, ref line.Direction, entity, m_weapon, 1, OwnerEntity); } CreateDecal(materialType); if (m_weapon == null || (entity.GetTopMostParent() != m_weapon.GetTopMostParent())) ApplyProjectileForce(entity, hitPosition, m_directionNormalized, false, m_projectileAmmoDefinition.ProjectileHitImpulse * m_impulseMultiplier); StopEffect(); m_state = MyProjectileStateEnum.KILLED; } ProfilerShort.End(); return true; }
/// <summary> /// Updates resource. /// </summary> public override void UpdateBeforeSimulation() { try { VRageRender.MyRenderProxy.GetRenderProfiler().StartProfilingBlock("MyMissile.UpdateBeforeSimulation"); if (m_isExploded) { if (Sandbox.Game.Multiplayer.Sync.IsServer) { // Create explosion float radius = m_missileAmmoDefinition.MissileExplosionRadius; BoundingSphereD explosionSphere = new BoundingSphereD(m_collisionPoint.HasValue ? m_collisionPoint.Value : PositionComp.GetPosition(), radius); MyEntity ownerEntity = null; var ownerId = Sync.Players.TryGetIdentity(m_owner); if (ownerId != null) ownerEntity = ownerId.Character; //MyEntities.TryGetEntityById(m_owner, out ownerEntity); // Call main explosion starter MyExplosionInfo info = new MyExplosionInfo() { PlayerDamage = 0, //Damage = m_ammoProperties.Damage, Damage = MyFakes.ENABLE_VOLUMETRIC_EXPLOSION ? m_missileAmmoDefinition.MissileExplosionDamage : 200, ExplosionType = m_explosionType, ExplosionSphere = explosionSphere, LifespanMiliseconds = MyExplosionsConstants.EXPLOSION_LIFESPAN, CascadeLevel = CascadedExplosionLevel, HitEntity = m_collidedEntity, ParticleScale = 0.2f, OwnerEntity = ownerEntity, Direction = WorldMatrix.Forward, VoxelExplosionCenter = explosionSphere.Center + radius * WorldMatrix.Forward * 0.25f, ExplosionFlags = MyExplosionFlags.AFFECT_VOXELS | MyExplosionFlags.APPLY_FORCE_AND_DAMAGE | MyExplosionFlags.CREATE_DEBRIS | MyExplosionFlags.CREATE_DECALS | MyExplosionFlags.CREATE_SHRAPNELS | MyExplosionFlags.APPLY_DEFORMATION, VoxelCutoutScale = 0.3f, PlaySound = true, ApplyForceAndDamage = true }; if (!MarkedToDestroy) info.ExplosionFlags |= MyExplosionFlags.CREATE_PARTICLE_EFFECT; MyExplosions.AddExplosion(ref info); if (m_collidedEntity != null && !(m_collidedEntity is MyAmmoBase)) { if (!m_collidedEntity.Physics.IsStatic) { m_collidedEntity.Physics.AddForce(MyPhysicsForceType.APPLY_WORLD_IMPULSE_AND_WORLD_ANGULAR_IMPULSE, 100 * Physics.LinearVelocity, m_collisionPoint, null); } } } //by Gregory: added null check. Decal won't be added if m_collidedEntity not found if (m_collisionPoint.HasValue && m_collidedEntity != null) { MyHitInfo hitInfo = new MyHitInfo(); hitInfo.Position = m_collisionPoint.Value; hitInfo.Normal = new Vector3D(1, 0, 0); // FIXME MyDecals.HandleAddDecal(m_collidedEntity, hitInfo, MyDamageType.Rocket); } Close(); return; } base.UpdateBeforeSimulation(); if (m_missileAmmoDefinition.MissileSkipAcceleration) Physics.LinearVelocity = WorldMatrix.Forward * m_missileAmmoDefinition.DesiredSpeed * 0.7f; else Physics.LinearVelocity += PositionComp.WorldMatrix.Forward * m_missileAmmoDefinition.MissileAcceleration * VRage.Game.MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS; if (m_smokeEffect == null) { // if (MyCamera.GetDistanceWithFOV(GetPosition()) < 150) { if (MyParticlesManager.TryCreateParticleEffect((int)MyParticleEffectsIDEnum.Smoke_Missile, out m_smokeEffect)) { m_smokeEffect.UserScale = 0.3f; var matrix = PositionComp.WorldMatrix; matrix.Translation -= matrix.Forward * m_smokeEffectOffsetMultiplier; m_smokeEffect.WorldMatrix = matrix; //m_smokeEffect.WorldMatrix = PositionComp.WorldMatrix; m_smokeEffect.AutoDelete = false; m_smokeEffect.CalculateDeltaMatrix = true; } } } Physics.AngularVelocity = Vector3.Zero; if ((Vector3.Distance(PositionComp.GetPosition(), m_origin) >= m_maxTrajectory)) { Explode(); return; } } finally { VRageRender.MyRenderProxy.GetRenderProfiler().EndProfilingBlock(); } }
internal void DoDamage(float damage, MyStringHash damageType, MyHitInfo? hitInfo, long attackerId) { float integrity = 0; foreach(var block in m_mapIdToBlock) { integrity += block.Value.MaxIntegrity; } for (int i = m_blocks.Count - 1; i >= 0; --i) { var block = m_blocks[i]; block.DoDamage(damage * (block.MaxIntegrity / integrity), damageType, hitInfo, true, attackerId); } }
void IMyDecalProxy.AddDecals(MyHitInfo hitInfo, MyStringHash source, object customdata, IMyDecalHandler decalHandler) { Debug.Assert(m_mapIdToBlock.Count > 0); MySlimBlock block = m_mapIdToBlock.First().Value; MyPhysicalMaterialDefinition physicalMaterial = block.BlockDefinition.PhysicalMaterial; MyDecalRenderInfo renderable = new MyDecalRenderInfo(); renderable.Flags = physicalMaterial.Transparent ? MyDecalFlags.Transparent : MyDecalFlags.None; renderable.Position = Vector3D.Transform(hitInfo.Position, CubeGrid.PositionComp.WorldMatrixInvScaled); renderable.Normal = Vector3D.TransformNormal(hitInfo.Normal, CubeGrid.PositionComp.WorldMatrixInvScaled); renderable.RenderObjectId = CubeGrid.Render.GetRenderObjectID(); renderable.Material = MyStringHash.GetOrCompute(physicalMaterial.Id.SubtypeName); var decalId = decalHandler.AddDecal(ref renderable); if (decalId != null) CubeGrid.RenderData.AddDecal(Position, decalId.Value); }
public void DoDamage(float damage, MyStringHash damageType, bool sync, MyHitInfo? hitInfo, long attackerId) { if (sync) { if (Sync.IsServer) MySyncDamage.DoDamageSynced(Entity, damage, damageType, attackerId); } else { MyDamageInformation info = new MyDamageInformation(false, damage, damageType, attackerId); if (Entity.UseDamageSystem) MyDamageSystem.Static.RaiseBeforeDamageApplied(Entity, ref info); m_integrity -= info.Amount; if (Entity.UseDamageSystem) MyDamageSystem.Static.RaiseAfterDamageApplied(Entity, info); if (m_integrity <= 0 && Sync.IsServer) { m_closeAfterSimulation = Sync.IsServer; if (Entity.UseDamageSystem) MyDamageSystem.Static.RaiseDestroyed(Entity, info); return; } } return; }
public bool DoDamage(float damage, MyStringHash damageType, bool sync, MyHitInfo? hitInfo, long attackerId) { if (Sync.IsServer) { MyDamageInformation info = new MyDamageInformation(false, damage, damageType, attackerId); if (UseDamageSystem) MyDamageSystem.Static.RaiseBeforeDamageApplied(this, ref info); m_hitPoints -= info.Amount; if (UseDamageSystem) MyDamageSystem.Static.RaiseAfterDamageApplied(this, info); if (m_hitPoints <= 0) { MyFracturedPiecesManager.Static.RemoveFracturePiece(this, 2); if (UseDamageSystem) MyDamageSystem.Static.RaiseDestroyed(this, info); } } return true; }
void IMyDecalProxy.AddDecals(MyHitInfo hitInfo, MyStringHash source, object customdata, IMyDecalHandler decalHandler) { MyDecalRenderInfo info = new MyDecalRenderInfo(); info.Position = hitInfo.Position; info.Normal = hitInfo.Normal; info.RenderObjectId = -1; info.Flags = MyDecalFlags.World; info.Material = Physics.MaterialType; decalHandler.AddDecal(ref info); }
private void GetHitEntityAndPosition(LineD line, out IMyEntity entity, out Vector3D hitPosition, out Vector3 hitNormal, out MyCharacterHitInfo charHitInfo) { entity = null; hitPosition = hitNormal = Vector3.Zero; charHitInfo = null; // 1. rough raycast int raycastListIndex = 0; do { if (entity == null) { if (raycastListIndex == 0) // cast only the first iteration { ProfilerShort.Begin("MyGamePruningStructure::CastProjectileRay"); MyPhysics.CastRay(line.From, line.To, m_raycastResult, MyPhysics.CollisionLayers.DefaultCollisionLayer); ProfilerShort.End(); } if (raycastListIndex < m_raycastResult.Count) { MyPhysics.HitInfo hitInfo = m_raycastResult[raycastListIndex]; entity = hitInfo.HkHitInfo.GetHitEntity() as MyEntity; hitPosition = hitInfo.Position; hitNormal = hitInfo.HkHitInfo.Normal; } } // 2. prevent shooting through characters, retest trajectory between entity and player if (!(entity is MyCharacter) || entity == null) { // first: raycast, get all entities in line, limit distance if possible LineD lineLimited = new LineD(line.From, entity == null ? line.To : hitPosition); if (m_entityRaycastResult == null) { m_entityRaycastResult = new List<MyLineSegmentOverlapResult<MyEntity>>(16); } else { m_entityRaycastResult.Clear(); } MyGamePruningStructure.GetAllEntitiesInRay(ref lineLimited, m_entityRaycastResult); // second: precise tests, find best result double bestDistanceSq = double.MaxValue; IMyEntity entityBest = null; for (int i = 0; i < m_entityRaycastResult.Count; i++) { if (m_entityRaycastResult[i].Element is MyCharacter) { MyCharacter hitCharacter = m_entityRaycastResult[i].Element as MyCharacter; bool intersection = hitCharacter.GetIntersectionWithLine(ref line, ref m_charHitInfo); if (intersection) { double distanceSq = Vector3D.DistanceSquared(m_charHitInfo.Triangle.IntersectionPointInWorldSpace, line.From); if (distanceSq < bestDistanceSq && !IsIgnoredEntity(hitCharacter)) { bestDistanceSq = distanceSq; entityBest = hitCharacter; hitPosition = m_charHitInfo.Triangle.IntersectionPointInWorldSpace; hitNormal = m_charHitInfo.Triangle.NormalInWorldSpace; charHitInfo = m_charHitInfo; } } } } // finally: do we have best result? then return it if (entityBest != null) { entity = entityBest; return; // this was precise result, so return } } // 3. nothing found in the precise test? then fallback to already found results if (entity == null) return; // no fallback results if (entity is MyCharacter) // retest character found in fallback { MyCharacter hitCharacter = entity as MyCharacter; bool intersection = hitCharacter.GetIntersectionWithLine(ref line, ref m_charHitInfo); if (intersection) { hitPosition = m_charHitInfo.Triangle.IntersectionPointInWorldSpace; hitNormal = m_charHitInfo.Triangle.NormalInWorldSpace; charHitInfo = m_charHitInfo; } else { entity = null; // no hit. } } else if (entity is MyGhostCharacter) { MyHitInfo info = new MyHitInfo(); info.Position = hitPosition; info.Normal = hitNormal; } else { MyCubeGrid grid = entity as MyCubeGrid; if (grid != null) { MyIntersectionResultLineTriangleEx? result; bool success = grid.GetIntersectionWithLine(ref line, out result); if (success && result.HasValue) { hitPosition = result.Value.IntersectionPointInWorldSpace; hitNormal = result.Value.NormalInWorldSpace; if (Vector3.Dot(hitNormal, line.Direction) > 0) hitNormal = -hitNormal; } MyHitInfo info = new MyHitInfo(); info.Position = hitPosition; info.Normal = hitNormal; } } } while (entity == null && ++raycastListIndex < m_entityRaycastResult.Count); }
void IMyDecalProxy.AddDecals(MyHitInfo hitInfo, MyStringHash source, object customdata, IMyDecalHandler decalHandler) { MyDecalRenderInfo renderable = new MyDecalRenderInfo(); renderable.Flags = BlockDefinition.PhysicalMaterial.Transparent ? MyDecalFlags.Transparent : MyDecalFlags.None; if (FatBlock == null) { renderable.Position = Vector3D.Transform(hitInfo.Position, CubeGrid.PositionComp.WorldMatrixInvScaled); renderable.Normal = Vector3D.TransformNormal(hitInfo.Normal, CubeGrid.PositionComp.WorldMatrixInvScaled); renderable.RenderObjectId = CubeGrid.Render.GetRenderObjectID(); } else { renderable.Position = Vector3D.Transform(hitInfo.Position, FatBlock.PositionComp.WorldMatrixInvScaled); renderable.Normal = Vector3D.TransformNormal(hitInfo.Normal, FatBlock.PositionComp.WorldMatrixInvScaled); renderable.RenderObjectId = FatBlock.Render.GetRenderObjectID(); } renderable.Material = MyStringHash.GetOrCompute(BlockDefinition.PhysicalMaterial.Id.SubtypeName); var decalId = decalHandler.AddDecal(ref renderable); if (decalId != null) CubeGrid.RenderData.AddDecal(Position, decalId.Value); }
void RigidBody_ContactPointCallback_Destruction(ref HkContactPointEvent value) { ProfilerShort.Begin("Grid Contact counter"); ProfilerShort.End(); MyGridContactInfo info = new MyGridContactInfo(ref value, m_grid); if (info.IsKnown) return; var myEntity = info.CurrentEntity;//value.Base.BodyA.GetEntity() == m_grid.Components ? value.Base.BodyA.GetEntity() : value.Base.BodyB.GetEntity(); if (myEntity == null || myEntity.Physics == null || myEntity.Physics.RigidBody == null) { return; } var myBody = myEntity.Physics.RigidBody; // CH: DEBUG var physicsBody1 = value.GetPhysicsBody(0); var physicsBody2 = value.GetPhysicsBody(1); if (physicsBody1 == null || physicsBody2 == null) return; var entity1 = physicsBody1.Entity; var entity2 = physicsBody2.Entity; if (entity1 == null || entity2 == null || entity1.Physics == null || entity2.Physics == null) return; if (entity1 is MyFracturedPiece && entity2 is MyFracturedPiece) return; var rigidBody1 = value.Base.BodyA; var rigidBody2 = value.Base.BodyB; info.HandleEvents(); if (rigidBody1.HasProperty(HkCharacterRigidBody.MANIPULATED_OBJECT) || rigidBody2.HasProperty(HkCharacterRigidBody.MANIPULATED_OBJECT)) return; if (info.CollidingEntity is Sandbox.Game.Entities.Character.MyCharacter || info.CollidingEntity == null || info.CollidingEntity.MarkedForClose) return; var grid1 = entity1 as MyCubeGrid; var grid2 = entity2 as MyCubeGrid; // CH: TODO: This is a hack Instead, the IMyDestroyableObject should be used and the subpart DoDamage code could delegate it to the grid // The thing is, this approach would probably need a rewrite of this whole method... if (grid2 == null && entity2 is MyEntitySubpart) { while (entity2 != null && !(entity2 is MyCubeGrid)) { entity2 = entity2.Parent; } if (entity2 != null) { physicsBody2 = entity2.Physics as MyPhysicsBody; rigidBody2 = physicsBody2.RigidBody; grid2 = entity2 as MyCubeGrid; } } if (grid1 != null && grid2 != null && (MyCubeGridGroups.Static.Physical.GetGroup(grid1) == MyCubeGridGroups.Static.Physical.GetGroup(grid2))) return; ProfilerShort.Begin("Grid contact point callback"); { var vel = Math.Abs(value.SeparatingVelocity); bool enoughSpeed = vel > 3; //float dot = Vector3.Dot(Vector3.Normalize(LinearVelocity), Vector3.Normalize(info.CollidingEntity.Physics.LinearVelocity)); Vector3 velocity1 = rigidBody1.GetVelocityAtPoint(info.Event.ContactPoint.Position); Vector3 velocity2 = rigidBody2.GetVelocityAtPoint(info.Event.ContactPoint.Position); float speed1 = velocity1.Length(); float speed2 = velocity2.Length(); Vector3 dir1 = speed1 > 0 ? Vector3.Normalize(velocity1) : Vector3.Zero; Vector3 dir2 = speed2 > 0 ? Vector3.Normalize(velocity2) : Vector3.Zero; float mass1 = MyDestructionHelper.MassFromHavok(rigidBody1.Mass); float mass2 = MyDestructionHelper.MassFromHavok(rigidBody2.Mass); float impact1 = speed1 * mass1; float impact2 = speed2 * mass2; float dot1withNormal = speed1 > 0 ? Vector3.Dot(dir1, value.ContactPoint.Normal) : 0; float dot2withNormal = speed2 > 0 ? Vector3.Dot(dir2, value.ContactPoint.Normal) : 0; speed1 *= Math.Abs(dot1withNormal); speed2 *= Math.Abs(dot2withNormal); bool is1Static = mass1 == 0; bool is2Static = mass2 == 0; bool is1Small = entity1 is MyFracturedPiece || (grid1 != null && grid1.GridSizeEnum == MyCubeSize.Small); bool is2Small = entity2 is MyFracturedPiece || (grid2 != null && grid2.GridSizeEnum == MyCubeSize.Small); float dot = Vector3.Dot(dir1, dir2); float maxDestructionRadius = 0.5f; impact1 *= info.ImpulseMultiplier; impact2 *= info.ImpulseMultiplier; MyHitInfo hitInfo = new MyHitInfo(); var hitPos = info.ContactPosition; hitInfo.Normal = value.ContactPoint.Normal; //direct hit if (dot1withNormal < 0.0f) { if (entity1 is MyFracturedPiece) impact1 /= 10; impact1 *= Math.Abs(dot1withNormal); //respect angle of hit if ((impact1 > 2000 && speed1 > 2 && !is2Small) || (impact1 > 500 && speed1 > 10)) //must be fast enought to destroy fracture piece (projectile) { //1 is big hitting if (is2Static || impact1 / impact2 > 10) { hitInfo.Position = hitPos + 0.1f * hitInfo.Normal; impact1 -= mass1; if (Sync.IsServer && impact1 > 0) { if (grid1 != null) { var blockPos = GetGridPosition(value.ContactPoint, rigidBody1, grid1, 0); grid1.DoDamage(impact1, hitInfo, blockPos, grid2 != null ? grid2.EntityId : 0); } else MyDestructionHelper.TriggerDestruction(impact1, (MyPhysicsBody)entity1.Physics, info.ContactPosition, value.ContactPoint.Normal, maxDestructionRadius); hitInfo.Position = hitPos - 0.1f * hitInfo.Normal; if (grid2 != null) { var blockPos = GetGridPosition(value.ContactPoint, rigidBody2, grid2, 1); grid2.DoDamage(impact1, hitInfo, blockPos, grid1 != null ? grid1.EntityId : 0); } else MyDestructionHelper.TriggerDestruction(impact1, (MyPhysicsBody)entity2.Physics, info.ContactPosition, value.ContactPoint.Normal, maxDestructionRadius); ReduceVelocities(info); } MyDecals.HandleAddDecal(entity1, hitInfo); MyDecals.HandleAddDecal(entity2, hitInfo); } } } if (dot2withNormal < 0.0f) { if (entity2 is MyFracturedPiece) impact2 /= 10; impact2 *= Math.Abs(dot2withNormal); //respect angle of hit if (impact2 > 2000 && speed2 > 2 && !is1Small || (impact2 > 500 && speed2 > 10)) //must be fast enought to destroy fracture piece (projectile) { //2 is big hitting if (is1Static || impact2 / impact1 > 10) { hitInfo.Position = hitPos + 0.1f * hitInfo.Normal; impact2 -= mass2; if (Sync.IsServer && impact2 > 0) { if (grid1 != null) { var blockPos = GetGridPosition(value.ContactPoint, rigidBody1, grid1, 0); grid1.DoDamage(impact2, hitInfo, blockPos, grid2 != null ? grid2.EntityId : 0); } else MyDestructionHelper.TriggerDestruction(impact2, (MyPhysicsBody)entity1.Physics, info.ContactPosition, value.ContactPoint.Normal, maxDestructionRadius); hitInfo.Position = hitPos - 0.1f * hitInfo.Normal; if (grid2 != null) { var blockPos = GetGridPosition(value.ContactPoint, rigidBody2, grid2, 1); grid2.DoDamage(impact2, hitInfo, blockPos, grid1 != null ? grid1.EntityId : 0); } else MyDestructionHelper.TriggerDestruction(impact2, (MyPhysicsBody)entity2.Physics, info.ContactPosition, value.ContactPoint.Normal, maxDestructionRadius); ReduceVelocities(info); } MyDecals.HandleAddDecal(entity1, hitInfo); MyDecals.HandleAddDecal(entity2, hitInfo); } } } //float destructionImpact = vel * (MyDestructionHelper.MassFromHavok(Mass) + MyDestructionHelper.MassFromHavok(info.CollidingEntity.Physics.Mass)); //destructionImpact *= info.ImpulseMultiplier; //if (destructionImpact > 2000 && enoughSpeed) //{ // CreateDestructionFor(destructionImpact, LinearVelocity + info.CollidingEntity.Physics.LinearVelocity, this, info, value.ContactPoint.Normal); // CreateDestructionFor(destructionImpact, LinearVelocity + info.CollidingEntity.Physics.LinearVelocity, info.CollidingEntity.Physics, info, value.ContactPoint.Normal); // ReduceVelocities(info); //} } ProfilerShort.End(); }
private void GetHitEntityAndPosition(LineD line, out IMyEntity entity, out Vector3D hitPosition, out Vector3 hitNormal, out bool hitHead) { entity = null; hitPosition = hitNormal = Vector3.Zero; hitHead = false; // 1. rough raycast if (entity == null) { ProfilerShort.Begin("MyGamePruningStructure::CastProjectileRay"); MyPhysics.HitInfo? hitInfo = MyPhysics.CastRay(line.From, line.To, MyPhysics.CollisionLayers.DefaultCollisionLayer); ProfilerShort.End(); if (hitInfo.HasValue) { entity = hitInfo.Value.HkHitInfo.GetHitEntity() as MyEntity; hitPosition = hitInfo.Value.Position; hitNormal = hitInfo.Value.HkHitInfo.Normal; } } // 2. prevent shooting through characters, retest trajectory between entity and player if (!(entity is MyCharacter) || entity == null) { // first: raycast, get all entities in line, limit distance if possible LineD lineLimited = new LineD(line.From, entity == null ? line.To : hitPosition); if (m_entityRaycastResult == null) { m_entityRaycastResult = new List<MyLineSegmentOverlapResult<MyEntity>>(16); } else { m_entityRaycastResult.Clear(); } MyGamePruningStructure.GetAllEntitiesInRay(ref lineLimited, m_entityRaycastResult); // second: precise tests, find best result double bestDistanceSq = double.MaxValue; IMyEntity entityBest = null; for (int i = 0; i < m_entityRaycastResult.Count; i++) { if (m_entityRaycastResult[i].Element is MyCharacter) { MyCharacter hitCharacter = m_entityRaycastResult[i].Element as MyCharacter; VRage.Game.Models.MyIntersectionResultLineTriangleEx? t; hitCharacter.GetIntersectionWithLine(ref line, out t, out hitHead); if (t != null) { double distanceSq = Vector3D.DistanceSquared(t.Value.IntersectionPointInWorldSpace, line.From); if (distanceSq < bestDistanceSq) { bestDistanceSq = distanceSq; entityBest = hitCharacter; hitPosition = t.Value.IntersectionPointInWorldSpace; hitNormal = t.Value.NormalInWorldSpace; } } } } // finally: do we have best result? then return it if (entityBest != null) { entity = entityBest; return; // this was precise result, so return } } // 3. nothing found in the precise test? then fallback to already found results if (entity == null) return; // no fallback results if (entity is MyCharacter) // retest character found in fallback { MyCharacter hitCharacter = entity as MyCharacter; VRage.Game.Models.MyIntersectionResultLineTriangleEx? t; hitCharacter.GetIntersectionWithLine(ref line, out t, out hitHead); if (t == null) { entity = null; // no hit. } else { hitPosition = t.Value.IntersectionPointInWorldSpace; hitNormal = t.Value.NormalInWorldSpace; hitHead = hitHead && m_projectileAmmoDefinition.HeadShot; // allow head shots only for ammo supporting it in definition } } else { MyCubeGrid grid = entity as MyCubeGrid; if (grid != null) { MyIntersectionResultLineTriangleEx? result; bool success = grid.GetIntersectionWithLine(ref line, out result); if (success) { hitPosition = result.Value.IntersectionPointInWorldSpace; hitNormal = result.Value.NormalInWorldSpace; } MyHitInfo info = new MyHitInfo(); info.Position = hitPosition; info.Normal = hitNormal; } } }
public bool DoDamage(float damage, MyStringHash damageType, bool sync, MyHitInfo? hitInfo, long attackerId) { if (sync) { Debug.Assert(Sync.IsServer); if (Sync.IsServer) DoDamageSynced(this, damage, damageType, hitInfo, attackerId); } else this.DoDamage(damage, damageType, hitInfo: hitInfo, attackerId: attackerId); return true; }
void IMyDecalProxy.AddDecals(MyHitInfo hitInfo, MyStringHash source, object customdata, IMyDecalHandler decalHandler) { MyDecalRenderInfo renderable = new MyDecalRenderInfo(); renderable.Flags = MyDecalFlags.World; renderable.Position = hitInfo.Position; renderable.Normal = hitInfo.Normal; renderable.RenderObjectId = Render.GetRenderObjectID(); renderable.Material = Physics.GetMaterialAt(hitInfo.Position); decalHandler.AddDecal(ref renderable); }
public void DoDamageInternal(float damage, MyStringHash damageType, bool addDirtyParts = true, MyHitInfo? hitInfo = null, long attackerId = 0) { if (!CubeGrid.BlocksDestructionEnabled && !ForceBlockDestructible) return; damage *= DamageRatio; // Low-integrity blocks get more damage if (MyPerGameSettings.Destruction || MyFakes.ENABLE_VR_BLOCK_DEFORMATION_RATIO) { damage *= DeformationRatio; } ProfilerShort.Begin("FatBlock.DoDamage"); try { if (FatBlock != null && CubeGrid.Physics != null && CubeGrid.Physics.Enabled) //Fatblock dont have physics { var destroyable = FatBlock as IMyDestroyableObject; if (destroyable != null) destroyable.DoDamage(damage, damageType, false, attackerId: attackerId); } } finally { ProfilerShort.End(); } MyDamageInformation damageInfo = new MyDamageInformation(false, damage, damageType, attackerId); if (UseDamageSystem) MyDamageSystem.Static.RaiseBeforeDamageApplied(this, ref damageInfo); MySession.Static.NegativeIntegrityTotal += damageInfo.Amount; Debug.Assert(damageInfo.Amount > 0); AccumulatedDamage += damageInfo.Amount; if (m_componentStack.Integrity - AccumulatedDamage <= MyComponentStack.MOUNT_THRESHOLD) { if (MyPerGameSettings.Destruction && hitInfo.HasValue) { AccumulatedDamage = 0; var gridPhysics = CubeGrid.Physics; float maxDestructionRadius = CubeGrid.GridSizeEnum == MyCubeSize.Small ? 0.5f : 3; if (Sync.IsServer) Sandbox.Engine.Physics.MyDestructionHelper.TriggerDestruction(damageInfo.Amount - m_componentStack.Integrity, gridPhysics, hitInfo.Value.Position, hitInfo.Value.Normal, maxDestructionRadius); } else { ApplyAccumulatedDamage(addDirtyParts, attackerId: attackerId); } CubeGrid.RemoveFromDamageApplication(this); } else { if (MyFakes.SHOW_DAMAGE_EFFECTS && FatBlock != null && BlockDefinition.RatioEnoughForDamageEffect(BuildIntegrity / MaxIntegrity) == false && BlockDefinition.RatioEnoughForDamageEffect((Integrity - damage) / MaxIntegrity)) FatBlock.SetDamageEffect(true); } if (UseDamageSystem) MyDamageSystem.Static.RaiseAfterDamageApplied(this, damageInfo); m_lastDamage = damage; m_lastAttackerId = attackerId; m_lastDamageType = damageType; }
public bool DoDamage(float damage, MyStringHash damageType, bool sync, MyHitInfo? hitInfo, long attackerId) { GameLogic.DoDamage(damage, damageType, sync, hitInfo, attackerId); return true; }
static void DoDamageSynced(MySlimBlock block, float damage, MyStringHash damageType, MyHitInfo? hitInfo, long attackerId) { var msg = new DoDamageSlimBlockMsg(); msg.GridEntityId = block.CubeGrid.EntityId; msg.Position = block.Position; msg.Damage = damage; msg.HitInfo = hitInfo; msg.AttackerEntityId = attackerId; msg.CompoundBlockId = 0xFFFFFFFF; // Get compound block id var blockOnPosition = block.CubeGrid.GetCubeBlock(block.Position); if (blockOnPosition != null && block != blockOnPosition && blockOnPosition.FatBlock is MyCompoundCubeBlock) { MyCompoundCubeBlock compound = blockOnPosition.FatBlock as MyCompoundCubeBlock; ushort? compoundBlockId = compound.GetBlockId(block); if (compoundBlockId != null) msg.CompoundBlockId = compoundBlockId.Value; } block.DoDamage(damage, damageType, hitInfo: hitInfo, attackerId: attackerId); #if !XB1_NOMULTIPLAYER MyMultiplayer.RaiseStaticEvent(s => MySlimBlock.DoDamageSlimBlock, msg); #endif // !XB1_NOMULTIPLAYER }
void IMyDecalProxy.AddDecals(MyHitInfo hitInfo, MyStringHash source, object customdata, IMyDecalHandler decalHandler) { // TODO }
bool IMyDestroyableObject.DoDamage(float damage, MyStringHash damageType, bool sync, MyHitInfo? hitInfo, long attackerId) { return DoDamage(damage, damageType, sync, attackerId); }
private Vector3D PlaceDecal() { Vector3D explosionPoint = m_collisionPoint.Value; MyHitInfo hitInfo = new MyHitInfo() { Position = explosionPoint, Normal = m_collisionNormal }; MyDecals.HandleAddDecal(m_collidedEntity, hitInfo, this.m_missileAmmoDefinition.PhysicalMaterial); return explosionPoint; }