Exemple #1
0
        public static void MatchVerts(Mesh mesh, PQS pqs, double oceanHeight, float scaleFactor)
        {
            ProfileTimer.Push("MatchVerts");
            if (pqs == null)
            {
                MonoBehaviour.print("ERROR matching verts: pqs is null!");
                return;
            }
            char sep = System.IO.Path.DirectorySeparatorChar;

            pqs.isBuildingMaps = true;

            Vector3[] vertices = new Vector3[mesh.vertexCount];
            for (int i = 0; i < mesh.vertexCount; i++)
            {
                Vector3 v      = mesh.vertices[i];
                double  height = pqs.GetSurfaceHeight(v);
                if (height < oceanHeight)
                {
                    height = oceanHeight;
                }
                vertices[i] = v.normalized * (float)(1000.0 * height / pqs.radius * scaleFactor);
            }
            pqs.isBuildingMaps = false;
            mesh.vertices      = vertices;
            ProfileTimer.Pop("MatchVerts");
        }
Exemple #2
0
        private Single GetAltitudeFromOcean(Vector3 position)
        {
            PQS ocean = GetOcean();

            return((Single)ocean.GetSurfaceHeight(ocean.GetRelativePosition(position)) -
                   (Single)Part.vessel.mainBody.Radius);
        }
Exemple #3
0
        protected Vector3 getVesselPosition()
        {
            PQS    pqs = this.part.vessel.mainBody.pqsController;
            double alt = pqs.GetSurfaceHeight(vessel.mainBody.GetRelSurfaceNVector(this.part.vessel.latitude, this.part.vessel.longitude)) - vessel.mainBody.Radius;

            alt = Math.Max(alt, 0); // Underwater!
            return(this.part.vessel.mainBody.GetRelSurfacePosition(this.part.vessel.latitude, this.part.vessel.longitude, alt));
        }
Exemple #4
0
		// return terrain height at point specified
		// - body terrain must be loaded for this to work: use it only for loaded vessels
		public static double TerrainHeight(CelestialBody body, Vector3d pos)
		{
			PQS pqs = body.pqsController;
			if (pqs == null) return 0.0;
			Vector2d latlong = body.GetLatitudeAndLongitude(pos);
			Vector3d radial = QuaternionD.AngleAxis(latlong.y, Vector3d.down) * QuaternionD.AngleAxis(latlong.x, Vector3d.forward) * Vector3d.right;
			return (pos - body.position).magnitude - pqs.GetSurfaceHeight(radial);
		}
Exemple #5
0
        /// <summary>
        ///  Returns the ground's altitude above sea level at this geo position.
        /// </summary>
        /// <returns></returns>
        /// <remarks>Borrowed this from the kOS mod with slight modification</remarks>
        /// <see cref="https://github.com/KSP-KOS/KOS/blob/develop/src/kOS/Suffixed/GeoCoordinates.cs"/>
        public Double GetTerrainAltitude()
        {
            double alt     = 0.0;
            PQS    bodyPQS = Body.pqsController;

            if (bodyPQS != null) // The sun has no terrain.  Everything else has a PQScontroller.
            {
                // The PQS controller gives the theoretical ideal smooth surface curve terrain.
                // The actual ground that exists in-game that you land on, however, is the terrain
                // polygon mesh which is built dynamically from the PQS controller's altitude values,
                // and it only approximates the PQS controller.  The discrepancy between the two
                // can be as high as 20 meters on relatively mild rolling terrain and is probably worse
                // in mountainous terrain with steeper slopes.  It also varies with the user terrain detail
                // graphics setting.

                // Therefore the algorithm here is this:  Get the PQS ideal terrain altitude first.
                // Then try using RayCast to get the actual terrain altitude, which will only work
                // if the LAT/LONG is near the active vessel so the relevant terrain polygons are
                // loaded.  If the RayCast hit works, it overrides the PQS altitude.

                // PQS controller ideal altitude value:
                // -------------------------------------

                // The vector the pqs GetSurfaceHeight method expects is a vector in the following
                // reference frame:
                //     Origin = body center.
                //     X axis = LATLNG(0,0), Y axis = LATLNG(90,0)(north pole), Z axis = LATLNG(0,-90).
                // Using that reference frame, you tell GetSurfaceHeight what the "up" vector is pointing through
                // the spot on the surface you're querying for.
                var bodyUpVector = new Vector3d(1, 0, 0);
                bodyUpVector = QuaternionD.AngleAxis(Latitude, Vector3d.forward /*around Z axis*/) * bodyUpVector;
                bodyUpVector = QuaternionD.AngleAxis(Longitude, Vector3d.down /*around -Y axis*/) * bodyUpVector;

                alt = bodyPQS.GetSurfaceHeight(bodyUpVector) - bodyPQS.radius;

                // Terrain polygon raycasting:
                // ---------------------------
                const double HIGH_AGL         = 1000.0;
                const double POINT_AGL        = 800.0;
                const int    TERRAIN_MASK_BIT = 15;

                // a point hopefully above the terrain:
                Vector3d worldRayCastStart = Body.GetWorldSurfacePosition(Latitude, Longitude, alt + HIGH_AGL);
                // a point a bit below it, to aim down to the terrain:
                Vector3d   worldRayCastStop = Body.GetWorldSurfacePosition(Latitude, Longitude, alt + POINT_AGL);
                RaycastHit hit;
                if (Physics.Raycast(worldRayCastStart, (worldRayCastStop - worldRayCastStart), out hit, float.MaxValue, 1 << TERRAIN_MASK_BIT))
                {
                    // Ensure hit is on the topside of planet, near the worldRayCastStart, not on the far side.
                    if (Mathf.Abs(hit.distance) < 3000)
                    {
                        // Okay a hit was found, use it instead of PQS alt:
                        alt = ((alt + HIGH_AGL) - hit.distance);
                    }
                }
            }
            return(alt);
        }
Exemple #6
0
        /// <summary>
        /// Get the altitude of the surface at a point directly under where the vessel will be at
        /// the specified time.
        /// </summary>
        /// <param name="vessel"></param>
        /// <param name="universalTime"></param>
        /// <param name="currentUniversalTime"></param>
        /// <returns></returns>
        private static double SurfaceAltitudeAtTime(Vessel vessel, double universalTime, double currentUniversalTime)
        {
            // Note that the actual *exact* surface height will be different from what this function returns.
            // That's because this function simply uses the PQS controller, which gives a theoretical ideal
            // smooth-surface-curve terrain.  The actual game adds polygons into the mix, which can throw the
            // number off by 20 meters or more.  Useful discussion (and code to work around it) is here,
            // in the GetTerrainAltitude function:
            // https://github.com/KSP-KOS/KOS/blob/develop/src/kOS/Suffixed/GeoCoordinates.cs#L136
            // Solving the problem to get a perfectly accurate number requires doing physics ray-casting.
            // For the purposes of *this* mod, the ballpark figure from PQS is good enough, so we don't
            // bother with the extra computation to get an exact number.

            // Thanks to DMagic for pointing me at how SCANSat does these calculations:
            // https://github.com/S-C-A-N/SCANsat/blob/release/SCANsat/SCANcontroller.cs#L2065-L2073

            // If the main body has no PQS controller (e.g. the sun), all surface altitudes are implicitly zero.
            PQS pqs = vessel.mainBody.pqsController;

            if (pqs == null)
            {
                return(0);
            }

            // Where will the vessel be at that time?
            Vector3d position = vessel.orbit.getPositionAtUT(universalTime);

            // How much will the body have rotated by then?
            double rotationDegrees = 0;

            if (vessel.mainBody.rotates)
            {
                double numRotations = (universalTime - currentUniversalTime) / vessel.mainBody.rotationPeriod;
                rotationDegrees = 360.0 * numRotations;
            }

            // What will the latitude and longitude be at that time, in radians?
            double latitude  = vessel.mainBody.GetLatitude(position);
            double longitude = vessel.mainBody.GetLongitude(position) - rotationDegrees;

            // Convert that to a unit radial vector.
            Vector3d radialVector = new Vector3d(1, 0, 0);

            radialVector = QuaternionD.AngleAxis(latitude, Vector3d.forward) * radialVector;
            radialVector = QuaternionD.AngleAxis(longitude, Vector3d.down) * radialVector;

            // Now we can get the surface height.
            double surfaceHeight = pqs.GetSurfaceHeight(radialVector) - pqs.radius;

            // If we're over water, then this altitude will be the height of the ocean floor,
            // which we're not interested in.  Report that as zero.
            return((vessel.mainBody.ocean && (surfaceHeight < 0)) ? 0 : surfaceHeight);
        }
