Inheritance: KMPVesselInfo
Example #1
0
        private void handleVesselUpdate(KMPVesselUpdate vessel_update)
        {
            KMPClientMain.DebugLog("handleVesselUpdate");

            String vessel_key = vessel_update.id.ToString();

            KMPVessel vessel = null;

            //Try to find the key in the vessel dictionary
            VesselEntry entry;
            if (vessels.TryGetValue(vessel_key, out entry))
            {
                vessel = entry.vessel;

                if (vessel == null || vessel.gameObj == null || (vessel.vesselRef != null && vessel.vesselRef.id != vessel_update.id))
                {
                    //Delete the vessel if it's null or needs to be renamed
                    vessels.Remove(vessel_key);

                    if (vessel != null && vessel.gameObj != null)
                        GameObject.Destroy(vessel.gameObj);

                    vessel = null;
                }
                else
                {
                    //Update the entry's timestamp
                    VesselEntry new_entry = new VesselEntry();
                    new_entry.vessel = entry.vessel;
                    new_entry.lastUpdateTime = UnityEngine.Time.realtimeSinceStartup;

                    vessels[vessel_key] = new_entry;
                }
            }

            if (vessel == null) {
                //Add the vessel to the dictionary
                vessel = new KMPVessel(vessel_update.name, vessel_update.player, vessel_update.id);
                entry = new VesselEntry();
                entry.vessel = vessel;
                entry.lastUpdateTime = UnityEngine.Time.realtimeSinceStartup;

                if (vessels.ContainsKey(vessel_key))
                    vessels[vessel_key] = entry;
                else
                    vessels.Add(vessel_key, entry);

                /*Queue this update for the next update call because updating a vessel on the same step as
                 * creating it usually causes problems for some reason */
                newVesselUpdateQueue.Enqueue(vessel_update);
                KMPClientMain.DebugLog("vessel update queued");
            }
            else
            {
                applyVesselUpdate(vessel_update, vessel); //Apply the vessel update to the existing vessel
                KMPClientMain.DebugLog("vessel update applied");
            }

            KMPClientMain.DebugLog("handleVesselUpdate done");
        }
Example #2
0
        private void addRemoteVessel(ProtoVessel protovessel, Guid vessel_id, KMPVesselUpdate update = null, double distance = 501d)
        {
            if (isInFlight && vessel_id == FlightGlobals.ActiveVessel.id)
            {
                KMPClientMain.DebugLog("Attempted to update controlled vessel!");
                return;
            }
            KMPClientMain.DebugLog("addRemoteVessel");
            Vector3 newWorldPos = Vector3.zero, newOrbitVel = Vector3.zero;
            bool setTarget = false, wasLoaded = false;
            try
            {
                //Ensure this vessel isn't already loaded
                Vessel oldVessel = FlightGlobals.Vessels.Find (v => v.id == vessel_id);
                if (oldVessel != null) {
                    KMPClientMain.DebugLog("killing extant vessel");
                    wasLoaded = oldVessel.loaded;
                    if (protovessel.vesselType == VesselType.EVA && wasLoaded)
                    {
                        return; //Don't touch EVAs here
                    }
                    else
                    {
                        setTarget = FlightGlobals.fetch.VesselTarget != null && FlightGlobals.fetch.VesselTarget.GetVessel().id == vessel_id;
                        if (oldVessel.loaded)
                        {
                            newWorldPos = oldVessel.transform.position;
                            if (oldVessel.altitude > 10000d)
                                newOrbitVel = oldVessel.GetObtVelocity();
                        }
                        oldVessel.Die();
                    }
                }

                if (protovessel.vesselType != VesselType.EVA && serverVessels_Parts.ContainsKey(vessel_id))
                {
                    KMPClientMain.DebugLog("killing known precursor vessels");
                    foreach (Part part in serverVessels_Parts[vessel_id])
                    {
                        try { if (!part.vessel.isEVA) part.vessel.Die(); } catch {}
                    }
                }
            } catch {}
            try
            {
                if ((protovessel.vesselType != VesselType.Debris && protovessel.vesselType != VesselType.Unknown) && protovessel.situation == Vessel.Situations.SUB_ORBITAL && protovessel.altitude < 25d)
                {
                    //Land flags, vessels and EVAs that are on sub-orbital trajectory
                    KMPClientMain.DebugLog("Placing sub-orbital protovessel on surface");
                    protovessel.situation = Vessel.Situations.LANDED;
                    protovessel.landed = true;
                    if (protovessel.vesselType == VesselType.Flag) protovessel.height = -1;
                }
                //Don't bother with suborbital debris
                else if (protovessel.vesselType == VesselType.Debris && protovessel.situation == Vessel.Situations.SUB_ORBITAL) return;

                CelestialBody body = null;

                if (update != null)
                {
                    body = FlightGlobals.Bodies.Find(b => b.name == update.bodyName);
                    if (update.situation != Situation.LANDED && update.situation != Situation.SPLASHED)
                    {
                        if (body.atmosphere && body.maxAtmosphereAltitude > protovessel.altitude)
                        {
                            //In-atmo vessel--only load if within visible range
                            if (distance > 500d)
                                return;
                        }
                    }
                }

                if (isInSafetyBubble(protovessel.position, body, protovessel.altitude)) //refuse to load anything too close to the KSC
                {
                    KMPClientMain.DebugLog("Tried to load vessel too close to KSC");
                    return;
                }

                IEnumerator<ProtoCrewMember> crewEnum = HighLogic.CurrentGame.CrewRoster.GetEnumerator();
                int applicants = 0;
                while (crewEnum.MoveNext())
                    if (crewEnum.Current.rosterStatus == ProtoCrewMember.RosterStatus.AVAILABLE) applicants++;

                if (protovessel.GetVesselCrew().Count * 5 > applicants)
                {
                    KMPClientMain.DebugLog("Adding crew applicants");
                    for (int i = 0; i < (protovessel.GetVesselCrew().Count * 5);)
                    {
                        ProtoCrewMember protoCrew = CrewGenerator.RandomCrewMemberPrototype();
                        if (!HighLogic.CurrentGame.CrewRoster.ExistsInRoster(protoCrew.name))
                        {
                            HighLogic.CurrentGame.CrewRoster.AddCrewMember(protoCrew);
                            i++;
                        }
                    }
                }
                if (vessels.ContainsKey(vessel_id.ToString()) && (!serverVessels_LoadDelay.ContainsKey(vessel_id) || (serverVessels_LoadDelay.ContainsKey(vessel_id) ? serverVessels_LoadDelay[vessel_id] < UnityEngine.Time.realtimeSinceStartup : false)))
                {
                    protovessel.Load(HighLogic.CurrentGame.flightState);
                    Vessel created_vessel = protovessel.vesselRef;
                    if (created_vessel != null)
                    {
                        try
                        {
                            OrbitPhysicsManager.HoldVesselUnpack(1);
                        }
                        catch (NullReferenceException)
                        {
                        }
                        if (!created_vessel.loaded) created_vessel.Load();
                        KMPClientMain.DebugLog(created_vessel.id.ToString() + " initializing: ProtoParts=" + protovessel.protoPartSnapshots.Count+ ",Parts=" + created_vessel.Parts.Count + ",Sit=" + created_vessel.situation.ToString() + ",type=" + created_vessel.vesselType + ",alt=" + protovessel.altitude);

                        vessels[vessel_id.ToString()].vessel.vesselRef = created_vessel;
                        serverVessels_PartCounts[vessel_id] = created_vessel.Parts.Count;
                        serverVessels_Parts[vessel_id] = new List<Part>();
                        serverVessels_Parts[vessel_id].AddRange(created_vessel.Parts);

                        bool distanceBlocksUnload = false;

                        if (created_vessel.vesselType != VesselType.Flag && created_vessel.vesselType != VesselType.EVA)
                        {
                            foreach (Part part in created_vessel.Parts)
                            {
                                part.OnLoad();
                                part.OnJustAboutToBeDestroyed += checkRemoteVesselIntegrity;
                                part.explosionPotential = 0;
                                part.terrainCollider = new PQS_PartCollider();
                                part.terrainCollider.part = part;
                                part.terrainCollider.useVelocityCollider = false;
                                part.terrainCollider.useGravityCollider = false;
                                part.breakingForce = float.MaxValue;
                                part.breakingTorque = float.MaxValue;
                            }
                            if (update != null && update.bodyName == FlightGlobals.ActiveVessel.mainBody.name)
                            {
                                KMPClientMain.DebugLog("update included");

                                //Update rotation

                                created_vessel.SetRotation(new Quaternion(update.rot[0],update.rot[1],update.rot[2],update.rot[3]));

                                if (update.relTime == RelativeTime.PRESENT)
                                {
                                    if (newWorldPos != Vector3.zero)
                                    {
                                        KMPClientMain.DebugLog("repositioning");
                                        created_vessel.transform.position = newWorldPos;
                                        if (wasLoaded) distanceBlocksUnload = Vector3.Distance(created_vessel.transform.position,FlightGlobals.ActiveVessel.transform.position) < 2000f;
                                    }
                                    if (newOrbitVel != Vector3.zero)
                                    {
                                        KMPClientMain.DebugLog("updating velocity");
                                        created_vessel.ChangeWorldVelocity((-1 * created_vessel.GetObtVelocity()) + newOrbitVel);
                                    }

                                    //Update FlightCtrlState
                                    if (created_vessel.ctrlState == null) created_vessel.ctrlState = new FlightCtrlState();
                                    created_vessel.ctrlState.CopyFrom(update.flightCtrlState.getAsFlightCtrlState(0.75f));
                                }
                                else
                                {
                                    serverVessels_InPresent[update.id] = false;
                                    foreach (Part part in created_vessel.Parts)
                                    {
                                        part.setOpacity(0.3f);
                                    }
                                }
                            }
                        }
                        if (!syncing && !distanceBlocksUnload) //This explicit Unload helps correct the effects of "Can't remove Part (Script) because PartBuoyancy (Script) depends on it" errors and associated NREs seen during rendezvous mode switching, but for unknown reasons it causes problems if active during universe sync
                            created_vessel.Unload();
                        if (setTarget) StartCoroutine(setDockingTarget(created_vessel));
                        KMPClientMain.DebugLog(created_vessel.id.ToString() + " initialized");
                    }
                }
            }
            catch (Exception e)
            {
                KMPClientMain.DebugLog("Error adding remote vessel: " + e.Message + " " + e.StackTrace);
            }
        }
