private void writePrimaryUpdate() { if (!syncing && isInFlight && !warping && !isInSafetyBubble(FlightGlobals.ship_position,FlightGlobals.ActiveVessel.mainBody,FlightGlobals.ActiveVessel.altitude)) { lastTick = Planetarium.GetUniversalTime(); //Write vessel status KMPVesselUpdate update = getVesselUpdate(FlightGlobals.ActiveVessel); if (FlightGlobals.ActiveVessel.vesselType == VesselType.EVA) lastEVAVessel = FlightGlobals.ActiveVessel; //Update the player vessel info VesselStatusInfo my_status = new VesselStatusInfo(); my_status.info = update; my_status.orbit = FlightGlobals.ActiveVessel.orbit; my_status.color = KMPVessel.generateActiveColor(playerName); my_status.ownerName = playerName; if (FlightGlobals.ActiveVessel.vesselName.Contains(" <") && FlightGlobals.ActiveVessel.vesselName.Contains(">")) FlightGlobals.ActiveVessel.vesselName = FlightGlobals.ActiveVessel.vesselName.Substring(0,FlightGlobals.ActiveVessel.vesselName.IndexOf(" <")); if (String.IsNullOrEmpty(FlightGlobals.ActiveVessel.vesselName.Trim())) FlightGlobals.ActiveVessel.vesselName = "Unknown"; my_status.vesselName = FlightGlobals.ActiveVessel.vesselName; my_status.lastUpdateTime = UnityEngine.Time.realtimeSinceStartup; if (playerStatus.ContainsKey(playerName)) playerStatus[playerName] = my_status; else playerStatus.Add(playerName, my_status); KMPClientMain.DebugLog("sending primary update"); try{ enqueuePluginInteropMessage(KMPCommon.PluginInteropMessageID.PRIMARY_PLUGIN_UPDATE, KSP.IO.IOUtils.SerializeToBinary(update)); } catch (Exception e) { KMPClientMain.DebugLog("err: " + e.Message); } } else { lastTick = 0d; //Check if the player is building a ship bool building_ship = HighLogic.LoadedSceneIsEditor && EditorLogic.fetch != null && EditorLogic.fetch.ship != null && EditorLogic.fetch.ship.Count > 0 && EditorLogic.fetch.shipNameField != null && EditorLogic.fetch.shipNameField.Text != null && EditorLogic.fetch.shipNameField.Text.Length > 0; String[] status_array = null; if (building_ship) { status_array = new String[3]; //Vessel name String shipname = EditorLogic.fetch.shipNameField.Text; if (shipname.Length > MAX_VESSEL_NAME_LENGTH) shipname = shipname.Substring(0, MAX_VESSEL_NAME_LENGTH); //Limit vessel name length status_array[1] = "Building " + shipname; //Vessel details status_array[2] = "Parts: " + EditorLogic.fetch.ship.Count; } else if (warping) { status_array = new String[2]; status_array[1] = "Warping"; } else if (syncing) { status_array = new String[2]; status_array[1] = "Synchronizing"; } else { status_array = new String[2]; switch (HighLogic.LoadedScene) { case GameScenes.FLIGHT: status_array[1] = "Preparing/launching from KSC"; break; case GameScenes.SPACECENTER: status_array[1] = "At Space Center"; break; case GameScenes.EDITOR: status_array[1] = "In Vehicle Assembly Building"; break; case GameScenes.SPH: status_array[1] = "In Space Plane Hangar"; break; case GameScenes.TRACKSTATION: status_array[1] = "At Tracking Station"; break; default: status_array[1] = String.Empty; break; } } //Check if player is idle if (isIdle) status_array[1] = "(Idle) " + status_array[1]; status_array[0] = playerName; //Serialize the update byte[] update_bytes = KSP.IO.IOUtils.SerializeToBinary(status_array); enqueuePluginInteropMessage(KMPCommon.PluginInteropMessageID.PRIMARY_PLUGIN_UPDATE, update_bytes); VesselStatusInfo my_status = statusArrayToInfo(status_array); if (playerStatus.ContainsKey(playerName)) playerStatus[playerName] = my_status; else playerStatus.Add(playerName, my_status); } }
private VesselStatusInfo statusArrayToInfo(String[] status_array) { if (status_array != null && status_array.Length >= STATUS_ARRAY_MIN_SIZE) { //Read status array VesselStatusInfo status = new VesselStatusInfo(); status.info = null; status.ownerName = status_array[0]; status.vesselName = status_array[1]; if (status_array.Length >= 3) status.detailText = status_array[2]; if (status_array.Length >= 4 && !String.IsNullOrEmpty(status_array[3])) status.currentSubspaceID = Int32.Parse(status_array[3]); else status.currentSubspaceID = -1; status.orbit = null; status.lastUpdateTime = UnityEngine.Time.realtimeSinceStartup; status.color = KMPVessel.generateActiveColor(status.ownerName); return status; } else return new VesselStatusInfo(); }
private void vesselStatusLabels(VesselStatusInfo status, bool big) { bool name_pressed = false; bool showSync = false; playerNameStyle.normal.textColor = status.color * 0.75f + Color.white * 0.25f; if (big) GUILayout.BeginHorizontal(); if (status.ownerName != null) name_pressed |= GUILayout.Button(status.ownerName, playerNameStyle); if (status.vesselName != null && status.vesselName.Length > 0) { String vessel_name = status.vesselName; if (status.currentSubspaceID > 0) { showSync = true; showServerSync = true; } if (status.info != null && status.info.detail != null && status.info.detail.idle) vessel_name = "(Idle) " + vessel_name; name_pressed |= GUILayout.Button(vessel_name, vesselNameStyle); } GUIStyle syncButtonStyle = new GUIStyle(GUI.skin.button); syncButtonStyle.normal.textColor = new Color(0.28f, 0.86f, 0.94f); syncButtonStyle.hover.textColor = new Color(0.48f, 0.96f, 0.96f); syncButtonStyle.margin = new RectOffset(150,10,0,0); syncButtonStyle.fixedHeight = 22f; if (big) { GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); } bool syncRequest = false; if (!isInFlight) GUI.enabled = false; if (showSync && FlightGlobals.ActiveVessel.ctrlState.mainThrottle == 0f) syncRequest |= GUILayout.Button("Sync",syncButtonStyle); GUI.enabled = true; if (big) GUILayout.EndHorizontal(); //Build the detail text StringBuilder sb = new StringBuilder(); //Check if the status has specific detail text if (status.detailText != null && status.detailText.Length > 0 && KMPInfoDisplay.infoDisplayDetailed) sb.Append(status.detailText); else if (status.info != null && status.info.detail != null) { bool exploded = false; bool situation_determined = false; if (status.info.situation == Situation.DESTROYED || status.info.detail.mass <= 0.0f) { sb.Append("Exploded at "); exploded = true; situation_determined = true; } else { //Check if the vessel's activity overrides the situation switch (status.info.detail.activity) { case Activity.AEROBRAKING: sb.Append("Aerobraking at "); situation_determined = true; break; case Activity.DOCKING: if (KMPVessel.situationIsGrounded(status.info.situation)) sb.Append("Docking on "); else sb.Append("Docking above "); situation_determined = true; break; case Activity.PARACHUTING: sb.Append("Parachuting to "); situation_determined = true; break; } if (!situation_determined) { switch (status.info.situation) { case Situation.DOCKED: sb.Append("Docked at "); break; case Situation.ENCOUNTERING: sb.Append("Encountering "); break; case Situation.ESCAPING: sb.Append("Escaping "); break; case Situation.FLYING: sb.Append("Flying at "); break; case Situation.LANDED: sb.Append("Landed at "); break; case Situation.ORBITING: sb.Append("Orbiting "); break; case Situation.PRELAUNCH: sb.Append("Prelaunch at "); break; case Situation.SPLASHED: sb.Append("Splashed at "); break; case Situation.ASCENDING: sb.Append("Ascending from "); break; case Situation.DESCENDING: sb.Append("Descending to "); break; } } } sb.Append(status.info.bodyName); if (!exploded && KMPInfoDisplay.infoDisplayDetailed) { bool show_mass = status.info.detail.mass >= 0.05f; bool show_fuel = status.info.detail.percentFuel < byte.MaxValue; bool show_rcs = status.info.detail.percentRCS < byte.MaxValue; bool show_crew = status.info.detail.numCrew < byte.MaxValue; if (show_mass || show_fuel || show_rcs || show_crew) sb.Append(" - "); if (show_mass) { sb.Append("Mass: "); sb.Append(status.info.detail.mass.ToString("0.0")); sb.Append(' '); } if (show_fuel) { sb.Append("Fuel: "); sb.Append(status.info.detail.percentFuel); sb.Append("% "); } if (show_rcs) { sb.Append("RCS: "); sb.Append(status.info.detail.percentRCS); sb.Append("% "); } if (show_crew) { sb.Append("Crew: "); sb.Append(status.info.detail.numCrew); } } } if (sb.Length > 0) GUILayout.Label(sb.ToString(), stateTextStyle); //If the name was pressed, then focus on that players' reference body if (name_pressed && HighLogic.LoadedSceneHasPlanetarium && planetariumCam != null && status.info != null && status.info.bodyName.Length > 0) { if (!MapView.MapIsEnabled) MapView.EnterMapView(); foreach (MapObject target in planetariumCam.targets) { if (target.name == status.info.bodyName) { planetariumCam.SetTarget(target); break; } } } if (syncRequest) StartCoroutine(sendSubspaceSyncRequest(status.currentSubspaceID)); }
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 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 void applyVesselUpdate(KLFVesselUpdate vessel_update, KLFVessel vessel) { //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 (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); } if (vessel_update.state == State.ACTIVE) { //Update the player status info VesselStatusInfo status = new VesselStatusInfo(); 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 = KLFVessel.generateActiveColor(status.ownerName); if (playerStatus.ContainsKey(status.ownerName)) playerStatus[status.ownerName] = status; else playerStatus.Add(status.ownerName, status); } }
private void handleVesselUpdate(KLFVesselUpdate vessel_update) { if (!isInFlight) { //While not in-flight don't create KLF vessel, just store the active vessel status info if (vessel_update.state == State.ACTIVE) { VesselStatusInfo status = new VesselStatusInfo(); status.info = vessel_update; status.ownerName = vessel_update.player; status.vesselName = vessel_update.name; status.orbit = null; status.lastUpdateTime = UnityEngine.Time.realtimeSinceStartup; status.color = KLFVessel.generateActiveColor(status.ownerName); if (playerStatus.ContainsKey(status.ownerName)) playerStatus[status.ownerName] = status; else playerStatus.Add(status.ownerName, status); } return; //Don't handle updates while not flying a ship } //Build the key for the vessel System.Text.StringBuilder sb = new System.Text.StringBuilder(); sb.Append(vessel_update.player); sb.Append(vessel_update.id.ToString()); String vessel_key = sb.ToString(); KLFVessel 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.vesselName != vessel_update.name) { //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 KLFVessel(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 */ vesselUpdateQueue.Enqueue(vessel_update); } else applyVesselUpdate(vessel_update, vessel); //Apply the vessel update to the existing vessel }
private VesselStatusInfo statusArrayToInfo(String[] status_array) { if (status_array != null && status_array.Length >= STATUS_ARRAY_MIN_SIZE) { //Read status array VesselStatusInfo status = new VesselStatusInfo(); status.info = null; status.ownerName = status_array[0]; status.vesselName = status_array[1]; if (status_array.Length >= 3) status.detailText = status_array[2]; status.orbit = null; status.lastUpdateTime = UnityEngine.Time.realtimeSinceStartup; status.color = KLFVessel.generateActiveColor(status.ownerName); return status; } else return new VesselStatusInfo(); }
private void writePrimaryUpdate() { if (isInFlight) { //Write vessel status KLFVesselUpdate update = getVesselUpdate(FlightGlobals.ActiveVessel); //Update the player vessel info VesselStatusInfo my_status = new VesselStatusInfo(); my_status.info = update; my_status.orbit = FlightGlobals.ActiveVessel.orbit; my_status.color = KLFVessel.generateActiveColor(playerName); my_status.ownerName = playerName; my_status.vesselName = FlightGlobals.ActiveVessel.vesselName; my_status.lastUpdateTime = UnityEngine.Time.realtimeSinceStartup; if (playerStatus.ContainsKey(playerName)) playerStatus[playerName] = my_status; else playerStatus.Add(playerName, my_status); enqueuePluginInteropMessage(KLFCommon.PluginInteropMessageID.PRIMARY_PLUGIN_UPDATE, KSP.IO.IOUtils.SerializeToBinary(update)); } else { //Check if the player is building a ship bool building_ship = HighLogic.LoadedSceneIsEditor && EditorLogic.fetch != null && EditorLogic.fetch.ship != null && EditorLogic.fetch.ship.Count > 0 && EditorLogic.fetch.shipNameField != null && EditorLogic.fetch.shipNameField.Text != null && EditorLogic.fetch.shipNameField.Text.Length > 0; String[] status_array = null; if (building_ship) { status_array = new String[3]; //Vessel name String shipname = EditorLogic.fetch.shipNameField.Text; if (shipname.Length > MAX_VESSEL_NAME_LENGTH) shipname = shipname.Substring(0, MAX_VESSEL_NAME_LENGTH); //Limit vessel name length status_array[1] = "Building " + shipname; //Vessel details status_array[2] = "Parts: " + EditorLogic.fetch.ship.Count; } else { status_array = new String[2]; switch (HighLogic.LoadedScene) { case GameScenes.SPACECENTER: status_array[1] = "At Space Center"; break; case GameScenes.EDITOR: status_array[1] = "In Vehicle Assembly Building"; break; case GameScenes.SPH: status_array[1] = "In Space Plane Hangar"; break; case GameScenes.TRACKSTATION: status_array[1] = "At Tracking Station"; break; default: status_array[1] = String.Empty; break; } } //Check if player is idle if (isIdle) status_array[1] = "(Idle) " + status_array[1]; status_array[0] = playerName; //Serialize the update byte[] update_bytes = KSP.IO.IOUtils.SerializeToBinary(status_array); enqueuePluginInteropMessage(KLFCommon.PluginInteropMessageID.PRIMARY_PLUGIN_UPDATE, update_bytes); VesselStatusInfo my_status = statusArrayToInfo(status_array); if (playerStatus.ContainsKey(playerName)) playerStatus[playerName] = my_status; else playerStatus.Add(playerName, my_status); } }
private void ApplyVesselUpdate(KLFVesselUpdate vesselUpdate, KLFVessel kVes) { //Find the CelestialBody that matches the one in the update CelestialBody updateBody = null; if(kVes.MainBody != null && kVes.MainBody.bodyName == vesselUpdate.BodyName) updateBody = kVes.MainBody; //already correct body else foreach (CelestialBody body in FlightGlobals.Bodies) if (body.bodyName == vesselUpdate.BodyName) { updateBody = body; break; } if (updateBody != null) {//Convert float arrays to Vector3s Vector3 pos = new Vector3(vesselUpdate.Position[0], vesselUpdate.Position[1], vesselUpdate.Position[2]); Vector3 dir = new Vector3(vesselUpdate.Direction[0], vesselUpdate.Direction[1], vesselUpdate.Direction[2]); Vector3 vel = new Vector3(vesselUpdate.Velocity[0], vesselUpdate.Velocity[1], vesselUpdate.Velocity[2]); kVes.Info = vesselUpdate; kVes.SetOrbitalData(updateBody, pos, vel, dir); } if (vesselUpdate.State == State.Active) {//Update the player status info VesselStatusInfo status = new VesselStatusInfo(); status.Info = vesselUpdate; status.User = vesselUpdate.Player; status.VesselName = vesselUpdate.Name; if (kVes.OrbitValid) status.Orbit = kVes.OrbitRender.driver.orbit; status.LastUpdateTime = UnityEngine.Time.realtimeSinceStartup; status.Color = KLFVessel.GenerateActiveColor(status.User); if (PlayerStatus.ContainsKey(status.User)) PlayerStatus[status.User] = status; else PlayerStatus.Add(status.User, status); } }
private void WritePrimaryUpdate() { if (IsInFlight) { //Write vessel status KLFVesselUpdate update = GetVesselUpdate(FlightGlobals.ActiveVessel); //Update the player vessel info VesselStatusInfo myStatus = new VesselStatusInfo(); myStatus.Info = update; myStatus.Orbit = FlightGlobals.ActiveVessel.orbit; myStatus.Color = KLFVessel.GenerateActiveColor(PlayerName); myStatus.User = PlayerName; myStatus.VesselName = FlightGlobals.ActiveVessel.vesselName; myStatus.LastUpdateTime = UnityEngine.Time.realtimeSinceStartup; if (PlayerStatus.ContainsKey(PlayerName)) PlayerStatus[PlayerName] = myStatus; else PlayerStatus.Add(PlayerName, myStatus); EnqueuePluginInteropMessage(KLFCommon.PluginInteropMessageID.PrimaryPluginUpdate , KSP.IO.IOUtils.SerializeToBinary(update)); } else { //Check if the player is building a ship bool buildingShip = HighLogic.LoadedSceneIsEditor && EditorLogic.fetch != null && EditorLogic.fetch.ship != null && EditorLogic.fetch.ship.Count > 0 && EditorLogic.fetch.shipNameField != null && EditorLogic.fetch.shipNameField.Text != null && EditorLogic.fetch.shipNameField.Text.Length > 0; //build status line to send to other clients String[] statusArray = null; if (buildingShip) { statusArray = new String[3]; //Vessel name String shipname = EditorLogic.fetch.shipNameField.Text; if (shipname.Length > MaxVesselNameLength) shipname = shipname.Substring(0, MaxVesselNameLength); statusArray[1] = "Building " + shipname; //Vessel details statusArray[2] = "Parts: " + EditorLogic.fetch.ship.Count; } else { statusArray = new String[2]; switch (HighLogic.LoadedScene) { case GameScenes.SPACECENTER: statusArray[1] = KSP_SC_Location; break; case GameScenes.EDITOR: statusArray[1] = "In Vehicle Assembly Building"; break; case GameScenes.TRACKSTATION: statusArray[1] = "At Tracking Station"; break; default: statusArray[1] = String.Empty; break; } } //Check if player is idle if (IsIdle) statusArray[1] = "(Idle) " + statusArray[1]; statusArray[0] = PlayerName; //Serialize the update byte[] updateBytes = KSP.IO.IOUtils.SerializeToBinary(statusArray); EnqueuePluginInteropMessage(KLFCommon.PluginInteropMessageID.PrimaryPluginUpdate, updateBytes); VesselStatusInfo myStatus = StatusArrayToInfo(statusArray); if (PlayerStatus.ContainsKey(PlayerName)) PlayerStatus[PlayerName] = myStatus; else PlayerStatus.Add(PlayerName, myStatus); } }
private void VesselStatusLabels(VesselStatusInfo status, bool big) { bool namePressed = false; PlayerNameStyle.normal.textColor = status.Color * 0.75f + Color.white * 0.25f; if (big) GUILayout.BeginHorizontal(); if (status.User != null) namePressed |= GUILayout.Button(status.User, PlayerNameStyle); if (status.VesselName != null && status.VesselName.Length > 0) { String vName = status.VesselName; if (status.Info != null && status.Info.Detail != null && status.Info.Detail.Idle) vName = "(Idle) " + vName; namePressed |= GUILayout.Button(vName, VesselNameStyle); } if (big) GUILayout.EndHorizontal(); //Build the detail text StringBuilder sb = new StringBuilder(); //Check if the status has specific detail text if (status.DetailText != null && status.DetailText.Length > 0 && KLFInfoDisplay.InfoDisplayDetailed) sb.Append(status.DetailText); else if (status.Info != null && status.Info.Detail != null) { bool exploded = false; bool situationDetermined = false; if(status.Info.Situation == Situation.Destroyed || status.Info.Detail.Mass <= 0.0f) { sb.Append("Exploded at "); exploded = true; situationDetermined = true; } else { //Check if the vessel's activity overrides the situation switch (status.Info.Detail.Activity) { case Activity.Aerobraking: sb.Append("Aerobraking at "); situationDetermined = true; break; case Activity.Docking: if (KLFVessel.SituationIsGrounded(status.Info.Situation)) sb.Append("Docking on "); else sb.Append("Docking above "); situationDetermined = true; break; case Activity.Parachuting: sb.Append("Parachuting to "); situationDetermined = true; break; } if (!situationDetermined) { switch (status.Info.Situation) { case Situation.Docked: sb.Append("Docked at "); break; case Situation.Encountering: sb.Append("Encountering "); break; case Situation.Escaping: sb.Append("Escaping "); break; case Situation.Flying: sb.Append("Flying at "); break; case Situation.Landed: sb.Append("Landed at "); break; case Situation.Orbiting: sb.Append("Orbiting "); break; case Situation.Prelaunch: sb.Append("Prelaunch at "); break; case Situation.Splashed: sb.Append("Splashed at "); break; case Situation.Ascending: sb.Append("Ascending from "); break; case Situation.Descending: sb.Append("Descending to "); break; } } } sb.Append(status.Info.BodyName); if (!exploded && KLFInfoDisplay.InfoDisplayDetailed) { bool showMass = status.Info.Detail.Mass >= 0.05f; bool showFuel = status.Info.Detail.FuelPercent < byte.MaxValue; bool showRcs = status.Info.Detail.RcsPercent < byte.MaxValue; bool showCrew = status.Info.Detail.CrewCount < byte.MaxValue; if (showMass || showFuel || showRcs || showCrew) sb.Append(" - "); if (showMass) { sb.Append("Mass: "); sb.Append(status.Info.Detail.Mass.ToString("0.0")); sb.Append(' '); } if (showFuel) { sb.Append("Fuel: "); sb.Append(status.Info.Detail.FuelPercent); sb.Append("% "); } if (showRcs) { sb.Append("RCS: "); sb.Append(status.Info.Detail.RcsPercent); sb.Append("% "); } if (showCrew) { sb.Append("Crew: "); sb.Append(status.Info.Detail.CrewCount); } } } if (sb.Length > 0) GUILayout.Label(sb.ToString(), StateTextStyle); if (namePressed && HighLogic.LoadedSceneHasPlanetarium && PlanetariumCam != null && status.Info != null && status.Info.BodyName.Length > 0) {//If name was pressed, focus on that players' reference body if (!MapView.MapIsEnabled) MapView.EnterMapView(); foreach (MapObject target in PlanetariumCam.targets) { if (target.name == status.Info.BodyName) { PlanetariumCam.SetTarget(target); break; } } } }
private VesselStatusInfo StatusArrayToInfo(String[] statusArray) { if (statusArray != null && statusArray.Length >= StatusArrayMinSize) {//Read status array VesselStatusInfo status = new VesselStatusInfo(); status.Info = null; status.User = statusArray[0]; status.VesselName = statusArray[1]; if (statusArray.Length >= 3) status.DetailText = statusArray[2]; status.Orbit = null; status.LastUpdateTime = UnityEngine.Time.realtimeSinceStartup; status.Color = KLFVessel.GenerateActiveColor(status.User); return status; } else return new VesselStatusInfo(); }
private void HandleVesselUpdate(KLFVesselUpdate vesselUpdate) { if (!IsInFlight) { //While not in-flight don't create KLF vessel, just store the active vessel status info if (vesselUpdate.State == State.Active) { VesselStatusInfo status = new VesselStatusInfo(); status.Info = vesselUpdate; status.User = vesselUpdate.Player; status.VesselName = vesselUpdate.Name; status.Orbit = null; status.LastUpdateTime = UnityEngine.Time.realtimeSinceStartup; status.Color = KLFVessel.GenerateActiveColor(status.User); if (PlayerStatus.ContainsKey(status.User)) PlayerStatus[status.User] = status; else PlayerStatus.Add(status.User, status); } return; //Don't handle updates while not flying a ship } //Build the key for the vessel System.Text.StringBuilder sb = new System.Text.StringBuilder(); sb.Append(vesselUpdate.Player); sb.Append(vesselUpdate.Id.ToString()); String vesselKey = sb.ToString(); KLFVessel kVes = null; //Try to find the key in the vessel dictionary VesselEntry entry; if (Vessels.TryGetValue(vesselKey, out entry)) { kVes = entry.Vessel; if(kVes == null || kVes.GameObj == null || kVes.VesselName != vesselUpdate.Name) {//Delete the vessel if it's null or needs to be renamed Vessels.Remove(vesselKey); if (kVes != null && kVes.GameObj != null) GameObject.Destroy(kVes.GameObj); kVes = null; } else { //Update the entry's timestamp VesselEntry newEntry = new VesselEntry(); newEntry.Vessel = entry.Vessel; newEntry.LastUpdateTime = UnityEngine.Time.realtimeSinceStartup; Vessels[vesselKey] = newEntry; } } if (kVes == null) {//Add the vessel to the dictionary kVes = new KLFVessel(vesselUpdate.Name, vesselUpdate.Player, vesselUpdate.Id); entry = new VesselEntry(); entry.Vessel = kVes; entry.LastUpdateTime = UnityEngine.Time.realtimeSinceStartup; if (Vessels.ContainsKey(vesselKey)) Vessels[vesselKey] = entry; else Vessels.Add(vesselKey, 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 */ VesselUpdateQueue.Enqueue(vesselUpdate); } else ApplyVesselUpdate(vesselUpdate, kVes); //Apply the vessel update to the existing vessel }