Exemple #7
0
        // Inspired by Hyperedit landing functions
        // https://github.com/Ezriilc/HyperEdit

        private Vector3d GetVesselPosition()
        {
            PQS pqs = vessel.mainBody.pqsController;

            if (null == pqs)
            {
                return(ZERO);
            }

            double alt = pqs.GetSurfaceHeight(vessel.mainBody.GetRelSurfaceNVector(0, 0)) - vessel.mainBody.Radius;

            alt = Math.Max(alt, 0); // Underwater!

            return(vessel.mainBody.GetRelSurfacePosition(0, 0, alt));
        }
Exemple #8
0
        /// <summary>
        /// Update the heat
        /// </summary>
        public void Update()
        {
            if (!FlightGlobals.ready)
            {
                return;
            }

            // Get all vessels
            List <Vessel> vessels = FlightGlobals.Vessels.FindAll(v => v.mainBody == _body);

            // Loop through them
            foreach (Vessel vessel in vessels)
            {
                Vector3 position         = vessel.transform.position;
                Double  distanceToPlanet =
                    Math.Abs(Vector3d.Distance(position, _body.transform.position)) -
                    _ocean.GetSurfaceHeight(_ocean.GetRelativePosition(position));
                Double heatingRate = heatCurve.Evaluate((Single)distanceToPlanet);
                foreach (Part part in vessel.Parts)
                {
                    part.temperature += heatingRate * Time.deltaTime;
                }
            }
        }
        public static void MatchVerts(Mesh mesh, PQS pqs, double oceanHeight, float scaleFactor)
        {
            if (pqs == null)
            {
                Utils.LogError("pqs is null");
                return;
            }
            pqs.isBuildingMaps = true;

            Vector3[] vertices = new Vector3[mesh.vertexCount];
            for (int i = 0; i < mesh.vertexCount; i++)
            {
                Vector3 v      = mesh.vertices[i];
                double  height = pqs.GetSurfaceHeight(v);
                if (height < oceanHeight)
                {
                    height = oceanHeight;
                }

                vertices[i] = v.normalized * (float)(1000.0 * height / pqs.radius * scaleFactor);
            }
            pqs.isBuildingMaps = false;
            mesh.vertices      = vertices;
        }