Example #3
0
        private void applyVesselUpdate(KMPVesselUpdate vessel_update, KMPVessel vessel)
        {
            serverVessels_RemoteID[vessel_update.id] = vessel_update.kmpID;

            //Find the CelestialBody that matches the one in the update
            CelestialBody update_body = null;
            if (vessel.mainBody != null && vessel.mainBody.bodyName == vessel_update.bodyName)
                update_body = vessel.mainBody; //Vessel already has the correct body
            else
            {
                //Find the celestial body in the list of bodies
                foreach (CelestialBody body in FlightGlobals.Bodies)
                {
                    if (body.bodyName == vessel_update.bodyName)
                    {
                        update_body = body;
                        break;
                    }
                }
            }

            Vector3 oldPosition = vessel.worldPosition;

            if (update_body != null)
            {
                //Convert float arrays to Vector3s
                Vector3 pos = new Vector3(vessel_update.pos[0], vessel_update.pos[1], vessel_update.pos[2]);
                Vector3 dir = new Vector3(vessel_update.dir[0], vessel_update.dir[1], vessel_update.dir[2]);
                Vector3 vel = new Vector3(vessel_update.vel[0], vessel_update.vel[1], vessel_update.vel[2]);
                vessel.info = vessel_update;
                vessel.setOrbitalData(update_body, pos, vel, dir);
            }

            KMPClientMain.DebugLog("vessel state: " + vessel_update.state.ToString() + ", tick=" + vessel_update.tick + ", realTick=" + Planetarium.GetUniversalTime());
            if (vessel_update.state == State.ACTIVE && !vessel_update.isSyncOnlyUpdate && vessel_update.relTime != RelativeTime.FUTURE && !vessel_update.isDockUpdate)
            {
                //Update the player status info
                VesselStatusInfo status = new VesselStatusInfo();
                if (vessel_update.relTime == RelativeTime.PRESENT) status.info = vessel_update;
                status.ownerName = vessel_update.player;
                status.vesselName = vessel_update.name;

                if (vessel.orbitValid)
                    status.orbit = vessel.orbitRenderer.driver.orbit;

                status.lastUpdateTime = UnityEngine.Time.realtimeSinceStartup;
                status.color = KMPVessel.generateActiveColor(status.ownerName);

                if (playerStatus.ContainsKey(status.ownerName))
                    playerStatus[status.ownerName] = status;
                else
                    playerStatus.Add(status.ownerName, status);
            }
            if (!vessel_update.id.Equals(Guid.Empty) && !docking)
            {
                //Update vessel privacy locks
                if (!isInFlight || vessel_update.id != FlightGlobals.ActiveVessel.id)
                {
                    serverVessels_InUse[vessel_update.id] = vessel_update.state == State.ACTIVE;
                    serverVessels_IsPrivate[vessel_update.id] = vessel_update.isPrivate;
                    serverVessels_IsMine[vessel_update.id] = vessel_update.isMine;
                    KMPClientMain.DebugLog("status flags updated: " + (vessel_update.state == State.ACTIVE) + " " + vessel_update.isPrivate + " " + vessel_update.isMine);
                    if (vessel_update.situation == Situation.DESTROYED)
                    {
                        KMPClientMain.DebugLog("killing vessel");
                        Vessel extant_vessel = FlightGlobals.Vessels.Find(v => v.id == vessel_update.id);
                        if (extant_vessel != null && !extant_vessel.isEVA) try { extant_vessel.Die(); } catch {}
                        return;
                    }
                }

                //Store protovessel if included
                if (vessel_update.getProtoVesselNode() != null && (!isInFlight || vessel_update.id != FlightGlobals.ActiveVessel.id)) serverVessels_ProtoVessels[vessel_update.id] = vessel_update.getProtoVesselNode();
            }
            if (isInFlightOrTracking)
            {
                if (vessel_update.id != FlightGlobals.ActiveVessel.id)
                {
                    KMPClientMain.DebugLog("retrieving vessel: " + vessel_update.id.ToString());
                    if (!vessel_update.id.Equals(Guid.Empty))
                    {
                        Vessel extant_vessel = vessel.vesselRef;
                        if (extant_vessel == null) extant_vessel = FlightGlobals.Vessels.Find(v => v.id == vessel_update.id);
                        if (isInFlight)
                        {
                            if (extant_vessel != null && vessel_update.state == State.ACTIVE && !vessel_update.isSyncOnlyUpdate)
                            {
                                 extant_vessel.name = vessel_update.name + " <" + vessel_update.player + ">";
                                 extant_vessel.vesselName = vessel_update.name + " <" + vessel_update.player + ">";
                            }
                            else if (extant_vessel != null)
                            {
                                extant_vessel.name = vessel_update.name;
                                extant_vessel.vesselName = vessel_update.name;
                            }
                        }
                        if (!serverVessels_LoadDelay.ContainsKey(vessel_update.id)
                            || (serverVessels_LoadDelay.ContainsKey(vessel_update.id) ? (serverVessels_LoadDelay[vessel_update.id] < UnityEngine.Time.realtimeSinceStartup) : false))
                        {
                            float incomingDistance = 2500f;
                            if (!syncing && vessel.worldPosition != Vector3.zero && vessel_update.relTime == RelativeTime.PRESENT)
                                incomingDistance = Vector3.Distance(vessel.worldPosition,FlightGlobals.ship_position);
                            if (vessel_update.relTime != RelativeTime.PRESENT) incomingDistance = 3000f; //Never treat vessels from another time as close by
                         	if (vessel_update.state == State.ACTIVE
                                    || vessel_update.isDockUpdate
                                    || (incomingDistance > vessel_update.distance
                                        && (serverVessels_LastUpdateDistanceTime.ContainsKey(vessel_update.id) ? (serverVessels_LastUpdateDistanceTime[vessel_update.id].Key > vessel_update.distance || serverVessels_LastUpdateDistanceTime[vessel_update.id].Value < Planetarium.GetUniversalTime()): true)))
                            {
                                serverVessels_LastUpdateDistanceTime[vessel_update.id] = new KeyValuePair<double, double>(vessel_update.distance,Planetarium.GetUniversalTime() + 0.75f);
                                if (extant_vessel != null)
                                {
                                    KMPClientMain.DebugLog("vessel found: " + extant_vessel.id);
                                    if (extant_vessel.vesselType != VesselType.Flag) //Special treatment for flags
                                    {
                                        vessel.vesselRef = extant_vessel;
                                        float ourDistance = 3000f;
                                        if (!extant_vessel.loaded)
                                        {
                                            if (KMPVessel.situationIsOrbital(vessel_update.situation))
                                                ourDistance = Vector3.Distance(extant_vessel.orbit.getPositionAtUT(Planetarium.GetUniversalTime()), FlightGlobals.ship_position);
                                            else ourDistance = Vector3.Distance(oldPosition, FlightGlobals.ship_position);
                                        }
                                        else ourDistance = Vector3.Distance(extant_vessel.GetWorldPos3D(), FlightGlobals.ship_position);
                                        bool countMismatch = false;
                                        ProtoVessel protovessel = null;
                                        if (serverVessels_ProtoVessels.ContainsKey(vessel_update.id))
                                        {
                                            protovessel = new ProtoVessel(serverVessels_ProtoVessels[vessel_update.id], HighLogic.CurrentGame);
                                        }
                                        if (serverVessels_PartCounts.ContainsKey(vessel_update.id))
                                        {
                                            //countMismatch = serverVessels_PartCounts[vessel_update.id] > 0 && extant_vessel.loaded && !extant_vessel.packed && serverVessels_PartCounts[vessel_update.id] != protovessel.protoPartSnapshots.Count;
                                            countMismatch = serverVessels_PartCounts[vessel_update.id] > 0 && serverVessels_PartCounts[vessel_update.id] != protovessel.protoPartSnapshots.Count;
                                        }
                                        if ((vessel_update.getProtoVesselNode() != null && (!KMPVessel.situationIsOrbital(vessel_update.situation) || ourDistance > 2500f || extant_vessel.altitude < 10000d)) || countMismatch)
                                        {
                                            KMPClientMain.DebugLog("updating from protovessel");
                                            serverVessels_PartCounts[vessel_update.id] = 0;
                                            if (protovessel != null)
                                            {
                                                if (vessel.orbitValid && KMPVessel.situationIsOrbital(vessel_update.situation) && protovessel.altitude > 10000f && protovessel.vesselType != VesselType.Flag && protovessel.vesselType != VesselType.EVA)
                                                {
                                                    protovessel = syncOrbit(vessel, vessel_update.tick, protovessel, vessel_update.w_pos[0]);
                                                }
                                                addRemoteVessel(protovessel, vessel_update.id, vessel_update, incomingDistance);
                                                if (vessel_update.situation == Situation.FLYING) serverVessels_LoadDelay[vessel.id] = UnityEngine.Time.realtimeSinceStartup + 5f;
                                            } else { KMPClientMain.DebugLog("Protovessel missing!"); }
                                        }
                                        else
                                        {
                                            KMPClientMain.DebugLog("no protovessel");
                                            if (vessel.orbitValid && !extant_vessel.isActiveVessel)
                                            {
                                                KMPClientMain.DebugLog("updating from flight data, distance: " + ourDistance);
                                                //Update orbit to our game's time if necessary
                                                //bool throttled = serverVessels_ObtSyncDelay.ContainsKey(vessel_update.id) && serverVessels_ObtSyncDelay[vessel_update.id] > UnityEngine.Time.realtimeSinceStartup;
                                                bool throttled = false;
                                                if (KMPVessel.situationIsOrbital(vessel_update.situation) && extant_vessel.altitude > 10000f)
                                                {
                                                    double tick = Planetarium.GetUniversalTime();
                                                    //Update orbit whenever out of sync or other vessel in past/future, or not in docking range
                                                    if (!throttled && (vessel_update.relTime == RelativeTime.PRESENT && ourDistance > (INACTIVE_VESSEL_RANGE+500f)) || (vessel_update.relTime != RelativeTime.PRESENT && Math.Abs(tick-vessel_update.tick) > 1.5d))
                                                    {
                                                        syncExtantVesselOrbit(vessel,vessel_update.tick,extant_vessel,vessel_update.w_pos[0]);
                                                        serverVessels_ObtSyncDelay[vessel_update.id] = UnityEngine.Time.realtimeSinceStartup + 1f;
                                                    }
                                                }

                                                if (FlightGlobals.ActiveVessel.mainBody == update_body && vessel_update.relTime == RelativeTime.PRESENT)
                                                {
                                                    KMPClientMain.DebugLog("full update");
                                                    if (serverVessels_InPresent.ContainsKey(vessel_update.id) ? !serverVessels_InPresent[vessel_update.id] : true)
                                                    {
                                                        serverVessels_InPresent[vessel_update.id] = true;
                                                        foreach (Part part in extant_vessel.Parts)
                                                        {
                                                            part.setOpacity(1f);
                                                        }
                                                    }

                                                    //Update rotation
                                                    if (extant_vessel.loaded)
                                                    {
                                                        extant_vessel.transform.up = vessel.worldDirection;
                                                        Quaternion rot = new Quaternion(vessel_update.rot[0],vessel_update.rot[1],vessel_update.rot[2],vessel_update.rot[3]);
                                                        extant_vessel.SetRotation(rot);
                                                        extant_vessel.angularMomentum = Vector3.zero;
                                                        extant_vessel.VesselSAS.LockHeading(rot);
                                                        extant_vessel.VesselSAS.currentRotation = rot;
                                                        extant_vessel.VesselSAS.SetDampingMode(false);
                                                    }

                                                    if (!KMPVessel.situationIsOrbital(vessel_update.situation) || extant_vessel.altitude < 10000f || ourDistance > 2500f)
                                                    {
                                                        KMPClientMain.DebugLog ("velocity update");
                                                        //Update velocity
                                                        if (extant_vessel.loaded)
                                                        {
                                                            if (update_body.GetAltitude(vessel.worldPosition)<10000d)
                                                            {
                                                                //Set velocity by surface velocity
                                                                Vector3d new_srf_vel = new Vector3d(vessel_update.s_vel[0],vessel_update.s_vel[1],vessel_update.s_vel[2]);
                                                                if (new_srf_vel.sqrMagnitude>1d) extant_vessel.ChangeWorldVelocity((-1 * extant_vessel.srf_velocity) + new_srf_vel);
                                                                else extant_vessel.ChangeWorldVelocity(-0.99f * extant_vessel.srf_velocity);
                                                            }
                                                            else
                                                            {
                                                                //Set velocity by orbit velocity
                                                                Vector3d new_obt_vel = new Vector3d(vessel_update.o_vel[0],vessel_update.o_vel[1],vessel_update.o_vel[2]);
                                                                if (new_obt_vel.sqrMagnitude>1d) extant_vessel.ChangeWorldVelocity((-1 * extant_vessel.obt_velocity) + new_obt_vel);
                                                                else extant_vessel.ChangeWorldVelocity(-0.99f * extant_vessel.obt_velocity);
                                                            }
                                                        }

                                                        //Update position
                                                        if (extant_vessel.altitude < 10000f || !extant_vessel.loaded)
                                                        {
                                                            if (extant_vessel.loaded && (vessel_update.situation == Situation.LANDED || vessel_update.situation == Situation.SPLASHED))
                                                            {
                                                                //Update surface position
                                                                KMPClientMain.DebugLog("surface position update");
                                                                Vector3d newPos = update_body.GetWorldSurfacePosition(vessel_update.w_pos[1],vessel_update.w_pos[2],extant_vessel.altitude+0.001d);
                                                                if ((newPos - extant_vessel.GetWorldPos3D()).sqrMagnitude > 1d)
                                                                    extant_vessel.SetPosition(newPos);
                                                                else if (Vector3.Distance(vessel.worldPosition, extant_vessel.GetWorldPos3D()) > 25f)
                                                                {
                                                                    serverVessels_PartCounts[vessel_update.id] = 0;
                                                                    addRemoteVessel(protovessel,vessel_update.id,vessel_update);
                                                                }
                                                            }
                                                            else if (!throttled && Vector3.Distance(vessel.worldPosition, extant_vessel.GetWorldPos3D()) > 1d
                                                                     && (extant_vessel.altitude < 10000f || ourDistance > 3000f)
                                                                     && update_body.GetAltitude(vessel.worldPosition) > 1d)
                                                            {
                                                                //Update 3D position
                                                                KMPClientMain.DebugLog("position update");
                                                                extant_vessel.SetPosition(vessel.worldPosition);
                                                            }
                                                            else if (!extant_vessel.loaded && ourDistance > 1000 && update_body.GetAltitude(vessel.worldPosition) > 1d)
                                                            {
                                                                //Stretch packing thresholds to prevent excessive load/unloads during rendezvous initiation
                                                                extant_vessel.distancePackThreshold += 250f;
                                                                extant_vessel.distanceUnpackThreshold += 100f;
                                                            } else
                                                            {
                                                                //Reset packing thresholds
                                                                extant_vessel.distancePackThreshold = 7500f;
                                                                extant_vessel.distanceUnpackThreshold = 1000f;
                                                            }
                                                        }

                                                        //Update FlightCtrlState
                                                        extant_vessel.ctrlState.CopyFrom(vessel_update.flightCtrlState.getAsFlightCtrlState(0.75f));
                                                    }
                                                    else
                                                    {
                                                        //Orbital rendezvous
                                                        KMPClientMain.DebugLog("orbital rendezvous");

                                                        //Update FlightCtrlState
                                                        extant_vessel.ctrlState.CopyFrom(vessel_update.flightCtrlState.getAsFlightCtrlState(0.6f));
                                                    }
                                                }
                                                else if (FlightGlobals.ActiveVessel.mainBody == vessel.mainBody)
                                                {
                                                    KMPClientMain.DebugLog("update from past/future");

                                                    if (!serverVessels_InPresent.ContainsKey(vessel_update.id) || serverVessels_InPresent.ContainsKey(vessel_update.id) ? serverVessels_InPresent[vessel_update.id]: false)
                                                    {
                                                        serverVessels_InPresent[vessel_update.id] = false;
                                                        foreach (Part part in extant_vessel.Parts)
                                                        {
                                                            part.setOpacity(0.3f);
                                                        }
                                                    }

                                                    //Update rotation only
                                                    extant_vessel.transform.up = vessel.worldDirection;
                                                    extant_vessel.SetRotation(new Quaternion(vessel_update.rot[0],vessel_update.rot[1],vessel_update.rot[2],vessel_update.rot[3]));
                                                }
                                            }
                                        }
                                        KMPClientMain.DebugLog("updated");
                                    }
                                    else
                                    {
                                        //Update flag if needed
                                        if (vessel_update.getProtoVesselNode() != null)
                                        {
                                            ProtoVessel protovessel = new ProtoVessel(serverVessels_ProtoVessels[vessel_update.id], HighLogic.CurrentGame);
                                            addRemoteVessel(protovessel,vessel_update.id,vessel_update);
                                        }
                                    }
                                }
                                else
                                {
                                    try
                                    {
                                        if (serverVessels_ProtoVessels.ContainsKey(vessel_update.id))
                                        {
                                            KMPClientMain.DebugLog("Adding new vessel: " + vessel_update.id);
                                            ProtoVessel protovessel = new ProtoVessel(serverVessels_ProtoVessels[vessel_update.id], HighLogic.CurrentGame);
                                            if (vessel.orbitValid && KMPVessel.situationIsOrbital(vessel_update.situation) && protovessel.vesselType != VesselType.Flag && protovessel.vesselType != VesselType.EVA)
                                            {
                                                protovessel = syncOrbit(vessel, vessel_update.tick, protovessel, vessel_update.w_pos[0]);
                                            }
                                            serverVessels_PartCounts[vessel_update.id] = 0;
                                            addRemoteVessel(protovessel, vessel_update.id, vessel_update, incomingDistance);
                                            HighLogic.CurrentGame.CrewRoster.ValidateAssignments(HighLogic.CurrentGame);
                                        }
                                        else
                                        {
                                            KMPClientMain.DebugLog("New vessel, but no matching protovessel available");
                                        }
                                    } catch (Exception e) { KMPClientMain.DebugLog("Vessel add error: " + e.Message + "\n" + e.StackTrace); }
                                }
                            }
                            else
                            {
                                KMPClientMain.DebugLog("Vessel update ignored: we are closer to target vessel or have recently updated from someone who was closer");
                            }
                        }
                        else
                        {
                            KMPClientMain.DebugLog("Vessel update ignored: target vessel on load delay list");
                        }
                    }
                }
                else
                {
                    //This is our vessel!
                    if (vessel_update.getProtoVesselNode() != null && docking)
                    {
                        KMPClientMain.DebugLog("Received updated protovessel for active vessel");
                        serverVessels_ProtoVessels[vessel_update.id] = vessel_update.getProtoVesselNode();
                    }

                    if (vessel_update.isDockUpdate && vessel_update.relTime == RelativeTime.PRESENT)
                    {
                        //Someone docked with us and has control
                        docking = true;
                        syncing = true;
                        ScreenMessages.PostScreenMessage("Other player has control of newly docked vessel",2.5f,ScreenMessageStyle.UPPER_LEFT);
                        KMPClientMain.DebugLog("Received docking update");
                        serverVessels_PartCounts[FlightGlobals.ActiveVessel.id] = 0;

                        //Return to tracking station
                        Invoke("dockedKickToTrackingStation",0.25f);
                        return;
                    }
                    //Try to negotiate our relative position with whatever sent this update
                    if (FlightGlobals.ActiveVessel.altitude > 10000d && vessel_update.relativeTo != Guid.Empty && Math.Abs(Planetarium.GetUniversalTime() - vessel_update.tick) < 2d)
                    {
                        Vessel updateFrom = FlightGlobals.Vessels.Find (v => v.id == vessel_update.relativeTo);
                        if (updateFrom != null && !updateFrom.loaded)
                        {
                            KMPClientMain.DebugLog("Rendezvous update from unloaded vessel");
                            if (vessel_update.distance < INACTIVE_VESSEL_RANGE)
                            {
                                //We're not in normal secondary vessel range but other vessel is, send negotiating reply
                                KMPVesselUpdate update = getVesselUpdate(updateFrom);
                                update.distance = INACTIVE_VESSEL_RANGE;
                                update.state = State.INACTIVE;
                                //Rendezvous relative position data
                                update.relativeTo = FlightGlobals.ActiveVessel.id;
                                Vector3d w_pos = updateFrom.findWorldCenterOfMass() - activeVesselPosition;
                                Vector3d o_vel = updateFrom.GetObtVelocity() - FlightGlobals.ActiveVessel.GetObtVelocity();
                                for (int i = 0; i < 3; i++)
                                {
                                    update.w_pos[i] = w_pos[i];
                                    update.o_vel[i] = o_vel[i];
                                }

                                byte[] update_bytes = KSP.IO.IOUtils.SerializeToBinary(update);
                                enqueuePluginInteropMessage(KMPCommon.PluginInteropMessageID.SECONDARY_PLUGIN_UPDATE, update_bytes);

                                //updateFrom.distancePackThreshold += INACTIVE_VESSEL_RANGE/2;
                            }
                        }
                        else if (updateFrom != null && updateFrom.loaded)
                        {
                            KMPClientMain.DebugLog("rendezvous positioning: " + updateFrom.id);

                            Vector3d updateFromPos = updateFrom.findWorldCenterOfMass();
                            Vector3d relPos = activeVesselPosition-updateFromPos;
                            Vector3d updateRelPos = new Vector3d(vessel_update.w_pos[0],vessel_update.w_pos[1],vessel_update.w_pos[2]);

                            if (!dockingRelVel.ContainsKey(updateFrom.id))
                                dockingRelVel[updateFrom.id] = updateFrom.GetObtVelocity();

                            Vector3d relVel = FlightGlobals.ActiveVessel.GetObtVelocity()-dockingRelVel[updateFrom.id];
                            Vector3d updateRelVel = new Vector3d(vessel_update.o_vel[0],vessel_update.o_vel[1],vessel_update.o_vel[2]);
                            Vector3d diffPos = updateRelPos - relPos;
                            Vector3d diffVel = updateRelVel - relVel;
                            diffPos *= 0.45d;
                            diffVel *= 0.45d;
                            Vector3d newPos = updateFromPos-diffPos;

                            bool applyUpdate = true;
                            double curTick = Planetarium.GetUniversalTime();
                            if (serverVessels_RendezvousSmoothPos.ContainsKey(updateFrom.id) ? (relPos.sqrMagnitude > (serverVessels_RendezvousSmoothPos[updateFrom.id].Key * 25) && serverVessels_RendezvousSmoothPos[updateFrom.id].Value > (curTick-5d)): false)
                                applyUpdate = false;
                            if (serverVessels_RendezvousSmoothVel.ContainsKey(updateFrom.id) ? (relVel.sqrMagnitude > (serverVessels_RendezvousSmoothVel[updateFrom.id].Key * 25) && serverVessels_RendezvousSmoothVel[updateFrom.id].Value > (curTick-5d)): false)
                                applyUpdate = false;

                            double expectedDist = Vector3d.Distance(newPos, activeVesselPosition);

                            if (applyUpdate)
                            {
                                serverVessels_RendezvousSmoothPos[updateFrom.id] = new KeyValuePair<double, double>(diffPos.sqrMagnitude,curTick);
                                serverVessels_RendezvousSmoothVel[updateFrom.id] = new KeyValuePair<double, double>(diffVel.sqrMagnitude,curTick);

                                try
                                {
                                    OrbitPhysicsManager.HoldVesselUnpack(1);
                                }
                                catch (NullReferenceException)
                                {
                                }

                                if (diffPos.sqrMagnitude < 1000000d && diffPos.sqrMagnitude > 0.5d)
                                {
                                    KMPClientMain.DebugLog("Docking Krakensbane shift");
                                    foreach (Vessel otherVessel in FlightGlobals.Vessels.Where(v => v.packed == false && v.id != FlightGlobals.ActiveVessel.id && v.id == updateFrom.id))
                                        otherVessel.GoOnRails();
                                    getKrakensbane().setOffset(diffPos);
                                }
                                else if (diffPos.sqrMagnitude >= 1000000d)
                                {
                                    KMPClientMain.DebugLog("Clamped docking Krakensbane shift");
                                    diffPos.Normalize();
                                    diffPos *= 1000d;
                                    foreach (Vessel otherVessel in FlightGlobals.Vessels.Where(v => v.packed == false && v.id != FlightGlobals.ActiveVessel.id))
                                        otherVessel.GoOnRails();
                                    getKrakensbane().setOffset(diffPos);
                                }

                                activeVesselPosition += diffPos;

                                if (diffVel.sqrMagnitude > 0.0025d && diffVel.sqrMagnitude < 2500d)
                                {
                                    KMPClientMain.DebugLog("Docking velocity update");
                                    if (updateFrom.packed) updateFrom.GoOffRails();
                                    updateFrom.ChangeWorldVelocity(-diffVel);
                                }
                                else if (diffVel.sqrMagnitude >= 2500d)
                                {
                                    KMPClientMain.DebugLog("Damping large velocity differential");
                                    diffVel = diffVel.normalized;
                                    diffVel *= 50d;
                                    if (updateFrom.packed) updateFrom.GoOffRails();
                                    updateFrom.ChangeWorldVelocity(-diffVel);
                                }

                                dockingRelVel[updateFrom.id] -= diffVel;

                                KMPClientMain.DebugLog("had dist:" + relPos.magnitude + " got dist:" + updateRelPos.magnitude);
                                KMPClientMain.DebugLog("expected dist:" + expectedDist + " diffPos mag: " + diffPos.sqrMagnitude);
                                KMPClientMain.DebugLog("had relVel:" + relVel.magnitude + " got relVel:" + updateRelVel.magnitude + " diffVel mag:" + diffVel.sqrMagnitude);
                            }
                        }  else KMPClientMain.DebugLog("Ignored docking position update: unexpected large pos/vel shift");
                    } else KMPClientMain.DebugLog("Ignored docking position update: " + (FlightGlobals.ActiveVessel.altitude > 10000d) + " " + (vessel_update.relativeTo != Guid.Empty) + " " + (Math.Abs(Planetarium.GetUniversalTime() - vessel_update.tick) < 1d));
                }
            }
        }
