public static void GetSpawnPosition(float collisionRadius, out Vector3 direction, out Vector3D position)
        {
            float distance = 0;

            foreach (var entity in MyEntities.GetEntities())
            {
                // Include only voxels
                if (entity is MyVoxelMap)
                {
                    distance = (float)MathHelper.Max(distance, entity.PositionComp.WorldVolume.Center.Length() + entity.PositionComp.WorldVolume.Radius);
                }
            }

            // 500 - 650m from last voxel
            distance += MyUtils.GetRandomFloat(500, 650);

            if (MyEntities.IsWorldLimited())
            {
                distance = Math.Min(distance, MyEntities.WorldSafeHalfExtent());
            }
            else
            {
                distance = Math.Min(distance, 20000); // limited spawn area in infinite worlds
            }
            direction = MyUtils.GetRandomVector3Normalized();
            var searchPosition = MyEntities.FindFreePlace((Vector3D)(direction * distance), collisionRadius);

            if (!searchPosition.HasValue)
            {
                searchPosition = (Vector3D)(direction * distance); // Spawn in existing place (better than crash)
            }
            Vector3D globalPoint = (Vector3D)searchPosition;

            position = globalPoint;

            if (MyGravityProviderSystem.CalculateNaturalGravityInPoint(globalPoint) != null && MyGravityProviderSystem.CalculateNaturalGravityInPoint(globalPoint).Length() != 0)
            {
                MyPlanet planet     = MyGravityProviderSystem.GetStrongestGravityWell(globalPoint);
                double   multiplier = planet.MaximumRadius / globalPoint.Length();
                globalPoint *= multiplier;
                Vector3D closestPoint = planet.GetClosestSurfacePointGlobal(ref globalPoint) * 1.25;
                searchPosition = MyEntities.FindFreePlace(closestPoint, collisionRadius);
                if (searchPosition.HasValue)
                {
                    position = searchPosition.Value;
                }
            }
            else
            {
                position = searchPosition.Value;
            }
        }
