private void Init(Vessel v, bool powered, bool storm) { // are we connected if (RemoteTech.Connected(v.id)) { linked = RemoteTech.ConnectedToKSC(v.id); status = RemoteTech.TargetsKSC(v.id) ? (int)LinkStatus.direct_link : (int)LinkStatus.indirect_link; target_name = status == (int)LinkStatus.direct_link ? Lib.Ellipsis("DSN: " + (RemoteTech.NameTargetsKSC(v.id) ?? ""), 20) : Lib.Ellipsis(RemoteTech.NameFirstHopToKSC(v.id) ?? "", 20); Guid[] controlPath = null; if (linked) { controlPath = RemoteTech.GetCommsControlPath(v.id); } // Get the lowest rate in ControlPath if (controlPath != null) { // Get rate from the firstHop, each Hop will do the same logic, then we will have the lowest rate for the path if (controlPath.Length > 0) { double dist = RemoteTech.GetCommsDistance(v.id, controlPath[0]); strength = 1 - (dist / Math.Max(RemoteTech.GetCommsMaxDistance(v.id, controlPath[0]), 1)); strength = Math.Pow(strength, Settings.DataRateDampingExponentRT); // If using relay, get the lowest rate if (status != (int)LinkStatus.direct_link) { Vessel target = FlightGlobals.FindVessel(controlPath[0]); ConnectionInfo ci = target.KerbalismData().Connection; strength *= ci.strength; rate = Math.Min(ci.rate, rate * strength); } else { rate *= strength; } } control_path = new List <string[]>(); Guid i = v.id; foreach (Guid id in controlPath) { var name = Lib.Ellipsis(RemoteTech.GetSatelliteName(i) + " \\ " + RemoteTech.GetSatelliteName(id), 35); var value = Lib.HumanReadablePerc(Math.Ceiling((1 - (RemoteTech.GetCommsDistance(i, id) / RemoteTech.GetCommsMaxDistance(i, id))) * 10000) / 10000, "F2"); var tooltip = "Distance: " + Lib.HumanReadableDistance(RemoteTech.GetCommsDistance(i, id)) + "\nMax Distance: " + Lib.HumanReadableDistance(RemoteTech.GetCommsMaxDistance(i, id)); control_path.Add(new string[] { name, value, tooltip }); i = id; } } } // is loss of connection due to a blackout else if (RemoteTech.GetCommsBlackout(v.id)) { status = storm ? (int)LinkStatus.storm : (int)LinkStatus.plasma; } }
// constructor /// <summary> Creates a <see cref="ConnectionInfo"/> object for the specified vessel from it's antenna modules</summary> public ConnectionInfo(Vessel v, bool powered, bool storm) { // set RemoteTech powered and storm state if (RemoteTech.Enabled) { RemoteTech.SetPoweredDown(v.id, !powered); RemoteTech.SetCommsBlackout(v.id, storm); } // return no connection if there is no ec left if (!powered) { // hysteresis delay if (DB.Vessel(v).hyspos_signal >= 5.0) { DB.Vessel(v).hyspos_signal = 5.0; DB.Vessel(v).hysneg_signal = 0.0; return; } DB.Vessel(v).hyspos_signal += 0.1; } else { // hysteresis delay DB.Vessel(v).hysneg_signal += 0.1; if (DB.Vessel(v).hysneg_signal < 5.0) { return; } DB.Vessel(v).hysneg_signal = 5.0; DB.Vessel(v).hyspos_signal = 0.0; } // if CommNet is enabled if (HighLogic.fetch.currentGame.Parameters.Difficulty.EnableCommNet) { AntennaInfoCommNet antennaInfo = new AntennaInfoCommNet(v); if (v.connection != null) { // force CommNet update of unloaded vessels if (!v.loaded) { Lib.ReflectionValue(v.connection, "unloadedDoOnce", true); } // are we connected to DSN if (v.connection.IsConnected) { ec = antennaInfo.ec; rate = antennaInfo.rate * PreferencesBasic.Instance.transmitFactor; linked = true; status = v.connection.ControlPath.First.hopType == CommNet.HopType.Home ? LinkStatus.direct_link : LinkStatus.indirect_link; strength = v.connection.SignalStrength; rate *= strength; target_name = Lib.Ellipsis(Localizer.Format(v.connection.ControlPath.First.end.displayName).Replace("Kerbin", "DSN"), 20); if (status != LinkStatus.direct_link) { Vessel firstHop = Lib.CommNodeToVessel(v.Connection.ControlPath.First.end); // Get rate from the firstHop, each Hop will do the same logic, then we will have the min rate for whole path rate = Math.Min(Cache.VesselInfo(FlightGlobals.FindVessel(firstHop.id)).connection.rate, rate); } } // is loss of connection due to plasma blackout else if (Lib.ReflectionValue <bool>(v.connection, "inPlasma")) // calling InPlasma causes a StackOverflow :( { status = LinkStatus.plasma; } } // if nothing has changed, no connection return; } // RemoteTech signal system else if (RemoteTech.Enabled) { AntennaInfoRT antennaInfo = new AntennaInfoRT(v); // are we connected if (RemoteTech.Connected(v.id)) { ec = antennaInfo.ec; rate = antennaInfo.rate * PreferencesBasic.Instance.transmitFactor; linked = RemoteTech.ConnectedToKSC(v.id); status = RemoteTech.TargetsKSC(v.id) ? LinkStatus.direct_link : LinkStatus.indirect_link; target_name = status == LinkStatus.direct_link ? Lib.Ellipsis("DSN: " + (RemoteTech.NameTargetsKSC(v.id) ?? ""), 20) : Lib.Ellipsis(RemoteTech.NameFirstHopToKSC(v.id) ?? "", 20); if (linked) { controlPath = RemoteTech.GetCommsControlPath(v.id); } // Get the lowest rate in ControlPath if (controlPath != null) { // Get rate from the firstHop, each Hop will do the same logic, then we will have the lowest rate for the path if (controlPath.Length > 0) { double dist = RemoteTech.GetCommsDistance(v.id, controlPath[0]); strength = 1 - (dist / Math.Max(RemoteTech.GetCommsMaxDistance(v.id, controlPath[0]), 1)); // If using relay, get the lowest rate if (status != LinkStatus.direct_link) { Vessel target = FlightGlobals.FindVessel(controlPath[0]); strength *= Cache.VesselInfo(target).connection.strength; rate = Math.Min(Cache.VesselInfo(target).connection.rate, rate * strength); } else { rate *= strength; } } } } // is loss of connection due to a blackout else if (RemoteTech.GetCommsBlackout(v.id)) { status = storm ? LinkStatus.storm : LinkStatus.plasma; } // if nothing has changed, no connection return; } // the simple stupid always connected signal system else { AntennaInfoCommNet antennaInfo = new AntennaInfoCommNet(v); ec = antennaInfo.ec * 0.16; // Consume 16% of the stock ec. Workaround for drain consumption with CommNet, ec consumption turns similar of RT rate = antennaInfo.rate * PreferencesBasic.Instance.transmitFactor; linked = true; status = LinkStatus.direct_link; strength = 1; // 100 % target_name = "DSN: KSC"; } }
// constructor /// <summary> Creates a <see cref="ConnectionInfo"/> object for the specified vessel from it's antenna modules</summary> public ConnectionInfo(Vessel v, bool powered, bool storm) { // set RemoteTech powered and storm state if (RemoteTech.Enabled) { RemoteTech.SetPoweredDown(v.id, !powered); RemoteTech.SetCommsBlackout(v.id, storm); } // return no connection if there is no ec left if (!powered) { // hysteresis delay if ((DB.Vessel(v).hyspos_signal >= 5.0)) { DB.Vessel(v).hyspos_signal = 5.0; DB.Vessel(v).hysneg_signal = 0.0; return; } DB.Vessel(v).hyspos_signal += 0.1; } else { // hysteresis delay DB.Vessel(v).hysneg_signal += 0.1; if (!(DB.Vessel(v).hysneg_signal >= 5.0)) { return; } DB.Vessel(v).hysneg_signal = 5.0; DB.Vessel(v).hyspos_signal = 0.0; } rate = 0.0; internal_cost = 0.0; external_cost = 0.0; // CommNet or simple signal system if (!RemoteTech.Enabled) { List <ModuleDataTransmitter> transmitters; // if vessel is loaded if (v.loaded) { // find transmitters transmitters = v.FindPartModulesImplementing <ModuleDataTransmitter>(); if (transmitters != null) { foreach (ModuleDataTransmitter t in transmitters) { if (t.antennaType == AntennaType.INTERNAL) // do not include internal data rate, ec cost only { internal_cost += t.DataResourceCost * t.DataRate; } else { // do we have an animation ModuleDeployableAntenna animation = t.part.FindModuleImplementing <ModuleDeployableAntenna>(); ModuleAnimateGeneric animationGeneric = t.part.FindModuleImplementing <ModuleAnimateGeneric>(); if (animation != null) { // only include data rate and ec cost if transmitter is extended if (animation.deployState == ModuleDeployablePart.DeployState.EXTENDED) { rate += t.DataRate; external_cost += t.DataResourceCost * t.DataRate; } } else if (animationGeneric != null) { // only include data rate and ec cost if transmitter is extended if (animationGeneric.animSpeed > 0) { rate += t.DataRate; external_cost += t.DataResourceCost * t.DataRate; } } // no animation else { rate += t.DataRate; external_cost += t.DataResourceCost * t.DataRate; } } } } } // if vessel is not loaded else { // find proto transmitters foreach (ProtoPartSnapshot p in v.protoVessel.protoPartSnapshots) { // get part prefab (required for module properties) Part part_prefab = PartLoader.getPartInfoByName(p.partName).partPrefab; transmitters = part_prefab.FindModulesImplementing <ModuleDataTransmitter>(); if (transmitters != null) { foreach (ModuleDataTransmitter t in transmitters) { if (t.antennaType == AntennaType.INTERNAL) // do not include internal data rate, ec cost only { internal_cost += t.DataResourceCost * t.DataRate; } else { // do we have an animation ProtoPartModuleSnapshot m = p.FindModule("ModuleDeployableAntenna") ?? p.FindModule("ModuleAnimateGeneric"); if (m != null) { // only include data rate and ec cost if transmitter is extended string deployState = Lib.Proto.GetString(m, "deployState"); float animSpeed = Lib.Proto.GetFloat(m, "animSpeed"); if (deployState == "EXTENDED" || animSpeed > 0) { rate += t.DataRate; external_cost += t.DataResourceCost * t.DataRate; } } // no animation else { rate += t.DataRate; external_cost += t.DataResourceCost * t.DataRate; } } } } } } // if CommNet is enabled if (HighLogic.fetch.currentGame.Parameters.Difficulty.EnableCommNet) { if (v.connection != null) { // force CommNet update of unloaded vessels if (!v.loaded) { Lib.ReflectionValue(v.connection, "unloadedDoOnce", true); } // are we connected to DSN or control station(can be another vessel with 3 or more crew in CommNet) if (v.connection.IsConnected) { linked = true; status = v.connection.ControlPath.First.hopType == HopType.Home ? LinkStatus.direct_link : LinkStatus.indirect_link; strength = v.connection.SignalStrength; if (status != LinkStatus.direct_link) { Vessel firstHop = Lib.CommNodeToVessel(v.Connection.ControlPath.First.end); // Get rate from the firstHop, each Hop will do the same logic, then we will have the min rate for whole path rate = Math.Min(Cache.VesselInfo(FlightGlobals.FindVessel(firstHop.id)).connection.rate, rate); } rate *= strength * PreferencesBasic.Instance.transmitFactor; target_name = Lib.Ellipsis(Localizer.Format(v.connection.ControlPath.First.end.displayName).Replace("Kerbin", "DSN"), 20); } // is loss of connection due to plasma blackout else if (Lib.ReflectionValue <bool>(v.connection, "inPlasma")) // calling InPlasma causes a StackOverflow :( { status = LinkStatus.plasma; rate = 0.0; internal_cost = 0.0; external_cost = 0.0; } } // no connection else { rate = 0.0; internal_cost = 0.0; external_cost = 0.0; } return; } // the simple stupid always connected signal system linked = true; status = LinkStatus.direct_link; strength = 1; // 100 % target_name = "DSN: KSC"; return; } // RemoteTech signal system else { // if vessel is loaded if (v.loaded) { // find transmitters foreach (Part p in v.parts) { foreach (PartModule m in p.Modules) { // calculate internal (passive) transmitter ec usage @ 0.5W each if (m.moduleName == "ModuleRTAntennaPassive") { internal_cost += 0.0005; } // calculate external transmitters else if (m.moduleName == "ModuleRTAntenna") { // only include ec cost if transmitter is active if (Lib.ReflectionValue <bool>(m, "IsRTActive")) { rate += Lib.ReflectionValue <float>(m, "RTPacketSize") / Lib.ReflectionValue <float>(m, "RTPacketInterval"); external_cost += m.resHandler.inputResources.Find(r => r.name == "ElectricCharge").rate; } } } } } // if vessel is not loaded else { // find proto transmitters foreach (ProtoPartSnapshot p in v.protoVessel.protoPartSnapshots) { // get part prefab (required for module properties) Part part_prefab = PartLoader.getPartInfoByName(p.partName).partPrefab; int index = 0; // module index foreach (ProtoPartModuleSnapshot m in p.modules) { // calculate internal (passive) transmitter ec usage @ 0.5W each if (m.moduleName == "ModuleRTAntennaPassive") { internal_cost += 0.0005; } // calculate external transmitters else if (m.moduleName == "ModuleRTAntenna") { // only include data rate and ec cost if transmitter is active skip if index is out of range if (Lib.Proto.GetBool(m, "IsRTActive") && index < part_prefab.Modules.Count) { // get module prefab PartModule pm = part_prefab.Modules.GetModule(index); if (pm != null) { external_cost += pm.resHandler.inputResources.Find(r => r.name == "ElectricCharge").rate; // only include data rate if vessel is connected float?packet_size = Lib.SafeReflectionValue <float>(pm, "RTPacketSize"); // workaround for old savegames if (packet_size == null) { Lib.Debug("Old SaveGame PartModule ModuleRTAntenna for part {0} on unloaded vessel {1}, using default values as a workaround", p.partName, v.vesselName); rate += 6.6666; // 6.67 Mb/s } else { rate += (float)packet_size / Lib.ReflectionValue <float>(pm, "RTPacketInterval"); } } else { Lib.Debug("Could not find PartModule ModuleRTAntenna for part {0} on unloaded vessel {1}, using default values as a workaround", p.partName, v.vesselName); rate += 6.6666; // 6.67 Mb/s in 100% factor external_cost += 0.025; // 25 W/s } } } index++; } } } // are we connected if (RemoteTech.Connected(v.id)) { linked = RemoteTech.ConnectedToKSC(v.id); status = RemoteTech.TargetsKSC(v.id) ? LinkStatus.direct_link : LinkStatus.indirect_link; strength = RemoteTech.GetSignalDelay(v.id); target_name = status == LinkStatus.direct_link ? Lib.Ellipsis("DSN: " + (RemoteTech.NameTargetsKSC(v.id) ?? ""), 20) : Lib.Ellipsis(RemoteTech.NameFirstHopToKSC(v.id) ?? "", 20); if (linked) { controlPath = RemoteTech.GetCommsControlPath(v.id); } // Get the smaller rate of the path if (controlPath != null) { // Get rate from the firstHop, each Hop will do the same logic, then we will have the min rate for whole path if (controlPath.Length > 0) { rate = Math.Min(Cache.VesselInfo(FlightGlobals.FindVessel(controlPath[0])).connection.rate, rate); } } rate *= PreferencesBasic.Instance.transmitFactor; } // is loss of connection due to a blackout else if (RemoteTech.GetCommsBlackout(v.id)) { status = storm ? LinkStatus.storm : LinkStatus.plasma; rate = 0.0; internal_cost = 0.0; external_cost = 0.0; } else { // no connection rate = 0.0; internal_cost = 0.0; external_cost = 0.0; } } }