Exemple #10
0
        private void UpdateMove()
        {
            if (!MovingVessel)
            {
                EndMove();
                return;
            }
            MovingVessel.IgnoreGForces(240);

            // Lerp is animating move
            if (!_hoverChanged)
            {
                MoveHeight = Mathf.Lerp(MoveHeight, _vBounds.BottomLength + HoverHeight, 10 * Time.fixedDeltaTime);
            }
            else
            {
                double alt = MovingVessel.radarAltitude;
                // sINCE Lerp is animating move from 0 to hoverheight, we do not want this going below current altitude
                if (MoveHeight < alt)
                {
                    MoveHeight = Convert.ToSingle(alt);
                }

                MoveHeight = MovingVessel.Splashed
          ? Mathf.Lerp(MoveHeight, _vBounds.BottomLength + _hoverAdjust, 10 * Time.fixedDeltaTime)
          : Mathf.Lerp(MoveHeight, _vBounds.BottomLength + (MoveHeight + _hoverAdjust < 0 ? -MoveHeight : _hoverAdjust), 10 * Time.fixedDeltaTime);
            }
            MovingVessel.ActionGroups.SetGroup(KSPActionGroup.RCS, false);

            _up = (MovingVessel.transform.position - FlightGlobals.currentMainBody.transform.position).normalized;

            Vector3 forward;

            if (MapView.MapIsEnabled)
            {
                forward = North();
            }
            else
            {
                forward = Vector3.ProjectOnPlane(MovingVessel.CoM - FlightCamera.fetch.mainCamera.transform.position, _up).normalized;
                if (Vector3.Dot(-_up, FlightCamera.fetch.mainCamera.transform.up) > 0)
                {
                    forward = Vector3.ProjectOnPlane(FlightCamera.fetch.mainCamera.transform.up, _up).normalized;
                }
            }

            Vector3 right = Vector3.Cross(_up, forward);

            Vector3 offsetDirection = Vector3.zero;
            bool    inputting       = false;

            //Altitude Adjustment
            if (GameSettings.THROTTLE_CUTOFF.GetKey())
            {
                _hoverAdjust  = 0f;
                _hoverChanged = false;
            }

            if (GameSettings.THROTTLE_UP.GetKey())
            {
                _hoverAdjust += MoveSpeed * Time.fixedDeltaTime;
                inputting     = true;
                _hoverChanged = true;
            }

            if (GameSettings.THROTTLE_DOWN.GetKey())
            {
                _hoverAdjust += -(MoveSpeed * Time.fixedDeltaTime);
                inputting     = true;
                _hoverChanged = true;
            }

            if (GameSettings.PITCH_DOWN.GetKey())
            {
                offsetDirection += (forward * MoveSpeed * Time.fixedDeltaTime);
                inputting        = true;
            }
            if (GameSettings.PITCH_UP.GetKey())
            {
                offsetDirection += (-forward * MoveSpeed * Time.fixedDeltaTime);
                inputting        = true;
            }

            if (GameSettings.YAW_RIGHT.GetKey())
            {
                offsetDirection += (right * MoveSpeed * Time.fixedDeltaTime);
                inputting        = true;
            }
            if (GameSettings.YAW_LEFT.GetKey())
            {
                offsetDirection += (-right * MoveSpeed * Time.fixedDeltaTime);
                inputting        = true;
            }

            if (GameSettings.TRANSLATE_RIGHT.GetKey())
            {
                _startRotation = Quaternion.AngleAxis(-RotationSpeed, MovingVessel.ReferenceTransform.forward) * _startRotation;
                _hasRotated    = true;
            }
            else if (GameSettings.TRANSLATE_LEFT.GetKey())
            {
                _startRotation = Quaternion.AngleAxis(RotationSpeed, MovingVessel.ReferenceTransform.forward) * _startRotation;
                _hasRotated    = true;
            }

            if (GameSettings.TRANSLATE_DOWN.GetKey())
            {
                _startRotation = Quaternion.AngleAxis(RotationSpeed, MovingVessel.ReferenceTransform.right) * _startRotation;
                _hasRotated    = true;
            }
            else if (GameSettings.TRANSLATE_UP.GetKey())
            {
                _startRotation = Quaternion.AngleAxis(-RotationSpeed, MovingVessel.ReferenceTransform.right) * _startRotation;
                _hasRotated    = true;
            }

            if (GameSettings.ROLL_LEFT.GetKey())
            {
                _startRotation = Quaternion.AngleAxis(RotationSpeed, MovingVessel.ReferenceTransform.up) * _startRotation;
                _hasRotated    = true;
            }
            else if (GameSettings.ROLL_RIGHT.GetKey())
            {
                _startRotation = Quaternion.AngleAxis(-RotationSpeed, MovingVessel.ReferenceTransform.up) * _startRotation;
                _hasRotated    = true;
            }

            //auto level plane
            if (GameSettings.TRANSLATE_FWD.GetKey())
            {
                Quaternion targetRot = Quaternion.LookRotation(-_up, forward);
                _startRotation = Quaternion.RotateTowards(_startRotation, targetRot, RotationSpeed * 2);
                _hasRotated    = true;
            }
            else if (GameSettings.TRANSLATE_BACK.GetKey())//auto level rocket
            {
                Quaternion targetRot = Quaternion.LookRotation(forward, _up);
                _startRotation = Quaternion.RotateTowards(_startRotation, targetRot, RotationSpeed * 2);
                _hasRotated    = true;
            }

            if (inputting)
            {
                _currMoveSpeed = Mathf.Clamp(Mathf.MoveTowards(_currMoveSpeed, MoveSpeed, MoveAccel * Time.fixedDeltaTime), 0, MoveSpeed);
            }
            else
            {
                _currMoveSpeed = 0;
            }

            Vector3 offset = offsetDirection.normalized * _currMoveSpeed;

            _currMoveVelocity = offset / Time.fixedDeltaTime;
            Vector3    vSrfPt        = MovingVessel.CoM - (MoveHeight * _up);
            bool       srfBelowWater = false;
            RaycastHit ringHit       = default;


            bool surfaceDetected = false;
            var  rayCastHits     = CapsuleCast();


            Array.Sort(rayCastHits, (r1, r2) => r1.distance.CompareTo(r2.distance));

            foreach (var hit in rayCastHits)
            {
                var partHit = hit.collider.gameObject.GetComponentInParent <Part>();

                if (partHit == null)
                {
                    ringHit         = hit;
                    surfaceDetected = true;
                    break;
                }

                if (partHit?.vessel == MovingVessel)
                {
                    continue;
                }


                ringHit         = hit;
                surfaceDetected = true;
                break;
            }

            Vector3 finalOffset = Vector3.zero;



            if (surfaceDetected)
            {
                if (FlightGlobals.getAltitudeAtPos(ringHit.point) < 0)
                {
                    srfBelowWater = true;
                }

                Vector3 rOffset = Vector3.Project(ringHit.point - vSrfPt, _up);
                Vector3 mOffset = (vSrfPt + offset) - MovingVessel.CoM;
                finalOffset = rOffset + mOffset + (MoveHeight * _up);
                MovingVessel.Translate(finalOffset);
            }

            PQS bodyPQS = MovingVessel.mainBody.pqsController;

            Vector3d geoCoords = WorldPositionToGeoCoords(MovingVessel.GetWorldPos3D() + (_currMoveVelocity * Time.fixedDeltaTime), MovingVessel.mainBody);
            double   lat       = geoCoords.x;
            double   lng       = geoCoords.y;

            Vector3d bodyUpVector = new Vector3d(1, 0, 0);

            bodyUpVector = QuaternionD.AngleAxis(lat, Vector3d.forward /*around Z axis*/) * bodyUpVector;
            bodyUpVector = QuaternionD.AngleAxis(lng, Vector3d.down /*around -Y axis*/) * bodyUpVector;

            double srfHeight = bodyPQS.GetSurfaceHeight(bodyUpVector);


#if false
            {
                double alt    = srfHeight - bodyPQS.radius;
                double rAlt   = movingVessel.radarAltitude;
                double tAlt   = TrueAlt(movingVessel);
                double pAlt   = movingVessel.pqsAltitude;
                double teralt = movingVessel.mainBody.TerrainAltitude(movingVessel.mainBody.GetLatitude(geoCoords), movingVessel.mainBody.GetLongitude(geoCoords));
                Log.dbg("Surface height: {0}", movingVessel.mainBody.pqsController.GetSurfaceHeight(up));
            }
#endif

            if (!surfaceDetected || srfBelowWater)
            {
                Vector3 terrainPos    = MovingVessel.mainBody.position + (float)srfHeight * _up;
                Vector3 waterSrfPoint = FlightGlobals.currentMainBody.position + ((float)FlightGlobals.currentMainBody.Radius * _up);

                if (!surfaceDetected)
                {
                    MovingVessel.SetPosition(terrainPos + (MoveHeight * _up) + offset);
                }
                else
                {
                    MovingVessel.SetPosition(waterSrfPoint + (MoveHeight * _up) + offset);
                }

                //update vessel situation to splashed down:
                MovingVessel.UpdateLandedSplashed();
            }

            //fix surface rotation
            Quaternion srfRotFix = Quaternion.FromToRotation(_startingUp, _up);
            _currRotation = srfRotFix * _startRotation;
            MovingVessel.SetRotation(_currRotation);

            if (Vector3.Angle(_startingUp, _up) > 5)
            {
                _startRotation = _currRotation;
                _startingUp    = _up;
            }

            MovingVessel.SetWorldVelocity(Vector3d.zero);
            MovingVessel.angularVelocity = Vector3.zero;
            MovingVessel.angularMomentum = Vector3.zero;
        }
        //Scaled Space Updater
        private void RegenerateModel(PQS bodyPQS, MeshFilter meshfilter_input)
        {
            var originalVert = meshfilter_input.mesh.vertices[0];
            var originalHeight = (float)bodyPQS.GetSurfaceHeight(originalVert);
            var scale = originalHeight / originalVert.magnitude;

            bodyPQS.isBuildingMaps = true;
            var newVerts = new Vector3[meshfilter_input.mesh.vertices.Count()];
            for (int i = 0; i < meshfilter_input.mesh.vertices.Count(); i++)
            {
                var vertex = meshfilter_input.mesh.vertices[i];
                var rootrad = (float)Math.Sqrt(vertex.x * vertex.x +
                                vertex.y * vertex.y +
                                vertex.z * vertex.z);
                var radius = (float)bodyPQS.GetSurfaceHeight(vertex)/scale;
                //radius = 1000;
                newVerts[i] = vertex * (radius / rootrad);
            }
            bodyPQS.isBuildingMaps = false;

            meshfilter_input.mesh.vertices = newVerts;

            meshfilter_input.mesh.RecalculateNormals();
            Utils.RecalculateTangents(meshfilter_input.mesh);
        }
Exemple #12
0
            public static void GenerateScaledSpace(CelestialBody body, Mesh meshinput)
            {
                PQS    bodyPQS       = body.pqsController;
                Single joolScaledRad = 1000f;
                Single joolRad       = 6000000f;
                Single scale         = (float)bodyPQS.radius / joolScaledRad;

                Vector3[] vertices = new Vector3[meshinput.vertices.Count()];

                // One could use pqs.radiusMin and pqs.radiusMax to determine minimum and maximum height.
                // But to be safe, the height limit values will be determined manually.
                Single radiusMin = 0;
                Single radiusMax = 0;

                bodyPQS.isBuildingMaps = true;
                for (Int32 i = 0; i < meshinput.vertices.Count(); i++)
                {
                    Vector3 vertex  = meshinput.vertices[i];
                    Single  rootrad = (float)Math.Sqrt(vertex.x * vertex.x +
                                                       vertex.y * vertex.y +
                                                       vertex.z * vertex.z);
                    Single localRadius = (float)bodyPQS.GetSurfaceHeight(vertex) / scale;
                    vertices[i] = vertex * (localRadius / rootrad);

                    if (i == 0)
                    {
                        radiusMin = radiusMax = localRadius;
                    }
                    else
                    {
                        if (radiusMin > localRadius)
                        {
                            radiusMin = localRadius;
                        }
                        if (radiusMax < localRadius)
                        {
                            radiusMax = localRadius;
                        }
                    }
                }
                bodyPQS.isBuildingMaps = false;

                // Adjust the mesh so the maximum radius has 1000 unit in scaled space.
                // (so the planets will fit in the science archive list)
                Single r = radiusMax / 1000;

                for (Int32 i = 0; i < vertices.Count(); i++)
                {
                    vertices[i] /= r;
                }

                // Use the lowest radius as collision radius.
                Single radius = radiusMin / r;

                // Calculate the local scale.
                Vector3 localScale = Vector3.one * ((float)bodyPQS.radius / joolRad) * r;

                // Apply the mesh to ScaledSpace
                MeshFilter     meshfilter = body.scaledBody.GetComponent <MeshFilter>();
                SphereCollider collider   = body.scaledBody.GetComponent <SphereCollider>();

                meshfilter.sharedMesh.vertices = vertices;
                meshfilter.sharedMesh.RecalculateNormals();
                Utility.RecalculateTangents(meshfilter.sharedMesh);
                collider.radius = radius;
                body.scaledBody.transform.localScale = localScale;

                // Serialize
                Directory.CreateDirectory(KSPUtil.ApplicationRootPath + Body.ScaledSpaceCacheDirectory);
                Utility.SerializeMesh(meshfilter.sharedMesh, KSPUtil.ApplicationRootPath + Body.ScaledSpaceCacheDirectory + "/" + body.name + ".bin");
            }
