예제 #1
0
        /// <summary>
        ///     Finds a random block facing the sky. Raycast is slightly randomized to simulate wind blowing rain
        /// </summary>
        /// <param name="grid"></param>
        /// <param name="blocks"></param>
        /// <param name="gravityDirection"></param>
        /// <param name="physicsCast"></param>
        /// <returns></returns>
        public static IMySlimBlock GetRandomSkyFacingBlock(IMyCubeGrid grid, List <IMySlimBlock> blocks, Vector3D gravityDirection, out LineD line, bool physicsCast = false)
        {
            Vector3D posInt = grid.GridIntegerToWorld(blocks.GetRandomItemFromList().Position) + -gravityDirection * 2;
            Vector3D posExt = posInt + gravityDirection * Math.Max(25, grid.WorldVolume.Radius * 2);

            posExt = RandomPositionFromPoint(ref posExt, grid.WorldVolume.Radius);
            line   = new LineD();

            Vector3I?blockPos = grid.RayCastBlocks(posExt, posInt);

            if (!blockPos.HasValue)
            {
                return(null);
            }

            IMySlimBlock block = grid.GetCubeBlock(blockPos.Value);

            if (block == null)
            {
                return(null);
            }

            if (physicsCast)
            {
                var hits = new List <IHitInfo>();
                MyAPIGateway.Physics.CastRay(posExt, grid.GridIntegerToWorld(blockPos.Value), hits);
                foreach (IHitInfo hit in hits)
                {
                    if (hit?.HitEntity?.GetTopMostParent() == null)
                    {
                        continue;
                    }

                    if (hit.HitEntity.GetTopMostParent().EntityId != grid.EntityId)
                    {
                        return(null);
                    }
                }
            }

            if (Debug)
            {
                Lines.Add(new LineD {
                    From = posExt, To = grid.GridIntegerToWorld(blockPos.Value)
                });
            }
            line = new LineD {
                From = posExt, To = grid.GridIntegerToWorld(blockPos.Value)
            };

            return(block);
        }
예제 #2
0
        /// <summary>
        ///     Gets a block on the exterior hull of a ship
        /// </summary>
        /// <param name="grid"></param>
        /// <param name="blocks"></param>
        /// <returns></returns>
        public static IMySlimBlock GetRandomExteriorBlock(IMyCubeGrid grid, List <IMySlimBlock> blocks)
        {
            Vector3D posInt = grid.GridIntegerToWorld(blocks.GetRandomItemFromList().Position);
            Vector3D posExt = RandomPositionFromPoint(ref posInt, grid.WorldAABB.HalfExtents.Length());

            if (Debug)
            {
                Lines.Add(new LineD {
                    From = posExt, To = posInt
                });
            }

            Vector3I?blockPos = grid.RayCastBlocks(posExt, posInt);

            return(blockPos.HasValue ? grid.GetCubeBlock(blockPos.Value) : null);
        }
예제 #3
0
        public static double?GridHitCheck(IMyCubeGrid cubeGrid, LineD lineCheck, Vector3D lineStartPoint, Vector3D lineEndPoint)
        {
            // Hit a grid, do a raycast to it for block hit.
            Vector3I?gridBlockHit = cubeGrid.RayCastBlocks(lineStartPoint, lineEndPoint);

            if (gridBlockHit.HasValue)
            {
                // Get the block on hit grid
                IMySlimBlock blk = cubeGrid.GetCubeBlock(gridBlockHit.Value);
                if (blk.FatBlock != null)
                {
                    var blockBBox = blk.FatBlock.LocalAABB;
                    MyOrientedBoundingBoxD blockOBB = new MyOrientedBoundingBoxD(blockBBox, blk.FatBlock.WorldMatrix);
                    double?blockIntersect           = blockOBB.Intersects(ref lineCheck);
                    if (blockIntersect != null)
                    {
                        var hitDist = blockOBB.Intersects(ref lineCheck);
                        return(hitDist);
                    }

                    //DrawOBB(blockOBB, Color.Red, MySimpleObjectRasterizer.Wireframe, 0.01f);
                }
                else
                {
                    var center = blk.GetPosition();

                    Vector3 halfExt;
                    blk.ComputeScaledHalfExtents(out halfExt);

                    BoundingBoxD           blockBBox = new BoundingBoxD(-halfExt, halfExt);
                    Quaternion             rotMatrix = Quaternion.CreateFromRotationMatrix(blk.CubeGrid.WorldMatrix);
                    MyOrientedBoundingBoxD blockOBB  = new MyOrientedBoundingBoxD(center, blockBBox.HalfExtents, rotMatrix);

                    var hitDist = blockOBB.Intersects(ref lineCheck);
                    return(hitDist);

                    //DrawOBB(blockOBB, Color.Green, MySimpleObjectRasterizer.Wireframe, 0.01f);
                }
            }

            return(double.MaxValue);
        }
