/// <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) { 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); } }
void IMyDecalProxy.AddDecals(MyHitInfo hitInfo, MyStringHash source, object customdata, IMyDecalHandler decalHandler) { Debug.Assert(m_mapIdToBlock.Count > 0); MyCubeGridHitInfo gridHitInfo = customdata as MyCubeGridHitInfo; 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); 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); }
void IMyDecalProxy.AddDecals(ref MyHitInfo hitInfo, MyStringHash source, object customdata, IMyDecalHandler decalHandler, MyStringHash material) { MyCubeGrid.MyCubeGridHitInfo gridHitInfo = customdata as MyCubeGrid.MyCubeGridHitInfo; if (gridHitInfo != null) { MyPhysicalMaterialDefinition physicalMaterial = this.m_mapIdToBlock.First <KeyValuePair <ushort, MySlimBlock> >().Value.BlockDefinition.PhysicalMaterial; MyDecalRenderInfo renderInfo = new MyDecalRenderInfo { Position = Vector3D.Transform(hitInfo.Position, base.CubeGrid.PositionComp.WorldMatrixInvScaled), Normal = (Vector3)Vector3D.TransformNormal(hitInfo.Normal, base.CubeGrid.PositionComp.WorldMatrixInvScaled), RenderObjectIds = base.CubeGrid.Render.RenderObjectIDs, Source = source }; VertexBoneIndicesWeights?affectingBoneIndicesWeights = gridHitInfo.Triangle.GetAffectingBoneIndicesWeights(ref m_boneIndexWeightTmp); if (affectingBoneIndicesWeights != null) { renderInfo.BoneIndices = affectingBoneIndicesWeights.Value.Indices; renderInfo.BoneWeights = affectingBoneIndicesWeights.Value.Weights; } renderInfo.Material = (material.GetHashCode() != 0) ? material : MyStringHash.GetOrCompute(physicalMaterial.Id.SubtypeName); m_tmpIds.Clear(); decalHandler.AddDecal(ref renderInfo, m_tmpIds); foreach (uint num in m_tmpIds) { base.CubeGrid.RenderData.AddDecal(base.Position, gridHitInfo, num); } } }
private bool fireAt(Vector3 target) { List <IHitInfo> hits = new List <IHitInfo>(); MyAPIGateway.Physics.CastRay(animator.getMuzzlePosition(), target, hits); //drawDebugLine(animator.grid.GetPosition(), target); IHitInfo hitInfo; if (findFirstNonNPC(hits, out hitInfo, true)) { var entity = hitInfo.HitEntity; var clearLOS = isEnemy(entity); if (!clearLOS) { return(false); } var grid = entity as MyCubeGrid; IMyDestroyableObject destroyable; spawnImpactParticle(hitInfo.Position, hitInfo.Normal); spawnLaunchParticle(animator.getMuzzlePosition(), -animator.grid.WorldMatrix.Forward); //spawnLaunchParticle(animator.getMuzzlePosition(), target - animator.getMuzzlePosition()); weaponLineAnimator.addAnim(animator.getMuzzlePosition(), hitInfo.Position); //spawnLaunchParticle(animator.grid.GetPosition(), hitInfo.Position - animator.grid.GetPosition()); shotAnimDur = 0; if (grid != null) { if (grid.Physics == null || !grid.Physics.Enabled || !grid.BlocksDestructionEnabled) { return(false); } var block = grid.GetTargetedBlock(hitInfo.Position) as IMySlimBlock; if (block == null) { return(false); } var myHitInfo = new MyHitInfo { Position = hitInfo.Position, Normal = hitInfo.Normal }; grid.DoDamage(damage, myHitInfo, null, animator.grid.EntityId); return(true); } else if ((destroyable = entity as IMyDestroyableObject) != null) { var myHitInfo = new MyHitInfo { Position = hitInfo.Position, Normal = hitInfo.Normal }; destroyable.DoDamage(damage, MyDamageType.Bullet, true, myHitInfo, animator.grid.EntityId); return(true); } } return(false); }
/// <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 material = default(MyStringHash), 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, material); return; } MyCubeGrid grid = entity as MyCubeGrid; if (grid != null) { MyCubeGridHitInfo info = customdata as MyCubeGridHitInfo; MySlimBlock block; if (info == null) { block = grid.GetTargetedBlock(hitInfo.Position); if (block == null) { return; } // If info is not provided, provide info with just block position m_gridHitInfo.Position = block.Position; customdata = m_gridHitInfo; } 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, material); }
void IMyDecalProxy.GetDecalRenderData(MyHitInfo hitInfo, out MyDecalRenderData renderable) { renderable = new MyDecalRenderData(); renderable.Position = hitInfo.Position; renderable.Normal = hitInfo.Normal; renderable.RenderObjectId = Render.GetRenderObjectID(); renderable.Material = Physics.GetMaterialAt(hitInfo.Position); }
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); }
void IMyDecalProxy.GetDecalRenderData(MyHitInfo hitInfo, out MyDecalRenderData renderable) { Debug.Assert(m_mapIdToBlock.Count > 0); MySlimBlock block = m_mapIdToBlock.First().Value; renderable = new MyDecalRenderData(); 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(block.BlockDefinition.PhysicalMaterial.Id.SubtypeName); }
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); }
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; }
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); }
void IMyDecalProxy.AddDecals(ref MyHitInfo hitInfo, MyStringHash source, object customdata, IMyDecalHandler decalHandler, MyStringHash material) { MyDecalRenderInfo renderInfo = new MyDecalRenderInfo { Position = hitInfo.Position, Normal = hitInfo.Normal, RenderObjectIds = null, Flags = MyDecalFlags.World, Source = source }; renderInfo.Material = (material.GetHashCode() != 0) ? material : base.Physics.MaterialType; decalHandler.AddDecal(ref renderInfo, null); }
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 override void UpdateAfterSimulation() { base.UpdateAfterSimulation(); bool isShooting = IsShooting; if (!m_isHit && IsShooting && (MySandboxGame.Static.UpdateTime - m_lastShot > MyTimeSpan.FromSeconds(m_shotToolAction.Value.HitStart))) { IMyHandToolComponent toolComponent; if (m_toolComponents.TryGetValue(m_shotHitCondition.Component, out toolComponent)) { MyCharacterDetectorComponent detectorComponent = m_owner.Components.Get <MyCharacterDetectorComponent>(); if (detectorComponent != null) { if (m_shotToolAction.Value.CustomShapeRadius > 0 && detectorComponent is MyCharacterShapecastDetectorComponent) { var shapeCastComponent = detectorComponent as MyCharacterShapecastDetectorComponent; shapeCastComponent.ShapeRadius = m_shotToolAction.Value.CustomShapeRadius; shapeCastComponent.DoDetectionModel(); shapeCastComponent.ShapeRadius = MyCharacterShapecastDetectorComponent.DEFAULT_SHAPE_RADIUS; } if (detectorComponent.DetectedEntity != null) { MyHitInfo hitInfo = new MyHitInfo(); hitInfo.Position = detectorComponent.HitPosition; hitInfo.Normal = detectorComponent.HitNormal; bool isBlock = false; float efficiencyMultiplier = 1.0f; bool canHit = CanHit(toolComponent, detectorComponent, ref isBlock, out efficiencyMultiplier); MyDecals.HandleAddDecal(detectorComponent.DetectedEntity, hitInfo, MyDamageType.Weapon); bool isHit = false; if (canHit) { if (!string.IsNullOrEmpty(m_shotToolAction.Value.StatsEfficiency) && Owner.StatComp != null) { efficiencyMultiplier *= Owner.StatComp.GetEfficiencyModifier(m_shotToolAction.Value.StatsEfficiency); } float efficiency = m_shotToolAction.Value.Efficiency * efficiencyMultiplier; var tool = detectorComponent.DetectedEntity as MyHandToolBase; if (isBlock && tool != null) { isHit = toolComponent.Hit(tool.Owner, hitInfo, detectorComponent.ShapeKey, efficiency); } else { isHit = toolComponent.Hit((MyEntity)detectorComponent.DetectedEntity, hitInfo, detectorComponent.ShapeKey, efficiency); } if (isHit && Sync.IsServer && Owner.StatComp != null) { if (!string.IsNullOrEmpty(m_shotHitCondition.StatsActionIfHit)) { Owner.StatComp.DoAction(m_shotHitCondition.StatsActionIfHit); } if (!string.IsNullOrEmpty(m_shotHitCondition.StatsModifierIfHit)) { Owner.StatComp.ApplyModifier(m_shotHitCondition.StatsModifierIfHit); } } } if (canHit || isBlock) // real hit is not controlled now - there isn't any server-client synchronization of hit currently and hit is performed only at server { if (!string.IsNullOrEmpty(m_shotToolAction.Value.HitSound)) { PlaySound(m_shotToolAction.Value.HitSound); } else { MyStringId collisionType = MyMaterialPropertiesHelper.CollisionType.Hit; bool showParticles = false; // If it didn't play the Sound with "Hit", it will try with "Start" if (MyAudioComponent.PlayContactSound(EntityId, m_hitCue, detectorComponent.HitPosition, m_toolItemDef.PhysicalMaterial, detectorComponent.HitMaterial)) { showParticles = true; } else if (MyAudioComponent.PlayContactSound(EntityId, m_startCue, detectorComponent.HitPosition, m_toolItemDef.PhysicalMaterial, detectorComponent.HitMaterial)) { showParticles = true; collisionType = MyMaterialPropertiesHelper.CollisionType.Start; } if (showParticles) { MyMaterialPropertiesHelper.Static.TryCreateCollisionEffect( collisionType, detectorComponent.HitPosition, detectorComponent.HitNormal, m_toolItemDef.PhysicalMaterial, detectorComponent.HitMaterial); } } this.RaiseEntityEvent(MyStringHash.GetOrCompute("Hit"), new MyEntityContainerEventExtensions.HitParams(MyStringHash.GetOrCompute(m_shotHitCondition.Component), detectorComponent.HitMaterial)); m_soundEmitter.StopSound(true); } } } } m_isHit = true; } if (!m_swingSoundPlayed && IsShooting && !m_isHit && (MySandboxGame.Static.UpdateTime - m_lastShot > MyTimeSpan.FromSeconds(m_shotToolAction.Value.SwingSoundStart))) { if (!string.IsNullOrEmpty(m_shotToolAction.Value.SwingSound)) { PlaySound(m_shotToolAction.Value.SwingSound); } m_swingSoundPlayed = true; } if (!isShooting && m_wasShooting) { m_owner.StopUpperCharacterAnimation(0.4f); m_shotToolAction = null; } m_wasShooting = isShooting; if (m_owner != null) { MatrixD blockingMatrix = MatrixD.CreateWorld(((MyEntity)m_owner.CurrentWeapon).PositionComp.GetPosition(), m_owner.WorldMatrix.Forward, m_owner.WorldMatrix.Up); ((MyBlockingBody)Physics).SetWorldMatrix(blockingMatrix); } foreach (var c in m_toolComponents.Values) { c.Update(); } }
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; } } }
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; } 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); }
private void GetHitEntityAndPosition(LineD line, out IMyEntity entity, out MyHitInfo hitInfoRet, out object customdata) { entity = null; hitInfoRet = new MyHitInfo(); customdata = 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; hitInfoRet.Position = hitInfo.Position; hitInfoRet.Normal = hitInfo.HkHitInfo.Normal; hitInfoRet.ShapeKey = hitInfo.HkHitInfo.GetShapeKey(0); } } // 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 : hitInfoRet.Position); 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; hitInfoRet.Position = m_charHitInfo.Triangle.IntersectionPointInWorldSpace; hitInfoRet.Normal = m_charHitInfo.Triangle.NormalInWorldSpace; customdata = 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) { hitInfoRet.Position = m_charHitInfo.Triangle.IntersectionPointInWorldSpace; hitInfoRet.Normal = m_charHitInfo.Triangle.NormalInWorldSpace; customdata = m_charHitInfo; } else { entity = null; // no hit. } } else { MyCubeGrid grid = entity as MyCubeGrid; if (grid != null) { bool success = grid.GetIntersectionWithLine(ref line, ref m_cubeGridHitInfo); if (success) { hitInfoRet.Position = m_cubeGridHitInfo.Triangle.IntersectionPointInWorldSpace; hitInfoRet.Normal = m_cubeGridHitInfo.Triangle.NormalInWorldSpace; if (Vector3.Dot(hitInfoRet.Normal, line.Direction) > 0) { hitInfoRet.Normal = -hitInfoRet.Normal; } customdata = m_cubeGridHitInfo; } MyHitInfo info = new MyHitInfo(); info.Position = hitInfoRet.Position; info.Normal = hitInfoRet.Normal; } MyVoxelBase voxel = entity as MyVoxelBase; if (voxel != null) { //get accurate hit because of particles and decals MyIntersectionResultLineTriangleEx?res; if (voxel.GetIntersectionWithLine(ref line, out res, IntersectionFlags.DIRECT_TRIANGLES)) { hitInfoRet.Position = res.Value.IntersectionPointInWorldSpace; hitInfoRet.Normal = res.Value.NormalInWorldSpace; hitInfoRet.ShapeKey = 0; } } } } while (entity == null && ++raycastListIndex < m_entityRaycastResult.Count); }
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); }
// 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); }
public void Apply(IReadOnlyList <IMyCubeGrid> group) { var totalAABB = BoundingBoxD.CreateInvalid(); // ReSharper disable once LoopCanBeConvertedToQuery foreach (var grid in group) { totalAABB = totalAABB.Include(grid.WorldAABB); } var totalSphere = new BoundingSphereD(totalAABB.Center, totalAABB.HalfExtents.Length()); foreach (var impact in m_impactDirectionRadius) { var speed = impact.Velocity.Length(); var direction = (Vector3D)impact.Velocity / speed; Vector3D start, end; { var rayOffset = totalAABB.HalfExtents * 0.8 * (Vector3D)impact.Shift; // mag2(rayOffset + l*direction) == radius*radius // (rayOffset + l*direction)*(rayOffset + l*direction) // mag2(rayOffset) + 2*l*dot(direction, rayOffset) + l*l*mag2(direction) // mag2(rayOffset) - (radius*radius) + 2*l*dot(direction, rayOffset) + l*l == 0 var c = rayOffset.LengthSquared() - totalSphere.Radius * totalSphere.Radius; var b = 2 * Vector3D.Dot(direction, rayOffset); const float a = 1; var rad = b * b - 4 * a * c; if (rad <= double.Epsilon) { continue; } var lLow = (-b - Math.Sqrt(rad)) / (2 * a); var lHigh = (-b + Math.Sqrt(rad)) / (2 * a); start = totalSphere.Center + rayOffset + lLow * direction; end = totalSphere.Center + rayOffset + lHigh * direction; } var ray = new RayD(start, direction); var bestHitLocation = default(Vector3D); var bestHitDistanceSquared = double.MaxValue; foreach (var grid in group) { if (!grid.WorldAABB.Intersects(ray).HasValue) { continue; } var block = grid.RayCastBlocks(start, end); if (!block.HasValue) { continue; } var world = Vector3D.Transform(block.Value * grid.GridSize, grid.WorldMatrix); var distance = Vector3D.DistanceSquared(world, start); if (distance > bestHitDistanceSquared) { continue; } bestHitDistanceSquared = distance; bestHitLocation = world; } if (bestHitDistanceSquared > double.MaxValue / 2) { continue; } var impactSphere = new BoundingSphereD(bestHitLocation, impact.Radius); var localSphere = new BoundingSphereD(); var damageAmount = impact.Mass * speed * speed * (4.0 / 3.0) * Math.PI; var damageTotals = new Dictionary <IMySlimBlock, double>(); foreach (var grid in group) { if (grid.WorldAABB.Intersects(impactSphere)) { // compute local sphere. localSphere.Center = Vector3D.Transform(impactSphere.Center, grid.WorldMatrixNormalizedInv) / grid.GridSize; localSphere.Radius = impactSphere.Radius / grid.GridSize; var min = Vector3I.Max(Vector3I.Floor(localSphere.Center - localSphere.Radius), grid.Min); var max = Vector3I.Min(Vector3I.Ceiling(localSphere.Center + localSphere.Radius), grid.Max); for (var itr = new Vector3I_RangeIterator(ref min, ref max); itr.IsValid(); itr.MoveNext()) { if (localSphere.Contains(itr.Current) == ContainmentType.Disjoint) { continue; } var block = grid.GetCubeBlock(itr.Current); if (block == null) { continue; } var distanceFactor = 1 - ((Vector3D)itr.Current - localSphere.Center).LengthSquared() / (localSphere.Radius * localSphere.Radius); var blockDamage = damageAmount * distanceFactor * ((block.BlockDefinition as MyCubeBlockDefinition)?.DeformationRatio ?? 1); damageTotals.AddValue(block, blockDamage); } } } // No idea what shape key should be. Logger.Debug("Apply damage to {0} blocks", damageTotals.Count); var hitInfo = new MyHitInfo() { Normal = direction, Position = impactSphere.Center, Velocity = impact.Velocity, ShapeKey = 0 }; foreach (var kv in damageTotals) { kv.Key.DoDamage((float)kv.Value, MyDamageType.Explosion, true, hitInfo); } } }
void IMyDecalProxy.AddDecals(MyHitInfo hitInfo, MyStringHash source, object customdata, IMyDecalHandler decalHandler, MyStringHash material) { // TODO }
/// <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(); } }
void IMyDecalProxy.GetDecalRenderData(MyHitInfo hitInfo, out MyDecalRenderData renderable) { // TODO renderable = new MyDecalRenderData(); renderable.Skip = true; }