Exemple #13
0
        private void UpdateMove()
        {
            if (!MovingVessel)
            {
//                EndMove();
                return;
            }
            MovingVessel.IgnoreGForces(240);

            // Lerp is animating move
            if (!_hoverChanged)
            {
                MoveHeight = Mathf.Lerp(MoveHeight, _vBounds.BottomLength + HoverHeight, 10 * Time.fixedDeltaTime);
            }
            else
            {
                double alt = MovingVessel.radarAltitude;
                // sINCE Lerp is animating move from 0 to hoverheight, we do not want this going below current altitude
                if (MoveHeight < alt)
                {
                    MoveHeight = Convert.ToSingle(alt);
                }

                MoveHeight = MovingVessel.Splashed
                  ? Mathf.Lerp(MoveHeight, _vBounds.BottomLength + _hoverAdjust, 10 * Time.fixedDeltaTime)
                  : Mathf.Lerp(MoveHeight, _vBounds.BottomLength + (MoveHeight + _hoverAdjust < 0 ? -MoveHeight : _hoverAdjust), 10 * Time.fixedDeltaTime);
            }
            MovingVessel.ActionGroups.SetGroup(KSPActionGroup.RCS, false);

            _up = (MovingVessel.transform.position - FlightGlobals.currentMainBody.transform.position).normalized;

            Vector3 forward;

            if (MapView.MapIsEnabled)
            {
                forward = North();
            }
            else
            {
                forward = Vector3.ProjectOnPlane(MovingVessel.CoM - FlightCamera.fetch.mainCamera.transform.position, _up).normalized;
                if (Vector3.Dot(-_up, FlightCamera.fetch.mainCamera.transform.up) > 0)
                {
                    forward = Vector3.ProjectOnPlane(FlightCamera.fetch.mainCamera.transform.up, _up).normalized;
                }
            }

            Vector3 right = Vector3.Cross(_up, forward);

            Vector3 offsetDirection = Vector3.zero;
            bool    inputting       = false;

            //auto level plane
            if (GameSettings.TRANSLATE_FWD.GetKey())
            {
                Quaternion targetRot = Quaternion.LookRotation(-_up, forward);
                _startRotation = Quaternion.RotateTowards(_startRotation, targetRot, RotationSpeed * 2);
                _hasRotated    = true;
            }
            else if (GameSettings.TRANSLATE_BACK.GetKey())//auto level rocket
            {
                Quaternion targetRot = Quaternion.LookRotation(forward, _up);
                _startRotation = Quaternion.RotateTowards(_startRotation, targetRot, RotationSpeed * 2);
                _hasRotated    = true;
            }

            if (inputting)
            {
                _currMoveSpeed = Mathf.Clamp(Mathf.MoveTowards(_currMoveSpeed, MoveSpeed, MoveAccel * Time.fixedDeltaTime), 0, MoveSpeed);
            }
            else
            {
                _currMoveSpeed = 0;
            }

            Vector3 offset = offsetDirection.normalized * _currMoveSpeed;

            _currMoveVelocity = offset / Time.fixedDeltaTime;
            Vector3    vSrfPt        = MovingVessel.CoM - (MoveHeight * _up);
            bool       srfBelowWater = false;
            RaycastHit ringHit;

            bool    surfaceDetected = CapsuleCast(out ringHit);
            Vector3 finalOffset     = Vector3.zero;

            if (surfaceDetected)
            {
                if (FlightGlobals.getAltitudeAtPos(ringHit.point) < 0)
                {
                    srfBelowWater = true;
                }

                Vector3 rOffset = Vector3.Project(ringHit.point - vSrfPt, _up);
                Vector3 mOffset = (vSrfPt + offset) - MovingVessel.CoM;
                finalOffset = rOffset + mOffset + (MoveHeight * _up);
                MovingVessel.Translate(finalOffset);
            }

            PQS bodyPQS = MovingVessel.mainBody.pqsController;

            Vector3d geoCoords = WorldPositionToGeoCoords(MovingVessel.GetWorldPos3D() + (_currMoveVelocity * Time.fixedDeltaTime), MovingVessel.mainBody);
            double   lat       = geoCoords.x;
            double   lng       = geoCoords.y;

            Vector3d bodyUpVector = new Vector3d(1, 0, 0);

            bodyUpVector = QuaternionD.AngleAxis(lat, Vector3d.forward /*around Z axis*/) * bodyUpVector;
            bodyUpVector = QuaternionD.AngleAxis(lng, Vector3d.down /*around -Y axis*/) * bodyUpVector;

            double srfHeight = bodyPQS.GetSurfaceHeight(bodyUpVector);

            if (!surfaceDetected || srfBelowWater)
            {
                Vector3 terrainPos    = MovingVessel.mainBody.position + (float)srfHeight * _up;
                Vector3 waterSrfPoint = FlightGlobals.currentMainBody.position + ((float)FlightGlobals.currentMainBody.Radius * _up);

                if (!surfaceDetected)
                {
                    MovingVessel.SetPosition(terrainPos + (MoveHeight * _up) + offset);
                }
                else
                {
                    MovingVessel.SetPosition(waterSrfPoint + (MoveHeight * _up) + offset);
                }

                //update vessel situation to splashed down:
                //MovingVessel.UpdateLandedSplashed();
            }

            //fix surface rotation
            Quaternion srfRotFix = Quaternion.FromToRotation(_startingUp, _up);

            _currRotation = srfRotFix * _startRotation;
            MovingVessel.SetRotation(_currRotation);

            if (Vector3.Angle(_startingUp, _up) > 5)
            {
                _startRotation = _currRotation;
                _startingUp    = _up;
            }

            MovingVessel.SetWorldVelocity(Vector3d.zero);
            MovingVessel.angularVelocity = Vector3.zero;
            MovingVessel.angularMomentum = Vector3.zero;
        }
        void FixAltitude()
        {
            CelestialBody body = FlightGlobals.currentMainBody;

            if (body == null)
            {
                return;
            }

            PQS pqs = body.pqsController;

            if (pqs == null)
            {
                return;
            }

            PQSCity city = GetComponent <PQSCity>();

            if (city == null)
            {
                return;
            }

            // Location
            Vector3 planet   = body.transform.position;
            Vector3 building = city.transform.position; // From body to city
            Vector3 location = (building - planet).normalized;

            // Sigma Dimensions Settings
            double resize          = body.Has("resize") ? body.Get <double>("resize") : 1;
            double landscape       = body.Has("landscape") ? body.Get <double>("landscape") : 1;
            double resizeBuildings = body.Has("resizeBuildings") ? body.Get <double>("resizeBuildings") : 1;

            // Max distance
            double maxDistance = Math.Abs(2 * pqs.mapMaxHeight);

            maxDistance *= resize * landscape > 1 ? resize * landscape : 1;
            maxDistance += body.Radius;


            RaycastHit[] hits = Physics.RaycastAll(planet + location * (float)maxDistance, -location, (float)maxDistance, LayerMask.GetMask("Local Scenery"));

            for (int i = 0; i < hits?.Length; i++)
            {
                if (hits[i].collider?.GetComponent <PQ>())
                {
                    // Update only once
                    TimingManager.UpdateRemove(TimingManager.TimingStage.Normal, FixAltitude);
                    Debug.Log("PQSCityFixer", "> Planet: " + body.transform.name);
                    Debug.Log("PQSCityFixer", "    > PQSCity: " + city);

                    // PQSCity parameters
                    double groundLevel = (hits[i].point - planet).magnitude - body.Radius;
                    double error       = pqs.GetSurfaceHeight(city.repositionRadial) - body.Radius - groundLevel;
                    double oceanDepth  = body.ocean && groundLevel < 0 ? -groundLevel : 0d;
                    groundLevel = body.ocean && groundLevel < 0 ? 0d : groundLevel;

                    Debug.Log("PQSCityFixer", "        > Ground Level at Mod = " + groundLevel);
                    Debug.Log("PQSCityFixer", "        > Ocean Depth at Mod = " + groundLevel);
                    Debug.Log("PQSCityFixer", "        > Ground Level Error at Mod = " + groundLevel);

                    // Fix Altitude
                    if (city.repositionToSphere && !city.repositionToSphereSurface)
                    {
                        // Offset = Distance from the radius of the planet

                        Debug.Log("PQSCityFixer", "        > PQSCity Original Radius Offset = " + city.repositionRadiusOffset);

                        double builtInOffset = city.repositionRadiusOffset - groundLevel / (resize * landscape);

                        Debug.Log("PQSCityFixer", "        > Builtuin Offset = " + builtInOffset);

                        city.repositionRadiusOffset = groundLevel + error / (resize * landscape) - (groundLevel + error - city.repositionRadiusOffset) / resizeBuildings;

                        Debug.Log("PQSCityFixer", "        > PQSCity Fixed Radius Offset = " + city.repositionRadiusOffset);
                    }
                    else
                    {
                        // Offset = Distance from the surface of the planet
                        if (!city.repositionToSphereSurface)
                        {
                            city.repositionToSphereSurface = true;
                            city.repositionRadiusOffset    = 0;
                        }
                        if (!city.repositionToSphereSurfaceAddHeight)
                        {
                            city.repositionToSphereSurfaceAddHeight = true;
                            city.repositionRadiusOffset             = 0;
                        }

                        Debug.Log("PQSCityFixer", "        > PQSCity Original Surface Offset = " + city.repositionRadiusOffset);

                        city.repositionRadiusOffset = oceanDepth + error / (resize * landscape) - (oceanDepth + error - city.repositionRadiusOffset) / resizeBuildings;

                        Debug.Log("PQSCityFixer", "        > PQSCity Fixed Surface Offset = " + city.repositionRadiusOffset);
                    }

                    city.Orientate();
                    DestroyImmediate(this);
                }
            }
        }
        private void UpdateMove()
        {
            if (!_moving) return;
            MovingVessel.IgnoreGForces(240);
            // Lerp is animating move
            if (!_hoverChanged)
            {
                //MoveHeight = Mathf.Lerp(MoveHeight, Convert.ToSingle(MovingVessel.radarAltitude), 10 * Time.fixedDeltaTime);// + HoverHeight, 10 * Time.fixedDeltaTime);
            }
            else
            {
                _alt = MoveHeight;
                if (MoveHeight < _alt) MoveHeight = (float)_alt;
                if (MoveHeight > _alt) MoveHeight = (float)_alt;
                MoveHeight = Mathf.Lerp(MoveHeight, (float)_alt + _hoverAdjust, 10 * Time.fixedDeltaTime);
            }
            MovingVessel.ActionGroups.SetGroup(KSPActionGroup.RCS, false);

            _hoverAdjust = 0;

            if (_externalControl)
            {
                if (MovingVessel.radarAltitude >= MovingVessel.altitude)
                {
                    MoveHeight = (float)MovingVessel.radarAltitude - (float)MovingVessel.altitude;
                }

                if (MoveHeight <= 10)
                {
                    MoveHeight = 10;
                }

                if (_distance >= 15 && _moving)
                {
                    if (OrXUtilities.instance.GetDistance(MovingVessel.longitude, MovingVessel.latitude, targetPosition.y, targetPosition.x, (MovingVessel.altitude + targetPosition.z) / 2) >= _distance * 0.5)
                    {
                        MoveHeight += 0.1f;
                    }
                    else
                    {
                        MoveHeight -= 0.1f;
                    }
                }
            }

            if (MoveHeight <= 10)
            {
                MoveSpeed = (float)MovingVessel.radarAltitude / 3;
            }
            else
            {
                if (MoveHeight >= 50)
                {
                    if (MoveHeight >= 100)
                    {
                        _lineRender.material.SetColor("_EmissiveColor", XKCDColors.BluePurple);
                        MoveSpeed = 100 + ((float)MovingVessel.radarAltitude / 10);
                    }
                    else
                    {
                        _lineRender.material.SetColor("_EmissiveColor", XKCDColors.AquaGreen);
                        MoveSpeed = (float)MovingVessel.radarAltitude;
                    }
                }
                else
                {
                    MoveSpeed = (float)MovingVessel.radarAltitude / 2;
                }
            }
            UpVect = (MovingVessel.transform.position - FlightGlobals.currentMainBody.transform.position).normalized;
            right = Vector3.Cross(UpVect, forward);

            offsetDirection = Vector3.zero;
            bool inputting = false;
            _moveSpeed = 0;

            //Altitude Adjustment

            _moveSpeed = MoveSpeed;

            if (!_externalControl)
            {
                if (MapView.MapIsEnabled)
                {
                    forward = North();
                }
                else
                {
                    forward = Vector3.ProjectOnPlane(MovingVessel.CoM - FlightCamera.fetch.mainCamera.transform.position, UpVect).normalized;
                    if (Vector3.Dot(-UpVect, FlightCamera.fetch.mainCamera.transform.up) > 0)
                    {
                        forward = Vector3.ProjectOnPlane(FlightCamera.fetch.mainCamera.transform.up, UpVect).normalized;
                    }
                }

                if (placingGate)
                {
                    if (MoveHeight >= 20)
                    {
                        MoveHeight = 20;
                    }
                }

                if (GameSettings.PITCH_DOWN.GetKey())
                {
                    offsetDirection += (forward * _moveSpeed * Time.fixedDeltaTime);
                    inputting = true;
                }
                if (GameSettings.PITCH_UP.GetKey())
                {
                    offsetDirection += (-forward * _moveSpeed * Time.fixedDeltaTime);
                    inputting = true;
                }

                if (GameSettings.YAW_RIGHT.GetKey())
                {
                    offsetDirection += (right * _moveSpeed * Time.fixedDeltaTime);
                    inputting = true;
                }
                if (GameSettings.YAW_LEFT.GetKey())
                {
                    offsetDirection += (-right * _moveSpeed * Time.fixedDeltaTime);
                    inputting = true;
                }

                if (GameSettings.THROTTLE_UP.GetKey())
                {
                    if (MovingVessel.radarAltitude <= 3000)
                    {
                        if (MovingVessel.altitude - MovingVessel.radarAltitude <= 0)
                        {
                            MoveHeight += (float)MovingVessel.altitude / 100;
                        }
                        else
                        {
                            MoveHeight += (float)MovingVessel.radarAltitude / 100;
                        }
                    }
                }
                if (GameSettings.THROTTLE_DOWN.GetKey())
                {
                    if (MovingVessel.radarAltitude >= 1)
                    {
                        if (MovingVessel.altitude - MovingVessel.radarAltitude <= 0)
                        {
                            MoveHeight -= (float)MovingVessel.altitude / 100;
                        }
                        else
                        {
                            MoveHeight -= (float)MovingVessel.radarAltitude / 100;
                        }
                    }
                }

                if (GameSettings.TRANSLATE_RIGHT.GetKey())
                {
                    _startRotation = Quaternion.AngleAxis(-RotationSpeed, MovingVessel.ReferenceTransform.forward) * _startRotation;
                    _hasRotated = true;
                }
                else if (GameSettings.TRANSLATE_LEFT.GetKey())
                {
                    _startRotation = Quaternion.AngleAxis(RotationSpeed, MovingVessel.ReferenceTransform.forward) * _startRotation;
                    _hasRotated = true;
                }

                if (GameSettings.TRANSLATE_DOWN.GetKey())
                {
                    _startRotation = Quaternion.AngleAxis(RotationSpeed, MovingVessel.ReferenceTransform.right) * _startRotation;
                    _hasRotated = true;
                }
                else if (GameSettings.TRANSLATE_UP.GetKey())
                {
                    _startRotation = Quaternion.AngleAxis(-RotationSpeed, MovingVessel.ReferenceTransform.right) * _startRotation;
                    _hasRotated = true;
                }

                if (GameSettings.ROLL_LEFT.GetKey())
                {
                    _startRotation = Quaternion.AngleAxis(RotationSpeed, MovingVessel.ReferenceTransform.up) * _startRotation;
                    _hasRotated = true;
                }
                else if (GameSettings.ROLL_RIGHT.GetKey())
                {
                    _startRotation = Quaternion.AngleAxis(-RotationSpeed, MovingVessel.ReferenceTransform.up) * _startRotation;
                    _hasRotated = true;
                }
            }
            else
            {
                forward = Vector3.ProjectOnPlane(MovingVessel.CoM - OrXHoloKron.instance.targetLoc, UpVect).normalized;
                offsetDirection += (-forward * _moveSpeed * Time.fixedDeltaTime);
            }

            if (spawningLocal)
            {
            }

            if (inputting || _externalControl)
            {
                _currMoveSpeed = Mathf.Clamp(Mathf.MoveTowards(_currMoveSpeed, _moveSpeed, MoveAccel * Time.fixedDeltaTime), 0, MoveSpeed);
            }
            else
            {
                _currMoveSpeed = 0;
            }

            Vector3 offset = offsetDirection.normalized * _currMoveSpeed;
            _currMoveVelocity = offset / Time.fixedDeltaTime;
            Vector3 vSrfPt = MovingVessel.CoM - (MoveHeight * UpVect);
            RaycastHit ringHit;

            bool surfaceDetected = CapsuleCast(out ringHit);
            Vector3 finalOffset = Vector3.zero;

            Vector3 rOffset = Vector3.Project(ringHit.point - vSrfPt, UpVect);
            Vector3 mOffset = (vSrfPt + offset) - MovingVessel.CoM;
            finalOffset = rOffset + mOffset + (MoveHeight * UpVect);
            if (!_moving) return;
            MovingVessel.Translate(finalOffset);

            PQS bodyPQS = MovingVessel.mainBody.pqsController;

            Vector3d geoCoords = OrXUtilities.instance.WorldPositionToGeoCoords(MovingVessel.GetWorldPos3D() + (_currMoveVelocity * Time.fixedDeltaTime), MovingVessel.mainBody);
            double lat = geoCoords.x;
            double lng = geoCoords.y;

            Vector3d bodyUpVector = new Vector3d(1, 0, 0);
            bodyUpVector = QuaternionD.AngleAxis(lat, Vector3d.forward/*around Z axis*/) * bodyUpVector;
            bodyUpVector = QuaternionD.AngleAxis(lng, Vector3d.down/*around -Y axis*/) * bodyUpVector;

            double srfHeight = bodyPQS.GetSurfaceHeight(bodyUpVector);

            if (!surfaceDetected)
            {
                Vector3 terrainPos = MovingVessel.mainBody.position + (float)srfHeight * UpVect;

                if (!surfaceDetected)
                {
                    MovingVessel.SetPosition(terrainPos + (MoveHeight * UpVect) + offset);
                }
            }

            //fix surface rotation
            Quaternion srfRotFix = Quaternion.FromToRotation(_startingUp, UpVect);
            _currRotation = srfRotFix * _startRotation;
            MovingVessel.SetRotation(_currRotation);

            if (Vector3.Angle(_startingUp, UpVect) > 5)
            {
                _startRotation = _currRotation;
                _startingUp = UpVect;
            }
            MovingVessel.SetWorldVelocity(Vector3d.zero);

            if (_externalControl)
            {
                double _dist = OrXUtilities.instance.GetDistance(MovingVessel.longitude, MovingVessel.latitude, targetPosition.y, targetPosition.x, (MovingVessel.altitude + targetPosition.z) / 2);
                
                if (OrXHoloKron.instance.triggerVessel != MovingVessel)
                {
                    if (_dist <= MoveHeight)
                    {
                        KillMove(true, false);
                    }
                }
                else
                {
                    if (_dist <= MoveHeight)
                    {
                        if (OrXHoloKron.instance._placingChallenger)
                        {
                            _moving = false;
                            _externalControl = false;
                            MovingVessel.SetWorldVelocity(Vector3.zero);
                            MovingVessel.IgnoreGForces(240);
                            spawningLocal = false;
                            OrXLog.instance.DebugLog("[OrX Vessel Move] ===== KILLING MOVE =====");
                            _lineRender.enabled = false;
                            IsMovingVessel = false;
                            MoveHeight = 0;
                            _hoverAdjust = 0f;
                            MovingVessel = new Vessel();
                            OrXHoloKron.instance._holdVesselPos = false;
                            _rb = MovingVessel.GetComponent<Rigidbody>();
                            _rb.isKinematic = true;
                            _rb = null;
                            OrXLog.instance.ResetFocusKeys();
                            OrXHoloKron.instance.OpenScoreboardMenu();
                        }
                        else
                        {
                            KillMove(true, false);
                        }
                    }
                }
            }
        }