예제 #4
0
        private void Check()
        {
            Vector3D End = Position + Velocity * Tools.Tick;

            IHitInfo hit;

            MyAPIGateway.Physics.CastRay(Position, End, out hit);
            if (hit != null)
            {
                Expired = true;

                //apply recoil
                if (Ammo.ProjectileHitImpulse > 0)
                {
                    Vector3 forceVector = -hit.Normal * Ammo.ProjectileHitImpulse;
                    hit.HitEntity.Physics.AddForce(MyPhysicsForceType.APPLY_WORLD_IMPULSE_AND_WORLD_ANGULAR_IMPULSE, forceVector, hit.Position, Vector3.Zero);
                }

                if (!MyAPIGateway.Session.IsServer)
                {
                    return;
                }

                if (hit.HitEntity is IMyDestroyableObject)
                {
                    (hit.HitEntity as IMyDestroyableObject).DoDamage(Ammo.ProjectileMassDamage, MyStringHash.GetOrCompute(Ammo.SubtypeId), false, null, ShooterId);
                }
                else if (hit.HitEntity is IMyCubeGrid)
                {
                    IMyCubeGrid grid   = hit.HitEntity as IMyCubeGrid;
                    Vector3I?   hitPos = grid.RayCastBlocks(hit.Position, hit.Position + Direction);
                    if (hitPos.HasValue)
                    {
                        IMySlimBlock block = grid.GetCubeBlock(hitPos.Value);
                        block.DoDamage(Ammo.ProjectileMassDamage, MyStringHash.GetOrCompute(Ammo.SubtypeId), false, null, ShooterId);
                    }
                }
            }
        }
예제 #5
0
        public static ConcurrentBag <MyGroups <MyCubeGrid, MyGridPhysicalGroupData> .Group> FindLookAtGridGroup(IMyCharacter controlledEntity)
        {
            const float range = 5000;
            Matrix      worldMatrix;
            Vector3D    startPosition;
            Vector3D    endPosition;

            worldMatrix   = controlledEntity.GetHeadMatrix(true, true, false); // dead center of player cross hairs, or the direction the player is looking with ALT.
            startPosition = worldMatrix.Translation + worldMatrix.Forward * 0.5f;
            endPosition   = worldMatrix.Translation + worldMatrix.Forward * (range + 0.5f);

            var list = new Dictionary <MyGroups <MyCubeGrid, MyGridPhysicalGroupData> .Group, double>();
            var ray  = new RayD(startPosition, worldMatrix.Forward);

            foreach (var group in MyCubeGridGroups.Static.Physical.Groups)
            {
                foreach (MyGroups <MyCubeGrid, MyGridPhysicalGroupData> .Node groupNodes in group.Nodes)
                {
                    IMyCubeGrid cubeGrid = groupNodes.NodeData;

                    if (cubeGrid == null)
                    {
                        continue;
                    }

                    if (cubeGrid.Physics == null)
                    {
                        continue;
                    }

                    // check if the ray comes anywhere near the Grid before continuing.
                    if (!ray.Intersects(cubeGrid.WorldAABB).HasValue)
                    {
                        continue;
                    }

                    Vector3I?hit = cubeGrid.RayCastBlocks(startPosition, endPosition);

                    if (!hit.HasValue)
                    {
                        continue;
                    }

                    double distance = (startPosition - cubeGrid.GridIntegerToWorld(hit.Value)).Length();


                    if (list.TryGetValue(group, out double oldDistance))
                    {
                        if (distance < oldDistance)
                        {
                            list.Remove(group);
                            list.Add(group, distance);
                        }
                    }
                    else
                    {
                        list.Add(group, distance);
                    }
                }
            }

            var bag = new ConcurrentBag <MyGroups <MyCubeGrid, MyGridPhysicalGroupData> .Group>();

            if (list.Count == 0)
            {
                return(bag);
            }

            // find the closest Entity.
            var item = list.OrderBy(f => f.Value).First();

            bag.Add(item.Key);

            return(bag);
        }