Example #4
0
        private KMPVesselUpdate getVesselUpdate(Vessel vessel, bool forceFullUpdate = false)
        {
            if (vessel == null || vessel.mainBody == null)
                return null;

            if (vessel.id == Guid.Empty) vessel.id = Guid.NewGuid();

            //Create a KMPVesselUpdate from the vessel data
            KMPVesselUpdate update;
            //KMPClientMain.DebugLog("Vid: " + vessel.id);
            //KMPClientMain.DebugLog("foreFullUpdate: " + forceFullUpdate);
            //KMPClientMain.DebugLog("ParCountsContains: " + serverVessels_PartCounts.ContainsKey(vessel.id));
            //KMPClientMain.DebugLog("TimeDelta: " + ((UnityEngine.Time.realtimeSinceStartup - lastFullProtovesselUpdate) < FULL_PROTOVESSEL_UPDATE_TIMEOUT));
            //KMPClientMain.DebugLog("Throttle: " + (FlightGlobals.ActiveVessel.ctrlState.mainThrottle == 0f));

            //Check for new/forced update
            if (!forceFullUpdate //not a forced update
                && (serverVessels_PartCounts.ContainsKey(vessel.id) ?
                    (vessel.id != FlightGlobals.ActiveVessel.id || (UnityEngine.Time.realtimeSinceStartup - lastFullProtovesselUpdate) < FULL_PROTOVESSEL_UPDATE_TIMEOUT) //not active vessel, or full protovessel timeout hasn't passed
                    : false)) //have a serverVessels_PartCounts entry
            {
                if ((serverVessels_PartCounts.ContainsKey(vessel.id) ? serverVessels_PartCounts[vessel.id] == vessel.Parts.Count : false) //Part count is the same
                    && (sentVessels_Situations.ContainsKey(vessel.id) ? (sentVessels_Situations[vessel.id] == vessel.situation) : false)) //Situation hasn't changed
                {
                    if (!newFlags.ContainsKey(vessel.id))	//Not an un-updated flag
                        update = new KMPVesselUpdate(vessel,false);
                    else if ((UnityEngine.Time.realtimeSinceStartup - newFlags[vessel.id]) < 65f) //Is a flag, but plaque timeout hasn't expired
                        update = new KMPVesselUpdate(vessel,false);
                    else //Is a flag, plaque timeout has expired so grab full update
                    {
                        update = new KMPVesselUpdate(vessel);
                        newFlags.Remove(vessel.id);
                    }

                }
                else
                {
                    //Vessel has changed
                    KMPClientMain.DebugLog("Full update: " + vessel.id);
                    update = new KMPVesselUpdate(vessel);
                    serverVessels_PartCounts[vessel.id] = vessel.Parts.Count;
                }
            }
            else
            {
                //New vessel or forced protovessel update
                update = new KMPVesselUpdate(vessel);
                if (vessel.id == FlightGlobals.ActiveVessel.id)
                {
                    KMPClientMain.DebugLog("First or forced proto update for active vessel: " + vessel.id);
                    lastFullProtovesselUpdate = UnityEngine.Time.realtimeSinceStartup;
                }
                if (!vessel.packed) serverVessels_PartCounts[vessel.id] = vessel.Parts.Count;
            }

            //Track vessel situation
            sentVessels_Situations[vessel.id] = vessel.situation;

            //Set privacy lock
            if (serverVessels_IsPrivate.ContainsKey(vessel.id)) update.isPrivate = serverVessels_IsPrivate[vessel.id];

            if (vessel.vesselName.Length <= MAX_VESSEL_NAME_LENGTH)
                update.name = vessel.vesselName;
            else
                update.name = vessel.vesselName.Substring(0, MAX_VESSEL_NAME_LENGTH);

            update.player = playerName;
            update.id = vessel.id;
            update.tick = Planetarium.GetUniversalTime();
            update.crewCount = vessel.GetCrewCount();

            if (serverVessels_RemoteID.ContainsKey(vessel.id)) update.kmpID = serverVessels_RemoteID[vessel.id];
            else
            {
                KMPClientMain.DebugLog("Generating new remote ID for vessel: " + vessel.id);
                Guid server_id = Guid.NewGuid();
                serverVessels_RemoteID[vessel.id] = server_id;
                update.kmpID = server_id;
                if (vessel.vesselType == VesselType.Flag)
                {
                    newFlags[vessel.id] = UnityEngine.Time.realtimeSinceStartup;
                }
            }

            Vector3 pos = vessel.mainBody.transform.InverseTransformPoint(vessel.GetWorldPos3D());
            Vector3 dir = vessel.mainBody.transform.InverseTransformDirection(vessel.transform.up);
            Vector3 vel = vessel.mainBody.transform.InverseTransformDirection(vessel.GetObtVelocity());
            Vector3d o_vel = vessel.obt_velocity;
            Vector3d s_vel = vessel.srf_velocity;
            Quaternion rot = vessel.transform.rotation;

            for (int i = 0; i < 3; i++)
            {
                update.pos[i] = pos[i];
                update.dir[i] = dir[i];
                update.vel[i] = vel[i];
                update.o_vel[i] = o_vel[i];
                update.s_vel[i] = s_vel[i];
            }
            for (int i = 0; i < 4; i++)
            {
                update.rot[i] = rot[i];
            }
            update.w_pos[0] = vessel.orbit.LAN;
            if (vessel.situation == Vessel.Situations.LANDED || vessel.situation == Vessel.Situations.SPLASHED)
            {
                update.w_pos[1] = vessel.latitude;
                update.w_pos[2] = vessel.longitude;
            }

            //Determine situation
            if ((vessel.loaded && vessel.GetTotalMass() <= 0.0) || (vessel.vesselType == VesselType.Debris && vessel.situation == Vessel.Situations.SUB_ORBITAL))
                update.situation = Situation.DESTROYED;
            else
            {
                switch (vessel.situation)
                {

                    case Vessel.Situations.LANDED:
                        update.situation = Situation.LANDED;
                        break;

                    case Vessel.Situations.SPLASHED:
                        update.situation = Situation.SPLASHED;
                        break;

                    case Vessel.Situations.PRELAUNCH:
                        update.situation = Situation.PRELAUNCH;
                        break;

                    case Vessel.Situations.SUB_ORBITAL:
                        if (vessel.orbit.timeToAp < vessel.orbit.period / 2.0)
                            update.situation = Situation.ASCENDING;
                        else
                            update.situation = Situation.DESCENDING;
                        break;

                    case Vessel.Situations.ORBITING:
                        update.situation = Situation.ORBITING;
                        break;

                    case Vessel.Situations.ESCAPING:
                        if (vessel.orbit.timeToPe > 0.0)
                            update.situation = Situation.ENCOUNTERING;
                        else
                            update.situation = Situation.ESCAPING;
                        break;

                    case Vessel.Situations.DOCKED:
                        update.situation = Situation.DOCKED;
                        break;

                    case Vessel.Situations.FLYING:
                        update.situation = Situation.FLYING;
                        break;

                    default:
                        update.situation = Situation.UNKNOWN;
                        break;

                }
            }

            if (vessel == FlightGlobals.ActiveVessel)
            {
                update.state = State.ACTIVE;

                //Set vessel details since it's the active vessel
                update.detail = getVesselDetail(vessel);
            }
            else if (vessel.isCommandable)
                update.state = State.INACTIVE;
            else
                update.state = State.DEAD;

            update.timeScale = (float)Planetarium.TimeScale;
            update.bodyName = vessel.mainBody.bodyName;

            return update;
        }