Exemple #16
0
        public static void MatchVerts(Mesh mesh, PQS pqs, double oceanHeight, float scaleFactor)
        {
            ProfileTimer.Push("MatchVerts");
            if (pqs == null)
            {
                MonoBehaviour.print("ERROR matching verts: pqs is null!");
                return;
            }
            char sep = System.IO.Path.DirectorySeparatorChar;
            pqs.isBuildingMaps = true;

            Vector3[] vertices = new Vector3[mesh.vertexCount];
            for (int i = 0; i < mesh.vertexCount; i++)
            {
                Vector3 v = mesh.vertices[i];
                double height = pqs.GetSurfaceHeight(v);
                if (height < oceanHeight)
                    height = oceanHeight;
                vertices[i] = v.normalized * (float)(1000.0 * height / pqs.radius * scaleFactor);
            }
            pqs.isBuildingMaps = false;
            mesh.vertices = vertices;
            ProfileTimer.Pop("MatchVerts");
        }
Exemple #17
0
        void Update()
        {
            CelestialBody body = FlightGlobals.currentMainBody;

            if (body == null)
            {
                return;
            }

            PQS pqs = body.pqsController;

            if (pqs == null)
            {
                return;
            }

            PQSCity2 city = GetComponent <PQSCity2>();

            if (city == null)
            {
                return;
            }

            // Location
            Vector3 planet   = body.transform.position;
            Vector3 building = city.transform.position; // From body to city
            Vector3 location = (building - planet).normalized;

            // Sigma Dimensions Settings
            double resize          = body.Has("resize") ? body.Get <double>("resize") : 1;
            double landscape       = body.Has("landscape") ? body.Get <double>("landscape") : 1;
            double resizeBuildings = body.Has("resizeBuildings") ? body.Get <double>("resizeBuildings") : 1;

            // Max distance
            double maxDistance = Math.Abs(2 * pqs.mapMaxHeight);

            maxDistance *= resize * landscape > 1 ? resize * landscape : 1;
            maxDistance += body.Radius;


            RaycastHit[] hits = Physics.RaycastAll(planet + location * (float)maxDistance, -location, (float)maxDistance, LayerMask.GetMask("Local Scenery"));

            for (int i = 0; i < hits?.Length; i++)
            {
                if (hits[i].collider?.GetComponent <PQ>())
                {
                    Debug.Log("PQSCity2Fixer", "> Planet: " + body.transform.name);
                    Debug.Log("PQSCity2Fixer", "    > PQSCity2: " + city);

                    // PQSCity2 parameters
                    double groundLevel = (hits[i].point - planet).magnitude - body.Radius;
                    Debug.Log("PQSCity2Fixer", "        > Ground Level at Mod (RAYCAST) = " + groundLevel);
                    double error = pqs.GetSurfaceHeight(city.PlanetRelativePosition) - body.Radius - groundLevel;
                    Debug.Log("PQSCity2Fixer", "        > Ground Level Error at Mod = " + error);
                    double oceanDepth = body.ocean && groundLevel < 0 ? -groundLevel : 0d;
                    Debug.Log("PQSCity2Fixer", "        > Ocean Depth at Mod = " + oceanDepth);
                    groundLevel = body.ocean && groundLevel < 0 ? 0d : groundLevel;
                    Debug.Log("PQSCity2Fixer", "        > Ground Level at Mod (NEW) = " + groundLevel);

                    // Because, SQUAD
                    city.PositioningPoint.localPosition /= (float)(body.Radius + city.alt);

                    // Fix Altitude
                    if (!city.snapToSurface)
                    {
                        // Alt = Distance from the radius of the planet

                        Debug.Log("PQSCity2Fixer", "        > PQSCity2 Original Radius Offset = " + city.alt);

                        double builtInOffset = city.alt - groundLevel / (resize * landscape);

                        Debug.Log("PQSCity2Fixer", "        > Builtuin Offset = " + builtInOffset);

                        city.alt = groundLevel + error / (resize * landscape) - (groundLevel + error - city.alt) / resizeBuildings;

                        Debug.Log("PQSCity2Fixer", "        > PQSCity2 Fixed Radius Offset = " + city.alt);
                    }
                    else
                    {
                        // Offset = Distance from the surface of the planet

                        Debug.Log("PQSCity2Fixer", "        > PQSCity2 Original Surface Offset = " + city.snapHeightOffset);

                        double newOffset = oceanDepth + error / (resize * landscape) - (oceanDepth + error - city.snapHeightOffset) / resizeBuildings;

                        city.alt += newOffset - city.snapHeightOffset;
                        city.snapHeightOffset = newOffset;

                        Debug.Log("PQSCity2Fixer", "        > PQSCity2 New Surface Offset = " + city.snapHeightOffset);
                    }

                    // Because, SQUAD
                    city.PositioningPoint.localPosition *= (float)(body.Radius + city.alt);

                    // Apply Changes and Destroy
                    city.Orientate();
                    DestroyImmediate(this);
                }
            }
        }