예제 #6
0
        void GetTarget(IMyCharacter character, out IMyCubeGrid targetGrid, out IMySlimBlock targetBlock, out IMyPlayer targetPlayer, out Vector3D aimPoint)
        {
            targetGrid   = null;
            targetBlock  = null;
            targetPlayer = null;

            bool     aiming  = Utils.IsAimingDownSights(character);
            MatrixD  head    = character.GetHeadMatrix(false, true);
            Vector3D rayDir  = head.Forward;
            Vector3D rayFrom = head.Translation;

            if (aiming)
            {
                rayFrom += rayDir * PAINT_AIM_START_OFFSET;
            }

            Vector3D rayTo = head.Translation + rayDir * PAINT_DISTANCE;

            aimPoint = rayTo;

            targetGrid = MyAPIGateway.CubeBuilder.FindClosestGrid();

            if (targetGrid == null || targetGrid.Physics == null || !targetGrid.Physics.Enabled)
            {
                targetGrid = null;
                return;
            }

            // older selection behavior when aiming down sights
            if (aiming)
            {
                Vector3I?blockPos = targetGrid.RayCastBlocks(rayFrom, rayTo);

                if (blockPos.HasValue)
                {
                    targetBlock = targetGrid.GetCubeBlock(blockPos.Value);
                }

                return;
            }

            // HACK copied and converted from MyDrillSensorRayCast.ReadEntitiesInRange() + MyCasterComponent.OnWorldPosChanged()
            // last cloned in SE v201
            #region Welder-like block selection
            hits.Clear();
            detections.Clear();
            rayOverlapResults.Clear();

            MyAPIGateway.Physics.CastRay(rayFrom, rayTo, hits, 24);

            foreach (IHitInfo hit in hits)
            {
                IMyEntity parent = hit.HitEntity?.GetTopMostParent();
                if (parent == null || parent.Physics == null || !parent.Physics.Enabled)
                {
                    continue;
                }

                Vector3D    hitPos = hit.Position;
                IMyCubeGrid grid   = parent as IMyCubeGrid;
                if (grid != null)
                {
                    // just how it's set in game code /shrug
                    hitPos += hit.Normal * -0.005f;
                }

                DetectionInfo detected;
                if (detections.TryGetValue(parent.EntityId, out detected))
                {
                    double dist1 = Vector3D.DistanceSquared(rayFrom, detected.DetectionPoint);
                    double dist2 = Vector3D.DistanceSquared(rayFrom, hitPos);
                    if (dist1 > dist2)
                    {
                        detections[parent.EntityId] = new DetectionInfo(parent, hitPos);
                    }
                }
                else
                {
                    detections[parent.EntityId] = new DetectionInfo(parent, hitPos);
                }
            }

            hits.Clear();

            LineD line = new LineD(rayFrom, rayTo);
            MyGamePruningStructure.GetAllEntitiesInRay(ref line, rayOverlapResults);

            foreach (MyLineSegmentOverlapResult <MyEntity> result in rayOverlapResults)
            {
                if (result.Element == null)
                {
                    continue;
                }

                IMyCubeBlock block = result.Element as IMyCubeBlock;
                if (block == null)
                {
                    continue;
                }

                MyCubeBlockDefinition def = (MyCubeBlockDefinition)block.SlimBlock.BlockDefinition;
                if (def.HasPhysics)
                {
                    continue; // this section is only for things that are not caught by the raycast
                }
                MyEntity parent = result.Element.GetTopMostParent();
                if (parent.Physics == null || !parent.Physics.Enabled)
                {
                    continue;
                }

                MatrixD invMatrix = block.PositionComp.WorldMatrixNormalizedInv;
                Vector3 localFrom = Vector3D.Transform(rayFrom, ref invMatrix);
                Vector3 localTo   = Vector3D.Transform(rayTo, ref invMatrix);

                float?intersectDistance = new Ray(localFrom, Vector3.Normalize(localTo - localFrom)).Intersects(block.PositionComp.LocalAABB) + 0.01f;
                if (intersectDistance.HasValue && intersectDistance <= PAINT_DISTANCE)
                {
                    Vector3D      hitPos = rayFrom + rayDir * intersectDistance.Value;
                    DetectionInfo detected;
                    if (detections.TryGetValue(parent.EntityId, out detected))
                    {
                        double dist1 = Vector3D.DistanceSquared(rayFrom, detected.DetectionPoint);
                        double dist2 = Vector3D.DistanceSquared(rayFrom, hitPos);
                        if (dist1 > dist2)
                        {
                            detections[parent.EntityId] = new DetectionInfo(parent, hitPos);
                        }
                    }
                    else
                    {
                        detections[parent.EntityId] = new DetectionInfo(parent, hitPos);
                    }
                }
            }

            rayOverlapResults.Clear();

            if (detections.Count == 0)
            {
                return;
            }

            double        closetDist = double.MaxValue;
            DetectionInfo closestObj = new DetectionInfo(null, Vector3D.Zero);

            foreach (DetectionInfo detected in detections.Values)
            {
                double dist = Vector3D.DistanceSquared(detected.DetectionPoint, rayFrom);
                if (dist < closetDist)
                {
                    closestObj = detected;
                    closetDist = dist;
                }
            }

            detections.Clear();

            targetGrid = closestObj.Entity as IMyCubeGrid;
            if (targetGrid == null)
            {
                return;
            }

            Vector3D localPos = Vector3D.Transform(closestObj.DetectionPoint, targetGrid.WorldMatrixNormalizedInv);
            Vector3I cube;
            targetGrid.FixTargetCube(out cube, localPos / targetGrid.GridSize);
            targetBlock = targetGrid.GetCubeBlock(cube);
            #endregion Welder-like block selection
        }