Example #5
0
        private IEnumerator<WaitForFixedUpdate> loadProtovessel(Vessel oldVessel, Vector3 newWorldPos, Vector3 newOrbitVel, bool wasLoaded, bool wasActive, bool setTarget, ProtoVessel protovessel, Guid vessel_id, KMPVessel kvessel, KMPVesselUpdate update, double distance)
        {
            yield return new WaitForFixedUpdate();
            Log.Debug("Loading protovessel: {0}", vessel_id.ToString() + ", name: " + protovessel.vesselName + ", type: " + protovessel.vesselType);
            if (oldVessel != null && !wasActive)
            {
                killVessel(oldVessel);
            }
            serverVessels_LoadDelay[vessel_id] = UnityEngine.Time.realtimeSinceStartup + 5f;
            serverVessels_PartCounts[vessel_id] = protovessel.protoPartSnapshots.Count;
            protovessel.Load(HighLogic.CurrentGame.flightState);
            Vessel created_vessel = protovessel.vesselRef;

            if (created_vessel != null)
            {
                try
                {
                    OrbitPhysicsManager.HoldVesselUnpack(1);
                }
                catch (NullReferenceException e)
                {
                    Log.Debug("Exception thrown in loadProtovessel(), catch 1, Exception: {0}", e.ToString());
                }

                Log.Debug(created_vessel.id.ToString() + " initializing: ProtoParts=" + protovessel.protoPartSnapshots.Count + ",Parts=" + created_vessel.Parts.Count + ",Sit=" + created_vessel.situation.ToString() + ",type=" + created_vessel.vesselType + ",alt=" + protovessel.altitude);

                //vessels[vessel_id.ToString()].vessel.vesselRef = created_vessel;
                serverVessels_PartCounts[vessel_id] = created_vessel.Parts.Count;
                serverVessels_Parts[vessel_id] = new List<Part>();
                serverVessels_Parts[vessel_id].AddRange(created_vessel.Parts);

                if (created_vessel.vesselType != VesselType.Flag && created_vessel.vesselType != VesselType.EVA)
                {
                    foreach (Part part in created_vessel.Parts)
                    {
                        part.OnLoad();
                        part.OnJustAboutToBeDestroyed += checkRemoteVesselIntegrity;
                        part.explosionPotential = 0;
                        part.terrainCollider = new PQS_PartCollider();
                        part.terrainCollider.part = part;
                        part.terrainCollider.useVelocityCollider = false;
                        part.terrainCollider.useGravityCollider = false;
                        part.breakingForce = float.MaxValue;
                        part.breakingTorque = float.MaxValue;
                    }
                    if (update == null || (update != null && update.bodyName == FlightGlobals.ActiveVessel.mainBody.name))
                    {
                        Log.Debug("update included");

                        if (update == null || (update.relTime == RelativeTime.PRESENT))
                        {
                            if (newWorldPos != Vector3.zero)
                            {
                                Log.Debug("repositioning");
                                created_vessel.transform.position = newWorldPos;
                            }
                            if (newOrbitVel != Vector3.zero)
                            {
                                Log.Debug("updating velocity");
                                created_vessel.ChangeWorldVelocity((-1 * created_vessel.GetObtVelocity()) + (new Vector3(newOrbitVel.x, newOrbitVel.z, newOrbitVel.y))); //xzy?
                            }
                            StartCoroutine(restoreVesselState(created_vessel, newWorldPos, newOrbitVel));
                            //Update FlightCtrlState
                            if (update != null)
                            {
                                if (created_vessel.ctrlState == null)
                                    created_vessel.ctrlState = new FlightCtrlState();
                                created_vessel.ctrlState.CopyFrom(update.flightCtrlState.getAsFlightCtrlState(0.75f));
                            }
                        }
                        else
                        {
                            StartCoroutine(setNewVesselNotInPresent(created_vessel));
                        }
                    }
                }
                if (setTarget)
                    StartCoroutine(setDockingTarget(created_vessel));
                if (wasActive)
                    StartCoroutine(setActiveVessel(created_vessel, oldVessel));
                Log.Debug(created_vessel.id.ToString() + " initialized");
            }
            else
            {
                Log.Debug("Failed to create vessel " + vessel_id);
            }
        }