Esempio n. 2
0
        private bool SpawnDrone(MyRadioAntenna antenna, long ownerId, Vector3D position, MySpawnGroupDefinition spawnGroup)
        {
            long     antennaEntityId = antenna.EntityId;
            Vector3D antennaPos      = antenna.PositionComp.GetPosition();

            var planet = MyGravityProviderSystem.GetStrongestGravityWell(position);

            Vector3D upVector;

            if (planet != null && planet.IsPositionInGravityWell(position))
            {
                if (!MyGravityProviderSystem.IsPositionInNaturalGravity(antennaPos))
                {
                    MySandboxGame.Log.WriteLine("Couldn't spawn drone; antenna is not in natural gravity but spawn location is.");
                    return(false);
                }
                planet.CorrectSpawnLocation(ref position, spawnGroup.SpawnRadius * 2.0);
                upVector = -planet.GetWorldGravityNormalized(ref position);
            }
            else
            {
                upVector = MyUtils.GetRandomVector3Normalized();
            }

            Vector3D direction    = MyUtils.GetRandomPerpendicularVector(ref upVector);
            MatrixD  originMatrix = MatrixD.CreateWorld(position, direction, upVector);

            foreach (var shipPrefab in spawnGroup.Prefabs)
            {
                Vector3D shipPosition = Vector3D.Transform((Vector3D)shipPrefab.Position, originMatrix);

                m_tmpGridList.Clear();

                MyPrefabManager.Static.SpawnPrefab(
                    resultList: m_tmpGridList,
                    prefabName: shipPrefab.SubtypeId,
                    position: shipPosition,
                    forward: direction,
                    up: upVector,
                    initialLinearVelocity: default(Vector3),
                    beaconName: null,
                    spawningOptions: VRage.Game.ModAPI.SpawningOptions.None,
                    ownerId: ownerId,
                    updateSync: true);

                foreach (var grid in m_tmpGridList)
                {
                    grid.ChangeGridOwnership(ownerId, MyOwnershipShareModeEnum.None);

                    MyRemoteControl firstRemote = null;

                    foreach (var block in grid.CubeBlocks)
                    {
                        if (block.FatBlock == null)
                        {
                            continue;
                        }

                        var pb = block.FatBlock as MyProgrammableBlock;
                        if (pb != null)
                        {
                            pb.SendRecompile();
                        }

                        var remote = block.FatBlock as MyRemoteControl;
                        if (firstRemote == null)
                        {
                            firstRemote = remote;
                        }
                    }

                    // If there's no remote control on the grid, we have to register it as is
                    RegisterDrone(antennaEntityId, (MyEntity)firstRemote ?? (MyEntity)grid);
                }

                m_tmpGridList.Clear();
            }
            return(true);
        }
        public override void UpdateBeforeSimulation()
        {
            base.UpdateBeforeSimulation();

            if (!MyFakes.ENABLE_PLANET_FIREFLIES)
            {
                return;
            }

            if (m_particleSpawnCounter-- > 0)
            {
                return;
            }

            m_particleSpawnCounter = 0;

            var entity = MySession.Static.ControlledEntity as MyEntity;

            if (entity == null)
            {
                return;
            }

            var controlledEntity = entity.GetTopMostParent();

            if (controlledEntity == null)
            {
                return;
            }

            try
            {
                ProfilerShort.Begin("Fireflies.Spawn");

                m_particleSpawnCounter = (int)Math.Round(m_particleSpawnCounter + m_particleSpawnCounter * m_particleSpawnIntervalRandomness * (MyRandom.Instance.NextFloat() * 2.0f - 1.0f));
                float normalVar = (MyRandom.Instance.FloatNormal() + 3.0f) / 6.0f;
                if (normalVar > m_particleDensity)
                {
                    return;
                }

                var naturalGravity = MyGravityProviderSystem.CalculateNaturalGravityInPoint(MySector.MainCamera.Position);
                if (naturalGravity.Dot(MySector.DirectionToSunNormalized) <= 0)                 // Only spawn at night and on planets
                {
                    return;
                }

                var velocity = (MySession.Static.GetCameraControllerEnum() != MyCameraControllerEnum.Entity &&
                                MySession.Static.GetCameraControllerEnum() != MyCameraControllerEnum.ThirdPersonSpectator
                                                                ? Vector3.Zero : controlledEntity.Physics.LinearVelocity);
                var speed = velocity.Length();

                var currentCharacter = controlledEntity as MyCharacter;

                float characterFlyingMaxSpeed = MyGridPhysics.ShipMaxLinearVelocity();

                if (currentCharacter != null && currentCharacter.Physics != null && currentCharacter.Physics.CharacterProxy != null)
                {
                    characterFlyingMaxSpeed = currentCharacter.Physics.CharacterProxy.CharacterFlyingMaxLinearVelocity();
                }

                Vector3 halfExtents = Vector3.One * m_particleSpawnDistance;
                if (speed / characterFlyingMaxSpeed > 1.0f)
                {
                    halfExtents += 10.0f * velocity / characterFlyingMaxSpeed;
                }

                var entityTranslation = MySector.MainCamera.Position;
                var searchPosition    = entityTranslation + velocity;

                MyPlanet planet = MyGravityProviderSystem.GetStrongestGravityWell(MySector.MainCamera.Position);

                if (planet == null || !planet.IsPositionInGravityWell(MySector.MainCamera.Position))
                {
                    return;
                }

                Vector3D cameraPosition        = MySector.MainCamera.Position;
                var      foundEnvironmentItems = planet.GetEnvironmentItemsAtPosition(ref cameraPosition);

                foreach (var environmentItems in foundEnvironmentItems)
                {
                    environmentItems.GetAllItemsInRadius(searchPosition, m_particleSpawnDistance, m_tmpItemInfos);
                }

                var  spawnPosition      = default(Vector3D);
                bool spawnPositionFound = m_tmpItemInfos.Count != 0;
                if (spawnPositionFound)
                {
                    int selectedTreeIndex = MyRandom.Instance.Next(0, m_tmpItemInfos.Count - 1);
                    spawnPosition      = m_tmpItemInfos[selectedTreeIndex].Transform.Position;
                    spawnPositionFound = true;
                }
                else
                {
                    return;
                }

                var spawnedParticle = Spawn(spawnPosition);

                if (spawnedParticle == null)
                {
                    return;
                }

                InitializePath(spawnedParticle);
            }
            finally
            {
                m_bodyCollisions.Clear();
                m_tmpItemInfos.Clear();

                ProfilerShort.End();
            }
        }
        /// <summary>
        /// Returns a position that should be safe to spawn at given the radius and position.
        /// </summary>
        /// <param name="collisionRadius">The radius of the object that is trying to spawn.</param>
        /// <param name="position">The position the object would like to spawn at.</param>
        /// <param name="forward">(Out) The forward vector the object should spawn with.</param>
        /// <param name="up">(Out) The up vector the object should spawn with.</param>
        /// <param name="planetSpawnHeightRatio">The ratio within the planet's max radius and atmosphere radius you are positioned in.</param>
        /// <param name="randomRangeMin">The minimum randomized distance that is added.</param>
        /// <param name="randomRangeMax">The minimum randomized distance that is added.</param>
        public static void GetSpawnPosition(float collisionRadius, ref Vector3D position, out Vector3D forward, out Vector3D up, float planetSpawnHeightRatio = 0.3f, float randomRangeMin = 500, float randomRangeMax = 650)
        {
            // Are we spawning near a planet?
            Vector3 gravity = MyGravityProviderSystem.CalculateNaturalGravityInPoint(position);

            if (gravity.LengthSquared() > 0)
            {
                MyPlanet planet = MyGravityProviderSystem.GetStrongestGravityWell(position);
                if (planet != null)
                {
                    GetSpawnPositionNearPlanet(planet, collisionRadius, ref position, out forward, out up, planetSpawnHeightRatio, randomRangeMin, randomRangeMax);
                    return;
                }
            }

            // Old logic, testing for asteroids and other objects
            double distance = 0;

            foreach (var entity in MyEntities.GetEntities())
            {
                MyVoxelMap voxelMap = entity as MyVoxelMap;

                // Only test against voxels
                if (entity == null)
                {
                    continue;
                }

                distance = MathHelper.Max(distance, entity.PositionComp.WorldVolume.Center.Length() + entity.PositionComp.WorldVolume.Radius);
            }

            // Random range from last voxel
            distance += MyUtils.GetRandomFloat(randomRangeMin, randomRangeMax);

            if (MyEntities.IsWorldLimited())
            {
                distance = Math.Min(distance, MyEntities.WorldSafeHalfExtent());
            }
            else
            {
                distance = Math.Min(distance, 20000); // limited spawn area in infinite worlds
            }
            // Compute random position
            forward = MyUtils.GetRandomVector3Normalized();
            up      = Vector3D.CalculatePerpendicularVector(forward);
            Vector3D randomizedPosition = position + (forward * distance);

            // Test if we can spawn here
            Vector3D?searchPosition = MyEntities.FindFreePlace(randomizedPosition, collisionRadius);

            if (searchPosition.HasValue)
            {
                randomizedPosition = searchPosition.Value;
            }

            // Make sure we didn't randomize into a planet
            gravity = MyGravityProviderSystem.CalculateNaturalGravityInPoint(randomizedPosition);
            if (gravity.LengthSquared() > 0)
            {
                MyPlanet planet = MyGravityProviderSystem.GetStrongestGravityWell(randomizedPosition);
                if (planet != null)
                {
                    GetSpawnPositionNearPlanet(planet, collisionRadius, ref position, out forward, out up, planetSpawnHeightRatio, randomRangeMin, randomRangeMax);
                }
                else
                {
                    position = randomizedPosition;
                }
            }
            else
            {
                position = randomizedPosition;
            }
        }