예제 #7
0
        public void TargetIntersectionCheck()
        {
            _entityScanList.Clear();
            _voxelScanList.Clear();
            _entityScanList = new List <MyLineSegmentOverlapResult <MyEntity> >();
            MyGamePruningStructure.GetTopmostEntitiesOverlappingRay(ref Line, _entityScanList);

            IMyCubeGrid closestGrid         = null;
            double      closestGridDistance = -1;

            MySafeZone closestZone         = null;
            double     closestZoneDistance = -1;

            IMyCharacter closestCharacter         = null;
            double       closestCharacterDistance = -1;

            foreach (var item in _entityScanList)
            {
                var targetGrid   = item.Element as IMyCubeGrid;
                var targetZone   = item.Element as MySafeZone;
                var targetVoxel  = item.Element as MyVoxelBase;
                var targetPlayer = item.Element as IMyCharacter;

                if (targetGrid != null)
                {
                    if (targetGrid == _collisionSystem.RemoteControl.SlimBlock.CubeGrid || _collisionSystem.RemoteControl.SlimBlock.CubeGrid.IsSameConstructAs(targetGrid))
                    {
                        continue;
                    }

                    if (closestGrid == null || (closestGrid != null && item.Distance < closestGridDistance))
                    {
                        closestGrid         = targetGrid;
                        closestGridDistance = item.Distance;
                    }
                }

                if (targetZone != null)
                {
                    if (closestZone == null || (closestZone != null && item.Distance < closestZoneDistance))
                    {
                        closestZone         = targetZone;
                        closestZoneDistance = item.Distance;
                    }
                }

                if (targetVoxel != null)
                {
                    _voxelScanList.Add(targetVoxel);
                }

                if (targetPlayer != null)
                {
                    if (closestCharacter == null || (closestCharacter != null && item.Distance < closestCharacterDistance))
                    {
                        closestCharacter         = targetPlayer;
                        closestCharacterDistance = item.Distance;
                    }
                }
            }

            if (closestGrid != null)
            {
                double minDist        = 0;
                double maxDist        = 0;
                bool   boxCheckResult = closestGrid.PositionComp.WorldAABB.Intersect(ref Ray, out minDist, out maxDist);

                Vector3D startBox = boxCheckResult ? (minDist - 5) * DirectionVector + StartPosition : StartPosition;
                Vector3D endBox   = boxCheckResult ? (maxDist + 5) * DirectionVector + StartPosition : EndPosition;

                var blockPos = closestGrid.RayCastBlocks(startBox, endBox);

                if (!blockPos.HasValue)
                {
                    return;
                }

                IMySlimBlock slimBlock = closestGrid.GetCubeBlock(blockPos.Value);

                if (slimBlock == null)
                {
                    return;
                }

                Vector3D blockPosition = Vector3D.Zero;
                slimBlock.ComputeWorldCenter(out blockPosition);


                GridCoords   = blockPosition;
                GridDistance = Vector3D.Distance(blockPosition, StartPosition);
                GridEntity   = closestGrid;
                GridOwner    = OwnershipHelper.GetOwnershipTypes(closestGrid, false);
                GridRelation = OwnershipHelper.GetTargetReputation(_collisionSystem.Owner, closestGrid, false);
            }

            if (closestZone != null)
            {
                SafezoneEntity   = closestZone;
                SafezoneCoords   = closestZoneDistance * DirectionVector + StartPosition;
                SafezoneDistance = closestZoneDistance;
            }

            if (closestCharacter != null)
            {
                PlayerEntity   = closestCharacter;
                PlayerCoords   = PlayerEntity.PositionComp.WorldAABB.Center;
                PlayerDistance = closestCharacterDistance;
            }
        }