Example #6
0
        private KMPVesselUpdate getVesselUpdate(Vessel vessel, bool forceFullUpdate = false, bool idOnlyUpdate = false)
        {
            if (vessel == null || vessel.mainBody == null)
                return null;

            if (vessel.id == Guid.Empty) vessel.id = Guid.NewGuid();

            //Create a KMPVesselUpdate from the vessel data
            KMPVesselUpdate update;
            //Log.Debug("Vid: " + vessel.id);
            //Log.Debug("foreFullUpdate: " + forceFullUpdate);
            //Log.Debug("ParCountsContains: " + serverVessels_PartCounts.ContainsKey(vessel.id));
            //Log.Debug("TimeDelta: " + ((UnityEngine.Time.realtimeSinceStartup - lastFullProtovesselUpdate) < FULL_PROTOVESSEL_UPDATE_TIMEOUT));
            //Log.Debug("Throttle: " + (FlightGlobals.ActiveVessel.ctrlState.mainThrottle == 0f));

            //Ensure privacy protections don't affect server's version of vessel
            foreach (Part part in vessel.Parts)
            {
                if ((serverParts_CrewCapacity.ContainsKey(part.uid) ? serverParts_CrewCapacity[part.uid] : 0) != 0)
                {
                    part.CrewCapacity = serverParts_CrewCapacity[part.uid];
                }
                foreach (PartModule module in part.Modules)
                {
                    if (module is ModuleDockingNode)
                    {
                        ModuleDockingNode dmodule = (ModuleDockingNode) module;
                        float absCaptureRange = Math.Abs(dmodule.captureRange);
                        dmodule.captureRange = absCaptureRange;
                        dmodule.isEnabled = true;
                    }
                    if (module is ModuleGrappleNode)
                    {
                        ModuleGrappleNode gmodule = (ModuleGrappleNode) module;
                        float absCaptureRange = Math.Abs(gmodule.captureRange);
                        gmodule.captureRange = absCaptureRange;
                        gmodule.isEnabled = true;
                    }
                }
            }

            if (idOnlyUpdate)
            {
                update = new KMPVesselUpdate(vessel,false);
            }
            //Check for new/forced update
            else if (!forceFullUpdate //not a forced update
                && !docking //not in the middle of a docking event
                && (serverVessels_PartCounts.ContainsKey(vessel.id) ?
                    ((isInFlight ? vessel.id != FlightGlobals.ActiveVessel.id : true) || (UnityEngine.Time.realtimeSinceStartup - lastFullProtovesselUpdate) < FULL_PROTOVESSEL_UPDATE_TIMEOUT) //not active vessel, or full protovessel timeout hasn't passed
                    : false)) //have a serverVessels_PartCounts entry
            {
                if ((serverVessels_PartCounts.ContainsKey(vessel.id) ? serverVessels_PartCounts[vessel.id] == vessel.Parts.Count : false) //Part count is the same
                    && (sentVessels_Situations.ContainsKey(vessel.id) ? (sentVessels_Situations[vessel.id] == vessel.situation) : false)) //Situation hasn't changed
                {
                    if (!newFlags.ContainsKey(vessel.id))	//Not an un-updated flag
                        update = new KMPVesselUpdate(vessel,false);
                    else if ((UnityEngine.Time.realtimeSinceStartup - newFlags[vessel.id]) < 65f) //Is a flag, but plaque timeout hasn't expired
                        update = new KMPVesselUpdate(vessel,false);
                    else //Is a flag, plaque timeout has expired so grab full update
                    {
                        update = new KMPVesselUpdate(vessel);
                        newFlags.Remove(vessel.id);
                    }

                }
                else
                {
                    //Vessel has changed
                    Log.Debug("Full update: " + vessel.id);
                    update = new KMPVesselUpdate(vessel);
                    serverVessels_PartCounts[vessel.id] = vessel.Parts.Count;
                }
            }
            else
            {
                //New vessel or forced protovessel update
                update = new KMPVesselUpdate(vessel);
                if (isInFlight && vessel.id == FlightGlobals.ActiveVessel.id)
                {
                    Log.Debug("First or forced proto update for active vessel: " + vessel.id);
                    lastFullProtovesselUpdate = UnityEngine.Time.realtimeSinceStartup;
                }
                if (!vessel.packed) serverVessels_PartCounts[vessel.id] = vessel.Parts.Count;
            }

            if (isInSafetyBubble(vessel.GetWorldPos3D(),vessel.mainBody,vessel.altitude)) update.clearProtoVessel();

            //Track vessel situation
            sentVessels_Situations[vessel.id] = vessel.situation;

            //Set privacy lock
            if (serverVessels_IsPrivate.ContainsKey(vessel.id)) update.isPrivate = serverVessels_IsPrivate[vessel.id];
            else update.isPrivate = false;

            if (vessel.vesselName.Length <= MAX_VESSEL_NAME_LENGTH)
                update.name = vessel.vesselName;
            else
                update.name = vessel.vesselName.Substring(0, MAX_VESSEL_NAME_LENGTH);

            update.player = playerName;
            update.id = vessel.id;
            update.tick = Planetarium.GetUniversalTime();

            if (serverVessels_RemoteID.ContainsKey(vessel.id)) update.kmpID = serverVessels_RemoteID[vessel.id];
            else
            {
                Log.Debug("Generating new remote ID for vessel: " + vessel.id);
                Guid server_id = Guid.NewGuid();
                serverVessels_RemoteID[vessel.id] = server_id;
                update.kmpID = server_id;
                if (vessel.vesselType == VesselType.Flag)
                {
                    newFlags[vessel.id] = UnityEngine.Time.realtimeSinceStartup;
                }
            }

            if (idOnlyUpdate) return update;

            update.crewCount = vessel.GetCrewCount();

            Vector3 pos = vessel.mainBody.transform.InverseTransformPoint(vessel.GetWorldPos3D());
            Vector3 dir = vessel.mainBody.transform.InverseTransformDirection(vessel.transform.up);
            Vector3 vel = vessel.mainBody.transform.InverseTransformDirection(vessel.GetObtVelocity());
            Vector3d o_vel = vessel.obt_velocity;
            Vector3d s_vel = vessel.srf_velocity;
            Vector3 forw = vessel.mainBody.transform.InverseTransformDirection(vessel.transform.forward);

            for (int i = 0; i < 3; i++)
            {
                update.pos[i] = pos[i];
                update.dir[i] = dir[i];
                update.vel[i] = vel[i];
                update.o_vel[i] = o_vel[i];
                update.s_vel[i] = s_vel[i];
                update.rot[i] = forw[i];
            }

            update.w_pos[0] = vessel.orbit.LAN;
            if (vessel.situation == Vessel.Situations.LANDED || vessel.situation == Vessel.Situations.SPLASHED)
            {
                update.w_pos[1] = vessel.latitude;
                update.w_pos[2] = vessel.longitude;
            }

            //Determine situation
            if ((vessel.loaded && vessel.GetTotalMass() <= 0.0) || (vessel.vesselType == VesselType.Debris && vessel.situation == Vessel.Situations.SUB_ORBITAL))
                update.situation = Situation.DESTROYED;
            else
            {
                switch (vessel.situation)
                {

                    case Vessel.Situations.LANDED:
                        update.situation = Situation.LANDED;
                        break;

                    case Vessel.Situations.SPLASHED:
                        update.situation = Situation.SPLASHED;
                        break;

                    case Vessel.Situations.PRELAUNCH:
                        update.situation = Situation.PRELAUNCH;
                        break;

                    case Vessel.Situations.SUB_ORBITAL:
                        if (vessel.orbit.timeToAp < vessel.orbit.period / 2.0)
                            update.situation = Situation.ASCENDING;
                        else
                            update.situation = Situation.DESCENDING;
                        break;

                    case Vessel.Situations.ORBITING:
                        update.situation = Situation.ORBITING;
                        break;

                    case Vessel.Situations.ESCAPING:
                        if (vessel.orbit.timeToPe > 0.0)
                            update.situation = Situation.ENCOUNTERING;
                        else
                            update.situation = Situation.ESCAPING;
                        break;

                    case Vessel.Situations.DOCKED:
                        update.situation = Situation.DOCKED;
                        break;

                    case Vessel.Situations.FLYING:
                        update.situation = Situation.FLYING;
                        break;

                    default:
                        update.situation = Situation.UNKNOWN;
                        break;

                }
            }

            if (isInFlight && vessel.id == FlightGlobals.ActiveVessel.id)
            {
                update.state = State.ACTIVE;
                //Set vessel details since it's the active vessel
                update.detail = getVesselDetail(vessel);
            }
            else if (vessel.isCommandable)
                update.state = State.INACTIVE;
            else
            {
                serverVessels_InUse[vessel.id] = false;
                update.state = State.DEAD;
            }

            update.timeScale = (float)Planetarium.TimeScale;
            update.bodyName = vessel.mainBody.bodyName;

            //Reset vessel privacy locks in case they were changed
            checkVesselPrivacy(vessel);

            return update;
        }
