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"); }
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); } }
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)); } } }
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; }
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); } }
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; }
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)); } } } }
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); } }
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); } }