예제 #8
0
        public void Check(Projectile p)
        {
            Vector3D End = p.Position + p.Velocity * Tools.Tick;

            IHitInfo hit;

            MyAPIGateway.Physics.CastRay(p.Position, End, out hit);
            if (hit != null)
            {
                Tools.Debug($"----- ricochet check start -----");
                if (hit.HitEntity is IMyDestroyableObject)
                {
                    p.Expired = true;
                    (hit.HitEntity as IMyDestroyableObject).DoDamage(p.Ammo.ProjectileMassDamage, MyStringHash.GetOrCompute(p.Ammo.SubtypeId), false, null, p.ShooterId);
                }
                else if (hit.HitEntity is IMyCubeGrid)
                {
                    Tools.Debug($"hit cube grid");
                    IMyCubeGrid grid = hit.HitEntity as IMyCubeGrid;

                    Vector3I?hitPos = grid.RayCastBlocks(hit.Position, hit.Position + Vector3D.Normalize(p.Velocity));  // p.Direction
                    if (hitPos.HasValue)
                    {
                        Tools.Debug($"hit block");
                        IMySlimBlock block = grid.GetCubeBlock(hitPos.Value);

                        Vector3 hitObjectVelocity = Vector3.Zero;
                        if (hit.HitEntity.Physics != null)
                        {
                            hitObjectVelocity = hit.HitEntity.Physics.LinearVelocity;
                        }

                        Vector3D relativeV      = p.Velocity - hitObjectVelocity;
                        float    NotHitAngle    = (float)Tools.AngleBetween(-Vector3D.Normalize(relativeV), hit.Normal);
                        float    HitAngle       = (90f - NotHitAngle);
                        float    NotHitFraction = NotHitAngle / 90f;

                        float random = (float)Tools.Random.NextDouble();

                        if (HitAngle < DeflectionAngle && RicochetChance > random)
                        {
                            Tools.Debug($"angle {HitAngle} < {DeflectionAngle}");
                            // Apply impulse
                            float impulse = p.Ammo.ProjectileHitImpulse * NotHitFraction * MaxVelocityTransfer;
                            if (hit.HitEntity.Physics != null)
                            {
                                hit.HitEntity.Physics.AddForce(MyPhysicsForceType.APPLY_WORLD_IMPULSE_AND_WORLD_ANGULAR_IMPULSE, p.Velocity * impulse * -hit.Normal, hit.Position, null);
                            }

                            // apply partial damage
                            float damage = p.Ammo.ProjectileMassDamage * NotHitFraction * MaxDamageTransfer;
                            if (block != null && MyAPIGateway.Session.IsServer)
                            {
                                Tools.Debug($"damage {damage}");
                                block.DoDamage(damage, MyStringHash.GetOrCompute(p.Ammo.SubtypeId), false, null, p.ShooterId);
                            }

                            // reduce velocity
                            p.Velocity -= p.Velocity * NotHitFraction * MaxVelocityTransfer;

                            // reflect
                            p.Velocity = Vector3.Reflect(p.Velocity, hit.Normal);

                            // calculate new direction
                            p.Direction      = Vector3D.Normalize(p.Velocity);
                            p.Position       = hit.Position + (p.Direction * 0.5f);
                            p.Origin         = p.Position;
                            p.DrawFullTracer = false;

                            //if (!MyAPIGateway.Utilities.IsDedicated)
                            //{
                            //    MatrixD world = MatrixD.CreateFromDir(hit.Normal);
                            //    world.Translation = hit.Position;

                            //    MyParticleEffect effect;
                            //    MyParticlesManager.TryCreateParticleEffect("Collision_Sparks_Directional", world, out effect);

                            //    effect.Loop = false;
                            //    effect.UserScale = 0.5f;
                            //    effect.UserEmitterScale = 16f;
                            //    effect.UserRadiusMultiplier = 0.1f;
                            //    effect.UserBirthMultiplier = 20f;
                            //    effect.DurationMin = 0.015f;
                            //    effect.DurationMax = 0.025f;
                            //    effect.SetRandomDuration();
                            //}
                        }
                        else
                        {
                            Tools.Debug($"obsorb damage");
                            if (block != null && MyAPIGateway.Session.IsServer)
                            {
                                block.DoDamage(p.Ammo.ProjectileMassDamage, MyStringHash.GetOrCompute(p.Ammo.SubtypeId), true);
                            }

                            p.Expired = true;
                        }
                    }
                }

                Tools.Debug($"----- ricochet check end -----");
            }
        }