Example #7
0
        private void applyVesselUpdate(KMPVesselUpdate vessel_update, KMPVessel vessel)
        {
            if (vessel_update.id.ToString() == SYNC_PLATE_ID)
            {
                Log.Debug("Refusing to update sync plate");
                return;
            }

            serverVessels_RemoteID[vessel_update.id] = vessel_update.kmpID;

            //Find the CelestialBody that matches the one in the update
            CelestialBody update_body = null;
            if (vessel.mainBody != null && vessel.mainBody.bodyName == vessel_update.bodyName)
                update_body = vessel.mainBody; //Vessel already has the correct body
            else
            {
                //Find the celestial body in the list of bodies
                foreach (CelestialBody body in FlightGlobals.Bodies)
                {
                    if (body.bodyName == vessel_update.bodyName)
                    {
                        update_body = body;
                        break;
                    }
                }
            }

            if (!vesselUpdatesLoaded.Contains(vessel_update.id)) //This can be moved elsewhere in addRemoteVessel (or applyVesselUpdate) to help track issues with loading a specific vessel
            {
                vesselUpdatesLoaded.Add(vessel_update.id);
            }

            Vector3 oldPosition = vessel.worldPosition;

            if (update_body != null)
            {
                //Convert float arrays to Vector3s
                Vector3 pos = new Vector3(vessel_update.pos[0], vessel_update.pos[1], vessel_update.pos[2]);
                Vector3 dir = new Vector3(vessel_update.dir[0], vessel_update.dir[1], vessel_update.dir[2]);
                Vector3 vel = new Vector3(vessel_update.vel[0], vessel_update.vel[1], vessel_update.vel[2]);
                vessel.info = vessel_update;
                vessel.setOrbitalData(update_body, pos, vel, dir);
            }

            Log.Debug("vessel state: " + vessel_update.state.ToString() + ", tick=" + vessel_update.tick + ", realTick=" + Planetarium.GetUniversalTime());
            if (vessel_update.state == State.ACTIVE && !vessel_update.isSyncOnlyUpdate && vessel_update.relTime != RelativeTime.FUTURE && !vessel_update.isDockUpdate)
            {
                //Update the player status info
                VesselStatusInfo status = new VesselStatusInfo();
                if (vessel_update.relTime == RelativeTime.PRESENT) status.info = vessel_update;
                status.ownerName = vessel_update.player;
                status.vesselName = vessel_update.name;

                if (vessel.orbitValid)
                    status.orbit = vessel.orbitRenderer.driver.orbit;

                status.lastUpdateTime = UnityEngine.Time.realtimeSinceStartup;
                status.color = KMPVessel.generateActiveColor(status.ownerName);

                if (playerStatus.ContainsKey(status.ownerName))
                    playerStatus[status.ownerName] = status;
                else
                    playerStatus.Add(status.ownerName, status);
            }

            if (!vessel_update.id.Equals(Guid.Empty) && !docking)
            {
                //Update vessel privacy locks
                serverVessels_InUse[vessel_update.id] = vessel_update.state == State.ACTIVE && !vessel_update.isMine && !vessel_update.isSyncOnlyUpdate;
                serverVessels_IsPrivate[vessel_update.id] = vessel_update.isPrivate;
                serverVessels_IsMine[vessel_update.id] = vessel_update.isMine;
                Log.Debug("status flags updated: " + (vessel_update.state == State.ACTIVE) + " " + vessel_update.isSyncOnlyUpdate + " " + vessel_update.isPrivate + " " + vessel_update.isMine);
                if (vessel_update.situation == Situation.DESTROYED && (isInFlight ? vessel_update.id != FlightGlobals.ActiveVessel.id : true))
                {
                    Log.Debug("Vessel reported destroyed, killing vessel");
                    Vessel extant_vessel = FlightGlobals.Vessels.Find(v => v.id == vessel_update.id);
                    if (extant_vessel != null)
                    {
                        try { killVessel(extant_vessel); } catch (Exception e) { Log.Debug("Exception thrown in applyVesselUpdate(), catch 1, Exception: {0}", e.ToString()); }
                    }
                    return;
                }
            }

            //Store protovessel if included
            if (vessel_update.getProtoVesselNode() != null) serverVessels_ProtoVessels[vessel_update.id] = vessel_update.getProtoVesselNode();

            //Apply update if able
            if (isInFlightOrTracking || syncing)
            {
                if (vessel_update.relativeTo == Guid.Empty && (isInFlight && vessel_update.id != FlightGlobals.ActiveVessel.id || (serverVessels_InUse[vessel_update.id] || (serverVessels_IsPrivate[vessel_update.id] && !serverVessels_IsMine[vessel_update.id]))))
                {
                    if (isInFlight && vessel_update.id == FlightGlobals.ActiveVessel.id && vessel_update.relTime == RelativeTime.PAST) {
                        kickToTrackingStation();
                        return;
                    }
                    Log.Debug("retrieving vessel: " + vessel_update.id.ToString());
                    if (!vessel_update.id.Equals(Guid.Empty))
                    {
                        Vessel extant_vessel = vessel.vesselRef;
                        if (extant_vessel == null) extant_vessel = FlightGlobals.Vessels.Find(v => v.id == vessel_update.id);
                        if (isInFlight)
                        {
                            if (extant_vessel != null && vessel_update.state == State.ACTIVE && !vessel_update.isSyncOnlyUpdate)
                            {
                                 extant_vessel.name = vessel_update.name + " <" + vessel_update.player + ">";
                                 extant_vessel.vesselName = vessel_update.name + " <" + vessel_update.player + ">";
                            }
                            else if (extant_vessel != null)
                            {
                                extant_vessel.name = vessel_update.name;
                                extant_vessel.vesselName = vessel_update.name;
                            }
                        }
            //						if (serverVessels_LoadDelay.ContainsKey(vessel_update.id) ? (serverVessels_LoadDelay[vessel_update.id] < UnityEngine.Time.realtimeSinceStartup) : true)
            //						{
                            float incomingDistance = 2500f;
                            if (!syncing && vessel.worldPosition != Vector3.zero && vessel_update.relTime == RelativeTime.PRESENT)
                                incomingDistance = Vector3.Distance(vessel.worldPosition,FlightGlobals.ship_position);
                            if (vessel_update.relTime != RelativeTime.PRESENT) incomingDistance = 3000f; //Never treat vessels from another time as close by
                         	if (vessel_update.state == State.ACTIVE
                                    || vessel_update.isDockUpdate
                                    || (incomingDistance > vessel_update.distance
                                        && (serverVessels_LastUpdateDistanceTime.ContainsKey(vessel_update.id) ? (serverVessels_LastUpdateDistanceTime[vessel_update.id].Key > vessel_update.distance || serverVessels_LastUpdateDistanceTime[vessel_update.id].Value < Planetarium.GetUniversalTime()): true)))
                            {
                                serverVessels_LastUpdateDistanceTime[vessel_update.id] = new KeyValuePair<double, double>(vessel_update.distance,Planetarium.GetUniversalTime() + 0.75f);
                                if (extant_vessel != null)
                                {
                                    //Log.Debug("vessel found: " + extant_vessel.id);
                                    if (extant_vessel.vesselType != VesselType.Flag) //Special treatment for flags
                                    {
                                        //vessel.vesselRef = extant_vessel;
                                        float ourDistance = 3000f;
                                        if (isInFlight)
                                        {
                                            if (!extant_vessel.loaded)
                                            {
                                                if (KMPVessel.situationIsOrbital(vessel_update.situation))
                                                    ourDistance = Vector3.Distance(extant_vessel.orbit.getPositionAtUT(Planetarium.GetUniversalTime()), FlightGlobals.ship_position);
                                                else ourDistance = Vector3.Distance(oldPosition, FlightGlobals.ship_position);
                                            }
                                        else ourDistance = Vector3.Distance(extant_vessel.GetWorldPos3D(), FlightGlobals.ship_position);
                                        }
                                        bool countMismatch = false;
                                        ProtoVessel protovessel = null;
                                        if (serverVessels_ProtoVessels.ContainsKey(vessel_update.id))
                                        {
                                            ConfigNode protoNode = serverVessels_ProtoVessels[vessel_update.id];
                                            checkProtoNodeCrew(protoNode);
                                            protovessel = new ProtoVessel(protoNode, HighLogic.CurrentGame);
                                        }
                                        if (serverVessels_PartCounts.ContainsKey(vessel_update.id))
                                        {
                                            //countMismatch = serverVessels_PartCounts[vessel_update.id] > 0 && extant_vessel.loaded && !extant_vessel.packed && serverVessels_PartCounts[vessel_update.id] != protovessel.protoPartSnapshots.Count;
                                            countMismatch = serverVessels_PartCounts[vessel_update.id] > 0 && serverVessels_PartCounts[vessel_update.id] != protovessel.protoPartSnapshots.Count;
                                        }
                                        if ((vessel_update.getProtoVesselNode() != null && (!KMPVessel.situationIsOrbital(vessel_update.situation) || ourDistance > 2500f || extant_vessel.altitude < 10000d)) || countMismatch)
                                        {
                                            Log.Debug("updating from protovessel");
                                            serverVessels_PartCounts[vessel_update.id] = 0;
                                            if (protovessel != null)
                                            {
                                                if (vessel.orbitValid && KMPVessel.situationIsOrbital(vessel_update.situation) && protovessel.altitude > 10000f && protovessel.vesselType != VesselType.Flag && protovessel.vesselType != VesselType.EVA && ourDistance > 2500f)
                                                {
                                                    protovessel = syncOrbit(vessel, vessel_update.tick, protovessel, vessel_update.w_pos[0]);
                                                }
                                                if (protovessel == null)
                                                {
                                                    Log.Debug("vessel collided with surface");
                                                    killVessel(extant_vessel);
                                                    return;
                                                }
                                                addRemoteVessel(protovessel, vessel_update.id, vessel, vessel_update, incomingDistance);
                                                if (vessel_update.situation == Situation.FLYING) serverVessels_LoadDelay[vessel.id] = UnityEngine.Time.realtimeSinceStartup + 5f;
                                            } else { Log.Debug("Protovessel missing!"); }
                                        }
                                        else
                                        {
                                            Log.Debug("no protovessel");
                                            if (vessel.orbitValid)
                                            {
                                                Log.Debug("updating from flight data, distance: " + ourDistance);
                                                //Update orbit to our game's time if necessary
                                                //bool throttled = serverVessels_ObtSyncDelay.ContainsKey(vessel_update.id) && serverVessels_ObtSyncDelay[vessel_update.id] > UnityEngine.Time.realtimeSinceStartup;
                                                bool throttled = false;
                                                if (KMPVessel.situationIsOrbital(vessel_update.situation) && extant_vessel.altitude > 10000f)
                                                {
                                                    double tick = Planetarium.GetUniversalTime();
                                                    //Update orbit whenever out of sync or other vessel in past/future, or not in docking range
                          							if (!throttled && !extant_vessel.loaded ||
                                                        (vessel_update.relTime == RelativeTime.PRESENT && (ourDistance > (INACTIVE_VESSEL_RANGE+500f))) ||
                          								(vessel_update.relTime != RelativeTime.PRESENT && Math.Abs(tick-vessel_update.tick) > 1.5d && isInFlight && vessel_update.id != FlightGlobals.ActiveVessel.id))
                                                    {
                                                        if (!syncExtantVesselOrbit(vessel,vessel_update.tick,extant_vessel,vessel_update.w_pos[0]))
                                                        {
                                                            //Collision!
                                                            Log.Debug("vessel collided with surface");
                                                            killVessel(extant_vessel);
                                                            return;
                                                        }
                                                        serverVessels_ObtSyncDelay[vessel_update.id] = UnityEngine.Time.realtimeSinceStartup + 1f;
                                                    }
                                                }

                                                if (isInFlight && FlightGlobals.ActiveVessel.mainBody == update_body && vessel_update.relTime == RelativeTime.PRESENT)
                                                {
                                                    if (!extant_vessel.loaded)
                                                    {
                                                        Log.Debug("Skipped full update, vessel not loaded");
                                                        return;
                                                    }
                                                    Log.Debug("full update");
                                                    if (serverVessels_InPresent.ContainsKey(vessel_update.id) ? !serverVessels_InPresent[vessel_update.id] : true)
                                                    {
                                                        serverVessels_InPresent[vessel_update.id] = true;
                                                        foreach (Part part in extant_vessel.Parts)
                                                        {
                                                            setPartOpacity(part,1f);
                                                        }
                                                    }

                                                    //Update rotation
                                                    if (extant_vessel.loaded)
                                                    {
                                                        Log.Debug("rotation set");

                                                        extant_vessel.transform.LookAt(extant_vessel.transform.position + extant_vessel.mainBody.transform.TransformDirection(new Vector3(vessel_update.rot[0],vessel_update.rot[1],vessel_update.rot[2])).normalized,vessel.worldDirection);
                                                        //Quaternion rot = extant_vessel.transform.rotation;
            //														if (extant_vessel.altitude > 10000f)
            //														{
            //															extant_vessel.transform.up = vessel.worldDirection;
            //															extant_vessel.transform.Rotate(rot.eulerAngles);
                                                            extant_vessel.SetRotation(extant_vessel.transform.rotation);
            //														}
                                                        extant_vessel.angularMomentum = Vector3.zero;
            //														extant_vessel.VesselSAS.LockHeading(extant_vessel.transform.rotation);
            //														extant_vessel.VesselSAS.currentRotation = rot;
                                                        extant_vessel.VesselSAS.SetDampingMode(false);
                                                    }

                                                    if (!KMPVessel.situationIsOrbital(vessel_update.situation) || extant_vessel.altitude < 10000f || vessel_update.id == FlightGlobals.ActiveVessel.id || ourDistance > 2500f)
                                                    {
                                                        Log.Debug ("velocity update");
                                                        //Update velocity
                                                        if (extant_vessel.loaded)
                                                        {
                                                            if (update_body.GetAltitude(vessel.worldPosition)<10000d)
                                                            {
                                                                //Set velocity by surface velocity
                                                                Vector3d new_srf_vel = new Vector3d(vessel_update.s_vel[0],vessel_update.s_vel[1],vessel_update.s_vel[2]);
                                                                if (new_srf_vel.sqrMagnitude>1d) extant_vessel.ChangeWorldVelocity((-1 * extant_vessel.srf_velocity) + new_srf_vel);
                                                                else extant_vessel.ChangeWorldVelocity(-0.99f * extant_vessel.srf_velocity);
                                                            }
                                                            else
                                                            {
                                                                //Set velocity by orbit velocity
                                                                Vector3d new_obt_vel = new Vector3d(vessel_update.o_vel[0],vessel_update.o_vel[1],vessel_update.o_vel[2]);
                                                                if (new_obt_vel.sqrMagnitude>1d) extant_vessel.ChangeWorldVelocity((-1 * extant_vessel.obt_velocity) + new_obt_vel);
                                                                else extant_vessel.ChangeWorldVelocity(-0.99f * extant_vessel.obt_velocity);
                                                            }
                                                        }

                                                        //Update position
                                                        if (extant_vessel.altitude < 10000f || !extant_vessel.loaded || vessel_update.id == FlightGlobals.ActiveVessel.id)
                                                        {
                                                            if (extant_vessel.loaded && (vessel_update.situation == Situation.LANDED || vessel_update.situation == Situation.SPLASHED))
                                                            {
                                                                //Update surface position
                                                                Log.Debug("surface position update");
                                                                Vector3d newPos = update_body.GetWorldSurfacePosition(vessel_update.w_pos[1],vessel_update.w_pos[2],extant_vessel.altitude+0.001d);
                                                                if (extant_vessel.packed) extant_vessel.GoOffRails();
                                                                extant_vessel.distancePackThreshold = Math.Max(extant_vessel.distancePackThreshold,Vector3.Distance(vessel.worldPosition, FlightGlobals.ship_position) + 250f);
                                                                if ((newPos - extant_vessel.GetWorldPos3D()).sqrMagnitude > 1d)
                                                                    extant_vessel.SetPosition(newPos);
                                                                else if (Vector3.Distance(vessel.worldPosition, extant_vessel.GetWorldPos3D()) > 25f)
                                                                {
                                                                    serverVessels_PartCounts[vessel_update.id] = 0;
                                                                    addRemoteVessel(protovessel,vessel_update.id,vessel,vessel_update);
                                                                }
                                                            }
                                                            else if (extant_vessel.loaded && ((!throttled && Vector3.Distance(vessel.worldPosition, extant_vessel.GetWorldPos3D()) > 1
                                                                     && (extant_vessel.altitude < 10000f || ourDistance > 2500f)) || vessel_update.id == FlightGlobals.ActiveVessel.id))
                                                            {
                                                                //Update 3D position
                                                                Log.Debug("position update");
                                                                if (extant_vessel.packed) extant_vessel.GoOffRails();
                                                                extant_vessel.distancePackThreshold = Math.Max(extant_vessel.distancePackThreshold,Vector3.Distance(vessel.worldPosition, FlightGlobals.ship_position) + 250f);
                                                                extant_vessel.SetPosition(vessel.worldPosition);
                                                            }
                                                            else if (!extant_vessel.loaded && Vector3.Distance(vessel.worldPosition, FlightGlobals.ship_position) < 2500f)
                                                            {
                                                                //Stretch packing thresholds to prevent excessive load/unloads during rendezvous initiation
                                                                extant_vessel.distancePackThreshold += 250f;
                                                                extant_vessel.distanceUnpackThreshold += 100f;
                                                            }
                                                            else
                                                            {
                                                                //Reset packing thresholds
                                                                extant_vessel.distancePackThreshold = 7500f;
                                                                extant_vessel.distanceUnpackThreshold = 1000f;
                                                            }
                                                        }

                                                        //Update FlightCtrlState

                                                        if (extant_vessel.id == FlightGlobals.ActiveVessel.id) {
                                                            FlightInputHandler.state.CopyFrom(vessel_update.flightCtrlState.getAsFlightCtrlState(0.75f));
                                                        } else {
                                                            extant_vessel.ctrlState.CopyFrom(vessel_update.flightCtrlState.getAsFlightCtrlState(0.75f));
                                                        }
                                                    }
                                                    else
                                                    {
                                                        if (ourDistance <= 2500f)
                                                        {
                                                            //Orbital rendezvous
                                                            Log.Debug("orbital rendezvous");

                                                            //Keep body-relative orbit intact
                                                            if (!extant_vessel.packed && (serverVessels_SkippedRendezvousUpdates.ContainsKey(extant_vessel.id) ? serverVessels_SkippedRendezvousUpdates[extant_vessel.id] > ALLOW_RENDEZ_OBT_UPDATE_LIMIT : false ))
                                                            {
                                                                serverVessels_SkippedRendezvousUpdates[extant_vessel.id] = -1;
                                                                Vector3d relPos = vessel.worldPosition - extant_vessel.GetWorldPos3D();
                                                                Vector3d relObtVel = new Vector3d(vessel_update.o_vel[0],vessel_update.o_vel[1],vessel_update.o_vel[2])-extant_vessel.obt_velocity;
                                                                if (relPos.sqrMagnitude > RENDEZ_OBT_UPDATE_RELPOS_MIN_SQRMAG || relObtVel.sqrMagnitude > RENDEZ_OBT_UPDATE_RELVEL_MIN_SQRMAG)
                                                                {
                                                                    Log.Debug("syncing relative orbit for mismatch");
                                                                    relPos *= RENDEZ_OBT_UPDATE_SCALE_FACTOR;
                                                                    relObtVel *= RENDEZ_OBT_UPDATE_SCALE_FACTOR;

                                                                    extant_vessel.SetPosition(extant_vessel.GetWorldPos3D() + relPos);
                                                                    FlightGlobals.ActiveVessel.SetPosition(FlightGlobals.ship_position + relPos);

                                                                    FlightGlobals.ActiveVessel.ChangeWorldVelocity(relObtVel);
                                                                    extant_vessel.ChangeWorldVelocity(relObtVel);
                                                                }
                                                            }

                                                            //Update FlightCtrlState
                                                            extant_vessel.ctrlState.CopyFrom(vessel_update.flightCtrlState.getAsFlightCtrlState(0.85f));
                                                        }
                                                    }
                                                }
                                                else if (isInFlight && FlightGlobals.ActiveVessel.mainBody == vessel.mainBody)
                                                {
                                                    Log.Debug("update from past/future");

                                                    if (!serverVessels_InPresent.ContainsKey(vessel_update.id) || serverVessels_InPresent.ContainsKey(vessel_update.id) ? serverVessels_InPresent[vessel_update.id]: false)
                                                    {
                                                        serverVessels_InPresent[vessel_update.id] = false;
                                                        foreach (Part part in extant_vessel.Parts)
                                                        {
                                                            setPartOpacity(part,0.3f);
                                                        }
                                                    }

                                                    //Update rotation only
                                                    extant_vessel.transform.LookAt(extant_vessel.transform.position + extant_vessel.mainBody.transform.TransformDirection(new Vector3(vessel_update.rot[0],vessel_update.rot[1],vessel_update.rot[2])).normalized,vessel.worldDirection);
                                                }
                                            }
                                        }
                                        Log.Debug("updated");
                                    }
                                    else
                                    {
                                        //Update flag if needed
                                        if (vessel_update.getProtoVesselNode() != null)
                                        {
                                            ConfigNode protoNode = serverVessels_ProtoVessels[vessel_update.id];
                                            checkProtoNodeCrew(protoNode);
                                            ProtoVessel protovessel = new ProtoVessel(protoNode, HighLogic.CurrentGame);
                                            addRemoteVessel(protovessel,vessel_update.id,vessel,vessel_update);
                                        }
                                    }
                                }
                                else
                                {
                                    try
                                    {
                                        if (serverVessels_ProtoVessels.ContainsKey(vessel_update.id))
                                        {
                                            Log.Debug("Adding new vessel: " + vessel_update.id);
                                            ConfigNode protoNode = serverVessels_ProtoVessels[vessel_update.id];
                                            checkProtoNodeCrew(protoNode);
                                            ProtoVessel protovessel = new ProtoVessel(protoNode, HighLogic.CurrentGame);
                                            if (vessel.orbitValid && KMPVessel.situationIsOrbital(vessel_update.situation) && protovessel.vesselType != VesselType.Flag)
                                            {
                                                protovessel = syncOrbit(vessel, vessel_update.tick, protovessel, vessel_update.w_pos[0]);
                                            }
                                            if (protovessel == null)
                                            {
                                                Log.Debug("Did not load vessel, has collided with surface");
                                                return;
                                            }
                                            serverVessels_PartCounts[vessel_update.id] = 0;
                                            addRemoteVessel(protovessel, vessel_update.id, vessel, vessel_update, incomingDistance);
                                            HighLogic.CurrentGame.CrewRoster.ValidateAssignments(HighLogic.CurrentGame);
                                        }
                                        else
                                        {
                                            Log.Debug("New vessel, but no matching protovessel available");
                                        }
                                    } catch (Exception e) { Log.Debug("Exception thrown in applyVesselUpdate(), catch 2, Exception: {0}", e.ToString()); Log.Debug("Vessel add error: " + e.Message + "\n" + e.StackTrace); }
                                }
                            }
                            else
                            {
                                Log.Debug("Vessel update ignored: we are closer to target vessel or have recently updated from someone who was closer");
                            }
            //						}
            //						else
            //						{
            //							Log.Debug("Vessel update ignored: target vessel on load delay list");
            //						}
                    }
                }
                else
                {
                    if (isInFlight && vessel_update.id == FlightGlobals.ActiveVessel.id)
                    {
                        Log.Debug("Relative update: " + vessel_update.relativeTo);
                        //This is our vessel!
                        if (vessel_update.getProtoVesselNode() != null)
                        {
                            Log.Debug("Received updated protovessel for active vessel");
                            serverVessels_ProtoVessels[vessel_update.id] = vessel_update.getProtoVesselNode();
                            ConfigNode protoNode = serverVessels_ProtoVessels[vessel_update.id];
                            checkProtoNodeCrew(protoNode);
                            ProtoVessel protovessel = new ProtoVessel(protoNode, HighLogic.CurrentGame);
                            addRemoteVessel(protovessel,vessel_update.id,vessel,vessel_update,0);
                        }

                        if (vessel_update.isDockUpdate && vessel_update.relTime == RelativeTime.PRESENT && !vessel_update.isSyncOnlyUpdate)
                        {
                            //Someone docked with us and has control
                            docking = true;
                            syncing = true;
                            ScreenMessages.PostScreenMessage("Other player has control of newly docked vessel",2.5f,ScreenMessageStyle.UPPER_CENTER);
                            Log.Debug("Received docking update");
                            serverVessels_PartCounts[FlightGlobals.ActiveVessel.id] = 0;
                            serverVessels_InUse[vessel_update.id] = true;
                            return;
                        }
                        //Try to negotiate our relative position with whatever sent this update
                        if (FlightGlobals.ActiveVessel.altitude > 10000d
                            && vessel_update.relativeTo != Guid.Empty
                            && Math.Abs(Planetarium.GetUniversalTime() - vessel_update.tick) < 4d
                            //&& (serverVessels_LoadDelay.ContainsKey(vessel_update.id) ? serverVessels_LoadDelay[vessel_update.id] < UnityEngine.Time.realtimeSinceStartup : true)
                            )
                        {
                            Vessel updateFrom = FlightGlobals.Vessels.Find (v => v.id == vessel_update.relativeTo);
                            if (updateFrom != null && !updateFrom.loaded)
                            {
                                Log.Debug("Rendezvous update from unloaded vessel");
                                if (vessel_update.distance < INACTIVE_VESSEL_RANGE)
                                {
                                    //We're not in normal secondary vessel range but other vessel is, send negotiating reply
                                    KMPVesselUpdate update = getVesselUpdate(updateFrom);
                                    update.distance = INACTIVE_VESSEL_RANGE;
                                    update.state = State.INACTIVE;
                                    //Rendezvous relative position data
                                    update.relativeTo = FlightGlobals.ActiveVessel.id;
                                    Vector3d w_pos = FlightGlobals.ActiveVessel.mainBody.transform.InverseTransformDirection(updateFrom.findWorldCenterOfMass() - activeVesselPosition);
                                    Vector3d o_vel = FlightGlobals.ActiveVessel.mainBody.transform.InverseTransformDirection(updateFrom.GetObtVelocity() - FlightGlobals.ActiveVessel.GetObtVelocity());
                                    for (int i = 0; i < 3; i++)
                                    {
                                        update.w_pos[i] = w_pos[i];
                                        update.o_vel[i] = o_vel[i];
                                    }

                                    byte[] update_bytes = KSP.IO.IOUtils.SerializeToBinary(update);
                                    enqueuePluginInteropMessage(KMPCommon.PluginInteropMessageID.SECONDARY_PLUGIN_UPDATE, update_bytes);

                                    //updateFrom.distancePackThreshold += INACTIVE_VESSEL_RANGE/2;
                                }
                            }
                            else if (updateFrom != null && updateFrom.loaded)
                            {
                                Log.Debug("rendezvous positioning: " + updateFrom.id);

                                Vector3d updateFromPos = updateFrom.packed ? updateFrom.GetWorldPos3D() : (Vector3d) updateFrom.findWorldCenterOfMass();
                                Vector3d relPos = activeVesselPosition-updateFromPos;
                                Vector3d updateRelPos = updateFrom.mainBody.transform.TransformDirection(new Vector3d(vessel_update.w_pos[0],vessel_update.w_pos[1],vessel_update.w_pos[2]));

                                if (!dockingRelVel.ContainsKey(updateFrom.id))
                                    dockingRelVel[updateFrom.id] = updateFrom.GetObtVelocity();

                                Vector3d relVel = FlightGlobals.ActiveVessel.GetObtVelocity()-dockingRelVel[updateFrom.id];
                                Vector3d updateRelVel = updateFrom.mainBody.transform.TransformDirection(new Vector3d(vessel_update.o_vel[0],vessel_update.o_vel[1],vessel_update.o_vel[2]));
                                Vector3d diffPos = updateRelPos - relPos;
                                Vector3d diffVel = updateRelVel - relVel;
                                diffPos *= 0.49d;
                                diffVel *= 0.49d;
                                Vector3d newPos = updateFromPos-diffPos;

                                if (!serverVessels_SkippedRendezvousUpdates.ContainsKey(updateFrom.id)) serverVessels_SkippedRendezvousUpdates[updateFrom.id] = 0;

                                bool applyUpdate = true;
                                double curTick = Planetarium.GetUniversalTime();
                                if (vessel_update.distance <= INACTIVE_VESSEL_RANGE && serverVessels_SkippedRendezvousUpdates[updateFrom.id] != -1) //If distance >= INACTIVE_VESSEL_RANGE then the other player didn't have us loaded--don't ignore even a large correction in this case
                                {
                                    bool smoothPosCheck = (serverVessels_RendezvousSmoothPos.ContainsKey(updateFrom.id) ? (diffPos.sqrMagnitude > (serverVessels_RendezvousSmoothPos[updateFrom.id].Key * SMOOTH_RENDEZ_UPDATE_MAX_DIFFPOS_SQRMAG_INCREASE_SCALE) && diffPos.sqrMagnitude > 1d && serverVessels_RendezvousSmoothPos[updateFrom.id].Value > (curTick-SMOOTH_RENDEZ_UPDATE_EXPIRE)): false);
                                    if ((serverVessels_RendezvousSmoothPos.ContainsKey(updateFrom.id) ? serverVessels_RendezvousSmoothPos[updateFrom.id].Value > (curTick-SMOOTH_RENDEZ_UPDATE_MIN_DELAY) : false) || smoothPosCheck)
                                    {
                                        applyUpdate = false;
                                        if (smoothPosCheck)
                                            serverVessels_SkippedRendezvousUpdates[updateFrom.id]++;
                                    }
                                    if (serverVessels_RendezvousSmoothVel.ContainsKey(updateFrom.id) ? (diffVel.sqrMagnitude > (serverVessels_RendezvousSmoothVel[updateFrom.id].Key * SMOOTH_RENDEZ_UPDATE_MAX_DIFFVEL_SQRMAG_INCREASE_SCALE) && diffVel.sqrMagnitude > 1d && serverVessels_RendezvousSmoothVel[updateFrom.id].Value > (curTick-SMOOTH_RENDEZ_UPDATE_EXPIRE)): false)
                                    {
                                        serverVessels_SkippedRendezvousUpdates[updateFrom.id]++;
                                        applyUpdate = false;
                                    }
                                }

                                double expectedDist = Vector3d.Distance(newPos, activeVesselPosition);
                                if (applyUpdate)
                                {
                                    serverVessels_RendezvousSmoothPos[updateFrom.id] = new KeyValuePair<double, double>(diffPos.sqrMagnitude,curTick);
                                    serverVessels_RendezvousSmoothVel[updateFrom.id] = new KeyValuePair<double, double>(diffVel.sqrMagnitude,curTick);
                                    serverVessels_SkippedRendezvousUpdates[updateFrom.id] = 0;
                                    try
                                    {
                                        OrbitPhysicsManager.HoldVesselUnpack(1);
                                    }
                                    catch (NullReferenceException e)
                                    {
                                        Log.Debug("Exception thrown in applyVesselUpdate(), catch 3, Exception: {0}", e.ToString());
                                    }

                                    if (diffPos.sqrMagnitude < 1000000d && diffPos.sqrMagnitude > 0.05d)
                                    {
                                        Log.Debug("Docking Krakensbane shift");
                                        foreach (Vessel otherVessel in FlightGlobals.Vessels.Where(v => v.packed == false && v.id != FlightGlobals.ActiveVessel.id && v.id == updateFrom.id))
                                            otherVessel.GoOnRails();
                                        getKrakensbane().setOffset(diffPos);
                                    }
                                    else if (diffPos.sqrMagnitude >= 1000000d)
                                    {
                                        Log.Debug("Clamped docking Krakensbane shift");
                                        diffPos.Normalize();
                                        diffPos *= 1000d;
                                        foreach (Vessel otherVessel in FlightGlobals.Vessels.Where(v => v.packed == false && v.id != FlightGlobals.ActiveVessel.id))
                                            otherVessel.GoOnRails();
                                        getKrakensbane().setOffset(diffPos);
                                    }

                                    activeVesselPosition += diffPos;

                                    if (diffVel.sqrMagnitude > 0.0025d && diffVel.sqrMagnitude < 2500d)
                                    {
                                        Log.Debug("Docking velocity update");
                                        if (updateFrom.packed) updateFrom.GoOffRails();
                                        updateFrom.ChangeWorldVelocity(-diffVel);
                                    }
                                    else if (diffVel.sqrMagnitude >= 2500d)
                                    {
                                        Log.Debug("Damping large velocity differential");
                                        diffVel = diffVel.normalized;
                                        diffVel *= 50d;
                                        if (updateFrom.packed) updateFrom.GoOffRails();
                                        updateFrom.ChangeWorldVelocity(-diffVel);
                                    }

                                    dockingRelVel[updateFrom.id] -= diffVel;
                                }
                                else Log.Debug("Ignored docking position update: unexpected large pos/vel shift");

                                Log.Debug("had dist:" + relPos.magnitude + " got dist:" + updateRelPos.magnitude);
                                Log.Debug("expected dist:" + expectedDist + " diffPos mag: " + diffPos.sqrMagnitude);
                                Log.Debug("had relVel:" + relVel.magnitude + " got relVel:" + updateRelVel.magnitude + " diffVel mag:" + diffVel.sqrMagnitude);
                            }
                        } else Log.Debug("Ignored docking position update: " + (FlightGlobals.ActiveVessel.altitude > 10000d) + " " + (vessel_update.relativeTo != Guid.Empty) + " " + (Math.Abs(Planetarium.GetUniversalTime() - vessel_update.tick) < 1d));
                    }
                }
            }
        }