Exemple #18
0
        void UpdateMove()
        {
            if (!movingVessel)
            {
                EndMove();
                return;
            }

            moveHeight = Mathf.Lerp(moveHeight, vBounds.bottomLength + hoverHeight, 10 * Time.fixedDeltaTime);

            movingVessel.ActionGroups.SetGroup(KSPActionGroup.RCS, false);

            up = (movingVessel.transform.position - FlightGlobals.currentMainBody.transform.position).normalized;

            Vector3 forward;

            if (MapView.MapIsEnabled)
            {
                forward = North();
            }
            else
            {
                forward = Vector3.ProjectOnPlane(movingVessel.CoM - FlightCamera.fetch.mainCamera.transform.position, up).normalized;
                if (Vector3.Dot(-up, FlightCamera.fetch.mainCamera.transform.up) > 0)
                {
                    forward = Vector3.ProjectOnPlane(FlightCamera.fetch.mainCamera.transform.up, up).normalized;
                }
            }

            Vector3 right = Vector3.Cross(up, forward);

            Vector3 offsetDirection = Vector3.zero;
            bool    inputting       = false;

            if (GameSettings.PITCH_DOWN.GetKey())
            {
                offsetDirection += (forward * moveSpeed * Time.fixedDeltaTime);
                inputting        = true;
            }
            if (GameSettings.PITCH_UP.GetKey())
            {
                offsetDirection += (-forward * moveSpeed * Time.fixedDeltaTime);
                inputting        = true;
            }

            if (GameSettings.YAW_RIGHT.GetKey())
            {
                offsetDirection += (right * moveSpeed * Time.fixedDeltaTime);
                inputting        = true;
            }
            if (GameSettings.YAW_LEFT.GetKey())
            {
                offsetDirection += (-right * moveSpeed * Time.fixedDeltaTime);
                inputting        = true;
            }

            if (GameSettings.TRANSLATE_RIGHT.GetKey())
            {
                startRotation = Quaternion.AngleAxis(-rotationSpeed, movingVessel.ReferenceTransform.forward) * startRotation;
                hasRotated    = true;
            }
            else if (GameSettings.TRANSLATE_LEFT.GetKey())
            {
                startRotation = Quaternion.AngleAxis(rotationSpeed, movingVessel.ReferenceTransform.forward) * startRotation;
                hasRotated    = true;
            }

            if (GameSettings.TRANSLATE_DOWN.GetKey())
            {
                startRotation = Quaternion.AngleAxis(rotationSpeed, movingVessel.ReferenceTransform.right) * startRotation;
                hasRotated    = true;
            }
            else if (GameSettings.TRANSLATE_UP.GetKey())
            {
                startRotation = Quaternion.AngleAxis(-rotationSpeed, movingVessel.ReferenceTransform.right) * startRotation;
                hasRotated    = true;
            }

            if (GameSettings.ROLL_LEFT.GetKey())
            {
                startRotation = Quaternion.AngleAxis(rotationSpeed, movingVessel.ReferenceTransform.up) * startRotation;
                hasRotated    = true;
            }
            else if (GameSettings.ROLL_RIGHT.GetKey())
            {
                startRotation = Quaternion.AngleAxis(-rotationSpeed, movingVessel.ReferenceTransform.up) * startRotation;
                hasRotated    = true;
            }

            //auto level plane
            if (GameSettings.TRANSLATE_FWD.GetKey())
            {
                Quaternion targetRot = Quaternion.LookRotation(-up, forward);
                startRotation = Quaternion.RotateTowards(startRotation, targetRot, rotationSpeed * 2);
                hasRotated    = true;
            }
            else if (GameSettings.TRANSLATE_BACK.GetKey())           //auto level rocket
            {
                Quaternion targetRot = Quaternion.LookRotation(forward, up);
                startRotation = Quaternion.RotateTowards(startRotation, targetRot, rotationSpeed * 2);
                hasRotated    = true;
            }

            if (inputting)
            {
                currMoveSpeed = Mathf.Clamp(Mathf.MoveTowards(currMoveSpeed, moveSpeed, moveAccel * Time.fixedDeltaTime), 0, moveSpeed);
            }
            else
            {
                currMoveSpeed = 0;
            }

            Vector3 offset = offsetDirection.normalized * currMoveSpeed;

            currMoveVelocity = offset / Time.fixedDeltaTime;

            Vector3    vSrfPt        = movingVessel.CoM - (moveHeight * up);
            bool       srfBelowWater = false;
            RaycastHit ringHit;
            //bool surfaceDetected = RingCast(out ringHit, 8);
            bool    surfaceDetected = CapsuleCast(out ringHit);
            Vector3 finalOffset     = Vector3.zero;

            if (surfaceDetected)
            {
                if (FlightGlobals.getAltitudeAtPos(ringHit.point) < 0)
                {
                    srfBelowWater = true;
                }

                Vector3 rOffset = Vector3.Project(ringHit.point - vSrfPt, up);
                Vector3 mOffset = (vSrfPt + offset) - movingVessel.CoM;
                finalOffset = rOffset + mOffset + (moveHeight * up);
                movingVessel.Translate(finalOffset);
            }

            Vector3d geoCoords    = WorldPositionToGeoCoords(movingVessel.GetWorldPos3D() + (currMoveVelocity * Time.fixedDeltaTime), movingVessel.mainBody);
            PQS      bodyPQS      = movingVessel.mainBody.pqsController;
            double   Lat          = geoCoords.x;
            double   Lng          = geoCoords.y;
            var      bodyUpVector = new Vector3d(1, 0, 0);

            bodyUpVector = QuaternionD.AngleAxis(Lat, Vector3d.forward /*around Z axis*/) * bodyUpVector;
            bodyUpVector = QuaternionD.AngleAxis(Lng, Vector3d.down /*around -Y axis*/) * bodyUpVector;
            double srfHeight = bodyPQS.GetSurfaceHeight(bodyUpVector);
            double alt       = srfHeight - bodyPQS.radius;

            if (!surfaceDetected || srfBelowWater)
            {
                //Debug.Log ("Surface height: "+movingVessel.mainBody.pqsController.GetSurfaceHeight(up));
                Vector3 terrainPos = movingVessel.mainBody.position + (float)srfHeight * up;
                if (alt > 0)
                {
                    movingVessel.SetPosition(terrainPos + (moveHeight * up) + offset);

                    //currMoveSpeed/=2; //this would slow you down in order to let terrain load, however, hovering high enough makes it so terrain doesnt matter
                }
                else
                {
                    Vector3 waterSrfPoint = FlightGlobals.currentMainBody.position + ((float)FlightGlobals.currentMainBody.Radius * up);
                    movingVessel.SetPosition(waterSrfPoint + (moveHeight * up) + offset);
                }
            }

            //fix surface rotation
            Quaternion srfRotFix = Quaternion.FromToRotation(startingUp, up);

            currRotation = srfRotFix * startRotation;
            movingVessel.SetRotation(currRotation);
            if (Vector3.Angle(startingUp, up) > 5)
            {
                startRotation = currRotation;
                startingUp    = up;
            }

            movingVessel.SetWorldVelocity(Vector3d.zero);
            movingVessel.angularVelocity = Vector3.zero;
            movingVessel.angularMomentum = Vector3.zero;
        }
        void Update()
        {
            if (time < 0.2)
            {
                time += Time.deltaTime;
            }
            else
            {
                time = 0;

                CelestialBody body = FlightGlobals.currentMainBody;
                if (body == null)
                {
                    return;
                }

                PQS pqs = body.pqsController;
                if (pqs == null)
                {
                    return;
                }

                PQSCity city = GetComponent <PQSCity>();
                if (city == null)
                {
                    return;
                }

                // Location
                Vector3 planet   = body.transform.position;
                Vector3 building = city.transform.position; // From body to city
                Vector3 location = (building - planet).normalized;

                // Sigma Dimensions Settings
                double resize          = body.Has("resize") ? body.Get <double>("resize") : 1;
                double landscape       = body.Has("landscape") ? body.Get <double>("landscape") : 1;
                double resizeBuildings = body.Has("resizeBuildings") ? body.Get <double>("resizeBuildings") : 1;

                // Max distance
                double maxDistance = Math.Abs(2 * pqs.mapMaxHeight);
                maxDistance *= resize * landscape > 1 ? resize * landscape : 1;
                maxDistance += body.Radius;

                RaycastHit[] hits = Physics.RaycastAll(planet + location * (float)maxDistance, -location, (float)maxDistance, LayerMask.GetMask("Local Scenery"));

                for (int i = 0; i < hits?.Length; i++)
                {
                    if (hits[i].collider?.GetComponent <PQ>())
                    {
                        Debug.Log("PQSCityFixer", "> Planet: " + body.transform.name);
                        Debug.Log("PQSCityFixer", "    > PQSCity: " + city);

                        // PQSCity parameters
                        double oldGroundLevel = pqs.GetSurfaceHeight(city.repositionRadial) - body.Radius;
                        Debug.Log("PQSCityFixer", "        > Old Ground Level at Mod (GETSURFACE) = " + oldGroundLevel);
                        double oldOceanOffset = body.ocean && oldGroundLevel < 0 ? oldGroundLevel : 0d;
                        Debug.Log("PQSCityFixer", "        > Old Ocean Offset at Mod = " + oldOceanOffset);
                        oldGroundLevel = body.ocean && oldGroundLevel < 0 ? 0d : oldGroundLevel;
                        Debug.Log("PQSCityFixer", "        > Old Ground Level at Mod (WITH OCEAN) = " + oldGroundLevel);

                        double groundLevel = (hits[i].point - planet).magnitude - body.Radius;
                        Debug.Log("PQSCityFixer", "        > Ground Level at Mod (RAYCAST) = " + groundLevel);
                        double oceanOffset = body.ocean && groundLevel < 0 ? groundLevel : 0d;
                        Debug.Log("PQSCityFixer", "        > Ocean Offset at Mod = " + oceanOffset);
                        groundLevel = body.ocean && groundLevel < 0 ? 0d : groundLevel;
                        Debug.Log("PQSCityFixer", "        > Ground Level at Mod (WITH OCEAN) = " + groundLevel);

                        // Fix Altitude
                        if (!city.repositionToSphere && !city.repositionToSphereSurface)
                        {
                            // Offset = Distance from the center of the planet
                            // THIS IS NOT POSSIBLE AS OF KSP 1.7.1

                            Debug.Log("PQSCityFixer", "        > PQSCity Current Center Offset = " + city.repositionRadiusOffset);

                            double builtInOffset = (city.repositionRadiusOffset - body.Radius - oldGroundLevel - oceanOffset) / resizeBuildings - (groundLevel + oceanOffset - oldGroundLevel - oldOceanOffset) / (resize * landscape);

                            Debug.Log("PQSCityFixer", "        > Builtin Offset = " + builtInOffset);

                            city.repositionRadiusOffset = body.Radius + groundLevel + oceanOffset + builtInOffset * resizeBuildings;

                            Debug.Log("PQSCityFixer", "        > PQSCity Fixed Center Offset = " + city.repositionRadiusOffset);
                        }
                        else if (city.repositionToSphere && !city.repositionToSphereSurface)
                        {
                            // Offset = Distance from the radius of the planet

                            Debug.Log("PQSCityFixer", "        > PQSCity Current Radius Offset = " + city.repositionRadiusOffset);

                            double builtInOffset = (city.repositionRadiusOffset - oldGroundLevel) / resizeBuildings - (groundLevel - oldGroundLevel) / (resize * landscape);

                            Debug.Log("PQSCityFixer", "        > Builtin Offset = " + builtInOffset);

                            city.repositionRadiusOffset = groundLevel + builtInOffset * resizeBuildings;

                            Debug.Log("PQSCityFixer", "        > PQSCity Fixed Radius Offset = " + city.repositionRadiusOffset);
                        }
                        else
                        {
                            // Offset = Distance from the surface of the planet

                            Debug.Log("PQSCityFixer", "        > PQSCity Current Surface Offset = " + city.repositionRadiusOffset);

                            double builtInOffset = city.repositionRadiusOffset / resizeBuildings - (groundLevel + oceanOffset - oldGroundLevel - oldOceanOffset) / (resize * landscape);

                            Debug.Log("PQSCityFixer", "        > Builtin Offset = " + builtInOffset);

                            city.repositionRadiusOffset = builtInOffset * resizeBuildings + groundLevel + oceanOffset - oldGroundLevel - oldOceanOffset;

                            Debug.Log("PQSCityFixer", "        > PQSCity Fixed Surface Offset = " + city.repositionRadiusOffset);
                        }

                        // Apply Changes and Destroy
                        city.Orientate();
                        DestroyImmediate(this);
                    }
                }
            }
        }