static ConfigNode resource_values(ProtoPartResourceSnapshot res) { var node = new ConfigNode("RESOURCE"); res.Save(node); return(node); }
protected void TransferResourceFromEVA(string resourceName) { double availableSpace = GetResourceAmount(resourceName, true) - GetResourceAmount(resourceName); double toAdd = 0d; for (int i = 0; i < FlightGlobals.ActiveVessel.evaController.ModuleInventoryPartReference.InventorySlots; i++) { if (availableSpace > 0d) { if (!FlightGlobals.ActiveVessel.evaController.ModuleInventoryPartReference.IsSlotEmpty(i)) { StoredPart sPart = FlightGlobals.ActiveVessel.evaController.ModuleInventoryPartReference.storedParts[i]; if (sPart.partName == RefuelCargoPartName) { ProtoPartResourceSnapshot res = sPart.snapshot.resources.Find(x => x.resourceName == resourceName); double availableResource = res.amount; double addable = UtilMath.Min(availableSpace, availableResource); toAdd += addable; Utils.Log($"Removed {addable} {resourceName} from {sPart.partName} ({availableResource} units in part, {availableSpace} space in target)"); availableSpace = UtilMath.Clamp(availableSpace - addable, 0, availableSpace); res.amount = UtilMath.Clamp(res.amount - addable, 0d, res.maxAmount); } } } } ScreenMessages.PostScreenMessage(new ScreenMessage(Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatFissionFuelContainer_Message_Stored", toAdd.ToString("F2"), resourceName, part.partInfo.title ), 5.0f, ScreenMessageStyle.UPPER_CENTER));; Utils.Log($"Added {toAdd} {resourceName} to {part.partInfo.title}"); part.RequestResource(resourceName, -toAdd, ResourceFlowMode.NO_FLOW); }
static void ProcessNonRechargeBattery(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, PartModule fission_generator, Resource_info ec, double elapsed_s) { ProtoPartResourceSnapshot proto_ec = p.resources.Find(k => k.resourceName == "ElectricCharge"); proto_ec.maxAmount = proto_ec.amount; ec.Sync(v, elapsed_s); }
/// <summary>Returns KIS resource description for the propellant in the part.</summary> /// <param name="item">Item to get resource for.</param> /// <returns>Resource description.</returns> ProtoPartResourceSnapshot GetCanisterFuelResource(KIS_Item item) { var resources = KISAPI.PartNodeUtils.GetResources(item.partNode); if (resources.Length == 0) { throw new Exception("Bad save state: no resource on the part"); } var itemResource = resources[0]; // Always use the first one. if (itemResource.resourceName == _mainResourceName) { return(itemResource); } // A mod that changes the default resource has been installed or removed. Update the part state. DebugEx.Warning( "Fixing saved state of the resource: oldName={0}, newName={1}", itemResource.resourceName, _mainResourceName); KISAPI.PartNodeUtils.DeleteResource(item.partNode, itemResource.resourceName); itemResource = new ProtoPartResourceSnapshot(part.Resources[0]) { amount = itemResource.amount }; KISAPI.PartNodeUtils.AddResource(item.partNode, itemResource); return(itemResource); }
/// <summary> /// Create a CacheResource /// </summary> /// <param name="inputprotoPartResourceSnapshot"></param> /// <param name="resourcename"></param> /// <param name="inputamount"></param> /// <param name="maxamount"></param> public CacheResource(uint craftId, ProtoPartResourceSnapshot inputprotoPartResourceSnapshot, string resourcename, double inputamount, double maxamount) { protoPartResourceSnapshot = new DictionaryValueList <string, ProtoPartResourceSnapshot>(); this.protoPartResourceSnapshot.Add(GetKey(craftId, inputprotoPartResourceSnapshot), inputprotoPartResourceSnapshot); this.resourceName = resourcename; this.amount = inputamount; this.maxAmount = maxamount; this.timeWarpOverflow = new CacheTimeWarpBuffer(); }
public ResourceProxy(ProtoPartResourceSnapshot res) : base(resource_values(res)) { if (res.resourceRef != null) { resourceRef = res.resourceRef; } protoRef = res; }
public static HashSet <ProtoPartResourceSnapshot> AddResource(VesselData data, float amount, string name, HashSet <ProtoPartResourceSnapshot> modified) { BackgroundProcessing.Debug("AddResource called, adding " + amount + " " + name, DebugLevel.ALL); if (!data.storage.ContainsKey(name)) { return(modified); } bool reduce = amount < 0; List <ProtoPartResourceSnapshot> relevantStorage = data.storage[name]; for (int i = 0; i < relevantStorage.Count; ++i) { ProtoPartResourceSnapshot r = relevantStorage[i]; if (amount == 0) { break; } float n; float m; n = (float)r.amount; m = (float)r.maxAmount; if ( !(float.IsInfinity(n) || float.IsInfinity(m)) ) { n += amount; amount = 0; if (reduce) { if (n < 0 && i < relevantStorage.Count - 1) { amount = n; n = 0; } } else { if (n > m && i < relevantStorage.Count - 1) { amount = n - m; n = m; } } r.amount = n; } modified.Add(r); } return(modified); }
private void consumeResources(ProtoVessel v, float amount) { int l = v.protoPartSnapshots.Count; for (int i = 0; i < l; i++) { ProtoPartSnapshot part = v.protoPartSnapshots[i]; if (part == null) { continue; } int r = part.resources.Count; for (int j = 0; j < r; j++) { ProtoPartResourceSnapshot resource = part.resources[j]; if (resource == null) { continue; } if (resource.resourceName != "ElectricCharge") { continue; } double partialEC = amount; double rAmount = 0; resource.resourceValues.TryGetValue("amount", ref rAmount); if (partialEC >= rAmount) { partialEC = rAmount; } rAmount -= partialEC; resource.resourceValues.SetValue("amount", rAmount.ToString()); amount -= (float)partialEC; if (amount <= 0) { return; } } } }
/// <summary>Adds a new resource into the config node.</summary> /// <param name="partNode"> /// The part's config or a persistent state. It can be a top-level node or the <c>PART</c> node. /// </param> /// <param name="resource"> /// The resource definition. If there is a resource with the same name in the node, it will be /// replaced. /// </param> public void AddResource(ConfigNode partNode, ProtoPartResourceSnapshot resource) { if (partNode.HasNode("PART")) { partNode = partNode.GetNode("PART"); } DeleteResource(partNode, resource.resourceName); var resourceNode = new ConfigNode("RESOURCE"); resource.Save(resourceNode); partNode.AddNode(resourceNode); }
/// <summary> /// Create or update a InterestedVessels entry's CachedResources for a ProtoVessel. /// </summary> /// <param name="vessel"></param> public static void CreatecachedVesselResources(ProtoVessel vessel) { if (UnloadedResources.InterestedVessels == null) { UnloadedResources.InterestedVessels = new DictionaryValueList <ProtoVessel, InterestedVessel>(); } List <CacheResource> cacheresources = new List <CacheResource>(); for (int i = 0; i < vessel.protoPartSnapshots.Count; i++) { ProtoPartSnapshot protoPartSnapshot = vessel.protoPartSnapshots[i]; for (int j = 0; j < protoPartSnapshot.resources.Count; j++) { ProtoPartResourceSnapshot protoPartResourceSnapshot = protoPartSnapshot.resources[j]; bool found = false; for (int k = 0; k < cacheresources.Count; k++) { if (cacheresources[k].resourceName == protoPartResourceSnapshot.resourceName) { cacheresources[k].amount += protoPartResourceSnapshot.amount; cacheresources[k].maxAmount += protoPartResourceSnapshot.maxAmount; cacheresources[k].protoPartResourceSnapshot.Add(CacheResource.GetKey(protoPartSnapshot, protoPartResourceSnapshot), protoPartResourceSnapshot); found = true; break; } } if (!found) { CacheResource newresource = new CacheResource(protoPartSnapshot.craftID, protoPartResourceSnapshot, protoPartResourceSnapshot.resourceName, protoPartResourceSnapshot.amount, protoPartResourceSnapshot.maxAmount); cacheresources.Add(newresource); } } } if (UnloadedResources.InterestedVessels.Contains(vessel)) { UnloadedResources.InterestedVessels[vessel].CachedResources = cacheresources; } else { InterestedVessel iVessel = new InterestedVessel(vessel.vesselRef, vessel); iVessel.CachedResources = cacheresources; UnloadedResources.InterestedVessels.Add(vessel, iVessel); UnloadedResources.InterestedVessels[vessel].TimeLastRefresh = Time.time; } }
public static bool HasResource(Vessel Vsl, string resource) { ProtoPartSnapshot[] Parts = Vsl.protoVessel.protoPartSnapshots.ToArray(); for (var i = 0; i < Parts.Length; i++) { ProtoPartSnapshot Part = Parts[i]; ProtoPartResourceSnapshot[] Resources = Part.resources.ToArray(); for (var k = 0; k < Resources.Length; k++) { ProtoPartResourceSnapshot Resrc = Resources[k]; if (Resrc.resourceName == resource && Resrc.amount > 0) { return(true); } } } return(false); }
public static float getMaxTotalVesselEC(ProtoVessel v) { double ec = 0; int l = v.protoPartSnapshots.Count; for (int i = 0; i < l; i++) { ProtoPartSnapshot part = v.protoPartSnapshots[i]; if (part == null) { continue; } int r = part.resources.Count; for (int j = 0; j < r; j++) { ProtoPartResourceSnapshot resource = part.resources[j]; if (resource == null) { continue; } if (resource.resourceName != "ElectricCharge") { continue; } double amount = 0; resource.resourceValues.TryGetValue("maxAmount", ref amount); ec += amount; } } //log("Vessel EC: {0:N4}", logLevels.warning, ec); return((float)ec); }
/// <summary>Creates a new item, given a saved state.</summary> /// <remarks> /// It's intentionally private. The items must be restored thru the factory methods. /// </remarks> /// <seealso cref="RestoreItemFromNode"/> KIS_Item(AvailablePart availablePart, ConfigNode itemNode, ModuleKISInventory inventory, int quantity) { this.availablePart = availablePart; this.inventory = inventory; this.quantity = quantity; SetPrefabModule(); this.stackable = CheckItemStackable(availablePart); this.partNode = new ConfigNode(); itemNode.GetNode("PART").CopyTo(partNode); ConfigAccessor.ReadFieldsFromNode( itemNode, GetType(), this, group: StdPersistentGroups.PartPersistant); this.itemVolume = KISAPI.PartUtils.GetPartVolume(availablePart, partNode: partNode); // COMPATIBILITY: Set/restore the dry cost and mass. // TODO(ihsoft): This code is only needed for the pre-1.17 KIS version saves. Drop it one day. if (this.itemDryMass < float.Epsilon || this.itemDryCost < float.Epsilon) { this._itemDryMass = KISAPI.PartUtils.GetPartDryMass(availablePart, partNode: partNode); this._itemDryCost = KISAPI.PartUtils.GetPartDryCost(availablePart, partNode: partNode); DebugEx.Warning("Calculated values for a pre 1.17 version save: dryMass={0}, dryCost={1}", this.itemDryMass, this.itemDryCost); } // COMPATIBILITY: Set/restore the resources cost and mass. // TODO(ihsoft): This code is only needed for the pre-1.17 KIS version saves. Drop it one day. var resourceNodes = PartNodeUtils.GetModuleNodes(partNode, "RESOURCE"); if (resourceNodes.Any() && (this.itemResourceMass < float.Epsilon || this.itemResourceCost < float.Epsilon)) { var oldResourceMass = this.itemResourceMass; foreach (var resourceNode in resourceNodes) { var resource = new ProtoPartResourceSnapshot(resourceNode); this._resourceMass += (float)resource.amount * resource.definition.density; this._resourceCost += (float)resource.amount * resource.definition.unitCost; } DebugEx.Warning("Calculated values for a pre 1.17 version save:" + " oldResourceMass={0}, newResourceMass={1}, resourceCost={2}", oldResourceMass, this.itemResourceMass, this.itemResourceCost); } }
bool CheckForEC(Vessel vessel) { // Need to add a check for range here double ec = 0; if (vessel.loaded) { for (int i = vessel.parts.Count - 1; i >= 0; i--) { Part p = vessel.parts[i]; for (int i1 = p.Resources.Count - 1; i1 >= 0; i1--) { PartResource r = p.Resources[i1]; if (r.resourceName == "ElectricCharge") { ec += r.amount; } } } } else { ProtoVessel proto = vessel.protoVessel; var res = new SortedDictionary <string, ResourceData>(); for (int i = proto.protoPartSnapshots.Count - 1; i >= 0; i--) { ProtoPartSnapshot p = proto.protoPartSnapshots[i]; for (int i1 = p.resources.Count - 1; i1 >= 0; i1--) { ProtoPartResourceSnapshot r = p.resources[i1]; if (r.resourceName == "ElectricCharge") { ec += r.amount; } } } } return(ec > 0.001); }
public Resource(T res) { if (res == null) { throw new NullReferenceException("Resource<T>: res cannot be null"); } if (!(is_resource || is_proto)) { throw new NotSupportedException("Resource<T>: T should be either " + "PartResource or ProtoPartResourceSnapshot"); } if (is_resource) { this.res = (PartResource)(object)res; } else { pres = (ProtoPartResourceSnapshot)(object)res; } }
protected double GetResourceEVAAmount(string resourceName) { double amt = 0d; if (FlightGlobals.ActiveVessel.evaController != null) { for (int i = 0; i < FlightGlobals.ActiveVessel.evaController.ModuleInventoryPartReference.InventorySlots; i++) { if (!FlightGlobals.ActiveVessel.evaController.ModuleInventoryPartReference.IsSlotEmpty(i)) { StoredPart sPart = FlightGlobals.ActiveVessel.evaController.ModuleInventoryPartReference.storedParts[i]; if (sPart.partName == RefuelCargoPartName) { ProtoPartResourceSnapshot res = sPart.snapshot.resources.Find(x => x.resourceName == resourceName); amt += res.amount; } } } } return(amt); }
public static int GetResourceCount(Vessel Vsl, string resource) { ProtoPartSnapshot[] Parts = Vsl.protoVessel.protoPartSnapshots.ToArray(); int resourceCount = 0; for (var i = 0; i < Parts.Length; i++) { ProtoPartSnapshot Part = Parts[i]; ProtoPartResourceSnapshot[] Resources = Part.resources.ToArray(); for (var k = 0; k < Resources.Length; k++) { ProtoPartResourceSnapshot Resrc = Resources[k]; if (Resrc.resourceName == resource) { resourceCount += (int)Resrc.amount; } } } return(resourceCount); }
public static CacheResource Load(ConfigNode node, ProtoVessel protoVessel) { string resName = ""; node.TryGetValue("resourceName", ref resName); double amt = 0; double maxamt = 0; node.TryGetValue("amount", ref amt); node.TryGetValue("maxAmount", ref maxamt); DictionaryValueList <string, ProtoPartResourceSnapshot> protoresSnapshots = new DictionaryValueList <string, ProtoPartResourceSnapshot>(); ConfigNode[] protoresourcesnapNodes = node.GetNodes("RESOURCE"); for (int rsI = 0; rsI < protoresourcesnapNodes.Length; rsI++) { string keyField = protoresourcesnapNodes[rsI].GetValue("craftID"); ProtoPartResourceSnapshot protoresSnap = new ProtoPartResourceSnapshot(protoresourcesnapNodes[rsI]); ProtoPartResourceSnapshot protoVesselResSnap = GetMatchingResourceSnapShot(keyField, protoresSnap, protoVessel); if (protoVesselResSnap != null) { protoresSnapshots.Add(keyField, protoVesselResSnap); } } if (protoresSnapshots.Count > 0) { Dictionary <string, ProtoPartResourceSnapshot> .Enumerator ppRSenumerator = protoresSnapshots.GetDictEnumerator(); ppRSenumerator.MoveNext(); string resourceKey = ""; uint craftID = CacheResource.RetrieveKey(ppRSenumerator.Current.Key, out resourceKey); CacheResource newCacheResource = new CacheResource(craftID, ppRSenumerator.Current.Value, resName, amt, maxamt); while (ppRSenumerator.MoveNext()) { newCacheResource.protoPartResourceSnapshot.Add(ppRSenumerator.Current.Key, ppRSenumerator.Current.Value); } ppRSenumerator.Dispose(); return(newCacheResource); } return(null); }
public static ProtoPartResourceSnapshot GetMatchingResourceSnapShot(string keyField, ProtoPartResourceSnapshot protoresSnap, ProtoVessel protoVessel) { ProtoPartResourceSnapshot returnSnapshot = null; string resourceKey = ""; uint craftID = CacheResource.RetrieveKey(keyField, out resourceKey); for (int pvPartI = 0; pvPartI < protoVessel.protoPartSnapshots.Count; pvPartI++) { if (protoVessel.protoPartSnapshots[pvPartI].craftID == craftID) { bool found = false; for (int ppSnapI = 0; ppSnapI < protoVessel.protoPartSnapshots[pvPartI].resources.Count; ppSnapI++) { if (protoVessel.protoPartSnapshots[pvPartI].resources[ppSnapI].resourceName == resourceKey) { //Compare the loaded values to the protoVessel snapshot. //If loaded is more then DO WE? update the protoVessel. Let's just report it for now. if (protoVessel.protoPartSnapshots[pvPartI].resources[ppSnapI].amount != protoresSnap.amount) { RSTUtils.Utilities.Log("ProtoVessel resource amounts differ"); } if (protoVessel.protoPartSnapshots[pvPartI].resources[ppSnapI].maxAmount != protoresSnap.maxAmount) { RSTUtils.Utilities.Log("ProtoVessel resource max amounts differ"); } returnSnapshot = protoVessel.protoPartSnapshots[pvPartI].resources[ppSnapI]; break; } } if (found) { break; } } } return(returnSnapshot); }
private static double GetUnloadedVesselMass(string name, ProtoVessel protoVessel) { double num = 0.0; for (int i = 0; i < protoVessel.protoPartSnapshots.Count; i++) { ProtoPartSnapshot protoPartSnapshot = protoVessel.protoPartSnapshots[i]; num += (double)protoPartSnapshot.mass; for (int j = 0; j < protoPartSnapshot.resources.Count; j++) { ProtoPartResourceSnapshot protoPartResourceSnapshot = protoPartSnapshot.resources[j]; if (protoPartResourceSnapshot != null) { if (protoPartResourceSnapshot.definition != null) { num += protoPartResourceSnapshot.amount * (double)protoPartResourceSnapshot.definition.density; } //else // Debug.Log("Vessel: " + name + ", resource: " + protoPartResourceSnapshot.resourceName + ", no definition"); } } } return(num); }
public static void ProtoBreak(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m) { // get reliability module prefab string type = Lib.Proto.GetString(m, "type", string.Empty); Reliability reliability = p.partPrefab.FindModulesImplementing <Reliability>().Find(k => k.type == type); if (reliability == null) { return; } // if manned, or if safemode didn't trigger if (Cache.VesselInfo(v).crew_capacity > 0 || Lib.RandomDouble() > Settings.SafeModeChance) { // flag as broken Lib.Proto.Set(m, "broken", true); // determine if this is a critical failure bool critical = Lib.RandomDouble() < Settings.CriticalChance; Lib.Proto.Set(m, "critical", critical); // for each associated module foreach (var proto_module in p.modules.FindAll(k => k.moduleName == reliability.type)) { // disable the module Lib.Proto.Set(proto_module, "isEnabled", false); } // type-specific hacks switch (reliability.type) { case "ProcessController": foreach (ProcessController pc in p.partPrefab.FindModulesImplementing <ProcessController>()) { ProtoPartResourceSnapshot res = p.resources.Find(k => k.resourceName == pc.resource); if (res != null) { res.flowState = false; } } break; } // show message Broken_msg(v, reliability.title, critical); } // safe mode else { // reset age Lib.Proto.Set(m, "last", 0.0); Lib.Proto.Set(m, "next", 0.0); // notify user Safemode_msg(v, reliability.title); } // in any case, incentive redundancy if (Settings.IncentiveRedundancy) { Incentive_redundancy(v, reliability.redundancy); } }
public KethaneProtoBattery(ProtoPartResourceSnapshot res) { protoResource = res; }
public static string GetKey(uint craftID, ProtoPartResourceSnapshot resourceSnapshot) { return(craftID + "," + resourceSnapshot.resourceName); }
public static string GetKey(ProtoPartSnapshot partSnapshot, ProtoPartResourceSnapshot resourceSnapshot) { return(partSnapshot.craftID + "," + resourceSnapshot.resourceName); }
/// <summary> /// We need to delay the EVA propellant modifications because ToEVA is called too early, before the EVA kerbal /// Start() code has run. /// </summary> IEnumerator PostEVATweaks(Part vesselHatch, Part kerbalPart, string evaPropName) { yield return(null); double evaPropQuantity = 0.0; bool hasJetPack = false; #if KSP15_16 || KSP17 || KSP18 || KSP110 hasJetPack = true; double evaPropCapacity = Lib.EvaPropellantCapacity(); // take as much of the propellant as possible. just imagine: there are 1.3 units left, and 12 occupants // in the ship. you want to send out an engineer to fix the chemical plant that produces monoprop, // and have to get from one end of the station to the other with just 0.1 units in the tank... // nope. evaPropQuantity = vesselHatch.RequestResource(evaPropName, evaPropCapacity); // Stock KSP adds 5 units of monoprop to EVAs. We want to limit that amount // to whatever was available in the ship, so we don't magically create EVA prop out of nowhere Lib.SetResource(kerbalPart, evaPropName, evaPropQuantity, evaPropCapacity); #else // Since KSP 1.11, EVA prop is stored on "EVA jetpack" inventory part, and filled in the editor, removing // the need for handling where the EVA propellant comes from (there is no more magic refill in stock). // However, stock doesn't provide any way to refill the jetpack, so we still handle that. KerbalEVA kerbalEVA = kerbalPart.FindModuleImplementing <KerbalEVA>(); List <ProtoPartResourceSnapshot> propContainers = new List <ProtoPartResourceSnapshot>(); if (kerbalEVA.ModuleInventoryPartReference != null) { foreach (StoredPart storedPart in kerbalEVA.ModuleInventoryPartReference.storedParts.Values) { // Note : the "evaJetpack" string is hardcoded in the KSP source if (storedPart.partName == "evaJetpack") { hasJetPack = true; } ProtoPartResourceSnapshot prop = storedPart.snapshot.resources.Find(p => p.resourceName == evaPropName); if (prop != null) { propContainers.Add(prop); } } } if (propContainers.Count > 0) { foreach (ProtoPartResourceSnapshot propContainer in propContainers) { if (propContainer.amount < propContainer.maxAmount) { double vesselPropTransferred = vesselHatch.RequestResource(evaPropName, propContainer.maxAmount - propContainer.amount); propContainer.amount = Math.Min(propContainer.amount + vesselPropTransferred, propContainer.maxAmount); } evaPropQuantity += propContainer.amount; } } #endif // show warning if there is little or no EVA propellant in the suit if (hasJetPack && evaPropQuantity <= 0.05 && !Lib.Landed(vesselHatch.vessel)) { Message.Post(Severity.danger, Local.CallBackMsg_EvaNoMP.Format("<b>" + evaPropName + "</b>"), Local.CallBackMsg_EvaNoMP2); //Lib.BuildString("There isn't any <<1>> in the EVA JetPack")"Don't let the ladder go!" } }
void FromEVA(GameEvents.FromToAction <Part, Part> data) { // contract configurator calls this event with both parts being the same when it adds a passenger if (data.from == data.to) { return; } // for each resource in the eva kerbal for (int i = 0; i < data.from.Resources.Count; ++i) { // get the resource PartResource res = data.from.Resources[i]; // add leftovers to the vessel data.to.RequestResource(res.resourceName, -res.amount); } #if !KSP15_16 && !KSP17 && !KSP18 && !KSP110 string evaPropName = Lib.EvaPropellantName(); if (evaPropName != "EVA Propellant") { KerbalEVA kerbalEVA = data.from.FindModuleImplementing <KerbalEVA>(); List <ProtoPartResourceSnapshot> propContainers = new List <ProtoPartResourceSnapshot>(); if (kerbalEVA.ModuleInventoryPartReference != null) { foreach (StoredPart storedPart in kerbalEVA.ModuleInventoryPartReference.storedParts.Values) { ProtoPartResourceSnapshot propContainer = storedPart.snapshot.resources.Find(p => p.resourceName == evaPropName); if (propContainer != null && propContainer.amount > 0.0) { propContainers.Add(propContainer); } } } if (propContainers.Count > 0) { // get vessel resources handler ResourceInfo evaPropOnVessel = ResourceCache.GetResource(data.to.vessel, evaPropName); double storageAvailable = evaPropOnVessel.Capacity - evaPropOnVessel.Amount; foreach (ProtoPartResourceSnapshot propContainer in propContainers) { double stored = Math.Min(propContainer.amount, storageAvailable); storageAvailable -= stored; evaPropOnVessel.Produce(stored, ResourceBroker.Generic); propContainer.amount = Math.Max(propContainer.amount - stored, 0.0); if (storageAvailable <= 0.0) { break; } } // Explaination : // - The ProtoCrewMember has already been removed from the EVA part and added to the vessel part // - It's inventory has already been saved // - The stock ModuleInventoryPart.RefillEVAPropellantOnBoarding() method has already been called // So to set the correct amount of EVA prop, we : // - Harmony patch ModuleInventoryPart.RefillEVAPropellantOnBoarding() so it doesn't refill anything // - Grab the ProtoCrewMember on the vessel part // - Call the SaveInventory() method again, with the modified amount on the inventory StoredPart data.to.protoModuleCrew[data.to.protoModuleCrew.Count - 1].SaveInventory(kerbalEVA.ModuleInventoryPartReference); } } #endif // merge drives data Drive.Transfer(data.from.vessel, data.to.vessel, true); // forget EVA vessel data Cache.PurgeVesselCaches(data.from.vessel); //Drive.Purge(data.from.vessel); // update boarded vessel this.OnVesselModified(data.to.vessel); // execute script data.to.vessel.KerbalismData().computer.Execute(data.to.vessel, ScriptType.eva_in); }
static void ProcessCryoTank(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, PartModule cryotank, Vessel_resources resources, Resource_info ec, double elapsed_s) { // Note. Currently background simulation of Cryotanks has an irregularity in that boiloff of a fuel type in a tank removes resources from all tanks // but at least some simulation is better than none ;) // get list of fuels, do nothing if no fuels IList fuels = Lib.ReflectionValue <IList>(cryotank, "fuels"); if (fuels == null) { return; } // is cooling available, note: comparing against amount in previous simulation step bool available = (Lib.Proto.GetBool(m, "CoolingEnabled") && ec.amount > double.Epsilon); // get cooling cost double cooling_cost = Lib.ReflectionValue <float>(cryotank, "CoolingCost"); string fuel_name = ""; double amount = 0.0; double total_cost = 0.0; double boiloff_rate = 0.0; foreach (var item in fuels) { fuel_name = Lib.ReflectionValue <string>(item, "fuelName"); // if fuel_name is null, don't do anything if (fuel_name == null) { continue; } //get fuel resource Resource_info fuel = resources.Info(v, fuel_name); // if there is some fuel // note: comparing against amount in previous simulation step if (fuel.amount > double.Epsilon) { // Try to find resource "fuel_name" in PartResources ProtoPartResourceSnapshot proto_fuel = p.resources.Find(k => k.resourceName == fuel_name); // If part doesn't have the fuel, don't do anything. if (proto_fuel == null) { continue; } // get amount in the part amount = proto_fuel.amount; // if cooling is enabled and there is enough EC if (available) { // calculate ec consumption total_cost += cooling_cost * amount * 0.001; } // if cooling is disabled or there wasn't any EC else { // get boiloff rate per-second boiloff_rate = Lib.ReflectionValue <float>(item, "boiloffRate") / 360000.0f; // let it boil off fuel.Consume(amount * (1.0 - Math.Pow(1.0 - boiloff_rate, elapsed_s))); } } } // apply EC consumption ec.Consume(total_cost * elapsed_s); }
public ResourceInfo(object obj) { _resourceInfo = (ProtoPartResourceSnapshot)obj; }
/// <summary> /// Request Resource processing on a ProtoVessel. /// If the ProtoVessel is not known or resources not cached for the ProtoVessel will automatically add them to the Cached data. /// </summary> /// <param name="vessel">ProtoVessel reference</param> /// <param name="resourceName">Name of the Resource we want to process</param> /// <param name="amount">The amount of the resource we want to process</param> /// <param name="amountReceived">returns the amount processed for the request in this variable</param> /// <param name="pushing">default of false (which means take resource). If true will push (put resource)</param> public static void RequestResource(ProtoVessel vessel, string resourceName, double amount, out double amountReceived, bool pushing = false) { amountReceived = 0d; if (UnloadedResources.InterestedVessels == null) { UnloadedResources.InterestedVessels = new DictionaryValueList <ProtoVessel, InterestedVessel>(); } //If there are no cachedResources for the vessel create one. if (!UnloadedResources.InterestedVessels.Contains(vessel)) { CacheResources.CreatecachedVesselResources(vessel); } //Double check, not really necessary. Now find the resource amounts if in the vessel. if (UnloadedResources.InterestedVessels.Contains(vessel)) { List <CacheResources.CacheResource> vslresources = UnloadedResources.InterestedVessels[vessel].CachedResources; for (int i = 0; i < vslresources.Count; i++) { CacheResources.CacheResource cacheResource = vslresources[i]; if (cacheResource.resourceName == resourceName) { if (!pushing) //We are taking resource { if (cacheResource.amount > 0 || cacheResource.timeWarpOverflow.totalAmount > 0) { if (cacheResource.timeWarpOverflow.totalAmount > 0 && TimeWarp.fetch != null && TimeWarp.CurrentRateIndex > CacheResources.timeWarpStep) //If we have timewarp Overflow check that first. { double amountTaken = 0; cacheResource.timeWarpOverflow.Take(amount, out amountTaken); amountReceived += amountTaken; amount -= amountTaken; if (amount <= 0) //Did we get all we need already? If so return. { return; } } //TimewarpOverflow didn't have enough or didn't have what we need. so now the partResrouceSnapshot Dictionary <string, ProtoPartResourceSnapshot> .Enumerator ppRSenumerator = cacheResource.protoPartResourceSnapshot.GetDictEnumerator(); while (ppRSenumerator.MoveNext()) { ProtoPartResourceSnapshot partResourceSnapshot = ppRSenumerator.Current.Value; if (partResourceSnapshot.amount > 0) { if (partResourceSnapshot.amount <= amount) //Not enough but take what it has { amountReceived += partResourceSnapshot.amount; amount -= partResourceSnapshot.amount; cacheResource.amount -= partResourceSnapshot.amount; partResourceSnapshot.amount = 0; } else //this part has more than we need. { amountReceived += amount; cacheResource.amount -= amount; partResourceSnapshot.amount -= amount; amount = 0; } } if (amount <= 0) //Did we get all we wanted? if so return. { ppRSenumerator.Dispose(); return; } } ppRSenumerator.Dispose(); } } else //We are putting a resource { //Get how much space there is in this part. double spaceAvailable = cacheResource.maxAmount - cacheResource.amount; if (spaceAvailable > 0) //If we have space put some in. { Dictionary <string, ProtoPartResourceSnapshot> .Enumerator ppRSenumerator = cacheResource.protoPartResourceSnapshot.GetDictEnumerator(); while (ppRSenumerator.MoveNext()) { ProtoPartResourceSnapshot partResourceSnapshot = ppRSenumerator.Current.Value; double partspaceAvailable = partResourceSnapshot.maxAmount - partResourceSnapshot.amount; if (partspaceAvailable > 0) { if (amount > partspaceAvailable) //If we can't fit it all in this part. Put what we can. { partResourceSnapshot.amount = partResourceSnapshot.maxAmount; cacheResource.amount += partspaceAvailable; amount -= partspaceAvailable; amountReceived += partspaceAvailable; } else //If we can fit it all in this part, put it in. { partResourceSnapshot.amount += amount; cacheResource.amount += amount; amountReceived += amount; amount = 0; } if (amount <= 0) //Did we get all we wanted? if so return. { return; } } } } //If we get here we had more than can fit in the parts... But if TimeWarp is too high, we put it in the overflow. if (TimeWarp.fetch != null && amount > 0) { if (TimeWarp.CurrentRateIndex > CacheResources.timeWarpStep) //But only if timewarp rate is high enough. { cacheResource.timeWarpOverflow.Add(amount); amountReceived += amount; amount = 0; return; } } } } } //End For loop all vessel resources. } }
public void Add(ProtoPartResourceSnapshot resource) { resources.Add(resource); }