Example #8
0
        private void addRemoteVessel(ProtoVessel protovessel, Guid vessel_id, KMPVessel kvessel = null, KMPVesselUpdate update = null, double distance = 501d)
        {
            if (vessel_id == FlightGlobals.ActiveVessel.id && (serverVessels_InUse.ContainsKey(vessel_id) ? !serverVessels_InUse.ContainsKey(vessel_id) : false)) return;
            if (serverVessels_LoadDelay.ContainsKey(vessel_id) ? serverVessels_LoadDelay[vessel_id] >= UnityEngine.Time.realtimeSinceStartup : false) return;
            serverVessels_LoadDelay[vessel_id] = UnityEngine.Time.realtimeSinceStartup + 5f;
            Log.Debug("addRemoteVessel: " + vessel_id.ToString() + ", name: " + protovessel.vesselName.ToString() + ", type: " + protovessel.vesselType.ToString());
            if (protovessel.vesselType == VesselType.Flag) {
                Invoke("ClearFlagLock", 5f);
            }
            Vector3 newWorldPos = Vector3.zero, newOrbitVel = Vector3.zero;
            bool setTarget = false, wasLoaded = false, wasActive = false;
            Vessel oldVessel = null;
            try
            {
                //Ensure this vessel isn't already loaded
                oldVessel = FlightGlobals.fetch.vessels.Find (v => v.id == vessel_id);
                if (oldVessel != null) {
                    wasLoaded = oldVessel.loaded;
                    if (protovessel.vesselType == VesselType.EVA && wasLoaded)
                    {
                        return; //Don't touch EVAs here
                    }
                    else
                    {
                        setTarget = FlightGlobals.fetch.VesselTarget != null && FlightGlobals.fetch.VesselTarget.GetVessel().id == vessel_id;
                        if (oldVessel.loaded)
                        {
                            newWorldPos = oldVessel.transform.position;
                            if (oldVessel.altitude > 10000d)
                                newOrbitVel = oldVessel.GetObtVelocity();
                        }
                        if (FlightGlobals.ActiveVessel != null ? oldVessel.id == FlightGlobals.ActiveVessel.id : false)
                        {
                            wasActive = true;
                        }
                    }

                    if (protovessel.vesselType != VesselType.EVA && serverVessels_Parts.ContainsKey(vessel_id))
                    {
                        Log.Debug("killing known precursor vessels");
                        foreach (Part part in serverVessels_Parts[vessel_id])
                        {
                            try { if (part.vessel != null && part.vessel.id != oldVessel.id) killVessel(part.vessel); } catch (Exception e) {  Log.Debug("Exception thrown in addRemoteVessel(), catch 1, Exception: {0}", e.ToString()); }
                        }
                    }
                }
            } catch (Exception e) {  Log.Debug("Exception thrown in addRemoteVessel(), catch 2, Exception: {0}", e.ToString()); }
            try
            {
                if ((protovessel.vesselType != VesselType.Debris && protovessel.vesselType != VesselType.Unknown) && protovessel.situation == Vessel.Situations.SUB_ORBITAL && protovessel.altitude < 25d)
                {
                    //Land flags, vessels and EVAs that are on sub-orbital trajectory
                    Log.Debug("Placing sub-orbital protovessel on surface");
                    protovessel.situation = Vessel.Situations.LANDED;
                    protovessel.landed = true;
                    if (protovessel.vesselType == VesselType.Flag) protovessel.height = -1;
                }
                //Don't bother with suborbital debris
                else if (protovessel.vesselType == VesselType.Debris && protovessel.situation == Vessel.Situations.SUB_ORBITAL) return;

                CelestialBody body = null;

                if (update != null)
                {
                    body = FlightGlobals.Bodies.Find(b => b.name == update.bodyName);
                    if (update.situation == Situation.FLYING)
                    {
                        if (body.atmosphere && body.maxAtmosphereAltitude > protovessel.altitude)
                        {
                            //In-atmo vessel--only load if within visible range
                            if (distance > 500d)
                                return;
                        }
                    }
                }

                if (isProtoVesselInSafetyBubble(protovessel)) //refuse to load anything too close to the KSC
                {
                    Log.Debug("Tried to load vessel too close to KSC");
                    return;
                }

                if (vessels.ContainsKey(vessel_id.ToString()))
                {
                    if (oldVessel != null)
                    {
                        if (wasActive)
                        {
                            Log.Debug("Preparing active vessel for replacement");
                            Vessel SyncPlate = FlightGlobals.fetch.vessels.Find(v => v.id.ToString() == SYNC_PLATE_ID);
                            if (SyncPlate != null) {
                                FlightGlobals.SetActiveVessel(SyncPlate);
                            } else
                            {
                                Log.Debug("Cannot set SyncPlate as active vessel!");
                            }
                            foreach (Part part in oldVessel.Parts)
                            {
                                part.Rigidbody.detectCollisions = false;
                                part.explosionPotential = 0;
                            }
                            //oldVessel.id = Guid.Empty;
                            serverVessels_InUse[oldVessel.id] = false;
                            serverVessels_IsPrivate[oldVessel.id] = false;
                            serverVessels_IsMine[oldVessel.id] = true;
                        }
                    }
                    StartCoroutine(loadProtovessel(oldVessel, newWorldPos, newOrbitVel, wasLoaded, wasActive, setTarget, protovessel, vessel_id, kvessel, update, distance));
                }
            }
            catch (Exception e)
            {
                Log.Debug("Exception thrown in addRemoteVessel(), catch 3, Exception: {0}", e.ToString());
                Log.Debug("Error adding remote vessel: " + e.Message + " " + e.StackTrace);
            }
        }
Example #9
0
        private void addRemoteVessel(ProtoVessel protovessel, Guid vessel_id, KMPVessel kvessel = null, KMPVesselUpdate update = null, double distance = 501d)
        {
            if (vessel_id == FlightGlobals.ActiveVessel.id && (serverVessels_InUse.ContainsKey(vessel_id) ? !serverVessels_InUse.ContainsKey(vessel_id) : false)) return;
            KMPClientMain.DebugLog("addRemoteVessel");
            Vector3 newWorldPos = Vector3.zero, newOrbitVel = Vector3.zero;
            bool setTarget = false, wasLoaded = false, wasActive = false;
            Vessel oldVessel = null;
            try
            {
                //Ensure this vessel isn't already loaded
                oldVessel = FlightGlobals.Vessels.Find (v => v.id == vessel_id);
                if (oldVessel != null) {
                    wasLoaded = oldVessel.loaded;
                    if (protovessel.vesselType == VesselType.EVA && wasLoaded)
                    {
                        return; //Don't touch EVAs here
                    }
                    else
                    {
                        setTarget = FlightGlobals.fetch.VesselTarget != null && FlightGlobals.fetch.VesselTarget.GetVessel().id == vessel_id;
                        if (oldVessel.loaded)
                        {
                            newWorldPos = oldVessel.transform.position;
                            if (oldVessel.altitude > 10000d)
                                newOrbitVel = oldVessel.GetObtVelocity();
                        }
                        if (oldVessel.id == FlightGlobals.ActiveVessel.id)
                            wasActive = true;
                    }
                }

                if (protovessel.vesselType != VesselType.EVA && serverVessels_Parts.ContainsKey(vessel_id))
                {
                    KMPClientMain.DebugLog("killing known precursor vessels");
                    foreach (Part part in serverVessels_Parts[vessel_id])
                    {
                        try { if (!part.vessel.isEVA && part.vessel.id != oldVessel.id) part.vessel.Die(); } catch {}
                    }
                }
            } catch {}
            try
            {
                if ((protovessel.vesselType != VesselType.Debris && protovessel.vesselType != VesselType.Unknown) && protovessel.situation == Vessel.Situations.SUB_ORBITAL && protovessel.altitude < 25d)
                {
                    //Land flags, vessels and EVAs that are on sub-orbital trajectory
                    KMPClientMain.DebugLog("Placing sub-orbital protovessel on surface");
                    protovessel.situation = Vessel.Situations.LANDED;
                    protovessel.landed = true;
                    if (protovessel.vesselType == VesselType.Flag) protovessel.height = -1;
                }
                //Don't bother with suborbital debris
                else if (protovessel.vesselType == VesselType.Debris && protovessel.situation == Vessel.Situations.SUB_ORBITAL) return;

                CelestialBody body = null;

                if (update != null)
                {
                    body = FlightGlobals.Bodies.Find(b => b.name == update.bodyName);
                    if (update.situation != Situation.LANDED && update.situation != Situation.SPLASHED)
                    {
                        if (body.atmosphere && body.maxAtmosphereAltitude > protovessel.altitude)
                        {
                            //In-atmo vessel--only load if within visible range
                            if (distance > 500d)
                                return;
                        }
                    }
                }

                if (isInSafetyBubble(protovessel.position, body, protovessel.altitude)) //refuse to load anything too close to the KSC
                {
                    KMPClientMain.DebugLog("Tried to load vessel too close to KSC");
                    return;
                }

                IEnumerator<ProtoCrewMember> crewEnum = HighLogic.CurrentGame.CrewRoster.GetEnumerator();
                int applicants = 0;
                while (crewEnum.MoveNext())
                    if (crewEnum.Current.rosterStatus == ProtoCrewMember.RosterStatus.AVAILABLE) applicants++;

                if (protovessel.GetVesselCrew().Count * 5 > applicants)
                {
                    KMPClientMain.DebugLog("Adding crew applicants");
                    for (int i = 0; i < (protovessel.GetVesselCrew().Count * 5);)
                    {
                        ProtoCrewMember protoCrew = CrewGenerator.RandomCrewMemberPrototype();
                        if (!HighLogic.CurrentGame.CrewRoster.ExistsInRoster(protoCrew.name))
                        {
                            HighLogic.CurrentGame.CrewRoster.AddCrewMember(protoCrew);
                            i++;
                        }
                    }
                }
                if (vessels.ContainsKey(vessel_id.ToString()) && (serverVessels_LoadDelay.ContainsKey(vessel_id) ? serverVessels_LoadDelay[vessel_id] < UnityEngine.Time.realtimeSinceStartup : true))
                {
                    if (wasActive)
                    {
                        KMPClientMain.DebugLog("Preparing active vessel for replacement");
                        oldVessel.MakeInactive();
                        foreach (Part part in oldVessel.Parts)
                        {
                            part.Rigidbody.detectCollisions = false;
                            part.explosionPotential = 0;
                        }
                        bool inUse = serverVessels_InUse[oldVessel.id];
                        bool isPrivate = serverVessels_IsPrivate[oldVessel.id];
                        bool isMine = serverVessels_IsMine[oldVessel.id];
                        oldVessel.id = new Guid();
                        FlightGlobals.SetActiveVessel(oldVessel);
                        serverVessels_InUse[oldVessel.id] = inUse;
                        serverVessels_IsPrivate[oldVessel.id] = isPrivate;
                        serverVessels_IsMine[oldVessel.id] = isMine;
                    }
                    else if (oldVessel != null && !oldVessel.isEVA)
                    {
                        KMPClientMain.DebugLog("Killing extant vessel");
                        oldVessel.Die();
                    }
                    StartCoroutine(loadProtovessel(oldVessel, newWorldPos, newOrbitVel, wasLoaded, wasActive, setTarget, protovessel, vessel_id, kvessel, update, distance));
                }
            }
            catch (Exception e)
            {
                KMPClientMain.DebugLog("Error adding remote vessel: " + e.Message + " " + e.StackTrace);
            }
        }